compiler, runtime, testing, common: Centralize Execution/Evaluation
Centralize the execution of statements and evaluation of expressions so that the user can specify a debugging "callback" after every execution/evaluation. The callback can be used for myriad things, but it seems likely that it will be useful for implementing: 1. Testing 2. Debugger Signed-off-by: Will Hawkins <hawkinsw@obs.cr>
This commit is contained in:
@@ -15,25 +15,32 @@
|
||||
// You should have received a copy of the GNU General Public License
|
||||
// along with this program. If not, see <https://www.gnu.org/licenses/>.
|
||||
|
||||
public typealias StatementInterloper = (EvaluatableStatement, ControlFlow, ProgramExecution) -> Void
|
||||
public typealias ExpressionInterloper = (EvaluatableExpression, Result<P4Value>, ProgramExecution) -> Void
|
||||
|
||||
open class ProgramExecution: CustomStringConvertible {
|
||||
public var scopes: VarValueScopes = VarValueScopes()
|
||||
let initialValues: VarValueScopes?
|
||||
var globalValues: VarValueScopes?
|
||||
var error: Error?
|
||||
var debug: DebugLevel = DebugLevel.Error
|
||||
var statement_interloper: StatementInterloper?
|
||||
var expression_interloper: ExpressionInterloper?
|
||||
|
||||
init(copy: ProgramExecution) {
|
||||
self.scopes = copy.scopes
|
||||
self.initialValues = copy.initialValues
|
||||
self.globalValues = copy.globalValues
|
||||
self.error = copy.error
|
||||
self.debug = copy.debug
|
||||
self.statement_interloper = copy.statement_interloper
|
||||
self.expression_interloper = copy.expression_interloper
|
||||
}
|
||||
|
||||
public init() {
|
||||
initialValues = .none
|
||||
globalValues = .none
|
||||
}
|
||||
|
||||
public init(withGlobalValues values: VarValueScopes) {
|
||||
initialValues = values
|
||||
globalValues = values
|
||||
}
|
||||
|
||||
open var description: String {
|
||||
@@ -64,6 +71,26 @@ 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
|
||||
}
|
||||
@@ -101,9 +128,17 @@ open class ProgramExecution: CustomStringConvertible {
|
||||
return new_pe
|
||||
}
|
||||
|
||||
public func initial_values() -> VarValueScopes? {
|
||||
return self.initialValues
|
||||
public func getGlobalValues() -> VarValueScopes {
|
||||
return self.globalValues ?? VarValueScopes()
|
||||
}
|
||||
|
||||
public func setGlobalValues(_ global_values: VarValueScopes) -> ProgramExecution {
|
||||
let new_pe = ProgramExecution(copy: self)
|
||||
new_pe.globalValues = global_values
|
||||
return new_pe
|
||||
}
|
||||
|
||||
|
||||
}
|
||||
|
||||
/// A scope that resolves variable identifiers to their values.
|
||||
|
||||
@@ -117,24 +117,13 @@ public enum Result<OKT>: Equatable {
|
||||
}
|
||||
}
|
||||
|
||||
extension Result where OKT: CustomStringConvertible {
|
||||
extension Result: CustomStringConvertible where OKT: CustomStringConvertible {
|
||||
public var description: String {
|
||||
switch self {
|
||||
case Result.Error(let e):
|
||||
return e.msg
|
||||
case Result.Ok(let o):
|
||||
return "\(o)"
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
extension Result: CustomStringConvertible {
|
||||
public var description: String {
|
||||
switch self {
|
||||
case Result.Error(let e):
|
||||
return e.msg
|
||||
case Result.Ok(_):
|
||||
return "Ok"
|
||||
return "Ok: \(o)"
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
@@ -90,7 +90,7 @@ public struct ParameterList: CustomStringConvertible, Equatable {
|
||||
public struct ArgumentList {
|
||||
public let arguments: [Argument]
|
||||
|
||||
public init(_ arguments: [Argument]) {
|
||||
public init(_ arguments: [Argument] = []) {
|
||||
self.arguments = arguments
|
||||
}
|
||||
|
||||
|
||||
@@ -32,7 +32,8 @@ public func Call<T>(
|
||||
for (parameter, argument) in zip(params.parameters, args.arguments) {
|
||||
let arg_idx = argument.index
|
||||
let arg_value = argument.argument
|
||||
let maybe_argument_value = arg_value.evaluate(execution: called_execution)
|
||||
//let maybe_argument_value = arg_value.evaluate(execution: called_execution)
|
||||
let maybe_argument_value = 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)")),
|
||||
@@ -82,3 +83,63 @@ public func Call<T>(
|
||||
}
|
||||
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<P4Value>, 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)
|
||||
|
||||
}
|
||||
|
||||
@@ -30,14 +30,14 @@ extension SelectCaseExpression: EvaluatableExpression {
|
||||
|
||||
extension SelectExpression: EvaluatableExpression {
|
||||
public func evaluate(execution: ProgramExecution) -> (Result<P4Value>, ProgramExecution) {
|
||||
switch self.selector.evaluate(execution: execution) {
|
||||
switch 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) = sce.key.evaluate(
|
||||
execution: updated_execution),
|
||||
if case (.Ok(let kse), let updated_execution) = EvaluateExpression(sce.key, inExecution: updated_execution),
|
||||
kse.eq(selector_value)
|
||||
{
|
||||
let result = sce.evaluate(execution: updated_execution)
|
||||
//let result = sce.evaluate(execution: updated_execution)
|
||||
let result = EvaluateExpression(sce, inExecution: updated_execution)
|
||||
return result
|
||||
}
|
||||
}
|
||||
@@ -210,12 +210,14 @@ public func binary_int_math_operator_checker(
|
||||
extension BinaryOperatorExpression: EvaluatableExpression {
|
||||
public func evaluate(execution: ProgramExecution) -> (Result<P4Value>, ProgramExecution) {
|
||||
let updated_execution = execution
|
||||
let maybe_evaluated_left = self.left.evaluate(execution: updated_execution)
|
||||
//let maybe_evaluated_left = self.left.evaluate(execution: updated_execution)
|
||||
let maybe_evaluated_left = 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 = self.right.evaluate(execution: updated_execution)
|
||||
let maybe_evaluated_right = EvaluateExpression(self.right, inExecution: updated_execution)
|
||||
guard case (.Ok(let evaluated_right), let updated_execution) = maybe_evaluated_right else {
|
||||
return maybe_evaluated_right
|
||||
}
|
||||
@@ -231,12 +233,14 @@ extension BinaryOperatorExpression: EvaluatableExpression {
|
||||
extension ArrayAccessExpression: EvaluatableExpression {
|
||||
public func evaluate(execution: ProgramExecution) -> (Result<P4Value>, ProgramExecution) {
|
||||
let updated_execution = execution
|
||||
let maybe_name = self.name.evaluate(execution: updated_execution)
|
||||
//let maybe_name = self.name.evaluate(execution: updated_execution)
|
||||
let maybe_name = 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 = self.indexor.evaluate(execution: updated_execution)
|
||||
let maybe_indexor = EvaluateExpression(self.indexor, inExecution: updated_execution)
|
||||
guard case (.Ok(let indexor), let updated_execution) = maybe_indexor else {
|
||||
return maybe_indexor
|
||||
}
|
||||
@@ -265,7 +269,8 @@ extension ArrayAccessExpression: EvaluatableLValueExpression {
|
||||
) -> Common.Result<(Common.VarValueScopes, P4Value)> {
|
||||
|
||||
let updated_execution = execution
|
||||
let maybe_value = self.name.evaluate(execution: updated_execution)
|
||||
//let maybe_value = self.name.evaluate(execution: updated_execution)
|
||||
let maybe_value = 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()!)"))
|
||||
@@ -275,7 +280,8 @@ extension ArrayAccessExpression: EvaluatableLValueExpression {
|
||||
}
|
||||
|
||||
// Now, get the indexor!
|
||||
let maybe_indexor_value = self.indexor.evaluate(execution: updated_execution)
|
||||
//let maybe_indexor_value = self.indexor.evaluate(execution: updated_execution)
|
||||
let maybe_indexor_value = 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()!)")
|
||||
@@ -341,7 +347,8 @@ extension FieldAccessExpression: EvaluatableExpression {
|
||||
public func evaluate(execution: ProgramExecution) -> (Result<P4Value>, ProgramExecution) {
|
||||
|
||||
let updated_execution = execution
|
||||
let maybe_struct = self.strct.evaluate(execution: updated_execution)
|
||||
//let maybe_struct = self.strct.evaluate(execution: updated_execution)
|
||||
let maybe_struct = EvaluateExpression(self.strct, inExecution: updated_execution)
|
||||
guard case (.Ok(let strct), let updated_execution) = maybe_struct else {
|
||||
return maybe_struct
|
||||
}
|
||||
@@ -375,7 +382,8 @@ 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 = self.strct.evaluate(execution: updated_execution)
|
||||
let maybe_value = 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()!)"))
|
||||
@@ -444,7 +452,8 @@ extension FieldAccessExpression: EvaluatableLValueExpression {
|
||||
|
||||
extension KeysetExpression: EvaluatableExpression {
|
||||
public func evaluate(execution: ProgramExecution) -> (Result<P4Value>, ProgramExecution) {
|
||||
return self.key.evaluate(execution: execution)
|
||||
//return self.key.evaluate(execution: execution)
|
||||
return EvaluateExpression(self.key, inExecution: execution)
|
||||
}
|
||||
|
||||
public func type() -> P4Type {
|
||||
|
||||
@@ -21,7 +21,8 @@ import P4Lang
|
||||
extension ParserAssignmentStatement: EvaluatableStatement {
|
||||
public func evaluate(execution: ProgramExecution) -> (ControlFlow, ProgramExecution) {
|
||||
let updated_execution = execution
|
||||
let result = self.value.evaluate(execution: updated_execution)
|
||||
//let result = self.value.evaluate(execution: updated_execution)
|
||||
let result = 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()!))
|
||||
}
|
||||
@@ -43,19 +44,23 @@ extension ParserStateDirectTransition: EvaluatableParserState {
|
||||
) -> (any EvaluatableParserState, Common.ProgramExecution) {
|
||||
var program = program.enter_scope()
|
||||
|
||||
for statement in statements {
|
||||
let (control_flow, next_program) = statement.evaluate(execution: program)
|
||||
switch control_flow {
|
||||
case .Next: program = next_program // Ok!
|
||||
case .Error: return (reject, next_program)
|
||||
default:
|
||||
return (
|
||||
reject,
|
||||
next_program.setError(
|
||||
error: Error(withMessage: "Invalid control flow (\(control_flow) in parser)"))
|
||||
)
|
||||
}
|
||||
|
||||
let (control_flow, next_execution) = ExecuteStatement(statements, handleResult: { (control_flow, execution) in
|
||||
return (control_flow, execution)
|
||||
}, inExecution: program)
|
||||
|
||||
|
||||
switch control_flow {
|
||||
case .Next: program = next_execution
|
||||
case .Error: return (reject, next_execution.exit_scope())
|
||||
default:
|
||||
return (
|
||||
reject,
|
||||
next_execution.exit_scope().setError(
|
||||
error: Error(withMessage: "Invalid control flow (\(control_flow) in parser)"))
|
||||
)
|
||||
}
|
||||
|
||||
let res = program.scopes.lookup(identifier: get_next_state())
|
||||
|
||||
if case .Ok(let value) = res {
|
||||
@@ -79,7 +84,6 @@ extension ParserStateDirectTransition: EvaluatableParserState {
|
||||
}
|
||||
|
||||
extension ParserStateNoTransition: EvaluatableParserState {
|
||||
|
||||
public func execute(
|
||||
program: Common.ProgramExecution
|
||||
) -> (any EvaluatableParserState, Common.ProgramExecution) {
|
||||
@@ -96,28 +100,30 @@ extension ParserStateNoTransition: EvaluatableParserState {
|
||||
}
|
||||
|
||||
extension ParserStateSelectTransition: EvaluatableParserState {
|
||||
|
||||
public func execute(
|
||||
program: Common.ProgramExecution
|
||||
) -> (any EvaluatableParserState, Common.ProgramExecution) {
|
||||
var program = program.enter_scope()
|
||||
|
||||
// First, evaluate the statements.
|
||||
for statement in statements {
|
||||
let (control_flow, next_program) = statement.evaluate(execution: program)
|
||||
switch control_flow {
|
||||
case .Next: program = next_program // Ok!
|
||||
case .Error: return (reject, next_program)
|
||||
default:
|
||||
return (
|
||||
reject,
|
||||
next_program.setError(
|
||||
error: Error(withMessage: "Invalid control flow (\(control_flow) in parser)"))
|
||||
)
|
||||
}
|
||||
let (control_flow, next_execution) = ExecuteStatement(statements, handleResult: { (control_flow, execution) in
|
||||
return (control_flow, execution)
|
||||
}, inExecution: program)
|
||||
|
||||
|
||||
switch control_flow {
|
||||
case .Next: program = next_execution
|
||||
case .Error: return (reject, next_execution.exit_scope())
|
||||
default:
|
||||
return (
|
||||
reject,
|
||||
next_execution.exit_scope().setError(
|
||||
error: Error(withMessage: "Invalid control flow (\(control_flow) in parser)"))
|
||||
)
|
||||
}
|
||||
|
||||
switch self.selectExpression.evaluate(execution: program) {
|
||||
|
||||
//switch self.selectExpression.evaluate(execution: program) {
|
||||
switch 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())
|
||||
@@ -156,10 +162,8 @@ extension Parser: LibraryCallable {
|
||||
withValue: P4Value(reject, P4Type.ReadOnly(reject.type())))
|
||||
|
||||
// Add initial values to the global scope
|
||||
if let initial = execution.initial_values() {
|
||||
for (name, value) in initial {
|
||||
execution = execution.declare(identifier: name, withValue: value)
|
||||
}
|
||||
for (name, value) in execution.getGlobalValues() {
|
||||
execution = execution.declare(identifier: name, withValue: value)
|
||||
}
|
||||
|
||||
// First, add every state to the scope!
|
||||
|
||||
@@ -29,22 +29,22 @@ public struct ParserRuntime: CustomStringConvertible {
|
||||
self.initialValues = .none
|
||||
}
|
||||
|
||||
init(parser: Parser, withInitialValues initial: VarValueScopes?) {
|
||||
init(parser: Parser, withGlobalValues initial: VarValueScopes?) {
|
||||
self.parser = parser
|
||||
self.initialValues = initial
|
||||
}
|
||||
|
||||
/// Create a parser runtime from a P4 program
|
||||
public static func create(program: P4Lang.Program) -> Result<ParserRuntime> {
|
||||
return ParserRuntime.create(program: program, withInitialValues: .none)
|
||||
return ParserRuntime.create(program: program, withGlobalValues: .none)
|
||||
}
|
||||
|
||||
public static func create(
|
||||
program: P4Lang.Program, withInitialValues initial: VarValueScopes?
|
||||
program: P4Lang.Program, withGlobalValues initial: VarValueScopes?
|
||||
) -> Result<ParserRuntime> {
|
||||
return switch program.starting_parser() {
|
||||
case .Ok(let parser):
|
||||
.Ok(P4Runtime.ParserRuntime(parser: parser, withInitialValues: initial))
|
||||
.Ok(P4Runtime.ParserRuntime(parser: parser, withGlobalValues: initial))
|
||||
case .Error(let error): .Error(error)
|
||||
}
|
||||
}
|
||||
@@ -52,12 +52,10 @@ public struct ParserRuntime: CustomStringConvertible {
|
||||
/// Run a P4 parser with no arguments
|
||||
public func run() -> Result<(ParserState, ProgramExecution)> {
|
||||
return self.run(withArguments: ArgumentList([]))
|
||||
|
||||
}
|
||||
|
||||
/// Run the P4 parser on a given packet
|
||||
public func run(withArguments arguments: ArgumentList) -> Result<(ParserState, ProgramExecution)>
|
||||
{
|
||||
|
||||
public func run(withArguments arguments: ArgumentList) -> Result<(ParserState, ProgramExecution)> {
|
||||
let pe =
|
||||
if let initial = initialValues {
|
||||
ProgramExecution(withGlobalValues: initial)
|
||||
@@ -65,6 +63,19 @@ public struct ParserRuntime: CustomStringConvertible {
|
||||
ProgramExecution()
|
||||
}
|
||||
|
||||
return self.run(withArguments: arguments, inExecution: pe)
|
||||
}
|
||||
|
||||
/// Run the P4 parser on a given packet
|
||||
public func run(withArguments arguments: ArgumentList, inExecution pe: ProgramExecution) -> Result<(ParserState, ProgramExecution)>
|
||||
{
|
||||
|
||||
let pe = if let globals = initialValues {
|
||||
pe.setGlobalValues(globals)
|
||||
} else {
|
||||
pe
|
||||
}
|
||||
|
||||
let (end_state, execution) = parser.call(execution: pe, arguments: arguments)
|
||||
if let error = execution.getError() {
|
||||
return .Error(error)
|
||||
|
||||
@@ -20,29 +20,31 @@ import P4Lang
|
||||
|
||||
extension BlockStatement: EvaluatableStatement {
|
||||
public func evaluate(execution: ProgramExecution) -> (ControlFlow, ProgramExecution) {
|
||||
var execution = execution
|
||||
for s in self.statements {
|
||||
let (control_flow, next_execution) = s.evaluate(execution: execution)
|
||||
switch control_flow {
|
||||
case ControlFlow.Return(let value): return (ControlFlow.Return(value), next_execution)
|
||||
case ControlFlow.Next: execution = next_execution
|
||||
case ControlFlow.Error: return (ControlFlow.Error, next_execution)
|
||||
default:
|
||||
return (
|
||||
ControlFlow.Next,
|
||||
next_execution.setError(
|
||||
error: Error(withMessage: "Invalid control flow \(control_flow) in block statement"))
|
||||
)
|
||||
}
|
||||
}
|
||||
return (ControlFlow.Next, execution)
|
||||
print("I am going to evaluate a block statement?")
|
||||
return ExecuteStatement(
|
||||
self.statements,
|
||||
handleResult: { (cf, execution) in
|
||||
switch cf {
|
||||
case ControlFlow.Return(let value): return (ControlFlow.Return(value), execution)
|
||||
case ControlFlow.Next: return (cf, execution)
|
||||
case ControlFlow.Error: return (ControlFlow.Error, execution)
|
||||
default:
|
||||
return (
|
||||
ControlFlow.Error,
|
||||
execution.setError(
|
||||
error: Error(withMessage: "Invalid control flow \(cf) in block statement"))
|
||||
)
|
||||
}
|
||||
},
|
||||
inExecution: execution)
|
||||
}
|
||||
}
|
||||
|
||||
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) = self.initializer.evaluate(execution: execution)
|
||||
case (.Ok(let initial_value), let execution) = EvaluateExpression(self.initializer, inExecution: execution)
|
||||
else {
|
||||
return (
|
||||
ControlFlow.Error,
|
||||
@@ -58,8 +60,8 @@ extension VariableDeclarationStatement: EvaluatableStatement {
|
||||
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) = self.condition.evaluate(execution: execution)
|
||||
case (.Ok(let evaluated_condition), let execution) = EvaluateExpression(self.condition, inExecution: execution)
|
||||
else {
|
||||
return (
|
||||
ControlFlow.Error,
|
||||
@@ -107,7 +109,8 @@ extension ExpressionStatement: EvaluatableStatement {
|
||||
public func evaluate(execution: ProgramExecution) -> (ControlFlow, ProgramExecution) {
|
||||
|
||||
// Evaluate, there might be side effects!
|
||||
return switch self.expression.evaluate(execution: execution) {
|
||||
//return switch self.expression.evaluate(execution: execution) {
|
||||
return switch 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))
|
||||
@@ -117,7 +120,8 @@ extension ExpressionStatement: EvaluatableStatement {
|
||||
|
||||
extension ReturnStatement: EvaluatableStatement {
|
||||
public func evaluate(execution: ProgramExecution) -> (ControlFlow, ProgramExecution) {
|
||||
return switch self.value.evaluate(execution: execution) {
|
||||
//return switch self.value.evaluate(execution: execution) {
|
||||
return switch 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))
|
||||
}
|
||||
|
||||
Reference in New Issue
Block a user