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 |