diff --git a/Sources/Common/Execution.swift b/Sources/Common/Execution.swift index a5e138f..a4f932a 100644 --- a/Sources/Common/Execution.swift +++ b/Sources/Common/Execution.swift @@ -15,6 +15,137 @@ // You should have received a copy of the GNU General Public License // along with this program. If not, see . + + +public typealias ExecuteStatementResultHandler = (ControlFlow, ProgramExecution) -> ( + ControlFlow, ProgramExecution +) + +public struct ClassicEvaluator: ProgramExecutionEvaluator { + public func ExecuteStatement( + _ statements: [EvaluatableStatement], handleResult handler: ExecuteStatementResultHandler, + inExecution execution: ProgramExecution, + ) -> (ControlFlow, ProgramExecution) { + + var execution = execution + for s in statements { + let (control_flow, next_execution) = s.evaluate(execution: execution) + + switch handler(control_flow, next_execution) { + case (ControlFlow.Next, let handled_next_execution): execution = handled_next_execution + case (ControlFlow.Return(let value), let handled_next_execution): + return (ControlFlow.Return(value), handled_next_execution) + case (let handled_control_flow, let handled_next_execution): + return (handled_control_flow, handled_next_execution) + } + } + return (ControlFlow.Next, execution) + } + + public func ExecuteStatement( + _ statement: EvaluatableStatement, handleResult handler: ExecuteStatementResultHandler, + inExecution execution: ProgramExecution + ) -> (ControlFlow, ProgramExecution) { + return ExecuteStatement([statement], handleResult: handler, inExecution: execution) + } + + public func EvaluateExpression( + _ expression: EvaluatableExpression, inExecution execution: ProgramExecution, + ) -> (Result, ProgramExecution) { + return expression.evaluate(execution: execution) + } +} + +public struct InterloperEvaluator: ProgramExecutionEvaluator { + var statement_interloper: StatementInterloper? + var expression_interloper: ExpressionInterloper? + + public init() {} + + public func getStatementInterloper() -> StatementInterloper? { + return self.statement_interloper + } + + public func setStatementInterloper( + _ interloper: @escaping StatementInterloper + ) -> InterloperEvaluator { + var pe = self + pe.statement_interloper = interloper + return pe + } + + public func getExpressionInterloper() -> ExpressionInterloper? { + return self.expression_interloper + } + + public func setExpressionInterloper( + _ interloper: @escaping ExpressionInterloper + ) -> InterloperEvaluator { + var pe = self + pe.expression_interloper = interloper + return pe + } + + public func ExecuteStatement( + _ statements: [EvaluatableStatement], handleResult handler: ExecuteStatementResultHandler, + inExecution execution: ProgramExecution, + ) -> (ControlFlow, ProgramExecution) { + + var debugger: StatementInterloper? = .none + var hasDebugInterloper = false + if let found_deb = self.getStatementInterloper() { + debugger = found_deb + hasDebugInterloper = true + } + + var execution = execution + for s in statements { + let (control_flow, next_execution) = s.evaluate(execution: execution) + + if hasDebugInterloper { + debugger!(s, control_flow, next_execution) + } + + switch handler(control_flow, next_execution) { + case (ControlFlow.Next, let handled_next_execution): execution = handled_next_execution + case (ControlFlow.Return(let value), let handled_next_execution): + return (ControlFlow.Return(value), handled_next_execution) + case (let handled_control_flow, let handled_next_execution): + return (handled_control_flow, handled_next_execution) + } + } + return (ControlFlow.Next, execution) + } + + public func ExecuteStatement( + _ statement: EvaluatableStatement, handleResult handler: ExecuteStatementResultHandler, + inExecution execution: ProgramExecution + ) -> (ControlFlow, ProgramExecution) { + return ExecuteStatement([statement], handleResult: handler, inExecution: execution) + } + + public func EvaluateExpression( + _ expression: EvaluatableExpression, inExecution execution: ProgramExecution, + ) -> (Result, ProgramExecution) { + + var debugger: ExpressionInterloper? = .none + var hasDebugInterloper = false + if let found_deb = self.getExpressionInterloper() { + debugger = found_deb + hasDebugInterloper = true + } + + let (result, execution) = expression.evaluate(execution: execution) + + if hasDebugInterloper { + debugger!(expression, result, execution) + } + + return (result, execution) + + } +} + public typealias StatementInterloper = (EvaluatableStatement, ControlFlow, ProgramExecution) -> Void public typealias ExpressionInterloper = (EvaluatableExpression, Result, ProgramExecution) -> Void @@ -24,24 +155,24 @@ open class ProgramExecution: CustomStringConvertible { var globalValues: VarValueScopes? var error: Error? var debug: DebugLevel = DebugLevel.Error - var statement_interloper: StatementInterloper? - var expression_interloper: ExpressionInterloper? + public let evaluator: ProgramExecutionEvaluator init(copy: ProgramExecution) { self.scopes = copy.scopes self.globalValues = copy.globalValues self.error = copy.error self.debug = copy.debug - self.statement_interloper = copy.statement_interloper - self.expression_interloper = copy.expression_interloper + self.evaluator = copy.evaluator } public init() { globalValues = .none + evaluator = ClassicEvaluator() } - public init(withGlobalValues values: VarValueScopes) { - globalValues = values + public init(_ evaluator: ProgramExecutionEvaluator) { + globalValues = .none + self.evaluator = evaluator } open var description: String { @@ -72,30 +203,6 @@ open class ProgramExecution: CustomStringConvertible { return pe } - public func getStatementInterloper() -> StatementInterloper? { - return self.statement_interloper - } - - public func setStatementInterloper( - _ interloper: @escaping StatementInterloper - ) -> ProgramExecution { - let pe = ProgramExecution(copy: self) - pe.statement_interloper = interloper - return pe - } - - public func getExpressionInterloper() -> ExpressionInterloper? { - return self.expression_interloper - } - - public func setExpressionInterloper( - _ interloper: @escaping ExpressionInterloper - ) -> ProgramExecution { - let pe = ProgramExecution(copy: self) - pe.expression_interloper = interloper - return pe - } - open func isDone() -> Bool { return false } diff --git a/Sources/Common/Protocols.swift b/Sources/Common/Protocols.swift index 03a5f2a..2f9c1ad 100644 --- a/Sources/Common/Protocols.swift +++ b/Sources/Common/Protocols.swift @@ -54,3 +54,19 @@ public protocol EvaluatableLValueExpression: EvaluatableExpression { ) -> Result<(VarValueScopes, P4Value)> func check(to: EvaluatableExpression, inScopes scopes: VarTypeScopes) -> Result<()> } + +public protocol ProgramExecutionEvaluator { + func ExecuteStatement( + _ statements: [EvaluatableStatement], handleResult handler: ExecuteStatementResultHandler, + inExecution execution: ProgramExecution, + ) -> (ControlFlow, ProgramExecution); + + func ExecuteStatement( + _ statement: EvaluatableStatement, handleResult handler: ExecuteStatementResultHandler, + inExecution execution: ProgramExecution + ) -> (ControlFlow, ProgramExecution); + + func EvaluateExpression( + _ expression: EvaluatableExpression, inExecution execution: ProgramExecution, + ) -> (Result, ProgramExecution) +} \ No newline at end of file diff --git a/Sources/P4Runtime/Common.swift b/Sources/P4Runtime/Common.swift index de70e3d..8926de9 100644 --- a/Sources/P4Runtime/Common.swift +++ b/Sources/P4Runtime/Common.swift @@ -33,7 +33,7 @@ public func Call( let arg_idx = argument.index let arg_value = argument.argument //let maybe_argument_value = arg_value.evaluate(execution: called_execution) - let maybe_argument_value = EvaluateExpression(arg_value, inExecution: called_execution) + let maybe_argument_value = called_execution.evaluator.EvaluateExpression(arg_value, inExecution: called_execution) guard case (.Ok(let argument_value), let updated_execution) = maybe_argument_value else { return ( .Error(Error(withMessage: "Cannot evaluate argument \(arg_idx): \(argument)")), @@ -84,65 +84,3 @@ public func Call( return (.Ok(call_result), updated_execution.replaceScopes(inout_scopes)) } -public typealias ExecuteStatementResultHandler = (ControlFlow, ProgramExecution) -> ( - ControlFlow, ProgramExecution -) - -public func ExecuteStatement( - _ statements: [EvaluatableStatement], handleResult handler: ExecuteStatementResultHandler, - inExecution execution: ProgramExecution, -) -> (ControlFlow, ProgramExecution) { - - var debugger: StatementInterloper? = .none - var hasDebugInterloper = false - if let found_deb = execution.getStatementInterloper() { - debugger = found_deb - hasDebugInterloper = true - } - - var execution = execution - for s in statements { - let (control_flow, next_execution) = s.evaluate(execution: execution) - - if hasDebugInterloper { - debugger!(s, control_flow, next_execution) - } - - switch handler(control_flow, next_execution) { - case (ControlFlow.Next, let handled_next_execution): execution = handled_next_execution - case (ControlFlow.Return(let value), let handled_next_execution): - return (ControlFlow.Return(value), handled_next_execution) - case (let handled_control_flow, let handled_next_execution): - return (handled_control_flow, handled_next_execution) - } - } - return (ControlFlow.Next, execution) -} - -public func ExecuteStatement( - _ statement: EvaluatableStatement, handleResult handler: ExecuteStatementResultHandler, - inExecution execution: ProgramExecution -) -> (ControlFlow, ProgramExecution) { - return ExecuteStatement([statement], handleResult: handler, inExecution: execution) -} - -public func EvaluateExpression( - _ expression: EvaluatableExpression, inExecution execution: ProgramExecution, -) -> (Result, ProgramExecution) { - - var debugger: ExpressionInterloper? = .none - var hasDebugInterloper = false - if let found_deb = execution.getExpressionInterloper() { - debugger = found_deb - hasDebugInterloper = true - } - - let (result, execution) = expression.evaluate(execution: execution) - - if hasDebugInterloper { - debugger!(expression, result, execution) - } - - return (result, execution) - -} diff --git a/Sources/P4Runtime/Expressions.swift b/Sources/P4Runtime/Expressions.swift index db6946e..bc4cf51 100644 --- a/Sources/P4Runtime/Expressions.swift +++ b/Sources/P4Runtime/Expressions.swift @@ -30,15 +30,15 @@ extension SelectCaseExpression: EvaluatableExpression { extension SelectExpression: EvaluatableExpression { public func evaluate(execution: ProgramExecution) -> (Result, ProgramExecution) { - switch EvaluateExpression(self.selector, inExecution: execution) { + switch execution.evaluator.EvaluateExpression(self.selector, inExecution: execution) { case (.Ok(let selector_value), let updated_execution): for sce in self.case_expressions { - if case (.Ok(let kse), let updated_execution) = EvaluateExpression( + if case (.Ok(let kse), let updated_execution) = updated_execution.evaluator.EvaluateExpression( sce.key, inExecution: updated_execution), kse.eq(selector_value) { //let result = sce.evaluate(execution: updated_execution) - let result = EvaluateExpression(sce, inExecution: updated_execution) + let result = updated_execution.evaluator.EvaluateExpression(sce, inExecution: updated_execution) return result } } @@ -212,13 +212,13 @@ extension BinaryOperatorExpression: EvaluatableExpression { public func evaluate(execution: ProgramExecution) -> (Result, ProgramExecution) { let updated_execution = execution //let maybe_evaluated_left = self.left.evaluate(execution: updated_execution) - let maybe_evaluated_left = EvaluateExpression(self.left, inExecution: updated_execution) + let maybe_evaluated_left = updated_execution.evaluator.EvaluateExpression(self.left, inExecution: updated_execution) guard case (.Ok(let evaluated_left), let updated_execution) = maybe_evaluated_left else { return maybe_evaluated_left } //let maybe_evaluated_right = self.right.evaluate(execution: updated_execution) - let maybe_evaluated_right = EvaluateExpression(self.right, inExecution: updated_execution) + let maybe_evaluated_right = updated_execution.evaluator.EvaluateExpression(self.right, inExecution: updated_execution) guard case (.Ok(let evaluated_right), let updated_execution) = maybe_evaluated_right else { return maybe_evaluated_right } @@ -235,13 +235,13 @@ extension ArrayAccessExpression: EvaluatableExpression { public func evaluate(execution: ProgramExecution) -> (Result, ProgramExecution) { let updated_execution = execution //let maybe_name = self.name.evaluate(execution: updated_execution) - let maybe_name = EvaluateExpression(self.name, inExecution: updated_execution) + let maybe_name = updated_execution.evaluator.EvaluateExpression(self.name, inExecution: updated_execution) guard case (.Ok(let name), let updated_execution) = maybe_name else { return maybe_name } //let maybe_indexor = self.indexor.evaluate(execution: updated_execution) - let maybe_indexor = EvaluateExpression(self.indexor, inExecution: updated_execution) + let maybe_indexor = updated_execution.evaluator.EvaluateExpression(self.indexor, inExecution: updated_execution) guard case (.Ok(let indexor), let updated_execution) = maybe_indexor else { return maybe_indexor } @@ -271,7 +271,7 @@ extension ArrayAccessExpression: EvaluatableLValueExpression { let updated_execution = execution //let maybe_value = self.name.evaluate(execution: updated_execution) - let maybe_value = EvaluateExpression(self.name, inExecution: updated_execution) + let maybe_value = updated_execution.evaluator.EvaluateExpression(self.name, inExecution: updated_execution) guard case (.Ok(let value), let updated_execution) = maybe_value else { return .Error( Error(withMessage: "\(self.name) cannot be evaluated: \(maybe_value.0.error()!)")) @@ -282,7 +282,7 @@ extension ArrayAccessExpression: EvaluatableLValueExpression { // Now, get the indexor! //let maybe_indexor_value = self.indexor.evaluate(execution: updated_execution) - let maybe_indexor_value = EvaluateExpression(self.indexor, inExecution: updated_execution) + let maybe_indexor_value = updated_execution.evaluator.EvaluateExpression(self.indexor, inExecution: updated_execution) guard case (.Ok(let indexor_value), let updated_execution) = maybe_indexor_value else { return Result.Error( Error(withMessage: "\(self.indexor) cannot be evaluated: \(maybe_indexor_value.0.error()!)") @@ -349,7 +349,7 @@ extension FieldAccessExpression: EvaluatableExpression { let updated_execution = execution //let maybe_struct = self.strct.evaluate(execution: updated_execution) - let maybe_struct = EvaluateExpression(self.strct, inExecution: updated_execution) + let maybe_struct = updated_execution.evaluator.EvaluateExpression(self.strct, inExecution: updated_execution) guard case (.Ok(let strct), let updated_execution) = maybe_struct else { return maybe_struct } @@ -384,7 +384,7 @@ extension FieldAccessExpression: EvaluatableLValueExpression { let updated_execution = execution // First, evaluate strct_id and make sure that it names a struct. //let maybe_value = self.strct.evaluate(execution: updated_execution) - let maybe_value = EvaluateExpression(self.strct, inExecution: updated_execution) + let maybe_value = updated_execution.evaluator.EvaluateExpression(self.strct, inExecution: updated_execution) guard case (.Ok(let value), let updated_execution) = maybe_value else { return .Error( Error(withMessage: "\(self.strct) cannot be evaluated: \(maybe_value.0.error()!)")) @@ -454,7 +454,7 @@ extension FieldAccessExpression: EvaluatableLValueExpression { extension KeysetExpression: EvaluatableExpression { public func evaluate(execution: ProgramExecution) -> (Result, ProgramExecution) { //return self.key.evaluate(execution: execution) - return EvaluateExpression(self.key, inExecution: execution) + return execution.evaluator.EvaluateExpression(self.key, inExecution: execution) } public func type() -> P4Type { diff --git a/Sources/P4Runtime/Parser.swift b/Sources/P4Runtime/Parser.swift index 8223c8c..e03bcb5 100644 --- a/Sources/P4Runtime/Parser.swift +++ b/Sources/P4Runtime/Parser.swift @@ -22,7 +22,7 @@ extension ParserAssignmentStatement: EvaluatableStatement { public func evaluate(execution: ProgramExecution) -> (ControlFlow, ProgramExecution) { let updated_execution = execution //let result = self.value.evaluate(execution: updated_execution) - let result = EvaluateExpression(self.value, inExecution: updated_execution) + let result = updated_execution.evaluator.EvaluateExpression(self.value, inExecution: updated_execution) guard case (.Ok(let value), let updated_execution) = result else { return (ControlFlow.Error, execution.setError(error: result.0.error()!)) } @@ -44,7 +44,7 @@ extension ParserStateDirectTransition: EvaluatableParserState { ) -> (any EvaluatableParserState, Common.ProgramExecution) { var program = program.enter_scope() - let (control_flow, next_execution) = ExecuteStatement( + let (control_flow, next_execution) = program.evaluator.ExecuteStatement( statements, handleResult: { (control_flow, execution) in return (control_flow, execution) @@ -105,7 +105,7 @@ extension ParserStateSelectTransition: EvaluatableParserState { ) -> (any EvaluatableParserState, Common.ProgramExecution) { var program = program.enter_scope() - let (control_flow, next_execution) = ExecuteStatement( + let (control_flow, next_execution) = program.evaluator.ExecuteStatement( statements, handleResult: { (control_flow, execution) in return (control_flow, execution) @@ -123,7 +123,7 @@ extension ParserStateSelectTransition: EvaluatableParserState { } //switch self.selectExpression.evaluate(execution: program) { - switch EvaluateExpression(self.selectExpression, inExecution: program) { + switch program.evaluator.EvaluateExpression(self.selectExpression, inExecution: program) { case (.Ok(let value), let program): if value.type().dataType().eq(rhs: self) { return (value.dataValue() as! EvaluatableParserState, program.exit_scope()) diff --git a/Sources/P4Runtime/Runtime.swift b/Sources/P4Runtime/Runtime.swift index 64e2fd1..fc54dc1 100644 --- a/Sources/P4Runtime/Runtime.swift +++ b/Sources/P4Runtime/Runtime.swift @@ -59,7 +59,7 @@ public struct ParserRuntime: CustomStringConvertible { { let pe = if let initial = initialValues { - ProgramExecution(withGlobalValues: initial) + ProgramExecution().setGlobalValues(initial) } else { ProgramExecution() } diff --git a/Sources/P4Runtime/Statements.swift b/Sources/P4Runtime/Statements.swift index 8bdc051..05ef20d 100644 --- a/Sources/P4Runtime/Statements.swift +++ b/Sources/P4Runtime/Statements.swift @@ -20,7 +20,7 @@ import P4Lang extension BlockStatement: EvaluatableStatement { public func evaluate(execution: ProgramExecution) -> (ControlFlow, ProgramExecution) { - return ExecuteStatement( + return execution.evaluator.ExecuteStatement( self.statements, handleResult: { (cf, execution) in switch cf { @@ -43,7 +43,7 @@ extension VariableDeclarationStatement: EvaluatableStatement { public func evaluate(execution: ProgramExecution) -> (ControlFlow, ProgramExecution) { guard //case (.Ok(let initial_value), let execution) = self.initializer.evaluate(execution: execution) - case (.Ok(let initial_value), let execution) = EvaluateExpression( + case (.Ok(let initial_value), let execution) = execution.evaluator.EvaluateExpression( self.initializer, inExecution: execution) else { return ( @@ -61,7 +61,7 @@ extension ConditionalStatement: EvaluatableStatement { public func evaluate(execution: ProgramExecution) -> (ControlFlow, ProgramExecution) { guard //case (.Ok(let evaluated_condition), let execution) = self.condition.evaluate(execution: execution) - case (.Ok(let evaluated_condition), let execution) = EvaluateExpression( + case (.Ok(let evaluated_condition), let execution) = execution.evaluator.EvaluateExpression( self.condition, inExecution: execution) else { return ( @@ -111,7 +111,7 @@ extension ExpressionStatement: EvaluatableStatement { // Evaluate, there might be side effects! //return switch self.expression.evaluate(execution: execution) { - return switch EvaluateExpression(self.expression, inExecution: execution) { + return switch execution.evaluator.EvaluateExpression(self.expression, inExecution: execution) { case (.Ok(_), let updated_context): (ControlFlow.Next, updated_context) case (.Error(let e), let updated_context): (ControlFlow.Next, updated_context.setError(error: e)) @@ -122,7 +122,7 @@ extension ExpressionStatement: EvaluatableStatement { extension ReturnStatement: EvaluatableStatement { public func evaluate(execution: ProgramExecution) -> (ControlFlow, ProgramExecution) { //return switch self.value.evaluate(execution: execution) { - return switch EvaluateExpression(self.value, inExecution: execution) { + return switch execution.evaluator.EvaluateExpression(self.value, inExecution: execution) { case (.Ok(let v), let execution): (ControlFlow.Return(v), execution) case (.Error(let e), let execution): (ControlFlow.Error, execution.setError(error: e)) } diff --git a/Tests/p4rseTests/InterloperTests.swift b/Tests/p4rseTests/InterloperTests.swift index f6f3640..da19c87 100644 --- a/Tests/p4rseTests/InterloperTests.swift +++ b/Tests/p4rseTests/InterloperTests.swift @@ -51,11 +51,11 @@ import TreeSitterP4 var statements_executed: [String] = Array() - let pe = ProgramExecution().setStatementInterloper({ (statement, cf, execution) in + let ev = InterloperEvaluator().setStatementInterloper() { (statement, cf, execution) in statements_executed.append("\(statement)") - }) + } - let (state_result, _) = try! #UseOkResult(runtime.run(withArguments: ArgumentList(), inExecution: pe)) + let (state_result, _) = try! #UseOkResult(runtime.run(withArguments: ArgumentList(), inExecution: ProgramExecution(ev))) #expect(AsInstantiatedParserState(state_result) == P4Lang.accept) @@ -90,12 +90,11 @@ import TreeSitterP4 var expressions_evaluated: [String] = Array() - let pe = ProgramExecution().setExpressionInterloper() { expression, result, execution in - print("Expression: \(expression)") + let ev = InterloperEvaluator().setExpressionInterloper() { expression, result, execution in expressions_evaluated.append("\(expression)") } - let (state_result, _) = try! #UseOkResult(runtime.run(withArguments: ArgumentList(), inExecution: pe)) + let (state_result, _) = try! #UseOkResult(runtime.run(withArguments: ArgumentList(), inExecution: ProgramExecution(ev))) #expect(AsInstantiatedParserState(state_result) == P4Lang.accept)