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

Side by Side Diff: pkg/kernel/lib/interpreter/interpreter.dart

Issue 2997563002: Implement support for static accessors (Closed)
Patch Set: Make main environment immutable 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 unified diff | Download patch
« no previous file with comments | « no previous file | pkg/kernel/testcases/interpreter/static_accessors.dart » ('j') | no next file with comments »
Toggle Intra-line Diffs ('i') | Expand Comments ('e') | Collapse Comments ('c') | Show Comments Hide Comments ('s')
OLDNEW
1 // Copyright (c) 2017, the Dart project authors. Please see the AUTHORS file 1 // Copyright (c) 2017, the Dart project authors. Please see the AUTHORS file
2 // for details. All rights reserved. Use of this source code is governed by a 2 // for details. All rights reserved. Use of this source code is governed by a
3 // BSD-style license that can be found in the LICENSE file. 3 // BSD-style license that can be found in the LICENSE file.
4 library kernel.interpreter; 4 library kernel.interpreter;
5 5
6 import '../ast.dart'; 6 import '../ast.dart';
7 import '../ast.dart' as ast show Class; 7 import '../ast.dart' as ast show Class;
8 8
9 import '../log.dart'; 9 import '../log.dart';
10 export '../log.dart'; 10 export '../log.dart';
11 11
12 class NotImplemented { 12 class NotImplemented {
13 String message; 13 String message;
14 14
15 NotImplemented(this.message); 15 NotImplemented(this.message);
16 16
17 String toString() => message; 17 String toString() => message;
18 } 18 }
19 19
20 class Interpreter { 20 class Interpreter {
21 Program program; 21 Program program;
22 StatementExecuter visitor = new StatementExecuter(); 22 StatementExecuter visitor = new StatementExecuter();
23 23
24 // The execution of the program starts with empty main environment.
25 static MainEnvironment mainEnvironment =
26 new MainEnvironment(<Member, Location>{});
27
24 Interpreter(this.program); 28 Interpreter(this.program);
25 29
26 void run() { 30 void run() {
27 assert(program.libraries.isEmpty); 31 assert(program.libraries.isEmpty);
28 Procedure mainMethod = program.mainMethod; 32 Procedure mainMethod = program.mainMethod;
29 33
30 if (mainMethod == null) return; 34 if (mainMethod == null) return;
31 35
32 Statement statementBlock = mainMethod.function.body; 36 Statement statementBlock = mainMethod.function.body;
33 ExecConfiguration configuration = new ExecConfiguration( 37 ExecConfiguration configuration = new ExecConfiguration(
(...skipping 16 matching lines...) Expand all
50 EnvironmentLocation(this.environment); 54 EnvironmentLocation(this.environment);
51 } 55 }
52 56
53 class Binding { 57 class Binding {
54 final VariableDeclaration variable; 58 final VariableDeclaration variable;
55 final Location location; 59 final Location location;
56 60
57 Binding(this.variable, this.location); 61 Binding(this.variable, this.location);
58 } 62 }
59 63
64 /// Represents the top level environment that binds previously accessed or set
65 /// static fields to the location that stores their value.
66 class MainEnvironment {
Dmitry Stefantsov 2017/08/16 12:06:46 Now that [MainEnvironment]s are immutable and we t
zhivkag 2017/08/16 12:27:44 One difference is that [MainEnvironment] maps [Mem
Dmitry Stefantsov 2017/08/16 12:38:50 Got it. Thanks for the explanation! No, I think
67 final Map<Member, Location> _staticFields;
68
69 MainEnvironment(this._staticFields);
70
71 bool contains(Member member) => _staticFields[member] != null;
72
73 Value lookup(Member member) {
74 assert(contains(member));
75 return _staticFields[member].value;
76 }
77
78 void update(Member member, Value value) {
79 assert(contains(member));
80 _staticFields[member].value = value;
81 }
82
83 MainEnvironment extend(Member member, Value value) {
84 var newMap = new Map<Member, Location>.from(_staticFields);
85 newMap[member] = new Location(value);
86 return new MainEnvironment(newMap);
87 }
88 }
89
60 class Environment { 90 class Environment {
61 final List<Binding> bindings = <Binding>[]; 91 final List<Binding> bindings = <Binding>[];
62 final Environment parent; 92 final Environment parent;
63 93
64 Value get thisInstance { 94 Value get thisInstance {
65 return containsThis() 95 return containsThis()
66 ? lookupThis().value 96 ? lookupThis().value
67 : throw "Invalid reference to 'this' expression"; 97 : throw "Invalid reference to 'this' expression";
68 } 98 }
69 99
(...skipping 27 matching lines...) Expand all
97 for (Binding b in bindings) { 127 for (Binding b in bindings) {
98 if (identical(b.variable.name, 'this')) return b.location; 128 if (identical(b.variable.name, 'this')) return b.location;
99 } 129 }
100 return parent.lookupThis(); 130 return parent.lookupThis();
101 } 131 }
102 132
103 Value lookup(VariableDeclaration variable) { 133 Value lookup(VariableDeclaration variable) {
104 return lookupBinding(variable).location.value; 134 return lookupBinding(variable).location.value;
105 } 135 }
106 136
107 void assign(VariableDeclaration variable, Value value) { 137 void update(VariableDeclaration variable, Value value) {
Dmitry Stefantsov 2017/08/16 12:06:47 How about renaming [update] to [updateStore] to be
zhivkag 2017/08/16 12:27:44 Done. I also renamed assign -> update -> updateSto
Dmitry Stefantsov 2017/08/16 12:38:50 I think [updateStore] is ok. As for "updateLocati
108 assert(contains(variable)); 138 assert(contains(variable));
109 lookupBinding(variable).location.value = value; 139 lookupBinding(variable).location.value = value;
110 } 140 }
111 141
112 Environment extend(VariableDeclaration variable, Value value) { 142 Environment extend(VariableDeclaration variable, Value value) {
113 assert(!contains(variable)); 143 assert(!contains(variable));
114 return new Environment(this) 144 return new Environment(this)
115 ..bindings.add(new Binding(variable, new Location(value))); 145 ..bindings.add(new Binding(variable, new Location(value)));
116 } 146 }
117 147
(...skipping 49 matching lines...) Expand 10 before | Expand all | Expand 10 after
167 node.receiver, config.environment, config.exceptionComponents, cont); 197 node.receiver, config.environment, config.exceptionComponents, cont);
168 } 198 }
169 199
170 Configuration visitPropertySet(PropertySet node, EvalConfiguration config) { 200 Configuration visitPropertySet(PropertySet node, EvalConfiguration config) {
171 var cont = new PropertySetEK(node.value, node.name, config.environment, 201 var cont = new PropertySetEK(node.value, node.name, config.environment,
172 config.exceptionComponents, config.continuation); 202 config.exceptionComponents, config.continuation);
173 return new EvalConfiguration( 203 return new EvalConfiguration(
174 node.receiver, config.environment, config.exceptionComponents, cont); 204 node.receiver, config.environment, config.exceptionComponents, cont);
175 } 205 }
176 206
177 Configuration visitStaticGet(StaticGet node, EvalConfiguration config) => 207 Configuration visitStaticGet(StaticGet node, EvalConfiguration config) {
178 defaultExpression(node, config); 208 Member member = node.target;
179 Configuration visitStaticSet(StaticSet node, EvalConfiguration config) => 209
180 defaultExpression(node, config); 210 if (member is Procedure && !member.isAccessor) {
211 // Create a closure for the method tear off.
212 var v = new FunctionValue(
213 member.function, new EnvironmentLocation(new Environment.empty()));
214 return new ValuePassingConfiguration(config.continuation, v);
215 }
216
217 if (member is Procedure && member.isGetter) {
218 // Execute the body of the getter.
219 var state = new State.initial()
220 .withReturnContinuation(config.continuation)
221 .withContinuation(new ExitSK(config.continuation, Value.nullInstance))
222 .withException(config.exceptionComponents);
223 return new ExecConfiguration(
224 member.function.body, new Environment.empty(), state);
225 }
226
227 assert(member is Field);
228 if (Interpreter.mainEnvironment.contains(member)) {
229 // Read the value for the member in the main environment.
230 return new ValuePassingConfiguration(
231 config.continuation, Interpreter.mainEnvironment.lookup(member));
232 }
233
234 // Otherwise, the static field is accessed for the first time.
235 // We extend the main environment with a new binding.
236 Interpreter.mainEnvironment =
237 Interpreter.mainEnvironment.extend(member, Value.nullInstance);
238
239 if ((member as Field).initializer == null) {
240 return new ValuePassingConfiguration(
241 config.continuation, Value.nullInstance);
242 }
243
244 // The initializer expression is evaluated otherwise.
245 var cont = new StaticSetEK(member, config.continuation);
246 return new EvalConfiguration((member as Field).initializer,
247 new Environment.empty(), config.exceptionComponents, cont);
248 }
249
250 Configuration visitStaticSet(StaticSet node, EvalConfiguration config) {
251 Member member = node.target;
252 ExpressionContinuation cont;
253
254 if (member is Procedure) {
255 assert(member.isSetter);
256 cont = new StaticSetterEK(
257 member.function, config.exceptionComponents, config.continuation);
258 } else {
259 assert(member is Field);
260 cont = new StaticSetEK(member, config.continuation);
261 }
262
263 return new EvalConfiguration(
264 node.value, config.environment, config.exceptionComponents, cont);
265 }
181 266
182 Configuration visitStaticInvocation( 267 Configuration visitStaticInvocation(
183 StaticInvocation node, EvalConfiguration config) { 268 StaticInvocation node, EvalConfiguration config) {
184 if ('print' == node.name.toString()) { 269 if ('print' == node.name.toString()) {
185 var cont = new PrintEK(config.continuation); 270 var cont = new PrintEK(config.continuation);
186 return new EvalConfiguration(node.arguments.positional.first, 271 return new EvalConfiguration(node.arguments.positional.first,
187 config.environment, config.exceptionComponents, cont); 272 config.environment, config.exceptionComponents, cont);
188 } else { 273 } else {
189 log.info('static-invocation-${node.target.name.toString()}\n'); 274 log.info('static-invocation-${node.target.name.toString()}\n');
190 275
(...skipping 231 matching lines...) Expand 10 before | Expand all | Expand 10 after
422 } 507 }
423 508
424 /// Configuration for execution of a [Statement]. 509 /// Configuration for execution of a [Statement].
425 class ExecConfiguration extends Configuration { 510 class ExecConfiguration extends Configuration {
426 final Statement currentStatement; 511 final Statement currentStatement;
427 final Environment environment; 512 final Environment environment;
428 final State state; 513 final State state;
429 514
430 ExecConfiguration(this.currentStatement, this.environment, this.state); 515 ExecConfiguration(this.currentStatement, this.environment, this.state);
431 516
432 Configuration step(StatementExecuter executer) => 517 Configuration step(StatementExecuter executer) {
433 executer.exec(currentStatement, this); 518 return executer.exec(currentStatement, this);
519 }
434 } 520 }
435 521
436 /// Configuration for applying a [StatementContinuation] to an [Environment]. 522 /// Configuration for applying a [StatementContinuation] to an [Environment].
437 class ForwardConfiguration extends Configuration { 523 class ForwardConfiguration extends Configuration {
438 final StatementContinuation continuation; 524 final StatementContinuation continuation;
439 final Environment environment; 525 final Environment environment;
440 526
441 ForwardConfiguration(this.continuation, this.environment); 527 ForwardConfiguration(this.continuation, this.environment);
442 528
443 Configuration step(StatementExecuter _) => continuation?.call(environment); 529 Configuration step(StatementExecuter _) => continuation?.call(environment);
(...skipping 552 matching lines...) Expand 10 before | Expand all | Expand 10 after
996 1082
997 SetterEK(this.receiver, this.name, this.continuation); 1083 SetterEK(this.receiver, this.name, this.continuation);
998 1084
999 Configuration call(Value v) { 1085 Configuration call(Value v) {
1000 Setter setter = receiver.class_.lookupImplicitSetter(name); 1086 Setter setter = receiver.class_.lookupImplicitSetter(name);
1001 setter(receiver, v); 1087 setter(receiver, v);
1002 return new ValuePassingConfiguration(continuation, v); 1088 return new ValuePassingConfiguration(continuation, v);
1003 } 1089 }
1004 } 1090 }
1005 1091
1092 class StaticSetEK extends ExpressionContinuation {
1093 final Member member;
1094 final ExpressionContinuation continuation;
1095
1096 StaticSetEK(this.member, this.continuation);
1097
1098 Configuration call(Value v) {
1099 Interpreter.mainEnvironment.update(member, v);
1100 return new ValuePassingConfiguration(continuation, v);
1101 }
1102 }
1103
1104 class StaticSetterEK extends ExpressionContinuation {
1105 final FunctionNode setter;
1106 final ExceptionComponents exceptionComponents;
1107 final ExpressionContinuation expressionContinuation;
1108
1109 StaticSetterEK(
1110 this.setter, this.exceptionComponents, this.expressionContinuation);
1111
1112 Configuration call(Value v) {
1113 VariableDeclaration arg = setter.positionalParameters.first;
1114 var env = new Environment.empty().extend(arg, v);
1115 var state = new State.initial()
1116 .withException(exceptionComponents)
1117 .withReturnContinuation(expressionContinuation)
1118 .withContinuation(
1119 new ExitSK(expressionContinuation, Value.nullInstance));
1120
1121 return new ExecConfiguration(setter.body, env, state);
1122 }
1123 }
1124
1006 /// Represents a continuation to be called after the evaluation of an actual 1125 /// Represents a continuation to be called after the evaluation of an actual
1007 /// argument for function invocation. 1126 /// argument for function invocation.
1008 class ExpressionListEK extends ExpressionContinuation { 1127 class ExpressionListEK extends ExpressionContinuation {
1009 final InterpreterExpression currentExpression; 1128 final InterpreterExpression currentExpression;
1010 final List<InterpreterExpression> expressions; 1129 final List<InterpreterExpression> expressions;
1011 final Environment environment; 1130 final Environment environment;
1012 final ExceptionComponents exceptionComponents; 1131 final ExceptionComponents exceptionComponents;
1013 final ApplicationContinuation applicationContinuation; 1132 final ApplicationContinuation applicationContinuation;
1014 1133
1015 ExpressionListEK(this.currentExpression, this.expressions, this.environment, 1134 ExpressionListEK(this.currentExpression, this.expressions, this.environment,
(...skipping 59 matching lines...) Expand 10 before | Expand all | Expand 10 after
1075 } 1194 }
1076 1195
1077 class VariableSetEK extends ExpressionContinuation { 1196 class VariableSetEK extends ExpressionContinuation {
1078 final VariableDeclaration variable; 1197 final VariableDeclaration variable;
1079 final Environment environment; 1198 final Environment environment;
1080 final ExpressionContinuation continuation; 1199 final ExpressionContinuation continuation;
1081 1200
1082 VariableSetEK(this.variable, this.environment, this.continuation); 1201 VariableSetEK(this.variable, this.environment, this.continuation);
1083 1202
1084 Configuration call(Value value) { 1203 Configuration call(Value value) {
1085 environment.assign(variable, value); 1204 environment.update(variable, value);
1086 return new ValuePassingConfiguration(continuation, value); 1205 return new ValuePassingConfiguration(continuation, value);
1087 } 1206 }
1088 } 1207 }
1089 1208
1090 class NotEK extends ExpressionContinuation { 1209 class NotEK extends ExpressionContinuation {
1091 final ExpressionContinuation continuation; 1210 final ExpressionContinuation continuation;
1092 1211
1093 NotEK(this.continuation); 1212 NotEK(this.continuation);
1094 1213
1095 Configuration call(Value value) { 1214 Configuration call(Value value) {
(...skipping 438 matching lines...) Expand 10 before | Expand all | Expand 10 after
1534 return new EvalConfiguration(node.expression, conf.environment, 1653 return new EvalConfiguration(node.expression, conf.environment,
1535 conf.state.exceptionComponents, cont); 1654 conf.state.exceptionComponents, cont);
1536 } 1655 }
1537 1656
1538 Configuration visitBlock(Block node, ExecConfiguration conf) { 1657 Configuration visitBlock(Block node, ExecConfiguration conf) {
1539 if (node.statements.isEmpty) { 1658 if (node.statements.isEmpty) {
1540 return new ForwardConfiguration( 1659 return new ForwardConfiguration(
1541 conf.state.continuation, conf.environment); 1660 conf.state.continuation, conf.environment);
1542 } 1661 }
1543 1662
1544 var env = new Environment(conf.environment);
1545 var cont = new BlockSK.fromConfig(node.statements.skip(1).toList(), conf); 1663 var cont = new BlockSK.fromConfig(node.statements.skip(1).toList(), conf);
1546 return new ExecConfiguration( 1664 return new ExecConfiguration(node.statements.first, conf.environment,
1547 node.statements.first, env, conf.state.withContinuation(cont)); 1665 conf.state.withContinuation(cont));
1548 } 1666 }
1549 1667
1550 Configuration visitEmptyStatement( 1668 Configuration visitEmptyStatement(
1551 EmptyStatement node, ExecConfiguration conf) { 1669 EmptyStatement node, ExecConfiguration conf) {
1552 return new ForwardConfiguration(conf.state.continuation, conf.environment); 1670 return new ForwardConfiguration(conf.state.continuation, conf.environment);
1553 } 1671 }
1554 1672
1555 Configuration visitIfStatement(IfStatement node, ExecConfiguration conf) { 1673 Configuration visitIfStatement(IfStatement node, ExecConfiguration conf) {
1556 var cont = new IfConditionEK( 1674 var cont = new IfConditionEK(
1557 node.then, node.otherwise, conf.environment, conf.state); 1675 node.then, node.otherwise, conf.environment, conf.state);
(...skipping 396 matching lines...) Expand 10 before | Expand all | Expand 10 after
1954 /// Initializes all non initialized fields from the provided class to 2072 /// Initializes all non initialized fields from the provided class to
1955 /// `Value.nullInstance` in the provided value. 2073 /// `Value.nullInstance` in the provided value.
1956 void _initializeNullFields(Class class_, Value value) { 2074 void _initializeNullFields(Class class_, Value value) {
1957 int startIndex = class_.superclass?.instanceSize ?? 0; 2075 int startIndex = class_.superclass?.instanceSize ?? 0;
1958 for (int i = startIndex; i < class_.instanceSize; i++) { 2076 for (int i = startIndex; i < class_.instanceSize; i++) {
1959 if (value.fields[i].value == null) { 2077 if (value.fields[i].value == null) {
1960 value.fields[i].value = Value.nullInstance; 2078 value.fields[i].value = Value.nullInstance;
1961 } 2079 }
1962 } 2080 }
1963 } 2081 }
OLDNEW
« 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