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 static MainEnvironment mainEnvironment = new MainEnvironment(); | |
25 | |
24 Interpreter(this.program); | 26 Interpreter(this.program); |
25 | 27 |
26 void run() { | 28 void run() { |
27 assert(program.libraries.isEmpty); | 29 assert(program.libraries.isEmpty); |
28 Procedure mainMethod = program.mainMethod; | 30 Procedure mainMethod = program.mainMethod; |
29 | 31 |
30 if (mainMethod == null) return; | 32 if (mainMethod == null) return; |
31 | 33 |
32 Statement statementBlock = mainMethod.function.body; | 34 Statement statementBlock = mainMethod.function.body; |
33 ExecConfiguration configuration = new ExecConfiguration( | 35 ExecConfiguration configuration = new ExecConfiguration( |
(...skipping 16 matching lines...) Expand all Loading... | |
50 EnvironmentLocation(this.environment); | 52 EnvironmentLocation(this.environment); |
51 } | 53 } |
52 | 54 |
53 class Binding { | 55 class Binding { |
54 final VariableDeclaration variable; | 56 final VariableDeclaration variable; |
55 final Location location; | 57 final Location location; |
56 | 58 |
57 Binding(this.variable, this.location); | 59 Binding(this.variable, this.location); |
58 } | 60 } |
59 | 61 |
62 class MainEnvironment { | |
63 Map<Member, Location> _staticFields = <Member, Location>{}; | |
64 | |
65 bool contains(Member member) => _staticFields[member] != null; | |
66 | |
67 Value lookup(Member member) { | |
68 assert(contains(member)); | |
69 return _staticFields[member].value; | |
70 } | |
71 | |
72 void update(Member member, Value value) { | |
Dmitry Stefantsov
2017/08/16 08:25:39
I would add a comment that [MainEnvironment] insta
| |
73 if (_staticFields[member] == null) { | |
74 _staticFields[member] = new Location(value); | |
75 } else { | |
76 _staticFields[member].value = value; | |
77 } | |
78 } | |
79 } | |
80 | |
60 class Environment { | 81 class Environment { |
61 final List<Binding> bindings = <Binding>[]; | 82 final List<Binding> bindings = <Binding>[]; |
62 final Environment parent; | 83 final Environment parent; |
63 | 84 |
64 Value get thisInstance { | 85 Value get thisInstance { |
65 return containsThis() | 86 return containsThis() |
66 ? lookupThis().value | 87 ? lookupThis().value |
67 : throw "Invalid reference to 'this' expression"; | 88 : throw "Invalid reference to 'this' expression"; |
68 } | 89 } |
69 | 90 |
(...skipping 97 matching lines...) Expand 10 before | Expand all | Expand 10 after Loading... | |
167 node.receiver, config.environment, config.exceptionComponents, cont); | 188 node.receiver, config.environment, config.exceptionComponents, cont); |
168 } | 189 } |
169 | 190 |
170 Configuration visitPropertySet(PropertySet node, EvalConfiguration config) { | 191 Configuration visitPropertySet(PropertySet node, EvalConfiguration config) { |
171 var cont = new PropertySetEK(node.value, node.name, config.environment, | 192 var cont = new PropertySetEK(node.value, node.name, config.environment, |
172 config.exceptionComponents, config.continuation); | 193 config.exceptionComponents, config.continuation); |
173 return new EvalConfiguration( | 194 return new EvalConfiguration( |
174 node.receiver, config.environment, config.exceptionComponents, cont); | 195 node.receiver, config.environment, config.exceptionComponents, cont); |
175 } | 196 } |
176 | 197 |
177 Configuration visitStaticGet(StaticGet node, EvalConfiguration config) => | 198 Configuration visitStaticGet(StaticGet node, EvalConfiguration config) { |
178 defaultExpression(node, config); | 199 Member member = node.target; |
179 Configuration visitStaticSet(StaticSet node, EvalConfiguration config) => | 200 |
180 defaultExpression(node, config); | 201 if (member is Procedure && !member.isAccessor) { |
202 // Create a closure for the method tear off. | |
203 var v = new FunctionValue( | |
204 member.function, new EnvironmentLocation(new Environment.empty())); | |
205 return new ValuePassingConfiguration(config.continuation, v); | |
206 } | |
207 | |
208 if (member is Procedure && member.isGetter) { | |
209 // Execute the body of the getter. | |
210 var state = new State.initial() | |
211 .withReturnContinuation(config.continuation) | |
212 .withContinuation(new ExitSK(config.continuation, Value.nullInstance)) | |
213 .withException(config.exceptionComponents); | |
214 return new ExecConfiguration( | |
215 member.function.body, new Environment.empty(), state); | |
216 } | |
217 | |
218 assert(member is Field); | |
219 if (Interpreter.mainEnvironment.contains(member)) { | |
Dmitry Stefantsov
2017/08/16 08:25:39
I would use a special value to indicate that the s
| |
220 // Read the value for the member in the main environment. | |
221 return new ValuePassingConfiguration( | |
222 config.continuation, Interpreter.mainEnvironment.lookup(member)); | |
223 } | |
224 | |
225 // Otherwise, the static field is accessed for the first time. | |
226 // We store `Value.nullInstance` if there the field doesn't have an | |
227 // initializer. | |
228 if ((member as Field).initializer == null) { | |
229 Interpreter.mainEnvironment.update(member, Value.nullInstance); | |
Dmitry Stefantsov
2017/08/16 08:25:39
If the special value for uninitialized variables h
| |
230 return new ValuePassingConfiguration( | |
231 config.continuation, Value.nullInstance); | |
232 } | |
233 | |
234 // The initializer expression is evaluated otherwise. | |
235 var cont = new StaticSetEK(member, config.continuation); | |
236 return new EvalConfiguration((member as Field).initializer, | |
237 new Environment.empty(), config.exceptionComponents, cont); | |
238 } | |
239 | |
240 Configuration visitStaticSet(StaticSet node, EvalConfiguration config) { | |
241 Member member = node.target; | |
242 ExpressionContinuation cont; | |
243 | |
244 if (member is Procedure) { | |
245 assert(member.isSetter); | |
246 cont = new StaticSetterEK( | |
247 member.function, config.exceptionComponents, config.continuation); | |
248 } else { | |
249 assert(member is Field); | |
250 cont = new StaticSetEK(member, config.continuation); | |
251 } | |
252 | |
253 return new EvalConfiguration( | |
254 node.value, config.environment, config.exceptionComponents, cont); | |
255 } | |
181 | 256 |
182 Configuration visitStaticInvocation( | 257 Configuration visitStaticInvocation( |
183 StaticInvocation node, EvalConfiguration config) { | 258 StaticInvocation node, EvalConfiguration config) { |
184 if ('print' == node.name.toString()) { | 259 if ('print' == node.name.toString()) { |
185 var cont = new PrintEK(config.continuation); | 260 var cont = new PrintEK(config.continuation); |
186 return new EvalConfiguration(node.arguments.positional.first, | 261 return new EvalConfiguration(node.arguments.positional.first, |
187 config.environment, config.exceptionComponents, cont); | 262 config.environment, config.exceptionComponents, cont); |
188 } else { | 263 } else { |
189 log.info('static-invocation-${node.target.name.toString()}\n'); | 264 log.info('static-invocation-${node.target.name.toString()}\n'); |
190 | 265 |
(...skipping 231 matching lines...) Expand 10 before | Expand all | Expand 10 after Loading... | |
422 } | 497 } |
423 | 498 |
424 /// Configuration for execution of a [Statement]. | 499 /// Configuration for execution of a [Statement]. |
425 class ExecConfiguration extends Configuration { | 500 class ExecConfiguration extends Configuration { |
426 final Statement currentStatement; | 501 final Statement currentStatement; |
427 final Environment environment; | 502 final Environment environment; |
428 final State state; | 503 final State state; |
429 | 504 |
430 ExecConfiguration(this.currentStatement, this.environment, this.state); | 505 ExecConfiguration(this.currentStatement, this.environment, this.state); |
431 | 506 |
432 Configuration step(StatementExecuter executer) => | 507 Configuration step(StatementExecuter executer) { |
433 executer.exec(currentStatement, this); | 508 return executer.exec(currentStatement, this); |
509 } | |
434 } | 510 } |
435 | 511 |
436 /// Configuration for applying a [StatementContinuation] to an [Environment]. | 512 /// Configuration for applying a [StatementContinuation] to an [Environment]. |
437 class ForwardConfiguration extends Configuration { | 513 class ForwardConfiguration extends Configuration { |
438 final StatementContinuation continuation; | 514 final StatementContinuation continuation; |
439 final Environment environment; | 515 final Environment environment; |
440 | 516 |
441 ForwardConfiguration(this.continuation, this.environment); | 517 ForwardConfiguration(this.continuation, this.environment); |
442 | 518 |
443 Configuration step(StatementExecuter _) => continuation?.call(environment); | 519 Configuration step(StatementExecuter _) => continuation?.call(environment); |
(...skipping 552 matching lines...) Expand 10 before | Expand all | Expand 10 after Loading... | |
996 | 1072 |
997 SetterEK(this.receiver, this.name, this.continuation); | 1073 SetterEK(this.receiver, this.name, this.continuation); |
998 | 1074 |
999 Configuration call(Value v) { | 1075 Configuration call(Value v) { |
1000 Setter setter = receiver.class_.lookupImplicitSetter(name); | 1076 Setter setter = receiver.class_.lookupImplicitSetter(name); |
1001 setter(receiver, v); | 1077 setter(receiver, v); |
1002 return new ValuePassingConfiguration(continuation, v); | 1078 return new ValuePassingConfiguration(continuation, v); |
1003 } | 1079 } |
1004 } | 1080 } |
1005 | 1081 |
1082 class StaticSetEK extends ExpressionContinuation { | |
1083 final Member member; | |
1084 final ExpressionContinuation continuation; | |
1085 | |
1086 StaticSetEK(this.member, this.continuation); | |
1087 | |
1088 Configuration call(Value v) { | |
1089 Interpreter.mainEnvironment.update(member, v); | |
1090 return new ValuePassingConfiguration(continuation, v); | |
1091 } | |
1092 } | |
1093 | |
1094 class StaticSetterEK extends ExpressionContinuation { | |
1095 final FunctionNode setter; | |
1096 final ExceptionComponents exceptionComponents; | |
1097 final ExpressionContinuation expressionContinuation; | |
1098 | |
1099 StaticSetterEK( | |
1100 this.setter, this.exceptionComponents, this.expressionContinuation); | |
1101 | |
1102 Configuration call(Value v) { | |
1103 VariableDeclaration arg = setter.positionalParameters.first; | |
1104 var env = new Environment.empty().extend(arg, v); | |
1105 var state = new State.initial() | |
1106 .withException(exceptionComponents) | |
1107 .withReturnContinuation(expressionContinuation) | |
1108 .withContinuation( | |
1109 new ExitSK(expressionContinuation, Value.nullInstance)); | |
1110 | |
1111 return new ExecConfiguration(setter.body, env, state); | |
1112 } | |
1113 } | |
1114 | |
1006 /// Represents a continuation to be called after the evaluation of an actual | 1115 /// Represents a continuation to be called after the evaluation of an actual |
1007 /// argument for function invocation. | 1116 /// argument for function invocation. |
1008 class ExpressionListEK extends ExpressionContinuation { | 1117 class ExpressionListEK extends ExpressionContinuation { |
1009 final InterpreterExpression currentExpression; | 1118 final InterpreterExpression currentExpression; |
1010 final List<InterpreterExpression> expressions; | 1119 final List<InterpreterExpression> expressions; |
1011 final Environment environment; | 1120 final Environment environment; |
1012 final ExceptionComponents exceptionComponents; | 1121 final ExceptionComponents exceptionComponents; |
1013 final ApplicationContinuation applicationContinuation; | 1122 final ApplicationContinuation applicationContinuation; |
1014 | 1123 |
1015 ExpressionListEK(this.currentExpression, this.expressions, this.environment, | 1124 ExpressionListEK(this.currentExpression, this.expressions, this.environment, |
(...skipping 518 matching lines...) Expand 10 before | Expand all | Expand 10 after Loading... | |
1534 return new EvalConfiguration(node.expression, conf.environment, | 1643 return new EvalConfiguration(node.expression, conf.environment, |
1535 conf.state.exceptionComponents, cont); | 1644 conf.state.exceptionComponents, cont); |
1536 } | 1645 } |
1537 | 1646 |
1538 Configuration visitBlock(Block node, ExecConfiguration conf) { | 1647 Configuration visitBlock(Block node, ExecConfiguration conf) { |
1539 if (node.statements.isEmpty) { | 1648 if (node.statements.isEmpty) { |
1540 return new ForwardConfiguration( | 1649 return new ForwardConfiguration( |
1541 conf.state.continuation, conf.environment); | 1650 conf.state.continuation, conf.environment); |
1542 } | 1651 } |
1543 | 1652 |
1544 var env = new Environment(conf.environment); | |
1545 var cont = new BlockSK.fromConfig(node.statements.skip(1).toList(), conf); | 1653 var cont = new BlockSK.fromConfig(node.statements.skip(1).toList(), conf); |
1546 return new ExecConfiguration( | 1654 return new ExecConfiguration(node.statements.first, conf.environment, |
1547 node.statements.first, env, conf.state.withContinuation(cont)); | 1655 conf.state.withContinuation(cont)); |
1548 } | 1656 } |
1549 | 1657 |
1550 Configuration visitEmptyStatement( | 1658 Configuration visitEmptyStatement( |
1551 EmptyStatement node, ExecConfiguration conf) { | 1659 EmptyStatement node, ExecConfiguration conf) { |
1552 return new ForwardConfiguration(conf.state.continuation, conf.environment); | 1660 return new ForwardConfiguration(conf.state.continuation, conf.environment); |
1553 } | 1661 } |
1554 | 1662 |
1555 Configuration visitIfStatement(IfStatement node, ExecConfiguration conf) { | 1663 Configuration visitIfStatement(IfStatement node, ExecConfiguration conf) { |
1556 var cont = new IfConditionEK( | 1664 var cont = new IfConditionEK( |
1557 node.then, node.otherwise, conf.environment, conf.state); | 1665 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 | 2062 /// Initializes all non initialized fields from the provided class to |
1955 /// `Value.nullInstance` in the provided value. | 2063 /// `Value.nullInstance` in the provided value. |
1956 void _initializeNullFields(Class class_, Value value) { | 2064 void _initializeNullFields(Class class_, Value value) { |
1957 int startIndex = class_.superclass?.instanceSize ?? 0; | 2065 int startIndex = class_.superclass?.instanceSize ?? 0; |
1958 for (int i = startIndex; i < class_.instanceSize; i++) { | 2066 for (int i = startIndex; i < class_.instanceSize; i++) { |
1959 if (value.fields[i].value == null) { | 2067 if (value.fields[i].value == null) { |
1960 value.fields[i].value = Value.nullInstance; | 2068 value.fields[i].value = Value.nullInstance; |
1961 } | 2069 } |
1962 } | 2070 } |
1963 } | 2071 } |
OLD | NEW |