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 | 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 ObjectValue receiver = eval(node.receiver, env); | |
|
Kevin Millikin (Google)
2017/03/23 10:42:51
We have to support property get on things like int
zhivkag
2017/03/23 13:50:39
Indeed, thanks! Done.
| |
| 124 return receiver.propertyGet(node.name); | |
|
Kevin Millikin (Google)
2017/03/23 10:42:50
I suggest we factor this slightly differently:
1.
zhivkag
2017/03/23 13:50:38
Done.
| |
| 125 } | |
| 126 | |
| 127 Value visitPropertySet(PropertySet node, env) { | |
| 128 ObjectValue receiver = eval(node.receiver, env); | |
| 129 Value value = eval(node.value, env); | |
| 130 return receiver.propertySet(node.name, value); | |
| 131 } | |
| 132 | |
| 133 Value visitDirectPropertyGet(DirectPropertyGet node, env) { | |
| 134 ObjectValue receiver = eval(node.receiver, env); | |
| 135 return receiver.directPropertyGet(node.target); | |
| 136 } | |
| 137 | |
| 138 Value visitDirectPropertySet(DirectPropertySet node, env) { | |
| 139 ObjectValue receiver = eval(node.receiver, env); | |
| 140 Value value = eval(node.value, env); | |
| 141 return receiver.directPropertySet(node.target, value); | |
| 142 } | |
| 143 | |
| 144 Value visitStaticGet(StaticGet node, env) => defaultExpression(node, env); | |
| 145 Value visitStaticSet(StaticSet node, env) => defaultExpression(node, env); | |
| 146 | |
| 122 Value visitStaticInvocation(StaticInvocation node, env) { | 147 Value visitStaticInvocation(StaticInvocation node, env) { |
| 123 if ('print' == node.name.toString()) { | 148 if ('print' == node.name.toString()) { |
| 124 // Special evaluation of print. | 149 // Special evaluation of print. |
| 125 var res = eval(node.arguments.positional[0], env); | 150 var res = eval(node.arguments.positional[0], env); |
| 126 print(res.value); | 151 print(res.value); |
| 127 return Value.nullInstance; | 152 return Value.nullInstance; |
| 128 } else { | 153 } else { |
| 129 throw new NotImplemented('Support for statement type ' | 154 throw new NotImplemented('Support for statement type ' |
| 130 '${node.runtimeType} is not implemented'); | 155 '${node.runtimeType} is not implemented'); |
| 131 } | 156 } |
| 132 } | 157 } |
| 133 | 158 |
| 134 Value visitMethodInvocation(MethodInvocation node, env) { | 159 Value visitMethodInvocation(MethodInvocation node, env) { |
| 135 // Currently supports only method invocation with <2 arguments and is used | 160 // Currently supports only method invocation with <2 arguments and is used |
| 136 // to evaluate implemented operators for int, double and String values. | 161 // to evaluate implemented operators for int, double and String values. |
| 137 var receiver = eval(node.receiver, env); | 162 var receiver = eval(node.receiver, env); |
| 138 if (node.arguments.positional.isNotEmpty) { | 163 if (node.arguments.positional.isNotEmpty) { |
| 139 var argValue = eval(node.arguments.positional.first, env); | 164 var argValue = eval(node.arguments.positional.first, env); |
| 140 return receiver.invokeMethod(node.name.name, argValue); | 165 return receiver.invokeMethod(node.name, argValue); |
| 141 } else { | 166 } else { |
| 142 return receiver.invokeMethod(node.name.name); | 167 return receiver.invokeMethod(node.name); |
| 143 } | 168 } |
| 144 } | 169 } |
| 145 | 170 |
| 146 Value visitConstructorInvocation(ConstructorInvocation node, env) => | 171 Value visitConstructorInvocation(ConstructorInvocation node, env) { |
| 147 defaultExpression(node, env); | 172 ClassDeclaration classDeclaration = |
| 173 new ClassDeclaration(node.target.enclosingClass.reference); | |
| 174 | |
| 175 Environment emptyEnv = new Environment.empty(); | |
| 176 // Currently we don't support initializers. | |
| 177 // TODO: Modify to respect dart semantics for initialization. | |
| 178 // 1. Init fields and eval initializers, repeat the same with super. | |
| 179 // 2. Eval the Function body of the constructor. | |
| 180 List<Value> fields = classDeclaration.instanceFields | |
| 181 .map((Field f) => eval(f.initializer, emptyEnv)) | |
| 182 .toList(growable: false); | |
| 183 | |
| 184 return new ObjectValue(classDeclaration, fields); | |
| 185 } | |
| 148 | 186 |
| 149 Value visitNot(Not node, env) { | 187 Value visitNot(Not node, env) { |
| 150 Value operand = eval(node.operand, env).toBoolean(); | 188 Value operand = eval(node.operand, env).toBoolean(); |
| 151 return identical(operand, Value.trueInstance) | 189 return identical(operand, Value.trueInstance) |
| 152 ? Value.falseInstance | 190 ? Value.falseInstance |
| 153 : Value.trueInstance; | 191 : Value.trueInstance; |
| 154 } | 192 } |
| 155 | 193 |
| 156 Value visitLogicalExpression(LogicalExpression node, env) { | 194 Value visitLogicalExpression(LogicalExpression node, env) { |
| 157 if ('||' == node.operator) { | 195 if ('||' == node.operator) { |
| (...skipping 42 matching lines...) Expand 10 before | Expand all | Expand 10 after Loading... | |
| 200 return eval(node.body, letEnv); | 238 return eval(node.body, letEnv); |
| 201 } | 239 } |
| 202 } | 240 } |
| 203 | 241 |
| 204 // TODO(zhivkag): Change misleading name. | 242 // TODO(zhivkag): Change misleading name. |
| 205 // This is representation of a class in the interpreter, not a declaration. | 243 // This is representation of a class in the interpreter, not a declaration. |
| 206 class ClassDeclaration { | 244 class ClassDeclaration { |
| 207 static final Map<Reference, ClassDeclaration> _classes = | 245 static final Map<Reference, ClassDeclaration> _classes = |
| 208 <Reference, ClassDeclaration>{}; | 246 <Reference, ClassDeclaration>{}; |
| 209 | 247 |
| 210 Class currentClass; | 248 Class superClass; |
|
Kevin Millikin (Google)
2017/03/23 10:42:51
We might not agree, but superclass is one word in
zhivkag
2017/03/23 13:50:38
Done.
| |
| 211 ClassDeclaration superClass; | 249 List<Field> instanceFields = <Field>[]; |
| 250 List<Field> staticFields = <Field>[]; | |
| 251 // Implicit getters and setters for instance Fields. | |
| 252 Map<Name, int> getters = <Name, int>{}; | |
|
Kevin Millikin (Google)
2017/03/23 10:42:51
Thinking ahead, this needs to map names to getters
zhivkag
2017/03/23 13:50:38
Done.
| |
| 253 Map<Name, int> setters = <Name, int>{}; | |
| 212 // The initializers of static fields are evaluated the first time the field | 254 // The initializers of static fields are evaluated the first time the field |
| 213 // is accessed. | 255 // is accessed. |
| 214 List<Value> staticFields = <Value>[]; | 256 List<Value> staticFieldValues = <Value>[]; |
| 215 List<Procedure> getters = <Procedure>[]; | 257 |
| 216 List<Procedure> setters = <Procedure>[]; | |
| 217 List<Procedure> methods = <Procedure>[]; | 258 List<Procedure> methods = <Procedure>[]; |
| 218 | 259 |
| 219 factory ClassDeclaration(Reference classRef) { | 260 factory ClassDeclaration(Reference classRef) { |
| 220 if (_classes.containsKey(classRef)) { | 261 if (_classes.containsKey(classRef)) { |
| 221 return _classes[classRef]; | 262 return _classes[classRef]; |
| 222 } | 263 } |
| 223 _classes[classRef] = new ClassDeclaration._internal(classRef.asClass); | 264 _classes[classRef] = new ClassDeclaration._internal(classRef.asClass); |
| 224 return _classes[classRef]; | 265 return _classes[classRef]; |
| 225 } | 266 } |
| 226 | 267 |
| 227 ClassDeclaration._internal(this.currentClass) { | 268 ClassDeclaration._internal(Class currentClass) { |
| 228 if (currentClass.superclass != null) { | 269 if (currentClass.superclass != null) { |
| 229 superClass = new ClassDeclaration(currentClass.superclass.reference); | 270 superClass = currentClass.superclass; |
| 230 } | 271 } |
| 231 // TODO: Populate getters, setters and methods. | 272 |
| 273 _populateInstanceFields(currentClass); | |
| 274 | |
| 275 // Populate implicit setters and getters. | |
| 276 for (int i = 0; i < instanceFields.length; i++) { | |
| 277 Field f = instanceFields[i]; | |
| 278 assert(f.hasImplicitGetter); | |
| 279 getters[f.name] = i; | |
|
Kevin Millikin (Google)
2017/03/23 10:42:51
So the getter function should be:
getters[f.name]
zhivkag
2017/03/23 13:50:38
Done.
| |
| 280 if (f.hasImplicitSetter) { | |
| 281 setters[f.name] = i; | |
| 282 } | |
| 283 } | |
| 284 // TODO: Populate methods. | |
| 285 } | |
| 286 | |
| 287 Value propertyGet(ObjectValue object, Name name) { | |
|
Kevin Millikin (Google)
2017/03/23 10:42:51
The name should be the verb form: getProperty.
zhivkag
2017/03/23 13:50:38
Done.
| |
| 288 if (getters.containsKey(name)) { | |
|
Kevin Millikin (Google)
2017/03/23 10:42:51
We should look in the superclass for a getter. If
zhivkag
2017/03/23 13:50:38
Makes sense, thanks! Done.
| |
| 289 return (object.fields)[getters[name]]; | |
| 290 } | |
| 291 // TODO: return NoSuchMethod if Name is not a Getter or Method tear-off | |
| 292 return notImplemented(obj: name); | |
| 293 } | |
| 294 | |
| 295 Value propertySet(ObjectValue object, Name name, Value value) { | |
|
Kevin Millikin (Google)
2017/03/23 10:42:51
Likewise, I's split this into looking up the sette
zhivkag
2017/03/23 13:50:39
Applied the suggestion but I have a doubt whether
| |
| 296 if (setters.containsKey(name)) { | |
| 297 object.fields[setters[name]] = value; | |
| 298 } | |
| 299 // TODO: return NoSuchMethodError if Name is not a Setter. | |
| 300 return Value.nullInstance; | |
| 301 } | |
| 302 | |
| 303 Value directPropertyGet(ObjectValue object, Member member) { | |
| 304 if (member is Field) { | |
| 305 for (int i = 0; i < instanceFields.length; i++) { | |
| 306 if (identical(member, instanceFields[i])) { | |
| 307 return object.fields[i]; | |
| 308 } | |
| 309 } | |
| 310 // TODO: throw NoSuchMethodError instead. | |
| 311 return notImplemented(m: 'NoSuchMethod: Field ${member} not found.'); | |
| 312 } | |
| 313 return notImplemented(obj: member); | |
| 314 } | |
| 315 | |
| 316 Value directPropertySet(ObjectValue object, Member member, Value value) { | |
| 317 if (member is Field) { | |
| 318 for (int i = 0; i < instanceFields.length; i++) { | |
| 319 if (identical(member, instanceFields[i])) { | |
| 320 object.fields[i] = value; | |
| 321 } | |
| 322 return Value.nullInstance; | |
| 323 } | |
| 324 // TODO: throw NoSuchMethodError instead. | |
| 325 return notImplemented(m: 'NoSuchMethod: Field $member not found.'); | |
| 326 } | |
| 327 return notImplemented(obj: member); | |
| 328 } | |
| 329 | |
| 330 // Populates with the instance fields of the current class and all its | |
| 331 // superclasses recursively. | |
| 332 _populateInstanceFields(Class class_) { | |
| 333 for (Field f in class_.fields) { | |
| 334 if (f.isInstanceMember) { | |
| 335 instanceFields.add(f); | |
| 336 } | |
| 337 } | |
| 338 | |
| 339 if (class_.superclass != null) { | |
| 340 _populateInstanceFields(class_.superclass); | |
| 341 } | |
| 232 } | 342 } |
| 233 } | 343 } |
| 234 | 344 |
| 235 abstract class Value { | 345 abstract class Value { |
| 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 { |
| 259 List<Value> fields; | 369 List<Value> fields; |
| 260 ClassDeclaration classDeclaration; | 370 ClassDeclaration classDeclaration; |
| 261 | 371 |
| 262 Object get value => this; | 372 Object get value => this; |
| 263 | 373 |
| 264 ObjectValue(Constructor constructor, Environment env) { | 374 ObjectValue(this.classDeclaration, this.fields); |
| 265 // TODO: Init fields and eval initializers, repeat the same with super. | 375 |
| 266 // TODO: Eval the Function body of the constructor, with env expanded with | 376 Value propertyGet(Name name) { |
| 267 // {VariableDeclaration("this") => this} | 377 return classDeclaration.propertyGet(this, name); |
| 268 notImplemented(obj: constructor.name); | |
| 269 } | 378 } |
| 379 | |
| 380 Value propertySet(Name name, Value value) => | |
| 381 classDeclaration.propertySet(this, name, value); | |
| 382 | |
| 383 Value directPropertyGet(Member member) => | |
| 384 classDeclaration.directPropertyGet(this, member); | |
| 385 Value directPropertySet(Member member, Value value) => | |
| 386 classDeclaration.directPropertySet(this, member, value); | |
| 270 } | 387 } |
| 271 | 388 |
| 272 class StringValue extends Value { | 389 class StringValue extends Value { |
| 273 final String value; | 390 final String value; |
| 274 | 391 |
| 275 static final operators = <String, Function>{ | 392 static final operators = <String, Function>{ |
| 276 '[]': (StringValue v1, Value v2) => v1[v2], | 393 '[]': (StringValue v1, Value v2) => v1[v2], |
| 277 '==': (StringValue v1, Value v2) => v1.equals(v2) | 394 '==': (StringValue v1, Value v2) => v1.equals(v2) |
| 278 }; | 395 }; |
| 279 | 396 |
| 280 StringValue(this.value); | 397 StringValue(this.value); |
| 281 | 398 |
| 282 Value invokeMethod(String name, [Value arg]) { | 399 Value invokeMethod(Name name, [Value arg]) { |
| 283 if (!operators.containsKey(name)) { | 400 if (!operators.containsKey(name.name)) { |
| 284 return notImplemented(obj: name); | 401 return notImplemented(obj: name); |
| 285 } | 402 } |
| 286 return operators[name](this, arg); | 403 return operators[name.name](this, arg); |
| 287 } | 404 } |
| 288 | 405 |
| 289 // Operators | 406 // Operators |
| 290 Value operator [](Value index) => new StringValue(value[index.value]); | 407 Value operator [](Value index) => new StringValue(value[index.value]); |
| 291 } | 408 } |
| 292 | 409 |
| 293 abstract class NumValue extends Value { | 410 abstract class NumValue extends Value { |
| 294 num get value; | 411 num get value; |
| 295 | 412 |
| 296 NumValue(); | 413 NumValue(); |
| 297 | 414 |
| 298 factory NumValue.fromValue(num value) { | 415 factory NumValue.fromValue(num value) { |
| 299 if (value is int) { | 416 if (value is int) { |
| 300 return new IntValue(value); | 417 return new IntValue(value); |
| 301 } else { | 418 } else { |
| 302 assert(value is double); | 419 assert(value is double); |
| 303 return new DoubleValue(value); | 420 return new DoubleValue(value); |
| 304 } | 421 } |
| 305 } | 422 } |
| 306 | 423 |
| 307 static final operators = <String, Function>{ | 424 static final operators = <String, Function>{ |
| 308 '+': (NumValue v1, Value v2) => v1 + v2, | 425 '+': (NumValue v1, Value v2) => v1 + v2, |
| 309 '-': (NumValue v1, Value v2) => v1 - v2, | 426 '-': (NumValue v1, Value v2) => v1 - v2, |
| 310 '>': (NumValue v1, Value v2) => v1 > v2, | 427 '>': (NumValue v1, Value v2) => v1 > v2, |
| 311 '<': (NumValue v1, Value v2) => v1 < v2, | 428 '<': (NumValue v1, Value v2) => v1 < v2, |
| 312 '==': (NumValue v1, Value v2) => v1.equals(v2), | 429 '==': (NumValue v1, Value v2) => v1.equals(v2), |
| 313 'unary-': (NumValue v1) => -v1, | 430 'unary-': (NumValue v1) => -v1, |
| 314 }; | 431 }; |
| 315 | 432 |
| 316 Value invokeMethod(String name, [Value arg]) { | 433 Value invokeMethod(Name name, [Value arg]) { |
| 317 if (!operators.containsKey(name)) return notImplemented(obj: name); | 434 if (!operators.containsKey(name.name)) return notImplemented(obj: name); |
| 318 if (arg == null) return operators[name](this); | 435 if (arg == null) return operators[name.name](this); |
| 319 return operators[name](this, arg); | 436 return operators[name.name](this, arg); |
| 320 } | 437 } |
| 321 | 438 |
| 322 // Operators | 439 // Operators |
| 323 NumValue operator +(Value other) => | 440 NumValue operator +(Value other) => |
| 324 new NumValue.fromValue(value + other.value); | 441 new NumValue.fromValue(value + other.value); |
| 325 NumValue operator -(Value other) => | 442 NumValue operator -(Value other) => |
| 326 new NumValue.fromValue(value - other.value); | 443 new NumValue.fromValue(value - other.value); |
| 327 NumValue operator -() => new NumValue.fromValue(-value); | 444 NumValue operator -() => new NumValue.fromValue(-value); |
| 328 | 445 |
| 329 BoolValue operator >(Value other) => | 446 BoolValue operator >(Value other) => |
| (...skipping 22 matching lines...) Expand all Loading... | |
| 352 | 469 |
| 353 class NullValue extends Value { | 470 class NullValue extends Value { |
| 354 Object get value => null; | 471 Object get value => null; |
| 355 | 472 |
| 356 const NullValue(); | 473 const NullValue(); |
| 357 } | 474 } |
| 358 | 475 |
| 359 notImplemented({String m, Object obj}) { | 476 notImplemented({String m, Object obj}) { |
| 360 throw new NotImplemented(m ?? 'Evaluation for $obj is not implemented'); | 477 throw new NotImplemented(m ?? 'Evaluation for $obj is not implemented'); |
| 361 } | 478 } |
| OLD | NEW |