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 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 | 20 |
| 21 Interpreter(this.program); | 21 Interpreter(this.program); |
| 22 | 22 |
| 23 void run() { | 23 void run() { |
| 24 assert(program.libraries.isEmpty); | 24 assert(program.libraries.isEmpty); |
| 25 Procedure mainMethod = program.mainMethod; | 25 Procedure mainMethod = program.mainMethod; |
| 26 Statement statementBlock = mainMethod.function.body; | 26 Statement statementBlock = mainMethod.function.body; |
| 27 Continuation cont = new Continuation(statementBlock, new State.initial()); | 27 StatementConfiguration configuration = |
| 28 visitor.trampolinedExecution(cont); | 28 new StatementConfiguration(statementBlock, new State.initial()); |
| 29 visitor.trampolinedExecution(configuration); | |
| 29 } | 30 } |
| 30 } | 31 } |
| 31 | 32 |
| 32 class Binding { | 33 class Binding { |
| 33 final VariableDeclaration variable; | 34 final VariableDeclaration variable; |
| 34 Value value; | 35 Value value; |
| 35 | 36 |
| 36 Binding(this.variable, this.value); | 37 Binding(this.variable, this.value); |
| 37 } | 38 } |
| 38 | 39 |
| (...skipping 28 matching lines...) Expand all Loading... | |
| 67 lookupBinding(variable).value = value; | 68 lookupBinding(variable).value = value; |
| 68 } | 69 } |
| 69 | 70 |
| 70 void expand(VariableDeclaration variable, Value value) { | 71 void expand(VariableDeclaration variable, Value value) { |
| 71 assert(!contains(variable)); | 72 assert(!contains(variable)); |
| 72 bindings.add(new Binding(variable, value)); | 73 bindings.add(new Binding(variable, value)); |
| 73 } | 74 } |
| 74 } | 75 } |
| 75 | 76 |
| 76 /// Evaluate expressions. | 77 /// Evaluate expressions. |
| 77 class Evaluator extends ExpressionVisitor1<Value> { | 78 class Evaluator extends ExpressionVisitor1<Configuration> { |
|
Kevin Millikin (Google)
2017/04/20 10:50:20
We should make ExpressionVisitor1 parameterized ov
zhivkag
2017/04/20 13:21:36
Acknowledged. I will do it in a follow-up CL.
| |
| 78 Value eval(Expression expr, Environment env) => expr.accept1(this, env); | 79 Configuration eval(Expression expr, ExpressionState state) => |
|
Kevin Millikin (Google)
2017/04/20 10:50:20
ExpressionState is ExpressionConfiguration without
zhivkag
2017/04/20 13:21:36
Acknowledged. I will do it in a follow-up CL.
| |
| 80 expr.accept1(this, state); | |
| 79 | 81 |
| 80 Value defaultExpression(Expression node, env) { | 82 Configuration defaultExpression(Expression node, state) { |
| 81 throw new NotImplemented('Evaluation for expressions of type ' | 83 throw new NotImplemented('Evaluation for expressions of type ' |
| 82 '${node.runtimeType} is not implemented.'); | 84 '${node.runtimeType} is not implemented.'); |
| 83 } | 85 } |
| 84 | 86 |
| 85 Value visitInvalidExpression1(InvalidExpression node, env) { | 87 Configuration visitInvalidExpression1(InvalidExpression node, state) { |
| 86 throw 'Invalid expression at ${node.location.toString()}'; | 88 throw 'Invalid expression at ${node.location.toString()}'; |
| 87 } | 89 } |
| 88 | 90 |
| 89 Value visitVariableGet(VariableGet node, env) { | 91 Configuration visitVariableGet(VariableGet node, state) { |
| 90 return env.lookup(node.variable); | 92 Value value = state.environment.lookup(node.variable); |
| 93 return state.nextConfiguration(value); | |
|
Kevin Millikin (Google)
2017/04/20 10:50:20
I think nextConfiguration is only needed because t
zhivkag
2017/04/20 13:21:36
Done.
| |
| 91 } | 94 } |
| 92 | 95 |
| 93 Value visitVariableSet(VariableSet node, env) { | 96 Configuration visitVariableSet(VariableSet node, state) { |
| 94 return env.assign(node.variable, eval(node.value, env)); | 97 var cont = new VariableSetContinuation(state, node.variable); |
| 98 return new ExpressionConfiguration( | |
| 99 node.value, state.withContinuation(cont)); | |
| 95 } | 100 } |
| 96 | 101 |
| 97 Value visitPropertyGet(PropertyGet node, env) { | 102 Configuration visitPropertyGet(PropertyGet node, state) { |
| 98 Value receiver = eval(node.receiver, env); | 103 var cont = new PropertyGetContinuation(node.name, state); |
| 99 return receiver.class_.lookupGetter(node.name)(receiver); | 104 return new ExpressionConfiguration( |
| 105 node.receiver, state.withContinuation(cont)); | |
| 100 } | 106 } |
| 101 | 107 |
| 102 Value visitPropertySet(PropertySet node, env) { | 108 Configuration visitPropertySet(PropertySet node, state) { |
| 103 Value receiver = eval(node.receiver, env); | 109 var cont = new PropertySetContinuation(node.value, node.name, state); |
| 104 Value value = eval(node.value, env); | 110 return new ExpressionConfiguration( |
| 105 receiver.class_.lookupSetter(node.name)(receiver, value); | 111 node.receiver, state.withContinuation(cont)); |
| 106 return value; | |
| 107 } | 112 } |
| 108 | 113 |
| 109 Value visitDirectPropertyGet(DirectPropertyGet node, env) { | 114 Configuration visitStaticGet(StaticGet node, state) => |
| 110 Value receiver = eval(node.receiver, env); | 115 defaultExpression(node, state); |
| 111 return receiver.class_.getProperty(receiver, node.target); | 116 Configuration visitStaticSet(StaticSet node, state) => |
| 112 } | 117 defaultExpression(node, state); |
| 113 | 118 |
| 114 Value visitDirectPropertySet(DirectPropertySet node, env) { | 119 Configuration visitStaticInvocation(StaticInvocation node, state) { |
| 115 Value receiver = eval(node.receiver, env); | |
| 116 Value value = eval(node.value, env); | |
| 117 receiver.class_.setProperty(receiver, node.target, value); | |
| 118 return value; | |
| 119 } | |
| 120 | |
| 121 Value visitStaticGet(StaticGet node, env) => defaultExpression(node, env); | |
| 122 Value visitStaticSet(StaticSet node, env) => defaultExpression(node, env); | |
| 123 | |
| 124 Value visitStaticInvocation(StaticInvocation node, env) { | |
| 125 if ('print' == node.name.toString()) { | 120 if ('print' == node.name.toString()) { |
| 126 // Special evaluation of print. | 121 return new ExpressionConfiguration(node.arguments.positional.first, |
| 127 var res = eval(node.arguments.positional[0], env); | 122 state.withContinuation(new PrintContinuation(state))); |
| 128 print(res.value); | |
| 129 return Value.nullInstance; | |
| 130 } else { | 123 } else { |
| 131 throw new NotImplemented('Support for statement type ' | 124 // Currently supports only static invocations with no arguments. |
| 132 '${node.runtimeType} is not implemented'); | 125 if (node.arguments.positional.isEmpty && node.arguments.named.isEmpty) { |
| 126 return new StatementConfiguration( | |
| 127 node.target.function.body, | |
| 128 state.statementState | |
|
Kevin Millikin (Google)
2017/04/20 10:50:20
This doesn't seem like the right StatementState he
zhivkag
2017/04/20 13:21:36
Done.
| |
| 129 .withExpressionContinuation(state.continuation)); | |
| 130 } | |
| 131 throw new NotImplemented( | |
| 132 'Support for static invocation with arguments is not implemented'); | |
| 133 } | 133 } |
| 134 } | 134 } |
| 135 | 135 |
| 136 Value visitMethodInvocation(MethodInvocation node, env) { | 136 Configuration visitMethodInvocation(MethodInvocation node, state) { |
| 137 // Currently supports only method invocation with <2 arguments and is used | 137 // Currently supports only method invocation with <2 arguments and is used |
| 138 // to evaluate implemented operators for int, double and String values. | 138 // to evaluate implemented operators for int, double and String values. |
| 139 var receiver = eval(node.receiver, env); | 139 var cont = |
| 140 if (node.arguments.positional.isNotEmpty) { | 140 new MethodInvocationContinuation(node.arguments, node.name, state); |
| 141 var argValue = eval(node.arguments.positional.first, env); | 141 |
| 142 return receiver.invokeMethod(node.name, argValue); | 142 return new ExpressionConfiguration( |
| 143 } else { | 143 node.receiver, state.withContinuation(cont)); |
| 144 return receiver.invokeMethod(node.name); | |
| 145 } | |
| 146 } | 144 } |
| 147 | 145 |
| 148 Value visitConstructorInvocation(ConstructorInvocation node, env) { | 146 Configuration visitConstructorInvocation(ConstructorInvocation node, state) { |
| 149 Class class_ = new Class(node.target.enclosingClass.reference); | 147 Class class_ = new Class(node.target.enclosingClass.reference); |
| 150 | 148 |
| 151 Environment emptyEnv = new Environment.empty(); | |
| 152 // Currently we don't support initializers. | 149 // Currently we don't support initializers. |
| 153 // TODO: Modify to respect dart semantics for initialization. | 150 // TODO: Modify to respect dart semantics for initialization. |
| 154 // 1. Init fields and eval initializers, repeat the same with super. | 151 // 1. Init fields and eval initializers, repeat the same with super. |
| 155 // 2. Eval the Function body of the constructor. | 152 // 2. Eval the Function body of the constructor. |
| 156 List<Value> fields = class_.instanceFields | 153 List<Value> fields = <Value>[]; |
| 157 .map((Field f) => eval(f.initializer ?? new NullLiteral(), emptyEnv)) | |
| 158 .toList(growable: false); | |
| 159 | 154 |
| 160 return new ObjectValue(class_, fields); | 155 return state.nextConfiguration(new ObjectValue(class_, fields)); |
| 161 } | 156 } |
| 162 | 157 |
| 163 Value visitNot(Not node, env) { | 158 Configuration visitNot(Not node, state) { |
| 164 Value operand = eval(node.operand, env).toBoolean(); | 159 return new ExpressionConfiguration( |
| 165 return identical(operand, Value.trueInstance) | 160 node.operand, state.withContinuation(new NotContinuation(state))); |
| 166 ? Value.falseInstance | |
| 167 : Value.trueInstance; | |
| 168 } | 161 } |
| 169 | 162 |
| 170 Value visitLogicalExpression(LogicalExpression node, env) { | 163 Configuration visitLogicalExpression(LogicalExpression node, state) { |
| 171 if ('||' == node.operator) { | 164 if ('||' == node.operator) { |
| 172 BoolValue left = eval(node.left, env).toBoolean(); | 165 var cont = new OrContinuation(node.right, state); |
| 173 return identical(left, Value.trueInstance) | 166 return new ExpressionConfiguration( |
| 174 ? Value.trueInstance | 167 node.left, state.withContinuation(cont)); |
| 175 : eval(node.right, env).toBoolean(); | |
| 176 } else { | 168 } else { |
| 177 assert('&&' == node.operator); | 169 assert('&&' == node.operator); |
| 178 BoolValue left = eval(node.left, env).toBoolean(); | 170 var cont = new AndContinuation(node.right, state); |
| 179 return identical(left, Value.falseInstance) | 171 return new ExpressionConfiguration( |
| 180 ? Value.falseInstance | 172 node.left, state.withContinuation(cont)); |
| 181 : eval(node.right, env).toBoolean(); | |
| 182 } | 173 } |
| 183 } | 174 } |
| 184 | 175 |
| 185 Value visitConditionalExpression(ConditionalExpression node, env) { | 176 Configuration visitConditionalExpression(ConditionalExpression node, state) { |
| 186 var condition = eval(node.condition, env).toBoolean(); | 177 var cont = new ConditionalContinuation(node.then, node.otherwise, state); |
| 187 return identical(condition, Value.trueInstance) | 178 return new ExpressionConfiguration( |
| 188 ? eval(node.then, env) | 179 node.condition, state.withContinuation(cont)); |
| 189 : eval(node.otherwise, env); | |
| 190 } | 180 } |
| 191 | 181 |
| 192 Value visitStringConcatenation(StringConcatenation node, env) { | 182 Configuration visitStringConcatenation(StringConcatenation node, state) { |
| 193 StringBuffer res = new StringBuffer(); | 183 var cont = new StringConcatenationContinuation(node.expressions, state); |
| 194 for (Expression e in node.expressions) { | 184 return new ExpressionConfiguration( |
| 195 res.write(eval(e, env).value); | 185 node.expressions.first, state.withContinuation(cont)); |
| 196 } | |
| 197 return new StringValue(res.toString()); | |
| 198 } | 186 } |
| 199 | 187 |
| 200 // Evaluation of BasicLiterals. | 188 // Evaluation of BasicLiterals. |
| 201 Value visitStringLiteral(StringLiteral node, env) => | 189 Configuration visitStringLiteral(StringLiteral node, state) { |
| 202 new StringValue(node.value); | 190 return state.nextConfiguration(new StringValue(node.value)); |
| 203 Value visitIntLiteral(IntLiteral node, env) => new IntValue(node.value); | 191 } |
| 204 Value visitDoubleLiteral(DoubleLiteral node, env) => | |
| 205 new DoubleValue(node.value); | |
| 206 Value visitBoolLiteral(BoolLiteral node, env) => | |
| 207 node.value ? Value.trueInstance : Value.falseInstance; | |
| 208 Value visitNullLiteral(NullLiteral node, env) => Value.nullInstance; | |
| 209 | 192 |
| 210 Value visitLet(Let node, env) { | 193 Configuration visitIntLiteral(IntLiteral node, state) { |
| 211 var value = eval(node.variable.initializer, env); | 194 return state.nextConfiguration(new IntValue(node.value)); |
| 212 var letEnv = new Environment(env); | 195 } |
| 213 letEnv.expand(node.variable, value); | 196 |
| 214 return eval(node.body, letEnv); | 197 Configuration visitDoubleLiteral(DoubleLiteral node, state) { |
| 198 return state.nextConfiguration(new DoubleValue(node.value)); | |
| 199 } | |
| 200 | |
| 201 Configuration visitBoolLiteral(BoolLiteral node, state) { | |
| 202 Value value = node.value ? Value.trueInstance : Value.falseInstance; | |
| 203 return state.nextConfiguration(value); | |
| 204 } | |
| 205 | |
| 206 Configuration visitNullLiteral(NullLiteral node, state) { | |
| 207 return state.nextConfiguration(Value.nullInstance); | |
| 208 } | |
| 209 | |
| 210 Configuration visitLet(Let node, state) { | |
| 211 var letCont = new LetContinuation(node.variable, node.body, state); | |
| 212 return new ExpressionConfiguration( | |
| 213 node.variable.initializer, state.withContinuation(letCont)); | |
| 215 } | 214 } |
| 216 } | 215 } |
| 217 | 216 |
| 218 /// Represents a state which consists of current environment, continuation to be | 217 /// Represents a state for statement execution. |
| 219 /// applied and the current label. | |
| 220 class State { | 218 class State { |
| 221 final Environment environment; | 219 final Environment environment; |
| 222 final Label labels; | 220 final Label labels; |
| 223 final Continuation continuation; | 221 final Configuration configuration; |
|
Kevin Millikin (Google)
2017/04/20 10:50:20
This is always a StatementConfiguration isn't it (
zhivkag
2017/04/20 13:21:36
Done.
| |
| 224 | 222 |
| 225 State(this.environment, this.labels, this.continuation); | 223 final ExpressionContinuation expressionContinuation; |
|
Dmitry Stefantsov
2017/04/12 12:53:11
It think it would be easier to understand the inte
Kevin Millikin (Google)
2017/04/20 10:50:20
It's 'returnContinuaton', which seems like a good
zhivkag
2017/04/20 13:21:36
Done.
| |
| 226 State.initial() : this(new Environment.empty(), null, null); | 224 |
| 225 State(this.environment, this.labels, this.configuration, | |
| 226 this.expressionContinuation); | |
| 227 | |
| 228 State.initial() : this(new Environment.empty(), null, null, null); | |
| 227 | 229 |
| 228 State withEnvironment(Environment env) { | 230 State withEnvironment(Environment env) { |
| 229 return new State(env, labels, continuation); | 231 return new State(env, labels, configuration, expressionContinuation); |
| 230 } | 232 } |
| 231 | 233 |
| 232 State withBreak(Statement stmt) { | 234 State withBreak(Statement stmt) { |
| 235 Label breakLabels = new Label(stmt, configuration, labels); | |
| 233 return new State( | 236 return new State( |
| 234 environment, new Label(stmt, continuation, labels), continuation); | 237 environment, breakLabels, configuration, expressionContinuation); |
| 235 } | 238 } |
| 236 | 239 |
| 237 State withContinuation(Continuation cont) { | 240 State withConfiguration(Configuration config) { |
| 238 return new State(environment, labels, cont); | 241 return new State(environment, labels, config, expressionContinuation); |
| 242 } | |
| 243 | |
| 244 State withExpressionContinuation(ExpressionContinuation cont) { | |
| 245 return new State(environment, labels, configuration, cont); | |
| 239 } | 246 } |
| 240 | 247 |
| 241 Label lookupLabel(LabeledStatement s) { | 248 Label lookupLabel(LabeledStatement s) { |
| 242 assert(labels != null); | 249 assert(labels != null); |
| 243 return labels.lookupLabel(s); | 250 return labels.lookupLabel(s); |
| 244 } | 251 } |
| 245 } | 252 } |
| 246 | 253 |
| 247 /// Represent the continuation for execution of statement. | 254 /// Represents a state for expression evaluation. |
| 248 class Continuation { | 255 class ExpressionState { |
| 249 final Statement statement; | 256 /// Enclosing statement state. |
| 250 final State state; | 257 final State statementState; |
|
Dmitry Stefantsov
2017/04/12 12:53:11
Same as above with "expressionContinuation", I thi
Kevin Millikin (Google)
2017/04/20 10:50:20
I think it's unnecessary as described above.
zhivkag
2017/04/20 13:21:36
Acknowledged.
zhivkag
2017/04/20 13:21:36
Acknowledged.
| |
| 251 | 258 |
| 252 Continuation(this.statement, this.state); | 259 /// Environment in which the expression is evaluated. |
| 260 final Environment environment; | |
| 261 | |
| 262 /// Next continuation to be applied. | |
| 263 final ExpressionContinuation continuation; | |
| 264 | |
| 265 ExpressionState(this.statementState, this.environment, this.continuation); | |
| 266 | |
| 267 ExpressionState.fromStatementState(State state) | |
| 268 : this(state, state.environment, null); | |
| 269 | |
| 270 ExpressionState withEnvironment(Environment env) { | |
| 271 return new ExpressionState(statementState, env, continuation); | |
| 272 } | |
| 273 | |
| 274 ExpressionState withContinuation(ExpressionContinuation cont) { | |
| 275 return new ExpressionState(statementState, environment, cont); | |
| 276 } | |
| 277 | |
| 278 /// Returns the next [Configuration] | |
| 279 Configuration nextConfiguration(Value v) { | |
| 280 if (continuation != null) { | |
| 281 return new ContinuationConfiguration(v, continuation); | |
| 282 } | |
| 283 return statementState.configuration; | |
| 284 } | |
| 253 } | 285 } |
| 254 | 286 |
| 255 /// Represents a labeled statement, the corresponding continuation and the | 287 /// Represents a labeled statement, the corresponding continuation and the |
| 256 /// enclosing label. | 288 /// enclosing label. |
| 257 class Label { | 289 class Label { |
| 258 final LabeledStatement statement; | 290 final LabeledStatement statement; |
| 259 final Continuation continuation; | 291 final StatementConfiguration configuration; |
| 260 final Label enclosingLabel; | 292 final Label enclosingLabel; |
| 261 | 293 |
| 262 Label(this.statement, this.continuation, this.enclosingLabel); | 294 Label(this.statement, this.configuration, this.enclosingLabel); |
| 263 | 295 |
| 264 Label lookupLabel(LabeledStatement s) { | 296 Label lookupLabel(LabeledStatement s) { |
| 265 if (identical(s, statement)) return this; | 297 if (identical(s, statement)) return this; |
| 266 assert(enclosingLabel != null); | 298 assert(enclosingLabel != null); |
| 267 return enclosingLabel.lookupLabel(s); | 299 return enclosingLabel.lookupLabel(s); |
| 268 } | 300 } |
| 269 } | 301 } |
| 270 | 302 |
| 303 abstract class Configuration { | |
| 304 /// Executes the current and returns the next configuration. | |
| 305 Configuration step(StatementExecuter executer); | |
| 306 } | |
| 307 | |
| 308 /// Represents the configuration for execution of statement. | |
| 309 class StatementConfiguration extends Configuration { | |
| 310 final Statement statement; | |
| 311 final State state; | |
| 312 | |
| 313 StatementConfiguration(this.statement, this.state); | |
| 314 | |
| 315 Configuration step(StatementExecuter executer) => | |
| 316 executer.exec(statement, state); | |
| 317 } | |
| 318 | |
| 319 /// Represents the configuration for applying an [ExpressionContinuation]. | |
| 320 class ContinuationConfiguration extends Configuration { | |
| 321 final Value value; | |
| 322 final ExpressionContinuation continuation; | |
| 323 | |
| 324 ContinuationConfiguration(this.value, this.continuation); | |
|
Kevin Millikin (Google)
2017/04/20 10:50:20
I prefer the argument order to be swapped here (sw
zhivkag
2017/04/20 13:21:36
Done.
| |
| 325 | |
| 326 Configuration step(StatementExecuter executer) => continuation(value); | |
| 327 } | |
| 328 | |
| 329 /// Represents the configuration for evaluating an [Expression]. | |
| 330 class ExpressionConfiguration extends Configuration { | |
| 331 final Expression expression; | |
| 332 final ExpressionState state; | |
| 333 | |
| 334 ExpressionConfiguration(this.expression, this.state); | |
| 335 | |
| 336 Configuration step(StatementExecuter executer) => | |
| 337 executer.eval(expression, state); | |
| 338 } | |
| 339 | |
| 340 /// Represents an expression continuation. | |
| 341 abstract class ExpressionContinuation { | |
| 342 ExpressionState get state; | |
|
Kevin Millikin (Google)
2017/04/20 10:50:20
I'm not sure that every expression continuation sh
zhivkag
2017/04/20 13:21:36
Done.
| |
| 343 | |
| 344 Configuration call(Value v); | |
| 345 } | |
| 346 | |
| 347 class PrintContinuation extends ExpressionContinuation { | |
| 348 final ExpressionState state; | |
| 349 | |
| 350 PrintContinuation(this.state); | |
| 351 | |
| 352 Configuration call(Value v) { | |
| 353 print(v.value); | |
| 354 return state.nextConfiguration(Value.nullInstance); | |
| 355 } | |
| 356 } | |
| 357 | |
| 358 class PropertyGetContinuation extends ExpressionContinuation { | |
| 359 final Name name; | |
| 360 final ExpressionState state; | |
| 361 | |
| 362 PropertyGetContinuation(this.name, this.state); | |
| 363 | |
| 364 Configuration call(Value receiver) { | |
| 365 Value propertyValue = receiver.class_.lookupGetter(name)(receiver); | |
|
Kevin Millikin (Google)
2017/04/20 10:50:20
Not for this change, but we will have to find a wa
zhivkag
2017/04/20 13:21:36
Indeed. This is sufficient for now only because we
| |
| 366 return state.nextConfiguration(propertyValue); | |
| 367 } | |
| 368 } | |
| 369 | |
| 370 class PropertySetContinuation extends ExpressionContinuation { | |
| 371 final Expression value; | |
| 372 final Name setterName; | |
| 373 final ExpressionState state; | |
| 374 | |
| 375 PropertySetContinuation(this.value, this.setterName, this.state); | |
| 376 | |
| 377 Configuration call(Value receiver) { | |
| 378 Setter setter = receiver.class_.lookupSetter(setterName); | |
|
Kevin Millikin (Google)
2017/04/20 10:50:20
The spec has that setters are looked up after eval
zhivkag
2017/04/20 13:21:36
Done.
| |
| 379 var cont = new SetterContinuation(setter, receiver, state); | |
| 380 return new ExpressionConfiguration(value, state.withContinuation(cont)); | |
| 381 } | |
| 382 } | |
| 383 | |
| 384 class SetterContinuation extends ExpressionContinuation { | |
| 385 final Setter setter; | |
| 386 final Value receiver; | |
| 387 final ExpressionState state; | |
| 388 | |
| 389 SetterContinuation(this.setter, this.receiver, this.state); | |
| 390 | |
| 391 Configuration call(Value v) { | |
| 392 setter(receiver, v); | |
| 393 return state.nextConfiguration(v); | |
| 394 } | |
| 395 } | |
| 396 | |
| 397 class StaticInvocationContinuation extends ExpressionContinuation { | |
| 398 final ExpressionState state; | |
| 399 | |
| 400 StaticInvocationContinuation(this.state); | |
| 401 | |
| 402 Configuration call(Value v) { | |
| 403 return state.nextConfiguration(v); | |
| 404 } | |
| 405 } | |
| 406 | |
| 407 class MethodInvocationContinuation extends ExpressionContinuation { | |
| 408 final Arguments arguments; | |
| 409 final Name methodName; | |
| 410 final ExpressionState state; | |
| 411 | |
| 412 MethodInvocationContinuation(this.arguments, this.methodName, this.state); | |
| 413 | |
| 414 Configuration call(Value receiver) { | |
| 415 if (arguments.positional.isEmpty) { | |
| 416 Value returnValue = receiver.invokeMethod(methodName); | |
| 417 return state.nextConfiguration(returnValue); | |
| 418 } | |
| 419 var cont = | |
| 420 new ArgumentsContinuation(receiver, methodName, arguments, state); | |
| 421 | |
| 422 return new ExpressionConfiguration( | |
| 423 arguments.positional.first, state.withContinuation(cont)); | |
| 424 } | |
| 425 } | |
| 426 | |
| 427 class ArgumentsContinuation extends ExpressionContinuation { | |
| 428 final Value receiver; | |
| 429 final Name methodName; | |
| 430 final Arguments arguments; | |
| 431 final ExpressionState state; | |
| 432 | |
| 433 ArgumentsContinuation( | |
| 434 this.receiver, this.methodName, this.arguments, this.state); | |
| 435 | |
| 436 Configuration call(Value value) { | |
| 437 // Currently evaluates only one argument, for simple method invocations | |
| 438 // with 1 argument. | |
| 439 Value returnValue = receiver.invokeMethod(methodName, value); | |
| 440 return state.nextConfiguration(returnValue); | |
| 441 } | |
| 442 } | |
| 443 | |
| 444 class VariableSetContinuation extends ExpressionContinuation { | |
| 445 final ExpressionState state; | |
| 446 final VariableDeclaration variable; | |
| 447 | |
| 448 VariableSetContinuation(this.state, this.variable); | |
| 449 | |
| 450 Configuration call(Value value) { | |
| 451 state.environment.assign(variable, value); | |
| 452 return state.nextConfiguration(value); | |
| 453 } | |
| 454 } | |
| 455 | |
| 456 class NotContinuation extends ExpressionContinuation { | |
| 457 final ExpressionState state; | |
| 458 | |
| 459 NotContinuation(this.state); | |
| 460 | |
| 461 Configuration call(Value value) { | |
| 462 Value notValue = identical(Value.trueInstance, value) | |
| 463 ? Value.falseInstance | |
| 464 : Value.trueInstance; | |
| 465 return state.nextConfiguration(notValue); | |
| 466 } | |
| 467 } | |
| 468 | |
| 469 class OrContinuation extends ExpressionContinuation { | |
| 470 final Expression right; | |
| 471 final ExpressionState state; | |
| 472 | |
| 473 OrContinuation(this.right, this.state); | |
| 474 | |
| 475 Configuration call(Value left) { | |
| 476 return identical(Value.trueInstance, left) | |
| 477 ? state.nextConfiguration(Value.trueInstance) | |
| 478 : new ExpressionConfiguration(right, state); | |
| 479 } | |
| 480 } | |
| 481 | |
| 482 class AndContinuation extends ExpressionContinuation { | |
| 483 final Expression right; | |
| 484 final ExpressionState state; | |
| 485 | |
| 486 AndContinuation(this.right, this.state); | |
| 487 | |
| 488 Configuration call(Value left) { | |
| 489 return identical(Value.falseInstance, left) | |
| 490 ? state.nextConfiguration(Value.falseInstance) | |
| 491 : new ExpressionConfiguration(right, state); | |
| 492 } | |
| 493 } | |
| 494 | |
| 495 class ConditionalContinuation extends ExpressionContinuation { | |
| 496 final Expression then; | |
| 497 final Expression otherwise; | |
| 498 final ExpressionState state; | |
| 499 | |
| 500 ConditionalContinuation(this.then, this.otherwise, this.state); | |
| 501 | |
| 502 Configuration call(Value value) { | |
| 503 return identical(Value.trueInstance, value) | |
| 504 ? new ExpressionConfiguration(then, state) | |
| 505 : new ExpressionConfiguration(otherwise, state); | |
| 506 } | |
| 507 } | |
| 508 | |
| 509 class StringConcatenationContinuation extends ExpressionContinuation { | |
| 510 final List<Expression> expressions; | |
| 511 final ExpressionState state; | |
| 512 | |
| 513 int _currentPosition = 0; | |
| 514 final List<Value> _values = <Value>[]; | |
| 515 | |
| 516 StringConcatenationContinuation(this.expressions, this.state); | |
| 517 | |
| 518 Configuration call(Value value) { | |
| 519 _values.add(value); | |
| 520 if (_values.length == expressions.length) { | |
| 521 StringBuffer res = new StringBuffer(); | |
| 522 | |
| 523 for (int i = 0; i < expressions.length; i++) { | |
| 524 res.write(_values[i].value); | |
| 525 } | |
| 526 | |
| 527 Value value = new StringValue(res.toString()); | |
| 528 return state.nextConfiguration(value); | |
| 529 } | |
| 530 return new ExpressionConfiguration( | |
| 531 expressions[++_currentPosition], state.withContinuation(this)); | |
| 532 } | |
| 533 } | |
| 534 | |
| 535 class LetContinuation extends ExpressionContinuation { | |
| 536 final VariableDeclaration variable; | |
| 537 final Expression letBody; | |
| 538 final ExpressionState state; | |
| 539 | |
| 540 LetContinuation(this.variable, this.letBody, this.state); | |
| 541 | |
| 542 Configuration call(Value value) { | |
| 543 var letState = state.withEnvironment(new Environment(state.environment)); | |
| 544 letState.environment.expand(variable, value); | |
| 545 return new ExpressionConfiguration(letBody, letState); | |
| 546 } | |
| 547 } | |
| 548 | |
| 549 /// Represents the continuation for the condition expression in [WhileStatement] . | |
| 550 class WhileConditionContinuation extends ExpressionContinuation { | |
| 551 final WhileStatement node; | |
| 552 final ExpressionState state; | |
| 553 | |
| 554 WhileConditionContinuation(this.node, this.state); | |
| 555 | |
| 556 StatementConfiguration call(Value v) { | |
| 557 if (identical(v, Value.trueInstance)) { | |
| 558 // Add configuration for the While statement to the linked list. | |
| 559 StatementConfiguration config = | |
| 560 new StatementConfiguration(node, state.statementState); | |
| 561 // Configuration for the body of the loop. | |
| 562 return new StatementConfiguration( | |
| 563 node.body, state.statementState.withConfiguration(config)); | |
| 564 } | |
| 565 | |
| 566 return state.statementState.configuration; | |
| 567 } | |
| 568 } | |
| 569 | |
| 570 /// Represents the continuation for the condition expression in [IfStatement]. | |
| 571 class IfConditionContinuation extends ExpressionContinuation { | |
| 572 final Statement then; | |
| 573 final Statement otherwise; | |
| 574 final ExpressionState state; | |
| 575 | |
| 576 IfConditionContinuation(this.then, this.otherwise, this.state); | |
| 577 | |
| 578 StatementConfiguration call(Value v) { | |
| 579 if (identical(v, Value.trueInstance)) { | |
| 580 return new StatementConfiguration(then, state.statementState); | |
| 581 } else if (otherwise != null) { | |
| 582 return new StatementConfiguration(otherwise, state.statementState); | |
| 583 } | |
| 584 return state.statementState.configuration; | |
| 585 } | |
| 586 } | |
| 587 | |
| 588 /// Represents the continuation for the initializer expression in | |
| 589 /// [VariableDeclaration]. | |
| 590 class VariableInitializerContinuation extends ExpressionContinuation { | |
| 591 final VariableDeclaration variable; | |
| 592 final ExpressionState state; | |
| 593 | |
| 594 VariableInitializerContinuation(this.variable, this.state); | |
| 595 | |
| 596 StatementConfiguration call(Value v) { | |
| 597 state.statementState.environment.expand(variable, v); | |
| 598 return state.statementState.configuration; | |
| 599 } | |
| 600 } | |
| 601 | |
| 271 /// Executes statements. | 602 /// Executes statements. |
| 272 /// | 603 /// |
| 273 /// Execution of a statement completes in one of the following ways: | 604 /// Execution of a statement completes in one of the following ways: |
| 274 /// - it completes normally, in which case the execution proceeds to applying | 605 /// - it completes normally, in which case the execution proceeds to applying |
| 275 /// the next continuation | 606 /// the next continuation |
| 276 /// - it breaks with a label, in which case the corresponding continuation is | 607 /// - it breaks with a label, in which case the corresponding continuation is |
| 277 /// returned and applied | 608 /// returned and applied |
| 278 /// - it returns with or without value, TBD | 609 /// - it returns with or without value, TBD |
| 279 /// - it throws, TBD | 610 /// - it throws, TBD |
| 280 class StatementExecuter extends StatementVisitor1<Continuation> { | 611 class StatementExecuter extends StatementVisitor1<Configuration> { |
| 281 Evaluator evaluator = new Evaluator(); | 612 Evaluator evaluator = new Evaluator(); |
| 282 | 613 |
| 283 void trampolinedExecution(Continuation continuation) { | 614 void trampolinedExecution(Configuration configuration) { |
| 284 while (continuation != null) { | 615 while (configuration != null) { |
| 285 continuation = exec(continuation.statement, continuation.state); | 616 configuration = configuration.step(this); |
| 286 } | 617 } |
| 287 } | 618 } |
| 288 | 619 |
| 289 Continuation exec(Statement statement, state) => | 620 Configuration exec(Statement statement, State state) => |
| 290 statement.accept1(this, state); | 621 statement.accept1(this, state); |
| 291 Value eval(Expression expression, env) => evaluator.eval(expression, env); | 622 Configuration eval(Expression expression, ExpressionState state) => |
| 623 evaluator.eval(expression, state); | |
| 292 | 624 |
| 293 Continuation defaultStatement(Statement node, state) { | 625 Configuration defaultStatement(Statement node, state) { |
| 294 throw notImplemented( | 626 throw notImplemented( |
| 295 m: "Execution is not implemented for statement:\n$node "); | 627 m: "Execution is not implemented for statement:\n$node "); |
| 296 } | 628 } |
| 297 | 629 |
| 298 Continuation visitInvalidStatement(InvalidStatement node, state) { | 630 Configuration visitInvalidStatement(InvalidStatement node, state) { |
| 299 throw "Invalid statement at ${node.location}"; | 631 throw "Invalid statement at ${node.location}"; |
| 300 } | 632 } |
| 301 | 633 |
| 302 Continuation visitExpressionStatement(ExpressionStatement node, state) { | 634 Configuration visitExpressionStatement(ExpressionStatement node, state) { |
| 303 eval(node.expression, state.environment); | 635 return new ExpressionConfiguration( |
| 304 return state.continuation; | 636 node.expression, new ExpressionState.fromStatementState(state)); |
| 305 } | 637 } |
| 306 | 638 |
| 307 Continuation visitBlock(Block node, state) { | 639 Configuration visitBlock(Block node, state) { |
| 308 if (node.statements.isEmpty) { | 640 if (node.statements.isEmpty) { |
| 309 return state.continuation; | 641 return state.configuration; |
| 310 } | 642 } |
| 311 State blockState = | 643 State blockState = |
| 312 state.withEnvironment(new Environment(state.environment)); | 644 state.withEnvironment(new Environment(state.environment)); |
| 313 Continuation cont = state.continuation; | 645 StatementConfiguration configuration = state.configuration; |
| 314 for (Statement s in node.statements.reversed) { | 646 for (Statement s in node.statements.reversed) { |
| 315 cont = new Continuation(s, blockState.withContinuation(cont)); | 647 configuration = new StatementConfiguration( |
| 648 s, blockState.withConfiguration(configuration)); | |
| 316 } | 649 } |
| 317 return cont; | 650 return configuration; |
| 318 } | 651 } |
| 319 | 652 |
| 320 Continuation visitEmptyStatement(EmptyStatement node, state) { | 653 Configuration visitEmptyStatement(EmptyStatement node, state) { |
| 321 return state.continuation; | 654 return state.configuration; |
| 322 } | 655 } |
| 323 | 656 |
| 324 Continuation visitIfStatement(IfStatement node, state) { | 657 Configuration visitIfStatement(IfStatement node, state) { |
| 325 Value cond = eval(node.condition, state.environment).toBoolean(); | 658 var expState = new ExpressionState.fromStatementState(state); |
| 326 if (identical(Value.trueInstance, cond)) { | 659 var cont = new IfConditionContinuation(node.then, node.otherwise, expState); |
| 327 return new Continuation(node.then, state); | 660 return new ExpressionConfiguration( |
| 328 } else if (node.otherwise != null) { | 661 node.condition, expState.withContinuation(cont)); |
| 329 return new Continuation(node.otherwise, state); | |
| 330 } | |
| 331 return state.continuation; | |
| 332 } | 662 } |
| 333 | 663 |
| 334 Continuation visitLabeledStatement(LabeledStatement node, state) { | 664 Configuration visitLabeledStatement(LabeledStatement node, state) { |
| 335 return new Continuation(node.body, state.withBreak(node)); | 665 return new StatementConfiguration(node.body, state.withBreak(node)); |
| 336 } | 666 } |
| 337 | 667 |
| 338 Continuation visitBreakStatement(BreakStatement node, state) { | 668 Configuration visitBreakStatement(BreakStatement node, state) { |
| 339 return state.lookupLabel(node.target).continuation; | 669 return state.lookupLabel(node.target).configuration; |
| 340 } | 670 } |
| 341 | 671 |
| 342 Continuation visitWhileStatement(WhileStatement node, state) { | 672 Configuration visitWhileStatement(WhileStatement node, state) { |
| 343 Value cond = eval(node.condition, state.environment).toBoolean(); | 673 var expState = new ExpressionState.fromStatementState(state); |
| 344 if (identical(Value.trueInstance, cond)) { | 674 var cont = new WhileConditionContinuation(node, expState); |
| 345 // Add continuation for the While statement to the linked list. | 675 |
| 346 Continuation cont = new Continuation(node, state); | 676 return new ExpressionConfiguration( |
| 347 // Continuation for the body of the loop. | 677 node.condition, expState.withContinuation(cont)); |
| 348 return new Continuation(node.body, state.withContinuation(cont)); | |
| 349 } | |
| 350 return state.continuation; | |
| 351 } | 678 } |
| 352 | 679 |
| 353 Continuation visitDoStatement(DoStatement node, state) { | 680 Configuration visitDoStatement(DoStatement node, state) { |
| 354 WhileStatement whileStatement = | 681 WhileStatement whileStatement = |
| 355 new WhileStatement(node.condition, node.body); | 682 new WhileStatement(node.condition, node.body); |
| 356 Continuation cont = new Continuation(whileStatement, state); | 683 StatementConfiguration configuration = |
| 357 return new Continuation(node.body, state.withContinuation(cont)); | 684 new StatementConfiguration(whileStatement, state); |
| 685 | |
| 686 return new StatementConfiguration( | |
| 687 node.body, state.withConfiguration(configuration)); | |
| 358 } | 688 } |
| 359 | 689 |
| 360 Continuation visitVariableDeclaration(VariableDeclaration node, state) { | 690 Configuration visitReturnStatement(ReturnStatement node, state) { |
| 361 Value value = node.initializer != null | 691 assert(state.expressionContinuation != null); |
| 362 ? eval(node.initializer, state.environment) | 692 // The new ExpressionState contains the next expression continuation. |
| 363 : Value.nullInstance; | 693 var expState = new ExpressionState.fromStatementState(state) |
| 364 state.environment.expand(node, value); | 694 .withContinuation(state.expressionContinuation); |
| 365 return state.continuation; | 695 return new ExpressionConfiguration(node.expression, expState); |
| 696 } | |
| 697 | |
| 698 Configuration visitVariableDeclaration(VariableDeclaration node, state) { | |
| 699 if (node.initializer != null) { | |
| 700 var expState = new ExpressionState.fromStatementState(state); | |
| 701 var cont = new VariableInitializerContinuation(node, expState); | |
| 702 return new ExpressionConfiguration( | |
| 703 node.initializer, expState.withContinuation(cont)); | |
| 704 } | |
| 705 state.environment.expand(node, Value.nullInstance); | |
| 706 return state.configuration; | |
| 366 } | 707 } |
| 367 } | 708 } |
| 368 | 709 |
| 710 // ------------------------------------------------------------------------ | |
| 711 // VALUES | |
| 712 // ------------------------------------------------------------------------ | |
| 713 | |
| 369 typedef Value Getter(Value receiver); | 714 typedef Value Getter(Value receiver); |
| 370 typedef void Setter(Value receiver, Value value); | 715 typedef void Setter(Value receiver, Value value); |
| 371 | 716 |
| 372 class Class { | 717 class Class { |
| 373 static final Map<Reference, Class> _classes = <Reference, Class>{}; | 718 static final Map<Reference, Class> _classes = <Reference, Class>{}; |
| 374 | 719 |
| 375 Class superclass; | 720 Class superclass; |
| 376 List<Field> instanceFields = <Field>[]; | 721 List<Field> instanceFields = <Field>[]; |
| 377 List<Field> staticFields = <Field>[]; | 722 List<Field> staticFields = <Field>[]; |
| 378 // Implicit getters and setters for instance Fields. | 723 // Implicit getters and setters for instance Fields. |
| (...skipping 206 matching lines...) Expand 10 before | Expand all | Expand 10 after Loading... | |
| 585 | 930 |
| 586 class NullValue extends LiteralValue { | 931 class NullValue extends LiteralValue { |
| 587 Object get value => null; | 932 Object get value => null; |
| 588 | 933 |
| 589 const NullValue(); | 934 const NullValue(); |
| 590 } | 935 } |
| 591 | 936 |
| 592 notImplemented({String m, Object obj}) { | 937 notImplemented({String m, Object obj}) { |
| 593 throw new NotImplemented(m ?? 'Evaluation for $obj is not implemented'); | 938 throw new NotImplemented(m ?? 'Evaluation for $obj is not implemented'); |
| 594 } | 939 } |
| OLD | NEW |