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 | 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 97 matching lines...) Expand 10 before | Expand all | Expand 10 after Loading... | |
| 114 Value visitVariableGet(VariableGet node, env) { | 115 Value visitVariableGet(VariableGet node, env) { |
| 115 return env.lookup(node.variable); | 116 return env.lookup(node.variable); |
| 116 } | 117 } |
| 117 | 118 |
| 118 Value visitVariableSet(VariableSet node, env) { | 119 Value visitVariableSet(VariableSet node, env) { |
| 119 return env.assign(node.variable, eval(node.value, env)); | 120 return env.assign(node.variable, eval(node.value, env)); |
| 120 } | 121 } |
| 121 | 122 |
| 122 Value visitPropertyGet(PropertyGet node, env) { | 123 Value visitPropertyGet(PropertyGet node, env) { |
| 123 Value receiver = eval(node.receiver, env); | 124 Value receiver = eval(node.receiver, env); |
| 124 return receiver.classDeclaration.lookupGetter(node.name)(receiver); | 125 return receiver.class_.lookupGetter(node.name)(receiver); |
| 125 } | 126 } |
| 126 | 127 |
| 127 Value visitPropertySet(PropertySet node, env) { | 128 Value visitPropertySet(PropertySet node, env) { |
| 128 Value receiver = eval(node.receiver, env); | 129 Value receiver = eval(node.receiver, env); |
| 129 Value value = eval(node.value, env); | 130 Value value = eval(node.value, env); |
| 130 receiver.classDeclaration.lookupSetter(node.name)(receiver, value); | 131 receiver.class_.lookupSetter(node.name)(receiver, value); |
| 131 return value; | 132 return value; |
| 132 } | 133 } |
| 133 | 134 |
| 134 Value visitDirectPropertyGet(DirectPropertyGet node, env) { | 135 Value visitDirectPropertyGet(DirectPropertyGet node, env) { |
| 135 Value receiver = eval(node.receiver, env); | 136 Value receiver = eval(node.receiver, env); |
| 136 return receiver.classDeclaration.getProperty(receiver, node.target); | 137 return receiver.class_.getProperty(receiver, node.target); |
| 137 } | 138 } |
| 138 | 139 |
| 139 Value visitDirectPropertySet(DirectPropertySet node, env) { | 140 Value visitDirectPropertySet(DirectPropertySet node, env) { |
| 140 Value receiver = eval(node.receiver, env); | 141 Value receiver = eval(node.receiver, env); |
| 141 Value value = eval(node.value, env); | 142 Value value = eval(node.value, env); |
| 142 receiver.classDeclaration.setProperty(receiver, node.target, value); | 143 receiver.class_.setProperty(receiver, node.target, value); |
| 143 return value; | 144 return value; |
| 144 } | 145 } |
| 145 | 146 |
| 146 Value visitStaticGet(StaticGet node, env) => defaultExpression(node, env); | 147 Value visitStaticGet(StaticGet node, env) => defaultExpression(node, env); |
| 147 Value visitStaticSet(StaticSet node, env) => defaultExpression(node, env); | 148 Value visitStaticSet(StaticSet node, env) => defaultExpression(node, env); |
| 148 | 149 |
| 149 Value visitStaticInvocation(StaticInvocation node, env) { | 150 Value visitStaticInvocation(StaticInvocation node, env) { |
| 150 if ('print' == node.name.toString()) { | 151 if ('print' == node.name.toString()) { |
| 151 // Special evaluation of print. | 152 // Special evaluation of print. |
| 152 var res = eval(node.arguments.positional[0], env); | 153 var res = eval(node.arguments.positional[0], env); |
| (...skipping 11 matching lines...) Expand all Loading... | |
| 164 var receiver = eval(node.receiver, env); | 165 var receiver = eval(node.receiver, env); |
| 165 if (node.arguments.positional.isNotEmpty) { | 166 if (node.arguments.positional.isNotEmpty) { |
| 166 var argValue = eval(node.arguments.positional.first, env); | 167 var argValue = eval(node.arguments.positional.first, env); |
| 167 return receiver.invokeMethod(node.name, argValue); | 168 return receiver.invokeMethod(node.name, argValue); |
| 168 } else { | 169 } else { |
| 169 return receiver.invokeMethod(node.name); | 170 return receiver.invokeMethod(node.name); |
| 170 } | 171 } |
| 171 } | 172 } |
| 172 | 173 |
| 173 Value visitConstructorInvocation(ConstructorInvocation node, env) { | 174 Value visitConstructorInvocation(ConstructorInvocation node, env) { |
| 174 ClassDeclaration classDeclaration = | 175 Class class_ = new Class(node.target.enclosingClass.reference); |
| 175 new ClassDeclaration(node.target.enclosingClass.reference); | |
| 176 | 176 |
| 177 Environment emptyEnv = new Environment.empty(); | 177 Environment emptyEnv = new Environment.empty(); |
| 178 // Currently we don't support initializers. | 178 // Currently we don't support initializers. |
| 179 // TODO: Modify to respect dart semantics for initialization. | 179 // TODO: Modify to respect dart semantics for initialization. |
| 180 // 1. Init fields and eval initializers, repeat the same with super. | 180 // 1. Init fields and eval initializers, repeat the same with super. |
| 181 // 2. Eval the Function body of the constructor. | 181 // 2. Eval the Function body of the constructor. |
| 182 List<Value> fields = classDeclaration.instanceFields | 182 List<Value> fields = class_.instanceFields |
| 183 .map((Field f) => eval(f.initializer, emptyEnv)) | 183 .map((Field f) => eval(f.initializer ?? new NullLiteral(), emptyEnv)) |
| 184 .toList(growable: false); | 184 .toList(growable: false); |
| 185 | 185 |
| 186 return new ObjectValue(classDeclaration, fields); | 186 return new ObjectValue(class_, fields); |
| 187 } | 187 } |
| 188 | 188 |
| 189 Value visitNot(Not node, env) { | 189 Value visitNot(Not node, env) { |
| 190 Value operand = eval(node.operand, env).toBoolean(); | 190 Value operand = eval(node.operand, env).toBoolean(); |
| 191 return identical(operand, Value.trueInstance) | 191 return identical(operand, Value.trueInstance) |
| 192 ? Value.falseInstance | 192 ? Value.falseInstance |
| 193 : Value.trueInstance; | 193 : Value.trueInstance; |
| 194 } | 194 } |
| 195 | 195 |
| 196 Value visitLogicalExpression(LogicalExpression node, env) { | 196 Value visitLogicalExpression(LogicalExpression node, env) { |
| (...skipping 42 matching lines...) Expand 10 before | Expand all | Expand 10 after Loading... | |
| 239 letEnv.expand(node.variable, value); | 239 letEnv.expand(node.variable, value); |
| 240 return eval(node.body, letEnv); | 240 return eval(node.body, letEnv); |
| 241 } | 241 } |
| 242 } | 242 } |
| 243 | 243 |
| 244 typedef Value Getter(Value receiver); | 244 typedef Value Getter(Value receiver); |
| 245 typedef void Setter(Value receiver, Value value); | 245 typedef void Setter(Value receiver, Value value); |
| 246 | 246 |
| 247 // TODO(zhivkag): Change misleading name. | 247 // TODO(zhivkag): Change misleading name. |
| 248 // This is representation of a class in the interpreter, not a declaration. | 248 // This is representation of a class in the interpreter, not a declaration. |
| 249 class ClassDeclaration { | 249 class Class { |
| 250 static final Map<Reference, ClassDeclaration> _classes = | 250 static final Map<Reference, Class> _classes = <Reference, Class>{}; |
| 251 <Reference, ClassDeclaration>{}; | |
| 252 | 251 |
| 253 ClassDeclaration superclass; | 252 Class superclass; |
| 254 List<Field> instanceFields = <Field>[]; | 253 List<Field> instanceFields = <Field>[]; |
| 255 List<Field> staticFields = <Field>[]; | 254 List<Field> staticFields = <Field>[]; |
| 256 // Implicit getters and setters for instance Fields. | 255 // Implicit getters and setters for instance Fields. |
| 257 Map<Name, Getter> getters = <Name, Getter>{}; | 256 Map<Name, Getter> getters = <Name, Getter>{}; |
| 258 Map<Name, Setter> setters = <Name, Setter>{}; | 257 Map<Name, Setter> setters = <Name, Setter>{}; |
| 259 // The initializers of static fields are evaluated the first time the field | 258 // The initializers of static fields are evaluated the first time the field |
| 260 // is accessed. | 259 // is accessed. |
| 261 List<Value> staticFieldValues = <Value>[]; | 260 List<Value> staticFieldValues = <Value>[]; |
| 262 | 261 |
| 263 List<Procedure> methods = <Procedure>[]; | 262 List<Procedure> methods = <Procedure>[]; |
| 264 | 263 |
| 265 factory ClassDeclaration(Reference classRef) { | 264 int get classSize => instanceFields.length; |
|
Kevin Millikin (Google)
2017/03/28 06:56:26
This is more like instanceSize.
zhivkag
2017/03/28 09:18:14
Done.
| |
| 265 | |
| 266 factory Class(Reference classRef) { | |
| 266 if (_classes.containsKey(classRef)) { | 267 if (_classes.containsKey(classRef)) { |
|
Kevin Millikin (Google)
2017/03/28 06:56:26
This pattern is in the libraries as putIfAbsent so
zhivkag
2017/03/28 09:18:14
Done.
| |
| 267 return _classes[classRef]; | 268 return _classes[classRef]; |
| 268 } | 269 } |
| 269 _classes[classRef] = new ClassDeclaration._internal(classRef.asClass); | 270 _classes[classRef] = new Class._internal(classRef.asClass); |
| 270 return _classes[classRef]; | 271 return _classes[classRef]; |
| 271 } | 272 } |
| 272 | 273 |
| 273 ClassDeclaration._internal(Class currentClass) { | 274 Class._internal(ast.Class currentClass) { |
| 274 if (currentClass.superclass != null) { | 275 if (currentClass.superclass != null) { |
| 275 superclass = new ClassDeclaration(currentClass.superclass.reference); | 276 superclass = new Class(currentClass.superclass.reference); |
| 276 } | 277 } |
| 277 | 278 |
| 278 _populateInstanceFields(currentClass); | 279 _populateInstanceFields(currentClass); |
| 279 | 280 |
| 280 // Populate implicit setters and getters. | 281 // Populate implicit setters and getters. |
| 281 for (int i = 0; i < instanceFields.length; i++) { | 282 for (int i = (superclass?.classSize ?? 0); i < instanceFields.length; i++) { |
|
Kevin Millikin (Google)
2017/03/28 06:56:26
I think it makes sense to move this into _populate
zhivkag
2017/03/28 09:18:14
Done.
| |
| 282 Field f = instanceFields[i]; | 283 Field f = instanceFields[i]; |
| 283 assert(f.hasImplicitGetter); | 284 assert(f.hasImplicitGetter); |
| 284 getters[f.name] = (Value receiver) => receiver.fields[i]; | 285 getters[f.name] = (Value receiver) => receiver.fields[i]; |
| 285 if (f.hasImplicitSetter) { | 286 if (f.hasImplicitSetter) { |
| 286 setters[f.name] = | 287 setters[f.name] = |
| 287 (Value receiver, Value value) => receiver.fields[i] = value; | 288 (Value receiver, Value value) => receiver.fields[i] = value; |
| 288 } | 289 } |
| 289 } | 290 } |
| 290 // TODO: Populate methods. | 291 // TODO: Populate methods. |
| 291 } | 292 } |
| (...skipping 28 matching lines...) Expand all Loading... | |
| 320 // TODO: throw NoSuchMethodError instead. | 321 // TODO: throw NoSuchMethodError instead. |
| 321 if (index < 0) return notImplemented(m: 'NoSuchMethod: ${member}'); | 322 if (index < 0) return notImplemented(m: 'NoSuchMethod: ${member}'); |
| 322 object.fields[index] = value; | 323 object.fields[index] = value; |
| 323 return Value.nullInstance; | 324 return Value.nullInstance; |
| 324 } | 325 } |
| 325 return notImplemented(obj: member); | 326 return notImplemented(obj: member); |
| 326 } | 327 } |
| 327 | 328 |
| 328 // Populates with the instance fields of the current class and all its | 329 // Populates with the instance fields of the current class and all its |
| 329 // superclasses recursively. | 330 // superclasses recursively. |
| 330 _populateInstanceFields(Class class_) { | 331 _populateInstanceFields(ast.Class class_) { |
| 332 if (class_.superclass != null) { | |
| 333 _populateInstanceFields(class_.superclass); | |
| 334 } | |
| 331 for (Field f in class_.fields) { | 335 for (Field f in class_.fields) { |
| 332 if (f.isInstanceMember) { | 336 if (f.isInstanceMember) { |
| 333 instanceFields.add(f); | 337 instanceFields.add(f); |
| 334 } | 338 } |
| 335 } | 339 } |
| 336 | |
| 337 if (class_.superclass != null) { | |
| 338 _populateInstanceFields(class_.superclass); | |
| 339 } | |
| 340 } | 340 } |
| 341 } | 341 } |
| 342 | 342 |
| 343 abstract class Value { | 343 abstract class Value { |
| 344 ClassDeclaration get classDeclaration; | 344 Class get class_; |
| 345 List<Value> get fields; | 345 List<Value> get fields; |
| 346 Object get value; | 346 Object get value; |
| 347 | 347 |
| 348 static final NullValue nullInstance = const NullValue(); | 348 static final NullValue nullInstance = const NullValue(); |
| 349 static final BoolValue trueInstance = const BoolValue(true); | 349 static final BoolValue trueInstance = const BoolValue(true); |
| 350 static final BoolValue falseInstance = const BoolValue(false); | 350 static final BoolValue falseInstance = const BoolValue(false); |
| 351 | 351 |
| 352 const Value(); | 352 const Value(); |
| 353 | 353 |
| 354 BoolValue toBoolean() { | 354 BoolValue toBoolean() { |
| 355 return identical(this, Value.trueInstance) | 355 return identical(this, Value.trueInstance) |
| 356 ? Value.trueInstance | 356 ? Value.trueInstance |
| 357 : Value.falseInstance; | 357 : Value.falseInstance; |
| 358 } | 358 } |
| 359 | 359 |
| 360 BoolValue equals(Value other) => | 360 BoolValue equals(Value other) => |
| 361 value == other.value ? Value.trueInstance : Value.falseInstance; | 361 value == other.value ? Value.trueInstance : Value.falseInstance; |
| 362 | 362 |
| 363 Value invokeMethod(Name name, [Value arg]) { | 363 Value invokeMethod(Name name, [Value arg]) { |
| 364 throw notImplemented(obj: name); | 364 throw notImplemented(obj: name); |
| 365 } | 365 } |
| 366 } | 366 } |
| 367 | 367 |
| 368 class ObjectValue extends Value { | 368 class ObjectValue extends Value { |
| 369 ClassDeclaration classDeclaration; | 369 Class class_; |
| 370 List<Value> fields; | 370 List<Value> fields; |
| 371 Object get value => this; | 371 Object get value => this; |
| 372 | 372 |
| 373 ObjectValue(this.classDeclaration, this.fields); | 373 ObjectValue(this.class_, this.fields); |
| 374 } | 374 } |
| 375 | 375 |
| 376 abstract class LiteralValue extends Value { | 376 abstract class LiteralValue extends Value { |
| 377 ClassDeclaration get classDeclaration => | 377 Class get class_ => |
| 378 notImplemented(m: "Loading class for literal is not implemented."); | 378 notImplemented(m: "Loading class for literal is not implemented."); |
| 379 List<Value> get fields => | 379 List<Value> get fields => |
| 380 notImplemented(m: "Literal value does not have fields"); | 380 notImplemented(m: "Literal value does not have fields"); |
| 381 | 381 |
| 382 const LiteralValue(); | 382 const LiteralValue(); |
| 383 } | 383 } |
| 384 | 384 |
| 385 class StringValue extends LiteralValue { | 385 class StringValue extends LiteralValue { |
| 386 final String value; | 386 final String value; |
| 387 | 387 |
| (...skipping 77 matching lines...) Expand 10 before | Expand all | Expand 10 after Loading... | |
| 465 | 465 |
| 466 class NullValue extends LiteralValue { | 466 class NullValue extends LiteralValue { |
| 467 Object get value => null; | 467 Object get value => null; |
| 468 | 468 |
| 469 const NullValue(); | 469 const NullValue(); |
| 470 } | 470 } |
| 471 | 471 |
| 472 notImplemented({String m, Object obj}) { | 472 notImplemented({String m, Object obj}) { |
| 473 throw new NotImplemented(m ?? 'Evaluation for $obj is not implemented'); | 473 throw new NotImplemented(m ?? 'Evaluation for $obj is not implemented'); |
| 474 } | 474 } |
| OLD | NEW |