OLD | NEW |
---|---|
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 Loading... | |
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 Loading... | |
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 Loading... | |
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 } |
OLD | NEW |