Chromium Code Reviews| Index: pkg/kernel/lib/interpreter/interpreter.dart |
| diff --git a/pkg/kernel/lib/interpreter/interpreter.dart b/pkg/kernel/lib/interpreter/interpreter.dart |
| index ea8f0186d1caf2ce425e50666a9d2a3f7bbae838..e31da20022e06f17cc546b39cd4807ce8d213c5d 100644 |
| --- a/pkg/kernel/lib/interpreter/interpreter.dart |
| +++ b/pkg/kernel/lib/interpreter/interpreter.dart |
| @@ -119,6 +119,31 @@ class Evaluator extends ExpressionVisitor1<Value> { |
| return env.assign(node.variable, eval(node.value, env)); |
| } |
| + Value visitPropertyGet(PropertyGet node, env) { |
| + 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.
|
| + 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.
|
| + } |
| + |
| + Value visitPropertySet(PropertySet node, env) { |
| + ObjectValue receiver = eval(node.receiver, env); |
| + Value value = eval(node.value, env); |
| + return receiver.propertySet(node.name, value); |
| + } |
| + |
| + Value visitDirectPropertyGet(DirectPropertyGet node, env) { |
| + ObjectValue receiver = eval(node.receiver, env); |
| + return receiver.directPropertyGet(node.target); |
| + } |
| + |
| + Value visitDirectPropertySet(DirectPropertySet node, env) { |
| + ObjectValue receiver = eval(node.receiver, env); |
| + Value value = eval(node.value, env); |
| + return receiver.directPropertySet(node.target, value); |
| + } |
| + |
| + Value visitStaticGet(StaticGet node, env) => defaultExpression(node, env); |
| + Value visitStaticSet(StaticSet node, env) => defaultExpression(node, env); |
| + |
| Value visitStaticInvocation(StaticInvocation node, env) { |
| if ('print' == node.name.toString()) { |
| // Special evaluation of print. |
| @@ -137,14 +162,27 @@ class Evaluator extends ExpressionVisitor1<Value> { |
| var receiver = eval(node.receiver, env); |
| if (node.arguments.positional.isNotEmpty) { |
| var argValue = eval(node.arguments.positional.first, env); |
| - return receiver.invokeMethod(node.name.name, argValue); |
| + return receiver.invokeMethod(node.name, argValue); |
| } else { |
| - return receiver.invokeMethod(node.name.name); |
| + return receiver.invokeMethod(node.name); |
| } |
| } |
| - Value visitConstructorInvocation(ConstructorInvocation node, env) => |
| - defaultExpression(node, env); |
| + Value visitConstructorInvocation(ConstructorInvocation node, env) { |
| + ClassDeclaration classDeclaration = |
| + new ClassDeclaration(node.target.enclosingClass.reference); |
| + |
| + Environment emptyEnv = new Environment.empty(); |
| + // Currently we don't support initializers. |
| + // TODO: Modify to respect dart semantics for initialization. |
| + // 1. Init fields and eval initializers, repeat the same with super. |
| + // 2. Eval the Function body of the constructor. |
| + List<Value> fields = classDeclaration.instanceFields |
| + .map((Field f) => eval(f.initializer, emptyEnv)) |
| + .toList(growable: false); |
| + |
| + return new ObjectValue(classDeclaration, fields); |
| + } |
| Value visitNot(Not node, env) { |
| Value operand = eval(node.operand, env).toBoolean(); |
| @@ -207,13 +245,16 @@ class ClassDeclaration { |
| static final Map<Reference, ClassDeclaration> _classes = |
| <Reference, ClassDeclaration>{}; |
| - Class currentClass; |
| - ClassDeclaration superClass; |
| + 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.
|
| + List<Field> instanceFields = <Field>[]; |
| + List<Field> staticFields = <Field>[]; |
| + // Implicit getters and setters for instance Fields. |
| + 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.
|
| + Map<Name, int> setters = <Name, int>{}; |
| // The initializers of static fields are evaluated the first time the field |
| // is accessed. |
| - List<Value> staticFields = <Value>[]; |
| - List<Procedure> getters = <Procedure>[]; |
| - List<Procedure> setters = <Procedure>[]; |
| + List<Value> staticFieldValues = <Value>[]; |
| + |
| List<Procedure> methods = <Procedure>[]; |
| factory ClassDeclaration(Reference classRef) { |
| @@ -224,11 +265,80 @@ class ClassDeclaration { |
| return _classes[classRef]; |
| } |
| - ClassDeclaration._internal(this.currentClass) { |
| + ClassDeclaration._internal(Class currentClass) { |
| if (currentClass.superclass != null) { |
| - superClass = new ClassDeclaration(currentClass.superclass.reference); |
| + superClass = currentClass.superclass; |
| + } |
| + |
| + _populateInstanceFields(currentClass); |
| + |
| + // Populate implicit setters and getters. |
| + for (int i = 0; i < instanceFields.length; i++) { |
| + Field f = instanceFields[i]; |
| + assert(f.hasImplicitGetter); |
| + 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.
|
| + if (f.hasImplicitSetter) { |
| + setters[f.name] = i; |
| + } |
| + } |
| + // TODO: Populate methods. |
| + } |
| + |
| + 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.
|
| + 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.
|
| + return (object.fields)[getters[name]]; |
| + } |
| + // TODO: return NoSuchMethod if Name is not a Getter or Method tear-off |
| + return notImplemented(obj: name); |
| + } |
| + |
| + 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
|
| + if (setters.containsKey(name)) { |
| + object.fields[setters[name]] = value; |
| + } |
| + // TODO: return NoSuchMethodError if Name is not a Setter. |
| + return Value.nullInstance; |
| + } |
| + |
| + Value directPropertyGet(ObjectValue object, Member member) { |
| + if (member is Field) { |
| + for (int i = 0; i < instanceFields.length; i++) { |
| + if (identical(member, instanceFields[i])) { |
| + return object.fields[i]; |
| + } |
| + } |
| + // TODO: throw NoSuchMethodError instead. |
| + return notImplemented(m: 'NoSuchMethod: Field ${member} not found.'); |
| + } |
| + return notImplemented(obj: member); |
| + } |
| + |
| + Value directPropertySet(ObjectValue object, Member member, Value value) { |
| + if (member is Field) { |
| + for (int i = 0; i < instanceFields.length; i++) { |
| + if (identical(member, instanceFields[i])) { |
| + object.fields[i] = value; |
| + } |
| + return Value.nullInstance; |
| + } |
| + // TODO: throw NoSuchMethodError instead. |
| + return notImplemented(m: 'NoSuchMethod: Field $member not found.'); |
| + } |
| + return notImplemented(obj: member); |
| + } |
| + |
| + // Populates with the instance fields of the current class and all its |
| + // superclasses recursively. |
| + _populateInstanceFields(Class class_) { |
| + for (Field f in class_.fields) { |
| + if (f.isInstanceMember) { |
| + instanceFields.add(f); |
| + } |
| + } |
| + |
| + if (class_.superclass != null) { |
| + _populateInstanceFields(class_.superclass); |
| } |
| - // TODO: Populate getters, setters and methods. |
| } |
| } |
| @@ -250,7 +360,7 @@ abstract class Value { |
| BoolValue equals(Value other) => |
| value == other.value ? Value.trueInstance : Value.falseInstance; |
| - Value invokeMethod(String name, [Value arg]) { |
| + Value invokeMethod(Name name, [Value arg]) { |
| throw notImplemented(obj: name); |
| } |
| } |
| @@ -261,12 +371,19 @@ class ObjectValue extends Value { |
| Object get value => this; |
| - ObjectValue(Constructor constructor, Environment env) { |
| - // TODO: Init fields and eval initializers, repeat the same with super. |
| - // TODO: Eval the Function body of the constructor, with env expanded with |
| - // {VariableDeclaration("this") => this} |
| - notImplemented(obj: constructor.name); |
| + ObjectValue(this.classDeclaration, this.fields); |
| + |
| + Value propertyGet(Name name) { |
| + return classDeclaration.propertyGet(this, name); |
| } |
| + |
| + Value propertySet(Name name, Value value) => |
| + classDeclaration.propertySet(this, name, value); |
| + |
| + Value directPropertyGet(Member member) => |
| + classDeclaration.directPropertyGet(this, member); |
| + Value directPropertySet(Member member, Value value) => |
| + classDeclaration.directPropertySet(this, member, value); |
| } |
| class StringValue extends Value { |
| @@ -279,11 +396,11 @@ class StringValue extends Value { |
| StringValue(this.value); |
| - Value invokeMethod(String name, [Value arg]) { |
| - if (!operators.containsKey(name)) { |
| + Value invokeMethod(Name name, [Value arg]) { |
| + if (!operators.containsKey(name.name)) { |
| return notImplemented(obj: name); |
| } |
| - return operators[name](this, arg); |
| + return operators[name.name](this, arg); |
| } |
| // Operators |
| @@ -313,10 +430,10 @@ abstract class NumValue extends Value { |
| 'unary-': (NumValue v1) => -v1, |
| }; |
| - Value invokeMethod(String name, [Value arg]) { |
| - if (!operators.containsKey(name)) return notImplemented(obj: name); |
| - if (arg == null) return operators[name](this); |
| - return operators[name](this, arg); |
| + Value invokeMethod(Name name, [Value arg]) { |
| + if (!operators.containsKey(name.name)) return notImplemented(obj: name); |
| + if (arg == null) return operators[name.name](this); |
| + return operators[name.name](this, arg); |
| } |
| // Operators |