Index: pkg/kernel/lib/interpreter/interpreter.dart |
diff --git a/pkg/kernel/lib/interpreter/interpreter.dart b/pkg/kernel/lib/interpreter/interpreter.dart |
index 6741928fa9ff7753c95d631e6446171560f27145..9f3b525e25414c0426ad33f8465032d3db06f9d9 100644 |
--- a/pkg/kernel/lib/interpreter/interpreter.dart |
+++ b/pkg/kernel/lib/interpreter/interpreter.dart |
@@ -21,6 +21,8 @@ class Interpreter { |
Program program; |
StatementExecuter visitor = new StatementExecuter(); |
+ static MainEnvironment mainEnvironment = new MainEnvironment(); |
+ |
Interpreter(this.program); |
void run() { |
@@ -57,6 +59,25 @@ class Binding { |
Binding(this.variable, this.location); |
} |
+class MainEnvironment { |
+ Map<Member, Location> _staticFields = <Member, Location>{}; |
+ |
+ bool contains(Member member) => _staticFields[member] != null; |
+ |
+ Value lookup(Member member) { |
+ assert(contains(member)); |
+ return _staticFields[member].value; |
+ } |
+ |
+ void update(Member member, Value value) { |
Dmitry Stefantsov
2017/08/16 08:25:39
I would add a comment that [MainEnvironment] insta
|
+ if (_staticFields[member] == null) { |
+ _staticFields[member] = new Location(value); |
+ } else { |
+ _staticFields[member].value = value; |
+ } |
+ } |
+} |
+ |
class Environment { |
final List<Binding> bindings = <Binding>[]; |
final Environment parent; |
@@ -174,10 +195,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 EnvironmentLocation(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)) { |
Dmitry Stefantsov
2017/08/16 08:25:39
I would use a special value to indicate that the s
|
+ // 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 store `Value.nullInstance` if there the field doesn't have an |
+ // initializer. |
+ if ((member as Field).initializer == null) { |
+ Interpreter.mainEnvironment.update(member, Value.nullInstance); |
Dmitry Stefantsov
2017/08/16 08:25:39
If the special value for uninitialized variables h
|
+ 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) { |
@@ -429,8 +504,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]. |
@@ -1003,6 +1079,39 @@ class SetterEK extends ExpressionContinuation { |
} |
} |
+class StaticSetEK extends ExpressionContinuation { |
+ final Member member; |
+ final ExpressionContinuation continuation; |
+ |
+ StaticSetEK(this.member, this.continuation); |
+ |
+ Configuration call(Value v) { |
+ Interpreter.mainEnvironment.update(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 { |
@@ -1541,10 +1650,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( |