Chromium Code Reviews
chromiumcodereview-hr@appspot.gserviceaccount.com (chromiumcodereview-hr) | Please choose your nickname with Settings | Help | Chromium Project | Gerrit Changes | Sign out
(25)

Side by Side Diff: frog/leg/compile_time_constants.dart

Issue 9662037: Compile time constants with fields. (Closed) Base URL: https://dart.googlecode.com/svn/branches/bleeding_edge/dart
Patch Set: Address comments. Created 8 years, 9 months ago
Use n/p to move between diff chunks; N/P to move between comments. Draft comments are only viewable by you.
Jump to:
View unified diff | Download patch | Annotate | Revision Log
« no previous file with comments | « no previous file | tests/co19/co19-leg.status » ('j') | no next file with comments »
Toggle Intra-line Diffs ('i') | Expand Comments ('e') | Collapse Comments ('c') | Show Comments Hide Comments ('s')
OLDNEW
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
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
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
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
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
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 }
OLDNEW
« no previous file with comments | « no previous file | tests/co19/co19-leg.status » ('j') | no next file with comments »

Powered by Google App Engine
This is Rietveld 408576698