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

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