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 | 7 |
8 class NotImplemented { | 8 class NotImplemented { |
9 String message; | 9 String message; |
10 | 10 |
(...skipping 101 matching lines...) Expand 10 before | Expand all | Expand 10 after Loading... |
112 } | 112 } |
113 | 113 |
114 Value visitVariableGet(VariableGet node, env) { | 114 Value visitVariableGet(VariableGet node, env) { |
115 return env.lookup(node.variable); | 115 return env.lookup(node.variable); |
116 } | 116 } |
117 | 117 |
118 Value visitVariableSet(VariableSet node, env) { | 118 Value visitVariableSet(VariableSet node, env) { |
119 return env.assign(node.variable, eval(node.value, env)); | 119 return env.assign(node.variable, eval(node.value, env)); |
120 } | 120 } |
121 | 121 |
| 122 Value visitPropertyGet(PropertyGet node, env) { |
| 123 Value receiver = eval(node.receiver, env); |
| 124 return receiver.classDeclaration.lookupGetter(node.name)(receiver); |
| 125 } |
| 126 |
| 127 Value visitPropertySet(PropertySet node, env) { |
| 128 Value receiver = eval(node.receiver, env); |
| 129 Value value = eval(node.value, env); |
| 130 receiver.classDeclaration.lookupSetter(node.name)(receiver, value); |
| 131 return value; |
| 132 } |
| 133 |
| 134 Value visitDirectPropertyGet(DirectPropertyGet node, env) { |
| 135 Value receiver = eval(node.receiver, env); |
| 136 return receiver.classDeclaration.getProperty(receiver, node.target); |
| 137 } |
| 138 |
| 139 Value visitDirectPropertySet(DirectPropertySet node, env) { |
| 140 Value receiver = eval(node.receiver, env); |
| 141 Value value = eval(node.value, env); |
| 142 receiver.classDeclaration.setProperty(receiver, node.target, value); |
| 143 return value; |
| 144 } |
| 145 |
| 146 Value visitStaticGet(StaticGet node, env) => defaultExpression(node, env); |
| 147 Value visitStaticSet(StaticSet node, env) => defaultExpression(node, env); |
| 148 |
122 Value visitStaticInvocation(StaticInvocation node, env) { | 149 Value visitStaticInvocation(StaticInvocation node, env) { |
123 if ('print' == node.name.toString()) { | 150 if ('print' == node.name.toString()) { |
124 // Special evaluation of print. | 151 // Special evaluation of print. |
125 var res = eval(node.arguments.positional[0], env); | 152 var res = eval(node.arguments.positional[0], env); |
126 print(res.value); | 153 print(res.value); |
127 return Value.nullInstance; | 154 return Value.nullInstance; |
128 } else { | 155 } else { |
129 throw new NotImplemented('Support for statement type ' | 156 throw new NotImplemented('Support for statement type ' |
130 '${node.runtimeType} is not implemented'); | 157 '${node.runtimeType} is not implemented'); |
131 } | 158 } |
132 } | 159 } |
133 | 160 |
134 Value visitMethodInvocation(MethodInvocation node, env) { | 161 Value visitMethodInvocation(MethodInvocation node, env) { |
135 // Currently supports only method invocation with <2 arguments and is used | 162 // Currently supports only method invocation with <2 arguments and is used |
136 // to evaluate implemented operators for int, double and String values. | 163 // to evaluate implemented operators for int, double and String values. |
137 var receiver = eval(node.receiver, env); | 164 var receiver = eval(node.receiver, env); |
138 if (node.arguments.positional.isNotEmpty) { | 165 if (node.arguments.positional.isNotEmpty) { |
139 var argValue = eval(node.arguments.positional.first, env); | 166 var argValue = eval(node.arguments.positional.first, env); |
140 return receiver.invokeMethod(node.name.name, argValue); | 167 return receiver.invokeMethod(node.name, argValue); |
141 } else { | 168 } else { |
142 return receiver.invokeMethod(node.name.name); | 169 return receiver.invokeMethod(node.name); |
143 } | 170 } |
144 } | 171 } |
145 | 172 |
146 Value visitConstructorInvocation(ConstructorInvocation node, env) => | 173 Value visitConstructorInvocation(ConstructorInvocation node, env) { |
147 defaultExpression(node, env); | 174 ClassDeclaration classDeclaration = |
| 175 new ClassDeclaration(node.target.enclosingClass.reference); |
| 176 |
| 177 Environment emptyEnv = new Environment.empty(); |
| 178 // Currently we don't support initializers. |
| 179 // TODO: Modify to respect dart semantics for initialization. |
| 180 // 1. Init fields and eval initializers, repeat the same with super. |
| 181 // 2. Eval the Function body of the constructor. |
| 182 List<Value> fields = classDeclaration.instanceFields |
| 183 .map((Field f) => eval(f.initializer, emptyEnv)) |
| 184 .toList(growable: false); |
| 185 |
| 186 return new ObjectValue(classDeclaration, fields); |
| 187 } |
148 | 188 |
149 Value visitNot(Not node, env) { | 189 Value visitNot(Not node, env) { |
150 Value operand = eval(node.operand, env).toBoolean(); | 190 Value operand = eval(node.operand, env).toBoolean(); |
151 return identical(operand, Value.trueInstance) | 191 return identical(operand, Value.trueInstance) |
152 ? Value.falseInstance | 192 ? Value.falseInstance |
153 : Value.trueInstance; | 193 : Value.trueInstance; |
154 } | 194 } |
155 | 195 |
156 Value visitLogicalExpression(LogicalExpression node, env) { | 196 Value visitLogicalExpression(LogicalExpression node, env) { |
157 if ('||' == node.operator) { | 197 if ('||' == node.operator) { |
(...skipping 36 matching lines...) Expand 10 before | Expand all | Expand 10 after Loading... |
194 Value visitNullLiteral(NullLiteral node, env) => Value.nullInstance; | 234 Value visitNullLiteral(NullLiteral node, env) => Value.nullInstance; |
195 | 235 |
196 Value visitLet(Let node, env) { | 236 Value visitLet(Let node, env) { |
197 var value = eval(node.variable.initializer, env); | 237 var value = eval(node.variable.initializer, env); |
198 var letEnv = new Environment(env); | 238 var letEnv = new Environment(env); |
199 letEnv.expand(node.variable, value); | 239 letEnv.expand(node.variable, value); |
200 return eval(node.body, letEnv); | 240 return eval(node.body, letEnv); |
201 } | 241 } |
202 } | 242 } |
203 | 243 |
| 244 typedef Value Getter(Value receiver); |
| 245 typedef void Setter(Value receiver, Value value); |
| 246 |
204 // TODO(zhivkag): Change misleading name. | 247 // TODO(zhivkag): Change misleading name. |
205 // 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. |
206 class ClassDeclaration { | 249 class ClassDeclaration { |
207 static final Map<Reference, ClassDeclaration> _classes = | 250 static final Map<Reference, ClassDeclaration> _classes = |
208 <Reference, ClassDeclaration>{}; | 251 <Reference, ClassDeclaration>{}; |
209 | 252 |
210 Class currentClass; | 253 ClassDeclaration superclass; |
211 ClassDeclaration superClass; | 254 List<Field> instanceFields = <Field>[]; |
| 255 List<Field> staticFields = <Field>[]; |
| 256 // Implicit getters and setters for instance Fields. |
| 257 Map<Name, Getter> getters = <Name, Getter>{}; |
| 258 Map<Name, Setter> setters = <Name, Setter>{}; |
212 // The initializers of static fields are evaluated the first time the field | 259 // The initializers of static fields are evaluated the first time the field |
213 // is accessed. | 260 // is accessed. |
214 List<Value> staticFields = <Value>[]; | 261 List<Value> staticFieldValues = <Value>[]; |
215 List<Procedure> getters = <Procedure>[]; | 262 |
216 List<Procedure> setters = <Procedure>[]; | |
217 List<Procedure> methods = <Procedure>[]; | 263 List<Procedure> methods = <Procedure>[]; |
218 | 264 |
219 factory ClassDeclaration(Reference classRef) { | 265 factory ClassDeclaration(Reference classRef) { |
220 if (_classes.containsKey(classRef)) { | 266 if (_classes.containsKey(classRef)) { |
221 return _classes[classRef]; | 267 return _classes[classRef]; |
222 } | 268 } |
223 _classes[classRef] = new ClassDeclaration._internal(classRef.asClass); | 269 _classes[classRef] = new ClassDeclaration._internal(classRef.asClass); |
224 return _classes[classRef]; | 270 return _classes[classRef]; |
225 } | 271 } |
226 | 272 |
227 ClassDeclaration._internal(this.currentClass) { | 273 ClassDeclaration._internal(Class currentClass) { |
228 if (currentClass.superclass != null) { | 274 if (currentClass.superclass != null) { |
229 superClass = new ClassDeclaration(currentClass.superclass.reference); | 275 superclass = new ClassDeclaration(currentClass.superclass.reference); |
230 } | 276 } |
231 // TODO: Populate getters, setters and methods. | 277 |
| 278 _populateInstanceFields(currentClass); |
| 279 |
| 280 // Populate implicit setters and getters. |
| 281 for (int i = 0; i < instanceFields.length; i++) { |
| 282 Field f = instanceFields[i]; |
| 283 assert(f.hasImplicitGetter); |
| 284 getters[f.name] = (Value receiver) => receiver.fields[i]; |
| 285 if (f.hasImplicitSetter) { |
| 286 setters[f.name] = |
| 287 (Value receiver, Value value) => receiver.fields[i] = value; |
| 288 } |
| 289 } |
| 290 // TODO: Populate methods. |
| 291 } |
| 292 |
| 293 Getter lookupGetter(Name name) { |
| 294 Getter getter = getters[name]; |
| 295 if (getter != null) return getter; |
| 296 if (superclass != null) return superclass.lookupGetter(name); |
| 297 return (Value receiver) => notImplemented(obj: name); |
| 298 } |
| 299 |
| 300 Setter lookupSetter(Name name) { |
| 301 Setter setter = setters[name]; |
| 302 if (setter != null) return setter; |
| 303 if (superclass != null) return lookupSetter(name); |
| 304 return (Value receiver, Value value) => notImplemented(obj: name); |
| 305 } |
| 306 |
| 307 Value getProperty(ObjectValue object, Member member) { |
| 308 if (member is Field) { |
| 309 int index = instanceFields.indexOf(member); |
| 310 // TODO: throw NoSuchMethodError instead. |
| 311 if (index < 0) return notImplemented(m: 'NoSuchMethod: ${member}'); |
| 312 return object.fields[index]; |
| 313 } |
| 314 return notImplemented(obj: member); |
| 315 } |
| 316 |
| 317 Value setProperty(ObjectValue object, Member member, Value value) { |
| 318 if (member is Field) { |
| 319 int index = instanceFields.indexOf(member); |
| 320 // TODO: throw NoSuchMethodError instead. |
| 321 if (index < 0) return notImplemented(m: 'NoSuchMethod: ${member}'); |
| 322 object.fields[index] = value; |
| 323 return Value.nullInstance; |
| 324 } |
| 325 return notImplemented(obj: member); |
| 326 } |
| 327 |
| 328 // Populates with the instance fields of the current class and all its |
| 329 // superclasses recursively. |
| 330 _populateInstanceFields(Class class_) { |
| 331 for (Field f in class_.fields) { |
| 332 if (f.isInstanceMember) { |
| 333 instanceFields.add(f); |
| 334 } |
| 335 } |
| 336 |
| 337 if (class_.superclass != null) { |
| 338 _populateInstanceFields(class_.superclass); |
| 339 } |
232 } | 340 } |
233 } | 341 } |
234 | 342 |
235 abstract class Value { | 343 abstract class Value { |
| 344 ClassDeclaration get classDeclaration; |
| 345 List<Value> get fields; |
236 Object get value; | 346 Object get value; |
237 | 347 |
238 static final NullValue nullInstance = const NullValue(); | 348 static final NullValue nullInstance = const NullValue(); |
239 static final BoolValue trueInstance = const BoolValue(true); | 349 static final BoolValue trueInstance = const BoolValue(true); |
240 static final BoolValue falseInstance = const BoolValue(false); | 350 static final BoolValue falseInstance = const BoolValue(false); |
241 | 351 |
242 const Value(); | 352 const Value(); |
243 | 353 |
244 BoolValue toBoolean() { | 354 BoolValue toBoolean() { |
245 return identical(this, Value.trueInstance) | 355 return identical(this, Value.trueInstance) |
246 ? Value.trueInstance | 356 ? Value.trueInstance |
247 : Value.falseInstance; | 357 : Value.falseInstance; |
248 } | 358 } |
249 | 359 |
250 BoolValue equals(Value other) => | 360 BoolValue equals(Value other) => |
251 value == other.value ? Value.trueInstance : Value.falseInstance; | 361 value == other.value ? Value.trueInstance : Value.falseInstance; |
252 | 362 |
253 Value invokeMethod(String name, [Value arg]) { | 363 Value invokeMethod(Name name, [Value arg]) { |
254 throw notImplemented(obj: name); | 364 throw notImplemented(obj: name); |
255 } | 365 } |
256 } | 366 } |
257 | 367 |
258 class ObjectValue extends Value { | 368 class ObjectValue extends Value { |
| 369 ClassDeclaration classDeclaration; |
259 List<Value> fields; | 370 List<Value> fields; |
260 ClassDeclaration classDeclaration; | |
261 | |
262 Object get value => this; | 371 Object get value => this; |
263 | 372 |
264 ObjectValue(Constructor constructor, Environment env) { | 373 ObjectValue(this.classDeclaration, this.fields); |
265 // TODO: Init fields and eval initializers, repeat the same with super. | |
266 // TODO: Eval the Function body of the constructor, with env expanded with | |
267 // {VariableDeclaration("this") => this} | |
268 notImplemented(obj: constructor.name); | |
269 } | |
270 } | 374 } |
271 | 375 |
272 class StringValue extends Value { | 376 abstract class LiteralValue extends Value { |
| 377 ClassDeclaration get classDeclaration => |
| 378 notImplemented(m: "Loading class for literal is not implemented."); |
| 379 List<Value> get fields => |
| 380 notImplemented(m: "Literal value does not have fields"); |
| 381 |
| 382 const LiteralValue(); |
| 383 } |
| 384 |
| 385 class StringValue extends LiteralValue { |
273 final String value; | 386 final String value; |
274 | 387 |
275 static final operators = <String, Function>{ | 388 static final operators = <String, Function>{ |
276 '[]': (StringValue v1, Value v2) => v1[v2], | 389 '[]': (StringValue v1, Value v2) => v1[v2], |
277 '==': (StringValue v1, Value v2) => v1.equals(v2) | 390 '==': (StringValue v1, Value v2) => v1.equals(v2) |
278 }; | 391 }; |
279 | 392 |
280 StringValue(this.value); | 393 StringValue(this.value); |
281 | 394 |
282 Value invokeMethod(String name, [Value arg]) { | 395 Value invokeMethod(Name name, [Value arg]) { |
283 if (!operators.containsKey(name)) { | 396 if (!operators.containsKey(name.name)) { |
284 return notImplemented(obj: name); | 397 return notImplemented(obj: name); |
285 } | 398 } |
286 return operators[name](this, arg); | 399 return operators[name.name](this, arg); |
287 } | 400 } |
288 | 401 |
289 // Operators | 402 // Operators |
290 Value operator [](Value index) => new StringValue(value[index.value]); | 403 Value operator [](Value index) => new StringValue(value[index.value]); |
291 } | 404 } |
292 | 405 |
293 abstract class NumValue extends Value { | 406 abstract class NumValue extends LiteralValue { |
294 num get value; | 407 num get value; |
295 | 408 |
296 NumValue(); | 409 NumValue(); |
297 | 410 |
298 factory NumValue.fromValue(num value) { | 411 factory NumValue.fromValue(num value) { |
299 if (value is int) { | 412 if (value is int) { |
300 return new IntValue(value); | 413 return new IntValue(value); |
301 } else { | 414 } else { |
302 assert(value is double); | 415 assert(value is double); |
303 return new DoubleValue(value); | 416 return new DoubleValue(value); |
304 } | 417 } |
305 } | 418 } |
306 | 419 |
307 static final operators = <String, Function>{ | 420 static final operators = <String, Function>{ |
308 '+': (NumValue v1, Value v2) => v1 + v2, | 421 '+': (NumValue v1, Value v2) => v1 + v2, |
309 '-': (NumValue v1, Value v2) => v1 - v2, | 422 '-': (NumValue v1, Value v2) => v1 - v2, |
310 '>': (NumValue v1, Value v2) => v1 > v2, | 423 '>': (NumValue v1, Value v2) => v1 > v2, |
311 '<': (NumValue v1, Value v2) => v1 < v2, | 424 '<': (NumValue v1, Value v2) => v1 < v2, |
312 '==': (NumValue v1, Value v2) => v1.equals(v2), | 425 '==': (NumValue v1, Value v2) => v1.equals(v2), |
313 'unary-': (NumValue v1) => -v1, | 426 'unary-': (NumValue v1) => -v1, |
314 }; | 427 }; |
315 | 428 |
316 Value invokeMethod(String name, [Value arg]) { | 429 Value invokeMethod(Name name, [Value arg]) { |
317 if (!operators.containsKey(name)) return notImplemented(obj: name); | 430 if (!operators.containsKey(name.name)) return notImplemented(obj: name); |
318 if (arg == null) return operators[name](this); | 431 if (arg == null) return operators[name.name](this); |
319 return operators[name](this, arg); | 432 return operators[name.name](this, arg); |
320 } | 433 } |
321 | 434 |
322 // Operators | 435 // Operators |
323 NumValue operator +(Value other) => | 436 NumValue operator +(Value other) => |
324 new NumValue.fromValue(value + other.value); | 437 new NumValue.fromValue(value + other.value); |
325 NumValue operator -(Value other) => | 438 NumValue operator -(Value other) => |
326 new NumValue.fromValue(value - other.value); | 439 new NumValue.fromValue(value - other.value); |
327 NumValue operator -() => new NumValue.fromValue(-value); | 440 NumValue operator -() => new NumValue.fromValue(-value); |
328 | 441 |
329 BoolValue operator >(Value other) => | 442 BoolValue operator >(Value other) => |
330 value > other.value ? Value.trueInstance : Value.falseInstance; | 443 value > other.value ? Value.trueInstance : Value.falseInstance; |
331 BoolValue operator <(Value other) => | 444 BoolValue operator <(Value other) => |
332 value < other.value ? Value.trueInstance : Value.falseInstance; | 445 value < other.value ? Value.trueInstance : Value.falseInstance; |
333 } | 446 } |
334 | 447 |
335 class IntValue extends NumValue { | 448 class IntValue extends NumValue { |
336 final int value; | 449 final int value; |
337 | 450 |
338 IntValue(this.value); | 451 IntValue(this.value); |
339 } | 452 } |
340 | 453 |
341 class DoubleValue extends NumValue { | 454 class DoubleValue extends NumValue { |
342 final double value; | 455 final double value; |
343 | 456 |
344 DoubleValue(this.value); | 457 DoubleValue(this.value); |
345 } | 458 } |
346 | 459 |
347 class BoolValue extends Value { | 460 class BoolValue extends LiteralValue { |
348 final bool value; | 461 final bool value; |
349 | 462 |
350 const BoolValue(this.value); | 463 const BoolValue(this.value); |
351 } | 464 } |
352 | 465 |
353 class NullValue extends Value { | 466 class NullValue extends LiteralValue { |
354 Object get value => null; | 467 Object get value => null; |
355 | 468 |
356 const NullValue(); | 469 const NullValue(); |
357 } | 470 } |
358 | 471 |
359 notImplemented({String m, Object obj}) { | 472 notImplemented({String m, Object obj}) { |
360 throw new NotImplemented(m ?? 'Evaluation for $obj is not implemented'); | 473 throw new NotImplemented(m ?? 'Evaluation for $obj is not implemented'); |
361 } | 474 } |
OLD | NEW |