| 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; |
| (...skipping 514 matching lines...) Expand 10 before | Expand all | Expand 10 after Loading... |
| 525 initialVariableValues[element] = value; | 525 initialVariableValues[element] = value; |
| 526 pendingVariables.remove(element); | 526 pendingVariables.remove(element); |
| 527 return value; | 527 return value; |
| 528 }); | 528 }); |
| 529 } | 529 } |
| 530 | 530 |
| 531 Constant compileNodeWithDefinitions(Node node, TreeElements definitions) { | 531 Constant compileNodeWithDefinitions(Node node, TreeElements definitions) { |
| 532 return measure(() { | 532 return measure(() { |
| 533 assert(node !== null); | 533 assert(node !== null); |
| 534 CompileTimeConstantEvaluator evaluator = | 534 CompileTimeConstantEvaluator evaluator = |
| 535 new CompileTimeConstantEvaluator(this, definitions, compiler); | 535 new CompileTimeConstantEvaluator(definitions, compiler); |
| 536 return evaluator.evaluate(node); | 536 return evaluator.evaluate(node); |
| 537 }); | 537 }); |
| 538 } | 538 } |
| 539 | 539 |
| 540 /** | 540 /** |
| 541 * Returns a [List] of static non final fields that need to be initialized. | 541 * Returns a [List] of static non final fields that need to be initialized. |
| 542 * The list must be evaluated in order since the fields might depend on each | 542 * The list must be evaluated in order since the fields might depend on each |
| 543 * other. | 543 * other. |
| 544 */ | 544 */ |
| 545 List<VariableElement> getStaticNonFinalFieldsForEmission() { | 545 List<VariableElement> getStaticNonFinalFieldsForEmission() { |
| (...skipping 113 matching lines...) Expand 10 before | Expand all | Expand 10 after Loading... |
| 659 } | 659 } |
| 660 } | 660 } |
| 661 } | 661 } |
| 662 | 662 |
| 663 String getJsConstructor(ClassElement element) { | 663 String getJsConstructor(ClassElement element) { |
| 664 return compiler.namer.isolatePropertyAccess(element); | 664 return compiler.namer.isolatePropertyAccess(element); |
| 665 } | 665 } |
| 666 } | 666 } |
| 667 | 667 |
| 668 class CompileTimeConstantEvaluator extends AbstractVisitor { | 668 class CompileTimeConstantEvaluator extends AbstractVisitor { |
| 669 final ConstantHandler constantHandler; | |
| 670 final TreeElements elements; | 669 final TreeElements elements; |
| 671 final Compiler compiler; | 670 final Compiler compiler; |
| 672 final Map<Element, Constant> definitions = null; | |
| 673 | 671 |
| 674 CompileTimeConstantEvaluator(this.constantHandler, | 672 CompileTimeConstantEvaluator(this.elements, this.compiler); |
| 675 this.elements, | |
| 676 this.compiler); | |
| 677 | |
| 678 CompileTimeConstantEvaluator.insideConstructor(this.constantHandler, | |
| 679 this.elements, | |
| 680 this.compiler, | |
| 681 this.definitions); | |
| 682 | |
| 683 bool insideConstructor() => definitions !== null; | |
| 684 | 673 |
| 685 Constant evaluate(Node node) { | 674 Constant evaluate(Node node) { |
| 686 return node.accept(this); | 675 return node.accept(this); |
| 687 } | 676 } |
| 688 | 677 |
| 689 visitNode(Node node) { | 678 visitNode(Node node) { |
| 690 error(node); | 679 error(node); |
| 691 } | 680 } |
| 692 | 681 |
| 693 Constant visitLiteralBool(LiteralBool node) { | 682 Constant visitLiteralBool(LiteralBool node) { |
| (...skipping 12 matching lines...) Expand all Loading... |
| 706 if (!node.isConst()) error(node); | 695 if (!node.isConst()) error(node); |
| 707 List<Constant> arguments = <Constant>[]; | 696 List<Constant> arguments = <Constant>[]; |
| 708 for (Link<Node> link = node.elements.nodes; | 697 for (Link<Node> link = node.elements.nodes; |
| 709 !link.isEmpty(); | 698 !link.isEmpty(); |
| 710 link = link.tail) { | 699 link = link.tail) { |
| 711 arguments.add(evaluate(link.head)); | 700 arguments.add(evaluate(link.head)); |
| 712 } | 701 } |
| 713 // TODO(floitsch): get type from somewhere. | 702 // TODO(floitsch): get type from somewhere. |
| 714 Type type = null; | 703 Type type = null; |
| 715 Constant constant = new ListConstant(type, arguments); | 704 Constant constant = new ListConstant(type, arguments); |
| 716 constantHandler.registerCompileTimeConstant(constant); | 705 compiler.constantHandler.registerCompileTimeConstant(constant); |
| 717 return constant; | 706 return constant; |
| 718 } | 707 } |
| 719 | 708 |
| 720 Constant visitLiteralMap(LiteralMap node) { | 709 Constant visitLiteralMap(LiteralMap node) { |
| 721 // TODO(floitsch): check for isConst, once the parser adds it into the node. | 710 // TODO(floitsch): check for isConst, once the parser adds it into the node. |
| 722 // if (!node.isConst()) error(node); | 711 // if (!node.isConst()) error(node); |
| 723 List<StringConstant> keys = <StringConstant>[]; | 712 List<StringConstant> keys = <StringConstant>[]; |
| 724 List<Constant> values = <Constant>[]; | 713 List<Constant> values = <Constant>[]; |
| 725 bool hasProtoKey = false; | 714 bool hasProtoKey = false; |
| 726 for (Link<Node> link = node.entries.nodes; | 715 for (Link<Node> link = node.entries.nodes; |
| (...skipping 13 matching lines...) Expand all Loading... |
| 740 keys.add(key); | 729 keys.add(key); |
| 741 values.add(evaluate(entry.value)); | 730 values.add(evaluate(entry.value)); |
| 742 } | 731 } |
| 743 if (hasProtoKey) { | 732 if (hasProtoKey) { |
| 744 compiler.unimplemented("visitLiteralMap with __proto__ key", | 733 compiler.unimplemented("visitLiteralMap with __proto__ key", |
| 745 node: node); | 734 node: node); |
| 746 } | 735 } |
| 747 // TODO(floitsch): this should be a List<String> type. | 736 // TODO(floitsch): this should be a List<String> type. |
| 748 Type keysType = null; | 737 Type keysType = null; |
| 749 ListConstant keysList = new ListConstant(keysType, keys); | 738 ListConstant keysList = new ListConstant(keysType, keys); |
| 750 constantHandler.registerCompileTimeConstant(keysList); | 739 compiler.constantHandler.registerCompileTimeConstant(keysList); |
| 751 ClassElement classElement = | 740 ClassElement classElement = |
| 752 compiler.jsHelperLibrary.find(MapConstant.DART_CLASS); | 741 compiler.jsHelperLibrary.find(MapConstant.DART_CLASS); |
| 753 classElement.ensureResolved(compiler); | 742 classElement.ensureResolved(compiler); |
| 754 // TODO(floitsch): copy over the generic type. | 743 // TODO(floitsch): copy over the generic type. |
| 755 Type type = new SimpleType(classElement.name, classElement); | 744 Type type = new SimpleType(classElement.name, classElement); |
| 756 compiler.registerInstantiatedClass(classElement); | 745 compiler.registerInstantiatedClass(classElement); |
| 757 Constant constant = new MapConstant(type, keysList, values); | 746 Constant constant = new MapConstant(type, keysList, values); |
| 758 constantHandler.registerCompileTimeConstant(constant); | 747 compiler.constantHandler.registerCompileTimeConstant(constant); |
| 759 return constant; | 748 return constant; |
| 760 } | 749 } |
| 761 | 750 |
| 762 Constant visitLiteralNull(LiteralNull node) { | 751 Constant visitLiteralNull(LiteralNull node) { |
| 763 return new NullConstant(); | 752 return new NullConstant(); |
| 764 } | 753 } |
| 765 | 754 |
| 766 Constant visitLiteralString(LiteralString node) { | 755 Constant visitLiteralString(LiteralString node) { |
| 767 return new StringConstant(node.dartString); | 756 return new StringConstant(node.dartString); |
| 768 } | 757 } |
| (...skipping 26 matching lines...) Expand all Loading... |
| 795 } | 784 } |
| 796 | 785 |
| 797 // TODO(floitsch): provide better error-messages. | 786 // TODO(floitsch): provide better error-messages. |
| 798 Constant visitSend(Send send) { | 787 Constant visitSend(Send send) { |
| 799 Element element = elements[send]; | 788 Element element = elements[send]; |
| 800 if (Elements.isStaticOrTopLevelField(element)) { | 789 if (Elements.isStaticOrTopLevelField(element)) { |
| 801 if (element.modifiers === null || | 790 if (element.modifiers === null || |
| 802 !element.modifiers.isFinal()) { | 791 !element.modifiers.isFinal()) { |
| 803 error(send); | 792 error(send); |
| 804 } | 793 } |
| 805 return constantHandler.compileVariable(element); | 794 return compiler.compileVariable(element); |
| 806 } else if (send.isPrefix) { | 795 } else if (send.isPrefix) { |
| 807 assert(send.isOperator); | 796 assert(send.isOperator); |
| 808 Constant receiverConstant = evaluate(send.receiver); | 797 Constant receiverConstant = evaluate(send.receiver); |
| 809 Operator op = send.selector; | 798 Operator op = send.selector; |
| 810 Constant folded; | 799 Constant folded; |
| 811 switch (op.source.stringValue) { | 800 switch (op.source.stringValue) { |
| 812 case "!": | 801 case "!": |
| 813 folded = const NotOperation().fold(receiverConstant); | 802 folded = const NotOperation().fold(receiverConstant); |
| 814 break; | 803 break; |
| 815 case "-": | 804 case "-": |
| 816 folded = const NegateOperation().fold(receiverConstant); | 805 folded = const NegateOperation().fold(receiverConstant); |
| 817 break; | 806 break; |
| 818 case "~": | 807 case "~": |
| 819 folded = const BitNotOperation().fold(receiverConstant); | 808 folded = const BitNotOperation().fold(receiverConstant); |
| 820 break; | 809 break; |
| 821 default: | 810 default: |
| 822 compiler.internalError("Unexpected operator.", node: op); | 811 compiler.internalError("Unexpected operator.", node: op); |
| 823 break; | 812 break; |
| 824 } | 813 } |
| 825 if (folded === null) error(send); | 814 if (folded === null) error(send); |
| 826 return folded; | 815 return folded; |
| 827 } else if (Elements.isLocal(element)) { | |
| 828 if (!insideConstructor()) error(send); | |
| 829 Constant constant = definitions[element]; | |
| 830 if (constant === null) { | |
| 831 compiler.internalError("Local variable without value", node: send); | |
| 832 } | |
| 833 return constant; | |
| 834 } else if (send.isOperator && !send.isPostfix) { | 816 } else if (send.isOperator && !send.isPostfix) { |
| 835 assert(send.argumentCount() == 1); | 817 assert(send.argumentCount() == 1); |
| 836 Constant left = evaluate(send.receiver); | 818 Constant left = evaluate(send.receiver); |
| 837 Constant right = evaluate(send.argumentsNode.nodes.head); | 819 Constant right = evaluate(send.argumentsNode.nodes.head); |
| 838 Operator op = send.selector.asOperator(); | 820 Operator op = send.selector.asOperator(); |
| 839 Constant folded; | 821 Constant folded; |
| 840 switch (op.source.stringValue) { | 822 switch (op.source.stringValue) { |
| 841 case "+": | 823 case "+": |
| 842 if (left.isString() && !right.isString()) { | 824 if (left.isString() && !right.isString()) { |
| 843 // At the moment only compile-time concatenation of two strings is | 825 // At the moment only compile-time concatenation of two strings is |
| (...skipping 80 matching lines...) Expand 10 before | Expand all | Expand 10 after Loading... |
| 924 if (folded === null) error(send); | 906 if (folded === null) error(send); |
| 925 return folded; | 907 return folded; |
| 926 } | 908 } |
| 927 return super.visitSend(send); | 909 return super.visitSend(send); |
| 928 } | 910 } |
| 929 | 911 |
| 930 visitSendSet(SendSet node) { | 912 visitSendSet(SendSet node) { |
| 931 error(node); | 913 error(node); |
| 932 } | 914 } |
| 933 | 915 |
| 916 /** Returns the list of constants that are passed to the static function. */ |
| 917 List<Constant> evaluateArgumentsToConstructor(Send send, |
| 918 FunctionElement target) { |
| 919 FunctionParameters parameters = target.computeParameters(compiler); |
| 920 List<Constant> arguments = <Constant>[]; |
| 921 Selector selector = elements.getSelector(send); |
| 922 |
| 923 Function compileArgument = evaluate; |
| 924 Function compileConstant = compiler.compileVariable; |
| 925 bool succeeded = selector.addSendArgumentsToList( |
| 926 send, arguments, parameters, compileArgument, compileConstant); |
| 927 if (!succeeded) error(send); |
| 928 return arguments; |
| 929 } |
| 930 |
| 934 Constant visitNewExpression(NewExpression node) { | 931 Constant visitNewExpression(NewExpression node) { |
| 935 Element currentElement = compiler.currentElement; | |
| 936 | |
| 937 void assignArgumentsToParameters( | |
| 938 FunctionParameters parameters, | |
| 939 Map<Element, Constant> constructorDefinitions, | |
| 940 Map<Element, Constant> fieldValues) { | |
| 941 Send send = node.send; | |
| 942 if (send.arguments.isEmpty() && parameters.parameterCount == 0) return; | |
| 943 List<Constant> arguments = <Constant>[]; | |
| 944 Selector selector = elements.getSelector(send); | |
| 945 | |
| 946 Function compileArgument = evaluate; | |
| 947 Function compileConstant = constantHandler.compileVariable; | |
| 948 bool succeeded = selector.addSendArgumentsToList( | |
| 949 send, arguments, parameters, compileArgument, compileConstant); | |
| 950 if (!succeeded) error(node); | |
| 951 | |
| 952 int index = 0; | |
| 953 parameters.forEachParameter((Element parameter) { | |
| 954 Constant argument = arguments[index++]; | |
| 955 constructorDefinitions[parameter] = argument; | |
| 956 if (parameter.kind == ElementKind.FIELD_PARAMETER) { | |
| 957 FieldParameterElement fieldParameterElement = parameter; | |
| 958 fieldValues[fieldParameterElement.fieldElement] = argument; | |
| 959 } | |
| 960 }); | |
| 961 } | |
| 962 | |
| 963 void compileInitializers(Link<Node> initializers, | |
| 964 CompileTimeConstantEvaluator evaluator, | |
| 965 TreeElements constructorElements, | |
| 966 Map<Element, Constant> constructorDefinitions, | |
| 967 Map<Element, Constant> fieldValues) { | |
| 968 for (Link<Node> link = initializers; !link.isEmpty(); link = link.tail) { | |
| 969 assert(link.head is Send); | |
| 970 if (link.head is !SendSet) { | |
| 971 // A super initializer or constructor redirection. | |
| 972 Send call = link.head; | |
| 973 assert(Initializers.isSuperConstructorCall(call) || | |
| 974 Initializers.isConstructorRedirect(call)); | |
| 975 compiler.unimplemented("ConstantHandler with this or super", | |
| 976 node: call); | |
| 977 } else { | |
| 978 // A field initializer. | |
| 979 SendSet init = link.head; | |
| 980 Link<Node> arguments = init.arguments; | |
| 981 assert(!arguments.isEmpty() && arguments.tail.isEmpty()); | |
| 982 Constant fieldValue = evaluator.evaluate(arguments.head); | |
| 983 fieldValues[constructorElements[init]] = fieldValue; | |
| 984 } | |
| 985 } | |
| 986 } | |
| 987 | |
| 988 List<Constant> buildJsNewArguments(ClassElement classElement, | |
| 989 Map<Element, Constant> fieldValues) { | |
| 990 List<Constant> jsNewArguments = <Constant>[]; | |
| 991 for (Element member in classElement.members) { | |
| 992 if (member.isInstanceMember() && member.kind == ElementKind.FIELD) { | |
| 993 Constant fieldValue = fieldValues[member]; | |
| 994 if (fieldValue === null) { | |
| 995 // Use the default value. | |
| 996 fieldValue = constantHandler.compileVariable(member); | |
| 997 } | |
| 998 jsNewArguments.add(fieldValue); | |
| 999 } | |
| 1000 } | |
| 1001 if (classElement.superclass != compiler.coreLibrary.find(Types.OBJECT)) { | |
| 1002 compiler.withCurrentElement(currentElement, () { | |
| 1003 compiler.unimplemented("ConstantHandler with super", node: node); | |
| 1004 }); | |
| 1005 } | |
| 1006 return jsNewArguments; | |
| 1007 } | |
| 1008 | |
| 1009 if (!node.isConst()) error(node); | 932 if (!node.isConst()) error(node); |
| 1010 | 933 |
| 1011 FunctionElement constructor = elements[node.send]; | 934 FunctionElement constructor = elements[node.send]; |
| 1012 TreeElements constructorElements = | 935 ClassElement classElement = constructor.enclosingElement; |
| 1013 compiler.resolver.resolveMethodElement(constructor); | 936 if (classElement.isInterface()) { |
| 1014 if (constructor != constructor.defaultImplementation) { | 937 compiler.resolver.resolveMethodElement(constructor); |
| 1015 constructor = constructor.defaultImplementation; | 938 constructor = constructor.defaultImplementation; |
| 1016 constructorElements = | 939 classElement = constructor.enclosingElement; |
| 1017 compiler.resolver.resolveMethodElement(constructor); | |
| 1018 } | 940 } |
| 1019 | 941 |
| 1020 List<Constant> jsNewArguments; | 942 List<Constant> arguments = |
| 1021 ClassElement classElement = constructor.enclosingElement; | 943 evaluateArgumentsToConstructor(node.send, constructor); |
| 1022 compiler.withCurrentElement(constructor, () { | 944 ConstructorEvaluator evaluator = |
| 1023 FunctionExpression functionNode = constructor.parseNode(compiler); | 945 new ConstructorEvaluator(constructor, compiler); |
| 1024 NodeList initializerList = functionNode.initializers; | 946 evaluator.evaluateConstructorFieldValues(arguments); |
| 1025 FunctionParameters parameters = constructor.computeParameters(compiler); | 947 List<Constant>jsNewArguments = evaluator.buildJsNewArguments(classElement); |
| 1026 | |
| 1027 Map<Element, Constant> fieldValues = new Map<Element, Constant>(); | |
| 1028 Map<Element, Constant> constructorDefinitions = | |
| 1029 new Map<Element, Constant>(); | |
| 1030 | |
| 1031 assignArgumentsToParameters(parameters, constructorDefinitions, | |
| 1032 fieldValues); | |
| 1033 CompileTimeConstantEvaluator initializerEvaluator = | |
| 1034 new CompileTimeConstantEvaluator.insideConstructor( | |
| 1035 constantHandler, constructorElements, compiler, | |
| 1036 constructorDefinitions); | |
| 1037 if (initializerList !== null) { | |
| 1038 Link<Node> initializers = functionNode.initializers.nodes; | |
| 1039 compileInitializers(initializers, | |
| 1040 initializerEvaluator, | |
| 1041 constructorElements, | |
| 1042 constructorDefinitions, | |
| 1043 fieldValues); | |
| 1044 } | |
| 1045 jsNewArguments = buildJsNewArguments(classElement, fieldValues); | |
| 1046 }); | |
| 1047 | |
| 1048 | 948 |
| 1049 compiler.registerInstantiatedClass(classElement); | 949 compiler.registerInstantiatedClass(classElement); |
| 1050 // TODO(floitsch): take generic types into account. | 950 // TODO(floitsch): take generic types into account. |
| 1051 Type type = classElement.computeType(compiler); | 951 Type type = classElement.computeType(compiler); |
| 1052 Constant constant = new ConstructedConstant(type, jsNewArguments); | 952 Constant constant = new ConstructedConstant(type, jsNewArguments); |
| 1053 constantHandler.registerCompileTimeConstant(constant); | 953 compiler.constantHandler.registerCompileTimeConstant(constant); |
| 1054 return constant; | 954 return constant; |
| 1055 } | 955 } |
| 1056 | 956 |
| 1057 Constant visitParenthesizedExpression(ParenthesizedExpression node) { | 957 Constant visitParenthesizedExpression(ParenthesizedExpression node) { |
| 1058 return node.expression.accept(this); | 958 return node.expression.accept(this); |
| 1059 } | 959 } |
| 1060 | 960 |
| 1061 error(Node node) { | 961 error(Node node) { |
| 1062 // TODO(floitsch): get the list of constants that are currently compiled | 962 // TODO(floitsch): get the list of constants that are currently compiled |
| 1063 // and present some kind of stack-trace. | 963 // and present some kind of stack-trace. |
| 1064 MessageKind kind = MessageKind.NOT_A_COMPILE_TIME_CONSTANT; | 964 MessageKind kind = MessageKind.NOT_A_COMPILE_TIME_CONSTANT; |
| 1065 compiler.reportError(node, new CompileTimeConstantError(kind, const [])); | 965 compiler.reportError(node, new CompileTimeConstantError(kind, const [])); |
| 1066 } | 966 } |
| 1067 } | 967 } |
| 968 |
| 969 class ConstructorEvaluator extends CompileTimeConstantEvaluator { |
| 970 FunctionElement constructor; |
| 971 final Map<Element, Constant> definitions; |
| 972 final Map<Element, Constant> fieldValues; |
| 973 |
| 974 ConstructorEvaluator(FunctionElement constructor, Compiler compiler) |
| 975 : this.constructor = constructor, |
| 976 this.definitions = new Map<Element, Constant>(), |
| 977 this.fieldValues = new Map<Element, Constant>(), |
| 978 super(compiler.resolver.resolveMethodElement(constructor), |
| 979 compiler); |
| 980 |
| 981 Constant visitSend(Send send) { |
| 982 Element element = elements[send]; |
| 983 if (Elements.isLocal(element)) { |
| 984 Constant constant = definitions[element]; |
| 985 if (constant === null) { |
| 986 compiler.internalError("Local variable without value", node: send); |
| 987 } |
| 988 return constant; |
| 989 } |
| 990 return super.visitSend(send); |
| 991 } |
| 992 |
| 993 /** |
| 994 * Given the arguments (a list of constants) assigns them to the parameters, |
| 995 * updating the definitions map. If the constructor has field-initializer |
| 996 * parameters (like [:this.x:]), also updates the [fieldValues] map. |
| 997 */ |
| 998 void assignArgumentsToParameters(List<Constant> arguments) { |
| 999 // Assign arguments to parameters. |
| 1000 FunctionParameters parameters = constructor.computeParameters(compiler); |
| 1001 int index = 0; |
| 1002 parameters.forEachParameter((Element parameter) { |
| 1003 Constant argument = arguments[index++]; |
| 1004 definitions[parameter] = argument; |
| 1005 if (parameter.kind == ElementKind.FIELD_PARAMETER) { |
| 1006 FieldParameterElement fieldParameterElement = parameter; |
| 1007 fieldValues[fieldParameterElement.fieldElement] = argument; |
| 1008 } |
| 1009 }); |
| 1010 } |
| 1011 |
| 1012 void evaluateSuperOrRedirectSend(FunctionElement targetConstructor, |
| 1013 List<Constant> targetArguments) { |
| 1014 ConstructorEvaluator evaluator = |
| 1015 new ConstructorEvaluator(targetConstructor, compiler); |
| 1016 evaluator.evaluateConstructorFieldValues(targetArguments); |
| 1017 // Copy over the fieldValues from the super/redirect-constructor. |
| 1018 evaluator.fieldValues.forEach((key, value) => fieldValues[key] = value); |
| 1019 } |
| 1020 |
| 1021 /** |
| 1022 * Runs through the initializers of the given [constructor] and updates |
| 1023 * the [fieldValues] map. |
| 1024 */ |
| 1025 void evaluateConstructorInitializers() { |
| 1026 FunctionExpression functionNode = constructor.parseNode(compiler); |
| 1027 NodeList initializerList = functionNode.initializers; |
| 1028 |
| 1029 bool foundSuperOrRedirect = false; |
| 1030 |
| 1031 if (initializerList !== null) { |
| 1032 for (Link<Node> link = initializerList.nodes; |
| 1033 !link.isEmpty(); |
| 1034 link = link.tail) { |
| 1035 assert(link.head is Send); |
| 1036 if (link.head is !SendSet) { |
| 1037 // A super initializer or constructor redirection. |
| 1038 Send call = link.head; |
| 1039 FunctionElement targetConstructor = elements[call]; |
| 1040 List<Constant> targetArguments = |
| 1041 evaluateArgumentsToConstructor(call, targetConstructor); |
| 1042 evaluateSuperOrRedirectSend(targetConstructor, targetArguments); |
| 1043 foundSuperOrRedirect = true; |
| 1044 } else { |
| 1045 // A field initializer. |
| 1046 SendSet init = link.head; |
| 1047 Link<Node> initArguments = init.arguments; |
| 1048 assert(!initArguments.isEmpty() && initArguments.tail.isEmpty()); |
| 1049 Constant fieldValue = evaluate(initArguments.head); |
| 1050 fieldValues[elements[init]] = fieldValue; |
| 1051 } |
| 1052 } |
| 1053 } |
| 1054 |
| 1055 if (!foundSuperOrRedirect) { |
| 1056 // No super initializer found. Try to find the default constructor if |
| 1057 // the class is not Object. |
| 1058 ClassElement enclosingClass = constructor.enclosingElement; |
| 1059 ClassElement superClass = enclosingClass.superclass; |
| 1060 if (enclosingClass != compiler.objectClass) { |
| 1061 assert(superClass !== null); |
| 1062 assert(superClass.isResolved); |
| 1063 FunctionElement targetConstructor = |
| 1064 superClass.lookupConstructor(superClass.name); |
| 1065 if (targetConstructor === null) { |
| 1066 compiler.internalError("no default constructor available"); |
| 1067 } |
| 1068 evaluateSuperOrRedirectSend(targetConstructor, const <Constant>[]); |
| 1069 } |
| 1070 } |
| 1071 } |
| 1072 |
| 1073 /** |
| 1074 * Simulates the execution of the [constructor] with the given |
| 1075 * [arguments] to obtain the field values that need to be passed to the |
| 1076 * native JavaScript constructor. |
| 1077 */ |
| 1078 void evaluateConstructorFieldValues(List<Constant> arguments) { |
| 1079 compiler.withCurrentElement(constructor, () { |
| 1080 assignArgumentsToParameters(arguments); |
| 1081 evaluateConstructorInitializers(); |
| 1082 }); |
| 1083 } |
| 1084 |
| 1085 List<Constant> buildJsNewArguments(ClassElement classElement) { |
| 1086 List<Constant> jsNewArguments = <Constant>[]; |
| 1087 // TODO(floitsch): share this code with the emitter, so that we don't |
| 1088 // need to care about the order of fields here. |
| 1089 while (classElement != compiler.objectClass) { |
| 1090 for (Element member in classElement.members) { |
| 1091 if (member.isInstanceMember() && member.kind == ElementKind.FIELD) { |
| 1092 Constant fieldValue = fieldValues[member]; |
| 1093 if (fieldValue === null) { |
| 1094 // Use the default value. |
| 1095 fieldValue = compiler.compileVariable(member); |
| 1096 } |
| 1097 jsNewArguments.add(fieldValue); |
| 1098 } |
| 1099 } |
| 1100 classElement = classElement.superclass; |
| 1101 } |
| 1102 return jsNewArguments; |
| 1103 } |
| 1104 } |
| OLD | NEW |