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

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

Issue 2764073002: Add support for implicit getters and setters (Closed)
Patch Set: Remove static get from Value Created 3 years, 9 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 | no next file » | 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 7
8 class NotImplemented { 8 class NotImplemented {
9 String message; 9 String message;
10 10
(...skipping 101 matching lines...) Expand 10 before | Expand all | Expand 10 after
112 } 112 }
113 113
114 Value visitVariableGet(VariableGet node, env) { 114 Value visitVariableGet(VariableGet node, env) {
115 return env.lookup(node.variable); 115 return env.lookup(node.variable);
116 } 116 }
117 117
118 Value visitVariableSet(VariableSet node, env) { 118 Value visitVariableSet(VariableSet node, env) {
119 return env.assign(node.variable, eval(node.value, env)); 119 return env.assign(node.variable, eval(node.value, env));
120 } 120 }
121 121
122 Value visitPropertyGet(PropertyGet node, env) {
123 ObjectValue receiver = eval(node.receiver, env);
Kevin Millikin (Google) 2017/03/23 10:42:51 We have to support property get on things like int
zhivkag 2017/03/23 13:50:39 Indeed, thanks! Done.
124 return receiver.propertyGet(node.name);
Kevin Millikin (Google) 2017/03/23 10:42:50 I suggest we factor this slightly differently: 1.
zhivkag 2017/03/23 13:50:38 Done.
125 }
126
127 Value visitPropertySet(PropertySet node, env) {
128 ObjectValue receiver = eval(node.receiver, env);
129 Value value = eval(node.value, env);
130 return receiver.propertySet(node.name, value);
131 }
132
133 Value visitDirectPropertyGet(DirectPropertyGet node, env) {
134 ObjectValue receiver = eval(node.receiver, env);
135 return receiver.directPropertyGet(node.target);
136 }
137
138 Value visitDirectPropertySet(DirectPropertySet node, env) {
139 ObjectValue receiver = eval(node.receiver, env);
140 Value value = eval(node.value, env);
141 return receiver.directPropertySet(node.target, value);
142 }
143
144 Value visitStaticGet(StaticGet node, env) => defaultExpression(node, env);
145 Value visitStaticSet(StaticSet node, env) => defaultExpression(node, env);
146
122 Value visitStaticInvocation(StaticInvocation node, env) { 147 Value visitStaticInvocation(StaticInvocation node, env) {
123 if ('print' == node.name.toString()) { 148 if ('print' == node.name.toString()) {
124 // Special evaluation of print. 149 // Special evaluation of print.
125 var res = eval(node.arguments.positional[0], env); 150 var res = eval(node.arguments.positional[0], env);
126 print(res.value); 151 print(res.value);
127 return Value.nullInstance; 152 return Value.nullInstance;
128 } else { 153 } else {
129 throw new NotImplemented('Support for statement type ' 154 throw new NotImplemented('Support for statement type '
130 '${node.runtimeType} is not implemented'); 155 '${node.runtimeType} is not implemented');
131 } 156 }
132 } 157 }
133 158
134 Value visitMethodInvocation(MethodInvocation node, env) { 159 Value visitMethodInvocation(MethodInvocation node, env) {
135 // Currently supports only method invocation with <2 arguments and is used 160 // Currently supports only method invocation with <2 arguments and is used
136 // to evaluate implemented operators for int, double and String values. 161 // to evaluate implemented operators for int, double and String values.
137 var receiver = eval(node.receiver, env); 162 var receiver = eval(node.receiver, env);
138 if (node.arguments.positional.isNotEmpty) { 163 if (node.arguments.positional.isNotEmpty) {
139 var argValue = eval(node.arguments.positional.first, env); 164 var argValue = eval(node.arguments.positional.first, env);
140 return receiver.invokeMethod(node.name.name, argValue); 165 return receiver.invokeMethod(node.name, argValue);
141 } else { 166 } else {
142 return receiver.invokeMethod(node.name.name); 167 return receiver.invokeMethod(node.name);
143 } 168 }
144 } 169 }
145 170
146 Value visitConstructorInvocation(ConstructorInvocation node, env) => 171 Value visitConstructorInvocation(ConstructorInvocation node, env) {
147 defaultExpression(node, env); 172 ClassDeclaration classDeclaration =
173 new ClassDeclaration(node.target.enclosingClass.reference);
174
175 Environment emptyEnv = new Environment.empty();
176 // Currently we don't support initializers.
177 // TODO: Modify to respect dart semantics for initialization.
178 // 1. Init fields and eval initializers, repeat the same with super.
179 // 2. Eval the Function body of the constructor.
180 List<Value> fields = classDeclaration.instanceFields
181 .map((Field f) => eval(f.initializer, emptyEnv))
182 .toList(growable: false);
183
184 return new ObjectValue(classDeclaration, fields);
185 }
148 186
149 Value visitNot(Not node, env) { 187 Value visitNot(Not node, env) {
150 Value operand = eval(node.operand, env).toBoolean(); 188 Value operand = eval(node.operand, env).toBoolean();
151 return identical(operand, Value.trueInstance) 189 return identical(operand, Value.trueInstance)
152 ? Value.falseInstance 190 ? Value.falseInstance
153 : Value.trueInstance; 191 : Value.trueInstance;
154 } 192 }
155 193
156 Value visitLogicalExpression(LogicalExpression node, env) { 194 Value visitLogicalExpression(LogicalExpression node, env) {
157 if ('||' == node.operator) { 195 if ('||' == node.operator) {
(...skipping 42 matching lines...) Expand 10 before | Expand all | Expand 10 after
200 return eval(node.body, letEnv); 238 return eval(node.body, letEnv);
201 } 239 }
202 } 240 }
203 241
204 // TODO(zhivkag): Change misleading name. 242 // TODO(zhivkag): Change misleading name.
205 // This is representation of a class in the interpreter, not a declaration. 243 // This is representation of a class in the interpreter, not a declaration.
206 class ClassDeclaration { 244 class ClassDeclaration {
207 static final Map<Reference, ClassDeclaration> _classes = 245 static final Map<Reference, ClassDeclaration> _classes =
208 <Reference, ClassDeclaration>{}; 246 <Reference, ClassDeclaration>{};
209 247
210 Class currentClass; 248 Class superClass;
Kevin Millikin (Google) 2017/03/23 10:42:51 We might not agree, but superclass is one word in
zhivkag 2017/03/23 13:50:38 Done.
211 ClassDeclaration superClass; 249 List<Field> instanceFields = <Field>[];
250 List<Field> staticFields = <Field>[];
251 // Implicit getters and setters for instance Fields.
252 Map<Name, int> getters = <Name, int>{};
Kevin Millikin (Google) 2017/03/23 10:42:51 Thinking ahead, this needs to map names to getters
zhivkag 2017/03/23 13:50:38 Done.
253 Map<Name, int> setters = <Name, int>{};
212 // The initializers of static fields are evaluated the first time the field 254 // The initializers of static fields are evaluated the first time the field
213 // is accessed. 255 // is accessed.
214 List<Value> staticFields = <Value>[]; 256 List<Value> staticFieldValues = <Value>[];
215 List<Procedure> getters = <Procedure>[]; 257
216 List<Procedure> setters = <Procedure>[];
217 List<Procedure> methods = <Procedure>[]; 258 List<Procedure> methods = <Procedure>[];
218 259
219 factory ClassDeclaration(Reference classRef) { 260 factory ClassDeclaration(Reference classRef) {
220 if (_classes.containsKey(classRef)) { 261 if (_classes.containsKey(classRef)) {
221 return _classes[classRef]; 262 return _classes[classRef];
222 } 263 }
223 _classes[classRef] = new ClassDeclaration._internal(classRef.asClass); 264 _classes[classRef] = new ClassDeclaration._internal(classRef.asClass);
224 return _classes[classRef]; 265 return _classes[classRef];
225 } 266 }
226 267
227 ClassDeclaration._internal(this.currentClass) { 268 ClassDeclaration._internal(Class currentClass) {
228 if (currentClass.superclass != null) { 269 if (currentClass.superclass != null) {
229 superClass = new ClassDeclaration(currentClass.superclass.reference); 270 superClass = currentClass.superclass;
230 } 271 }
231 // TODO: Populate getters, setters and methods. 272
273 _populateInstanceFields(currentClass);
274
275 // Populate implicit setters and getters.
276 for (int i = 0; i < instanceFields.length; i++) {
277 Field f = instanceFields[i];
278 assert(f.hasImplicitGetter);
279 getters[f.name] = i;
Kevin Millikin (Google) 2017/03/23 10:42:51 So the getter function should be: getters[f.name]
zhivkag 2017/03/23 13:50:38 Done.
280 if (f.hasImplicitSetter) {
281 setters[f.name] = i;
282 }
283 }
284 // TODO: Populate methods.
285 }
286
287 Value propertyGet(ObjectValue object, Name name) {
Kevin Millikin (Google) 2017/03/23 10:42:51 The name should be the verb form: getProperty.
zhivkag 2017/03/23 13:50:38 Done.
288 if (getters.containsKey(name)) {
Kevin Millikin (Google) 2017/03/23 10:42:51 We should look in the superclass for a getter. If
zhivkag 2017/03/23 13:50:38 Makes sense, thanks! Done.
289 return (object.fields)[getters[name]];
290 }
291 // TODO: return NoSuchMethod if Name is not a Getter or Method tear-off
292 return notImplemented(obj: name);
293 }
294
295 Value propertySet(ObjectValue object, Name name, Value value) {
Kevin Millikin (Google) 2017/03/23 10:42:51 Likewise, I's split this into looking up the sette
zhivkag 2017/03/23 13:50:39 Applied the suggestion but I have a doubt whether
296 if (setters.containsKey(name)) {
297 object.fields[setters[name]] = value;
298 }
299 // TODO: return NoSuchMethodError if Name is not a Setter.
300 return Value.nullInstance;
301 }
302
303 Value directPropertyGet(ObjectValue object, Member member) {
304 if (member is Field) {
305 for (int i = 0; i < instanceFields.length; i++) {
306 if (identical(member, instanceFields[i])) {
307 return object.fields[i];
308 }
309 }
310 // TODO: throw NoSuchMethodError instead.
311 return notImplemented(m: 'NoSuchMethod: Field ${member} not found.');
312 }
313 return notImplemented(obj: member);
314 }
315
316 Value directPropertySet(ObjectValue object, Member member, Value value) {
317 if (member is Field) {
318 for (int i = 0; i < instanceFields.length; i++) {
319 if (identical(member, instanceFields[i])) {
320 object.fields[i] = value;
321 }
322 return Value.nullInstance;
323 }
324 // TODO: throw NoSuchMethodError instead.
325 return notImplemented(m: 'NoSuchMethod: Field $member not found.');
326 }
327 return notImplemented(obj: member);
328 }
329
330 // Populates with the instance fields of the current class and all its
331 // superclasses recursively.
332 _populateInstanceFields(Class class_) {
333 for (Field f in class_.fields) {
334 if (f.isInstanceMember) {
335 instanceFields.add(f);
336 }
337 }
338
339 if (class_.superclass != null) {
340 _populateInstanceFields(class_.superclass);
341 }
232 } 342 }
233 } 343 }
234 344
235 abstract class Value { 345 abstract class Value {
236 Object get value; 346 Object get value;
237 347
238 static final NullValue nullInstance = const NullValue(); 348 static final NullValue nullInstance = const NullValue();
239 static final BoolValue trueInstance = const BoolValue(true); 349 static final BoolValue trueInstance = const BoolValue(true);
240 static final BoolValue falseInstance = const BoolValue(false); 350 static final BoolValue falseInstance = const BoolValue(false);
241 351
242 const Value(); 352 const Value();
243 353
244 BoolValue toBoolean() { 354 BoolValue toBoolean() {
245 return identical(this, Value.trueInstance) 355 return identical(this, Value.trueInstance)
246 ? Value.trueInstance 356 ? Value.trueInstance
247 : Value.falseInstance; 357 : Value.falseInstance;
248 } 358 }
249 359
250 BoolValue equals(Value other) => 360 BoolValue equals(Value other) =>
251 value == other.value ? Value.trueInstance : Value.falseInstance; 361 value == other.value ? Value.trueInstance : Value.falseInstance;
252 362
253 Value invokeMethod(String name, [Value arg]) { 363 Value invokeMethod(Name name, [Value arg]) {
254 throw notImplemented(obj: name); 364 throw notImplemented(obj: name);
255 } 365 }
256 } 366 }
257 367
258 class ObjectValue extends Value { 368 class ObjectValue extends Value {
259 List<Value> fields; 369 List<Value> fields;
260 ClassDeclaration classDeclaration; 370 ClassDeclaration classDeclaration;
261 371
262 Object get value => this; 372 Object get value => this;
263 373
264 ObjectValue(Constructor constructor, Environment env) { 374 ObjectValue(this.classDeclaration, this.fields);
265 // TODO: Init fields and eval initializers, repeat the same with super. 375
266 // TODO: Eval the Function body of the constructor, with env expanded with 376 Value propertyGet(Name name) {
267 // {VariableDeclaration("this") => this} 377 return classDeclaration.propertyGet(this, name);
268 notImplemented(obj: constructor.name);
269 } 378 }
379
380 Value propertySet(Name name, Value value) =>
381 classDeclaration.propertySet(this, name, value);
382
383 Value directPropertyGet(Member member) =>
384 classDeclaration.directPropertyGet(this, member);
385 Value directPropertySet(Member member, Value value) =>
386 classDeclaration.directPropertySet(this, member, value);
270 } 387 }
271 388
272 class StringValue extends Value { 389 class StringValue extends Value {
273 final String value; 390 final String value;
274 391
275 static final operators = <String, Function>{ 392 static final operators = <String, Function>{
276 '[]': (StringValue v1, Value v2) => v1[v2], 393 '[]': (StringValue v1, Value v2) => v1[v2],
277 '==': (StringValue v1, Value v2) => v1.equals(v2) 394 '==': (StringValue v1, Value v2) => v1.equals(v2)
278 }; 395 };
279 396
280 StringValue(this.value); 397 StringValue(this.value);
281 398
282 Value invokeMethod(String name, [Value arg]) { 399 Value invokeMethod(Name name, [Value arg]) {
283 if (!operators.containsKey(name)) { 400 if (!operators.containsKey(name.name)) {
284 return notImplemented(obj: name); 401 return notImplemented(obj: name);
285 } 402 }
286 return operators[name](this, arg); 403 return operators[name.name](this, arg);
287 } 404 }
288 405
289 // Operators 406 // Operators
290 Value operator [](Value index) => new StringValue(value[index.value]); 407 Value operator [](Value index) => new StringValue(value[index.value]);
291 } 408 }
292 409
293 abstract class NumValue extends Value { 410 abstract class NumValue extends Value {
294 num get value; 411 num get value;
295 412
296 NumValue(); 413 NumValue();
297 414
298 factory NumValue.fromValue(num value) { 415 factory NumValue.fromValue(num value) {
299 if (value is int) { 416 if (value is int) {
300 return new IntValue(value); 417 return new IntValue(value);
301 } else { 418 } else {
302 assert(value is double); 419 assert(value is double);
303 return new DoubleValue(value); 420 return new DoubleValue(value);
304 } 421 }
305 } 422 }
306 423
307 static final operators = <String, Function>{ 424 static final operators = <String, Function>{
308 '+': (NumValue v1, Value v2) => v1 + v2, 425 '+': (NumValue v1, Value v2) => v1 + v2,
309 '-': (NumValue v1, Value v2) => v1 - v2, 426 '-': (NumValue v1, Value v2) => v1 - v2,
310 '>': (NumValue v1, Value v2) => v1 > v2, 427 '>': (NumValue v1, Value v2) => v1 > v2,
311 '<': (NumValue v1, Value v2) => v1 < v2, 428 '<': (NumValue v1, Value v2) => v1 < v2,
312 '==': (NumValue v1, Value v2) => v1.equals(v2), 429 '==': (NumValue v1, Value v2) => v1.equals(v2),
313 'unary-': (NumValue v1) => -v1, 430 'unary-': (NumValue v1) => -v1,
314 }; 431 };
315 432
316 Value invokeMethod(String name, [Value arg]) { 433 Value invokeMethod(Name name, [Value arg]) {
317 if (!operators.containsKey(name)) return notImplemented(obj: name); 434 if (!operators.containsKey(name.name)) return notImplemented(obj: name);
318 if (arg == null) return operators[name](this); 435 if (arg == null) return operators[name.name](this);
319 return operators[name](this, arg); 436 return operators[name.name](this, arg);
320 } 437 }
321 438
322 // Operators 439 // Operators
323 NumValue operator +(Value other) => 440 NumValue operator +(Value other) =>
324 new NumValue.fromValue(value + other.value); 441 new NumValue.fromValue(value + other.value);
325 NumValue operator -(Value other) => 442 NumValue operator -(Value other) =>
326 new NumValue.fromValue(value - other.value); 443 new NumValue.fromValue(value - other.value);
327 NumValue operator -() => new NumValue.fromValue(-value); 444 NumValue operator -() => new NumValue.fromValue(-value);
328 445
329 BoolValue operator >(Value other) => 446 BoolValue operator >(Value other) =>
(...skipping 22 matching lines...) Expand all
352 469
353 class NullValue extends Value { 470 class NullValue extends Value {
354 Object get value => null; 471 Object get value => null;
355 472
356 const NullValue(); 473 const NullValue();
357 } 474 }
358 475
359 notImplemented({String m, Object obj}) { 476 notImplemented({String m, Object obj}) {
360 throw new NotImplemented(m ?? 'Evaluation for $obj is not implemented'); 477 throw new NotImplemented(m ?? 'Evaluation for $obj is not implemented');
361 } 478 }
OLDNEW
« no previous file with comments | « no previous file | no next file » | no next file with comments »

Powered by Google App Engine
This is Rietveld 408576698