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

Side by Side Diff: frog/leg/compile_time_constants.dart

Issue 9665001: Implement constant maps. (Closed) Base URL: https://dart.googlecode.com/svn/branches/bleeding_edge/dart
Patch Set: cosmetic change. Created 8 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 | Annotate | Revision Log
« no previous file with comments | « no previous file | frog/leg/lib/constant_map.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) 2012, the Dart project authors. Please see the AUTHORS file 1 // Copyright (c) 2012, 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 4
5 class Constant implements Hashable { 5 class Constant implements Hashable {
6 const Constant(); 6 const Constant();
7 7
8 bool isNull() => false; 8 bool isNull() => false;
9 bool isBool() => false; 9 bool isBool() => false;
10 bool isTrue() => false; 10 bool isTrue() => false;
11 bool isFalse() => false; 11 bool isFalse() => false;
12 bool isInt() => false; 12 bool isInt() => false;
13 bool isDouble() => false; 13 bool isDouble() => false;
14 bool isNum() => false; 14 bool isNum() => false;
15 bool isString() => false; 15 bool isString() => false;
16 bool isList() => false; 16 bool isList() => false;
17 bool isMap() => false; 17 bool isMap() => false;
18 bool isConstructedObject() => false; 18 bool isConstructedObject() => false;
19 /** Returns true if the constant is a list, a map or a constructed object. */ 19 /** Returns true if the constant is a list, a map or a constructed object. */
20 bool isObject() => false; 20 bool isObject() => false;
21 21
22 abstract void writeJsCode(StringBuffer buffer, ConstantHandler handler); 22 abstract void writeJsCode(StringBuffer buffer, ConstantHandler handler);
23
24 /**
25 * Recursively adds the constants dependencies unless the dependency is
26 * already in the [seenConstants] list. Does not add itself to the [list].
ngeoffray 2012/03/10 18:33:55 [seenConstants] list -> [seenConstants] set.
floitsch 2012/03/10 19:58:54 has been removed.
27 *
28 * The dependent constants must always be added before the user of the
29 * constant.
30 *
31 * Any constant that is added to the list must also be added to the set.
32 */
33 // TODO(floitsch): this should take an ordered set.
34 abstract void addDependencies(List<Constant> list,
ngeoffray 2012/03/10 18:33:55 Maybe rename list to orderedList. 'list' is too ge
floitsch 2012/03/10 19:58:54 has been removed.
35 Set<Constant> seenConstants);
23 } 36 }
24 37
25 class PrimitiveConstant extends Constant { 38 class PrimitiveConstant extends Constant {
26 abstract get value(); 39 abstract get value();
27 const PrimitiveConstant(); 40 const PrimitiveConstant();
28 41
29 bool operator ==(var other) { 42 bool operator ==(var other) {
30 if (other is !PrimitiveConstant) return false; 43 if (other is !PrimitiveConstant) return false;
31 PrimitiveConstant otherPrimitive = other; 44 PrimitiveConstant otherPrimitive = other;
32 // We use == instead of === so that DartStrings compare correctly. 45 // We use == instead of === so that DartStrings compare correctly.
33 return value == otherPrimitive.value; 46 return value == otherPrimitive.value;
34 } 47 }
35 48
36 String toString() => value.toString(); 49 String toString() => value.toString();
50 void addDependencies(List<Constant> list, Set<Constant> seenConstants) {
51 // Primitive constants don't have dependencies.
52 }
37 abstract DartString toDartString(); 53 abstract DartString toDartString();
38 } 54 }
39 55
40 class NullConstant extends PrimitiveConstant { 56 class NullConstant extends PrimitiveConstant {
41 factory NullConstant() => const NullConstant._internal(); 57 factory NullConstant() => const NullConstant._internal();
42 const NullConstant._internal(); 58 const NullConstant._internal();
43 bool isNull() => true; 59 bool isNull() => true;
44 get value() => null; 60 get value() => null;
45 61
46 void writeJsCode(StringBuffer buffer, ConstantHandler handler) { 62 void writeJsCode(StringBuffer buffer, ConstantHandler handler) {
(...skipping 184 matching lines...) Expand 10 before | Expand all | Expand 10 after
231 247
232 int hashCode() => _hashCode; 248 int hashCode() => _hashCode;
233 DartString toDartString() => value; 249 DartString toDartString() => value;
234 } 250 }
235 251
236 class ObjectConstant extends Constant { 252 class ObjectConstant extends Constant {
237 final Type type; 253 final Type type;
238 254
239 ObjectConstant(this.type); 255 ObjectConstant(this.type);
240 bool isObject() => true; 256 bool isObject() => true;
257
258 void addDependency(Constant constant,
ngeoffray 2012/03/10 18:33:55 Instead of putting addDependeny on a Constant clas
floitsch 2012/03/10 19:58:54 replaced with getDependencies().
259 List<Constant> list,
260 Set<Constant> seenConstants) {
261 if (!seenConstants.contains(constant)) {
262 constant.addDependencies(list, seenConstants);
263 list.add(constant);
264 seenConstants.add(constant);
265 }
266 }
241 } 267 }
242 268
243 class ListConstant extends ObjectConstant { 269 class ListConstant extends ObjectConstant {
244 final List<Constant> entries; 270 final List<Constant> entries;
245 int _hashCode; 271 int _hashCode;
246 272
247 ListConstant(Type type, this.entries) : super(type) { 273 ListConstant(Type type, this.entries) : super(type) {
248 // TODO(floitsch): create a better hash. 274 // TODO(floitsch): create a better hash.
249 int hash = 0; 275 int hash = 0;
250 for (Constant input in entries) hash ^= input.hashCode(); 276 for (Constant input in entries) hash ^= input.hashCode();
(...skipping 17 matching lines...) Expand all
268 entry.writeJsCode(buffer, handler); 294 entry.writeJsCode(buffer, handler);
269 } 295 }
270 } 296 }
271 buffer.add("])"); 297 buffer.add("])");
272 } 298 }
273 299
274 bool operator ==(var other) { 300 bool operator ==(var other) {
275 if (other is !ListConstant) return false; 301 if (other is !ListConstant) return false;
276 ListConstant otherList = other; 302 ListConstant otherList = other;
277 if (hashCode() != otherList.hashCode()) return false; 303 if (hashCode() != otherList.hashCode()) return false;
278 // TODO(floitsch): verify that the types are the same. 304 // TODO(floitsch): verify that the generic types are the same.
279 if (entries.length != otherList.entries.length) return false; 305 if (entries.length != otherList.entries.length) return false;
280 for (int i = 0; i < entries.length; i++) { 306 for (int i = 0; i < entries.length; i++) {
281 if (entries[i] != otherList.entries[i]) return false; 307 if (entries[i] != otherList.entries[i]) return false;
282 } 308 }
283 return true; 309 return true;
284 } 310 }
285 311
286 int hashCode() => _hashCode; 312 int hashCode() => _hashCode;
313
314 void addDependencies(List<Constant> list, Set<Constant> seenConstants) {
315 for (Constant constant in entries) {
316 addDependency(constant, list, seenConstants);
317 }
318 }
319 }
320
321 class MapConstant extends ObjectConstant {
322 /** The dart class implementing constant map literals. */
323 static final SourceString DART_CLASS = const SourceString("ConstantMap");
324 static final SourceString LENGTH_NAME = const SourceString("length");
325 static final SourceString JS_OBJECT_NAME = const SourceString("_jsObject");
326 static final SourceString KEYS_NAME = const SourceString("_keys");
327
328 final ListConstant keys;
329 final List<Constant> values;
330 int _hashCode;
331
332 MapConstant(Type type, this.keys, this.values) : super(type) {
333 // TODO(floitsch): create a better hash.
334 int hash = 0;
335 for (Constant value in values) hash ^= value.hashCode();
336 _hashCode = hash;
337 }
338 bool isMap() => true;
339
340 void writeJsCode(StringBuffer buffer, ConstantHandler handler) {
341 String isolatePrototype = "${handler.compiler.namer.ISOLATE}.prototype";
342
343 void writeJsMap() {
344 buffer.add("{");
345 for (int i = 0; i < keys.entries.length; i++) {
346 if (i != 0) buffer.add(", ");
347
348 StringConstant key = keys.entries[i];
349 key.writeJsCode(buffer, handler);
350 buffer.add(": ");
351 Constant value = values[i];
352 // TODO(floitsch): share this code with the ListConstant and
353 // ConstructedConstant.
354 if (value.isObject()) {
355 String name = handler.getNameForConstant(value);
356 buffer.add("$isolatePrototype.$name");
357 } else {
358 value.writeJsCode(buffer, handler);
359 }
360 }
361 buffer.add("}");
362 }
363
364 void badFieldCountError() {
365 handler.compiler.internalError(
366 "Compiler and ConstantMap disagree on number of fields.");
367 }
368
369 ClassElement classElement = type.element;
370 buffer.add("new ");
371 buffer.add(handler.getJsConstructor(classElement));
372 buffer.add("(");
373 // The arguments of the JavaScript constructor for any given Dart class
374 // are in the same order as the members of the class element.
375 int emittedArgumentCount = 0;
376 for (Element element in classElement.members) {
377 if (element.name == LENGTH_NAME) {
378 buffer.add(keys.entries.length);
379 } else if (element.name == JS_OBJECT_NAME) {
380 writeJsMap();
381 } else if (element.name == KEYS_NAME) {
382 // TODO(floitsch): share this code with the ListConstant and
383 // ConstructedConstant.
384 String name = handler.getNameForConstant(keys);
385 buffer.add("$isolatePrototype.$name");
386 } else {
387 // Skip methods.
388 if (element.kind == ElementKind.FIELD) badFieldCountError();
389 continue;
390 }
391 emittedArgumentCount++;
392 if (emittedArgumentCount == 3) {
393 break; // All arguments have been emitted.
394 } else {
395 buffer.add(", ");
396 }
397 }
398 if (emittedArgumentCount != 3) badFieldCountError();
399 buffer.add(")");
400 }
401
402 bool operator ==(var other) {
403 if (other is !MapConstant) return false;
404 MapConstant otherMap = other;
405 if (hashCode() != otherMap.hashCode()) return false;
406 // TODO(floitsch): verify that the generic types are the same.
407 if (keys != otherMap.keys) return false;
408 for (int i = 0; i < values.length; i++) {
409 if (values[i] != otherMap.values[i]) return false;
410 }
411 return true;
412 }
413
414 int hashCode() => _hashCode;
415
416 void addDependencies(List<Constant> list, Set<Constant> seenConstants) {
417 addDependency(keys, list, seenConstants);
418 for (Constant constant in values) {
419 addDependency(constant, list, seenConstants);
420 }
421 }
287 } 422 }
288 423
289 class ConstructedConstant extends ObjectConstant { 424 class ConstructedConstant extends ObjectConstant {
290 final List<Constant> fields; 425 final List<Constant> fields;
291 int _hashCode; 426 int _hashCode;
292 427
293 ConstructedConstant(Type type, this.fields) : super(type) { 428 ConstructedConstant(Type type, this.fields) : super(type) {
294 assert(type !== null); 429 assert(type !== null);
295 // TODO(floitsch): create a better hash. 430 // TODO(floitsch): create a better hash.
296 int hash = 0; 431 int hash = 0;
297 for (Constant field in fields) { 432 for (Constant field in fields) {
298 hash ^= field.hashCode(); 433 hash ^= field.hashCode();
299 } 434 }
300 hash ^= type.element.hashCode(); 435 hash ^= type.element.hashCode();
301 _hashCode = hash; 436 _hashCode = hash;
302 } 437 }
303 bool isConstructedObject() => true; 438 bool isConstructedObject() => true;
304 439
305 void writeJsCode(StringBuffer buffer, ConstantHandler handler) { 440 void writeJsCode(StringBuffer buffer, ConstantHandler handler) {
306 buffer.add("new "); 441 buffer.add("new ");
307 buffer.add(handler.getJsConstructor(type.element)); 442 buffer.add(handler.getJsConstructor(type.element));
308 buffer.add("("); 443 buffer.add("(");
309 String isolatePrototype = "${handler.compiler.namer.ISOLATE}.prototype"; 444 String isolatePrototype = "${handler.compiler.namer.ISOLATE}.prototype";
310 for (int i = 0; i < fields.length; i++) { 445 for (int i = 0; i < fields.length; i++) {
311 if (i != 0) buffer.add(", "); 446 if (i != 0) buffer.add(", ");
312 Constant field = fields[i]; 447 Constant field = fields[i];
313 // TODO(floitsch): share this code with the ListConstant. 448 // TODO(floitsch): share this code with the ListConstant.
314 if (field.isObject()) { 449 if (field.isObject()) {
315 String name = handler.getNameForConstant(entry); 450 String name = handler.getNameForConstant(field);
316 buffer.add("$isolatePrototype.$name"); 451 buffer.add("$isolatePrototype.$name");
317 } else { 452 } else {
318 field.writeJsCode(buffer, handler); 453 field.writeJsCode(buffer, handler);
319 } 454 }
320 } 455 }
321 buffer.add(")"); 456 buffer.add(")");
322 } 457 }
323 458
324 bool operator ==(var otherVar) { 459 bool operator ==(var otherVar) {
325 if (otherVar is !ConstructedConstant) return false; 460 if (otherVar is !ConstructedConstant) return false;
326 ConstructedConstant other = otherVar; 461 ConstructedConstant other = otherVar;
327 if (hashCode() != other.hashCode()) return false; 462 if (hashCode() != other.hashCode()) return false;
328 // TODO(floitsch): verify that the (generic) types are the same. 463 // TODO(floitsch): verify that the (generic) types are the same.
329 if (type.element != other.type.element) return false; 464 if (type.element != other.type.element) return false;
330 if (fields.length != other.fields.length) return false; 465 if (fields.length != other.fields.length) return false;
331 for (int i = 0; i < fields.length; i++) { 466 for (int i = 0; i < fields.length; i++) {
332 if (fields[i] != other.fields[i]) return false; 467 if (fields[i] != other.fields[i]) return false;
333 } 468 }
334 return true; 469 return true;
335 } 470 }
336 471
337 int hashCode() => _hashCode; 472 int hashCode() => _hashCode;
473
474 void addDependencies(List<Constant> list, Set<Constant> seenConstants) {
475 for (Constant constant in fields) {
476 addDependency(constant, list, seenConstants);
477 }
478 }
338 } 479 }
339 480
340 /** 481 /**
341 * The [ConstantHandler] keeps track of compile-time constants, 482 * The [ConstantHandler] keeps track of compile-time constants,
342 * initializations of global and static fields, and default values of 483 * initializations of global and static fields, and default values of
343 * optional parameters. 484 * optional parameters.
344 */ 485 */
345 class ConstantHandler extends CompilerTask { 486 class ConstantHandler extends CompilerTask {
346 // Contains the initial value of fields. Must contain all static and global 487 // Contains the initial value of fields. Must contain all static and global
347 // initializations of used fields. May contain caches for instance fields. 488 // initializations of used fields. May contain caches for instance fields.
(...skipping 111 matching lines...) Expand 10 before | Expand all | Expand 10 after
459 */ 600 */
460 List<VariableElement> getStaticFinalFieldsForEmission() { 601 List<VariableElement> getStaticFinalFieldsForEmission() {
461 return initialVariableValues.getKeys().filter((element) { 602 return initialVariableValues.getKeys().filter((element) {
462 return element.kind == ElementKind.FIELD 603 return element.kind == ElementKind.FIELD
463 && !element.isInstanceMember() 604 && !element.isInstanceMember()
464 && element.modifiers.isFinal(); 605 && element.modifiers.isFinal();
465 }); 606 });
466 } 607 }
467 608
468 List<Constant> getConstantsForEmission() { 609 List<Constant> getConstantsForEmission() {
469 return compiledConstants.getKeys(); 610 // TODO(floitsch): Improve the creation of the dependencies.
611 Set<Constant> seenConstants = new Set<Constant>();
612 List<Constant> result = new List<Constant>();
613 compiledConstants.forEach((Constant key, ignored) {
614 if (seenConstants.contains(key)) return;
615 key.addDependencies(result, seenConstants);
616 assert(!seenConstants.contains(key));
617 seenConstants.add(key);
618 result.add(key);
619 });
620 return result;
470 } 621 }
471 622
472 String getNameForConstant(Constant constant) { 623 String getNameForConstant(Constant constant) {
473 return compiledConstants[constant]; 624 return compiledConstants[constant];
474 } 625 }
475 626
476 StringBuffer writeJsCode(StringBuffer buffer, Constant value) { 627 StringBuffer writeJsCode(StringBuffer buffer, Constant value) {
477 value.writeJsCode(buffer, this); 628 value.writeJsCode(buffer, this);
478 return buffer; 629 return buffer;
479 } 630 }
(...skipping 105 matching lines...) Expand 10 before | Expand all | Expand 10 after
585 Constant visitLiteralDouble(LiteralDouble node) { 736 Constant visitLiteralDouble(LiteralDouble node) {
586 return new DoubleConstant(node.value); 737 return new DoubleConstant(node.value);
587 } 738 }
588 739
589 Constant visitLiteralInt(LiteralInt node) { 740 Constant visitLiteralInt(LiteralInt node) {
590 return new IntConstant(node.value); 741 return new IntConstant(node.value);
591 } 742 }
592 743
593 Constant visitLiteralList(LiteralList node) { 744 Constant visitLiteralList(LiteralList node) {
594 if (!node.isConst()) error(node); 745 if (!node.isConst()) error(node);
595 List arguments = []; 746 List<Constant> arguments = <Constant>[];
596 for (Link<Node> link = node.elements.nodes; 747 for (Link<Node> link = node.elements.nodes;
597 !link.isEmpty(); 748 !link.isEmpty();
598 link = link.tail) { 749 link = link.tail) {
599 arguments.add(evaluate(link.head)); 750 arguments.add(evaluate(link.head));
600 } 751 }
601 // TODO(floitsch): get type from somewhere. 752 // TODO(floitsch): get type from somewhere.
602 Type type = null; 753 Type type = null;
603 return constantHandler.compileListLiteral(node, type, arguments); 754 return constantHandler.compileListLiteral(node, type, arguments);
604 } 755 }
605 756
606 Constant visitLiteralMap(LiteralMap node) { 757 Constant visitLiteralMap(LiteralMap node) {
607 compiler.unimplemented("CompileTimeConstantEvaluator map", node: node); 758 // TODO(floitsch): check for isConst, once the parser adds it into the node.
759 // if (!node.isConst()) error(node);
760 List<StringConstant> keys = <StringConstant>[];
761 List<Constant> values = <Constant>[];
762 bool hasProtoKey = false;
763 for (Link<Node> link = node.entries.nodes;
764 !link.isEmpty();
765 link = link.tail) {
766 LiteralMapEntry entry = link.head;
767 Constant key = evaluate(entry.key);
768 if (!key.isString() ||
769 (entry.key.asLiteralString() === null &&
770 entry.key.asStringInterpolation() === null)) {
ngeoffray 2012/03/10 18:33:55 AFAIK, string interpolation for constants is still
floitsch 2012/03/10 19:58:54 This is in preparation for future changes. Since s
ngeoffray 2012/03/10 22:28:03 I'd prefer that you remove it. I have a strong ave
floitsch 2012/03/10 22:58:22 Done.
771 MessageKind kind = MessageKind.KEY_NOT_A_STRING_LITERAL;
772 // TODO(floitsch): is resolution error the correct error?
773 compiler.reportError(entry.key, new ResolutionError(kind, const []));
774 }
775 // TODO(floitsch): make this faster.
776 StringConstant keyConstant = key;
777 if (keyConstant.value == new LiteralDartString("__proto__")) {
778 hasProtoKey = true;
779 }
780 keys.add(key);
781 values.add(evaluate(entry.value));
782 }
783 if (hasProtoKey) {
784 compiler.unimplemented("visitLiteralMap with __proto__ key",
785 node: node);
786 }
787 // TODO(floitsch): this should be a List<String> type.
788 Type keysType = null;
789 ListConstant keysList = new ListConstant(keysType, keys);
790 constantHandler.registerCompileTimeConstant(keysList);
791 ClassElement classElement =
792 compiler.jsHelperLibrary.find(MapConstant.DART_CLASS);
793 classElement.ensureResolved(compiler);
794 // TODO(floitsch): copy over the generic type.
795 Type type = new SimpleType(classElement.name, classElement);
796 compiler.registerInstantiatedClass(classElement);
797 Constant constant = new MapConstant(type, keysList, values);
798 constantHandler.registerCompileTimeConstant(constant);
799 return constant;
608 } 800 }
609 801
610 Constant visitLiteralNull(LiteralNull node) { 802 Constant visitLiteralNull(LiteralNull node) {
611 return new NullConstant(); 803 return new NullConstant();
612 } 804 }
613 805
614 Constant visitLiteralString(LiteralString node) { 806 Constant visitLiteralString(LiteralString node) {
615 return new StringConstant(node.dartString); 807 return new StringConstant(node.dartString);
616 } 808 }
617 809
(...skipping 144 matching lines...) Expand 10 before | Expand all | Expand 10 after
762 arguments); 954 arguments);
763 } 955 }
764 956
765 error(Node node) { 957 error(Node node) {
766 // TODO(floitsch): get the list of constants that are currently compiled 958 // TODO(floitsch): get the list of constants that are currently compiled
767 // and present some kind of stack-trace. 959 // and present some kind of stack-trace.
768 MessageKind kind = MessageKind.NOT_A_COMPILE_TIME_CONSTANT; 960 MessageKind kind = MessageKind.NOT_A_COMPILE_TIME_CONSTANT;
769 compiler.reportError(node, new CompileTimeConstantError(kind, const [])); 961 compiler.reportError(node, new CompileTimeConstantError(kind, const []));
770 } 962 }
771 } 963 }
OLDNEW
« no previous file with comments | « no previous file | frog/leg/lib/constant_map.dart » ('j') | no next file with comments »

Powered by Google App Engine
This is Rietveld 408576698