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

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

Issue 9475021: Refactor Constants. (Closed) Base URL: https://dart.googlecode.com/svn/branches/bleeding_edge/dart
Patch Set: Address comment. 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/ssa/builder.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 // TODO(floitsch): finish implementation.
6 class Constant implements Hashable { 5 class Constant implements Hashable {
7 // TODO(floitsch): remove the direct access to the string. 6 const Constant();
8 final String jsCode; 7
9 Constant(this.jsCode); 8 bool isNull() => false;
10 9 /** [isInt] implies [isNum]. */
11 int hashCode() => jsCode.hashCode(); 10 bool isInt() => false;
12 bool operator ==(var other) { 11 /** [isDouble] implies [isNum]. */
13 if (other is !Constant) return false; 12 bool isDouble() => false;
14 Constant otherConstant = other; 13 bool isBool() => false;
15 return jsCode == otherConstant.jsCode; 14 bool isString() => false;
16 } 15 /** [isList] implies [isObject]. */
16 bool isList() => false;
17 /** [isMap] implies [isObject]. */
18 bool isMap() => false;
19 bool isConstructedObject() => false;
20
21 bool isNum() => isInt() || isDouble();
22 bool isObject() => isList() || isMap() || isConstructedObject();
23
24 /**
25 * Returns [:null:] if the operation is not supported on this constant.
26 * The [op] operator is assumed to be a prefix operator.
27 */
28 Constant unaryFold(String op) => null;
29
30 /**
31 * Returns [:null:] if the operation is not supported on this constant, or
32 * if the operation would have thrown an exception.
33 */
34 Constant binaryFold(String op, Constant other) {
35 if (op == "==" || op == "===") {
36 return new BoolConstant(this == other);
37 } else if (op == "!=" || op == "!==") {
38 return new BoolConstant(this != other);
39 }
40 }
41
42 abstract void writeJsCode(StringBuffer buffer,
43 CompileTimeConstantHandler handler);
44 }
45
46 class PrimitiveConstant extends Constant {
47 // TODO(floitsch): this should be an abstract getter, but there is a bug in
48 // the VM.
49 get value() => null;
50 const PrimitiveConstant();
51
52 bool operator ==(var other) {
53 if (other is !PrimitiveConstant) return false;
54 PrimitiveConstant otherPrimitive = other;
55 // We use == instead of === so that DartStrings compare correctly.
56 return value == otherPrimitive.value;
57 }
58 }
59
60 class NullConstant extends PrimitiveConstant {
61 const NullConstant();
62 bool isNull() => true;
63 get value() => null;
64
65 void writeJsCode(StringBuffer buffer, CompileTimeConstantHandler handler) {
66 buffer.add("(void 0)");
67 }
68
69 // The magic constant has no meaning. It is just a random value.
70 int hashCode() => 785965825;
71 }
72
73 class IntConstant extends PrimitiveConstant {
74 final int value;
75 // TODO(floitsch): cache the most common integer values.
76 const IntConstant(this.value);
77 bool isInt() => true;
78
79 void writeJsCode(StringBuffer buffer, CompileTimeConstantHandler handler) {
80 buffer.add("($value)");
81 }
82
83 IntConstant unaryFold(String op) {
84 if (op == "-") return new IntConstant(-value);
85 if (op == "~") return new IntConstant(~value);
86 return null;
87 }
88
89 Constant binaryFold(String op, Constant other) {
90 if (other.isNum()) {
91 PrimitiveConstant otherPrimitive = other;
92 num rightNum = otherPrimitive.value;
93 switch (op) {
94 case "<": return new BoolConstant(value < rightNum);
95 case "<=": return new BoolConstant(value <= rightNum);
96 case ">": return new BoolConstant(value > rightNum);
97 case ">=": return new BoolConstant(value >= rightNum);
98 case "/": return new DoubleConstant(value / rightNum);
99 // We have to treat '==' and '!=' here in case rightNum is a double.
100 case "==": return new BoolConstant(value == rightNum);
101 case "!=": return new BoolConstant(value != rightNum);
102 }
103 if (other.isInt()) {
104 int right = rightNum;
105 switch (op) {
106 case "+": return new IntConstant(value + right);
107 case "-": return new IntConstant(value - right);
108 case "*": return new IntConstant(value * right);
109 case "%": return new IntConstant(value % right);
110 case "~/": return new IntConstant(value ~/ right);
111 case "|": return new IntConstant(value | right);
112 case "&": return new IntConstant(value & right);
113 case "^": return new IntConstant(value ^ right);
114 case "<<":
115 // TODO(floitsch): find a better way to guard against shifts to the
116 // left.
117 if (right > 100) null;
118 if (right < 0) null;
119 return new IntConstant(value << right);
120 case ">>":
121 if (right < 0) return null;
122 return new IntConstant(value >> right);
123 }
124 } else if (other.isDouble()) {
125 double right = rightNum;
126 switch (op) {
127 case "+": return new DoubleConstant(value + right);
128 case "-": return new DoubleConstant(value - right);
129 case "*": return new DoubleConstant(value * right);
130 case "~/": return new DoubleConstant(value ~/ right);
131 case "%": return new DoubleConstant(value % right);
132 }
133 }
134 }
135 // Visit super in case the [op] was "==", "===", "!=" or "!==".
136 return super.binaryFold(op, other);
137 }
138
139 // We have to override the equality operator so that ints and doubles are
140 // treated as separate constants.
141 // The is [:!IntConstant:] check at the beginning of the function makes sure
142 // that we compare only equal to integer constants.
143 bool operator ==(var other) {
144 if (other is !IntConstant) return false;
145 IntConstant otherInt = other;
146 return value == otherInt.value;
147 }
148
149 int hashCode() => value.hashCode();
150 }
151
152 class DoubleConstant extends PrimitiveConstant {
153 final double value;
154 const DoubleConstant(this.value);
155 bool isDouble() => true;
156
157 void writeJsCode(StringBuffer buffer, CompileTimeConstantHandler handler) {
158 if (value.isNaN()) {
159 buffer.add("(0/0)");
160 } else if (value == double.INFINITY) {
161 buffer.add("(1/0)");
162 } else if (value == -double.INFINITY) {
163 buffer.add("(-1/0)");
164 } else {
165 buffer.add("($value)");
166 }
167 }
168
169 DoubleConstant unaryFold(String op) {
170 if (op == "-") return new DoubleConstant(-value);
171 return null;
172 }
173
174 Constant binaryFold(String op, Constant other) {
175 if (other.isNum()) {
176 PrimitiveConstant otherPrimitive = other;
177 num right = otherPrimitive.value;
178 switch (op) {
179 case "<": return new BoolConstant(value < right);
180 case "<=": return new BoolConstant(value <= right);
181 case ">": return new BoolConstant(value > right);
182 case ">=": return new BoolConstant(value >= right);
183 case "+": return new DoubleConstant(value + right);
184 case "-": return new DoubleConstant(value - right);
185 case "*": return new DoubleConstant(value * right);
186 case "~/": return new DoubleConstant(value ~/ right);
187 case "/": return new DoubleConstant(value / right);
188 case "%": return new DoubleConstant(value % right);
189 // We have to handle '==' and '!=' here in case right is an integer,
190 // or one of the operands is NaN, -0.0 or 0.0.
191 case "==": return new BoolConstant(value == right);
192 case "!=": return new BoolConstant(value != right);
193 }
194 }
195 // Visit super in case the [op] was "==", "===", "!=" or "!===".
196 return super.binaryFold(op, other);
197 }
198
199 bool operator ==(var other) {
200 if (other is !DoubleConstant) return false;
201 DoubleConstant otherDouble = other;
202 double otherValue = otherDouble.value;
203 if (value == 0.0 && otherValue == 0.0) {
204 return value.isNegative() == otherValue.isNegative();
205 } else if (value.isNaN()) {
206 return otherValue.isNaN();
207 } else {
208 return value == otherValue;
209 }
210 }
211
212 int hashCode() => value.hashCode();
213 }
214
215 class BoolConstant extends PrimitiveConstant {
216 final bool value;
217 const BoolConstant(this.value);
218 bool isBool() => true;
219
220 void writeJsCode(StringBuffer buffer, CompileTimeConstantHandler handler) {
221 buffer.add(value ? "true" : "false");
222 }
223
224 BoolConstant unaryFold(String op) {
225 if (op == "!") return new BoolConstant(!value);
226 return null;
227 }
228
229 bool operator ==(var other) {
230 if (other is !BoolConstant) return false;
231 BoolConstant otherBool = other;
232 return value == otherBool.value;
233 }
234
235 // The magic constants are just random values. They don't have any
236 // significance.
237 int hashCode() => value ? 499 : 536555975;
238 }
239
240 class StringConstant extends PrimitiveConstant {
241 final DartString value;
242 int _hashCode;
243
244 StringConstant(this.value) {
245 // TODO(floitsch): compute hashcode without calling toString() on the
246 // DartString.
247 _hashCode = value.toString().hashCode();
248 }
249 bool isString() => true;
250
251 void writeJsCode(StringBuffer buffer, CompileTimeConstantHandler handler) {
252 buffer.add("'");
253 CompileTimeConstantHandler.writeEscapedString(value, buffer, (reason) {
254 throw new CompilerCancelledException(reason);
255 });
256 buffer.add("'");
257 }
258
259 StringConstant binaryFold(String op, Constant other) {
260 if (other.isString() && op == "+") {
261 StringConstant otherString = other;
262 DartString right = otherString.value;
263 return new StringConstant(new ConsDartString(value, right));
264 }
265 // Visit super in case the [op] was "==", "===", "!=" or "!===".
266 return super.binaryFold(op, other);
267 }
268
269 bool operator ==(var other) {
270 if (other is !StringConstant) return false;
271 StringConstant otherString = other;
272 return (_hashCode == otherString._hashCode) && (value == otherString.value);
273 }
274
275 int hashCode() => _hashCode;
276 }
277
278 class ObjectConstant extends Constant {
279 final Type type;
280
281 ObjectConstant(this.type);
282 }
283
284 class ListConstant extends ObjectConstant {
285 final List<Constant> entries;
286 int _hashCode;
287
288 ListConstant(Type type, this.entries) : super(type) {
289 // TODO(floitsch): create a better hash.
290 int hash = 0;
291 for (Constant input in entries) hash ^= input.hashCode();
292 _hashCode = hash;
293 }
294 bool isList() => true;
295
296 void writeJsCode(StringBuffer buffer, CompileTimeConstantHandler handler) {
297 // TODO(floitsch): we should not need to go through the compiler to make
298 // the list constant.
299 buffer.add(handler.compiler.namer.ISOLATE);
300 buffer.add(".prototype.makeConstantList");
301 buffer.add("([");
302 for (int i = 0; i < entries.length; i++) {
303 if (i != 0) buffer.add(", ");
304 Constant entry = entries[i];
305 if (entry.isObject()) {
306 handler.getNameForConstant(entry);
307 } else {
308 entry.writeJsCode(buffer, handler);
309 }
310 }
311 buffer.add("])");
312 }
313
314 bool operator ==(var other) {
315 if (other is !ListConstant) return false;
316 ListConstant otherList = other;
317 if (hashCode() != otherList.hashCode()) return false;
318 // TODO(floitsch): verify that the types are the same.
319 if (entries.length != otherList.entries.length) return false;
320 for (int i = 0; i < entries.length; i++) {
321 if (entries[i] != otherList.entries[i]) return false;
322 }
323 return true;
324 }
325
326 int hashCode() => _hashCode;
327 }
328
329 class ConstructedConstant extends ObjectConstant {
330 final List<Constant> fields;
331 int _hashCode;
332
333 ConstructedConstant(Type type, this.fields) : super(type) {
334 assert(type !== null);
335 // TODO(floitsch): create a better hash.
336 int hash = 0;
337 for (Constant field in fields) {
338 hash ^= field.hashCode();
339 }
340 hash ^= type.element.hashCode();
341 _hashCode = hash;
342 }
343 bool isConstructedObject() => true;
344
345 void writeJsCode(StringBuffer buffer, CompileTimeConstantHandler handler) {
346 buffer.add("new ");
347 buffer.add(handler.getJsConstructor(type.element));
348 buffer.add("(");
349 for (int i = 0; i < fields.length; i++) {
350 if (i != 0) buffer.add(", ");
351 Constant field = fields[i];
352 // TODO(floitsch): share this code with the ListConstant.
353 if (field.isObject()) {
354 handler.getNameForConstant(field);
355 } else {
356 field.writeJsCode(buffer, handler);
357 }
358 }
359 buffer.add(")");
360 }
361
362 bool operator ==(var otherVar) {
363 if (otherVar is !ConstructedConstant) return false;
364 ConstructedConstant other = otherVar;
365 if (hashCode() != other.hashCode()) return false;
366 // TODO(floitsch): verify that the (generic) types are the same.
367 if (type.element != other.type.element) return false;
368 if (fields.length != other.fields.length) return false;
369 for (int i = 0; i < fields.length; i++) {
370 if (fields[i] != other.fields[i]) return false;
371 }
372 return true;
373 }
374
375 int hashCode() => _hashCode;
17 } 376 }
18 377
19 /** 378 /**
20 * The [CompileTimeConstantHandler] keeps track of compile-time constants, 379 * The [CompileTimeConstantHandler] keeps track of compile-time constants,
21 * initializations of global and static fields, and default values of 380 * initializations of global and static fields, and default values of
22 * optional parameters. 381 * optional parameters.
23 */ 382 */
24 class CompileTimeConstantHandler extends CompilerTask { 383 class CompileTimeConstantHandler extends CompilerTask {
25 // Contains the initial value of fields. Must contain all static and global 384 // Contains the initial value of fields. Must contain all static and global
26 // initializations of used fields. May contain caches for instance fields. 385 // initializations of used fields. May contain caches for instance fields.
(...skipping 24 matching lines...) Expand all
51 assert(work.element.kind == ElementKind.FIELD 410 assert(work.element.kind == ElementKind.FIELD
52 || work.element.kind == ElementKind.PARAMETER); 411 || work.element.kind == ElementKind.PARAMETER);
53 VariableElement element = work.element; 412 VariableElement element = work.element;
54 // Shortcut if it has already been compiled. 413 // Shortcut if it has already been compiled.
55 if (initialVariableValues.containsKey(element)) return; 414 if (initialVariableValues.containsKey(element)) return;
56 compileVariableWithDefinitions(element, work.resolutionTree); 415 compileVariableWithDefinitions(element, work.resolutionTree);
57 } 416 }
58 417
59 compileVariable(VariableElement element) { 418 compileVariable(VariableElement element) {
60 if (initialVariableValues.containsKey(element)) { 419 if (initialVariableValues.containsKey(element)) {
61 return initialVariableValues[element]; 420 Constant result = initialVariableValues[element];
421 // TODO(floitsch): remove the following line once the rest of the
422 // compiler has been adapted.
423 if (!result.isObject()) return result.dynamic.value;
424 return result;
62 } 425 }
63 // TODO(floitsch): keep track of currently compiling elements so that we 426 // TODO(floitsch): keep track of currently compiling elements so that we
64 // don't end up in an infinite loop: final x = y; final y = x; 427 // don't end up in an infinite loop: final x = y; final y = x;
65 TreeElements definitions = compiler.analyzeElement(element); 428 TreeElements definitions = compiler.analyzeElement(element);
66 return compileVariableWithDefinitions(element, definitions); 429 Constant constant = compileVariableWithDefinitions(element, definitions);
430 // TODO(floitsch): remove the following line once the rest of the
431 // compiler has been adapted.
432 if (!constant.isObject()) return constant.dynamic.value;
433 return constant;
67 } 434 }
68 435
69 compileVariableWithDefinitions(VariableElement element, 436 compileVariableWithDefinitions(VariableElement element,
70 TreeElements definitions) { 437 TreeElements definitions) {
71 return measure(() { 438 return measure(() {
72 Node node = element.parseNode(compiler); 439 Node node = element.parseNode(compiler);
73 assert(node !== null); 440 assert(node !== null);
74 SendSet assignment = node.asSendSet(); 441 SendSet assignment = node.asSendSet();
75 var value; 442 var value;
76 if (assignment === null) { 443 if (assignment === null) {
77 // No initial value. 444 // No initial value.
78 value = null; 445 value = const NullConstant();
79 } else { 446 } else {
80 Node right = assignment.arguments.head; 447 Node right = assignment.arguments.head;
81 CompileTimeConstantEvaluator evaluator = 448 CompileTimeConstantEvaluator evaluator =
82 new CompileTimeConstantEvaluator(this, definitions, compiler); 449 new CompileTimeConstantEvaluator(this, definitions, compiler);
83 value = evaluator.evaluate(right); 450 value = evaluator.evaluate(right);
84 } 451 }
85 initialVariableValues[element] = value; 452 initialVariableValues[element] = value;
86 return value; 453 return value;
87 }); 454 });
88 } 455 }
89 456
90 compileObjectCreation(Node node, Element constructor, List arguments) { 457 ConstructedConstant compileObjectConstruction(Node node,
458 Type type,
459 List arguments) {
91 if (!arguments.isEmpty()) { 460 if (!arguments.isEmpty()) {
92 compiler.unimplemented("CompileTimeConstantHandler with arguments", 461 compiler.unimplemented("CompileTimeConstantHandler with arguments",
93 node: node); 462 node: node);
94 } 463 }
95 ClassElement classElement = constructor.enclosingElement; 464 ClassElement classElement = type.element;
96 for (Element member in classElement.members) { 465 for (Element member in classElement.members) {
97 if (Elements.isInstanceField(member)) { 466 if (Elements.isInstanceField(member)) {
98 compiler.unimplemented("CompileTimeConstantHandler with fields", 467 compiler.unimplemented("CompileTimeConstantHandler with fields",
99 node: node); 468 node: node);
100 } 469 }
101 } 470 }
102 if (classElement.superclass != compiler.coreLibrary.find(Types.OBJECT)) { 471 if (classElement.superclass != compiler.coreLibrary.find(Types.OBJECT)) {
103 compiler.unimplemented("CompileTimeConstantHandler with super", 472 compiler.unimplemented("CompileTimeConstantHandler with super",
104 node: node); 473 node: node);
105 } 474 }
106 compiler.registerInstantiatedClass(classElement); 475 compiler.registerInstantiatedClass(classElement);
107 Namer namer = compiler.namer; 476 Constant constant = new ConstructedConstant(type, arguments);
108 String instantiation = "new ${namer.isolatePropertyAccess(classElement)}()";
109 Constant constant = new Constant(instantiation);
110 registerCompileTimeConstant(constant); 477 registerCompileTimeConstant(constant);
111 return constant; 478 return constant;
112 } 479 }
113 480
114 compileListLiteral(Node node, List arguments) { 481 ListConstant compileListLiteral(Node node,
115 StringBuffer buffer = new StringBuffer(); 482 Type type,
116 buffer.add(compiler.namer.ISOLATE); 483 List<Constant> arguments) {
117 buffer.add(".prototype.makeConstantList"); 484 Constant constant = new ListConstant(type, arguments);
118 buffer.add("([");
119 for (int i = 0; i < arguments.length; i++) {
120 if (i != 0) buffer.add(", ");
121 // TODO(floitsch): canonicalize if the constant is in the
122 // [compiledConstant] set.
123 writeJsCode(buffer, arguments[i]);
124 }
125 buffer.add("])");
126 // TODO(floitsch): do we have to register 'List' as instantiated class?
127 String array = buffer.toString();
128 Constant constant = new Constant(array);
129 registerCompileTimeConstant(constant); 485 registerCompileTimeConstant(constant);
130 return constant; 486 return constant;
131 } 487 }
132 488
133 /** 489 /**
134 * Returns a [List] of static non final fields that need to be initialized. 490 * Returns a [List] of static non final fields that need to be initialized.
135 * The list must be evaluated in order since the fields might depend on each 491 * The list must be evaluated in order since the fields might depend on each
136 * other. 492 * other.
137 */ 493 */
138 List<VariableElement> getStaticNonFinalFieldsForEmission() { 494 List<VariableElement> getStaticNonFinalFieldsForEmission() {
(...skipping 18 matching lines...) Expand all
157 } 513 }
158 514
159 List<Constant> getConstantsForEmission() { 515 List<Constant> getConstantsForEmission() {
160 return compiledConstants.getKeys(); 516 return compiledConstants.getKeys();
161 } 517 }
162 518
163 String getNameForConstant(Constant constant) { 519 String getNameForConstant(Constant constant) {
164 return compiledConstants[constant]; 520 return compiledConstants[constant];
165 } 521 }
166 522
167 StringBuffer writeJsCode(StringBuffer buffer, var value) { 523 StringBuffer writeJsCode(StringBuffer buffer, Constant value) {
168 if (value === null) { 524 value.writeJsCode(buffer, this);
169 buffer.add("(void 0)");
170 } else if (value is num) {
171 if (value.isNaN()) {
172 buffer.add("(0/0)");
173 } else if (value == double.INFINITY) {
174 buffer.add("(1/0)");
175 } else if (value == -double.INFINITY) {
176 buffer.add("(-1/0)");
177 } else {
178 buffer.add("($value)");
179 }
180 } else if (value === true) {
181 buffer.add("true");
182 } else if (value === false) {
183 buffer.add("false");
184 } else if (value is DartString) {
185 buffer.add("'");
186 writeEscapedString(value, buffer, (reason) {
187 compiler.cancel("failed to write escaped string: $value");
188 });
189 buffer.add("'");
190 } else if (value is Constant) {
191 Constant constant = value;
192 buffer.add(constant.jsCode);
193 } else {
194 // TODO(floitsch): support more values.
195 compiler.unimplemented("CompileTimeConstantHandler writeJsCode",
196 element: element);
197 }
198 return buffer; 525 return buffer;
199 } 526 }
200 527
201 StringBuffer writeJsCodeForVariable(StringBuffer buffer, 528 StringBuffer writeJsCodeForVariable(StringBuffer buffer,
202 VariableElement element) { 529 VariableElement element) {
203 var value = initialVariableValues[element]; 530 if (!initialVariableValues.containsKey(element)) {
204 if (value is Constant) { 531 buffer.add("(void 0)");
205 String name = compiledConstants[value]; 532 return buffer;
533 // TODO(floitsch): reenable the following lines, once we fixed the rest
534 // of the compiler.
535 /*
536 compiler.internalError("No initial value for given element",
537 element: element);
538 */
539 }
540 Constant constant = initialVariableValues[element];
541 if (constant.isObject()) {
542 String name = compiledConstants[constant];
206 buffer.add("${compiler.namer.ISOLATE}.prototype.$name"); 543 buffer.add("${compiler.namer.ISOLATE}.prototype.$name");
207 } else { 544 } else {
208 return writeJsCode(buffer, initialVariableValues[element]); 545 writeJsCode(buffer, constant);
209 } 546 }
547 return buffer;
210 } 548 }
211 549
212 /** 550 /**
213 * Write the contents of the quoted string to a [StringBuffer] in 551 * Write the contents of the quoted string to a [StringBuffer] in
214 * a form that is valid as JavaScript string literal content. 552 * a form that is valid as JavaScript string literal content.
215 * The string is assumed quoted by single quote characters. 553 * The string is assumed quoted by single quote characters.
216 */ 554 */
217 static void writeEscapedString(DartString string, 555 static void writeEscapedString(DartString string,
218 StringBuffer buffer, 556 StringBuffer buffer,
219 void cancel(String reason)) { 557 void cancel(String reason)) {
(...skipping 35 matching lines...) Expand 10 before | Expand all | Expand 10 after
255 buffer.add('0'); 593 buffer.add('0');
256 } 594 }
257 buffer.add(code.toRadixString(16)); 595 buffer.add(code.toRadixString(16));
258 } 596 }
259 } else { 597 } else {
260 buffer.add(new String.fromCharCodes(<int>[code])); 598 buffer.add(new String.fromCharCodes(<int>[code]));
261 } 599 }
262 } 600 }
263 } 601 }
264 } 602 }
603
604 String getJsConstructor(ClassElement element) {
605 return compiler.namer.isolatePropertyAccess(element);
606 }
265 } 607 }
266 608
267 class CompileTimeConstantEvaluator extends AbstractVisitor { 609 class CompileTimeConstantEvaluator extends AbstractVisitor {
268 final CompileTimeConstantHandler constantHandler; 610 final CompileTimeConstantHandler constantHandler;
269 final TreeElements definitions; 611 final TreeElements definitions;
270 final Compiler compiler; 612 final Compiler compiler;
271 613
272 CompileTimeConstantEvaluator(this.constantHandler, 614 CompileTimeConstantEvaluator(this.constantHandler,
273 this.definitions, 615 this.definitions,
274 this.compiler); 616 this.compiler);
275 617
276 evaluate(Node node) { 618 Constant evaluate(Node node) {
277 return node.accept(this); 619 return node.accept(this);
278 } 620 }
279 621
280 visitNode(Node node) { 622 visitNode(Node node) {
281 compiler.unimplemented("CompileTimeConstantEvaluator", node: node); 623 compiler.unimplemented("CompileTimeConstantEvaluator", node: node);
282 } 624 }
283 625
284 visitLiteral(Literal literal) { 626 Constant visitLiteralBool(LiteralBool node) {
285 if (literal is LiteralString) { 627 // TODO(floitsch): make BoolConstant a factory and cache the two values
286 assert(literal.asLiteralString().isValidated()); 628 // there.
287 return literal.asLiteralString().dartString; 629 return node.value ? const BoolConstant(true) : const BoolConstant(false);
630 }
631
632 Constant visitLiteralDouble(LiteralDouble node) {
633 return new DoubleConstant(node.value);
634 }
635
636 Constant visitLiteralInt(LiteralInt node) {
637 return new IntConstant(node.value);
638 }
639
640 Constant visitLiteralList(LiteralList node) {
641 if (!node.isConst()) error(node);
642 List arguments = [];
643 for (Link<Node> link = node.elements.nodes;
644 !link.isEmpty();
645 link = link.tail) {
646 arguments.add(evaluate(link.head));
288 } 647 }
289 return literal.value; 648 // TODO(floitsch): get type from somewhere.
649 Type type = null;
650 return constantHandler.compileListLiteral(node, type, arguments);
651 }
652
653 Constant visitLiteralMap(LiteralMap node) {
654 compiler.unimplemented("CompileTimeConstantEvaluator map", node: node);
655 }
656
657 Constant visitLiteralNull(LiteralNull node) {
658 return const NullConstant();
659 }
660
661 Constant visitLiteralString(LiteralString node) {
662 return new StringConstant(node.dartString);
290 } 663 }
291 664
292 // TODO(floitsch): provide better error-messages. 665 // TODO(floitsch): provide better error-messages.
293 visitSend(Send send) { 666 visitSend(Send send) {
294 Element element = definitions[send]; 667 Element element = definitions[send];
295 if (Elements.isStaticOrTopLevelField(element)) { 668 if (Elements.isStaticOrTopLevelField(element)) {
296 if (element.modifiers === null || 669 if (element.modifiers === null ||
297 !element.modifiers.isFinal()) { 670 !element.modifiers.isFinal()) {
298 error(send); 671 error(send);
299 } 672 }
300 return constantHandler.compileVariable(element); 673 // TODO(floitsch): compileVariable temporarily returns primitives, so
674 // that the rest of the compiler can be adapted incrementally. Therefore
675 // we have to get the constant from the hashtable instead of using the
676 // returned result directly.
677 constantHandler.compileVariable(element);
678 return constantHandler.initialVariableValues[element];
301 } else if (send.isPrefix) { 679 } else if (send.isPrefix) {
302 assert(send.isOperator); 680 assert(send.isOperator);
303 var receiverValue = evaluate(send.receiver); 681 Constant receiverConstant = evaluate(send.receiver);
304 Operator op = send.selector; 682 Operator op = send.selector;
305 switch (op.source.stringValue) { 683 Constant folded = receiverConstant.unaryFold(op.source.stringValue);
306 case "-": 684 if (folded === null) error(send);
307 if (receiverValue is !num) error(send); 685 return folded;
308 return -receiverValue;
309 case "~":
310 if (receiverValue is !int) error(send);
311 return ~receiverValue;
312 case "!":
313 if (receiverValue is !bool) error(send);
314 return !receiverValue;
315 default:
316 error(send);
317 }
318 } else if (send.isOperator && !send.isPostfix) { 686 } else if (send.isOperator && !send.isPostfix) {
319 assert(send.argumentCount() == 1); 687 assert(send.argumentCount() == 1);
320 var left = evaluate(send.receiver); 688 Constant left = evaluate(send.receiver);
321 var right = evaluate(send.argumentsNode.nodes.head); 689 Constant right = evaluate(send.argumentsNode.nodes.head);
322 String op = send.selector.asOperator().source.stringValue; 690 String op = send.selector.asOperator().source.stringValue;
323 691 Constant folded = left.binaryFold(op, right);
324 if (op == "==" || op == "===") { 692 if (folded === null) error(send);
325 // We use == instead of === so that non-canonicalized DartStrings can 693 return folded;
326 // use their equality operator.
327 return left == right;
328 } else if (op == "!=" || op == "!==") {
329 return left != right;
330 }
331 if (left is num && right is num) {
332 switch (op) {
333 case "+": return left + right;
334 case "-": return left - right;
335 case "*": return left * right;
336 case "/": return left / right;
337 case "~/":
338 case "%":
339 if (left is int && right is int && right == 0) {
340 error(send);
341 }
342 return op == "~/" ? left ~/ right : left % right;
343 case "<": return left < right;
344 case "<=": return left <= right;
345 case ">": return left > right;
346 case ">=": return left >= right;
347 }
348 }
349 if (left is int && right is int) {
350 switch (op) {
351 case "|": return left | right;
352 case "&": return left & right;
353 case "<<":
354 // TODO(floitsch): find a better way to guard against shifts to the
355 // left.
356 if (right > 100) error(send);
357 if (right < 0) error(send);
358 return left << right;
359 case ">>":
360 if (right < 0) error(send);
361 return left >> right;
362 case "^": return left ^ right;
363 }
364 }
365 if (left is DartString && right is DartString && op == "+") {
366 return new ConsDartString(left, right);
367 }
368 } 694 }
369 return super.visitSend(send); 695 return super.visitSend(send);
370 } 696 }
371 697
372 visitSendSet(SendSet node) { 698 visitSendSet(SendSet node) {
373 error(node); 699 error(node);
374 } 700 }
375 701
376 visitNewExpression(NewExpression node) { 702 visitNewExpression(NewExpression node) {
377 if (!node.isConst()) error(node); 703 if (!node.isConst()) error(node);
378 Send send = node.send; 704 Send send = node.send;
379 List arguments; 705 List arguments;
380 if (send.arguments.isEmpty()) { 706 if (send.arguments.isEmpty()) {
381 arguments = const []; 707 arguments = const [];
382 } else { 708 } else {
383 arguments = []; 709 arguments = [];
384 for (Link<Node> link = send.arguments; 710 for (Link<Node> link = send.arguments;
385 !link.isEmpty(); 711 !link.isEmpty();
386 link = link.tail) { 712 link = link.tail) {
387 arguments.add(evaluate(link.head)); 713 arguments.add(evaluate(link.head));
388 } 714 }
389 } 715 }
390 return constantHandler.compileObjectCreation(node, definitions[node.send], 716 // TODO(floitsch): get the type from somewhere.
391 arguments); 717 Element constructorElement = definitions[node.send];
392 } 718 ClassElement classElement = constructorElement.enclosingElement;
393 719 Type type = new SimpleType(classElement.name, classElement);
394 visitLiteralList(LiteralList node) { 720 return constantHandler.compileObjectConstruction(node,
395 if (!node.isConst()) error(node); 721 type,
396 List arguments = []; 722 arguments);
397 for (Link<Node> link = node.elements.nodes;
398 !link.isEmpty();
399 link = link.tail) {
400 arguments.add(evaluate(link.head));
401 }
402 return constantHandler.compileListLiteral(node, arguments);
403 } 723 }
404 724
405 error(Node node) { 725 error(Node node) {
406 // TODO(floitsch): get the list of constants that are currently compiled 726 // TODO(floitsch): get the list of constants that are currently compiled
407 // and present some kind of stack-trace. 727 // and present some kind of stack-trace.
408 MessageKind kind = MessageKind.NOT_A_COMPILE_TIME_CONSTANT; 728 MessageKind kind = MessageKind.NOT_A_COMPILE_TIME_CONSTANT;
409 compiler.reportError(node, new CompileTimeConstantError(kind, const [])); 729 compiler.reportError(node, new CompileTimeConstantError(kind, const []));
410 } 730 }
411 } 731 }
OLDNEW
« no previous file with comments | « no previous file | frog/leg/ssa/builder.dart » ('j') | no next file with comments »

Powered by Google App Engine
This is Rietveld 408576698