Index: pkg/kernel/lib/interpreter/interpreter.dart |
diff --git a/pkg/kernel/lib/interpreter/interpreter.dart b/pkg/kernel/lib/interpreter/interpreter.dart |
index a64fe581f12f7be928f4f34308138c6a63545c48..84f86afd6736570296ac5e4f05e47ac6f83f25a1 100644 |
--- a/pkg/kernel/lib/interpreter/interpreter.dart |
+++ b/pkg/kernel/lib/interpreter/interpreter.dart |
@@ -17,7 +17,6 @@ class NotImplemented { |
class Interpreter { |
Program program; |
StatementExecuter visitor = new StatementExecuter(); |
- Environment env = new Environment.empty(); |
Interpreter(this.program); |
@@ -25,19 +24,11 @@ class Interpreter { |
assert(program.libraries.isEmpty); |
Procedure mainMethod = program.mainMethod; |
Statement statementBlock = mainMethod.function.body; |
- visitor.exec(statementBlock, env); |
+ Continuation cont = new Continuation(statementBlock, new State.empty()); |
+ visitor.trampolinedExecution(cont); |
} |
} |
-class InvalidExpressionError { |
- InvalidExpression expression; |
- |
- InvalidExpressionError(this.expression); |
- |
- String toString() => |
- 'Invalid expression at ${expression.location.toString()}'; |
-} |
- |
class Binding { |
final VariableDeclaration variable; |
Value value; |
@@ -82,6 +73,7 @@ class Environment { |
} |
} |
+/// Evaluate expressions. |
class Evaluator extends ExpressionVisitor1<Value> { |
Value eval(Expression expr, Environment env) => expr.accept1(this, env); |
@@ -91,7 +83,7 @@ class Evaluator extends ExpressionVisitor1<Value> { |
} |
Value visitInvalidExpression1(InvalidExpression node, env) { |
- throw new InvalidExpressionError(node); |
+ throw 'Invalid expression at ${node.location.toString()}'; |
} |
Value visitVariableGet(VariableGet node, env) { |
@@ -223,57 +215,164 @@ class Evaluator extends ExpressionVisitor1<Value> { |
} |
} |
+/// Represents a state which consists of current environment, continuation to be |
+/// applied and the current label. |
+class State { |
+ final Environment env; |
+ final Continuation continuation; |
+ Label label; |
Kevin Millikin (Google)
2017/04/05 08:21:47
List these in the same order as the constructor ar
zhivkag
2017/04/05 10:00:19
Done.
|
+ |
+ State(this.env, this.label, this.continuation); |
+ State.withEnvironment(Environment env, State s) |
Kevin Millikin (Google)
2017/04/05 08:21:47
This is basically a static function that we have t
zhivkag
2017/04/05 10:00:19
Done.
|
+ : this(env, s.label, s.continuation); |
+ |
+ State.withContinuation(Continuation cont, State s) |
+ : this(s.env, s.label, cont); |
+ |
+ State.empty() |
Kevin Millikin (Google)
2017/04/05 08:21:48
Empty state seems ambiguous. Perhaps State.initia
zhivkag
2017/04/05 10:00:20
Done.
|
+ : this(new Environment.empty(), new Label.empty(), |
+ const Continuation.empty()); |
+ |
+ void addLabel(Statement s) { |
+ label = new Label(s, continuation, label); |
Kevin Millikin (Google)
2017/04/05 08:21:47
Suggest to make label be final and use a construct
zhivkag
2017/04/05 10:00:19
Done.
|
+ } |
+ |
+ Label lookupLabel(LabeledStatement s) { |
+ return label.lookupLabel(s); |
+ } |
+} |
+ |
+/// Represent the continuation for execution of statement. |
+class Continuation { |
+ final Statement statement; |
+ final State state; |
+ |
+ Continuation(this.statement, this.state); |
+ const Continuation.empty() |
Kevin Millikin (Google)
2017/04/05 08:21:47
This is the initial continuation, right? I think
zhivkag
2017/04/05 10:00:19
Yes, we shouldn't apply this continuation. exec sh
|
+ : statement = null, |
+ state = null; |
+} |
+ |
+/// Represents a labeled statement, the corresponding continuation and the |
+/// enclosing label. |
+class Label { |
+ final LabeledStatement statement; |
+ final Continuation continuation; |
+ final Label enclosingLabel; |
+ |
+ Label(this.statement, this.continuation, this.enclosingLabel); |
+ Label.empty() |
Kevin Millikin (Google)
2017/04/05 08:21:48
Does it make sense to use null as the sentinel for
zhivkag
2017/04/05 10:00:19
Done.
|
+ : statement = null, |
+ continuation = new Continuation.empty(), |
+ enclosingLabel = null; |
+ |
+ Label lookupLabel(LabeledStatement s) { |
+ if (identical(s, statement)) return this; |
+ return enclosingLabel.lookupLabel(s); |
Kevin Millikin (Google)
2017/04/05 08:21:47
In a well-formed program we will not get that encl
zhivkag
2017/04/05 10:00:19
Done.
|
+ } |
+} |
+ |
/// Executes statements. |
-class StatementExecuter extends StatementVisitor1 { |
+/// |
+/// Execution of a statement completes in one of the following ways: |
+/// - it completes normally, in which case the execution proceeds to applying |
+/// the next continuation |
+/// - it breaks with a label, in which case the corresponding continuation is |
+/// returned and applied |
+/// - it returns with or without value, TBD |
+/// - it throws, TBD |
+class StatementExecuter extends StatementVisitor1<Continuation> { |
Evaluator evaluator = new Evaluator(); |
- exec(Statement statement, env) => statement.accept1(this, env); |
- eval(Expression expression, env) => evaluator.eval(expression, env); |
+ void trampolinedExecution(Continuation continuation) { |
+ while (!identical(continuation, const Continuation.empty())) { |
+ continuation = exec(continuation.statement, continuation.state); |
+ } |
+ } |
- defaultStatement(Statement node, env) { |
+ Continuation exec(Statement statement, state) => |
+ statement.accept1(this, state); |
+ Value eval(Expression expression, env) => evaluator.eval(expression, env); |
+ |
+ Continuation defaultStatement(Statement node, state) { |
throw notImplemented( |
m: "Execution is not implemented for statement:\n$node "); |
} |
- visitInvalidStatement(InvalidStatement node, env) { |
+ Continuation visitInvalidStatement(InvalidStatement node, state) { |
throw "Invalid statement at ${node.location}"; |
} |
- visitExpressionStatement(ExpressionStatement node, env) { |
- return eval(node.expression, env); |
+ Continuation visitExpressionStatement(ExpressionStatement node, state) { |
+ eval(node.expression, state.env); |
+ return state.continuation; |
} |
- visitBlock(Block node, env) { |
- Environment blockEnv = new Environment(env); |
- for (Statement s in node.statements) { |
- exec(s, blockEnv); |
+ Continuation visitBlock(Block node, state) { |
+ // Block statement introduces a new environment. |
+ Environment blockEnv = new Environment(state.env); |
+ State blockState = new State.withEnvironment(blockEnv, state); |
+ Continuation cont; |
Kevin Millikin (Google)
2017/04/05 08:21:47
Maybe it's a little hard to reason about this code
zhivkag
2017/04/05 10:00:19
Done.
|
+ for (Statement s in node.statements.reversed) { |
+ cont = new Continuation(s, blockState); |
+ blockState = new State.withContinuation(cont, blockState); |
} |
+ return cont != null ? cont : state.continuation; |
} |
- visitEmptyStatement(EmptyStatement node, env) {} |
+ Continuation visitEmptyStatement(EmptyStatement node, state) { |
+ return state.continuation; |
+ } |
- visitIfStatement(IfStatement node, env) { |
- Value condition = eval(node.condition, env).toBoolean(); |
- if (identical(Value.trueInstance, condition)) { |
- exec(node.then, env); |
- } else { |
- exec(node.otherwise, env); |
+ Continuation visitIfStatement(IfStatement node, state) { |
+ Value cond = eval(node.condition, state.env).toBoolean(); |
+ if (identical(Value.trueInstance, cond)) { |
+ return new Continuation(node.then, state); |
Kevin Millikin (Google)
2017/04/05 08:21:47
Here we can (should?) have:
return exec(node.then
zhivkag
2017/04/05 10:00:19
Acknowledged.
|
+ } else if (node.otherwise != null) { |
+ return new Continuation(node.otherwise, state); |
} |
+ return state.continuation; |
+ } |
+ |
+ Continuation visitLabeledStatement(LabeledStatement node, state) { |
+ state.addLabel(node); |
+ return new Continuation(node.body, state); |
+ } |
+ |
+ Continuation visitBreakStatement(BreakStatement node, state) { |
+ return state.lookupLabel(node.target).continuation; |
+ } |
+ |
+ Continuation visitWhileStatement(WhileStatement node, state) { |
+ Value cond = eval(node.condition, state.env).toBoolean(); |
+ if (identical(Value.trueInstance, cond)) { |
+ // Add continuation for the While statement to the linked list. |
+ Continuation c = new Continuation(node, state); |
+ // Continuation for the body of the loop. |
+ return new Continuation(node.body, new State.withContinuation(c, state)); |
Kevin Millikin (Google)
2017/04/05 08:21:47
return exec(node.body, state.withContinuation(c));
zhivkag
2017/04/05 10:00:19
Acknowledged.
|
+ } |
+ return state.continuation; |
+ } |
+ |
+ Continuation visitDoStatement(DoStatement node, state) { |
+ WhileStatement whileStatement = |
+ new WhileStatement(node.condition, node.body); |
+ Continuation c = new Continuation(whileStatement, state); |
+ return new Continuation(node.body, new State.withContinuation(c, state)); |
} |
- visitVariableDeclaration(VariableDeclaration node, env) { |
+ Continuation visitVariableDeclaration(VariableDeclaration node, state) { |
Value value = node.initializer != null |
- ? eval(node.initializer, env) |
+ ? eval(node.initializer, state.env) |
: Value.nullInstance; |
- env.expand(node, value); |
+ state.env.expand(node, value); |
+ return state.continuation; |
} |
} |
typedef Value Getter(Value receiver); |
typedef void Setter(Value receiver, Value value); |
-// TODO(zhivkag): Change misleading name. |
-// This is representation of a class in the interpreter, not a declaration. |
class Class { |
static final Map<Reference, Class> _classes = <Reference, Class>{}; |