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

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

Issue 2764073002: Add support for implicit getters and setters (Closed)
Patch Set: Fix formatting 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 Value receiver = eval(node.receiver, env);
124 return receiver.classDeclaration.lookupGetter(node.name)(receiver);
125 }
126
127 Value visitPropertySet(PropertySet node, env) {
128 Value receiver = eval(node.receiver, env);
129 Value value = eval(node.value, env);
130 receiver.classDeclaration.lookupSetter(node.name)(receiver, value);
131 return value;
132 }
133
134 Value visitDirectPropertyGet(DirectPropertyGet node, env) {
135 Value receiver = eval(node.receiver, env);
136 return receiver.classDeclaration.getProperty(receiver, node.target);
137 }
138
139 Value visitDirectPropertySet(DirectPropertySet node, env) {
140 Value receiver = eval(node.receiver, env);
141 Value value = eval(node.value, env);
142 receiver.classDeclaration.setProperty(receiver, node.target, value);
143 return value;
144 }
145
146 Value visitStaticGet(StaticGet node, env) => defaultExpression(node, env);
147 Value visitStaticSet(StaticSet node, env) => defaultExpression(node, env);
148
122 Value visitStaticInvocation(StaticInvocation node, env) { 149 Value visitStaticInvocation(StaticInvocation node, env) {
123 if ('print' == node.name.toString()) { 150 if ('print' == node.name.toString()) {
124 // Special evaluation of print. 151 // Special evaluation of print.
125 var res = eval(node.arguments.positional[0], env); 152 var res = eval(node.arguments.positional[0], env);
126 print(res.value); 153 print(res.value);
127 return Value.nullInstance; 154 return Value.nullInstance;
128 } else { 155 } else {
129 throw new NotImplemented('Support for statement type ' 156 throw new NotImplemented('Support for statement type '
130 '${node.runtimeType} is not implemented'); 157 '${node.runtimeType} is not implemented');
131 } 158 }
132 } 159 }
133 160
134 Value visitMethodInvocation(MethodInvocation node, env) { 161 Value visitMethodInvocation(MethodInvocation node, env) {
135 // Currently supports only method invocation with <2 arguments and is used 162 // Currently supports only method invocation with <2 arguments and is used
136 // to evaluate implemented operators for int, double and String values. 163 // to evaluate implemented operators for int, double and String values.
137 var receiver = eval(node.receiver, env); 164 var receiver = eval(node.receiver, env);
138 if (node.arguments.positional.isNotEmpty) { 165 if (node.arguments.positional.isNotEmpty) {
139 var argValue = eval(node.arguments.positional.first, env); 166 var argValue = eval(node.arguments.positional.first, env);
140 return receiver.invokeMethod(node.name.name, argValue); 167 return receiver.invokeMethod(node.name, argValue);
141 } else { 168 } else {
142 return receiver.invokeMethod(node.name.name); 169 return receiver.invokeMethod(node.name);
143 } 170 }
144 } 171 }
145 172
146 Value visitConstructorInvocation(ConstructorInvocation node, env) => 173 Value visitConstructorInvocation(ConstructorInvocation node, env) {
147 defaultExpression(node, env); 174 ClassDeclaration classDeclaration =
175 new ClassDeclaration(node.target.enclosingClass.reference);
176
177 Environment emptyEnv = new Environment.empty();
178 // Currently we don't support initializers.
179 // TODO: Modify to respect dart semantics for initialization.
180 // 1. Init fields and eval initializers, repeat the same with super.
181 // 2. Eval the Function body of the constructor.
182 List<Value> fields = classDeclaration.instanceFields
183 .map((Field f) => eval(f.initializer, emptyEnv))
184 .toList(growable: false);
185
186 return new ObjectValue(classDeclaration, fields);
187 }
148 188
149 Value visitNot(Not node, env) { 189 Value visitNot(Not node, env) {
150 Value operand = eval(node.operand, env).toBoolean(); 190 Value operand = eval(node.operand, env).toBoolean();
151 return identical(operand, Value.trueInstance) 191 return identical(operand, Value.trueInstance)
152 ? Value.falseInstance 192 ? Value.falseInstance
153 : Value.trueInstance; 193 : Value.trueInstance;
154 } 194 }
155 195
156 Value visitLogicalExpression(LogicalExpression node, env) { 196 Value visitLogicalExpression(LogicalExpression node, env) {
157 if ('||' == node.operator) { 197 if ('||' == node.operator) {
(...skipping 36 matching lines...) Expand 10 before | Expand all | Expand 10 after
194 Value visitNullLiteral(NullLiteral node, env) => Value.nullInstance; 234 Value visitNullLiteral(NullLiteral node, env) => Value.nullInstance;
195 235
196 Value visitLet(Let node, env) { 236 Value visitLet(Let node, env) {
197 var value = eval(node.variable.initializer, env); 237 var value = eval(node.variable.initializer, env);
198 var letEnv = new Environment(env); 238 var letEnv = new Environment(env);
199 letEnv.expand(node.variable, value); 239 letEnv.expand(node.variable, value);
200 return eval(node.body, letEnv); 240 return eval(node.body, letEnv);
201 } 241 }
202 } 242 }
203 243
244 typedef Value Getter(Value receiver);
245 typedef void Setter(Value receiver, Value value);
246
204 // TODO(zhivkag): Change misleading name. 247 // TODO(zhivkag): Change misleading name.
205 // This is representation of a class in the interpreter, not a declaration. 248 // This is representation of a class in the interpreter, not a declaration.
206 class ClassDeclaration { 249 class ClassDeclaration {
207 static final Map<Reference, ClassDeclaration> _classes = 250 static final Map<Reference, ClassDeclaration> _classes =
208 <Reference, ClassDeclaration>{}; 251 <Reference, ClassDeclaration>{};
209 252
210 Class currentClass; 253 ClassDeclaration superclass;
211 ClassDeclaration superClass; 254 List<Field> instanceFields = <Field>[];
255 List<Field> staticFields = <Field>[];
256 // Implicit getters and setters for instance Fields.
257 Map<Name, Getter> getters = <Name, Getter>{};
258 Map<Name, Setter> setters = <Name, Setter>{};
212 // The initializers of static fields are evaluated the first time the field 259 // The initializers of static fields are evaluated the first time the field
213 // is accessed. 260 // is accessed.
214 List<Value> staticFields = <Value>[]; 261 List<Value> staticFieldValues = <Value>[];
215 List<Procedure> getters = <Procedure>[]; 262
216 List<Procedure> setters = <Procedure>[];
217 List<Procedure> methods = <Procedure>[]; 263 List<Procedure> methods = <Procedure>[];
218 264
219 factory ClassDeclaration(Reference classRef) { 265 factory ClassDeclaration(Reference classRef) {
220 if (_classes.containsKey(classRef)) { 266 if (_classes.containsKey(classRef)) {
221 return _classes[classRef]; 267 return _classes[classRef];
222 } 268 }
223 _classes[classRef] = new ClassDeclaration._internal(classRef.asClass); 269 _classes[classRef] = new ClassDeclaration._internal(classRef.asClass);
224 return _classes[classRef]; 270 return _classes[classRef];
225 } 271 }
226 272
227 ClassDeclaration._internal(this.currentClass) { 273 ClassDeclaration._internal(Class currentClass) {
228 if (currentClass.superclass != null) { 274 if (currentClass.superclass != null) {
229 superClass = new ClassDeclaration(currentClass.superclass.reference); 275 superclass = new ClassDeclaration(currentClass.superclass.reference);
230 } 276 }
231 // TODO: Populate getters, setters and methods. 277
278 _populateInstanceFields(currentClass);
279
280 // Populate implicit setters and getters.
281 for (int i = 0; i < instanceFields.length; i++) {
282 Field f = instanceFields[i];
283 assert(f.hasImplicitGetter);
284 getters[f.name] = (Value receiver) => receiver.fields[i];
285 if (f.hasImplicitSetter) {
286 setters[f.name] =
287 (Value receiver, Value value) => receiver.fields[i] = value;
288 }
289 }
290 // TODO: Populate methods.
291 }
292
293 Getter lookupGetter(Name name) {
294 Getter getter = getters[name];
295 if (getter != null) return getter;
296 if (superclass != null) return superclass.lookupGetter(name);
297 return (Value receiver) => notImplemented(obj: name);
298 }
299
300 Setter lookupSetter(Name name) {
301 Setter setter = setters[name];
302 if (setter != null) return setter;
303 if (superclass != null) return lookupSetter(name);
304 return (Value receiver, Value value) => notImplemented(obj: name);
305 }
306
307 Value getProperty(ObjectValue object, Member member) {
308 if (member is Field) {
309 int index = instanceFields.indexOf(member);
310 // TODO: throw NoSuchMethodError instead.
311 if (index < 0) return notImplemented(m: 'NoSuchMethod: ${member}');
312 return object.fields[index];
313 }
314 return notImplemented(obj: member);
315 }
316
317 Value setProperty(ObjectValue object, Member member, Value value) {
318 if (member is Field) {
319 int index = instanceFields.indexOf(member);
320 // TODO: throw NoSuchMethodError instead.
321 if (index < 0) return notImplemented(m: 'NoSuchMethod: ${member}');
322 object.fields[index] = value;
323 return Value.nullInstance;
324 }
325 return notImplemented(obj: member);
326 }
327
328 // Populates with the instance fields of the current class and all its
329 // superclasses recursively.
330 _populateInstanceFields(Class class_) {
331 for (Field f in class_.fields) {
332 if (f.isInstanceMember) {
333 instanceFields.add(f);
334 }
335 }
336
337 if (class_.superclass != null) {
338 _populateInstanceFields(class_.superclass);
339 }
232 } 340 }
233 } 341 }
234 342
235 abstract class Value { 343 abstract class Value {
344 ClassDeclaration get classDeclaration;
345 List<Value> get fields;
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 {
369 ClassDeclaration classDeclaration;
259 List<Value> fields; 370 List<Value> fields;
260 ClassDeclaration classDeclaration;
261
262 Object get value => this; 371 Object get value => this;
263 372
264 ObjectValue(Constructor constructor, Environment env) { 373 ObjectValue(this.classDeclaration, this.fields);
265 // TODO: Init fields and eval initializers, repeat the same with super.
266 // TODO: Eval the Function body of the constructor, with env expanded with
267 // {VariableDeclaration("this") => this}
268 notImplemented(obj: constructor.name);
269 }
270 } 374 }
271 375
272 class StringValue extends Value { 376 abstract class LiteralValue extends Value {
377 ClassDeclaration get classDeclaration =>
378 notImplemented(m: "Loading class for literal is not implemented.");
379 List<Value> get fields =>
380 notImplemented(m: "Literal value does not have fields");
381
382 const LiteralValue();
383 }
384
385 class StringValue extends LiteralValue {
273 final String value; 386 final String value;
274 387
275 static final operators = <String, Function>{ 388 static final operators = <String, Function>{
276 '[]': (StringValue v1, Value v2) => v1[v2], 389 '[]': (StringValue v1, Value v2) => v1[v2],
277 '==': (StringValue v1, Value v2) => v1.equals(v2) 390 '==': (StringValue v1, Value v2) => v1.equals(v2)
278 }; 391 };
279 392
280 StringValue(this.value); 393 StringValue(this.value);
281 394
282 Value invokeMethod(String name, [Value arg]) { 395 Value invokeMethod(Name name, [Value arg]) {
283 if (!operators.containsKey(name)) { 396 if (!operators.containsKey(name.name)) {
284 return notImplemented(obj: name); 397 return notImplemented(obj: name);
285 } 398 }
286 return operators[name](this, arg); 399 return operators[name.name](this, arg);
287 } 400 }
288 401
289 // Operators 402 // Operators
290 Value operator [](Value index) => new StringValue(value[index.value]); 403 Value operator [](Value index) => new StringValue(value[index.value]);
291 } 404 }
292 405
293 abstract class NumValue extends Value { 406 abstract class NumValue extends LiteralValue {
294 num get value; 407 num get value;
295 408
296 NumValue(); 409 NumValue();
297 410
298 factory NumValue.fromValue(num value) { 411 factory NumValue.fromValue(num value) {
299 if (value is int) { 412 if (value is int) {
300 return new IntValue(value); 413 return new IntValue(value);
301 } else { 414 } else {
302 assert(value is double); 415 assert(value is double);
303 return new DoubleValue(value); 416 return new DoubleValue(value);
304 } 417 }
305 } 418 }
306 419
307 static final operators = <String, Function>{ 420 static final operators = <String, Function>{
308 '+': (NumValue v1, Value v2) => v1 + v2, 421 '+': (NumValue v1, Value v2) => v1 + v2,
309 '-': (NumValue v1, Value v2) => v1 - v2, 422 '-': (NumValue v1, Value v2) => v1 - v2,
310 '>': (NumValue v1, Value v2) => v1 > v2, 423 '>': (NumValue v1, Value v2) => v1 > v2,
311 '<': (NumValue v1, Value v2) => v1 < v2, 424 '<': (NumValue v1, Value v2) => v1 < v2,
312 '==': (NumValue v1, Value v2) => v1.equals(v2), 425 '==': (NumValue v1, Value v2) => v1.equals(v2),
313 'unary-': (NumValue v1) => -v1, 426 'unary-': (NumValue v1) => -v1,
314 }; 427 };
315 428
316 Value invokeMethod(String name, [Value arg]) { 429 Value invokeMethod(Name name, [Value arg]) {
317 if (!operators.containsKey(name)) return notImplemented(obj: name); 430 if (!operators.containsKey(name.name)) return notImplemented(obj: name);
318 if (arg == null) return operators[name](this); 431 if (arg == null) return operators[name.name](this);
319 return operators[name](this, arg); 432 return operators[name.name](this, arg);
320 } 433 }
321 434
322 // Operators 435 // Operators
323 NumValue operator +(Value other) => 436 NumValue operator +(Value other) =>
324 new NumValue.fromValue(value + other.value); 437 new NumValue.fromValue(value + other.value);
325 NumValue operator -(Value other) => 438 NumValue operator -(Value other) =>
326 new NumValue.fromValue(value - other.value); 439 new NumValue.fromValue(value - other.value);
327 NumValue operator -() => new NumValue.fromValue(-value); 440 NumValue operator -() => new NumValue.fromValue(-value);
328 441
329 BoolValue operator >(Value other) => 442 BoolValue operator >(Value other) =>
330 value > other.value ? Value.trueInstance : Value.falseInstance; 443 value > other.value ? Value.trueInstance : Value.falseInstance;
331 BoolValue operator <(Value other) => 444 BoolValue operator <(Value other) =>
332 value < other.value ? Value.trueInstance : Value.falseInstance; 445 value < other.value ? Value.trueInstance : Value.falseInstance;
333 } 446 }
334 447
335 class IntValue extends NumValue { 448 class IntValue extends NumValue {
336 final int value; 449 final int value;
337 450
338 IntValue(this.value); 451 IntValue(this.value);
339 } 452 }
340 453
341 class DoubleValue extends NumValue { 454 class DoubleValue extends NumValue {
342 final double value; 455 final double value;
343 456
344 DoubleValue(this.value); 457 DoubleValue(this.value);
345 } 458 }
346 459
347 class BoolValue extends Value { 460 class BoolValue extends LiteralValue {
348 final bool value; 461 final bool value;
349 462
350 const BoolValue(this.value); 463 const BoolValue(this.value);
351 } 464 }
352 465
353 class NullValue extends Value { 466 class NullValue extends LiteralValue {
354 Object get value => null; 467 Object get value => null;
355 468
356 const NullValue(); 469 const NullValue();
357 } 470 }
358 471
359 notImplemented({String m, Object obj}) { 472 notImplemented({String m, Object obj}) {
360 throw new NotImplemented(m ?? 'Evaluation for $obj is not implemented'); 473 throw new NotImplemented(m ?? 'Evaluation for $obj is not implemented');
361 } 474 }
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