| 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 479 matching lines...) Expand 10 before | Expand all | Expand 10 after Loading... |
| 490 Constant result = initialVariableValues[element]; | 490 Constant result = initialVariableValues[element]; |
| 491 return result; | 491 return result; |
| 492 } | 492 } |
| 493 // TODO(floitsch): keep track of currently compiling elements so that we | 493 // TODO(floitsch): keep track of currently compiling elements so that we |
| 494 // don't end up in an infinite loop: final x = y; final y = x; | 494 // don't end up in an infinite loop: final x = y; final y = x; |
| 495 TreeElements definitions = compiler.analyzeElement(element); | 495 TreeElements definitions = compiler.analyzeElement(element); |
| 496 Constant constant = compileVariableWithDefinitions(element, definitions); | 496 Constant constant = compileVariableWithDefinitions(element, definitions); |
| 497 return constant; | 497 return constant; |
| 498 } | 498 } |
| 499 | 499 |
| 500 compileVariableWithDefinitions(VariableElement element, | 500 Constant compileVariableWithDefinitions(VariableElement element, |
| 501 TreeElements definitions) { | 501 TreeElements definitions) { |
| 502 return measure(() { | 502 return measure(() { |
| 503 Node node = element.parseNode(compiler); | 503 Node node = element.parseNode(compiler); |
| 504 assert(node !== null); | 504 assert(node !== null); |
| 505 SendSet assignment = node.asSendSet(); | 505 SendSet assignment = node.asSendSet(); |
| 506 var value; | 506 var value; |
| 507 if (assignment === null) { | 507 if (assignment === null) { |
| 508 // No initial value. | 508 // No initial value. |
| 509 value = new NullConstant(); | 509 value = new NullConstant(); |
| 510 } else { | 510 } else { |
| 511 Node right = assignment.arguments.head; | 511 Node right = assignment.arguments.head; |
| 512 CompileTimeConstantEvaluator evaluator = | 512 CompileTimeConstantEvaluator evaluator = |
| 513 new CompileTimeConstantEvaluator(this, definitions, compiler); | 513 new CompileTimeConstantEvaluator(this, definitions, compiler); |
| 514 value = evaluator.evaluate(right); | 514 value = evaluator.evaluate(right); |
| 515 } | 515 } |
| 516 initialVariableValues[element] = value; | 516 initialVariableValues[element] = value; |
| 517 return value; | 517 return value; |
| 518 }); | 518 }); |
| 519 } | 519 } |
| 520 | 520 |
| 521 ConstructedConstant compileObjectConstruction(Node node, | |
| 522 Type type, | |
| 523 List arguments) { | |
| 524 if (!arguments.isEmpty()) { | |
| 525 compiler.unimplemented("ConstantHandler with arguments", node: node); | |
| 526 } | |
| 527 ClassElement classElement = type.element; | |
| 528 for (Element member in classElement.members) { | |
| 529 if (Elements.isInstanceField(member)) { | |
| 530 compiler.unimplemented("ConstantHandler with fields", node: node); | |
| 531 } | |
| 532 } | |
| 533 if (classElement.superclass != compiler.coreLibrary.find(Types.OBJECT)) { | |
| 534 compiler.unimplemented("ConstantHandler with super", node: node); | |
| 535 } | |
| 536 compiler.registerInstantiatedClass(classElement); | |
| 537 Constant constant = new ConstructedConstant(type, arguments); | |
| 538 registerCompileTimeConstant(constant); | |
| 539 return constant; | |
| 540 } | |
| 541 | |
| 542 ListConstant compileListLiteral(Node node, | |
| 543 Type type, | |
| 544 List<Constant> arguments) { | |
| 545 Constant constant = new ListConstant(type, arguments); | |
| 546 registerCompileTimeConstant(constant); | |
| 547 return constant; | |
| 548 } | |
| 549 | |
| 550 /** | 521 /** |
| 551 * Returns a [List] of static non final fields that need to be initialized. | 522 * Returns a [List] of static non final fields that need to be initialized. |
| 552 * The list must be evaluated in order since the fields might depend on each | 523 * The list must be evaluated in order since the fields might depend on each |
| 553 * other. | 524 * other. |
| 554 */ | 525 */ |
| 555 List<VariableElement> getStaticNonFinalFieldsForEmission() { | 526 List<VariableElement> getStaticNonFinalFieldsForEmission() { |
| 556 return initialVariableValues.getKeys().filter((element) { | 527 return initialVariableValues.getKeys().filter((element) { |
| 557 return element.kind == ElementKind.FIELD | 528 return element.kind == ElementKind.FIELD |
| 558 && !element.isInstanceMember() | 529 && !element.isInstanceMember() |
| 559 && !element.modifiers.isFinal(); | 530 && !element.modifiers.isFinal(); |
| (...skipping 110 matching lines...) Expand 10 before | Expand all | Expand 10 after Loading... |
| 670 } | 641 } |
| 671 } | 642 } |
| 672 | 643 |
| 673 String getJsConstructor(ClassElement element) { | 644 String getJsConstructor(ClassElement element) { |
| 674 return compiler.namer.isolatePropertyAccess(element); | 645 return compiler.namer.isolatePropertyAccess(element); |
| 675 } | 646 } |
| 676 } | 647 } |
| 677 | 648 |
| 678 class CompileTimeConstantEvaluator extends AbstractVisitor { | 649 class CompileTimeConstantEvaluator extends AbstractVisitor { |
| 679 final ConstantHandler constantHandler; | 650 final ConstantHandler constantHandler; |
| 680 final TreeElements definitions; | 651 final TreeElements elements; |
| 681 final Compiler compiler; | 652 final Compiler compiler; |
| 653 final Map<Element, Constant> definitions = null; |
| 682 | 654 |
| 683 CompileTimeConstantEvaluator(this.constantHandler, | 655 CompileTimeConstantEvaluator(this.constantHandler, |
| 684 this.definitions, | 656 this.elements, |
| 685 this.compiler); | 657 this.compiler); |
| 686 | 658 |
| 659 CompileTimeConstantEvaluator.insideConstructor(this.constantHandler, |
| 660 this.elements, |
| 661 this.compiler, |
| 662 this.definitions); |
| 663 |
| 664 bool insideConstructor() => definitions !== null; |
| 665 |
| 687 Constant evaluate(Node node) { | 666 Constant evaluate(Node node) { |
| 688 return node.accept(this); | 667 return node.accept(this); |
| 689 } | 668 } |
| 690 | 669 |
| 691 visitNode(Node node) { | 670 visitNode(Node node) { |
| 692 compiler.unimplemented("CompileTimeConstantEvaluator", node: node); | 671 compiler.unimplemented("CompileTimeConstantEvaluator", node: node); |
| 693 } | 672 } |
| 694 | 673 |
| 695 Constant visitLiteralBool(LiteralBool node) { | 674 Constant visitLiteralBool(LiteralBool node) { |
| 696 // TODO(floitsch): make BoolConstant a factory and cache the two values | 675 // TODO(floitsch): make BoolConstant a factory and cache the two values |
| (...skipping 12 matching lines...) Expand all Loading... |
| 709 Constant visitLiteralList(LiteralList node) { | 688 Constant visitLiteralList(LiteralList node) { |
| 710 if (!node.isConst()) error(node); | 689 if (!node.isConst()) error(node); |
| 711 List<Constant> arguments = <Constant>[]; | 690 List<Constant> arguments = <Constant>[]; |
| 712 for (Link<Node> link = node.elements.nodes; | 691 for (Link<Node> link = node.elements.nodes; |
| 713 !link.isEmpty(); | 692 !link.isEmpty(); |
| 714 link = link.tail) { | 693 link = link.tail) { |
| 715 arguments.add(evaluate(link.head)); | 694 arguments.add(evaluate(link.head)); |
| 716 } | 695 } |
| 717 // TODO(floitsch): get type from somewhere. | 696 // TODO(floitsch): get type from somewhere. |
| 718 Type type = null; | 697 Type type = null; |
| 719 return constantHandler.compileListLiteral(node, type, arguments); | 698 Constant constant = new ListConstant(type, arguments); |
| 699 constantHandler.registerCompileTimeConstant(constant); |
| 700 return constant; |
| 720 } | 701 } |
| 721 | 702 |
| 722 Constant visitLiteralMap(LiteralMap node) { | 703 Constant visitLiteralMap(LiteralMap node) { |
| 723 // TODO(floitsch): check for isConst, once the parser adds it into the node. | 704 // TODO(floitsch): check for isConst, once the parser adds it into the node. |
| 724 // if (!node.isConst()) error(node); | 705 // if (!node.isConst()) error(node); |
| 725 List<StringConstant> keys = <StringConstant>[]; | 706 List<StringConstant> keys = <StringConstant>[]; |
| 726 List<Constant> values = <Constant>[]; | 707 List<Constant> values = <Constant>[]; |
| 727 bool hasProtoKey = false; | 708 bool hasProtoKey = false; |
| 728 for (Link<Node> link = node.entries.nodes; | 709 for (Link<Node> link = node.entries.nodes; |
| 729 !link.isEmpty(); | 710 !link.isEmpty(); |
| (...skipping 33 matching lines...) Expand 10 before | Expand all | Expand 10 after Loading... |
| 763 | 744 |
| 764 Constant visitLiteralNull(LiteralNull node) { | 745 Constant visitLiteralNull(LiteralNull node) { |
| 765 return new NullConstant(); | 746 return new NullConstant(); |
| 766 } | 747 } |
| 767 | 748 |
| 768 Constant visitLiteralString(LiteralString node) { | 749 Constant visitLiteralString(LiteralString node) { |
| 769 return new StringConstant(node.dartString); | 750 return new StringConstant(node.dartString); |
| 770 } | 751 } |
| 771 | 752 |
| 772 // TODO(floitsch): provide better error-messages. | 753 // TODO(floitsch): provide better error-messages. |
| 773 visitSend(Send send) { | 754 Constant visitSend(Send send) { |
| 774 Element element = definitions[send]; | 755 Element element = elements[send]; |
| 775 if (Elements.isStaticOrTopLevelField(element)) { | 756 if (Elements.isStaticOrTopLevelField(element)) { |
| 776 if (element.modifiers === null || | 757 if (element.modifiers === null || |
| 777 !element.modifiers.isFinal()) { | 758 !element.modifiers.isFinal()) { |
| 778 error(send); | 759 error(send); |
| 779 } | 760 } |
| 780 return constantHandler.compileVariable(element); | 761 return constantHandler.compileVariable(element); |
| 781 } else if (send.isPrefix) { | 762 } else if (send.isPrefix) { |
| 782 assert(send.isOperator); | 763 assert(send.isOperator); |
| 783 Constant receiverConstant = evaluate(send.receiver); | 764 Constant receiverConstant = evaluate(send.receiver); |
| 784 Operator op = send.selector; | 765 Operator op = send.selector; |
| 785 Constant folded; | 766 Constant folded; |
| 786 switch (op.source.stringValue) { | 767 switch (op.source.stringValue) { |
| 787 case "!": | 768 case "!": |
| 788 folded = const NotOperation().fold(receiverConstant); | 769 folded = const NotOperation().fold(receiverConstant); |
| 789 break; | 770 break; |
| 790 case "-": | 771 case "-": |
| 791 folded = const NegateOperation().fold(receiverConstant); | 772 folded = const NegateOperation().fold(receiverConstant); |
| 792 break; | 773 break; |
| 793 case "~": | 774 case "~": |
| 794 folded = const BitNotOperation().fold(receiverConstant); | 775 folded = const BitNotOperation().fold(receiverConstant); |
| 795 break; | 776 break; |
| 796 default: | 777 default: |
| 797 compiler.internalError("Unexpected operator.", node: op); | 778 compiler.internalError("Unexpected operator.", node: op); |
| 798 break; | 779 break; |
| 799 } | 780 } |
| 800 if (folded === null) error(send); | 781 if (folded === null) error(send); |
| 801 return folded; | 782 return folded; |
| 783 } else if (Elements.isLocal(element)) { |
| 784 if (!insideConstructor()) error(send); |
| 785 Constant constant = definitions[element]; |
| 786 if (constant === null) { |
| 787 compiler.internalError("Local variable without value", node: send); |
| 788 } |
| 789 return constant; |
| 802 } else if (send.isOperator && !send.isPostfix) { | 790 } else if (send.isOperator && !send.isPostfix) { |
| 803 assert(send.argumentCount() == 1); | 791 assert(send.argumentCount() == 1); |
| 804 Constant left = evaluate(send.receiver); | 792 Constant left = evaluate(send.receiver); |
| 805 Constant right = evaluate(send.argumentsNode.nodes.head); | 793 Constant right = evaluate(send.argumentsNode.nodes.head); |
| 806 Operator op = send.selector.asOperator(); | 794 Operator op = send.selector.asOperator(); |
| 807 Constant folded; | 795 Constant folded; |
| 808 switch (op.source.stringValue) { | 796 switch (op.source.stringValue) { |
| 809 case "+": | 797 case "+": |
| 810 if (left.isString() && !right.isString()) { | 798 if (left.isString() && !right.isString()) { |
| 811 // At the moment only compile-time concatenation of two strings is | 799 // At the moment only compile-time concatenation of two strings is |
| (...skipping 74 matching lines...) Expand 10 before | Expand all | Expand 10 after Loading... |
| 886 if (folded === null) error(send); | 874 if (folded === null) error(send); |
| 887 return folded; | 875 return folded; |
| 888 } | 876 } |
| 889 return super.visitSend(send); | 877 return super.visitSend(send); |
| 890 } | 878 } |
| 891 | 879 |
| 892 visitSendSet(SendSet node) { | 880 visitSendSet(SendSet node) { |
| 893 error(node); | 881 error(node); |
| 894 } | 882 } |
| 895 | 883 |
| 896 visitNewExpression(NewExpression node) { | 884 Constant visitNewExpression(NewExpression node) { |
| 897 if (!node.isConst()) error(node); | 885 List<Constant> compileArguments() { |
| 898 Send send = node.send; | 886 if (!node.isConst()) error(node); |
| 899 List arguments; | 887 Send send = node.send; |
| 900 if (send.arguments.isEmpty()) { | 888 List<Constant> arguments; |
| 901 arguments = const []; | 889 if (send.arguments.isEmpty()) { |
| 902 } else { | 890 arguments = const <Constant>[]; |
| 903 arguments = []; | 891 } else { |
| 904 for (Link<Node> link = send.arguments; | 892 arguments = <Constant>[]; |
| 905 !link.isEmpty(); | 893 for (Link<Node> link = send.arguments; |
| 906 link = link.tail) { | 894 !link.isEmpty(); |
| 907 arguments.add(evaluate(link.head)); | 895 link = link.tail) { |
| 896 arguments.add(evaluate(link.head)); |
| 897 } |
| 898 } |
| 899 return arguments; |
| 900 } |
| 901 |
| 902 void assignArgumentsToParameters( |
| 903 List<Constant> arguments, |
| 904 FunctionParameters parameters, |
| 905 Map<Element, Constant> constructorDefinitions) { |
| 906 if (arguments.length != parameters.parameterCount) { |
| 907 if (arguments.length < parameters.parameterCount && |
| 908 arguments.length >= parameters.requiredParameterCount) { |
| 909 compiler.unimplemented("ConstantHandler with optional arguments", |
| 910 node: node); |
| 911 } else { |
| 912 error(node); |
| 913 } |
| 914 } |
| 915 int index = 0; |
| 916 parameters.forEachParameter((Element parameter) { |
| 917 constructorDefinitions[parameter] = arguments[index++]; |
| 918 }); |
| 919 } |
| 920 |
| 921 void compileInitializers(Link<Node> initializers, |
| 922 CompileTimeConstantEvaluator evaluator, |
| 923 TreeElements constructorElements, |
| 924 Map<Element, Constant> constructorDefinitions) { |
| 925 for (Link<Node> link = initializers; !link.isEmpty(); link = link.tail) { |
| 926 assert(link.head is Send); |
| 927 if (link.head is !SendSet) { |
| 928 // A super initializer or constructor redirection. |
| 929 Send call = link.head; |
| 930 assert(Initializers.isSuperConstructorCall(call) || |
| 931 Initializers.isConstructorRedirect(call)); |
| 932 compiler.unimplemented("ConstantHandler with this or super", |
| 933 node: call); |
| 934 } else { |
| 935 // A field initializer. |
| 936 SendSet init = link.head; |
| 937 Link<Node> arguments = init.arguments; |
| 938 assert(!arguments.isEmpty() && arguments.tail.isEmpty()); |
| 939 Constant fieldValue = evaluator.evaluate(arguments.head); |
| 940 constructorDefinitions[constructorElements[init]] = fieldValue; |
| 941 } |
| 908 } | 942 } |
| 909 } | 943 } |
| 944 |
| 945 List<Constant> buildJsConstructorArguments( |
| 946 ClassElement classElement, |
| 947 Map<Element, Constant> constructorDefinitions) { |
| 948 List<Constant> fieldValues = <Constant>[]; |
| 949 for (Element member in classElement.members) { |
| 950 if (member.isInstanceMember() && member.kind == ElementKind.FIELD) { |
| 951 Constant fieldValue = constructorDefinitions[member]; |
| 952 if (fieldValue === null) { |
| 953 // Use the default value. |
| 954 fieldValue = constantHandler.compileVariable(member); |
| 955 } |
| 956 fieldValues.add(fieldValue); |
| 957 } |
| 958 } |
| 959 if (classElement.superclass != compiler.coreLibrary.find(Types.OBJECT)) { |
| 960 compiler.unimplemented("ConstantHandler with super", node: node); |
| 961 } |
| 962 return fieldValues; |
| 963 } |
| 964 |
| 910 // TODO(floitsch): get the type from somewhere. | 965 // TODO(floitsch): get the type from somewhere. |
| 911 Element constructorElement = definitions[node.send]; | 966 FunctionElement constructor = elements[node.send]; |
| 912 ClassElement classElement = constructorElement.enclosingElement; | 967 ClassElement classElement = constructor.enclosingElement; |
| 968 TreeElements constructorElements = |
| 969 compiler.resolver.resolveMethodElement(constructor); |
| 970 FunctionExpression functionNode = constructor.parseNode(compiler); |
| 971 NodeList initializerList = functionNode.initializers; |
| 972 FunctionParameters parameters = constructor.computeParameters(compiler); |
| 973 |
| 974 Map<Element, Constant> constructorDefinitions = |
| 975 new Map<Element, Constant>(); |
| 976 |
| 977 List<Constant> arguments = compileArguments(); |
| 978 assignArgumentsToParameters(arguments, parameters, constructorDefinitions); |
| 979 CompileTimeConstantEvaluator initializerEvaluator = |
| 980 new CompileTimeConstantEvaluator.insideConstructor( |
| 981 constantHandler, constructorElements, compiler, |
| 982 constructorDefinitions); |
| 983 if (initializerList !== null) { |
| 984 Link<Node> initializers = functionNode.initializers.nodes; |
| 985 compileInitializers(initializers, |
| 986 initializerEvaluator, |
| 987 constructorElements, |
| 988 constructorDefinitions); |
| 989 } |
| 990 List<Constant> fieldValues = |
| 991 buildJsConstructorArguments(classElement, constructorDefinitions); |
| 992 |
| 993 compiler.registerInstantiatedClass(classElement); |
| 913 Type type = new SimpleType(classElement.name, classElement); | 994 Type type = new SimpleType(classElement.name, classElement); |
| 914 return constantHandler.compileObjectConstruction(node, | 995 Constant constant = new ConstructedConstant(type, fieldValues); |
| 915 type, | 996 constantHandler.registerCompileTimeConstant(constant); |
| 916 arguments); | 997 return constant; |
| 917 } | 998 } |
| 918 | 999 |
| 919 error(Node node) { | 1000 error(Node node) { |
| 920 // TODO(floitsch): get the list of constants that are currently compiled | 1001 // TODO(floitsch): get the list of constants that are currently compiled |
| 921 // and present some kind of stack-trace. | 1002 // and present some kind of stack-trace. |
| 922 MessageKind kind = MessageKind.NOT_A_COMPILE_TIME_CONSTANT; | 1003 MessageKind kind = MessageKind.NOT_A_COMPILE_TIME_CONSTANT; |
| 923 compiler.reportError(node, new CompileTimeConstantError(kind, const [])); | 1004 compiler.reportError(node, new CompileTimeConstantError(kind, const [])); |
| 924 } | 1005 } |
| 925 } | 1006 } |
| OLD | NEW |