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 |