Chromium Code Reviews| 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 |