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

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: rebase 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 | no next file » | 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.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
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
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
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 }
OLDNEW
« no previous file with comments | « no previous file | no next file » | no next file with comments »

Powered by Google App Engine
This is Rietveld 408576698