| OLD | NEW |
| 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; |
| (...skipping 292 matching lines...) Expand 10 before | Expand all | Expand 10 after Loading... |
| 303 } | 303 } |
| 304 return true; | 304 return true; |
| 305 } | 305 } |
| 306 | 306 |
| 307 int hashCode() => _hashCode; | 307 int hashCode() => _hashCode; |
| 308 | 308 |
| 309 List<Constant> getDependencies() => entries; | 309 List<Constant> getDependencies() => entries; |
| 310 } | 310 } |
| 311 | 311 |
| 312 class MapConstant extends ObjectConstant { | 312 class MapConstant extends ObjectConstant { |
| 313 /** |
| 314 * The [PROTO_PROPERTY] must not be used as normal property in any JavaScript |
| 315 * object. It would change the prototype chain. |
| 316 */ |
| 317 static final String PROTO_PROPERTY = "__proto__"; |
| 318 |
| 313 /** The dart class implementing constant map literals. */ | 319 /** The dart class implementing constant map literals. */ |
| 314 static final SourceString DART_CLASS = const SourceString("ConstantMap"); | 320 static final SourceString DART_CLASS = const SourceString("ConstantMap"); |
| 321 static final SourceString DART_PROTO_CLASS = |
| 322 const SourceString("ConstantProtoMap"); |
| 315 static final SourceString LENGTH_NAME = const SourceString("length"); | 323 static final SourceString LENGTH_NAME = const SourceString("length"); |
| 316 static final SourceString JS_OBJECT_NAME = const SourceString("_jsObject"); | 324 static final SourceString JS_OBJECT_NAME = const SourceString("_jsObject"); |
| 317 static final SourceString KEYS_NAME = const SourceString("_keys"); | 325 static final SourceString KEYS_NAME = const SourceString("_keys"); |
| 326 static final SourceString PROTO_VALUE = const SourceString("_protoValue"); |
| 318 | 327 |
| 319 final ListConstant keys; | 328 final ListConstant keys; |
| 320 final List<Constant> values; | 329 final List<Constant> values; |
| 330 final Constant protoValue; |
| 321 int _hashCode; | 331 int _hashCode; |
| 322 | 332 |
| 323 MapConstant(Type type, this.keys, this.values) : super(type) { | 333 MapConstant(Type type, this.keys, this.values, this.protoValue) |
| 334 : super(type) { |
| 324 // TODO(floitsch): create a better hash. | 335 // TODO(floitsch): create a better hash. |
| 325 int hash = 0; | 336 int hash = 0; |
| 326 for (Constant value in values) hash ^= value.hashCode(); | 337 for (Constant value in values) hash ^= value.hashCode(); |
| 327 _hashCode = hash; | 338 _hashCode = hash; |
| 328 } | 339 } |
| 329 bool isMap() => true; | 340 bool isMap() => true; |
| 330 | 341 |
| 331 void writeJsCode(StringBuffer buffer, ConstantHandler handler) { | 342 void writeJsCode(StringBuffer buffer, ConstantHandler handler) { |
| 332 | 343 |
| 333 void writeJsMap() { | 344 void writeJsMap() { |
| 334 buffer.add("{"); | 345 buffer.add("{"); |
| 346 int valueIndex = 0; |
| 335 for (int i = 0; i < keys.entries.length; i++) { | 347 for (int i = 0; i < keys.entries.length; i++) { |
| 336 if (i != 0) buffer.add(", "); | 348 StringConstant key = keys.entries[i]; |
| 349 if (key.value == const LiteralDartString(PROTO_PROPERTY)) continue; |
| 350 |
| 351 if (valueIndex != 0) buffer.add(", "); |
| 337 | 352 |
| 338 StringConstant key = keys.entries[i]; | |
| 339 key.writeJsCode(buffer, handler); | 353 key.writeJsCode(buffer, handler); |
| 340 buffer.add(": "); | 354 buffer.add(": "); |
| 341 Constant value = values[i]; | 355 Constant value = values[valueIndex++]; |
| 342 value.writeCanonicalizedJsCode(buffer, handler); | 356 value.writeCanonicalizedJsCode(buffer, handler); |
| 343 } | 357 } |
| 344 buffer.add("}"); | 358 buffer.add("}"); |
| 359 if (valueIndex != values.length) { |
| 360 handler.compiler.internalError("Bad value count."); |
| 361 } |
| 345 } | 362 } |
| 346 | 363 |
| 347 void badFieldCountError() { | 364 void badFieldCountError() { |
| 348 handler.compiler.internalError( | 365 handler.compiler.internalError( |
| 349 "Compiler and ConstantMap disagree on number of fields."); | 366 "Compiler and ConstantMap disagree on number of fields."); |
| 350 } | 367 } |
| 351 | 368 |
| 352 ClassElement classElement = type.element; | 369 ClassElement classElement = type.element; |
| 353 buffer.add("new "); | 370 buffer.add("new "); |
| 354 buffer.add(handler.getJsConstructor(classElement)); | 371 buffer.add(handler.getJsConstructor(classElement)); |
| 355 buffer.add("("); | 372 buffer.add("("); |
| 356 // The arguments of the JavaScript constructor for any given Dart class | 373 // The arguments of the JavaScript constructor for any given Dart class |
| 357 // are in the same order as the members of the class element. | 374 // are in the same order as the members of the class element. |
| 358 int emittedArgumentCount = 0; | 375 int emittedArgumentCount = 0; |
| 359 classElement.forEachInstanceField( | 376 classElement.forEachInstanceField( |
| 360 includeBackendMembers: true, | 377 includeBackendMembers: true, |
| 361 includeSuperMembers: true, | 378 includeSuperMembers: true, |
| 362 f: (ClassElement enclosing, Element field) { | 379 f: (ClassElement enclosing, Element field) { |
| 363 if (emittedArgumentCount != 0) buffer.add(", "); | 380 if (emittedArgumentCount != 0) buffer.add(", "); |
| 364 if (field.name == LENGTH_NAME) { | 381 if (field.name == LENGTH_NAME) { |
| 365 buffer.add(keys.entries.length); | 382 buffer.add(keys.entries.length); |
| 366 } else if (field.name == JS_OBJECT_NAME) { | 383 } else if (field.name == JS_OBJECT_NAME) { |
| 367 writeJsMap(); | 384 writeJsMap(); |
| 368 } else if (field.name == KEYS_NAME) { | 385 } else if (field.name == KEYS_NAME) { |
| 369 keys.writeCanonicalizedJsCode(buffer, handler); | 386 keys.writeCanonicalizedJsCode(buffer, handler); |
| 387 } else if (field.name == PROTO_VALUE) { |
| 388 assert(protoValue !== null); |
| 389 protoValue.writeCanonicalizedJsCode(buffer, handler); |
| 370 } else { | 390 } else { |
| 371 badFieldCountError(); | 391 badFieldCountError(); |
| 372 } | 392 } |
| 373 emittedArgumentCount++; | 393 emittedArgumentCount++; |
| 374 }); | 394 }); |
| 375 if (emittedArgumentCount != 3) badFieldCountError(); | 395 if ((protoValue === null && emittedArgumentCount != 3) || |
| 396 (protoValue !== null && emittedArgumentCount != 4)) { |
| 397 badFieldCountError(); |
| 398 } |
| 376 buffer.add(")"); | 399 buffer.add(")"); |
| 377 } | 400 } |
| 378 | 401 |
| 379 bool operator ==(var other) { | 402 bool operator ==(var other) { |
| 380 if (other is !MapConstant) return false; | 403 if (other is !MapConstant) return false; |
| 381 MapConstant otherMap = other; | 404 MapConstant otherMap = other; |
| 382 if (hashCode() != otherMap.hashCode()) return false; | 405 if (hashCode() != otherMap.hashCode()) return false; |
| 383 // TODO(floitsch): verify that the generic types are the same. | 406 // TODO(floitsch): verify that the generic types are the same. |
| 384 if (keys != otherMap.keys) return false; | 407 if (keys != otherMap.keys) return false; |
| 385 for (int i = 0; i < values.length; i++) { | 408 for (int i = 0; i < values.length; i++) { |
| (...skipping 316 matching lines...) Expand 10 before | Expand all | Expand 10 after Loading... |
| 702 // TODO(floitsch): get type from somewhere. | 725 // TODO(floitsch): get type from somewhere. |
| 703 Type type = null; | 726 Type type = null; |
| 704 Constant constant = new ListConstant(type, arguments); | 727 Constant constant = new ListConstant(type, arguments); |
| 705 compiler.constantHandler.registerCompileTimeConstant(constant); | 728 compiler.constantHandler.registerCompileTimeConstant(constant); |
| 706 return constant; | 729 return constant; |
| 707 } | 730 } |
| 708 | 731 |
| 709 Constant visitLiteralMap(LiteralMap node) { | 732 Constant visitLiteralMap(LiteralMap node) { |
| 710 if (!node.isConst()) error(node); | 733 if (!node.isConst()) error(node); |
| 711 List<StringConstant> keys = <StringConstant>[]; | 734 List<StringConstant> keys = <StringConstant>[]; |
| 712 List<Constant> values = <Constant>[]; | 735 Map<StringConstant, Constant> map = new Map<StringConstant, Constant>(); |
| 713 bool hasProtoKey = false; | |
| 714 for (Link<Node> link = node.entries.nodes; | 736 for (Link<Node> link = node.entries.nodes; |
| 715 !link.isEmpty(); | 737 !link.isEmpty(); |
| 716 link = link.tail) { | 738 link = link.tail) { |
| 717 LiteralMapEntry entry = link.head; | 739 LiteralMapEntry entry = link.head; |
| 718 Constant key = evaluate(entry.key); | 740 Constant key = evaluate(entry.key); |
| 719 if (!key.isString() || entry.key.asLiteralString() === null) { | 741 if (!key.isString() || entry.key.asLiteralString() === null) { |
| 720 MessageKind kind = MessageKind.KEY_NOT_A_STRING_LITERAL; | 742 MessageKind kind = MessageKind.KEY_NOT_A_STRING_LITERAL; |
| 721 compiler.reportError(entry.key, new ResolutionError(kind, const [])); | 743 compiler.reportError(entry.key, new ResolutionError(kind, const [])); |
| 722 } | 744 } |
| 723 // TODO(floitsch): make this faster. | |
| 724 StringConstant keyConstant = key; | 745 StringConstant keyConstant = key; |
| 725 if (keyConstant.value == new LiteralDartString("__proto__")) { | 746 if (!map.containsKey(key)) keys.add(key); |
| 726 hasProtoKey = true; | 747 map[key] = evaluate(entry.value); |
| 748 } |
| 749 List<Constant> values = <Constant>[]; |
| 750 Constant protoValue = null; |
| 751 for (StringConstant key in keys) { |
| 752 if (key.value == const LiteralDartString(MapConstant.PROTO_PROPERTY)) { |
| 753 protoValue = map[key]; |
| 754 } else { |
| 755 values.add(map[key]); |
| 727 } | 756 } |
| 728 keys.add(key); | |
| 729 values.add(evaluate(entry.value)); | |
| 730 } | 757 } |
| 731 if (hasProtoKey) { | 758 bool hasProtoKey = (protoValue !== null); |
| 732 compiler.unimplemented("visitLiteralMap with __proto__ key", | |
| 733 node: node); | |
| 734 } | |
| 735 // TODO(floitsch): this should be a List<String> type. | 759 // TODO(floitsch): this should be a List<String> type. |
| 736 Type keysType = null; | 760 Type keysType = null; |
| 737 ListConstant keysList = new ListConstant(keysType, keys); | 761 ListConstant keysList = new ListConstant(keysType, keys); |
| 738 compiler.constantHandler.registerCompileTimeConstant(keysList); | 762 compiler.constantHandler.registerCompileTimeConstant(keysList); |
| 739 ClassElement classElement = | 763 SourceString className = hasProtoKey |
| 740 compiler.jsHelperLibrary.find(MapConstant.DART_CLASS); | 764 ? MapConstant.DART_PROTO_CLASS |
| 765 : MapConstant.DART_CLASS; |
| 766 ClassElement classElement = compiler.jsHelperLibrary.find(className); |
| 741 classElement.ensureResolved(compiler); | 767 classElement.ensureResolved(compiler); |
| 742 // TODO(floitsch): copy over the generic type. | 768 // TODO(floitsch): copy over the generic type. |
| 743 Type type = new SimpleType(classElement.name, classElement); | 769 Type type = new SimpleType(classElement.name, classElement); |
| 744 compiler.registerInstantiatedClass(classElement); | 770 compiler.registerInstantiatedClass(classElement); |
| 745 Constant constant = new MapConstant(type, keysList, values); | 771 Constant constant = new MapConstant(type, keysList, values, protoValue); |
| 746 compiler.constantHandler.registerCompileTimeConstant(constant); | 772 compiler.constantHandler.registerCompileTimeConstant(constant); |
| 747 return constant; | 773 return constant; |
| 748 } | 774 } |
| 749 | 775 |
| 750 Constant visitLiteralNull(LiteralNull node) { | 776 Constant visitLiteralNull(LiteralNull node) { |
| 751 return new NullConstant(); | 777 return new NullConstant(); |
| 752 } | 778 } |
| 753 | 779 |
| 754 Constant visitLiteralString(LiteralString node) { | 780 Constant visitLiteralString(LiteralString node) { |
| 755 return new StringConstant(node.dartString); | 781 return new StringConstant(node.dartString); |
| (...skipping 342 matching lines...) Expand 10 before | Expand all | Expand 10 after Loading... |
| 1098 Constant fieldValue = fieldValues[field]; | 1124 Constant fieldValue = fieldValues[field]; |
| 1099 if (fieldValue === null) { | 1125 if (fieldValue === null) { |
| 1100 // Use the default value. | 1126 // Use the default value. |
| 1101 fieldValue = compiler.compileVariable(field); | 1127 fieldValue = compiler.compileVariable(field); |
| 1102 } | 1128 } |
| 1103 jsNewArguments.add(fieldValue); | 1129 jsNewArguments.add(fieldValue); |
| 1104 }); | 1130 }); |
| 1105 return jsNewArguments; | 1131 return jsNewArguments; |
| 1106 } | 1132 } |
| 1107 } | 1133 } |
| OLD | NEW |