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 interface ConstantVisitor<R> { | |
6 R visitSentinel(SentinelConstant constant); | |
7 R visitFunction(FunctionConstant constant); | |
8 R visitNull(NullConstant constant); | |
9 R visitInt(IntConstant constant); | |
10 R visitDouble(DoubleConstant constant); | |
11 R visitTrue(TrueConstant constant); | |
12 R visitFalse(FalseConstant constant); | |
13 R visitString(StringConstant constant); | |
14 R visitList(ListConstant constant); | |
15 R visitMap(MapConstant constant); | |
16 R visitConstructed(ConstructedConstant constant); | |
17 } | |
18 | |
19 class Constant implements Hashable { | 5 class Constant implements Hashable { |
20 const Constant(); | 6 const Constant(); |
21 | 7 |
22 bool isNull() => false; | 8 bool isNull() => false; |
23 bool isBool() => false; | 9 bool isBool() => false; |
24 bool isTrue() => false; | 10 bool isTrue() => false; |
25 bool isFalse() => false; | 11 bool isFalse() => false; |
26 bool isInt() => false; | 12 bool isInt() => false; |
27 bool isDouble() => false; | 13 bool isDouble() => false; |
28 bool isNum() => false; | 14 bool isNum() => false; |
29 bool isString() => false; | 15 bool isString() => false; |
30 bool isList() => false; | 16 bool isList() => false; |
31 bool isMap() => false; | 17 bool isMap() => false; |
32 bool isConstructedObject() => false; | 18 bool isConstructedObject() => false; |
33 bool isFunction() => false; | 19 bool isFunction() => false; |
34 /** Returns true if the constant is null, a bool, a number or a string. */ | 20 /** Returns true if the constant is null, a bool, a number or a string. */ |
35 bool isPrimitive() => false; | 21 bool isPrimitive() => false; |
36 /** Returns true if the constant is a list, a map or a constructed object. */ | 22 /** Returns true if the constant is a list, a map or a constructed object. */ |
37 bool isObject() => false; | 23 bool isObject() => false; |
38 bool isSentinel() => false; | 24 bool isSentinel() => false; |
39 | 25 |
40 bool isNaN() => false; | 26 bool isNaN() => false; |
41 bool isMinusZero() => false; | 27 bool isMinusZero() => false; |
42 | 28 |
| 29 abstract void _writeJsCode(CodeBuffer buffer, ConstantHandler handler); |
| 30 /** |
| 31 * Unless the constant can be emitted multiple times (as for numbers and |
| 32 * strings) adds its canonical name to the buffer. |
| 33 */ |
| 34 abstract void _writeCanonicalizedJsCode(CodeBuffer buffer, |
| 35 ConstantHandler handler); |
43 abstract List<Constant> getDependencies(); | 36 abstract List<Constant> getDependencies(); |
44 | |
45 abstract accept(ConstantVisitor); | |
46 } | 37 } |
47 | 38 |
48 class SentinelConstant extends Constant { | 39 class SentinelConstant extends Constant { |
49 const SentinelConstant(); | 40 const SentinelConstant(); |
50 static final SENTINEL = const SentinelConstant(); | 41 static final SENTINEL = const SentinelConstant(); |
51 | 42 |
| 43 void _writeJsCode(CodeBuffer buffer, ConstantHandler handler) { |
| 44 handler.compiler.internalError( |
| 45 "The parameter sentinel constant does not need specific JS code"); |
| 46 } |
| 47 |
| 48 void _writeCanonicalizedJsCode(CodeBuffer buffer, ConstantHandler handler) { |
| 49 buffer.add(handler.compiler.namer.CURRENT_ISOLATE); |
| 50 } |
| 51 |
52 List<Constant> getDependencies() => const <Constant>[]; | 52 List<Constant> getDependencies() => const <Constant>[]; |
53 | 53 |
54 // Just use a random value. | 54 // Just use a randome value. |
55 int hashCode() => 24297418; | 55 int hashCode() => 926429784158; |
56 | 56 |
57 bool isSentinel() => true; | 57 bool isSentinel() => true; |
58 | |
59 accept(ConstantVisitor visitor) => visitor.visitSentinel(this); | |
60 } | 58 } |
61 | 59 |
62 class FunctionConstant extends Constant { | 60 class FunctionConstant extends Constant { |
63 Element element; | 61 Element element; |
64 | 62 |
65 FunctionConstant(this.element); | 63 FunctionConstant(this.element); |
66 | 64 |
67 bool isFunction() => true; | 65 bool isFunction() => true; |
68 | 66 |
69 bool operator ==(var other) { | 67 bool operator ==(var other) { |
70 if (other is !FunctionConstant) return false; | 68 if (other is !FunctionConstant) return false; |
71 return other.element === element; | 69 return other.element === element; |
72 } | 70 } |
73 | 71 |
74 String toString() => element.toString(); | 72 String toString() => element.toString(); |
75 List<Constant> getDependencies() => const <Constant>[]; | 73 List<Constant> getDependencies() => const <Constant>[]; |
76 DartString toDartString() { | 74 DartString toDartString() { |
77 return new DartString.literal(element.name.slowToString()); | 75 return new DartString.literal(element.name.slowToString()); |
78 } | 76 } |
79 | 77 |
| 78 void _writeJsCode(CodeBuffer buffer, ConstantHandler handler) { |
| 79 handler.compiler.internalError( |
| 80 "A constant function does not need specific JS code"); |
| 81 } |
| 82 |
| 83 void _writeCanonicalizedJsCode(CodeBuffer buffer, ConstantHandler handler) { |
| 84 buffer.add(handler.compiler.namer.isolatePropertiesAccess(element)); |
| 85 } |
| 86 |
80 int hashCode() => (17 * element.hashCode()) & 0x7fffffff; | 87 int hashCode() => (17 * element.hashCode()) & 0x7fffffff; |
81 | |
82 accept(ConstantVisitor visitor) => visitor.visitFunction(this); | |
83 } | 88 } |
84 | 89 |
85 class PrimitiveConstant extends Constant { | 90 class PrimitiveConstant extends Constant { |
86 abstract get value; | 91 abstract get value; |
87 const PrimitiveConstant(); | 92 const PrimitiveConstant(); |
88 bool isPrimitive() => true; | 93 bool isPrimitive() => true; |
89 | 94 |
90 bool operator ==(var other) { | 95 bool operator ==(var other) { |
91 if (other is !PrimitiveConstant) return false; | 96 if (other is !PrimitiveConstant) return false; |
92 PrimitiveConstant otherPrimitive = other; | 97 PrimitiveConstant otherPrimitive = other; |
93 // We use == instead of === so that DartStrings compare correctly. | 98 // We use == instead of === so that DartStrings compare correctly. |
94 return value == otherPrimitive.value; | 99 return value == otherPrimitive.value; |
95 } | 100 } |
96 | 101 |
97 String toString() => value.toString(); | 102 String toString() => value.toString(); |
98 // Primitive constants don't have dependencies. | 103 // Primitive constants don't have dependencies. |
99 List<Constant> getDependencies() => const <Constant>[]; | 104 List<Constant> getDependencies() => const <Constant>[]; |
100 abstract DartString toDartString(); | 105 abstract DartString toDartString(); |
| 106 |
| 107 void _writeCanonicalizedJsCode(CodeBuffer buffer, ConstantHandler handler) { |
| 108 _writeJsCode(buffer, handler); |
| 109 } |
101 } | 110 } |
102 | 111 |
103 class NullConstant extends PrimitiveConstant { | 112 class NullConstant extends PrimitiveConstant { |
104 /** The value a Dart null is compiled to in JavaScript. */ | 113 /** The value a Dart null is compiled to in JavaScript. */ |
105 static const String JsNull = "null"; | 114 static const String JsNull = "null"; |
106 | 115 |
107 factory NullConstant() => const NullConstant._internal(); | 116 factory NullConstant() => const NullConstant._internal(); |
108 const NullConstant._internal(); | 117 const NullConstant._internal(); |
109 bool isNull() => true; | 118 bool isNull() => true; |
110 get value => null; | 119 get value => null; |
111 | 120 |
112 void _writeJsCode(CodeBuffer buffer, ConstantHandler handler) { | 121 void _writeJsCode(CodeBuffer buffer, ConstantHandler handler) { |
113 buffer.add(JsNull); | 122 buffer.add(JsNull); |
114 } | 123 } |
115 | 124 |
116 // The magic constant has no meaning. It is just a random value. | 125 // The magic constant has no meaning. It is just a random value. |
117 int hashCode() => 785965825; | 126 int hashCode() => 785965825; |
118 DartString toDartString() => const LiteralDartString("null"); | 127 DartString toDartString() => const LiteralDartString("null"); |
119 | |
120 accept(ConstantVisitor visitor) => visitor.visitNull(this); | |
121 } | 128 } |
122 | 129 |
123 class NumConstant extends PrimitiveConstant { | 130 class NumConstant extends PrimitiveConstant { |
124 abstract num get value; | 131 abstract num get value; |
125 const NumConstant(); | 132 const NumConstant(); |
126 bool isNum() => true; | 133 bool isNum() => true; |
127 } | 134 } |
128 | 135 |
129 class IntConstant extends NumConstant { | 136 class IntConstant extends NumConstant { |
130 final int value; | 137 final int value; |
(...skipping 11 matching lines...) Expand all Loading... |
142 case 9: return const IntConstant._internal(9); | 149 case 9: return const IntConstant._internal(9); |
143 case 10: return const IntConstant._internal(10); | 150 case 10: return const IntConstant._internal(10); |
144 case -1: return const IntConstant._internal(-1); | 151 case -1: return const IntConstant._internal(-1); |
145 case -2: return const IntConstant._internal(-2); | 152 case -2: return const IntConstant._internal(-2); |
146 default: return new IntConstant._internal(value); | 153 default: return new IntConstant._internal(value); |
147 } | 154 } |
148 } | 155 } |
149 const IntConstant._internal(this.value); | 156 const IntConstant._internal(this.value); |
150 bool isInt() => true; | 157 bool isInt() => true; |
151 | 158 |
| 159 void _writeJsCode(CodeBuffer buffer, ConstantHandler handler) { |
| 160 buffer.add("$value"); |
| 161 } |
| 162 |
152 // We have to override the equality operator so that ints and doubles are | 163 // We have to override the equality operator so that ints and doubles are |
153 // treated as separate constants. | 164 // treated as separate constants. |
154 // The is [:!IntConstant:] check at the beginning of the function makes sure | 165 // The is [:!IntConstant:] check at the beginning of the function makes sure |
155 // that we compare only equal to integer constants. | 166 // that we compare only equal to integer constants. |
156 bool operator ==(var other) { | 167 bool operator ==(var other) { |
157 if (other is !IntConstant) return false; | 168 if (other is !IntConstant) return false; |
158 IntConstant otherInt = other; | 169 IntConstant otherInt = other; |
159 return value == otherInt.value; | 170 return value == otherInt.value; |
160 } | 171 } |
161 | 172 |
162 int hashCode() => value.hashCode(); | 173 int hashCode() => value.hashCode(); |
163 DartString toDartString() => new DartString.literal(value.toString()); | 174 DartString toDartString() => new DartString.literal(value.toString()); |
164 | |
165 accept(ConstantVisitor visitor) => visitor.visitInt(this); | |
166 } | 175 } |
167 | 176 |
168 class DoubleConstant extends NumConstant { | 177 class DoubleConstant extends NumConstant { |
169 final double value; | 178 final double value; |
170 factory DoubleConstant(double value) { | 179 factory DoubleConstant(double value) { |
171 if (value.isNaN()) { | 180 if (value.isNaN()) { |
172 return const DoubleConstant._internal(double.NAN); | 181 return const DoubleConstant._internal(double.NAN); |
173 } else if (value == double.INFINITY) { | 182 } else if (value == double.INFINITY) { |
174 return const DoubleConstant._internal(double.INFINITY); | 183 return const DoubleConstant._internal(double.INFINITY); |
175 } else if (value == -double.INFINITY) { | 184 } else if (value == -double.INFINITY) { |
176 return const DoubleConstant._internal(-double.INFINITY); | 185 return const DoubleConstant._internal(-double.INFINITY); |
177 } else if (value == 0.0 && !value.isNegative()) { | 186 } else if (value == 0.0 && !value.isNegative()) { |
178 return const DoubleConstant._internal(0.0); | 187 return const DoubleConstant._internal(0.0); |
179 } else if (value == 1.0) { | 188 } else if (value == 1.0) { |
180 return const DoubleConstant._internal(1.0); | 189 return const DoubleConstant._internal(1.0); |
181 } else { | 190 } else { |
182 return new DoubleConstant._internal(value); | 191 return new DoubleConstant._internal(value); |
183 } | 192 } |
184 } | 193 } |
185 const DoubleConstant._internal(this.value); | 194 const DoubleConstant._internal(this.value); |
186 bool isDouble() => true; | 195 bool isDouble() => true; |
187 bool isNaN() => value.isNaN(); | 196 bool isNaN() => value.isNaN(); |
188 // We need to check for the negative sign since -0.0 == 0.0. | 197 // We need to check for the negative sign since -0.0 == 0.0. |
189 bool isMinusZero() => value == 0.0 && value.isNegative(); | 198 bool isMinusZero() => value == 0.0 && value.isNegative(); |
190 | 199 |
| 200 void _writeJsCode(CodeBuffer buffer, ConstantHandler handler) { |
| 201 if (value.isNaN()) { |
| 202 buffer.add("(0/0)"); |
| 203 } else if (value == double.INFINITY) { |
| 204 buffer.add("(1/0)"); |
| 205 } else if (value == -double.INFINITY) { |
| 206 buffer.add("(-1/0)"); |
| 207 } else { |
| 208 buffer.add("$value"); |
| 209 } |
| 210 } |
| 211 |
191 bool operator ==(var other) { | 212 bool operator ==(var other) { |
192 if (other is !DoubleConstant) return false; | 213 if (other is !DoubleConstant) return false; |
193 DoubleConstant otherDouble = other; | 214 DoubleConstant otherDouble = other; |
194 double otherValue = otherDouble.value; | 215 double otherValue = otherDouble.value; |
195 if (value == 0.0 && otherValue == 0.0) { | 216 if (value == 0.0 && otherValue == 0.0) { |
196 return value.isNegative() == otherValue.isNegative(); | 217 return value.isNegative() == otherValue.isNegative(); |
197 } else if (value.isNaN()) { | 218 } else if (value.isNaN()) { |
198 return otherValue.isNaN(); | 219 return otherValue.isNaN(); |
199 } else { | 220 } else { |
200 return value == otherValue; | 221 return value == otherValue; |
201 } | 222 } |
202 } | 223 } |
203 | 224 |
204 int hashCode() => value.hashCode(); | 225 int hashCode() => value.hashCode(); |
205 DartString toDartString() => new DartString.literal(value.toString()); | 226 DartString toDartString() => new DartString.literal(value.toString()); |
206 | |
207 accept(ConstantVisitor visitor) => visitor.visitDouble(this); | |
208 } | 227 } |
209 | 228 |
210 class BoolConstant extends PrimitiveConstant { | 229 class BoolConstant extends PrimitiveConstant { |
211 factory BoolConstant(value) { | 230 factory BoolConstant(value) { |
212 return value ? new TrueConstant() : new FalseConstant(); | 231 return value ? new TrueConstant() : new FalseConstant(); |
213 } | 232 } |
214 const BoolConstant._internal(); | 233 const BoolConstant._internal(); |
215 bool isBool() => true; | 234 bool isBool() => true; |
216 | 235 |
217 abstract BoolConstant negate(); | 236 abstract BoolConstant negate(); |
218 } | 237 } |
219 | 238 |
220 class TrueConstant extends BoolConstant { | 239 class TrueConstant extends BoolConstant { |
221 final bool value = true; | 240 final bool value = true; |
222 | 241 |
223 factory TrueConstant() => const TrueConstant._internal(); | 242 factory TrueConstant() => const TrueConstant._internal(); |
224 const TrueConstant._internal() : super._internal(); | 243 const TrueConstant._internal() : super._internal(); |
225 bool isTrue() => true; | 244 bool isTrue() => true; |
226 | 245 |
| 246 void _writeJsCode(CodeBuffer buffer, ConstantHandler handler) { |
| 247 buffer.add("true"); |
| 248 } |
| 249 |
227 FalseConstant negate() => new FalseConstant(); | 250 FalseConstant negate() => new FalseConstant(); |
228 | 251 |
229 bool operator ==(var other) => this === other; | 252 bool operator ==(var other) => this === other; |
230 // The magic constant is just a random value. It does not have any | 253 // The magic constant is just a random value. It does not have any |
231 // significance. | 254 // significance. |
232 int hashCode() => 499; | 255 int hashCode() => 499; |
233 DartString toDartString() => const LiteralDartString("true"); | 256 DartString toDartString() => const LiteralDartString("true"); |
234 | |
235 accept(ConstantVisitor visitor) => visitor.visitTrue(this); | |
236 } | 257 } |
237 | 258 |
238 class FalseConstant extends BoolConstant { | 259 class FalseConstant extends BoolConstant { |
239 final bool value = false; | 260 final bool value = false; |
240 | 261 |
241 factory FalseConstant() => const FalseConstant._internal(); | 262 factory FalseConstant() => const FalseConstant._internal(); |
242 const FalseConstant._internal() : super._internal(); | 263 const FalseConstant._internal() : super._internal(); |
243 bool isFalse() => true; | 264 bool isFalse() => true; |
244 | 265 |
| 266 void _writeJsCode(CodeBuffer buffer, ConstantHandler handler) { |
| 267 buffer.add("false"); |
| 268 } |
| 269 |
245 TrueConstant negate() => new TrueConstant(); | 270 TrueConstant negate() => new TrueConstant(); |
246 | 271 |
247 bool operator ==(var other) => this === other; | 272 bool operator ==(var other) => this === other; |
248 // The magic constant is just a random value. It does not have any | 273 // The magic constant is just a random value. It does not have any |
249 // significance. | 274 // significance. |
250 int hashCode() => 536555975; | 275 int hashCode() => 536555975; |
251 DartString toDartString() => const LiteralDartString("false"); | 276 DartString toDartString() => const LiteralDartString("false"); |
252 | |
253 accept(ConstantVisitor visitor) => visitor.visitFalse(this); | |
254 } | 277 } |
255 | 278 |
256 class StringConstant extends PrimitiveConstant { | 279 class StringConstant extends PrimitiveConstant { |
257 final DartString value; | 280 final DartString value; |
258 int _hashCode; | 281 int _hashCode; |
259 final Node node; | 282 final Node node; |
260 | 283 |
261 StringConstant(this.value, this.node) { | 284 StringConstant(this.value, this.node) { |
262 // TODO(floitsch): cache StringConstants. | 285 // TODO(floitsch): cache StringConstants. |
263 // TODO(floitsch): compute hashcode without calling toString() on the | 286 // TODO(floitsch): compute hashcode without calling toString() on the |
264 // DartString. | 287 // DartString. |
265 _hashCode = value.slowToString().hashCode(); | 288 _hashCode = value.slowToString().hashCode(); |
266 } | 289 } |
267 bool isString() => true; | 290 bool isString() => true; |
268 | 291 |
| 292 void _writeJsCode(CodeBuffer buffer, ConstantHandler handler) { |
| 293 buffer.add("'"); |
| 294 ConstantHandler.writeEscapedString(value, buffer, (reason) { |
| 295 handler.compiler.reportError(node, reason); |
| 296 }); |
| 297 buffer.add("'"); |
| 298 } |
| 299 |
269 bool operator ==(var other) { | 300 bool operator ==(var other) { |
270 if (other is !StringConstant) return false; | 301 if (other is !StringConstant) return false; |
271 StringConstant otherString = other; | 302 StringConstant otherString = other; |
272 return (_hashCode == otherString._hashCode) && (value == otherString.value); | 303 return (_hashCode == otherString._hashCode) && (value == otherString.value); |
273 } | 304 } |
274 | 305 |
275 int hashCode() => _hashCode; | 306 int hashCode() => _hashCode; |
276 DartString toDartString() => value; | 307 DartString toDartString() => value; |
277 int get length => value.length; | 308 int get length => value.length; |
278 | |
279 accept(ConstantVisitor visitor) => visitor.visitString(this); | |
280 } | 309 } |
281 | 310 |
282 class ObjectConstant extends Constant { | 311 class ObjectConstant extends Constant { |
283 final DartType type; | 312 final DartType type; |
284 | 313 |
285 ObjectConstant(this.type); | 314 ObjectConstant(this.type); |
286 bool isObject() => true; | 315 bool isObject() => true; |
287 | 316 |
288 // TODO(1603): The class should be marked as abstract, but the VM doesn't | 317 // TODO(1603): The class should be marked as abstract, but the VM doesn't |
289 // currently allow this. | 318 // currently allow this. |
290 abstract int hashCode(); | 319 abstract int hashCode(); |
| 320 |
| 321 void _writeCanonicalizedJsCode(CodeBuffer buffer, ConstantHandler handler) { |
| 322 String name = handler.getNameForConstant(this); |
| 323 buffer.add(handler.compiler.namer.isolatePropertiesAccessForConstant(name)); |
| 324 } |
291 } | 325 } |
292 | 326 |
293 class ListConstant extends ObjectConstant { | 327 class ListConstant extends ObjectConstant { |
294 final List<Constant> entries; | 328 final List<Constant> entries; |
295 int _hashCode; | 329 int _hashCode; |
296 | 330 |
297 ListConstant(DartType type, this.entries) : super(type) { | 331 ListConstant(DartType type, this.entries) : super(type) { |
298 // TODO(floitsch): create a better hash. | 332 // TODO(floitsch): create a better hash. |
299 int hash = 0; | 333 int hash = 0; |
300 for (Constant input in entries) hash ^= input.hashCode(); | 334 for (Constant input in entries) hash ^= input.hashCode(); |
301 _hashCode = hash; | 335 _hashCode = hash; |
302 } | 336 } |
303 bool isList() => true; | 337 bool isList() => true; |
304 | 338 |
| 339 void _writeJsCode(CodeBuffer buffer, ConstantHandler handler) { |
| 340 // TODO(floitsch): we should not need to go through the compiler to make |
| 341 // the list constant. |
| 342 buffer.add("${handler.compiler.namer.ISOLATE}.makeConstantList"); |
| 343 buffer.add("(["); |
| 344 for (int i = 0; i < entries.length; i++) { |
| 345 if (i != 0) buffer.add(", "); |
| 346 Constant entry = entries[i]; |
| 347 handler.writeConstant(buffer, entry); |
| 348 } |
| 349 buffer.add("])"); |
| 350 } |
| 351 |
305 bool operator ==(var other) { | 352 bool operator ==(var other) { |
306 if (other is !ListConstant) return false; | 353 if (other is !ListConstant) return false; |
307 ListConstant otherList = other; | 354 ListConstant otherList = other; |
308 if (hashCode() != otherList.hashCode()) return false; | 355 if (hashCode() != otherList.hashCode()) return false; |
309 // TODO(floitsch): verify that the generic types are the same. | 356 // TODO(floitsch): verify that the generic types are the same. |
310 if (entries.length != otherList.entries.length) return false; | 357 if (entries.length != otherList.entries.length) return false; |
311 for (int i = 0; i < entries.length; i++) { | 358 for (int i = 0; i < entries.length; i++) { |
312 if (entries[i] != otherList.entries[i]) return false; | 359 if (entries[i] != otherList.entries[i]) return false; |
313 } | 360 } |
314 return true; | 361 return true; |
315 } | 362 } |
316 | 363 |
317 int hashCode() => _hashCode; | 364 int hashCode() => _hashCode; |
318 | 365 |
319 List<Constant> getDependencies() => entries; | 366 List<Constant> getDependencies() => entries; |
320 | 367 |
321 int get length => entries.length; | 368 int get length => entries.length; |
322 | |
323 accept(ConstantVisitor visitor) => visitor.visitList(this); | |
324 } | 369 } |
325 | 370 |
326 class MapConstant extends ObjectConstant { | 371 class MapConstant extends ObjectConstant { |
327 /** | 372 /** |
328 * The [PROTO_PROPERTY] must not be used as normal property in any JavaScript | 373 * The [PROTO_PROPERTY] must not be used as normal property in any JavaScript |
329 * object. It would change the prototype chain. | 374 * object. It would change the prototype chain. |
330 */ | 375 */ |
331 static const LiteralDartString PROTO_PROPERTY = | 376 static const String PROTO_PROPERTY = "__proto__"; |
332 const LiteralDartString("__proto__"); | |
333 | 377 |
334 /** The dart class implementing constant map literals. */ | 378 /** The dart class implementing constant map literals. */ |
335 static const SourceString DART_CLASS = const SourceString("ConstantMap"); | 379 static const SourceString DART_CLASS = const SourceString("ConstantMap"); |
336 static const SourceString DART_PROTO_CLASS = | 380 static const SourceString DART_PROTO_CLASS = |
337 const SourceString("ConstantProtoMap"); | 381 const SourceString("ConstantProtoMap"); |
338 static const SourceString LENGTH_NAME = const SourceString("length"); | 382 static const SourceString LENGTH_NAME = const SourceString("length"); |
339 static const SourceString JS_OBJECT_NAME = const SourceString("_jsObject"); | 383 static const SourceString JS_OBJECT_NAME = const SourceString("_jsObject"); |
340 static const SourceString KEYS_NAME = const SourceString("_keys"); | 384 static const SourceString KEYS_NAME = const SourceString("_keys"); |
341 static const SourceString PROTO_VALUE = const SourceString("_protoValue"); | 385 static const SourceString PROTO_VALUE = const SourceString("_protoValue"); |
342 | 386 |
343 final ListConstant keys; | 387 final ListConstant keys; |
344 final List<Constant> values; | 388 final List<Constant> values; |
345 final Constant protoValue; | 389 final Constant protoValue; |
346 int _hashCode; | 390 int _hashCode; |
347 | 391 |
348 MapConstant(DartType type, this.keys, this.values, this.protoValue) | 392 MapConstant(DartType type, this.keys, this.values, this.protoValue) |
349 : super(type) { | 393 : super(type) { |
350 // TODO(floitsch): create a better hash. | 394 // TODO(floitsch): create a better hash. |
351 int hash = 0; | 395 int hash = 0; |
352 for (Constant value in values) hash ^= value.hashCode(); | 396 for (Constant value in values) hash ^= value.hashCode(); |
353 _hashCode = hash; | 397 _hashCode = hash; |
354 } | 398 } |
355 bool isMap() => true; | 399 bool isMap() => true; |
356 | 400 |
| 401 void _writeJsCode(CodeBuffer buffer, ConstantHandler handler) { |
| 402 |
| 403 void writeJsMap() { |
| 404 buffer.add("{"); |
| 405 int valueIndex = 0; |
| 406 for (int i = 0; i < keys.entries.length; i++) { |
| 407 StringConstant key = keys.entries[i]; |
| 408 if (key.value == const LiteralDartString(PROTO_PROPERTY)) continue; |
| 409 |
| 410 if (valueIndex != 0) buffer.add(", "); |
| 411 |
| 412 key._writeJsCode(buffer, handler); |
| 413 buffer.add(": "); |
| 414 Constant value = values[valueIndex++]; |
| 415 handler.writeConstant(buffer, value); |
| 416 } |
| 417 buffer.add("}"); |
| 418 if (valueIndex != values.length) { |
| 419 handler.compiler.internalError("Bad value count."); |
| 420 } |
| 421 } |
| 422 |
| 423 void badFieldCountError() { |
| 424 handler.compiler.internalError( |
| 425 "Compiler and ConstantMap disagree on number of fields."); |
| 426 } |
| 427 |
| 428 ClassElement classElement = type.element; |
| 429 buffer.add("new "); |
| 430 buffer.add(handler.getJsConstructor(classElement)); |
| 431 buffer.add("("); |
| 432 // The arguments of the JavaScript constructor for any given Dart class |
| 433 // are in the same order as the members of the class element. |
| 434 int emittedArgumentCount = 0; |
| 435 classElement.forEachInstanceField( |
| 436 includeBackendMembers: true, |
| 437 includeSuperMembers: true, |
| 438 f: (ClassElement enclosing, Element field) { |
| 439 if (emittedArgumentCount != 0) buffer.add(", "); |
| 440 if (field.name == LENGTH_NAME) { |
| 441 buffer.add(keys.entries.length); |
| 442 } else if (field.name == JS_OBJECT_NAME) { |
| 443 writeJsMap(); |
| 444 } else if (field.name == KEYS_NAME) { |
| 445 handler.writeConstant(buffer, keys); |
| 446 } else if (field.name == PROTO_VALUE) { |
| 447 assert(protoValue !== null); |
| 448 handler.writeConstant(buffer, protoValue); |
| 449 } else { |
| 450 badFieldCountError(); |
| 451 } |
| 452 emittedArgumentCount++; |
| 453 }); |
| 454 if ((protoValue === null && emittedArgumentCount != 3) || |
| 455 (protoValue !== null && emittedArgumentCount != 4)) { |
| 456 badFieldCountError(); |
| 457 } |
| 458 buffer.add(")"); |
| 459 } |
| 460 |
357 bool operator ==(var other) { | 461 bool operator ==(var other) { |
358 if (other is !MapConstant) return false; | 462 if (other is !MapConstant) return false; |
359 MapConstant otherMap = other; | 463 MapConstant otherMap = other; |
360 if (hashCode() != otherMap.hashCode()) return false; | 464 if (hashCode() != otherMap.hashCode()) return false; |
361 // TODO(floitsch): verify that the generic types are the same. | 465 // TODO(floitsch): verify that the generic types are the same. |
362 if (keys != otherMap.keys) return false; | 466 if (keys != otherMap.keys) return false; |
363 for (int i = 0; i < values.length; i++) { | 467 for (int i = 0; i < values.length; i++) { |
364 if (values[i] != otherMap.values[i]) return false; | 468 if (values[i] != otherMap.values[i]) return false; |
365 } | 469 } |
366 return true; | 470 return true; |
367 } | 471 } |
368 | 472 |
369 int hashCode() => _hashCode; | 473 int hashCode() => _hashCode; |
370 | 474 |
371 List<Constant> getDependencies() { | 475 List<Constant> getDependencies() { |
372 List<Constant> result = <Constant>[keys]; | 476 List<Constant> result = <Constant>[keys]; |
373 result.addAll(values); | 477 result.addAll(values); |
374 return result; | 478 return result; |
375 } | 479 } |
376 | 480 |
377 int get length => keys.length; | 481 int get length => keys.length; |
378 | |
379 accept(ConstantVisitor visitor) => visitor.visitMap(this); | |
380 } | 482 } |
381 | 483 |
382 class ConstructedConstant extends ObjectConstant { | 484 class ConstructedConstant extends ObjectConstant { |
383 final List<Constant> fields; | 485 final List<Constant> fields; |
384 int _hashCode; | 486 int _hashCode; |
385 | 487 |
386 ConstructedConstant(DartType type, this.fields) : super(type) { | 488 ConstructedConstant(DartType type, this.fields) : super(type) { |
387 assert(type !== null); | 489 assert(type !== null); |
388 // TODO(floitsch): create a better hash. | 490 // TODO(floitsch): create a better hash. |
389 int hash = 0; | 491 int hash = 0; |
390 for (Constant field in fields) { | 492 for (Constant field in fields) { |
391 hash ^= field.hashCode(); | 493 hash ^= field.hashCode(); |
392 } | 494 } |
393 hash ^= type.element.hashCode(); | 495 hash ^= type.element.hashCode(); |
394 _hashCode = hash; | 496 _hashCode = hash; |
395 } | 497 } |
396 bool isConstructedObject() => true; | 498 bool isConstructedObject() => true; |
397 | 499 |
| 500 void _writeJsCode(CodeBuffer buffer, ConstantHandler handler) { |
| 501 buffer.add("new "); |
| 502 buffer.add(handler.getJsConstructor(type.element)); |
| 503 buffer.add("("); |
| 504 for (int i = 0; i < fields.length; i++) { |
| 505 if (i != 0) buffer.add(", "); |
| 506 Constant field = fields[i]; |
| 507 handler.writeConstant(buffer, field); |
| 508 } |
| 509 buffer.add(")"); |
| 510 } |
| 511 |
398 bool operator ==(var otherVar) { | 512 bool operator ==(var otherVar) { |
399 if (otherVar is !ConstructedConstant) return false; | 513 if (otherVar is !ConstructedConstant) return false; |
400 ConstructedConstant other = otherVar; | 514 ConstructedConstant other = otherVar; |
401 if (hashCode() != other.hashCode()) return false; | 515 if (hashCode() != other.hashCode()) return false; |
402 // TODO(floitsch): verify that the (generic) types are the same. | 516 // TODO(floitsch): verify that the (generic) types are the same. |
403 if (type.element != other.type.element) return false; | 517 if (type.element != other.type.element) return false; |
404 if (fields.length != other.fields.length) return false; | 518 if (fields.length != other.fields.length) return false; |
405 for (int i = 0; i < fields.length; i++) { | 519 for (int i = 0; i < fields.length; i++) { |
406 if (fields[i] != other.fields[i]) return false; | 520 if (fields[i] != other.fields[i]) return false; |
407 } | 521 } |
408 return true; | 522 return true; |
409 } | 523 } |
410 | 524 |
411 int hashCode() => _hashCode; | 525 int hashCode() => _hashCode; |
412 List<Constant> getDependencies() => fields; | 526 List<Constant> getDependencies() => fields; |
413 | |
414 accept(ConstantVisitor visitor) => visitor.visitConstructed(this); | |
415 } | 527 } |
OLD | NEW |