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 // 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 |