Chromium Code Reviews| OLD | NEW |
|---|---|
| 1 // Copyright (c) 2012, the Dart project authors. Please see the AUTHORS file | 1 // Copyright (c) 2012, the Dart project authors. Please see the AUTHORS file |
| 2 // for details. All rights reserved. Use of this source code is governed by a | 2 // for details. All rights reserved. Use of this source code is governed by a |
| 3 // BSD-style license that can be found in the LICENSE file. | 3 // BSD-style license that can be found in the LICENSE file. |
| 4 | 4 |
| 5 class Constant implements Hashable { | 5 class Constant implements Hashable { |
| 6 const Constant(); | 6 const Constant(); |
| 7 | 7 |
| 8 bool isNull() => false; | 8 bool isNull() => false; |
| 9 /** [isInt] implies [isNum]. */ | 9 /** [isInt] implies [isNum]. */ |
| 10 bool isInt() => false; | 10 bool isInt() => false; |
| 11 /** [isDouble] implies [isNum]. */ | 11 /** [isDouble] implies [isNum]. */ |
| 12 bool isDouble() => false; | 12 bool isDouble() => false; |
| 13 bool isBool() => false; | 13 bool isBool() => false; |
| 14 bool isString() => false; | 14 bool isString() => false; |
| 15 /** [isList] implies [isObject]. */ | 15 /** [isList] implies [isObject]. */ |
| 16 bool isList() => false; | 16 bool isList() => false; |
| 17 /** [isMap] implies [isObject]. */ | 17 /** [isMap] implies [isObject]. */ |
| 18 bool isMap() => false; | 18 bool isMap() => false; |
| 19 bool isConstructedObject() => false; | 19 bool isConstructedObject() => false; |
| 20 | 20 |
| 21 bool isNum() => isInt() || isDouble(); | 21 bool isNum() => isInt() || isDouble(); |
| 22 bool isObject() => isList() || isMap() || isConstructedObject(); | 22 bool isObject() => isList() || isMap() || isConstructedObject(); |
| 23 bool isTrue() { | |
|
kasperl
2012/03/05 13:53:16
This smells like you should have two separate Bool
floitsch
2012/03/05 15:43:24
I will do that when I introduce caching for the co
| |
| 24 if (!isBool()) return false; | |
| 25 BoolConstant boolConstant = this; | |
| 26 return boolConstant.value; | |
| 27 } | |
| 28 bool isFalse() { | |
| 29 if (!isBool()) return false; | |
| 30 BoolConstant boolConstant = this; | |
| 31 return !boolConstant.value; | |
| 32 } | |
| 23 | 33 |
| 24 /** | 34 /** |
| 25 * Returns [:null:] if the operation is not supported on this constant. | 35 * Returns [:null:] if the operation is not supported on this constant. |
| 26 * The [op] operator is assumed to be a prefix operator. | 36 * The [op] operator is assumed to be a prefix operator. |
| 27 */ | 37 */ |
| 28 Constant unaryFold(String op) => null; | 38 Constant unaryFold(String op) => null; |
| 29 | 39 |
| 30 /** | 40 /** |
| 31 * Returns [:null:] if the operation is not supported on this constant, or | 41 * Returns [:null:] if the operation is not supported on this constant, or |
| 32 * if the operation would have thrown an exception. | 42 * if the operation would have thrown an exception. |
| 33 */ | 43 */ |
| 34 Constant binaryFold(String op, Constant other) { | 44 Constant binaryFold(String op, Constant other) { |
|
kasperl
2012/03/05 13:53:16
It sort of rubs me the wrong way to use a string f
floitsch
2012/03/05 15:43:24
will fix in another CL.
| |
| 35 if (op == "==" || op == "===") { | 45 if (op == "==" || op == "===") { |
| 36 return new BoolConstant(this == other); | 46 return new BoolConstant(this == other); |
| 37 } else if (op == "!=" || op == "!==") { | 47 } else if (op == "!=" || op == "!==") { |
| 38 return new BoolConstant(this != other); | 48 return new BoolConstant(this != other); |
| 39 } | 49 } |
| 40 } | 50 } |
| 41 | 51 |
| 42 abstract void writeJsCode(StringBuffer buffer, | 52 abstract void writeJsCode(StringBuffer buffer, |
| 43 CompileTimeConstantHandler handler); | 53 CompileTimeConstantHandler handler); |
| 44 } | 54 } |
| 45 | 55 |
| 46 class PrimitiveConstant extends Constant { | 56 class PrimitiveConstant extends Constant { |
| 47 // TODO(floitsch): this should be an abstract getter, but there is a bug in | 57 // TODO(floitsch): this should be an abstract getter, but there is a bug in |
| 48 // the VM. | 58 // the VM. |
|
kasperl
2012/03/05 13:53:16
Did you file this as a bug? Update comment with bu
floitsch
2012/03/05 15:43:24
bug is gone.
| |
| 49 get value() => null; | 59 get value() => null; |
| 50 const PrimitiveConstant(); | 60 const PrimitiveConstant(); |
| 51 | 61 |
| 52 bool operator ==(var other) { | 62 bool operator ==(var other) { |
| 53 if (other is !PrimitiveConstant) return false; | 63 if (other is !PrimitiveConstant) return false; |
| 54 PrimitiveConstant otherPrimitive = other; | 64 PrimitiveConstant otherPrimitive = other; |
| 55 // We use == instead of === so that DartStrings compare correctly. | 65 // We use == instead of === so that DartStrings compare correctly. |
| 56 return value == otherPrimitive.value; | 66 return value == otherPrimitive.value; |
| 57 } | 67 } |
| 68 | |
| 69 String toString() => value.toString(); | |
| 58 } | 70 } |
| 59 | 71 |
| 60 class NullConstant extends PrimitiveConstant { | 72 class NullConstant extends PrimitiveConstant { |
| 61 const NullConstant(); | 73 const NullConstant(); |
| 62 bool isNull() => true; | 74 bool isNull() => true; |
| 63 get value() => null; | 75 get value() => null; |
| 64 | 76 |
| 65 void writeJsCode(StringBuffer buffer, CompileTimeConstantHandler handler) { | 77 void writeJsCode(StringBuffer buffer, CompileTimeConstantHandler handler) { |
| 66 buffer.add("(void 0)"); | 78 buffer.add("(void 0)"); |
| 67 } | 79 } |
| (...skipping 39 matching lines...) Expand 10 before | Expand all | Expand 10 after Loading... | |
| 107 case "-": return new IntConstant(value - right); | 119 case "-": return new IntConstant(value - right); |
| 108 case "*": return new IntConstant(value * right); | 120 case "*": return new IntConstant(value * right); |
| 109 case "%": return new IntConstant(value % right); | 121 case "%": return new IntConstant(value % right); |
| 110 case "~/": return new IntConstant(value ~/ right); | 122 case "~/": return new IntConstant(value ~/ right); |
| 111 case "|": return new IntConstant(value | right); | 123 case "|": return new IntConstant(value | right); |
| 112 case "&": return new IntConstant(value & right); | 124 case "&": return new IntConstant(value & right); |
| 113 case "^": return new IntConstant(value ^ right); | 125 case "^": return new IntConstant(value ^ right); |
| 114 case "<<": | 126 case "<<": |
| 115 // TODO(floitsch): find a better way to guard against shifts to the | 127 // TODO(floitsch): find a better way to guard against shifts to the |
| 116 // left. | 128 // left. |
| 117 if (right > 100) null; | 129 if (right > 100) return null; |
| 118 if (right < 0) null; | 130 if (right < 0) return null; |
| 119 return new IntConstant(value << right); | 131 return new IntConstant(value << right); |
| 120 case ">>": | 132 case ">>": |
| 121 if (right < 0) return null; | 133 if (right < 0) return null; |
| 122 return new IntConstant(value >> right); | 134 return new IntConstant(value >> right); |
| 123 } | 135 } |
| 124 } else if (other.isDouble()) { | 136 } else if (other.isDouble()) { |
| 125 double right = rightNum; | 137 double right = rightNum; |
| 126 switch (op) { | 138 switch (op) { |
| 127 case "+": return new DoubleConstant(value + right); | 139 case "+": return new DoubleConstant(value + right); |
| 128 case "-": return new DoubleConstant(value - right); | 140 case "-": return new DoubleConstant(value - right); |
| (...skipping 160 matching lines...) Expand 10 before | Expand all | Expand 10 after Loading... | |
| 289 // TODO(floitsch): create a better hash. | 301 // TODO(floitsch): create a better hash. |
| 290 int hash = 0; | 302 int hash = 0; |
| 291 for (Constant input in entries) hash ^= input.hashCode(); | 303 for (Constant input in entries) hash ^= input.hashCode(); |
| 292 _hashCode = hash; | 304 _hashCode = hash; |
| 293 } | 305 } |
| 294 bool isList() => true; | 306 bool isList() => true; |
| 295 | 307 |
| 296 void writeJsCode(StringBuffer buffer, CompileTimeConstantHandler handler) { | 308 void writeJsCode(StringBuffer buffer, CompileTimeConstantHandler handler) { |
| 297 // TODO(floitsch): we should not need to go through the compiler to make | 309 // TODO(floitsch): we should not need to go through the compiler to make |
| 298 // the list constant. | 310 // the list constant. |
| 299 buffer.add(handler.compiler.namer.ISOLATE); | 311 String isolatePrototype = "${handler.compiler.namer.ISOLATE}.prototype"; |
| 300 buffer.add(".prototype.makeConstantList"); | 312 buffer.add("$isolatePrototype.makeConstantList"); |
| 301 buffer.add("(["); | 313 buffer.add("(["); |
| 302 for (int i = 0; i < entries.length; i++) { | 314 for (int i = 0; i < entries.length; i++) { |
| 303 if (i != 0) buffer.add(", "); | 315 if (i != 0) buffer.add(", "); |
| 304 Constant entry = entries[i]; | 316 Constant entry = entries[i]; |
| 305 if (entry.isObject()) { | 317 if (entry.isObject()) { |
| 306 handler.getNameForConstant(entry); | 318 String name = handler.getNameForConstant(entry); |
| 319 buffer.add("$isolatePrototype.$name"); | |
| 307 } else { | 320 } else { |
| 308 entry.writeJsCode(buffer, handler); | 321 entry.writeJsCode(buffer, handler); |
| 309 } | 322 } |
| 310 } | 323 } |
| 311 buffer.add("])"); | 324 buffer.add("])"); |
| 312 } | 325 } |
| 313 | 326 |
| 314 bool operator ==(var other) { | 327 bool operator ==(var other) { |
| 315 if (other is !ListConstant) return false; | 328 if (other is !ListConstant) return false; |
| 316 ListConstant otherList = other; | 329 ListConstant otherList = other; |
| (...skipping 94 matching lines...) Expand 10 before | Expand all | Expand 10 after Loading... | |
| 411 || work.element.kind == ElementKind.PARAMETER); | 424 || work.element.kind == ElementKind.PARAMETER); |
| 412 VariableElement element = work.element; | 425 VariableElement element = work.element; |
| 413 // Shortcut if it has already been compiled. | 426 // Shortcut if it has already been compiled. |
| 414 if (initialVariableValues.containsKey(element)) return; | 427 if (initialVariableValues.containsKey(element)) return; |
| 415 compileVariableWithDefinitions(element, work.resolutionTree); | 428 compileVariableWithDefinitions(element, work.resolutionTree); |
| 416 } | 429 } |
| 417 | 430 |
| 418 compileVariable(VariableElement element) { | 431 compileVariable(VariableElement element) { |
| 419 if (initialVariableValues.containsKey(element)) { | 432 if (initialVariableValues.containsKey(element)) { |
| 420 Constant result = initialVariableValues[element]; | 433 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; | 434 return result; |
| 425 } | 435 } |
| 426 // TODO(floitsch): keep track of currently compiling elements so that we | 436 // TODO(floitsch): keep track of currently compiling elements so that we |
| 427 // don't end up in an infinite loop: final x = y; final y = x; | 437 // don't end up in an infinite loop: final x = y; final y = x; |
| 428 TreeElements definitions = compiler.analyzeElement(element); | 438 TreeElements definitions = compiler.analyzeElement(element); |
| 429 Constant constant = compileVariableWithDefinitions(element, definitions); | 439 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; | 440 return constant; |
| 434 } | 441 } |
| 435 | 442 |
| 436 compileVariableWithDefinitions(VariableElement element, | 443 compileVariableWithDefinitions(VariableElement element, |
| 437 TreeElements definitions) { | 444 TreeElements definitions) { |
| 438 return measure(() { | 445 return measure(() { |
| 439 Node node = element.parseNode(compiler); | 446 Node node = element.parseNode(compiler); |
| 440 assert(node !== null); | 447 assert(node !== null); |
| 441 SendSet assignment = node.asSendSet(); | 448 SendSet assignment = node.asSendSet(); |
| 442 var value; | 449 var value; |
| (...skipping 220 matching lines...) Expand 10 before | Expand all | Expand 10 after Loading... | |
| 663 } | 670 } |
| 664 | 671 |
| 665 // TODO(floitsch): provide better error-messages. | 672 // TODO(floitsch): provide better error-messages. |
| 666 visitSend(Send send) { | 673 visitSend(Send send) { |
| 667 Element element = definitions[send]; | 674 Element element = definitions[send]; |
| 668 if (Elements.isStaticOrTopLevelField(element)) { | 675 if (Elements.isStaticOrTopLevelField(element)) { |
| 669 if (element.modifiers === null || | 676 if (element.modifiers === null || |
| 670 !element.modifiers.isFinal()) { | 677 !element.modifiers.isFinal()) { |
| 671 error(send); | 678 error(send); |
| 672 } | 679 } |
| 673 // TODO(floitsch): compileVariable temporarily returns primitives, so | 680 return constantHandler.compileVariable(element); |
| 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]; | |
| 679 } else if (send.isPrefix) { | 681 } else if (send.isPrefix) { |
| 680 assert(send.isOperator); | 682 assert(send.isOperator); |
| 681 Constant receiverConstant = evaluate(send.receiver); | 683 Constant receiverConstant = evaluate(send.receiver); |
| 682 Operator op = send.selector; | 684 Operator op = send.selector; |
| 683 Constant folded = receiverConstant.unaryFold(op.source.stringValue); | 685 Constant folded = receiverConstant.unaryFold(op.source.stringValue); |
| 684 if (folded === null) error(send); | 686 if (folded === null) error(send); |
| 685 return folded; | 687 return folded; |
| 686 } else if (send.isOperator && !send.isPostfix) { | 688 } else if (send.isOperator && !send.isPostfix) { |
| 687 assert(send.argumentCount() == 1); | 689 assert(send.argumentCount() == 1); |
| 688 Constant left = evaluate(send.receiver); | 690 Constant left = evaluate(send.receiver); |
| (...skipping 33 matching lines...) Expand 10 before | Expand all | Expand 10 after Loading... | |
| 722 arguments); | 724 arguments); |
| 723 } | 725 } |
| 724 | 726 |
| 725 error(Node node) { | 727 error(Node node) { |
| 726 // TODO(floitsch): get the list of constants that are currently compiled | 728 // TODO(floitsch): get the list of constants that are currently compiled |
| 727 // and present some kind of stack-trace. | 729 // and present some kind of stack-trace. |
| 728 MessageKind kind = MessageKind.NOT_A_COMPILE_TIME_CONSTANT; | 730 MessageKind kind = MessageKind.NOT_A_COMPILE_TIME_CONSTANT; |
| 729 compiler.reportError(node, new CompileTimeConstantError(kind, const [])); | 731 compiler.reportError(node, new CompileTimeConstantError(kind, const [])); |
| 730 } | 732 } |
| 731 } | 733 } |
| OLD | NEW |