| 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 | 8 |
| 8 class NotImplemented { | 9 class NotImplemented { |
| 9 String message; | 10 String message; |
| 10 | 11 |
| 11 NotImplemented(this.message); | 12 NotImplemented(this.message); |
| 12 | 13 |
| 13 String toString() => message; | 14 String toString() => message; |
| 14 } | 15 } |
| 15 | 16 |
| 16 class Interpreter { | 17 class Interpreter { |
| (...skipping 79 matching lines...) Expand 10 before | Expand all | Expand 10 after Loading... |
| 96 Value visitVariableGet(VariableGet node, env) { | 97 Value visitVariableGet(VariableGet node, env) { |
| 97 return env.lookup(node.variable); | 98 return env.lookup(node.variable); |
| 98 } | 99 } |
| 99 | 100 |
| 100 Value visitVariableSet(VariableSet node, env) { | 101 Value visitVariableSet(VariableSet node, env) { |
| 101 return env.assign(node.variable, eval(node.value, env)); | 102 return env.assign(node.variable, eval(node.value, env)); |
| 102 } | 103 } |
| 103 | 104 |
| 104 Value visitPropertyGet(PropertyGet node, env) { | 105 Value visitPropertyGet(PropertyGet node, env) { |
| 105 Value receiver = eval(node.receiver, env); | 106 Value receiver = eval(node.receiver, env); |
| 106 return receiver.classDeclaration.lookupGetter(node.name)(receiver); | 107 return receiver.class_.lookupGetter(node.name)(receiver); |
| 107 } | 108 } |
| 108 | 109 |
| 109 Value visitPropertySet(PropertySet node, env) { | 110 Value visitPropertySet(PropertySet node, env) { |
| 110 Value receiver = eval(node.receiver, env); | 111 Value receiver = eval(node.receiver, env); |
| 111 Value value = eval(node.value, env); | 112 Value value = eval(node.value, env); |
| 112 receiver.classDeclaration.lookupSetter(node.name)(receiver, value); | 113 receiver.class_.lookupSetter(node.name)(receiver, value); |
| 113 return value; | 114 return value; |
| 114 } | 115 } |
| 115 | 116 |
| 116 Value visitDirectPropertyGet(DirectPropertyGet node, env) { | 117 Value visitDirectPropertyGet(DirectPropertyGet node, env) { |
| 117 Value receiver = eval(node.receiver, env); | 118 Value receiver = eval(node.receiver, env); |
| 118 return receiver.classDeclaration.getProperty(receiver, node.target); | 119 return receiver.class_.getProperty(receiver, node.target); |
| 119 } | 120 } |
| 120 | 121 |
| 121 Value visitDirectPropertySet(DirectPropertySet node, env) { | 122 Value visitDirectPropertySet(DirectPropertySet node, env) { |
| 122 Value receiver = eval(node.receiver, env); | 123 Value receiver = eval(node.receiver, env); |
| 123 Value value = eval(node.value, env); | 124 Value value = eval(node.value, env); |
| 124 receiver.classDeclaration.setProperty(receiver, node.target, value); | 125 receiver.class_.setProperty(receiver, node.target, value); |
| 125 return value; | 126 return value; |
| 126 } | 127 } |
| 127 | 128 |
| 128 Value visitStaticGet(StaticGet node, env) => defaultExpression(node, env); | 129 Value visitStaticGet(StaticGet node, env) => defaultExpression(node, env); |
| 129 Value visitStaticSet(StaticSet node, env) => defaultExpression(node, env); | 130 Value visitStaticSet(StaticSet node, env) => defaultExpression(node, env); |
| 130 | 131 |
| 131 Value visitStaticInvocation(StaticInvocation node, env) { | 132 Value visitStaticInvocation(StaticInvocation node, env) { |
| 132 if ('print' == node.name.toString()) { | 133 if ('print' == node.name.toString()) { |
| 133 // Special evaluation of print. | 134 // Special evaluation of print. |
| 134 var res = eval(node.arguments.positional[0], env); | 135 var res = eval(node.arguments.positional[0], env); |
| (...skipping 11 matching lines...) Expand all Loading... |
| 146 var receiver = eval(node.receiver, env); | 147 var receiver = eval(node.receiver, env); |
| 147 if (node.arguments.positional.isNotEmpty) { | 148 if (node.arguments.positional.isNotEmpty) { |
| 148 var argValue = eval(node.arguments.positional.first, env); | 149 var argValue = eval(node.arguments.positional.first, env); |
| 149 return receiver.invokeMethod(node.name, argValue); | 150 return receiver.invokeMethod(node.name, argValue); |
| 150 } else { | 151 } else { |
| 151 return receiver.invokeMethod(node.name); | 152 return receiver.invokeMethod(node.name); |
| 152 } | 153 } |
| 153 } | 154 } |
| 154 | 155 |
| 155 Value visitConstructorInvocation(ConstructorInvocation node, env) { | 156 Value visitConstructorInvocation(ConstructorInvocation node, env) { |
| 156 ClassDeclaration classDeclaration = | 157 Class class_ = new Class(node.target.enclosingClass.reference); |
| 157 new ClassDeclaration(node.target.enclosingClass.reference); | |
| 158 | 158 |
| 159 Environment emptyEnv = new Environment.empty(); | 159 Environment emptyEnv = new Environment.empty(); |
| 160 // Currently we don't support initializers. | 160 // Currently we don't support initializers. |
| 161 // TODO: Modify to respect dart semantics for initialization. | 161 // TODO: Modify to respect dart semantics for initialization. |
| 162 // 1. Init fields and eval initializers, repeat the same with super. | 162 // 1. Init fields and eval initializers, repeat the same with super. |
| 163 // 2. Eval the Function body of the constructor. | 163 // 2. Eval the Function body of the constructor. |
| 164 List<Value> fields = classDeclaration.instanceFields | 164 List<Value> fields = class_.instanceFields |
| 165 .map((Field f) => eval(f.initializer, emptyEnv)) | 165 .map((Field f) => eval(f.initializer ?? new NullLiteral(), emptyEnv)) |
| 166 .toList(growable: false); | 166 .toList(growable: false); |
| 167 | 167 |
| 168 return new ObjectValue(classDeclaration, fields); | 168 return new ObjectValue(class_, fields); |
| 169 } | 169 } |
| 170 | 170 |
| 171 Value visitNot(Not node, env) { | 171 Value visitNot(Not node, env) { |
| 172 Value operand = eval(node.operand, env).toBoolean(); | 172 Value operand = eval(node.operand, env).toBoolean(); |
| 173 return identical(operand, Value.trueInstance) | 173 return identical(operand, Value.trueInstance) |
| 174 ? Value.falseInstance | 174 ? Value.falseInstance |
| 175 : Value.trueInstance; | 175 : Value.trueInstance; |
| 176 } | 176 } |
| 177 | 177 |
| 178 Value visitLogicalExpression(LogicalExpression node, env) { | 178 Value visitLogicalExpression(LogicalExpression node, env) { |
| (...skipping 88 matching lines...) Expand 10 before | Expand all | Expand 10 after Loading... |
| 267 : Value.nullInstance; | 267 : Value.nullInstance; |
| 268 env.expand(node, value); | 268 env.expand(node, value); |
| 269 } | 269 } |
| 270 } | 270 } |
| 271 | 271 |
| 272 typedef Value Getter(Value receiver); | 272 typedef Value Getter(Value receiver); |
| 273 typedef void Setter(Value receiver, Value value); | 273 typedef void Setter(Value receiver, Value value); |
| 274 | 274 |
| 275 // TODO(zhivkag): Change misleading name. | 275 // TODO(zhivkag): Change misleading name. |
| 276 // This is representation of a class in the interpreter, not a declaration. | 276 // This is representation of a class in the interpreter, not a declaration. |
| 277 class ClassDeclaration { | 277 class Class { |
| 278 static final Map<Reference, ClassDeclaration> _classes = | 278 static final Map<Reference, Class> _classes = <Reference, Class>{}; |
| 279 <Reference, ClassDeclaration>{}; | |
| 280 | 279 |
| 281 ClassDeclaration superclass; | 280 Class superclass; |
| 282 List<Field> instanceFields = <Field>[]; | 281 List<Field> instanceFields = <Field>[]; |
| 283 List<Field> staticFields = <Field>[]; | 282 List<Field> staticFields = <Field>[]; |
| 284 // Implicit getters and setters for instance Fields. | 283 // Implicit getters and setters for instance Fields. |
| 285 Map<Name, Getter> getters = <Name, Getter>{}; | 284 Map<Name, Getter> getters = <Name, Getter>{}; |
| 286 Map<Name, Setter> setters = <Name, Setter>{}; | 285 Map<Name, Setter> setters = <Name, Setter>{}; |
| 287 // The initializers of static fields are evaluated the first time the field | 286 // The initializers of static fields are evaluated the first time the field |
| 288 // is accessed. | 287 // is accessed. |
| 289 List<Value> staticFieldValues = <Value>[]; | 288 List<Value> staticFieldValues = <Value>[]; |
| 290 | 289 |
| 291 List<Procedure> methods = <Procedure>[]; | 290 List<Procedure> methods = <Procedure>[]; |
| 292 | 291 |
| 293 factory ClassDeclaration(Reference classRef) { | 292 int get instanceSize => instanceFields.length; |
| 294 if (_classes.containsKey(classRef)) { | 293 |
| 295 return _classes[classRef]; | 294 factory Class(Reference classRef) { |
| 296 } | 295 return _classes.putIfAbsent( |
| 297 _classes[classRef] = new ClassDeclaration._internal(classRef.asClass); | 296 classRef, () => new Class._internal(classRef.asClass)); |
| 298 return _classes[classRef]; | |
| 299 } | 297 } |
| 300 | 298 |
| 301 ClassDeclaration._internal(Class currentClass) { | 299 Class._internal(ast.Class currentClass) { |
| 302 if (currentClass.superclass != null) { | 300 if (currentClass.superclass != null) { |
| 303 superclass = new ClassDeclaration(currentClass.superclass.reference); | 301 superclass = new Class(currentClass.superclass.reference); |
| 304 } | 302 } |
| 305 | 303 |
| 306 _populateInstanceFields(currentClass); | 304 _populateInstanceFields(currentClass); |
| 307 | |
| 308 // Populate implicit setters and getters. | |
| 309 for (int i = 0; i < instanceFields.length; i++) { | |
| 310 Field f = instanceFields[i]; | |
| 311 assert(f.hasImplicitGetter); | |
| 312 getters[f.name] = (Value receiver) => receiver.fields[i]; | |
| 313 if (f.hasImplicitSetter) { | |
| 314 setters[f.name] = | |
| 315 (Value receiver, Value value) => receiver.fields[i] = value; | |
| 316 } | |
| 317 } | |
| 318 // TODO: Populate methods. | 305 // TODO: Populate methods. |
| 319 } | 306 } |
| 320 | 307 |
| 321 Getter lookupGetter(Name name) { | 308 Getter lookupGetter(Name name) { |
| 322 Getter getter = getters[name]; | 309 Getter getter = getters[name]; |
| 323 if (getter != null) return getter; | 310 if (getter != null) return getter; |
| 324 if (superclass != null) return superclass.lookupGetter(name); | 311 if (superclass != null) return superclass.lookupGetter(name); |
| 325 return (Value receiver) => notImplemented(obj: name); | 312 return (Value receiver) => notImplemented(obj: name); |
| 326 } | 313 } |
| 327 | 314 |
| (...skipping 18 matching lines...) Expand all Loading... |
| 346 if (member is Field) { | 333 if (member is Field) { |
| 347 int index = instanceFields.indexOf(member); | 334 int index = instanceFields.indexOf(member); |
| 348 // TODO: throw NoSuchMethodError instead. | 335 // TODO: throw NoSuchMethodError instead. |
| 349 if (index < 0) return notImplemented(m: 'NoSuchMethod: ${member}'); | 336 if (index < 0) return notImplemented(m: 'NoSuchMethod: ${member}'); |
| 350 object.fields[index] = value; | 337 object.fields[index] = value; |
| 351 return Value.nullInstance; | 338 return Value.nullInstance; |
| 352 } | 339 } |
| 353 return notImplemented(obj: member); | 340 return notImplemented(obj: member); |
| 354 } | 341 } |
| 355 | 342 |
| 356 // Populates with the instance fields of the current class and all its | 343 /// Populates instance variables and the corresponding implicit getters and |
| 357 // superclasses recursively. | 344 /// setters for the current class and its superclass recursively. |
| 358 _populateInstanceFields(Class class_) { | 345 _populateInstanceFields(ast.Class class_) { |
| 359 for (Field f in class_.fields) { | 346 if (class_.superclass != null) { |
| 360 if (f.isInstanceMember) { | 347 _populateInstanceFields(class_.superclass); |
| 361 instanceFields.add(f); | |
| 362 } | |
| 363 } | 348 } |
| 364 | 349 |
| 365 if (class_.superclass != null) { | 350 for (Field f in class_.fields) { |
| 366 _populateInstanceFields(class_.superclass); | 351 if (f.isStatic) continue; |
| 352 instanceFields.add(f); |
| 353 assert(f.hasImplicitGetter); |
| 354 |
| 355 int currentFieldIndex = instanceFields.length - 1; |
| 356 |
| 357 // Shadowing an inherited getter with the same name. |
| 358 getters[f.name] = (Value receiver) => receiver.fields[currentFieldIndex]; |
| 359 if (f.hasImplicitSetter) { |
| 360 // Shadowing an inherited setter with the same name. |
| 361 setters[f.name] = (Value receiver, Value value) => |
| 362 receiver.fields[currentFieldIndex] = value; |
| 363 } |
| 367 } | 364 } |
| 368 } | 365 } |
| 369 } | 366 } |
| 370 | 367 |
| 371 abstract class Value { | 368 abstract class Value { |
| 372 ClassDeclaration get classDeclaration; | 369 Class get class_; |
| 373 List<Value> get fields; | 370 List<Value> get fields; |
| 374 Object get value; | 371 Object get value; |
| 375 | 372 |
| 376 static final NullValue nullInstance = const NullValue(); | 373 static final NullValue nullInstance = const NullValue(); |
| 377 static final BoolValue trueInstance = const BoolValue(true); | 374 static final BoolValue trueInstance = const BoolValue(true); |
| 378 static final BoolValue falseInstance = const BoolValue(false); | 375 static final BoolValue falseInstance = const BoolValue(false); |
| 379 | 376 |
| 380 const Value(); | 377 const Value(); |
| 381 | 378 |
| 382 BoolValue toBoolean() { | 379 BoolValue toBoolean() { |
| 383 return identical(this, Value.trueInstance) | 380 return identical(this, Value.trueInstance) |
| 384 ? Value.trueInstance | 381 ? Value.trueInstance |
| 385 : Value.falseInstance; | 382 : Value.falseInstance; |
| 386 } | 383 } |
| 387 | 384 |
| 388 BoolValue equals(Value other) => | 385 BoolValue equals(Value other) => |
| 389 value == other.value ? Value.trueInstance : Value.falseInstance; | 386 value == other.value ? Value.trueInstance : Value.falseInstance; |
| 390 | 387 |
| 391 Value invokeMethod(Name name, [Value arg]) { | 388 Value invokeMethod(Name name, [Value arg]) { |
| 392 throw notImplemented(obj: name); | 389 throw notImplemented(obj: name); |
| 393 } | 390 } |
| 394 } | 391 } |
| 395 | 392 |
| 396 class ObjectValue extends Value { | 393 class ObjectValue extends Value { |
| 397 ClassDeclaration classDeclaration; | 394 Class class_; |
| 398 List<Value> fields; | 395 List<Value> fields; |
| 399 Object get value => this; | 396 Object get value => this; |
| 400 | 397 |
| 401 ObjectValue(this.classDeclaration, this.fields); | 398 ObjectValue(this.class_, this.fields); |
| 402 } | 399 } |
| 403 | 400 |
| 404 abstract class LiteralValue extends Value { | 401 abstract class LiteralValue extends Value { |
| 405 ClassDeclaration get classDeclaration => | 402 Class get class_ => |
| 406 notImplemented(m: "Loading class for literal is not implemented."); | 403 notImplemented(m: "Loading class for literal is not implemented."); |
| 407 List<Value> get fields => | 404 List<Value> get fields => |
| 408 notImplemented(m: "Literal value does not have fields"); | 405 notImplemented(m: "Literal value does not have fields"); |
| 409 | 406 |
| 410 const LiteralValue(); | 407 const LiteralValue(); |
| 411 } | 408 } |
| 412 | 409 |
| 413 class StringValue extends LiteralValue { | 410 class StringValue extends LiteralValue { |
| 414 final String value; | 411 final String value; |
| 415 | 412 |
| (...skipping 77 matching lines...) Expand 10 before | Expand all | Expand 10 after Loading... |
| 493 | 490 |
| 494 class NullValue extends LiteralValue { | 491 class NullValue extends LiteralValue { |
| 495 Object get value => null; | 492 Object get value => null; |
| 496 | 493 |
| 497 const NullValue(); | 494 const NullValue(); |
| 498 } | 495 } |
| 499 | 496 |
| 500 notImplemented({String m, Object obj}) { | 497 notImplemented({String m, Object obj}) { |
| 501 throw new NotImplemented(m ?? 'Evaluation for $obj is not implemented'); | 498 throw new NotImplemented(m ?? 'Evaluation for $obj is not implemented'); |
| 502 } | 499 } |
| OLD | NEW |