Chromium Code Reviews
chromiumcodereview-hr@appspot.gserviceaccount.com (chromiumcodereview-hr) | Please choose your nickname with Settings | Help | Chromium Project | Gerrit Changes | Sign out
(817)

Side by Side Diff: pkg/kernel/lib/interpreter/interpreter.dart

Issue 2790063002: Implement flow control with breaks (Closed)
Patch Set: Apply comments Created 3 years, 8 months ago
Use n/p to move between diff chunks; N/P to move between comments. Draft comments are only viewable by you.
Jump to:
View unified diff | Download patch
« no previous file with comments | « no previous file | no next file » | no next file with comments »
Toggle Intra-line Diffs ('i') | Expand Comments ('e') | Collapse Comments ('c') | Show Comments Hide Comments ('s')
OLDNEW
1 // Copyright (c) 2017, the Dart project authors. Please see the AUTHORS file 1 // Copyright (c) 2017, the Dart project authors. Please see the AUTHORS file
2 // for details. All rights reserved. Use of this source code is governed by a 2 // for details. All rights reserved. Use of this source code is governed by a
3 // BSD-style license that can be found in the LICENSE file. 3 // BSD-style license that can be found in the LICENSE file.
4 library kernel.interpreter; 4 library kernel.interpreter;
5 5
6 import '../ast.dart'; 6 import '../ast.dart';
7 import '../ast.dart' as ast show Class; 7 import '../ast.dart' as ast show Class;
8 8
9 class NotImplemented { 9 class NotImplemented {
10 String message; 10 String message;
11 11
12 NotImplemented(this.message); 12 NotImplemented(this.message);
13 13
14 String toString() => message; 14 String toString() => message;
15 } 15 }
16 16
17 class Interpreter { 17 class Interpreter {
18 Program program; 18 Program program;
19 StatementExecuter visitor = new StatementExecuter(); 19 StatementExecuter visitor = new StatementExecuter();
20 Environment env = new Environment.empty();
21 20
22 Interpreter(this.program); 21 Interpreter(this.program);
23 22
24 void run() { 23 void run() {
25 assert(program.libraries.isEmpty); 24 assert(program.libraries.isEmpty);
26 Procedure mainMethod = program.mainMethod; 25 Procedure mainMethod = program.mainMethod;
27 Statement statementBlock = mainMethod.function.body; 26 Statement statementBlock = mainMethod.function.body;
28 visitor.exec(statementBlock, env); 27 Continuation cont = new Continuation(statementBlock, new State.empty());
28 visitor.trampolinedExecution(cont);
29 } 29 }
30 } 30 }
31 31
32 class InvalidExpressionError {
33 InvalidExpression expression;
34
35 InvalidExpressionError(this.expression);
36
37 String toString() =>
38 'Invalid expression at ${expression.location.toString()}';
39 }
40
41 class Binding { 32 class Binding {
42 final VariableDeclaration variable; 33 final VariableDeclaration variable;
43 Value value; 34 Value value;
44 35
45 Binding(this.variable, this.value); 36 Binding(this.variable, this.value);
46 } 37 }
47 38
48 class Environment { 39 class Environment {
49 final List<Binding> bindings = <Binding>[]; 40 final List<Binding> bindings = <Binding>[];
50 final Environment parent; 41 final Environment parent;
(...skipping 24 matching lines...) Expand all
75 assert(contains(variable)); 66 assert(contains(variable));
76 lookupBinding(variable).value = value; 67 lookupBinding(variable).value = value;
77 } 68 }
78 69
79 void expand(VariableDeclaration variable, Value value) { 70 void expand(VariableDeclaration variable, Value value) {
80 assert(!contains(variable)); 71 assert(!contains(variable));
81 bindings.add(new Binding(variable, value)); 72 bindings.add(new Binding(variable, value));
82 } 73 }
83 } 74 }
84 75
76 /// Evaluate expressions.
85 class Evaluator extends ExpressionVisitor1<Value> { 77 class Evaluator extends ExpressionVisitor1<Value> {
86 Value eval(Expression expr, Environment env) => expr.accept1(this, env); 78 Value eval(Expression expr, Environment env) => expr.accept1(this, env);
87 79
88 Value defaultExpression(Expression node, env) { 80 Value defaultExpression(Expression node, env) {
89 throw new NotImplemented('Evaluation for expressions of type ' 81 throw new NotImplemented('Evaluation for expressions of type '
90 '${node.runtimeType} is not implemented.'); 82 '${node.runtimeType} is not implemented.');
91 } 83 }
92 84
93 Value visitInvalidExpression1(InvalidExpression node, env) { 85 Value visitInvalidExpression1(InvalidExpression node, env) {
94 throw new InvalidExpressionError(node); 86 throw 'Invalid expression at ${node.location.toString()}';
95 } 87 }
96 88
97 Value visitVariableGet(VariableGet node, env) { 89 Value visitVariableGet(VariableGet node, env) {
98 return env.lookup(node.variable); 90 return env.lookup(node.variable);
99 } 91 }
100 92
101 Value visitVariableSet(VariableSet node, env) { 93 Value visitVariableSet(VariableSet node, env) {
102 return env.assign(node.variable, eval(node.value, env)); 94 return env.assign(node.variable, eval(node.value, env));
103 } 95 }
104 96
(...skipping 111 matching lines...) Expand 10 before | Expand all | Expand 10 after
216 Value visitNullLiteral(NullLiteral node, env) => Value.nullInstance; 208 Value visitNullLiteral(NullLiteral node, env) => Value.nullInstance;
217 209
218 Value visitLet(Let node, env) { 210 Value visitLet(Let node, env) {
219 var value = eval(node.variable.initializer, env); 211 var value = eval(node.variable.initializer, env);
220 var letEnv = new Environment(env); 212 var letEnv = new Environment(env);
221 letEnv.expand(node.variable, value); 213 letEnv.expand(node.variable, value);
222 return eval(node.body, letEnv); 214 return eval(node.body, letEnv);
223 } 215 }
224 } 216 }
225 217
218 /// Represents a state which consists of current environment, continuation to be
219 /// applied and the current label.
220 class State {
221 final Environment env;
222 final Continuation continuation;
223 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.
224
225 State(this.env, this.label, this.continuation);
226 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.
227 : this(env, s.label, s.continuation);
228
229 State.withContinuation(Continuation cont, State s)
230 : this(s.env, s.label, cont);
231
232 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.
233 : this(new Environment.empty(), new Label.empty(),
234 const Continuation.empty());
235
236 void addLabel(Statement s) {
237 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.
238 }
239
240 Label lookupLabel(LabeledStatement s) {
241 return label.lookupLabel(s);
242 }
243 }
244
245 /// Represent the continuation for execution of statement.
246 class Continuation {
247 final Statement statement;
248 final State state;
249
250 Continuation(this.statement, this.state);
251 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
252 : statement = null,
253 state = null;
254 }
255
256 /// Represents a labeled statement, the corresponding continuation and the
257 /// enclosing label.
258 class Label {
259 final LabeledStatement statement;
260 final Continuation continuation;
261 final Label enclosingLabel;
262
263 Label(this.statement, this.continuation, this.enclosingLabel);
264 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.
265 : statement = null,
266 continuation = new Continuation.empty(),
267 enclosingLabel = null;
268
269 Label lookupLabel(LabeledStatement s) {
270 if (identical(s, statement)) return this;
271 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.
272 }
273 }
274
226 /// Executes statements. 275 /// Executes statements.
227 class StatementExecuter extends StatementVisitor1 { 276 ///
277 /// Execution of a statement completes in one of the following ways:
278 /// - it completes normally, in which case the execution proceeds to applying
279 /// the next continuation
280 /// - it breaks with a label, in which case the corresponding continuation is
281 /// returned and applied
282 /// - it returns with or without value, TBD
283 /// - it throws, TBD
284 class StatementExecuter extends StatementVisitor1<Continuation> {
228 Evaluator evaluator = new Evaluator(); 285 Evaluator evaluator = new Evaluator();
229 286
230 exec(Statement statement, env) => statement.accept1(this, env); 287 void trampolinedExecution(Continuation continuation) {
231 eval(Expression expression, env) => evaluator.eval(expression, env); 288 while (!identical(continuation, const Continuation.empty())) {
289 continuation = exec(continuation.statement, continuation.state);
290 }
291 }
232 292
233 defaultStatement(Statement node, env) { 293 Continuation exec(Statement statement, state) =>
294 statement.accept1(this, state);
295 Value eval(Expression expression, env) => evaluator.eval(expression, env);
296
297 Continuation defaultStatement(Statement node, state) {
234 throw notImplemented( 298 throw notImplemented(
235 m: "Execution is not implemented for statement:\n$node "); 299 m: "Execution is not implemented for statement:\n$node ");
236 } 300 }
237 301
238 visitInvalidStatement(InvalidStatement node, env) { 302 Continuation visitInvalidStatement(InvalidStatement node, state) {
239 throw "Invalid statement at ${node.location}"; 303 throw "Invalid statement at ${node.location}";
240 } 304 }
241 305
242 visitExpressionStatement(ExpressionStatement node, env) { 306 Continuation visitExpressionStatement(ExpressionStatement node, state) {
243 return eval(node.expression, env); 307 eval(node.expression, state.env);
308 return state.continuation;
244 } 309 }
245 310
246 visitBlock(Block node, env) { 311 Continuation visitBlock(Block node, state) {
247 Environment blockEnv = new Environment(env); 312 // Block statement introduces a new environment.
248 for (Statement s in node.statements) { 313 Environment blockEnv = new Environment(state.env);
249 exec(s, blockEnv); 314 State blockState = new State.withEnvironment(blockEnv, state);
315 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.
316 for (Statement s in node.statements.reversed) {
317 cont = new Continuation(s, blockState);
318 blockState = new State.withContinuation(cont, blockState);
250 } 319 }
320 return cont != null ? cont : state.continuation;
251 } 321 }
252 322
253 visitEmptyStatement(EmptyStatement node, env) {} 323 Continuation visitEmptyStatement(EmptyStatement node, state) {
254 324 return state.continuation;
255 visitIfStatement(IfStatement node, env) {
256 Value condition = eval(node.condition, env).toBoolean();
257 if (identical(Value.trueInstance, condition)) {
258 exec(node.then, env);
259 } else {
260 exec(node.otherwise, env);
261 }
262 } 325 }
263 326
264 visitVariableDeclaration(VariableDeclaration node, env) { 327 Continuation visitIfStatement(IfStatement node, state) {
328 Value cond = eval(node.condition, state.env).toBoolean();
329 if (identical(Value.trueInstance, cond)) {
330 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.
331 } else if (node.otherwise != null) {
332 return new Continuation(node.otherwise, state);
333 }
334 return state.continuation;
335 }
336
337 Continuation visitLabeledStatement(LabeledStatement node, state) {
338 state.addLabel(node);
339 return new Continuation(node.body, state);
340 }
341
342 Continuation visitBreakStatement(BreakStatement node, state) {
343 return state.lookupLabel(node.target).continuation;
344 }
345
346 Continuation visitWhileStatement(WhileStatement node, state) {
347 Value cond = eval(node.condition, state.env).toBoolean();
348 if (identical(Value.trueInstance, cond)) {
349 // Add continuation for the While statement to the linked list.
350 Continuation c = new Continuation(node, state);
351 // Continuation for the body of the loop.
352 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.
353 }
354 return state.continuation;
355 }
356
357 Continuation visitDoStatement(DoStatement node, state) {
358 WhileStatement whileStatement =
359 new WhileStatement(node.condition, node.body);
360 Continuation c = new Continuation(whileStatement, state);
361 return new Continuation(node.body, new State.withContinuation(c, state));
362 }
363
364 Continuation visitVariableDeclaration(VariableDeclaration node, state) {
265 Value value = node.initializer != null 365 Value value = node.initializer != null
266 ? eval(node.initializer, env) 366 ? eval(node.initializer, state.env)
267 : Value.nullInstance; 367 : Value.nullInstance;
268 env.expand(node, value); 368 state.env.expand(node, value);
369 return state.continuation;
269 } 370 }
270 } 371 }
271 372
272 typedef Value Getter(Value receiver); 373 typedef Value Getter(Value receiver);
273 typedef void Setter(Value receiver, Value value); 374 typedef void Setter(Value receiver, Value value);
274 375
275 // TODO(zhivkag): Change misleading name.
276 // This is representation of a class in the interpreter, not a declaration.
277 class Class { 376 class Class {
278 static final Map<Reference, Class> _classes = <Reference, Class>{}; 377 static final Map<Reference, Class> _classes = <Reference, Class>{};
279 378
280 Class superclass; 379 Class superclass;
281 List<Field> instanceFields = <Field>[]; 380 List<Field> instanceFields = <Field>[];
282 List<Field> staticFields = <Field>[]; 381 List<Field> staticFields = <Field>[];
283 // Implicit getters and setters for instance Fields. 382 // Implicit getters and setters for instance Fields.
284 Map<Name, Getter> getters = <Name, Getter>{}; 383 Map<Name, Getter> getters = <Name, Getter>{};
285 Map<Name, Setter> setters = <Name, Setter>{}; 384 Map<Name, Setter> setters = <Name, Setter>{};
286 // The initializers of static fields are evaluated the first time the field 385 // The initializers of static fields are evaluated the first time the field
(...skipping 203 matching lines...) Expand 10 before | Expand all | Expand 10 after
490 589
491 class NullValue extends LiteralValue { 590 class NullValue extends LiteralValue {
492 Object get value => null; 591 Object get value => null;
493 592
494 const NullValue(); 593 const NullValue();
495 } 594 }
496 595
497 notImplemented({String m, Object obj}) { 596 notImplemented({String m, Object obj}) {
498 throw new NotImplemented(m ?? 'Evaluation for $obj is not implemented'); 597 throw new NotImplemented(m ?? 'Evaluation for $obj is not implemented');
499 } 598 }
OLDNEW
« no previous file with comments | « no previous file | no next file » | no next file with comments »

Powered by Google App Engine
This is Rietveld 408576698