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