Index: pkg/kernel/lib/interpreter/interpreter.dart |
diff --git a/pkg/kernel/lib/interpreter/interpreter.dart b/pkg/kernel/lib/interpreter/interpreter.dart |
index 2c03f2512c2bf68f0684509e931872d7175d606d..8fd6ff83d731adcc78f9b7ebce394e3d1ef8965a 100644 |
--- a/pkg/kernel/lib/interpreter/interpreter.dart |
+++ b/pkg/kernel/lib/interpreter/interpreter.dart |
@@ -21,6 +21,10 @@ class Interpreter { |
Program program; |
StatementExecuter visitor = new StatementExecuter(); |
+ // The execution of the program starts with empty main environment. |
+ static MainEnvironment mainEnvironment = |
+ new MainEnvironment(<Member, Location>{}); |
+ |
Interpreter(this.program); |
void run() { |
@@ -50,6 +54,32 @@ class Binding { |
Binding(this.variable, this.location); |
} |
+/// Represents the top level environment that binds previously accessed or set |
+/// static fields to the location that stores their value. |
+class MainEnvironment { |
+ final Map<Member, Location> _staticFields; |
+ |
+ MainEnvironment(this._staticFields); |
+ |
+ bool contains(Member member) => _staticFields[member] != null; |
+ |
+ Value lookup(Member member) { |
+ assert(contains(member)); |
+ return _staticFields[member].value; |
+ } |
+ |
+ void updateStore(Member member, Value value) { |
+ assert(contains(member)); |
+ _staticFields[member].value = value; |
+ } |
+ |
+ MainEnvironment extend(Member member, Value value) { |
+ var newMap = new Map<Member, Location>.from(_staticFields); |
+ newMap[member] = new Location(value); |
+ return new MainEnvironment(newMap); |
+ } |
+} |
+ |
class Environment { |
final List<Binding> bindings = <Binding>[]; |
final Environment parent; |
@@ -97,7 +127,7 @@ class Environment { |
return lookupBinding(variable).location.value; |
} |
- void assign(VariableDeclaration variable, Value value) { |
+ void updateStore(VariableDeclaration variable, Value value) { |
assert(contains(variable)); |
lookupBinding(variable).location.value = value; |
} |
@@ -167,10 +197,64 @@ class Evaluator extends ExpressionVisitor1<Configuration, EvalConfiguration> { |
node.receiver, config.environment, config.exceptionComponents, cont); |
} |
- Configuration visitStaticGet(StaticGet node, EvalConfiguration config) => |
- defaultExpression(node, config); |
- Configuration visitStaticSet(StaticSet node, EvalConfiguration config) => |
- defaultExpression(node, config); |
+ Configuration visitStaticGet(StaticGet node, EvalConfiguration config) { |
+ Member member = node.target; |
+ |
+ if (member is Procedure && !member.isAccessor) { |
+ // Create a closure for the method tear off. |
+ var v = new FunctionValue(member.function, new Environment.empty()); |
+ return new ValuePassingConfiguration(config.continuation, v); |
+ } |
+ |
+ if (member is Procedure && member.isGetter) { |
+ // Execute the body of the getter. |
+ var state = new State.initial() |
+ .withReturnContinuation(config.continuation) |
+ .withContinuation(new ExitSK(config.continuation, Value.nullInstance)) |
+ .withException(config.exceptionComponents); |
+ return new ExecConfiguration( |
+ member.function.body, new Environment.empty(), state); |
+ } |
+ |
+ assert(member is Field); |
+ if (Interpreter.mainEnvironment.contains(member)) { |
+ // Read the value for the member in the main environment. |
+ return new ValuePassingConfiguration( |
+ config.continuation, Interpreter.mainEnvironment.lookup(member)); |
+ } |
+ |
+ // Otherwise, the static field is accessed for the first time. |
+ // We extend the main environment with a new binding. |
+ Interpreter.mainEnvironment = |
+ Interpreter.mainEnvironment.extend(member, Value.nullInstance); |
+ |
+ if ((member as Field).initializer == null) { |
+ return new ValuePassingConfiguration( |
+ config.continuation, Value.nullInstance); |
+ } |
+ |
+ // The initializer expression is evaluated otherwise. |
+ var cont = new StaticSetEK(member, config.continuation); |
+ return new EvalConfiguration((member as Field).initializer, |
+ new Environment.empty(), config.exceptionComponents, cont); |
+ } |
+ |
+ Configuration visitStaticSet(StaticSet node, EvalConfiguration config) { |
+ Member member = node.target; |
+ ExpressionContinuation cont; |
+ |
+ if (member is Procedure) { |
+ assert(member.isSetter); |
+ cont = new StaticSetterEK( |
+ member.function, config.exceptionComponents, config.continuation); |
+ } else { |
+ assert(member is Field); |
+ cont = new StaticSetEK(member, config.continuation); |
+ } |
+ |
+ return new EvalConfiguration( |
+ node.value, config.environment, config.exceptionComponents, cont); |
+ } |
Configuration visitStaticInvocation( |
StaticInvocation node, EvalConfiguration config) { |
@@ -263,6 +347,12 @@ class Evaluator extends ExpressionVisitor1<Configuration, EvalConfiguration> { |
node.expression, config.environment, config.exceptionComponents, cont); |
} |
+ Configuration visitFunctionExpression( |
+ FunctionExpression node, EvalConfiguration config) { |
+ var val = new FunctionValue(node.function, config.environment); |
+ return new ValuePassingConfiguration(config.continuation, val); |
+ } |
+ |
// Evaluation of BasicLiterals. |
Configuration visitStringLiteral( |
StringLiteral node, EvalConfiguration config) { |
@@ -415,8 +505,9 @@ class ExecConfiguration extends Configuration { |
ExecConfiguration(this.currentStatement, this.environment, this.state); |
- Configuration step(StatementExecuter executer) => |
- executer.exec(currentStatement, this); |
+ Configuration step(StatementExecuter executer) { |
+ return executer.exec(currentStatement, this); |
+ } |
} |
/// Configuration for applying a [StatementContinuation] to an [Environment]. |
@@ -892,6 +983,24 @@ class InstanceFieldsA extends ApplicationContinuation { |
return new EvalConfiguration(expr, environment, exceptionComponents, cont); |
} |
} |
+ |
+class FunctionValueA extends ApplicationContinuation { |
+ final FunctionValue receiver; |
+ final ExceptionComponents exceptionComponents; |
+ final ExpressionContinuation returnContinuation; |
+ |
+ FunctionValueA( |
+ this.receiver, this.exceptionComponents, this.returnContinuation); |
+ |
+ Configuration call(List<InterpreterValue> vs) { |
+ Environment env = ApplicationContinuation.createEnvironment( |
+ receiver.function, vs, receiver.environment); |
+ var scont = new ExitSK(returnContinuation, Value.nullInstance); |
+ var state = new State(null, exceptionComponents, returnContinuation, scont); |
+ return new ExecConfiguration(receiver.function.body, env, state); |
+ } |
+} |
+ |
// ------------------------------------------------------------------------ |
// Expression Continuations |
// ------------------------------------------------------------------------ |
@@ -971,6 +1080,44 @@ class SetterEK extends ExpressionContinuation { |
} |
} |
+class StaticSetEK extends ExpressionContinuation { |
+ final Member member; |
+ final ExpressionContinuation continuation; |
+ |
+ StaticSetEK(this.member, this.continuation); |
+ |
+ Configuration call(Value v) { |
+ if (Interpreter.mainEnvironment.contains(member)) { |
+ Interpreter.mainEnvironment.updateStore(member, v); |
+ } else { |
+ Interpreter.mainEnvironment = |
+ Interpreter.mainEnvironment.extend(member, v); |
+ } |
+ return new ValuePassingConfiguration(continuation, v); |
+ } |
+} |
+ |
+class StaticSetterEK extends ExpressionContinuation { |
+ final FunctionNode setter; |
+ final ExceptionComponents exceptionComponents; |
+ final ExpressionContinuation expressionContinuation; |
+ |
+ StaticSetterEK( |
+ this.setter, this.exceptionComponents, this.expressionContinuation); |
+ |
+ Configuration call(Value v) { |
+ VariableDeclaration arg = setter.positionalParameters.first; |
+ var env = new Environment.empty().extend(arg, v); |
+ var state = new State.initial() |
+ .withException(exceptionComponents) |
+ .withReturnContinuation(expressionContinuation) |
+ .withContinuation( |
+ new ExitSK(expressionContinuation, Value.nullInstance)); |
+ |
+ return new ExecConfiguration(setter.body, env, state); |
+ } |
+} |
+ |
/// Represents a continuation to be called after the evaluation of an actual |
/// argument for function invocation. |
class ExpressionListEK extends ExpressionContinuation { |
@@ -1002,6 +1149,16 @@ class MethodInvocationEK extends ExpressionContinuation { |
this.exceptionComponents, this.continuation); |
Configuration call(Value receiver) { |
+ if (receiver is FunctionValue) { |
+ // TODO(zhivkag): use method lookup instead. |
+ assert(methodName.toString() == 'call'); |
+ var args = _getArgumentExpressions(arguments, receiver.function); |
+ var acont = |
+ new FunctionValueA(receiver, exceptionComponents, continuation); |
+ return new EvalListConfiguration( |
+ args, environment, exceptionComponents, acont); |
+ } |
+ |
if (arguments.positional.isEmpty) { |
Value returnValue = receiver.invokeMethod(methodName); |
return new ValuePassingConfiguration(continuation, returnValue); |
@@ -1040,7 +1197,7 @@ class VariableSetEK extends ExpressionContinuation { |
VariableSetEK(this.variable, this.environment, this.continuation); |
Configuration call(Value value) { |
- environment.assign(variable, value); |
+ environment.updateStore(variable, value); |
return new ValuePassingConfiguration(continuation, value); |
} |
} |
@@ -1122,8 +1279,7 @@ class LetEK extends ExpressionContinuation { |
this.continuation); |
Configuration call(Value value) { |
- var letEnv = new Environment(environment); |
- letEnv.extend(variable, value); |
+ var letEnv = environment.extend(variable, value); |
return new EvalConfiguration( |
letBody, letEnv, exceptionComponents, continuation); |
} |
@@ -1500,10 +1656,9 @@ class StatementExecuter |
conf.state.continuation, conf.environment); |
} |
- var env = new Environment(conf.environment); |
var cont = new BlockSK.fromConfig(node.statements.skip(1).toList(), conf); |
- return new ExecConfiguration( |
- node.statements.first, env, conf.state.withContinuation(cont)); |
+ return new ExecConfiguration(node.statements.first, conf.environment, |
+ conf.state.withContinuation(cont)); |
} |
Configuration visitEmptyStatement( |
@@ -1599,6 +1754,14 @@ class StatementExecuter |
return new ForwardConfiguration(conf.state.continuation, |
conf.environment.extend(node, Value.nullInstance)); |
} |
+ |
+ Configuration visitFunctionDeclaration( |
+ FunctionDeclaration node, ExecConfiguration conf) { |
+ var newEnv = conf.environment.extend(node.variable, Value.nullInstance); |
+ var fun = new FunctionValue(node.function, newEnv); |
+ newEnv.updateStore(node.variable, fun); |
+ return new ForwardConfiguration(conf.state.continuation, newEnv); |
+ } |
} |
// ------------------------------------------------------------------------ |
@@ -1734,6 +1897,18 @@ class ObjectValue extends Value { |
} |
} |
+class FunctionValue extends Value { |
+ Class get class_ => throw 'Class for FunctionValue is not defined'; |
+ List<Location> get fields => throw 'FunctionValue has no fields.'; |
+ |
+ FunctionValue get value => this; |
+ |
+ final FunctionNode function; |
+ final Environment environment; |
+ |
+ FunctionValue(this.function, this.environment); |
+} |
+ |
abstract class LiteralValue extends Value { |
Class get class_ => |
notImplemented(m: "Loading class for literal is not implemented."); |