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 import '../log.dart'; | 9 import '../log.dart'; |
10 export '../log.dart'; | 10 export '../log.dart'; |
11 | 11 |
12 class NotImplemented { | 12 class NotImplemented { |
13 String message; | 13 String message; |
14 | 14 |
15 NotImplemented(this.message); | 15 NotImplemented(this.message); |
16 | 16 |
17 String toString() => message; | 17 String toString() => message; |
18 } | 18 } |
19 | 19 |
20 class Interpreter { | 20 class Interpreter { |
21 Program program; | 21 Program program; |
22 StatementExecuter visitor = new StatementExecuter(); | 22 StatementExecuter visitor = new StatementExecuter(); |
23 | 23 |
24 // The execution of the program starts with empty main environment. | |
25 static MainEnvironment mainEnvironment = | |
26 new MainEnvironment(<Member, Location>{}); | |
27 | |
24 Interpreter(this.program); | 28 Interpreter(this.program); |
25 | 29 |
26 void run() { | 30 void run() { |
27 assert(program.libraries.isEmpty); | 31 assert(program.libraries.isEmpty); |
28 Procedure mainMethod = program.mainMethod; | 32 Procedure mainMethod = program.mainMethod; |
29 | 33 |
30 if (mainMethod == null) return; | 34 if (mainMethod == null) return; |
31 | 35 |
32 Statement statementBlock = mainMethod.function.body; | 36 Statement statementBlock = mainMethod.function.body; |
33 ExecConfiguration configuration = new ExecConfiguration( | 37 ExecConfiguration configuration = new ExecConfiguration( |
(...skipping 16 matching lines...) Expand all Loading... | |
50 EnvironmentLocation(this.environment); | 54 EnvironmentLocation(this.environment); |
51 } | 55 } |
52 | 56 |
53 class Binding { | 57 class Binding { |
54 final VariableDeclaration variable; | 58 final VariableDeclaration variable; |
55 final Location location; | 59 final Location location; |
56 | 60 |
57 Binding(this.variable, this.location); | 61 Binding(this.variable, this.location); |
58 } | 62 } |
59 | 63 |
64 /// Represents the top level environment that binds previously accessed or set | |
65 /// static fields to the location that stores their value. | |
66 class MainEnvironment { | |
Dmitry Stefantsov
2017/08/16 12:06:46
Now that [MainEnvironment]s are immutable and we t
zhivkag
2017/08/16 12:27:44
One difference is that [MainEnvironment] maps [Mem
Dmitry Stefantsov
2017/08/16 12:38:50
Got it. Thanks for the explanation! No, I think
| |
67 final Map<Member, Location> _staticFields; | |
68 | |
69 MainEnvironment(this._staticFields); | |
70 | |
71 bool contains(Member member) => _staticFields[member] != null; | |
72 | |
73 Value lookup(Member member) { | |
74 assert(contains(member)); | |
75 return _staticFields[member].value; | |
76 } | |
77 | |
78 void update(Member member, Value value) { | |
79 assert(contains(member)); | |
80 _staticFields[member].value = value; | |
81 } | |
82 | |
83 MainEnvironment extend(Member member, Value value) { | |
84 var newMap = new Map<Member, Location>.from(_staticFields); | |
85 newMap[member] = new Location(value); | |
86 return new MainEnvironment(newMap); | |
87 } | |
88 } | |
89 | |
60 class Environment { | 90 class Environment { |
61 final List<Binding> bindings = <Binding>[]; | 91 final List<Binding> bindings = <Binding>[]; |
62 final Environment parent; | 92 final Environment parent; |
63 | 93 |
64 Value get thisInstance { | 94 Value get thisInstance { |
65 return containsThis() | 95 return containsThis() |
66 ? lookupThis().value | 96 ? lookupThis().value |
67 : throw "Invalid reference to 'this' expression"; | 97 : throw "Invalid reference to 'this' expression"; |
68 } | 98 } |
69 | 99 |
(...skipping 27 matching lines...) Expand all Loading... | |
97 for (Binding b in bindings) { | 127 for (Binding b in bindings) { |
98 if (identical(b.variable.name, 'this')) return b.location; | 128 if (identical(b.variable.name, 'this')) return b.location; |
99 } | 129 } |
100 return parent.lookupThis(); | 130 return parent.lookupThis(); |
101 } | 131 } |
102 | 132 |
103 Value lookup(VariableDeclaration variable) { | 133 Value lookup(VariableDeclaration variable) { |
104 return lookupBinding(variable).location.value; | 134 return lookupBinding(variable).location.value; |
105 } | 135 } |
106 | 136 |
107 void assign(VariableDeclaration variable, Value value) { | 137 void update(VariableDeclaration variable, Value value) { |
Dmitry Stefantsov
2017/08/16 12:06:47
How about renaming [update] to [updateStore] to be
zhivkag
2017/08/16 12:27:44
Done. I also renamed assign -> update -> updateSto
Dmitry Stefantsov
2017/08/16 12:38:50
I think [updateStore] is ok. As for "updateLocati
| |
108 assert(contains(variable)); | 138 assert(contains(variable)); |
109 lookupBinding(variable).location.value = value; | 139 lookupBinding(variable).location.value = value; |
110 } | 140 } |
111 | 141 |
112 Environment extend(VariableDeclaration variable, Value value) { | 142 Environment extend(VariableDeclaration variable, Value value) { |
113 assert(!contains(variable)); | 143 assert(!contains(variable)); |
114 return new Environment(this) | 144 return new Environment(this) |
115 ..bindings.add(new Binding(variable, new Location(value))); | 145 ..bindings.add(new Binding(variable, new Location(value))); |
116 } | 146 } |
117 | 147 |
(...skipping 49 matching lines...) Expand 10 before | Expand all | Expand 10 after Loading... | |
167 node.receiver, config.environment, config.exceptionComponents, cont); | 197 node.receiver, config.environment, config.exceptionComponents, cont); |
168 } | 198 } |
169 | 199 |
170 Configuration visitPropertySet(PropertySet node, EvalConfiguration config) { | 200 Configuration visitPropertySet(PropertySet node, EvalConfiguration config) { |
171 var cont = new PropertySetEK(node.value, node.name, config.environment, | 201 var cont = new PropertySetEK(node.value, node.name, config.environment, |
172 config.exceptionComponents, config.continuation); | 202 config.exceptionComponents, config.continuation); |
173 return new EvalConfiguration( | 203 return new EvalConfiguration( |
174 node.receiver, config.environment, config.exceptionComponents, cont); | 204 node.receiver, config.environment, config.exceptionComponents, cont); |
175 } | 205 } |
176 | 206 |
177 Configuration visitStaticGet(StaticGet node, EvalConfiguration config) => | 207 Configuration visitStaticGet(StaticGet node, EvalConfiguration config) { |
178 defaultExpression(node, config); | 208 Member member = node.target; |
179 Configuration visitStaticSet(StaticSet node, EvalConfiguration config) => | 209 |
180 defaultExpression(node, config); | 210 if (member is Procedure && !member.isAccessor) { |
211 // Create a closure for the method tear off. | |
212 var v = new FunctionValue( | |
213 member.function, new EnvironmentLocation(new Environment.empty())); | |
214 return new ValuePassingConfiguration(config.continuation, v); | |
215 } | |
216 | |
217 if (member is Procedure && member.isGetter) { | |
218 // Execute the body of the getter. | |
219 var state = new State.initial() | |
220 .withReturnContinuation(config.continuation) | |
221 .withContinuation(new ExitSK(config.continuation, Value.nullInstance)) | |
222 .withException(config.exceptionComponents); | |
223 return new ExecConfiguration( | |
224 member.function.body, new Environment.empty(), state); | |
225 } | |
226 | |
227 assert(member is Field); | |
228 if (Interpreter.mainEnvironment.contains(member)) { | |
229 // Read the value for the member in the main environment. | |
230 return new ValuePassingConfiguration( | |
231 config.continuation, Interpreter.mainEnvironment.lookup(member)); | |
232 } | |
233 | |
234 // Otherwise, the static field is accessed for the first time. | |
235 // We extend the main environment with a new binding. | |
236 Interpreter.mainEnvironment = | |
237 Interpreter.mainEnvironment.extend(member, Value.nullInstance); | |
238 | |
239 if ((member as Field).initializer == null) { | |
240 return new ValuePassingConfiguration( | |
241 config.continuation, Value.nullInstance); | |
242 } | |
243 | |
244 // The initializer expression is evaluated otherwise. | |
245 var cont = new StaticSetEK(member, config.continuation); | |
246 return new EvalConfiguration((member as Field).initializer, | |
247 new Environment.empty(), config.exceptionComponents, cont); | |
248 } | |
249 | |
250 Configuration visitStaticSet(StaticSet node, EvalConfiguration config) { | |
251 Member member = node.target; | |
252 ExpressionContinuation cont; | |
253 | |
254 if (member is Procedure) { | |
255 assert(member.isSetter); | |
256 cont = new StaticSetterEK( | |
257 member.function, config.exceptionComponents, config.continuation); | |
258 } else { | |
259 assert(member is Field); | |
260 cont = new StaticSetEK(member, config.continuation); | |
261 } | |
262 | |
263 return new EvalConfiguration( | |
264 node.value, config.environment, config.exceptionComponents, cont); | |
265 } | |
181 | 266 |
182 Configuration visitStaticInvocation( | 267 Configuration visitStaticInvocation( |
183 StaticInvocation node, EvalConfiguration config) { | 268 StaticInvocation node, EvalConfiguration config) { |
184 if ('print' == node.name.toString()) { | 269 if ('print' == node.name.toString()) { |
185 var cont = new PrintEK(config.continuation); | 270 var cont = new PrintEK(config.continuation); |
186 return new EvalConfiguration(node.arguments.positional.first, | 271 return new EvalConfiguration(node.arguments.positional.first, |
187 config.environment, config.exceptionComponents, cont); | 272 config.environment, config.exceptionComponents, cont); |
188 } else { | 273 } else { |
189 log.info('static-invocation-${node.target.name.toString()}\n'); | 274 log.info('static-invocation-${node.target.name.toString()}\n'); |
190 | 275 |
(...skipping 231 matching lines...) Expand 10 before | Expand all | Expand 10 after Loading... | |
422 } | 507 } |
423 | 508 |
424 /// Configuration for execution of a [Statement]. | 509 /// Configuration for execution of a [Statement]. |
425 class ExecConfiguration extends Configuration { | 510 class ExecConfiguration extends Configuration { |
426 final Statement currentStatement; | 511 final Statement currentStatement; |
427 final Environment environment; | 512 final Environment environment; |
428 final State state; | 513 final State state; |
429 | 514 |
430 ExecConfiguration(this.currentStatement, this.environment, this.state); | 515 ExecConfiguration(this.currentStatement, this.environment, this.state); |
431 | 516 |
432 Configuration step(StatementExecuter executer) => | 517 Configuration step(StatementExecuter executer) { |
433 executer.exec(currentStatement, this); | 518 return executer.exec(currentStatement, this); |
519 } | |
434 } | 520 } |
435 | 521 |
436 /// Configuration for applying a [StatementContinuation] to an [Environment]. | 522 /// Configuration for applying a [StatementContinuation] to an [Environment]. |
437 class ForwardConfiguration extends Configuration { | 523 class ForwardConfiguration extends Configuration { |
438 final StatementContinuation continuation; | 524 final StatementContinuation continuation; |
439 final Environment environment; | 525 final Environment environment; |
440 | 526 |
441 ForwardConfiguration(this.continuation, this.environment); | 527 ForwardConfiguration(this.continuation, this.environment); |
442 | 528 |
443 Configuration step(StatementExecuter _) => continuation?.call(environment); | 529 Configuration step(StatementExecuter _) => continuation?.call(environment); |
(...skipping 552 matching lines...) Expand 10 before | Expand all | Expand 10 after Loading... | |
996 | 1082 |
997 SetterEK(this.receiver, this.name, this.continuation); | 1083 SetterEK(this.receiver, this.name, this.continuation); |
998 | 1084 |
999 Configuration call(Value v) { | 1085 Configuration call(Value v) { |
1000 Setter setter = receiver.class_.lookupImplicitSetter(name); | 1086 Setter setter = receiver.class_.lookupImplicitSetter(name); |
1001 setter(receiver, v); | 1087 setter(receiver, v); |
1002 return new ValuePassingConfiguration(continuation, v); | 1088 return new ValuePassingConfiguration(continuation, v); |
1003 } | 1089 } |
1004 } | 1090 } |
1005 | 1091 |
1092 class StaticSetEK extends ExpressionContinuation { | |
1093 final Member member; | |
1094 final ExpressionContinuation continuation; | |
1095 | |
1096 StaticSetEK(this.member, this.continuation); | |
1097 | |
1098 Configuration call(Value v) { | |
1099 Interpreter.mainEnvironment.update(member, v); | |
1100 return new ValuePassingConfiguration(continuation, v); | |
1101 } | |
1102 } | |
1103 | |
1104 class StaticSetterEK extends ExpressionContinuation { | |
1105 final FunctionNode setter; | |
1106 final ExceptionComponents exceptionComponents; | |
1107 final ExpressionContinuation expressionContinuation; | |
1108 | |
1109 StaticSetterEK( | |
1110 this.setter, this.exceptionComponents, this.expressionContinuation); | |
1111 | |
1112 Configuration call(Value v) { | |
1113 VariableDeclaration arg = setter.positionalParameters.first; | |
1114 var env = new Environment.empty().extend(arg, v); | |
1115 var state = new State.initial() | |
1116 .withException(exceptionComponents) | |
1117 .withReturnContinuation(expressionContinuation) | |
1118 .withContinuation( | |
1119 new ExitSK(expressionContinuation, Value.nullInstance)); | |
1120 | |
1121 return new ExecConfiguration(setter.body, env, state); | |
1122 } | |
1123 } | |
1124 | |
1006 /// Represents a continuation to be called after the evaluation of an actual | 1125 /// Represents a continuation to be called after the evaluation of an actual |
1007 /// argument for function invocation. | 1126 /// argument for function invocation. |
1008 class ExpressionListEK extends ExpressionContinuation { | 1127 class ExpressionListEK extends ExpressionContinuation { |
1009 final InterpreterExpression currentExpression; | 1128 final InterpreterExpression currentExpression; |
1010 final List<InterpreterExpression> expressions; | 1129 final List<InterpreterExpression> expressions; |
1011 final Environment environment; | 1130 final Environment environment; |
1012 final ExceptionComponents exceptionComponents; | 1131 final ExceptionComponents exceptionComponents; |
1013 final ApplicationContinuation applicationContinuation; | 1132 final ApplicationContinuation applicationContinuation; |
1014 | 1133 |
1015 ExpressionListEK(this.currentExpression, this.expressions, this.environment, | 1134 ExpressionListEK(this.currentExpression, this.expressions, this.environment, |
(...skipping 59 matching lines...) Expand 10 before | Expand all | Expand 10 after Loading... | |
1075 } | 1194 } |
1076 | 1195 |
1077 class VariableSetEK extends ExpressionContinuation { | 1196 class VariableSetEK extends ExpressionContinuation { |
1078 final VariableDeclaration variable; | 1197 final VariableDeclaration variable; |
1079 final Environment environment; | 1198 final Environment environment; |
1080 final ExpressionContinuation continuation; | 1199 final ExpressionContinuation continuation; |
1081 | 1200 |
1082 VariableSetEK(this.variable, this.environment, this.continuation); | 1201 VariableSetEK(this.variable, this.environment, this.continuation); |
1083 | 1202 |
1084 Configuration call(Value value) { | 1203 Configuration call(Value value) { |
1085 environment.assign(variable, value); | 1204 environment.update(variable, value); |
1086 return new ValuePassingConfiguration(continuation, value); | 1205 return new ValuePassingConfiguration(continuation, value); |
1087 } | 1206 } |
1088 } | 1207 } |
1089 | 1208 |
1090 class NotEK extends ExpressionContinuation { | 1209 class NotEK extends ExpressionContinuation { |
1091 final ExpressionContinuation continuation; | 1210 final ExpressionContinuation continuation; |
1092 | 1211 |
1093 NotEK(this.continuation); | 1212 NotEK(this.continuation); |
1094 | 1213 |
1095 Configuration call(Value value) { | 1214 Configuration call(Value value) { |
(...skipping 438 matching lines...) Expand 10 before | Expand all | Expand 10 after Loading... | |
1534 return new EvalConfiguration(node.expression, conf.environment, | 1653 return new EvalConfiguration(node.expression, conf.environment, |
1535 conf.state.exceptionComponents, cont); | 1654 conf.state.exceptionComponents, cont); |
1536 } | 1655 } |
1537 | 1656 |
1538 Configuration visitBlock(Block node, ExecConfiguration conf) { | 1657 Configuration visitBlock(Block node, ExecConfiguration conf) { |
1539 if (node.statements.isEmpty) { | 1658 if (node.statements.isEmpty) { |
1540 return new ForwardConfiguration( | 1659 return new ForwardConfiguration( |
1541 conf.state.continuation, conf.environment); | 1660 conf.state.continuation, conf.environment); |
1542 } | 1661 } |
1543 | 1662 |
1544 var env = new Environment(conf.environment); | |
1545 var cont = new BlockSK.fromConfig(node.statements.skip(1).toList(), conf); | 1663 var cont = new BlockSK.fromConfig(node.statements.skip(1).toList(), conf); |
1546 return new ExecConfiguration( | 1664 return new ExecConfiguration(node.statements.first, conf.environment, |
1547 node.statements.first, env, conf.state.withContinuation(cont)); | 1665 conf.state.withContinuation(cont)); |
1548 } | 1666 } |
1549 | 1667 |
1550 Configuration visitEmptyStatement( | 1668 Configuration visitEmptyStatement( |
1551 EmptyStatement node, ExecConfiguration conf) { | 1669 EmptyStatement node, ExecConfiguration conf) { |
1552 return new ForwardConfiguration(conf.state.continuation, conf.environment); | 1670 return new ForwardConfiguration(conf.state.continuation, conf.environment); |
1553 } | 1671 } |
1554 | 1672 |
1555 Configuration visitIfStatement(IfStatement node, ExecConfiguration conf) { | 1673 Configuration visitIfStatement(IfStatement node, ExecConfiguration conf) { |
1556 var cont = new IfConditionEK( | 1674 var cont = new IfConditionEK( |
1557 node.then, node.otherwise, conf.environment, conf.state); | 1675 node.then, node.otherwise, conf.environment, conf.state); |
(...skipping 396 matching lines...) Expand 10 before | Expand all | Expand 10 after Loading... | |
1954 /// Initializes all non initialized fields from the provided class to | 2072 /// Initializes all non initialized fields from the provided class to |
1955 /// `Value.nullInstance` in the provided value. | 2073 /// `Value.nullInstance` in the provided value. |
1956 void _initializeNullFields(Class class_, Value value) { | 2074 void _initializeNullFields(Class class_, Value value) { |
1957 int startIndex = class_.superclass?.instanceSize ?? 0; | 2075 int startIndex = class_.superclass?.instanceSize ?? 0; |
1958 for (int i = startIndex; i < class_.instanceSize; i++) { | 2076 for (int i = startIndex; i < class_.instanceSize; i++) { |
1959 if (value.fields[i].value == null) { | 2077 if (value.fields[i].value == null) { |
1960 value.fields[i].value = Value.nullInstance; | 2078 value.fields[i].value = Value.nullInstance; |
1961 } | 2079 } |
1962 } | 2080 } |
1963 } | 2081 } |
OLD | NEW |