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 |