Chromium Code Reviews| Index: pkg/kernel/lib/interpreter/interpreter.dart |
| diff --git a/pkg/kernel/lib/interpreter/interpreter.dart b/pkg/kernel/lib/interpreter/interpreter.dart |
| index 857d065f61b08c16c298c3f500c05fbfe5bcb072..156e681eda2be78a3a101b8d21ad84797ec99cc0 100644 |
| --- a/pkg/kernel/lib/interpreter/interpreter.dart |
| +++ b/pkg/kernel/lib/interpreter/interpreter.dart |
| @@ -24,8 +24,9 @@ class Interpreter { |
| assert(program.libraries.isEmpty); |
| Procedure mainMethod = program.mainMethod; |
| Statement statementBlock = mainMethod.function.body; |
| - Continuation cont = new Continuation(statementBlock, new State.initial()); |
| - visitor.trampolinedExecution(cont); |
| + StatementConfiguration configuration = |
| + new StatementConfiguration(statementBlock, new State.initial()); |
| + visitor.trampolinedExecution(configuration); |
| } |
| } |
| @@ -74,168 +75,174 @@ class Environment { |
| } |
| /// Evaluate expressions. |
| -class Evaluator extends ExpressionVisitor1<Value> { |
| - Value eval(Expression expr, Environment env) => expr.accept1(this, env); |
| +class Evaluator extends ExpressionVisitor1<Configuration> { |
|
Kevin Millikin (Google)
2017/04/20 10:50:20
We should make ExpressionVisitor1 parameterized ov
zhivkag
2017/04/20 13:21:36
Acknowledged. I will do it in a follow-up CL.
|
| + Configuration eval(Expression expr, ExpressionState state) => |
|
Kevin Millikin (Google)
2017/04/20 10:50:20
ExpressionState is ExpressionConfiguration without
zhivkag
2017/04/20 13:21:36
Acknowledged. I will do it in a follow-up CL.
|
| + expr.accept1(this, state); |
| - Value defaultExpression(Expression node, env) { |
| + Configuration defaultExpression(Expression node, state) { |
| throw new NotImplemented('Evaluation for expressions of type ' |
| '${node.runtimeType} is not implemented.'); |
| } |
| - Value visitInvalidExpression1(InvalidExpression node, env) { |
| + Configuration visitInvalidExpression1(InvalidExpression node, state) { |
| throw 'Invalid expression at ${node.location.toString()}'; |
| } |
| - Value visitVariableGet(VariableGet node, env) { |
| - return env.lookup(node.variable); |
| + Configuration visitVariableGet(VariableGet node, state) { |
| + Value value = state.environment.lookup(node.variable); |
| + return state.nextConfiguration(value); |
|
Kevin Millikin (Google)
2017/04/20 10:50:20
I think nextConfiguration is only needed because t
zhivkag
2017/04/20 13:21:36
Done.
|
| } |
| - Value visitVariableSet(VariableSet node, env) { |
| - return env.assign(node.variable, eval(node.value, env)); |
| + Configuration visitVariableSet(VariableSet node, state) { |
| + var cont = new VariableSetContinuation(state, node.variable); |
| + return new ExpressionConfiguration( |
| + node.value, state.withContinuation(cont)); |
| } |
| - Value visitPropertyGet(PropertyGet node, env) { |
| - Value receiver = eval(node.receiver, env); |
| - return receiver.class_.lookupGetter(node.name)(receiver); |
| + Configuration visitPropertyGet(PropertyGet node, state) { |
| + var cont = new PropertyGetContinuation(node.name, state); |
| + return new ExpressionConfiguration( |
| + node.receiver, state.withContinuation(cont)); |
| } |
| - Value visitPropertySet(PropertySet node, env) { |
| - Value receiver = eval(node.receiver, env); |
| - Value value = eval(node.value, env); |
| - receiver.class_.lookupSetter(node.name)(receiver, value); |
| - return value; |
| + Configuration visitPropertySet(PropertySet node, state) { |
| + var cont = new PropertySetContinuation(node.value, node.name, state); |
| + return new ExpressionConfiguration( |
| + node.receiver, state.withContinuation(cont)); |
| } |
| - Value visitDirectPropertyGet(DirectPropertyGet node, env) { |
| - Value receiver = eval(node.receiver, env); |
| - return receiver.class_.getProperty(receiver, node.target); |
| - } |
| - |
| - Value visitDirectPropertySet(DirectPropertySet node, env) { |
| - Value receiver = eval(node.receiver, env); |
| - Value value = eval(node.value, env); |
| - receiver.class_.setProperty(receiver, node.target, value); |
| - return value; |
| - } |
| + Configuration visitStaticGet(StaticGet node, state) => |
| + defaultExpression(node, state); |
| + Configuration visitStaticSet(StaticSet node, state) => |
| + defaultExpression(node, state); |
| - Value visitStaticGet(StaticGet node, env) => defaultExpression(node, env); |
| - Value visitStaticSet(StaticSet node, env) => defaultExpression(node, env); |
| - |
| - Value visitStaticInvocation(StaticInvocation node, env) { |
| + Configuration visitStaticInvocation(StaticInvocation node, state) { |
| if ('print' == node.name.toString()) { |
| - // Special evaluation of print. |
| - var res = eval(node.arguments.positional[0], env); |
| - print(res.value); |
| - return Value.nullInstance; |
| + return new ExpressionConfiguration(node.arguments.positional.first, |
| + state.withContinuation(new PrintContinuation(state))); |
| } else { |
| - throw new NotImplemented('Support for statement type ' |
| - '${node.runtimeType} is not implemented'); |
| + // Currently supports only static invocations with no arguments. |
| + if (node.arguments.positional.isEmpty && node.arguments.named.isEmpty) { |
| + return new StatementConfiguration( |
| + node.target.function.body, |
| + state.statementState |
|
Kevin Millikin (Google)
2017/04/20 10:50:20
This doesn't seem like the right StatementState he
zhivkag
2017/04/20 13:21:36
Done.
|
| + .withExpressionContinuation(state.continuation)); |
| + } |
| + throw new NotImplemented( |
| + 'Support for static invocation with arguments is not implemented'); |
| } |
| } |
| - Value visitMethodInvocation(MethodInvocation node, env) { |
| + Configuration visitMethodInvocation(MethodInvocation node, state) { |
| // Currently supports only method invocation with <2 arguments and is used |
| // to evaluate implemented operators for int, double and String values. |
| - var receiver = eval(node.receiver, env); |
| - if (node.arguments.positional.isNotEmpty) { |
| - var argValue = eval(node.arguments.positional.first, env); |
| - return receiver.invokeMethod(node.name, argValue); |
| - } else { |
| - return receiver.invokeMethod(node.name); |
| - } |
| + var cont = |
| + new MethodInvocationContinuation(node.arguments, node.name, state); |
| + |
| + return new ExpressionConfiguration( |
| + node.receiver, state.withContinuation(cont)); |
| } |
| - Value visitConstructorInvocation(ConstructorInvocation node, env) { |
| + Configuration visitConstructorInvocation(ConstructorInvocation node, state) { |
| Class class_ = new Class(node.target.enclosingClass.reference); |
| - Environment emptyEnv = new Environment.empty(); |
| // Currently we don't support initializers. |
| // TODO: Modify to respect dart semantics for initialization. |
| // 1. Init fields and eval initializers, repeat the same with super. |
| // 2. Eval the Function body of the constructor. |
| - List<Value> fields = class_.instanceFields |
| - .map((Field f) => eval(f.initializer ?? new NullLiteral(), emptyEnv)) |
| - .toList(growable: false); |
| + List<Value> fields = <Value>[]; |
| - return new ObjectValue(class_, fields); |
| + return state.nextConfiguration(new ObjectValue(class_, fields)); |
| } |
| - Value visitNot(Not node, env) { |
| - Value operand = eval(node.operand, env).toBoolean(); |
| - return identical(operand, Value.trueInstance) |
| - ? Value.falseInstance |
| - : Value.trueInstance; |
| + Configuration visitNot(Not node, state) { |
| + return new ExpressionConfiguration( |
| + node.operand, state.withContinuation(new NotContinuation(state))); |
| } |
| - Value visitLogicalExpression(LogicalExpression node, env) { |
| + Configuration visitLogicalExpression(LogicalExpression node, state) { |
| if ('||' == node.operator) { |
| - BoolValue left = eval(node.left, env).toBoolean(); |
| - return identical(left, Value.trueInstance) |
| - ? Value.trueInstance |
| - : eval(node.right, env).toBoolean(); |
| + var cont = new OrContinuation(node.right, state); |
| + return new ExpressionConfiguration( |
| + node.left, state.withContinuation(cont)); |
| } else { |
| assert('&&' == node.operator); |
| - BoolValue left = eval(node.left, env).toBoolean(); |
| - return identical(left, Value.falseInstance) |
| - ? Value.falseInstance |
| - : eval(node.right, env).toBoolean(); |
| + var cont = new AndContinuation(node.right, state); |
| + return new ExpressionConfiguration( |
| + node.left, state.withContinuation(cont)); |
| } |
| } |
| - Value visitConditionalExpression(ConditionalExpression node, env) { |
| - var condition = eval(node.condition, env).toBoolean(); |
| - return identical(condition, Value.trueInstance) |
| - ? eval(node.then, env) |
| - : eval(node.otherwise, env); |
| + Configuration visitConditionalExpression(ConditionalExpression node, state) { |
| + var cont = new ConditionalContinuation(node.then, node.otherwise, state); |
| + return new ExpressionConfiguration( |
| + node.condition, state.withContinuation(cont)); |
| } |
| - Value visitStringConcatenation(StringConcatenation node, env) { |
| - StringBuffer res = new StringBuffer(); |
| - for (Expression e in node.expressions) { |
| - res.write(eval(e, env).value); |
| - } |
| - return new StringValue(res.toString()); |
| + Configuration visitStringConcatenation(StringConcatenation node, state) { |
| + var cont = new StringConcatenationContinuation(node.expressions, state); |
| + return new ExpressionConfiguration( |
| + node.expressions.first, state.withContinuation(cont)); |
| } |
| // Evaluation of BasicLiterals. |
| - Value visitStringLiteral(StringLiteral node, env) => |
| - new StringValue(node.value); |
| - Value visitIntLiteral(IntLiteral node, env) => new IntValue(node.value); |
| - Value visitDoubleLiteral(DoubleLiteral node, env) => |
| - new DoubleValue(node.value); |
| - Value visitBoolLiteral(BoolLiteral node, env) => |
| - node.value ? Value.trueInstance : Value.falseInstance; |
| - Value visitNullLiteral(NullLiteral node, env) => Value.nullInstance; |
| + Configuration visitStringLiteral(StringLiteral node, state) { |
| + return state.nextConfiguration(new StringValue(node.value)); |
| + } |
| + |
| + Configuration visitIntLiteral(IntLiteral node, state) { |
| + return state.nextConfiguration(new IntValue(node.value)); |
| + } |
| + |
| + Configuration visitDoubleLiteral(DoubleLiteral node, state) { |
| + return state.nextConfiguration(new DoubleValue(node.value)); |
| + } |
| + |
| + Configuration visitBoolLiteral(BoolLiteral node, state) { |
| + Value value = node.value ? Value.trueInstance : Value.falseInstance; |
| + return state.nextConfiguration(value); |
| + } |
| + |
| + Configuration visitNullLiteral(NullLiteral node, state) { |
| + return state.nextConfiguration(Value.nullInstance); |
| + } |
| - Value visitLet(Let node, env) { |
| - var value = eval(node.variable.initializer, env); |
| - var letEnv = new Environment(env); |
| - letEnv.expand(node.variable, value); |
| - return eval(node.body, letEnv); |
| + Configuration visitLet(Let node, state) { |
| + var letCont = new LetContinuation(node.variable, node.body, state); |
| + return new ExpressionConfiguration( |
| + node.variable.initializer, state.withContinuation(letCont)); |
| } |
| } |
| -/// Represents a state which consists of current environment, continuation to be |
| -/// applied and the current label. |
| +/// Represents a state for statement execution. |
| class State { |
| final Environment environment; |
| final Label labels; |
| - final Continuation continuation; |
| + final Configuration configuration; |
|
Kevin Millikin (Google)
2017/04/20 10:50:20
This is always a StatementConfiguration isn't it (
zhivkag
2017/04/20 13:21:36
Done.
|
| - State(this.environment, this.labels, this.continuation); |
| - State.initial() : this(new Environment.empty(), null, null); |
| + final ExpressionContinuation expressionContinuation; |
|
Dmitry Stefantsov
2017/04/12 12:53:11
It think it would be easier to understand the inte
Kevin Millikin (Google)
2017/04/20 10:50:20
It's 'returnContinuaton', which seems like a good
zhivkag
2017/04/20 13:21:36
Done.
|
| + |
| + State(this.environment, this.labels, this.configuration, |
| + this.expressionContinuation); |
| + |
| + State.initial() : this(new Environment.empty(), null, null, null); |
| State withEnvironment(Environment env) { |
| - return new State(env, labels, continuation); |
| + return new State(env, labels, configuration, expressionContinuation); |
| } |
| State withBreak(Statement stmt) { |
| + Label breakLabels = new Label(stmt, configuration, labels); |
| return new State( |
| - environment, new Label(stmt, continuation, labels), continuation); |
| + environment, breakLabels, configuration, expressionContinuation); |
| } |
| - State withContinuation(Continuation cont) { |
| - return new State(environment, labels, cont); |
| + State withConfiguration(Configuration config) { |
| + return new State(environment, labels, config, expressionContinuation); |
| + } |
| + |
| + State withExpressionContinuation(ExpressionContinuation cont) { |
| + return new State(environment, labels, configuration, cont); |
| } |
| Label lookupLabel(LabeledStatement s) { |
| @@ -244,22 +251,47 @@ class State { |
| } |
| } |
| -/// Represent the continuation for execution of statement. |
| -class Continuation { |
| - final Statement statement; |
| - final State state; |
| +/// Represents a state for expression evaluation. |
| +class ExpressionState { |
| + /// Enclosing statement state. |
| + final State statementState; |
|
Dmitry Stefantsov
2017/04/12 12:53:11
Same as above with "expressionContinuation", I thi
Kevin Millikin (Google)
2017/04/20 10:50:20
I think it's unnecessary as described above.
zhivkag
2017/04/20 13:21:36
Acknowledged.
zhivkag
2017/04/20 13:21:36
Acknowledged.
|
| + |
| + /// Environment in which the expression is evaluated. |
| + final Environment environment; |
| + |
| + /// Next continuation to be applied. |
| + final ExpressionContinuation continuation; |
| + |
| + ExpressionState(this.statementState, this.environment, this.continuation); |
| - Continuation(this.statement, this.state); |
| + ExpressionState.fromStatementState(State state) |
| + : this(state, state.environment, null); |
| + |
| + ExpressionState withEnvironment(Environment env) { |
| + return new ExpressionState(statementState, env, continuation); |
| + } |
| + |
| + ExpressionState withContinuation(ExpressionContinuation cont) { |
| + return new ExpressionState(statementState, environment, cont); |
| + } |
| + |
| + /// Returns the next [Configuration] |
| + Configuration nextConfiguration(Value v) { |
| + if (continuation != null) { |
| + return new ContinuationConfiguration(v, continuation); |
| + } |
| + return statementState.configuration; |
| + } |
| } |
| /// Represents a labeled statement, the corresponding continuation and the |
| /// enclosing label. |
| class Label { |
| final LabeledStatement statement; |
| - final Continuation continuation; |
| + final StatementConfiguration configuration; |
| final Label enclosingLabel; |
| - Label(this.statement, this.continuation, this.enclosingLabel); |
| + Label(this.statement, this.configuration, this.enclosingLabel); |
| Label lookupLabel(LabeledStatement s) { |
| if (identical(s, statement)) return this; |
| @@ -268,6 +300,305 @@ class Label { |
| } |
| } |
| +abstract class Configuration { |
| + /// Executes the current and returns the next configuration. |
| + Configuration step(StatementExecuter executer); |
| +} |
| + |
| +/// Represents the configuration for execution of statement. |
| +class StatementConfiguration extends Configuration { |
| + final Statement statement; |
| + final State state; |
| + |
| + StatementConfiguration(this.statement, this.state); |
| + |
| + Configuration step(StatementExecuter executer) => |
| + executer.exec(statement, state); |
| +} |
| + |
| +/// Represents the configuration for applying an [ExpressionContinuation]. |
| +class ContinuationConfiguration extends Configuration { |
| + final Value value; |
| + final ExpressionContinuation continuation; |
| + |
| + ContinuationConfiguration(this.value, this.continuation); |
|
Kevin Millikin (Google)
2017/04/20 10:50:20
I prefer the argument order to be swapped here (sw
zhivkag
2017/04/20 13:21:36
Done.
|
| + |
| + Configuration step(StatementExecuter executer) => continuation(value); |
| +} |
| + |
| +/// Represents the configuration for evaluating an [Expression]. |
| +class ExpressionConfiguration extends Configuration { |
| + final Expression expression; |
| + final ExpressionState state; |
| + |
| + ExpressionConfiguration(this.expression, this.state); |
| + |
| + Configuration step(StatementExecuter executer) => |
| + executer.eval(expression, state); |
| +} |
| + |
| +/// Represents an expression continuation. |
| +abstract class ExpressionContinuation { |
| + ExpressionState get state; |
|
Kevin Millikin (Google)
2017/04/20 10:50:20
I'm not sure that every expression continuation sh
zhivkag
2017/04/20 13:21:36
Done.
|
| + |
| + Configuration call(Value v); |
| +} |
| + |
| +class PrintContinuation extends ExpressionContinuation { |
| + final ExpressionState state; |
| + |
| + PrintContinuation(this.state); |
| + |
| + Configuration call(Value v) { |
| + print(v.value); |
| + return state.nextConfiguration(Value.nullInstance); |
| + } |
| +} |
| + |
| +class PropertyGetContinuation extends ExpressionContinuation { |
| + final Name name; |
| + final ExpressionState state; |
| + |
| + PropertyGetContinuation(this.name, this.state); |
| + |
| + Configuration call(Value receiver) { |
| + Value propertyValue = receiver.class_.lookupGetter(name)(receiver); |
|
Kevin Millikin (Google)
2017/04/20 10:50:20
Not for this change, but we will have to find a wa
zhivkag
2017/04/20 13:21:36
Indeed. This is sufficient for now only because we
|
| + return state.nextConfiguration(propertyValue); |
| + } |
| +} |
| + |
| +class PropertySetContinuation extends ExpressionContinuation { |
| + final Expression value; |
| + final Name setterName; |
| + final ExpressionState state; |
| + |
| + PropertySetContinuation(this.value, this.setterName, this.state); |
| + |
| + Configuration call(Value receiver) { |
| + Setter setter = receiver.class_.lookupSetter(setterName); |
|
Kevin Millikin (Google)
2017/04/20 10:50:20
The spec has that setters are looked up after eval
zhivkag
2017/04/20 13:21:36
Done.
|
| + var cont = new SetterContinuation(setter, receiver, state); |
| + return new ExpressionConfiguration(value, state.withContinuation(cont)); |
| + } |
| +} |
| + |
| +class SetterContinuation extends ExpressionContinuation { |
| + final Setter setter; |
| + final Value receiver; |
| + final ExpressionState state; |
| + |
| + SetterContinuation(this.setter, this.receiver, this.state); |
| + |
| + Configuration call(Value v) { |
| + setter(receiver, v); |
| + return state.nextConfiguration(v); |
| + } |
| +} |
| + |
| +class StaticInvocationContinuation extends ExpressionContinuation { |
| + final ExpressionState state; |
| + |
| + StaticInvocationContinuation(this.state); |
| + |
| + Configuration call(Value v) { |
| + return state.nextConfiguration(v); |
| + } |
| +} |
| + |
| +class MethodInvocationContinuation extends ExpressionContinuation { |
| + final Arguments arguments; |
| + final Name methodName; |
| + final ExpressionState state; |
| + |
| + MethodInvocationContinuation(this.arguments, this.methodName, this.state); |
| + |
| + Configuration call(Value receiver) { |
| + if (arguments.positional.isEmpty) { |
| + Value returnValue = receiver.invokeMethod(methodName); |
| + return state.nextConfiguration(returnValue); |
| + } |
| + var cont = |
| + new ArgumentsContinuation(receiver, methodName, arguments, state); |
| + |
| + return new ExpressionConfiguration( |
| + arguments.positional.first, state.withContinuation(cont)); |
| + } |
| +} |
| + |
| +class ArgumentsContinuation extends ExpressionContinuation { |
| + final Value receiver; |
| + final Name methodName; |
| + final Arguments arguments; |
| + final ExpressionState state; |
| + |
| + ArgumentsContinuation( |
| + this.receiver, this.methodName, this.arguments, this.state); |
| + |
| + Configuration call(Value value) { |
| + // Currently evaluates only one argument, for simple method invocations |
| + // with 1 argument. |
| + Value returnValue = receiver.invokeMethod(methodName, value); |
| + return state.nextConfiguration(returnValue); |
| + } |
| +} |
| + |
| +class VariableSetContinuation extends ExpressionContinuation { |
| + final ExpressionState state; |
| + final VariableDeclaration variable; |
| + |
| + VariableSetContinuation(this.state, this.variable); |
| + |
| + Configuration call(Value value) { |
| + state.environment.assign(variable, value); |
| + return state.nextConfiguration(value); |
| + } |
| +} |
| + |
| +class NotContinuation extends ExpressionContinuation { |
| + final ExpressionState state; |
| + |
| + NotContinuation(this.state); |
| + |
| + Configuration call(Value value) { |
| + Value notValue = identical(Value.trueInstance, value) |
| + ? Value.falseInstance |
| + : Value.trueInstance; |
| + return state.nextConfiguration(notValue); |
| + } |
| +} |
| + |
| +class OrContinuation extends ExpressionContinuation { |
| + final Expression right; |
| + final ExpressionState state; |
| + |
| + OrContinuation(this.right, this.state); |
| + |
| + Configuration call(Value left) { |
| + return identical(Value.trueInstance, left) |
| + ? state.nextConfiguration(Value.trueInstance) |
| + : new ExpressionConfiguration(right, state); |
| + } |
| +} |
| + |
| +class AndContinuation extends ExpressionContinuation { |
| + final Expression right; |
| + final ExpressionState state; |
| + |
| + AndContinuation(this.right, this.state); |
| + |
| + Configuration call(Value left) { |
| + return identical(Value.falseInstance, left) |
| + ? state.nextConfiguration(Value.falseInstance) |
| + : new ExpressionConfiguration(right, state); |
| + } |
| +} |
| + |
| +class ConditionalContinuation extends ExpressionContinuation { |
| + final Expression then; |
| + final Expression otherwise; |
| + final ExpressionState state; |
| + |
| + ConditionalContinuation(this.then, this.otherwise, this.state); |
| + |
| + Configuration call(Value value) { |
| + return identical(Value.trueInstance, value) |
| + ? new ExpressionConfiguration(then, state) |
| + : new ExpressionConfiguration(otherwise, state); |
| + } |
| +} |
| + |
| +class StringConcatenationContinuation extends ExpressionContinuation { |
| + final List<Expression> expressions; |
| + final ExpressionState state; |
| + |
| + int _currentPosition = 0; |
| + final List<Value> _values = <Value>[]; |
| + |
| + StringConcatenationContinuation(this.expressions, this.state); |
| + |
| + Configuration call(Value value) { |
| + _values.add(value); |
| + if (_values.length == expressions.length) { |
| + StringBuffer res = new StringBuffer(); |
| + |
| + for (int i = 0; i < expressions.length; i++) { |
| + res.write(_values[i].value); |
| + } |
| + |
| + Value value = new StringValue(res.toString()); |
| + return state.nextConfiguration(value); |
| + } |
| + return new ExpressionConfiguration( |
| + expressions[++_currentPosition], state.withContinuation(this)); |
| + } |
| +} |
| + |
| +class LetContinuation extends ExpressionContinuation { |
| + final VariableDeclaration variable; |
| + final Expression letBody; |
| + final ExpressionState state; |
| + |
| + LetContinuation(this.variable, this.letBody, this.state); |
| + |
| + Configuration call(Value value) { |
| + var letState = state.withEnvironment(new Environment(state.environment)); |
| + letState.environment.expand(variable, value); |
| + return new ExpressionConfiguration(letBody, letState); |
| + } |
| +} |
| + |
| +/// Represents the continuation for the condition expression in [WhileStatement]. |
| +class WhileConditionContinuation extends ExpressionContinuation { |
| + final WhileStatement node; |
| + final ExpressionState state; |
| + |
| + WhileConditionContinuation(this.node, this.state); |
| + |
| + StatementConfiguration call(Value v) { |
| + if (identical(v, Value.trueInstance)) { |
| + // Add configuration for the While statement to the linked list. |
| + StatementConfiguration config = |
| + new StatementConfiguration(node, state.statementState); |
| + // Configuration for the body of the loop. |
| + return new StatementConfiguration( |
| + node.body, state.statementState.withConfiguration(config)); |
| + } |
| + |
| + return state.statementState.configuration; |
| + } |
| +} |
| + |
| +/// Represents the continuation for the condition expression in [IfStatement]. |
| +class IfConditionContinuation extends ExpressionContinuation { |
| + final Statement then; |
| + final Statement otherwise; |
| + final ExpressionState state; |
| + |
| + IfConditionContinuation(this.then, this.otherwise, this.state); |
| + |
| + StatementConfiguration call(Value v) { |
| + if (identical(v, Value.trueInstance)) { |
| + return new StatementConfiguration(then, state.statementState); |
| + } else if (otherwise != null) { |
| + return new StatementConfiguration(otherwise, state.statementState); |
| + } |
| + return state.statementState.configuration; |
| + } |
| +} |
| + |
| +/// Represents the continuation for the initializer expression in |
| +/// [VariableDeclaration]. |
| +class VariableInitializerContinuation extends ExpressionContinuation { |
| + final VariableDeclaration variable; |
| + final ExpressionState state; |
| + |
| + VariableInitializerContinuation(this.variable, this.state); |
| + |
| + StatementConfiguration call(Value v) { |
| + state.statementState.environment.expand(variable, v); |
| + return state.statementState.configuration; |
| + } |
| +} |
| + |
| /// Executes statements. |
| /// |
| /// Execution of a statement completes in one of the following ways: |
| @@ -277,95 +608,109 @@ class Label { |
| /// returned and applied |
| /// - it returns with or without value, TBD |
| /// - it throws, TBD |
| -class StatementExecuter extends StatementVisitor1<Continuation> { |
| +class StatementExecuter extends StatementVisitor1<Configuration> { |
| Evaluator evaluator = new Evaluator(); |
| - void trampolinedExecution(Continuation continuation) { |
| - while (continuation != null) { |
| - continuation = exec(continuation.statement, continuation.state); |
| + void trampolinedExecution(Configuration configuration) { |
| + while (configuration != null) { |
| + configuration = configuration.step(this); |
| } |
| } |
| - Continuation exec(Statement statement, state) => |
| + Configuration exec(Statement statement, State state) => |
| statement.accept1(this, state); |
| - Value eval(Expression expression, env) => evaluator.eval(expression, env); |
| + Configuration eval(Expression expression, ExpressionState state) => |
| + evaluator.eval(expression, state); |
| - Continuation defaultStatement(Statement node, state) { |
| + Configuration defaultStatement(Statement node, state) { |
| throw notImplemented( |
| m: "Execution is not implemented for statement:\n$node "); |
| } |
| - Continuation visitInvalidStatement(InvalidStatement node, state) { |
| + Configuration visitInvalidStatement(InvalidStatement node, state) { |
| throw "Invalid statement at ${node.location}"; |
| } |
| - Continuation visitExpressionStatement(ExpressionStatement node, state) { |
| - eval(node.expression, state.environment); |
| - return state.continuation; |
| + Configuration visitExpressionStatement(ExpressionStatement node, state) { |
| + return new ExpressionConfiguration( |
| + node.expression, new ExpressionState.fromStatementState(state)); |
| } |
| - Continuation visitBlock(Block node, state) { |
| + Configuration visitBlock(Block node, state) { |
| if (node.statements.isEmpty) { |
| - return state.continuation; |
| + return state.configuration; |
| } |
| State blockState = |
| state.withEnvironment(new Environment(state.environment)); |
| - Continuation cont = state.continuation; |
| + StatementConfiguration configuration = state.configuration; |
| for (Statement s in node.statements.reversed) { |
| - cont = new Continuation(s, blockState.withContinuation(cont)); |
| + configuration = new StatementConfiguration( |
| + s, blockState.withConfiguration(configuration)); |
| } |
| - return cont; |
| + return configuration; |
| } |
| - Continuation visitEmptyStatement(EmptyStatement node, state) { |
| - return state.continuation; |
| + Configuration visitEmptyStatement(EmptyStatement node, state) { |
| + return state.configuration; |
| } |
| - Continuation visitIfStatement(IfStatement node, state) { |
| - Value cond = eval(node.condition, state.environment).toBoolean(); |
| - if (identical(Value.trueInstance, cond)) { |
| - return new Continuation(node.then, state); |
| - } else if (node.otherwise != null) { |
| - return new Continuation(node.otherwise, state); |
| - } |
| - return state.continuation; |
| + Configuration visitIfStatement(IfStatement node, state) { |
| + var expState = new ExpressionState.fromStatementState(state); |
| + var cont = new IfConditionContinuation(node.then, node.otherwise, expState); |
| + return new ExpressionConfiguration( |
| + node.condition, expState.withContinuation(cont)); |
| } |
| - Continuation visitLabeledStatement(LabeledStatement node, state) { |
| - return new Continuation(node.body, state.withBreak(node)); |
| + Configuration visitLabeledStatement(LabeledStatement node, state) { |
| + return new StatementConfiguration(node.body, state.withBreak(node)); |
| } |
| - Continuation visitBreakStatement(BreakStatement node, state) { |
| - return state.lookupLabel(node.target).continuation; |
| + Configuration visitBreakStatement(BreakStatement node, state) { |
| + return state.lookupLabel(node.target).configuration; |
| } |
| - Continuation visitWhileStatement(WhileStatement node, state) { |
| - Value cond = eval(node.condition, state.environment).toBoolean(); |
| - if (identical(Value.trueInstance, cond)) { |
| - // Add continuation for the While statement to the linked list. |
| - Continuation cont = new Continuation(node, state); |
| - // Continuation for the body of the loop. |
| - return new Continuation(node.body, state.withContinuation(cont)); |
| - } |
| - return state.continuation; |
| + Configuration visitWhileStatement(WhileStatement node, state) { |
| + var expState = new ExpressionState.fromStatementState(state); |
| + var cont = new WhileConditionContinuation(node, expState); |
| + |
| + return new ExpressionConfiguration( |
| + node.condition, expState.withContinuation(cont)); |
| } |
| - Continuation visitDoStatement(DoStatement node, state) { |
| + Configuration visitDoStatement(DoStatement node, state) { |
| WhileStatement whileStatement = |
| new WhileStatement(node.condition, node.body); |
| - Continuation cont = new Continuation(whileStatement, state); |
| - return new Continuation(node.body, state.withContinuation(cont)); |
| + StatementConfiguration configuration = |
| + new StatementConfiguration(whileStatement, state); |
| + |
| + return new StatementConfiguration( |
| + node.body, state.withConfiguration(configuration)); |
| } |
| - Continuation visitVariableDeclaration(VariableDeclaration node, state) { |
| - Value value = node.initializer != null |
| - ? eval(node.initializer, state.environment) |
| - : Value.nullInstance; |
| - state.environment.expand(node, value); |
| - return state.continuation; |
| + Configuration visitReturnStatement(ReturnStatement node, state) { |
| + assert(state.expressionContinuation != null); |
| + // The new ExpressionState contains the next expression continuation. |
| + var expState = new ExpressionState.fromStatementState(state) |
| + .withContinuation(state.expressionContinuation); |
| + return new ExpressionConfiguration(node.expression, expState); |
| + } |
| + |
| + Configuration visitVariableDeclaration(VariableDeclaration node, state) { |
| + if (node.initializer != null) { |
| + var expState = new ExpressionState.fromStatementState(state); |
| + var cont = new VariableInitializerContinuation(node, expState); |
| + return new ExpressionConfiguration( |
| + node.initializer, expState.withContinuation(cont)); |
| + } |
| + state.environment.expand(node, Value.nullInstance); |
| + return state.configuration; |
| } |
| } |
| +// ------------------------------------------------------------------------ |
| +// VALUES |
| +// ------------------------------------------------------------------------ |
| + |
| typedef Value Getter(Value receiver); |
| typedef void Setter(Value receiver, Value value); |