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 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.withDefinitions(this.constantHandler, | |
| 660 this.elements, | |
| 661 this.compiler, | |
| 662 this.definitions); | |
| 663 | |
| 687 Constant evaluate(Node node) { | 664 Constant evaluate(Node node) { |
| 688 return node.accept(this); | 665 return node.accept(this); |
| 689 } | 666 } |
| 690 | 667 |
| 691 visitNode(Node node) { | 668 visitNode(Node node) { |
| 692 compiler.unimplemented("CompileTimeConstantEvaluator", node: node); | 669 compiler.unimplemented("CompileTimeConstantEvaluator", node: node); |
| 693 } | 670 } |
| 694 | 671 |
| 695 Constant visitLiteralBool(LiteralBool node) { | 672 Constant visitLiteralBool(LiteralBool node) { |
| 696 // TODO(floitsch): make BoolConstant a factory and cache the two values | 673 // TODO(floitsch): make BoolConstant a factory and cache the two values |
| (...skipping 12 matching lines...) Expand all Loading... | |
| 709 Constant visitLiteralList(LiteralList node) { | 686 Constant visitLiteralList(LiteralList node) { |
| 710 if (!node.isConst()) error(node); | 687 if (!node.isConst()) error(node); |
| 711 List<Constant> arguments = <Constant>[]; | 688 List<Constant> arguments = <Constant>[]; |
| 712 for (Link<Node> link = node.elements.nodes; | 689 for (Link<Node> link = node.elements.nodes; |
| 713 !link.isEmpty(); | 690 !link.isEmpty(); |
| 714 link = link.tail) { | 691 link = link.tail) { |
| 715 arguments.add(evaluate(link.head)); | 692 arguments.add(evaluate(link.head)); |
| 716 } | 693 } |
| 717 // TODO(floitsch): get type from somewhere. | 694 // TODO(floitsch): get type from somewhere. |
| 718 Type type = null; | 695 Type type = null; |
| 719 return constantHandler.compileListLiteral(node, type, arguments); | 696 Constant constant = new ListConstant(type, arguments); |
| 697 constantHandler.registerCompileTimeConstant(constant); | |
| 698 return constant; | |
| 720 } | 699 } |
| 721 | 700 |
| 722 Constant visitLiteralMap(LiteralMap node) { | 701 Constant visitLiteralMap(LiteralMap node) { |
| 723 // TODO(floitsch): check for isConst, once the parser adds it into the node. | 702 // TODO(floitsch): check for isConst, once the parser adds it into the node. |
| 724 // if (!node.isConst()) error(node); | 703 // if (!node.isConst()) error(node); |
| 725 List<StringConstant> keys = <StringConstant>[]; | 704 List<StringConstant> keys = <StringConstant>[]; |
| 726 List<Constant> values = <Constant>[]; | 705 List<Constant> values = <Constant>[]; |
| 727 bool hasProtoKey = false; | 706 bool hasProtoKey = false; |
| 728 for (Link<Node> link = node.entries.nodes; | 707 for (Link<Node> link = node.entries.nodes; |
| 729 !link.isEmpty(); | 708 !link.isEmpty(); |
| (...skipping 36 matching lines...) Expand 10 before | Expand all | Expand 10 after Loading... | |
| 766 | 745 |
| 767 Constant visitLiteralNull(LiteralNull node) { | 746 Constant visitLiteralNull(LiteralNull node) { |
| 768 return new NullConstant(); | 747 return new NullConstant(); |
| 769 } | 748 } |
| 770 | 749 |
| 771 Constant visitLiteralString(LiteralString node) { | 750 Constant visitLiteralString(LiteralString node) { |
| 772 return new StringConstant(node.dartString); | 751 return new StringConstant(node.dartString); |
| 773 } | 752 } |
| 774 | 753 |
| 775 // TODO(floitsch): provide better error-messages. | 754 // TODO(floitsch): provide better error-messages. |
| 776 visitSend(Send send) { | 755 Constant visitSend(Send send) { |
| 777 Element element = definitions[send]; | 756 Element element = elements[send]; |
| 778 if (Elements.isStaticOrTopLevelField(element)) { | 757 if (Elements.isStaticOrTopLevelField(element)) { |
| 779 if (element.modifiers === null || | 758 if (element.modifiers === null || |
| 780 !element.modifiers.isFinal()) { | 759 !element.modifiers.isFinal()) { |
| 781 error(send); | 760 error(send); |
| 782 } | 761 } |
| 783 return constantHandler.compileVariable(element); | 762 return constantHandler.compileVariable(element); |
| 784 } else if (send.isPrefix) { | 763 } else if (send.isPrefix) { |
| 785 assert(send.isOperator); | 764 assert(send.isOperator); |
| 786 Constant receiverConstant = evaluate(send.receiver); | 765 Constant receiverConstant = evaluate(send.receiver); |
| 787 Operator op = send.selector; | 766 Operator op = send.selector; |
| 788 Constant folded; | 767 Constant folded; |
| 789 switch (op.source.stringValue) { | 768 switch (op.source.stringValue) { |
| 790 case "!": | 769 case "!": |
| 791 folded = const NotOperation().fold(receiverConstant); | 770 folded = const NotOperation().fold(receiverConstant); |
| 792 break; | 771 break; |
| 793 case "-": | 772 case "-": |
| 794 folded = const NegateOperation().fold(receiverConstant); | 773 folded = const NegateOperation().fold(receiverConstant); |
| 795 break; | 774 break; |
| 796 case "~": | 775 case "~": |
| 797 folded = const BitNotOperation().fold(receiverConstant); | 776 folded = const BitNotOperation().fold(receiverConstant); |
| 798 break; | 777 break; |
| 799 default: | 778 default: |
| 800 compiler.internalError("Unexpected operator.", node: op); | 779 compiler.internalError("Unexpected operator.", node: op); |
| 801 break; | 780 break; |
| 802 } | 781 } |
| 803 if (folded === null) error(send); | 782 if (folded === null) error(send); |
| 804 return folded; | 783 return folded; |
| 784 } else if (Elements.isLocal(element)) { | |
| 785 if (definitions === null) error(send); | |
|
ngeoffray
2012/03/12 14:02:53
What does it mean to not have a definitions? Not b
floitsch
2012/03/12 14:37:53
Done.
| |
| 786 Constant constant = definitions[element]; | |
| 787 if (constant === null) { | |
| 788 compiler.internalError("Local variable without value", node: send); | |
| 789 } | |
| 790 return constant; | |
| 805 } else if (send.isOperator && !send.isPostfix) { | 791 } else if (send.isOperator && !send.isPostfix) { |
| 806 assert(send.argumentCount() == 1); | 792 assert(send.argumentCount() == 1); |
| 807 Constant left = evaluate(send.receiver); | 793 Constant left = evaluate(send.receiver); |
| 808 Constant right = evaluate(send.argumentsNode.nodes.head); | 794 Constant right = evaluate(send.argumentsNode.nodes.head); |
| 809 Operator op = send.selector.asOperator(); | 795 Operator op = send.selector.asOperator(); |
| 810 Constant folded; | 796 Constant folded; |
| 811 switch (op.source.stringValue) { | 797 switch (op.source.stringValue) { |
| 812 case "+": | 798 case "+": |
| 813 if (left.isString() && !right.isString()) { | 799 if (left.isString() && !right.isString()) { |
| 814 // At the moment only compile-time concatenation of two strings is | 800 // At the moment only compile-time concatenation of two strings is |
| (...skipping 74 matching lines...) Expand 10 before | Expand all | Expand 10 after Loading... | |
| 889 if (folded === null) error(send); | 875 if (folded === null) error(send); |
| 890 return folded; | 876 return folded; |
| 891 } | 877 } |
| 892 return super.visitSend(send); | 878 return super.visitSend(send); |
| 893 } | 879 } |
| 894 | 880 |
| 895 visitSendSet(SendSet node) { | 881 visitSendSet(SendSet node) { |
| 896 error(node); | 882 error(node); |
| 897 } | 883 } |
| 898 | 884 |
| 899 visitNewExpression(NewExpression node) { | 885 Constant visitNewExpression(NewExpression node) { |
| 900 if (!node.isConst()) error(node); | 886 List<Constant> compileArguments() { |
| 901 Send send = node.send; | 887 if (!node.isConst()) error(node); |
| 902 List arguments; | 888 Send send = node.send; |
| 903 if (send.arguments.isEmpty()) { | 889 List<Constant> arguments; |
| 904 arguments = const []; | 890 if (send.arguments.isEmpty()) { |
| 905 } else { | 891 arguments = const []; |
|
ngeoffray
2012/03/12 14:02:53
const <Constant>[];
floitsch
2012/03/12 14:37:53
Done.
| |
| 906 arguments = []; | 892 } else { |
| 907 for (Link<Node> link = send.arguments; | 893 arguments = []; |
|
ngeoffray
2012/03/12 14:02:53
<Constant>[];
floitsch
2012/03/12 14:37:53
Done.
| |
| 908 !link.isEmpty(); | 894 for (Link<Node> link = send.arguments; |
| 909 link = link.tail) { | 895 !link.isEmpty(); |
| 910 arguments.add(evaluate(link.head)); | 896 link = link.tail) { |
| 897 arguments.add(evaluate(link.head)); | |
| 898 } | |
| 899 } | |
| 900 return arguments; | |
| 901 } | |
| 902 | |
| 903 void assignArgumentsToParameters( | |
| 904 List<Constant> arguments, | |
| 905 FunctionParameters parameters, | |
| 906 Map<Element, Constant> constructorDefinitions) { | |
| 907 if (arguments.length != parameters.parameterCount) { | |
| 908 if (arguments.length < parameters.parameterCount && | |
| 909 arguments.length >= parameters.requiredParameterCount) { | |
| 910 compiler.unimplemented("ConstantHandler with optional arguments", | |
| 911 node: node); | |
| 912 } else { | |
| 913 error(node); | |
| 914 } | |
| 915 } | |
| 916 int index = 0; | |
| 917 parameters.forEachParameter((Element parameter) { | |
| 918 constructorDefinitions[parameter] = arguments[index++]; | |
| 919 }); | |
| 920 } | |
| 921 | |
| 922 void compileInitializers(Link<Node> initializers, | |
| 923 CompileTimeConstantEvaluator evaluator, | |
| 924 TreeElements constructorElements, | |
| 925 Map<Element, Constant> constructorDefinitions) { | |
| 926 for (Link<Node> link = initializers; !link.isEmpty(); link = link.tail) { | |
| 927 assert(link.head is Send); | |
| 928 if (link.head is !SendSet) { | |
| 929 // A super initializer or constructor redirection. | |
| 930 Send call = link.head; | |
| 931 assert(Initializers.isSuperConstructorCall(call) || | |
| 932 Initializers.isConstructorRedirect(call)); | |
| 933 compiler.unimplemented("ConstantHandler with this or super", | |
| 934 node: call); | |
| 935 } else { | |
| 936 // A field initializer. | |
| 937 SendSet init = link.head; | |
| 938 Link<Node> arguments = init.arguments; | |
| 939 assert(!arguments.isEmpty() && arguments.tail.isEmpty()); | |
| 940 Constant fieldValue = evaluator.evaluate(arguments.head); | |
| 941 constructorDefinitions[constructorElements[init]] = fieldValue; | |
| 942 } | |
| 911 } | 943 } |
| 912 } | 944 } |
| 945 | |
| 946 List<Constant> buildJsConstructorArguments( | |
| 947 ClassElement classElement, | |
| 948 Map<Element, Constant> constructorDefinitions) { | |
| 949 List<Constant> fieldValues = <Constant>[]; | |
| 950 for (Element member in classElement.members) { | |
| 951 if (member.isInstanceMember() && member.kind == ElementKind.FIELD) { | |
| 952 Constant fieldValue = constructorDefinitions[member]; | |
| 953 if (fieldValue === null) { | |
| 954 // Use the default value. | |
| 955 fieldValue = constantHandler.compileVariable(member); | |
| 956 } | |
| 957 fieldValues.add(fieldValue); | |
| 958 } | |
| 959 } | |
| 960 if (classElement.superclass != compiler.coreLibrary.find(Types.OBJECT)) { | |
| 961 compiler.unimplemented("ConstantHandler with super", node: node); | |
| 962 } | |
| 963 return fieldValues; | |
| 964 } | |
| 965 | |
| 913 // TODO(floitsch): get the type from somewhere. | 966 // TODO(floitsch): get the type from somewhere. |
| 914 Element constructorElement = definitions[node.send]; | 967 FunctionElement constructor = elements[node.send]; |
| 915 ClassElement classElement = constructorElement.enclosingElement; | 968 ClassElement classElement = constructor.enclosingElement; |
| 969 TreeElements constructorElements = | |
| 970 compiler.resolver.resolveMethodElement(constructor); | |
| 971 FunctionExpression functionNode = constructor.parseNode(compiler); | |
| 972 NodeList initializerList = functionNode.initializers; | |
| 973 FunctionParameters parameters = constructor.computeParameters(compiler); | |
| 974 | |
| 975 Map<Element, Constant> constructorDefinitions = | |
| 976 new Map<Element, Constant>(); | |
| 977 | |
| 978 List<Constant> arguments = compileArguments(); | |
| 979 assignArgumentsToParameters(arguments, parameters, constructorDefinitions); | |
| 980 CompileTimeConstantEvaluator initializerEvaluator = | |
| 981 new CompileTimeConstantEvaluator.withDefinitions( | |
| 982 constantHandler, constructorElements, compiler, | |
| 983 constructorDefinitions); | |
| 984 if (initializerList !== null) { | |
| 985 Link<Node> initializers = functionNode.initializers.nodes; | |
| 986 compileInitializers(initializers, | |
| 987 initializerEvaluator, | |
| 988 constructorElements, | |
| 989 constructorDefinitions); | |
| 990 } | |
| 991 List<Constant> fieldValues = | |
| 992 buildJsConstructorArguments(classElement, constructorDefinitions); | |
| 993 | |
| 994 compiler.registerInstantiatedClass(classElement); | |
| 916 Type type = new SimpleType(classElement.name, classElement); | 995 Type type = new SimpleType(classElement.name, classElement); |
| 917 return constantHandler.compileObjectConstruction(node, | 996 Constant constant = new ConstructedConstant(type, fieldValues); |
| 918 type, | 997 constantHandler.registerCompileTimeConstant(constant); |
| 919 arguments); | 998 return constant; |
| 920 } | 999 } |
| 921 | 1000 |
| 922 error(Node node) { | 1001 error(Node node) { |
| 923 // TODO(floitsch): get the list of constants that are currently compiled | 1002 // TODO(floitsch): get the list of constants that are currently compiled |
| 924 // and present some kind of stack-trace. | 1003 // and present some kind of stack-trace. |
| 925 MessageKind kind = MessageKind.NOT_A_COMPILE_TIME_CONSTANT; | 1004 MessageKind kind = MessageKind.NOT_A_COMPILE_TIME_CONSTANT; |
| 926 compiler.reportError(node, new CompileTimeConstantError(kind, const [])); | 1005 compiler.reportError(node, new CompileTimeConstantError(kind, const [])); |
| 927 } | 1006 } |
| 928 } | 1007 } |
| OLD | NEW |