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

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

Issue 2790063002: Implement flow control with breaks (Closed)
Patch Set: Implement breaks with linked states, conts and labels 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;
224
225 State(this.env, this.label, this.continuation);
226 State.fromEnvironment(Environment env, State s)
Dmitry Stefantsov 2017/04/03 14:17:20 It's probably nitpicking, but 'fromEnvironment' lo
zhivkag 2017/04/03 14:32:30 Done.
227 : this(env, s.label, s.continuation);
228
229 State.fromContinuation(Continuation cont, State s)
230 : this(s.env, s.label, cont);
231
232 State.empty()
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);
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()
252 : statement = null,
253 state = null;
254 }
255
256 /// Represents a labeled statement, the corresponding continuation and the
257 /// enclosing labeled statement.
Dmitry Stefantsov 2017/04/03 14:17:20 Maybe "labeled statement" ==> "label"?
zhivkag 2017/04/03 14:32:30 Done.
258 class Label {
259 final LabeledStatement statement;
260 final Continuation continuation;
261 final Label label;
Dmitry Stefantsov 2017/04/03 14:17:20 Maybe "label" ==> "enclosingLabel"?
zhivkag 2017/04/03 14:32:30 Done.
262
263 Label(this.statement, this.continuation, this.label);
264 Label.empty()
265 : statement = null,
266 continuation = new Continuation.empty(),
267 label = null;
268
269 Label lookupLabel(LabeledStatement s) {
270 if (identical(s, statement)) return this;
271 return label.lookupLabel(s);
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, cont) => statement.accept1(this, cont);
Dmitry Stefantsov 2017/04/03 14:17:20 From the code below it looks like "cont" should be
zhivkag 2017/04/03 14:32:31 Indeed, I have missed to rename this (and some oth
294 Value eval(Expression expression, env) => evaluator.eval(expression, env);
295
296 Continuation defaultStatement(Statement node, cont) {
234 throw notImplemented( 297 throw notImplemented(
235 m: "Execution is not implemented for statement:\n$node "); 298 m: "Execution is not implemented for statement:\n$node ");
236 } 299 }
237 300
238 visitInvalidStatement(InvalidStatement node, env) { 301 Continuation visitInvalidStatement(InvalidStatement node, cont) {
239 throw "Invalid statement at ${node.location}"; 302 throw "Invalid statement at ${node.location}";
240 } 303 }
241 304
242 visitExpressionStatement(ExpressionStatement node, env) { 305 Continuation visitExpressionStatement(ExpressionStatement node, state) {
243 return eval(node.expression, env); 306 eval(node.expression, state.env);
307 return state.continuation;
244 } 308 }
245 309
246 visitBlock(Block node, env) { 310 Continuation visitBlock(Block node, state) {
247 Environment blockEnv = new Environment(env); 311 // Block statement introduces a new environment.
248 for (Statement s in node.statements) { 312 Environment blockEnv = new Environment(state.env);
249 exec(s, blockEnv); 313 State blockState = new State.fromEnvironment(blockEnv, state);
314 Continuation cont;
315 for (Statement s in node.statements.reversed) {
316 cont = new Continuation(s, blockState);
317 blockState = new State.fromContinuation(cont, blockState);
250 } 318 }
319 return cont != null ? cont : state.continuation;
251 } 320 }
252 321
253 visitEmptyStatement(EmptyStatement node, env) {} 322 Continuation visitEmptyStatement(EmptyStatement node, state) {
254 323 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 } 324 }
263 325
264 visitVariableDeclaration(VariableDeclaration node, env) { 326 Continuation visitIfStatement(IfStatement node, state) {
327 Value cond = eval(node.condition, state.env).toBoolean();
328 if (identical(Value.trueInstance, cond)) {
329 return new Continuation(node.then, state);
330 } else if (node.otherwise != null) {
331 return new Continuation(node.otherwise, state);
332 }
333 return state.continuation;
334 }
335
336 Continuation visitLabeledStatement(LabeledStatement node, state) {
337 state.addLabel(node);
338 return new Continuation(node.body, state);
339 }
340
341 Continuation visitBreakStatement(BreakStatement node, state) {
342 return state.lookupLabel(node.target).continuation;
343 }
344
345 Continuation visitWhileStatement(WhileStatement node, state) {
346 Value cond = eval(node.condition, state.env).toBoolean();
347 if (identical(Value.trueInstance, cond)) {
348 // Add continuation for the While statement to the linked list.
349 Continuation c = new Continuation(node, state);
350 // Continuation for the body of the loop.
351 return new Continuation(node.body, new State.fromContinuation(c, state));
352 }
353 return state.continuation;
354 }
355
356 Continuation visitDoStatement(DoStatement node, state) {
357 WhileStatement whileStatement =
358 new WhileStatement(node.condition, node.body);
359 Continuation c = new Continuation(whileStatement, state);
360 return new Continuation(node.body, new State.fromContinuation(c, state));
361 }
362
363 Continuation visitVariableDeclaration(VariableDeclaration node, state) {
265 Value value = node.initializer != null 364 Value value = node.initializer != null
266 ? eval(node.initializer, env) 365 ? eval(node.initializer, state.env)
267 : Value.nullInstance; 366 : Value.nullInstance;
268 env.expand(node, value); 367 state.env.expand(node, value);
368 return state.continuation;
269 } 369 }
270 } 370 }
271 371
272 typedef Value Getter(Value receiver); 372 typedef Value Getter(Value receiver);
273 typedef void Setter(Value receiver, Value value); 373 typedef void Setter(Value receiver, Value value);
274 374
275 // TODO(zhivkag): Change misleading name.
276 // This is representation of a class in the interpreter, not a declaration.
277 class Class { 375 class Class {
278 static final Map<Reference, Class> _classes = <Reference, Class>{}; 376 static final Map<Reference, Class> _classes = <Reference, Class>{};
279 377
280 Class superclass; 378 Class superclass;
281 List<Field> instanceFields = <Field>[]; 379 List<Field> instanceFields = <Field>[];
282 List<Field> staticFields = <Field>[]; 380 List<Field> staticFields = <Field>[];
283 // Implicit getters and setters for instance Fields. 381 // Implicit getters and setters for instance Fields.
284 Map<Name, Getter> getters = <Name, Getter>{}; 382 Map<Name, Getter> getters = <Name, Getter>{};
285 Map<Name, Setter> setters = <Name, Setter>{}; 383 Map<Name, Setter> setters = <Name, Setter>{};
286 // The initializers of static fields are evaluated the first time the field 384 // 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 588
491 class NullValue extends LiteralValue { 589 class NullValue extends LiteralValue {
492 Object get value => null; 590 Object get value => null;
493 591
494 const NullValue(); 592 const NullValue();
495 } 593 }
496 594
497 notImplemented({String m, Object obj}) { 595 notImplemented({String m, Object obj}) {
498 throw new NotImplemented(m ?? 'Evaluation for $obj is not implemented'); 596 throw new NotImplemented(m ?? 'Evaluation for $obj is not implemented');
499 } 597 }
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