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 |