| 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..46453f221a2d8c94fe3797fd4801e3a70650a5ba 100644
|
| --- a/pkg/kernel/lib/interpreter/interpreter.dart
|
| +++ b/pkg/kernel/lib/interpreter/interpreter.dart
|
| @@ -119,6 +119,33 @@ class Evaluator extends ExpressionVisitor1<Value> {
|
| return env.assign(node.variable, eval(node.value, env));
|
| }
|
|
|
| + Value visitPropertyGet(PropertyGet node, env) {
|
| + Value receiver = eval(node.receiver, env);
|
| + return receiver.classDeclaration.lookupGetter(node.name)(receiver);
|
| + }
|
| +
|
| + Value visitPropertySet(PropertySet node, env) {
|
| + Value receiver = eval(node.receiver, env);
|
| + Value value = eval(node.value, env);
|
| + receiver.classDeclaration.lookupSetter(node.name)(receiver, value);
|
| + return value;
|
| + }
|
| +
|
| + Value visitDirectPropertyGet(DirectPropertyGet node, env) {
|
| + Value receiver = eval(node.receiver, env);
|
| + return receiver.classDeclaration.getProperty(receiver, node.target);
|
| + }
|
| +
|
| + Value visitDirectPropertySet(DirectPropertySet node, env) {
|
| + Value receiver = eval(node.receiver, env);
|
| + Value value = eval(node.value, env);
|
| + receiver.classDeclaration.setProperty(receiver, node.target, value);
|
| + return 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 +164,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();
|
| @@ -201,19 +241,25 @@ class Evaluator extends ExpressionVisitor1<Value> {
|
| }
|
| }
|
|
|
| +typedef Value Getter(Value receiver);
|
| +typedef void Setter(Value receiver, Value value);
|
| +
|
| // TODO(zhivkag): Change misleading name.
|
| // This is representation of a class in the interpreter, not a declaration.
|
| class ClassDeclaration {
|
| static final Map<Reference, ClassDeclaration> _classes =
|
| <Reference, ClassDeclaration>{};
|
|
|
| - Class currentClass;
|
| - ClassDeclaration superClass;
|
| + ClassDeclaration superclass;
|
| + List<Field> instanceFields = <Field>[];
|
| + List<Field> staticFields = <Field>[];
|
| + // Implicit getters and setters for instance Fields.
|
| + Map<Name, Getter> getters = <Name, Getter>{};
|
| + Map<Name, Setter> setters = <Name, Setter>{};
|
| // 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,15 +270,79 @@ class ClassDeclaration {
|
| return _classes[classRef];
|
| }
|
|
|
| - ClassDeclaration._internal(this.currentClass) {
|
| + ClassDeclaration._internal(Class currentClass) {
|
| if (currentClass.superclass != null) {
|
| - superClass = new ClassDeclaration(currentClass.superclass.reference);
|
| + superclass = new ClassDeclaration(currentClass.superclass.reference);
|
| + }
|
| +
|
| + _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] = (Value receiver) => receiver.fields[i];
|
| + if (f.hasImplicitSetter) {
|
| + setters[f.name] =
|
| + (Value receiver, Value value) => receiver.fields[i] = value;
|
| + }
|
| + }
|
| + // TODO: Populate methods.
|
| + }
|
| +
|
| + Getter lookupGetter(Name name) {
|
| + Getter getter = getters[name];
|
| + if (getter != null) return getter;
|
| + if (superclass != null) return superclass.lookupGetter(name);
|
| + return (Value receiver) => notImplemented(obj: name);
|
| + }
|
| +
|
| + Setter lookupSetter(Name name) {
|
| + Setter setter = setters[name];
|
| + if (setter != null) return setter;
|
| + if (superclass != null) return lookupSetter(name);
|
| + return (Value receiver, Value value) => notImplemented(obj: name);
|
| + }
|
| +
|
| + Value getProperty(ObjectValue object, Member member) {
|
| + if (member is Field) {
|
| + int index = instanceFields.indexOf(member);
|
| + // TODO: throw NoSuchMethodError instead.
|
| + if (index < 0) return notImplemented(m: 'NoSuchMethod: ${member}');
|
| + return object.fields[index];
|
| + }
|
| + return notImplemented(obj: member);
|
| + }
|
| +
|
| + Value setProperty(ObjectValue object, Member member, Value value) {
|
| + if (member is Field) {
|
| + int index = instanceFields.indexOf(member);
|
| + // TODO: throw NoSuchMethodError instead.
|
| + if (index < 0) return notImplemented(m: 'NoSuchMethod: ${member}');
|
| + object.fields[index] = value;
|
| + return Value.nullInstance;
|
| + }
|
| + 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.
|
| }
|
| }
|
|
|
| abstract class Value {
|
| + ClassDeclaration get classDeclaration;
|
| + List<Value> get fields;
|
| Object get value;
|
|
|
| static final NullValue nullInstance = const NullValue();
|
| @@ -250,26 +360,29 @@ 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);
|
| }
|
| }
|
|
|
| class ObjectValue extends Value {
|
| - List<Value> fields;
|
| ClassDeclaration classDeclaration;
|
| -
|
| + List<Value> fields;
|
| 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);
|
| +}
|
| +
|
| +abstract class LiteralValue extends Value {
|
| + ClassDeclaration get classDeclaration =>
|
| + notImplemented(m: "Loading class for literal is not implemented.");
|
| + List<Value> get fields =>
|
| + notImplemented(m: "Literal value does not have fields");
|
| +
|
| + const LiteralValue();
|
| }
|
|
|
| -class StringValue extends Value {
|
| +class StringValue extends LiteralValue {
|
| final String value;
|
|
|
| static final operators = <String, Function>{
|
| @@ -279,18 +392,18 @@ 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
|
| Value operator [](Value index) => new StringValue(value[index.value]);
|
| }
|
|
|
| -abstract class NumValue extends Value {
|
| +abstract class NumValue extends LiteralValue {
|
| num get value;
|
|
|
| NumValue();
|
| @@ -313,10 +426,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
|
| @@ -344,13 +457,13 @@ class DoubleValue extends NumValue {
|
| DoubleValue(this.value);
|
| }
|
|
|
| -class BoolValue extends Value {
|
| +class BoolValue extends LiteralValue {
|
| final bool value;
|
|
|
| const BoolValue(this.value);
|
| }
|
|
|
| -class NullValue extends Value {
|
| +class NullValue extends LiteralValue {
|
| Object get value => null;
|
|
|
| const NullValue();
|
|
|