| OLD | NEW |
| 1 // Copyright (c) 2012, the Dart project authors. Please see the AUTHORS file | 1 // Copyright (c) 2012, the Dart project authors. Please see the AUTHORS file |
| 2 // for details. All rights reserved. Use of this source code is governed by a | 2 // for details. All rights reserved. Use of this source code is governed by a |
| 3 // BSD-style license that can be found in the LICENSE file. | 3 // BSD-style license that can be found in the LICENSE file. |
| 4 | 4 |
| 5 class Constant implements Hashable { | 5 class Constant implements Hashable { |
| 6 const Constant(); | 6 const Constant(); |
| 7 | 7 |
| 8 bool isNull() => false; | 8 bool isNull() => false; |
| 9 bool isBool() => false; | 9 bool isBool() => false; |
| 10 bool isTrue() => false; | 10 bool isTrue() => false; |
| 11 bool isFalse() => false; | 11 bool isFalse() => false; |
| 12 bool isInt() => false; | 12 bool isInt() => false; |
| 13 bool isDouble() => false; | 13 bool isDouble() => false; |
| 14 bool isNum() => false; | 14 bool isNum() => false; |
| 15 bool isString() => false; | 15 bool isString() => false; |
| 16 bool isList() => false; | 16 bool isList() => false; |
| 17 bool isMap() => false; | 17 bool isMap() => false; |
| 18 bool isConstructedObject() => false; | 18 bool isConstructedObject() => false; |
| 19 bool isFunction() => false; | 19 bool isFunction() => false; |
| 20 /** 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. */ |
| 21 bool isPrimitive() => false; | 21 bool isPrimitive() => false; |
| 22 /** 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. */ |
| 23 bool isObject() => false; | 23 bool isObject() => false; |
| 24 | 24 |
| 25 bool isNaN() => false; | 25 bool isNaN() => false; |
| 26 bool isMinusZero() => false; |
| 26 | 27 |
| 27 abstract void _writeJsCode(CodeBuffer buffer, ConstantHandler handler); | 28 abstract void _writeJsCode(CodeBuffer buffer, ConstantHandler handler); |
| 28 /** | 29 /** |
| 29 * Unless the constant can be emitted multiple times (as for numbers and | 30 * Unless the constant can be emitted multiple times (as for numbers and |
| 30 * strings) adds its canonical name to the buffer. | 31 * strings) adds its canonical name to the buffer. |
| 31 */ | 32 */ |
| 32 abstract void _writeCanonicalizedJsCode(CodeBuffer buffer, | 33 abstract void _writeCanonicalizedJsCode(CodeBuffer buffer, |
| 33 ConstantHandler handler); | 34 ConstantHandler handler); |
| 34 abstract List<Constant> getDependencies(); | 35 abstract List<Constant> getDependencies(); |
| 35 } | 36 } |
| (...skipping 128 matching lines...) Expand 10 before | Expand all | Expand 10 after Loading... |
| 164 return const DoubleConstant._internal(0.0); | 165 return const DoubleConstant._internal(0.0); |
| 165 } else if (value == 1.0) { | 166 } else if (value == 1.0) { |
| 166 return const DoubleConstant._internal(1.0); | 167 return const DoubleConstant._internal(1.0); |
| 167 } else { | 168 } else { |
| 168 return new DoubleConstant._internal(value); | 169 return new DoubleConstant._internal(value); |
| 169 } | 170 } |
| 170 } | 171 } |
| 171 const DoubleConstant._internal(this.value); | 172 const DoubleConstant._internal(this.value); |
| 172 bool isDouble() => true; | 173 bool isDouble() => true; |
| 173 bool isNaN() => value.isNaN(); | 174 bool isNaN() => value.isNaN(); |
| 175 // We need to check for the negative sign since -0.0 == 0.0. |
| 176 bool isMinusZero() => value == 0.0 && value.isNegative(); |
| 174 | 177 |
| 175 void _writeJsCode(CodeBuffer buffer, ConstantHandler handler) { | 178 void _writeJsCode(CodeBuffer buffer, ConstantHandler handler) { |
| 176 if (value.isNaN()) { | 179 if (value.isNaN()) { |
| 177 buffer.add("(0/0)"); | 180 buffer.add("(0/0)"); |
| 178 } else if (value == double.INFINITY) { | 181 } else if (value == double.INFINITY) { |
| 179 buffer.add("(1/0)"); | 182 buffer.add("(1/0)"); |
| 180 } else if (value == -double.INFINITY) { | 183 } else if (value == -double.INFINITY) { |
| 181 buffer.add("(-1/0)"); | 184 buffer.add("(-1/0)"); |
| 182 } else { | 185 } else { |
| 183 buffer.add("$value"); | 186 buffer.add("$value"); |
| (...skipping 17 matching lines...) Expand all Loading... |
| 201 DartString toDartString() => new DartString.literal(value.toString()); | 204 DartString toDartString() => new DartString.literal(value.toString()); |
| 202 } | 205 } |
| 203 | 206 |
| 204 class BoolConstant extends PrimitiveConstant { | 207 class BoolConstant extends PrimitiveConstant { |
| 205 factory BoolConstant(value) { | 208 factory BoolConstant(value) { |
| 206 return value ? new TrueConstant() : new FalseConstant(); | 209 return value ? new TrueConstant() : new FalseConstant(); |
| 207 } | 210 } |
| 208 const BoolConstant._internal(); | 211 const BoolConstant._internal(); |
| 209 bool isBool() => true; | 212 bool isBool() => true; |
| 210 | 213 |
| 211 BoolConstant unaryFold(String op) { | |
| 212 if (op == "!") return new BoolConstant(!value); | |
| 213 return null; | |
| 214 } | |
| 215 | |
| 216 abstract BoolConstant negate(); | 214 abstract BoolConstant negate(); |
| 217 } | 215 } |
| 218 | 216 |
| 219 class TrueConstant extends BoolConstant { | 217 class TrueConstant extends BoolConstant { |
| 220 final bool value = true; | 218 final bool value = true; |
| 221 | 219 |
| 222 factory TrueConstant() => const TrueConstant._internal(); | 220 factory TrueConstant() => const TrueConstant._internal(); |
| 223 const TrueConstant._internal() : super._internal(); | 221 const TrueConstant._internal() : super._internal(); |
| 224 bool isTrue() => true; | 222 bool isTrue() => true; |
| 225 | 223 |
| (...skipping 279 matching lines...) Expand 10 before | Expand all | Expand 10 after Loading... |
| 505 int hashCode() => _hashCode; | 503 int hashCode() => _hashCode; |
| 506 List<Constant> getDependencies() => fields; | 504 List<Constant> getDependencies() => fields; |
| 507 } | 505 } |
| 508 | 506 |
| 509 /** | 507 /** |
| 510 * The [ConstantHandler] keeps track of compile-time constants, | 508 * The [ConstantHandler] keeps track of compile-time constants, |
| 511 * initializations of global and static fields, and default values of | 509 * initializations of global and static fields, and default values of |
| 512 * optional parameters. | 510 * optional parameters. |
| 513 */ | 511 */ |
| 514 class ConstantHandler extends CompilerTask { | 512 class ConstantHandler extends CompilerTask { |
| 513 final ConstantSystem constantSystem; |
| 515 // Contains the initial value of fields. Must contain all static and global | 514 // Contains the initial value of fields. Must contain all static and global |
| 516 // initializations of used fields. May contain caches for instance fields. | 515 // initializations of used fields. May contain caches for instance fields. |
| 517 final Map<VariableElement, Constant> initialVariableValues; | 516 final Map<VariableElement, Constant> initialVariableValues; |
| 518 | 517 |
| 519 // Map from compile-time constants to their JS name. | 518 // Map from compile-time constants to their JS name. |
| 520 final Map<Constant, String> compiledConstants; | 519 final Map<Constant, String> compiledConstants; |
| 521 | 520 |
| 522 // The set of variable elements that are in the process of being computed. | 521 // The set of variable elements that are in the process of being computed. |
| 523 final Set<VariableElement> pendingVariables; | 522 final Set<VariableElement> pendingVariables; |
| 524 | 523 |
| 525 ConstantHandler(Compiler compiler) | 524 ConstantHandler(Compiler compiler, this.constantSystem) |
| 526 : initialVariableValues = new Map<VariableElement, Dynamic>(), | 525 : initialVariableValues = new Map<VariableElement, Dynamic>(), |
| 527 compiledConstants = new Map<Constant, String>(), | 526 compiledConstants = new Map<Constant, String>(), |
| 528 pendingVariables = new Set<VariableElement>(), | 527 pendingVariables = new Set<VariableElement>(), |
| 529 super(compiler); | 528 super(compiler); |
| 530 String get name => 'ConstantHandler'; | 529 String get name => 'ConstantHandler'; |
| 531 | 530 |
| 532 void registerCompileTimeConstant(Constant constant) { | 531 void registerCompileTimeConstant(Constant constant) { |
| 533 Function ifAbsentThunk = (() { | 532 Function ifAbsentThunk = (() { |
| 534 return constant.isFunction() | 533 return constant.isFunction() |
| 535 ? null : compiler.namer.getFreshGlobalName("CTC"); | 534 ? null : compiler.namer.getFreshGlobalName("CTC"); |
| (...skipping 55 matching lines...) Expand 10 before | Expand all | Expand 10 after Loading... |
| 591 } | 590 } |
| 592 initialVariableValues[element] = value; | 591 initialVariableValues[element] = value; |
| 593 pendingVariables.remove(element); | 592 pendingVariables.remove(element); |
| 594 return value; | 593 return value; |
| 595 }); | 594 }); |
| 596 } | 595 } |
| 597 | 596 |
| 598 Constant compileNodeWithDefinitions(Node node, TreeElements definitions) { | 597 Constant compileNodeWithDefinitions(Node node, TreeElements definitions) { |
| 599 return measure(() { | 598 return measure(() { |
| 600 assert(node !== null); | 599 assert(node !== null); |
| 601 CompileTimeConstantEvaluator evaluator = | 600 CompileTimeConstantEvaluator evaluator = new CompileTimeConstantEvaluator( |
| 602 new CompileTimeConstantEvaluator(definitions, compiler); | 601 constantSystem, definitions, compiler); |
| 603 return evaluator.evaluate(node); | 602 return evaluator.evaluate(node); |
| 604 }); | 603 }); |
| 605 } | 604 } |
| 606 | 605 |
| 607 /** Attempts to compile a constant expression. Returns null if not possible */ | 606 /** Attempts to compile a constant expression. Returns null if not possible */ |
| 608 Constant tryCompileNodeWithDefinitions(Node node, TreeElements definitions) { | 607 Constant tryCompileNodeWithDefinitions(Node node, TreeElements definitions) { |
| 609 return measure(() { | 608 return measure(() { |
| 610 assert(node !== null); | 609 assert(node !== null); |
| 611 try { | 610 try { |
| 612 TryCompileTimeConstantEvaluator evaluator = | 611 TryCompileTimeConstantEvaluator evaluator = |
| 613 new TryCompileTimeConstantEvaluator(definitions, compiler); | 612 new TryCompileTimeConstantEvaluator(constantSystem, |
| 613 definitions, |
| 614 compiler); |
| 614 return evaluator.evaluate(node); | 615 return evaluator.evaluate(node); |
| 615 } on CompileTimeConstantError catch (exn) { | 616 } on CompileTimeConstantError catch (exn) { |
| 616 return null; | 617 return null; |
| 617 } | 618 } |
| 618 }); | 619 }); |
| 619 } | 620 } |
| 620 | 621 |
| 621 /** | 622 /** |
| 622 * Returns a [List] of static non final fields that need to be initialized. | 623 * Returns a [List] of static non final fields that need to be initialized. |
| 623 * The list must be evaluated in order since the fields might depend on each | 624 * The list must be evaluated in order since the fields might depend on each |
| (...skipping 116 matching lines...) Expand 10 before | Expand all | Expand 10 after Loading... |
| 740 } | 741 } |
| 741 } | 742 } |
| 742 } | 743 } |
| 743 | 744 |
| 744 String getJsConstructor(ClassElement element) { | 745 String getJsConstructor(ClassElement element) { |
| 745 return compiler.namer.isolatePropertiesAccess(element); | 746 return compiler.namer.isolatePropertiesAccess(element); |
| 746 } | 747 } |
| 747 } | 748 } |
| 748 | 749 |
| 749 class CompileTimeConstantEvaluator extends AbstractVisitor { | 750 class CompileTimeConstantEvaluator extends AbstractVisitor { |
| 751 final ConstantSystem constantSystem; |
| 750 final TreeElements elements; | 752 final TreeElements elements; |
| 751 final Compiler compiler; | 753 final Compiler compiler; |
| 752 | 754 |
| 753 CompileTimeConstantEvaluator(this.elements, this.compiler); | 755 CompileTimeConstantEvaluator(this.constantSystem, |
| 756 this.elements, |
| 757 this.compiler); |
| 754 | 758 |
| 755 Constant evaluate(Node node) { | 759 Constant evaluate(Node node) { |
| 756 return node.accept(this); | 760 return node.accept(this); |
| 757 } | 761 } |
| 758 | 762 |
| 759 visitNode(Node node) { | 763 visitNode(Node node) { |
| 760 error(node); | 764 error(node); |
| 761 } | 765 } |
| 762 | 766 |
| 763 Constant visitLiteralBool(LiteralBool node) { | 767 Constant visitLiteralBool(LiteralBool node) { |
| 764 return new BoolConstant(node.value); | 768 return constantSystem.createBool(node.value); |
| 765 } | 769 } |
| 766 | 770 |
| 767 Constant visitLiteralDouble(LiteralDouble node) { | 771 Constant visitLiteralDouble(LiteralDouble node) { |
| 768 return new DoubleConstant(node.value); | 772 return constantSystem.createDouble(node.value); |
| 769 } | 773 } |
| 770 | 774 |
| 771 Constant visitLiteralInt(LiteralInt node) { | 775 Constant visitLiteralInt(LiteralInt node) { |
| 772 return new IntConstant(node.value); | 776 return constantSystem.createInt(node.value); |
| 773 } | 777 } |
| 774 | 778 |
| 775 Constant visitLiteralList(LiteralList node) { | 779 Constant visitLiteralList(LiteralList node) { |
| 776 if (!node.isConst()) error(node); | 780 if (!node.isConst()) error(node); |
| 777 List<Constant> arguments = <Constant>[]; | 781 List<Constant> arguments = <Constant>[]; |
| 778 for (Link<Node> link = node.elements.nodes; | 782 for (Link<Node> link = node.elements.nodes; |
| 779 !link.isEmpty(); | 783 !link.isEmpty(); |
| 780 link = link.tail) { | 784 link = link.tail) { |
| 781 arguments.add(evaluate(link.head)); | 785 arguments.add(evaluate(link.head)); |
| 782 } | 786 } |
| (...skipping 42 matching lines...) Expand 10 before | Expand all | Expand 10 after Loading... |
| 825 classElement.ensureResolved(compiler); | 829 classElement.ensureResolved(compiler); |
| 826 // TODO(floitsch): copy over the generic type. | 830 // TODO(floitsch): copy over the generic type. |
| 827 DartType type = new InterfaceType(classElement); | 831 DartType type = new InterfaceType(classElement); |
| 828 compiler.registerInstantiatedClass(classElement); | 832 compiler.registerInstantiatedClass(classElement); |
| 829 Constant constant = new MapConstant(type, keysList, values, protoValue); | 833 Constant constant = new MapConstant(type, keysList, values, protoValue); |
| 830 compiler.constantHandler.registerCompileTimeConstant(constant); | 834 compiler.constantHandler.registerCompileTimeConstant(constant); |
| 831 return constant; | 835 return constant; |
| 832 } | 836 } |
| 833 | 837 |
| 834 Constant visitLiteralNull(LiteralNull node) { | 838 Constant visitLiteralNull(LiteralNull node) { |
| 835 return new NullConstant(); | 839 return constantSystem.createNull(); |
| 836 } | 840 } |
| 837 | 841 |
| 838 Constant visitLiteralString(LiteralString node) { | 842 Constant visitLiteralString(LiteralString node) { |
| 839 return new StringConstant(node.dartString, node); | 843 return constantSystem.createString(node.dartString, node); |
| 840 } | 844 } |
| 841 | 845 |
| 842 Constant visitStringJuxtaposition(StringJuxtaposition node) { | 846 Constant visitStringJuxtaposition(StringJuxtaposition node) { |
| 843 StringConstant left = evaluate(node.first); | 847 StringConstant left = evaluate(node.first); |
| 844 StringConstant right = evaluate(node.second); | 848 StringConstant right = evaluate(node.second); |
| 845 return new StringConstant(new DartString.concat(left.value, right.value), | 849 return constantSystem.createString( |
| 846 node); | 850 new DartString.concat(left.value, right.value), node); |
| 847 } | 851 } |
| 848 | 852 |
| 849 Constant visitStringInterpolation(StringInterpolation node) { | 853 Constant visitStringInterpolation(StringInterpolation node) { |
| 850 StringConstant initialString = evaluate(node.string); | 854 StringConstant initialString = evaluate(node.string); |
| 851 DartString accumulator = initialString.value; | 855 DartString accumulator = initialString.value; |
| 852 for (StringInterpolationPart part in node.parts) { | 856 for (StringInterpolationPart part in node.parts) { |
| 853 Constant expression = evaluate(part.expression); | 857 Constant expression = evaluate(part.expression); |
| 854 DartString expressionString; | 858 DartString expressionString; |
| 855 if (expression.isNum() || expression.isBool()) { | 859 if (expression.isNum() || expression.isBool()) { |
| 856 PrimitiveConstant primitive = expression; | 860 PrimitiveConstant primitive = expression; |
| 857 expressionString = new DartString.literal(primitive.value.toString()); | 861 expressionString = new DartString.literal(primitive.value.toString()); |
| 858 } else if (expression.isString()) { | 862 } else if (expression.isString()) { |
| 859 PrimitiveConstant primitive = expression; | 863 PrimitiveConstant primitive = expression; |
| 860 expressionString = primitive.value; | 864 expressionString = primitive.value; |
| 861 } else { | 865 } else { |
| 862 error(part.expression); | 866 error(part.expression); |
| 863 } | 867 } |
| 864 accumulator = new DartString.concat(accumulator, expressionString); | 868 accumulator = new DartString.concat(accumulator, expressionString); |
| 865 StringConstant partString = evaluate(part.string); | 869 StringConstant partString = evaluate(part.string); |
| 866 accumulator = new DartString.concat(accumulator, partString.value); | 870 accumulator = new DartString.concat(accumulator, partString.value); |
| 867 }; | 871 }; |
| 868 return new StringConstant(accumulator, node); | 872 return constantSystem.createString(accumulator, node); |
| 869 } | 873 } |
| 870 | 874 |
| 871 // TODO(floitsch): provide better error-messages. | 875 // TODO(floitsch): provide better error-messages. |
| 872 Constant visitSend(Send send) { | 876 Constant visitSend(Send send) { |
| 873 Element element = elements[send]; | 877 Element element = elements[send]; |
| 874 if (Elements.isStaticOrTopLevelField(element)) { | 878 if (Elements.isStaticOrTopLevelField(element)) { |
| 875 if (element.modifiers === null || | 879 if (element.modifiers === null || |
| 876 // TODO(johnniwinther): This should eventually be [isConst]. | 880 // TODO(johnniwinther): This should eventually be [isConst]. |
| 877 !element.modifiers.isFinalOrConst()) { | 881 !element.modifiers.isFinalOrConst()) { |
| 878 error(send); | 882 error(send); |
| 879 } | 883 } |
| 880 return compiler.compileVariable(element); | 884 return compiler.compileVariable(element); |
| 881 } else if (Elements.isStaticOrTopLevelFunction(element) | 885 } else if (Elements.isStaticOrTopLevelFunction(element) |
| 882 && send.isPropertyAccess) { | 886 && send.isPropertyAccess) { |
| 883 compiler.codegenWorld.staticFunctionsNeedingGetter.add(element); | 887 compiler.codegenWorld.staticFunctionsNeedingGetter.add(element); |
| 884 Constant constant = new FunctionConstant(element); | 888 Constant constant = new FunctionConstant(element); |
| 885 compiler.constantHandler.registerCompileTimeConstant(constant); | 889 compiler.constantHandler.registerCompileTimeConstant(constant); |
| 886 return constant; | 890 return constant; |
| 887 } else if (send.isPrefix) { | 891 } else if (send.isPrefix) { |
| 888 assert(send.isOperator); | 892 assert(send.isOperator); |
| 889 Constant receiverConstant = evaluate(send.receiver); | 893 Constant receiverConstant = evaluate(send.receiver); |
| 890 Operator op = send.selector; | 894 Operator op = send.selector; |
| 891 Constant folded; | 895 Constant folded; |
| 892 switch (op.source.stringValue) { | 896 switch (op.source.stringValue) { |
| 893 case "!": | 897 case "!": |
| 894 folded = const NotOperation().fold(receiverConstant); | 898 folded = constantSystem.not.fold(receiverConstant); |
| 895 break; | 899 break; |
| 896 case "-": | 900 case "-": |
| 897 folded = const NegateOperation().fold(receiverConstant); | 901 folded = constantSystem.negate.fold(receiverConstant); |
| 898 break; | 902 break; |
| 899 case "~": | 903 case "~": |
| 900 folded = const BitNotOperation().fold(receiverConstant); | 904 folded = constantSystem.bitNot.fold(receiverConstant); |
| 901 break; | 905 break; |
| 902 default: | 906 default: |
| 903 compiler.internalError("Unexpected operator.", node: op); | 907 compiler.internalError("Unexpected operator.", node: op); |
| 904 break; | 908 break; |
| 905 } | 909 } |
| 906 if (folded === null) error(send); | 910 if (folded === null) error(send); |
| 907 return folded; | 911 return folded; |
| 908 } else if (send.isOperator && !send.isPostfix) { | 912 } else if (send.isOperator && !send.isPostfix) { |
| 909 assert(send.argumentCount() == 1); | 913 assert(send.argumentCount() == 1); |
| 910 Constant left = evaluate(send.receiver); | 914 Constant left = evaluate(send.receiver); |
| 911 Constant right = evaluate(send.argumentsNode.nodes.head); | 915 Constant right = evaluate(send.argumentsNode.nodes.head); |
| 912 Operator op = send.selector.asOperator(); | 916 Operator op = send.selector.asOperator(); |
| 913 Constant folded = null; | 917 Constant folded = null; |
| 914 switch (op.source.stringValue) { | 918 switch (op.source.stringValue) { |
| 915 case "+": | 919 case "+": |
| 916 folded = const AddOperation().fold(left, right); | 920 folded = constantSystem.add.fold(left, right); |
| 917 break; | 921 break; |
| 918 case "-": | 922 case "-": |
| 919 folded = const SubtractOperation().fold(left, right); | 923 folded = constantSystem.subtract.fold(left, right); |
| 920 break; | 924 break; |
| 921 case "*": | 925 case "*": |
| 922 folded = const MultiplyOperation().fold(left, right); | 926 folded = constantSystem.multiply.fold(left, right); |
| 923 break; | 927 break; |
| 924 case "/": | 928 case "/": |
| 925 folded = const DivideOperation().fold(left, right); | 929 folded = constantSystem.divide.fold(left, right); |
| 926 break; | 930 break; |
| 927 case "%": | 931 case "%": |
| 928 folded = const ModuloOperation().fold(left, right); | 932 folded = constantSystem.modulo.fold(left, right); |
| 929 break; | 933 break; |
| 930 case "~/": | 934 case "~/": |
| 931 folded = const TruncatingDivideOperation().fold(left, right); | 935 folded = constantSystem.truncatingDivide.fold(left, right); |
| 932 break; | 936 break; |
| 933 case "|": | 937 case "|": |
| 934 folded = const BitOrOperation().fold(left, right); | 938 folded = constantSystem.bitOr.fold(left, right); |
| 935 break; | 939 break; |
| 936 case "&": | 940 case "&": |
| 937 folded = const BitAndOperation().fold(left, right); | 941 folded = constantSystem.bitAnd.fold(left, right); |
| 938 break; | 942 break; |
| 939 case "^": | 943 case "^": |
| 940 folded = const BitXorOperation().fold(left, right); | 944 folded = constantSystem.bitXor.fold(left, right); |
| 941 break; | 945 break; |
| 942 case "||": | 946 case "||": |
| 943 folded = const BooleanOr().fold(left, right); | 947 folded = constantSystem.booleanOr.fold(left, right); |
| 944 break; | 948 break; |
| 945 case "&&": | 949 case "&&": |
| 946 folded = const BooleanAnd().fold(left, right); | 950 folded = constantSystem.booleanAnd.fold(left, right); |
| 947 break; | 951 break; |
| 948 case "<<": | 952 case "<<": |
| 949 folded = const ShiftLeftOperation().fold(left, right); | 953 folded = constantSystem.shiftLeft.fold(left, right); |
| 950 break; | 954 break; |
| 951 case ">>": | 955 case ">>": |
| 952 folded = const ShiftRightOperation().fold(left, right); | 956 folded = constantSystem.shiftRight.fold(left, right); |
| 953 break; | 957 break; |
| 954 case "<": | 958 case "<": |
| 955 folded = const LessOperation().fold(left, right); | 959 folded = constantSystem.less.fold(left, right); |
| 956 break; | 960 break; |
| 957 case "<=": | 961 case "<=": |
| 958 folded = const LessEqualOperation().fold(left, right); | 962 folded = constantSystem.lessEqual.fold(left, right); |
| 959 break; | 963 break; |
| 960 case ">": | 964 case ">": |
| 961 folded = const GreaterOperation().fold(left, right); | 965 folded = constantSystem.greater.fold(left, right); |
| 962 break; | 966 break; |
| 963 case ">=": | 967 case ">=": |
| 964 folded = const GreaterEqualOperation().fold(left, right); | 968 folded = constantSystem.greaterEqual.fold(left, right); |
| 965 break; | 969 break; |
| 966 case "==": | 970 case "==": |
| 967 if (left.isPrimitive() && right.isPrimitive()) { | 971 if (left.isPrimitive() && right.isPrimitive()) { |
| 968 folded = const EqualsOperation().fold(left, right); | 972 folded = constantSystem.equal.fold(left, right); |
| 969 } | 973 } |
| 970 break; | 974 break; |
| 971 case "===": | 975 case "===": |
| 972 if (left.isPrimitive() && right.isPrimitive()) { | 976 if (left.isPrimitive() && right.isPrimitive()) { |
| 973 folded = const IdentityOperation().fold(left, right); | 977 folded = constantSystem.identity.fold(left, right); |
| 974 } | 978 } |
| 975 break; | 979 break; |
| 976 case "!=": | 980 case "!=": |
| 977 if (left.isPrimitive() && right.isPrimitive()) { | 981 if (left.isPrimitive() && right.isPrimitive()) { |
| 978 BoolConstant areEquals = const EqualsOperation().fold(left, right); | 982 BoolConstant areEquals = constantSystem.equal.fold(left, right); |
| 979 if (areEquals === null) { | 983 if (areEquals === null) { |
| 980 folded = null; | 984 folded = null; |
| 981 } else { | 985 } else { |
| 982 folded = areEquals.negate(); | 986 folded = areEquals.negate(); |
| 983 } | 987 } |
| 984 } | 988 } |
| 985 break; | 989 break; |
| 986 case "!==": | 990 case "!==": |
| 987 if (left.isPrimitive() && right.isPrimitive()) { | 991 if (left.isPrimitive() && right.isPrimitive()) { |
| 988 BoolConstant areIdentical = | 992 BoolConstant areIdentical = |
| 989 const IdentityOperation().fold(left, right); | 993 constantSystem.identity.fold(left, right); |
| 990 if (areIdentical === null) { | 994 if (areIdentical === null) { |
| 991 folded = null; | 995 folded = null; |
| 992 } else { | 996 } else { |
| 993 folded = areIdentical.negate(); | 997 folded = areIdentical.negate(); |
| 994 } | 998 } |
| 995 } | 999 } |
| 996 break; | 1000 break; |
| 997 } | 1001 } |
| 998 if (folded === null) error(send); | 1002 if (folded === null) error(send); |
| 999 return folded; | 1003 return folded; |
| (...skipping 32 matching lines...) Expand 10 before | Expand all | Expand 10 after Loading... |
| 1032 if (classElement.isInterface()) { | 1036 if (classElement.isInterface()) { |
| 1033 compiler.resolver.resolveMethodElement(constructor); | 1037 compiler.resolver.resolveMethodElement(constructor); |
| 1034 constructor = constructor.defaultImplementation; | 1038 constructor = constructor.defaultImplementation; |
| 1035 classElement = constructor.getEnclosingClass(); | 1039 classElement = constructor.getEnclosingClass(); |
| 1036 } | 1040 } |
| 1037 | 1041 |
| 1038 Selector selector = elements.getSelector(send); | 1042 Selector selector = elements.getSelector(send); |
| 1039 List<Constant> arguments = | 1043 List<Constant> arguments = |
| 1040 evaluateArgumentsToConstructor(selector, send.arguments, constructor); | 1044 evaluateArgumentsToConstructor(selector, send.arguments, constructor); |
| 1041 ConstructorEvaluator evaluator = | 1045 ConstructorEvaluator evaluator = |
| 1042 new ConstructorEvaluator(constructor, compiler); | 1046 new ConstructorEvaluator(constructor, constantSystem, compiler); |
| 1043 evaluator.evaluateConstructorFieldValues(arguments); | 1047 evaluator.evaluateConstructorFieldValues(arguments); |
| 1044 List<Constant> jsNewArguments = evaluator.buildJsNewArguments(classElement); | 1048 List<Constant> jsNewArguments = evaluator.buildJsNewArguments(classElement); |
| 1045 | 1049 |
| 1046 compiler.registerInstantiatedClass(classElement); | 1050 compiler.registerInstantiatedClass(classElement); |
| 1047 // TODO(floitsch): take generic types into account. | 1051 // TODO(floitsch): take generic types into account. |
| 1048 DartType type = classElement.computeType(compiler); | 1052 DartType type = classElement.computeType(compiler); |
| 1049 Constant constant = new ConstructedConstant(type, jsNewArguments); | 1053 Constant constant = new ConstructedConstant(type, jsNewArguments); |
| 1050 compiler.constantHandler.registerCompileTimeConstant(constant); | 1054 compiler.constantHandler.registerCompileTimeConstant(constant); |
| 1051 return constant; | 1055 return constant; |
| 1052 } | 1056 } |
| 1053 | 1057 |
| 1054 Constant visitParenthesizedExpression(ParenthesizedExpression node) { | 1058 Constant visitParenthesizedExpression(ParenthesizedExpression node) { |
| 1055 return node.expression.accept(this); | 1059 return node.expression.accept(this); |
| 1056 } | 1060 } |
| 1057 | 1061 |
| 1058 error(Node node) { | 1062 error(Node node) { |
| 1059 // TODO(floitsch): get the list of constants that are currently compiled | 1063 // TODO(floitsch): get the list of constants that are currently compiled |
| 1060 // and present some kind of stack-trace. | 1064 // and present some kind of stack-trace. |
| 1061 MessageKind kind = MessageKind.NOT_A_COMPILE_TIME_CONSTANT; | 1065 MessageKind kind = MessageKind.NOT_A_COMPILE_TIME_CONSTANT; |
| 1062 compiler.reportError(node, new CompileTimeConstantError(kind, const [])); | 1066 compiler.reportError(node, new CompileTimeConstantError(kind, const [])); |
| 1063 } | 1067 } |
| 1064 } | 1068 } |
| 1065 | 1069 |
| 1066 class TryCompileTimeConstantEvaluator extends CompileTimeConstantEvaluator { | 1070 class TryCompileTimeConstantEvaluator extends CompileTimeConstantEvaluator { |
| 1067 TryCompileTimeConstantEvaluator(TreeElements elements, Compiler compiler): | 1071 TryCompileTimeConstantEvaluator(ConstantSystem constantSystem, |
| 1068 super(elements, compiler); | 1072 TreeElements elements, |
| 1073 Compiler compiler): |
| 1074 super(constantSystem, elements, compiler); |
| 1069 | 1075 |
| 1070 error(Node node) { | 1076 error(Node node) { |
| 1071 // Just fail without reporting it anywhere. | 1077 // Just fail without reporting it anywhere. |
| 1072 throw new CompileTimeConstantError( | 1078 throw new CompileTimeConstantError( |
| 1073 MessageKind.NOT_A_COMPILE_TIME_CONSTANT, const []); | 1079 MessageKind.NOT_A_COMPILE_TIME_CONSTANT, const []); |
| 1074 } | 1080 } |
| 1075 } | 1081 } |
| 1076 | 1082 |
| 1077 class ConstructorEvaluator extends CompileTimeConstantEvaluator { | 1083 class ConstructorEvaluator extends CompileTimeConstantEvaluator { |
| 1078 FunctionElement constructor; | 1084 FunctionElement constructor; |
| 1079 final Map<Element, Constant> definitions; | 1085 final Map<Element, Constant> definitions; |
| 1080 final Map<Element, Constant> fieldValues; | 1086 final Map<Element, Constant> fieldValues; |
| 1081 | 1087 |
| 1082 ConstructorEvaluator(FunctionElement constructor, Compiler compiler) | 1088 ConstructorEvaluator(FunctionElement constructor, |
| 1089 ConstantSystem constantSystem, |
| 1090 Compiler compiler) |
| 1083 : this.constructor = constructor, | 1091 : this.constructor = constructor, |
| 1084 this.definitions = new Map<Element, Constant>(), | 1092 this.definitions = new Map<Element, Constant>(), |
| 1085 this.fieldValues = new Map<Element, Constant>(), | 1093 this.fieldValues = new Map<Element, Constant>(), |
| 1086 super(compiler.resolver.resolveMethodElement(constructor), | 1094 super(constantSystem, |
| 1095 compiler.resolver.resolveMethodElement(constructor), |
| 1087 compiler); | 1096 compiler); |
| 1088 | 1097 |
| 1089 Constant visitSend(Send send) { | 1098 Constant visitSend(Send send) { |
| 1090 Element element = elements[send]; | 1099 Element element = elements[send]; |
| 1091 if (Elements.isLocal(element)) { | 1100 if (Elements.isLocal(element)) { |
| 1092 Constant constant = definitions[element]; | 1101 Constant constant = definitions[element]; |
| 1093 if (constant === null) { | 1102 if (constant === null) { |
| 1094 compiler.internalError("Local variable without value", node: send); | 1103 compiler.internalError("Local variable without value", node: send); |
| 1095 } | 1104 } |
| 1096 return constant; | 1105 return constant; |
| (...skipping 19 matching lines...) Expand all Loading... |
| 1116 } | 1125 } |
| 1117 }); | 1126 }); |
| 1118 } | 1127 } |
| 1119 | 1128 |
| 1120 void evaluateSuperOrRedirectSend(Selector selector, | 1129 void evaluateSuperOrRedirectSend(Selector selector, |
| 1121 Link<Node> arguments, | 1130 Link<Node> arguments, |
| 1122 FunctionElement targetConstructor) { | 1131 FunctionElement targetConstructor) { |
| 1123 List<Constant> compiledArguments = | 1132 List<Constant> compiledArguments = |
| 1124 evaluateArgumentsToConstructor(selector, arguments, targetConstructor); | 1133 evaluateArgumentsToConstructor(selector, arguments, targetConstructor); |
| 1125 | 1134 |
| 1126 ConstructorEvaluator evaluator = | 1135 ConstructorEvaluator evaluator = new ConstructorEvaluator( |
| 1127 new ConstructorEvaluator(targetConstructor, compiler); | 1136 targetConstructor, constantSystem, compiler); |
| 1128 evaluator.evaluateConstructorFieldValues(compiledArguments); | 1137 evaluator.evaluateConstructorFieldValues(compiledArguments); |
| 1129 // Copy over the fieldValues from the super/redirect-constructor. | 1138 // Copy over the fieldValues from the super/redirect-constructor. |
| 1130 evaluator.fieldValues.forEach((key, value) => fieldValues[key] = value); | 1139 evaluator.fieldValues.forEach((key, value) => fieldValues[key] = value); |
| 1131 } | 1140 } |
| 1132 | 1141 |
| 1133 /** | 1142 /** |
| 1134 * Runs through the initializers of the given [constructor] and updates | 1143 * Runs through the initializers of the given [constructor] and updates |
| 1135 * the [fieldValues] map. | 1144 * the [fieldValues] map. |
| 1136 */ | 1145 */ |
| 1137 void evaluateConstructorInitializers() { | 1146 void evaluateConstructorInitializers() { |
| (...skipping 72 matching lines...) Expand 10 before | Expand all | Expand 10 after Loading... |
| 1210 Constant fieldValue = fieldValues[field]; | 1219 Constant fieldValue = fieldValues[field]; |
| 1211 if (fieldValue === null) { | 1220 if (fieldValue === null) { |
| 1212 // Use the default value. | 1221 // Use the default value. |
| 1213 fieldValue = compiler.compileVariable(field); | 1222 fieldValue = compiler.compileVariable(field); |
| 1214 } | 1223 } |
| 1215 jsNewArguments.add(fieldValue); | 1224 jsNewArguments.add(fieldValue); |
| 1216 }); | 1225 }); |
| 1217 return jsNewArguments; | 1226 return jsNewArguments; |
| 1218 } | 1227 } |
| 1219 } | 1228 } |
| OLD | NEW |