Chromium Code Reviews
chromiumcodereview-hr@appspot.gserviceaccount.com (chromiumcodereview-hr) | Please choose your nickname with Settings | Help | Chromium Project | Gerrit Changes | Sign out
(388)

Unified Diff: pkg/kernel/lib/interpreter/interpreter.dart

Issue 2997563002: Implement support for static accessors (Closed)
Patch Set: Fix execution of setter body Created 3 years, 4 months ago
Use n/p to move between diff chunks; N/P to move between comments. Draft comments are only viewable by you.
Jump to:
View side-by-side diff with in-line comments
Download patch
« no previous file with comments | « no previous file | pkg/kernel/testcases/interpreter/static_accessors.dart » ('j') | no next file with comments »
Expand Comments ('e') | Collapse Comments ('c') | Show Comments Hide Comments ('s')
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(
« no previous file with comments | « no previous file | pkg/kernel/testcases/interpreter/static_accessors.dart » ('j') | no next file with comments »

Powered by Google App Engine
This is Rietveld 408576698