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; |
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 null, a bool, a number or a string. */ | 19 /** Returns true if the constant is null, a bool, a number or a string. */ |
20 bool isPrimitive() => false; | 20 bool isPrimitive() => false; |
21 /** Returns true if the constant is a list, a map or a constructed object. */ | 21 /** Returns true if the constant is a list, a map or a constructed object. */ |
22 bool isObject() => false; | 22 bool isObject() => false; |
23 | 23 |
24 bool isNaN() => false; | 24 bool isNaN() => false; |
25 | 25 |
26 abstract void _writeJsCode(StringBuffer buffer, ConstantHandler handler); | 26 abstract void _writeJsCode(CodeBuffer buffer, ConstantHandler handler); |
27 /** | 27 /** |
28 * Unless the constant can be emitted multiple times (as for numbers and | 28 * Unless the constant can be emitted multiple times (as for numbers and |
29 * strings) adds its canonical name to the buffer. | 29 * strings) adds its canonical name to the buffer. |
30 */ | 30 */ |
31 abstract void _writeCanonicalizedJsCode(StringBuffer buffer, | 31 abstract void _writeCanonicalizedJsCode(CodeBuffer buffer, |
32 ConstantHandler handler); | 32 ConstantHandler handler); |
33 abstract List<Constant> getDependencies(); | 33 abstract List<Constant> getDependencies(); |
34 } | 34 } |
35 | 35 |
36 class PrimitiveConstant extends Constant { | 36 class PrimitiveConstant extends Constant { |
37 abstract get value(); | 37 abstract get value(); |
38 const PrimitiveConstant(); | 38 const PrimitiveConstant(); |
39 bool isPrimitive() => true; | 39 bool isPrimitive() => true; |
40 | 40 |
41 bool operator ==(var other) { | 41 bool operator ==(var other) { |
42 if (other is !PrimitiveConstant) return false; | 42 if (other is !PrimitiveConstant) return false; |
43 PrimitiveConstant otherPrimitive = other; | 43 PrimitiveConstant otherPrimitive = other; |
44 // We use == instead of === so that DartStrings compare correctly. | 44 // We use == instead of === so that DartStrings compare correctly. |
45 return value == otherPrimitive.value; | 45 return value == otherPrimitive.value; |
46 } | 46 } |
47 | 47 |
48 String toString() => value.toString(); | 48 String toString() => value.toString(); |
49 // Primitive constants don't have dependencies. | 49 // Primitive constants don't have dependencies. |
50 List<Constant> getDependencies() => const <Constant>[]; | 50 List<Constant> getDependencies() => const <Constant>[]; |
51 abstract DartString toDartString(); | 51 abstract DartString toDartString(); |
52 | 52 |
53 void _writeCanonicalizedJsCode(StringBuffer buffer, ConstantHandler handler) { | 53 void _writeCanonicalizedJsCode(CodeBuffer buffer, ConstantHandler handler) { |
54 _writeJsCode(buffer, handler); | 54 _writeJsCode(buffer, handler); |
55 } | 55 } |
56 } | 56 } |
57 | 57 |
58 class NullConstant extends PrimitiveConstant { | 58 class NullConstant extends PrimitiveConstant { |
59 /** The value a Dart null is compiled to in JavaScript. */ | 59 /** The value a Dart null is compiled to in JavaScript. */ |
60 static final String JsNull = "null"; | 60 static final String JsNull = "null"; |
61 | 61 |
62 factory NullConstant() => const NullConstant._internal(); | 62 factory NullConstant() => const NullConstant._internal(); |
63 const NullConstant._internal(); | 63 const NullConstant._internal(); |
64 bool isNull() => true; | 64 bool isNull() => true; |
65 get value() => null; | 65 get value() => null; |
66 | 66 |
67 void _writeJsCode(StringBuffer buffer, ConstantHandler handler) { | 67 void _writeJsCode(CodeBuffer buffer, ConstantHandler handler) { |
68 buffer.add(JsNull); | 68 buffer.add(JsNull); |
69 } | 69 } |
70 | 70 |
71 // The magic constant has no meaning. It is just a random value. | 71 // The magic constant has no meaning. It is just a random value. |
72 int hashCode() => 785965825; | 72 int hashCode() => 785965825; |
73 DartString toDartString() => const LiteralDartString("null"); | 73 DartString toDartString() => const LiteralDartString("null"); |
74 } | 74 } |
75 | 75 |
76 class NumConstant extends PrimitiveConstant { | 76 class NumConstant extends PrimitiveConstant { |
77 abstract num get value(); | 77 abstract num get value(); |
(...skipping 17 matching lines...) Expand all Loading... |
95 case 9: return const IntConstant._internal(9); | 95 case 9: return const IntConstant._internal(9); |
96 case 10: return const IntConstant._internal(10); | 96 case 10: return const IntConstant._internal(10); |
97 case -1: return const IntConstant._internal(-1); | 97 case -1: return const IntConstant._internal(-1); |
98 case -2: return const IntConstant._internal(-2); | 98 case -2: return const IntConstant._internal(-2); |
99 default: return new IntConstant._internal(value); | 99 default: return new IntConstant._internal(value); |
100 } | 100 } |
101 } | 101 } |
102 const IntConstant._internal(this.value); | 102 const IntConstant._internal(this.value); |
103 bool isInt() => true; | 103 bool isInt() => true; |
104 | 104 |
105 void _writeJsCode(StringBuffer buffer, ConstantHandler handler) { | 105 void _writeJsCode(CodeBuffer buffer, ConstantHandler handler) { |
106 buffer.add("$value"); | 106 buffer.add("$value"); |
107 } | 107 } |
108 | 108 |
109 // We have to override the equality operator so that ints and doubles are | 109 // We have to override the equality operator so that ints and doubles are |
110 // treated as separate constants. | 110 // treated as separate constants. |
111 // The is [:!IntConstant:] check at the beginning of the function makes sure | 111 // The is [:!IntConstant:] check at the beginning of the function makes sure |
112 // that we compare only equal to integer constants. | 112 // that we compare only equal to integer constants. |
113 bool operator ==(var other) { | 113 bool operator ==(var other) { |
114 if (other is !IntConstant) return false; | 114 if (other is !IntConstant) return false; |
115 IntConstant otherInt = other; | 115 IntConstant otherInt = other; |
(...skipping 18 matching lines...) Expand all Loading... |
134 } else if (value == 1.0) { | 134 } else if (value == 1.0) { |
135 return const DoubleConstant._internal(1.0); | 135 return const DoubleConstant._internal(1.0); |
136 } else { | 136 } else { |
137 return new DoubleConstant._internal(value); | 137 return new DoubleConstant._internal(value); |
138 } | 138 } |
139 } | 139 } |
140 const DoubleConstant._internal(this.value); | 140 const DoubleConstant._internal(this.value); |
141 bool isDouble() => true; | 141 bool isDouble() => true; |
142 bool isNaN() => value.isNaN(); | 142 bool isNaN() => value.isNaN(); |
143 | 143 |
144 void _writeJsCode(StringBuffer buffer, ConstantHandler handler) { | 144 void _writeJsCode(CodeBuffer buffer, ConstantHandler handler) { |
145 if (value.isNaN()) { | 145 if (value.isNaN()) { |
146 buffer.add("(0/0)"); | 146 buffer.add("(0/0)"); |
147 } else if (value == double.INFINITY) { | 147 } else if (value == double.INFINITY) { |
148 buffer.add("(1/0)"); | 148 buffer.add("(1/0)"); |
149 } else if (value == -double.INFINITY) { | 149 } else if (value == -double.INFINITY) { |
150 buffer.add("(-1/0)"); | 150 buffer.add("(-1/0)"); |
151 } else { | 151 } else { |
152 buffer.add("$value"); | 152 buffer.add("$value"); |
153 } | 153 } |
154 } | 154 } |
(...skipping 30 matching lines...) Expand all Loading... |
185 abstract BoolConstant negate(); | 185 abstract BoolConstant negate(); |
186 } | 186 } |
187 | 187 |
188 class TrueConstant extends BoolConstant { | 188 class TrueConstant extends BoolConstant { |
189 final bool value = true; | 189 final bool value = true; |
190 | 190 |
191 factory TrueConstant() => const TrueConstant._internal(); | 191 factory TrueConstant() => const TrueConstant._internal(); |
192 const TrueConstant._internal() : super._internal(); | 192 const TrueConstant._internal() : super._internal(); |
193 bool isTrue() => true; | 193 bool isTrue() => true; |
194 | 194 |
195 void _writeJsCode(StringBuffer buffer, ConstantHandler handler) { | 195 void _writeJsCode(CodeBuffer buffer, ConstantHandler handler) { |
196 buffer.add("true"); | 196 buffer.add("true"); |
197 } | 197 } |
198 | 198 |
199 FalseConstant negate() => new FalseConstant(); | 199 FalseConstant negate() => new FalseConstant(); |
200 | 200 |
201 bool operator ==(var other) => this === other; | 201 bool operator ==(var other) => this === other; |
202 // The magic constant is just a random value. It does not have any | 202 // The magic constant is just a random value. It does not have any |
203 // significance. | 203 // significance. |
204 int hashCode() => 499; | 204 int hashCode() => 499; |
205 DartString toDartString() => const LiteralDartString("true"); | 205 DartString toDartString() => const LiteralDartString("true"); |
206 } | 206 } |
207 | 207 |
208 class FalseConstant extends BoolConstant { | 208 class FalseConstant extends BoolConstant { |
209 final bool value = false; | 209 final bool value = false; |
210 | 210 |
211 factory FalseConstant() => const FalseConstant._internal(); | 211 factory FalseConstant() => const FalseConstant._internal(); |
212 const FalseConstant._internal() : super._internal(); | 212 const FalseConstant._internal() : super._internal(); |
213 bool isFalse() => true; | 213 bool isFalse() => true; |
214 | 214 |
215 void _writeJsCode(StringBuffer buffer, ConstantHandler handler) { | 215 void _writeJsCode(CodeBuffer buffer, ConstantHandler handler) { |
216 buffer.add("false"); | 216 buffer.add("false"); |
217 } | 217 } |
218 | 218 |
219 TrueConstant negate() => new TrueConstant(); | 219 TrueConstant negate() => new TrueConstant(); |
220 | 220 |
221 bool operator ==(var other) => this === other; | 221 bool operator ==(var other) => this === other; |
222 // The magic constant is just a random value. It does not have any | 222 // The magic constant is just a random value. It does not have any |
223 // significance. | 223 // significance. |
224 int hashCode() => 536555975; | 224 int hashCode() => 536555975; |
225 DartString toDartString() => const LiteralDartString("false"); | 225 DartString toDartString() => const LiteralDartString("false"); |
226 } | 226 } |
227 | 227 |
228 class StringConstant extends PrimitiveConstant { | 228 class StringConstant extends PrimitiveConstant { |
229 final DartString value; | 229 final DartString value; |
230 int _hashCode; | 230 int _hashCode; |
231 final Node node; | 231 final Node node; |
232 | 232 |
233 StringConstant(this.value, this.node) { | 233 StringConstant(this.value, this.node) { |
234 // TODO(floitsch): cache StringConstants. | 234 // TODO(floitsch): cache StringConstants. |
235 // TODO(floitsch): compute hashcode without calling toString() on the | 235 // TODO(floitsch): compute hashcode without calling toString() on the |
236 // DartString. | 236 // DartString. |
237 _hashCode = value.slowToString().hashCode(); | 237 _hashCode = value.slowToString().hashCode(); |
238 } | 238 } |
239 bool isString() => true; | 239 bool isString() => true; |
240 | 240 |
241 void _writeJsCode(StringBuffer buffer, ConstantHandler handler) { | 241 void _writeJsCode(CodeBuffer buffer, ConstantHandler handler) { |
242 buffer.add("'"); | 242 buffer.add("'"); |
243 ConstantHandler.writeEscapedString(value, buffer, (reason) { | 243 ConstantHandler.writeEscapedString(value, buffer, (reason) { |
244 handler.compiler.reportError(node, reason); | 244 handler.compiler.reportError(node, reason); |
245 }); | 245 }); |
246 buffer.add("'"); | 246 buffer.add("'"); |
247 } | 247 } |
248 | 248 |
249 bool operator ==(var other) { | 249 bool operator ==(var other) { |
250 if (other is !StringConstant) return false; | 250 if (other is !StringConstant) return false; |
251 StringConstant otherString = other; | 251 StringConstant otherString = other; |
252 return (_hashCode == otherString._hashCode) && (value == otherString.value); | 252 return (_hashCode == otherString._hashCode) && (value == otherString.value); |
253 } | 253 } |
254 | 254 |
255 int hashCode() => _hashCode; | 255 int hashCode() => _hashCode; |
256 DartString toDartString() => value; | 256 DartString toDartString() => value; |
257 int get length() => value.length; | 257 int get length() => value.length; |
258 } | 258 } |
259 | 259 |
260 class ObjectConstant extends Constant { | 260 class ObjectConstant extends Constant { |
261 final Type type; | 261 final Type type; |
262 | 262 |
263 ObjectConstant(this.type); | 263 ObjectConstant(this.type); |
264 bool isObject() => true; | 264 bool isObject() => true; |
265 | 265 |
266 // TODO(1603): The class should be marked as abstract, but the VM doesn't | 266 // TODO(1603): The class should be marked as abstract, but the VM doesn't |
267 // currently allow this. | 267 // currently allow this. |
268 abstract int hashCode(); | 268 abstract int hashCode(); |
269 | 269 |
270 void _writeCanonicalizedJsCode(StringBuffer buffer, ConstantHandler handler) { | 270 void _writeCanonicalizedJsCode(CodeBuffer buffer, ConstantHandler handler) { |
271 String name = handler.getNameForConstant(this); | 271 String name = handler.getNameForConstant(this); |
272 buffer.add(handler.compiler.namer.isolatePropertiesAccessForConstant(name)); | 272 buffer.add(handler.compiler.namer.isolatePropertiesAccessForConstant(name)); |
273 } | 273 } |
274 } | 274 } |
275 | 275 |
276 class ListConstant extends ObjectConstant { | 276 class ListConstant extends ObjectConstant { |
277 final List<Constant> entries; | 277 final List<Constant> entries; |
278 int _hashCode; | 278 int _hashCode; |
279 | 279 |
280 ListConstant(Type type, this.entries) : super(type) { | 280 ListConstant(Type type, this.entries) : super(type) { |
281 // TODO(floitsch): create a better hash. | 281 // TODO(floitsch): create a better hash. |
282 int hash = 0; | 282 int hash = 0; |
283 for (Constant input in entries) hash ^= input.hashCode(); | 283 for (Constant input in entries) hash ^= input.hashCode(); |
284 _hashCode = hash; | 284 _hashCode = hash; |
285 } | 285 } |
286 bool isList() => true; | 286 bool isList() => true; |
287 | 287 |
288 void _writeJsCode(StringBuffer buffer, ConstantHandler handler) { | 288 void _writeJsCode(CodeBuffer buffer, ConstantHandler handler) { |
289 // TODO(floitsch): we should not need to go through the compiler to make | 289 // TODO(floitsch): we should not need to go through the compiler to make |
290 // the list constant. | 290 // the list constant. |
291 buffer.add("${handler.compiler.namer.ISOLATE}.makeConstantList"); | 291 buffer.add("${handler.compiler.namer.ISOLATE}.makeConstantList"); |
292 buffer.add("(["); | 292 buffer.add("(["); |
293 for (int i = 0; i < entries.length; i++) { | 293 for (int i = 0; i < entries.length; i++) { |
294 if (i != 0) buffer.add(", "); | 294 if (i != 0) buffer.add(", "); |
295 Constant entry = entries[i]; | 295 Constant entry = entries[i]; |
296 handler.writeConstant(buffer, entry); | 296 handler.writeConstant(buffer, entry); |
297 } | 297 } |
298 buffer.add("])"); | 298 buffer.add("])"); |
(...skipping 41 matching lines...) Expand 10 before | Expand all | Expand 10 after Loading... |
340 | 340 |
341 MapConstant(Type type, this.keys, this.values, this.protoValue) | 341 MapConstant(Type type, this.keys, this.values, this.protoValue) |
342 : super(type) { | 342 : super(type) { |
343 // TODO(floitsch): create a better hash. | 343 // TODO(floitsch): create a better hash. |
344 int hash = 0; | 344 int hash = 0; |
345 for (Constant value in values) hash ^= value.hashCode(); | 345 for (Constant value in values) hash ^= value.hashCode(); |
346 _hashCode = hash; | 346 _hashCode = hash; |
347 } | 347 } |
348 bool isMap() => true; | 348 bool isMap() => true; |
349 | 349 |
350 void _writeJsCode(StringBuffer buffer, ConstantHandler handler) { | 350 void _writeJsCode(CodeBuffer buffer, ConstantHandler handler) { |
351 | 351 |
352 void writeJsMap() { | 352 void writeJsMap() { |
353 buffer.add("{"); | 353 buffer.add("{"); |
354 int valueIndex = 0; | 354 int valueIndex = 0; |
355 for (int i = 0; i < keys.entries.length; i++) { | 355 for (int i = 0; i < keys.entries.length; i++) { |
356 StringConstant key = keys.entries[i]; | 356 StringConstant key = keys.entries[i]; |
357 if (key.value == const LiteralDartString(PROTO_PROPERTY)) continue; | 357 if (key.value == const LiteralDartString(PROTO_PROPERTY)) continue; |
358 | 358 |
359 if (valueIndex != 0) buffer.add(", "); | 359 if (valueIndex != 0) buffer.add(", "); |
360 | 360 |
(...skipping 78 matching lines...) Expand 10 before | Expand all | Expand 10 after Loading... |
439 // TODO(floitsch): create a better hash. | 439 // TODO(floitsch): create a better hash. |
440 int hash = 0; | 440 int hash = 0; |
441 for (Constant field in fields) { | 441 for (Constant field in fields) { |
442 hash ^= field.hashCode(); | 442 hash ^= field.hashCode(); |
443 } | 443 } |
444 hash ^= type.element.hashCode(); | 444 hash ^= type.element.hashCode(); |
445 _hashCode = hash; | 445 _hashCode = hash; |
446 } | 446 } |
447 bool isConstructedObject() => true; | 447 bool isConstructedObject() => true; |
448 | 448 |
449 void _writeJsCode(StringBuffer buffer, ConstantHandler handler) { | 449 void _writeJsCode(CodeBuffer buffer, ConstantHandler handler) { |
450 buffer.add("new "); | 450 buffer.add("new "); |
451 buffer.add(handler.getJsConstructor(type.element)); | 451 buffer.add(handler.getJsConstructor(type.element)); |
452 buffer.add("("); | 452 buffer.add("("); |
453 for (int i = 0; i < fields.length; i++) { | 453 for (int i = 0; i < fields.length; i++) { |
454 if (i != 0) buffer.add(", "); | 454 if (i != 0) buffer.add(", "); |
455 Constant field = fields[i]; | 455 Constant field = fields[i]; |
456 handler.writeConstant(buffer, field); | 456 handler.writeConstant(buffer, field); |
457 } | 457 } |
458 buffer.add(")"); | 458 buffer.add(")"); |
459 } | 459 } |
(...skipping 166 matching lines...) Expand 10 before | Expand all | Expand 10 after Loading... |
626 | 626 |
627 compiledConstants.forEach((Constant key, ignored) => addConstant(key)); | 627 compiledConstants.forEach((Constant key, ignored) => addConstant(key)); |
628 return result; | 628 return result; |
629 } | 629 } |
630 | 630 |
631 String getNameForConstant(Constant constant) { | 631 String getNameForConstant(Constant constant) { |
632 return compiledConstants[constant]; | 632 return compiledConstants[constant]; |
633 } | 633 } |
634 | 634 |
635 /** This function writes the constant in non-canonicalized form. */ | 635 /** This function writes the constant in non-canonicalized form. */ |
636 StringBuffer writeJsCode(StringBuffer buffer, Constant value) { | 636 CodeBuffer writeJsCode(CodeBuffer buffer, Constant value) { |
637 value._writeJsCode(buffer, this); | 637 value._writeJsCode(buffer, this); |
638 return buffer; | 638 return buffer; |
639 } | 639 } |
640 | 640 |
641 StringBuffer writeConstant(StringBuffer buffer, Constant value) { | 641 CodeBuffer writeConstant(CodeBuffer buffer, Constant value) { |
642 value._writeCanonicalizedJsCode(buffer, this); | 642 value._writeCanonicalizedJsCode(buffer, this); |
643 return buffer; | 643 return buffer; |
644 } | 644 } |
645 | 645 |
646 StringBuffer writeJsCodeForVariable(StringBuffer buffer, | 646 CodeBuffer writeJsCodeForVariable(CodeBuffer buffer, |
647 VariableElement element) { | 647 VariableElement element) { |
648 if (!initialVariableValues.containsKey(element)) { | 648 if (!initialVariableValues.containsKey(element)) { |
649 compiler.internalError("No initial value for given element", | 649 compiler.internalError("No initial value for given element", |
650 element: element); | 650 element: element); |
651 } | 651 } |
652 Constant constant = initialVariableValues[element]; | 652 Constant constant = initialVariableValues[element]; |
653 writeConstant(buffer, constant); | 653 writeConstant(buffer, constant); |
654 return buffer; | 654 return buffer; |
655 } | 655 } |
656 | 656 |
657 /** | 657 /** |
658 * Write the contents of the quoted string to a [StringBuffer] in | 658 * Write the contents of the quoted string to a [CodeBuffer] in |
659 * a form that is valid as JavaScript string literal content. | 659 * a form that is valid as JavaScript string literal content. |
660 * The string is assumed quoted by single quote characters. | 660 * The string is assumed quoted by single quote characters. |
661 */ | 661 */ |
662 static void writeEscapedString(DartString string, | 662 static void writeEscapedString(DartString string, |
663 StringBuffer buffer, | 663 CodeBuffer buffer, |
664 void cancel(String reason)) { | 664 void cancel(String reason)) { |
665 Iterator<int> iterator = string.iterator(); | 665 Iterator<int> iterator = string.iterator(); |
666 while (iterator.hasNext()) { | 666 while (iterator.hasNext()) { |
667 int code = iterator.next(); | 667 int code = iterator.next(); |
668 if (code === $SQ) { | 668 if (code === $SQ) { |
669 buffer.add(@"\'"); | 669 buffer.add(@"\'"); |
670 } else if (code === $LF) { | 670 } else if (code === $LF) { |
671 buffer.add(@'\n'); | 671 buffer.add(@'\n'); |
672 } else if (code === $CR) { | 672 } else if (code === $CR) { |
673 buffer.add(@'\r'); | 673 buffer.add(@'\r'); |
(...skipping 492 matching lines...) Expand 10 before | Expand all | Expand 10 after Loading... |
1166 Constant fieldValue = fieldValues[field]; | 1166 Constant fieldValue = fieldValues[field]; |
1167 if (fieldValue === null) { | 1167 if (fieldValue === null) { |
1168 // Use the default value. | 1168 // Use the default value. |
1169 fieldValue = compiler.compileVariable(field); | 1169 fieldValue = compiler.compileVariable(field); |
1170 } | 1170 } |
1171 jsNewArguments.add(fieldValue); | 1171 jsNewArguments.add(fieldValue); |
1172 }); | 1172 }); |
1173 return jsNewArguments; | 1173 return jsNewArguments; |
1174 } | 1174 } |
1175 } | 1175 } |
OLD | NEW |