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

Side by Side Diff: frog/value.dart

Issue 9143001: Fixes 2 tests and a crash (Closed) Base URL: https://dart.googlecode.com/svn/branches/bleeding_edge/dart
Patch Set: Created 8 years, 11 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
OLDNEW
1 // Copyright (c) 2011, the Dart project authors. Please see the AUTHORS file 1 // Copyright (c) 2011, 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 /** 5 /**
6 * Represents a meta-value for code generation. 6 * Represents a meta-value for code generation.
7 */ 7 */
8 class Value { 8 class Value {
9 Type _type; 9 Type _type;
10 10
(...skipping 41 matching lines...) Expand 10 before | Expand all | Expand 10 after
52 52
53 // TODO(jimhug): Replace with TypeValue. 53 // TODO(jimhug): Replace with TypeValue.
54 Value.type(this._type, this.span) 54 Value.type(this._type, this.span)
55 : code = null, needsTemp = false, isType = true { 55 : code = null, needsTemp = false, isType = true {
56 if (_type == null) world.internalError('type passed as null', span); 56 if (_type == null) world.internalError('type passed as null', span);
57 } 57 }
58 58
59 /** Is this value a constant expression? */ 59 /** Is this value a constant expression? */
60 bool get isConst() => false; 60 bool get isConst() => false;
61 61
62 /**
63 * A canonicalized form of the code. Two const expressions that result in the
64 * same instance should have the same [canonicalCode].
65 */
66 String get canonicalCode() => null;
67
68 /** If [isConst], the [EvaluatedValue] that defines this value. */ 62 /** If [isConst], the [EvaluatedValue] that defines this value. */
69 EvaluatedValue get constValue() => null; 63 EvaluatedValue get constValue() => null;
70 64
71 // TODO(jimhug): Fix these names once get/set are truly pseudo-keywords. 65 // TODO(jimhug): Fix these names once get/set are truly pseudo-keywords.
72 // See issue #379. 66 // See issue #379.
73 Value get_(MethodGenerator context, String name, Node node) { 67 Value get_(MethodGenerator context, String name, Node node) {
74 final member = _resolveMember(context, name, node); 68 final member = _resolveMember(context, name, node);
75 if (member != null) { 69 if (member != null) {
76 return member._get(context, node, this); 70 return member._get(context, node, this);
77 } else { 71 } else {
78 return invokeNoSuchMethod(context, 'get:$name', node); 72 return invokeNoSuchMethod(context, 'get:$name', node);
79 } 73 }
80 } 74 }
81 75
82 Value set_(MethodGenerator context, String name, Node node, Value value, 76 Value set_(MethodGenerator context, String name, Node node, Value value,
83 [bool isDynamic=false]) { 77 [bool isDynamic=false]) {
84 78
85 final member = _resolveMember(context, name, node, isDynamic); 79 final member = _resolveMember(context, name, node, isDynamic);
86 if (member != null) { 80 if (member != null) {
87 return member._set(context, node, this, value, isDynamic); 81 return member._set(context, node, this, value, isDynamic);
88 } else { 82 } else {
89 return invokeNoSuchMethod(context, 'set:$name', node, 83 return invokeNoSuchMethod(context, 'set:$name', node,
90 new Arguments(null, [value])); 84 new Arguments(null, [value]));
91 } 85 }
92 } 86 }
93 87
88 Value binop(int kind, Value other, MethodGenerator context, var node) {
89 switch (kind) {
90 case TokenKind.AND:
91 case TokenKind.OR:
92 final code = '${code} ${node.op} ${other.code}';
93 return new Value(world.nonNullBool, code, node.span);
94 // TODO(jimhug): Lot's to resolve here.
95 case TokenKind.EQ_STRICT:
96 return new Value(world.nonNullBool, '${code} == ${other.code}',
97 node.span);
98 case TokenKind.NE_STRICT:
99 return new Value(world.nonNullBool, '${code} != ${other.code}',
100 node.span);
101 }
102
103 var name = kind == TokenKind.NE ? ':ne': TokenKind.binaryMethodName(kind);
104 return invoke(context, name, node, new Arguments(null, [other]));
105 }
106
94 107
95 Value invoke(MethodGenerator context, String name, Node node, Arguments args, 108 Value invoke(MethodGenerator context, String name, Node node, Arguments args,
96 [bool isDynamic=false]) { 109 [bool isDynamic=false]) {
97 110
98 // TODO(jmesserly): it'd be nice to remove these special cases 111 // TODO(jmesserly): it'd be nice to remove these special cases
99 // We could create a :call in world members, and have that handle the 112 // We could create a :call in world members, and have that handle the
100 // canInvoke/Invoke logic. 113 // canInvoke/Invoke logic.
101 114
102 // Note: this check is a little different than the one in canInvoke, because 115 // Note: this check is a little different than the one in canInvoke, because
103 // sometimes we need to call dynamically even if we found the :call method 116 // sometimes we need to call dynamically even if we found the :call method
(...skipping 314 matching lines...) Expand 10 before | Expand all | Expand 10 after
418 if (toType.isVar) { 431 if (toType.isVar) {
419 world.error('can not resolve type', span); 432 world.error('can not resolve type', span);
420 } 433 }
421 434
422 String testCode = null; 435 String testCode = null;
423 if (toType.isVar || toType.isObject || toType is ParameterType) { 436 if (toType.isVar || toType.isObject || toType is ParameterType) {
424 // Note: everything is an Object, including null. 437 // Note: everything is an Object, including null.
425 if (needsTemp) { 438 if (needsTemp) {
426 return new Value(world.nonNullBool, '($code, true)', span); 439 return new Value(world.nonNullBool, '($code, true)', span);
427 } else { 440 } else {
428 return new EvaluatedValue(world.nonNullBool, true, 'true', null); 441 // TODO(jimhug): Mark non-const?
442 return Value.fromBool(true, span);
429 } 443 }
430 } 444 }
431 445
432 if (toType.library.isCore) { 446 if (toType.library.isCore) {
433 var typeofName = toType.typeofName; 447 var typeofName = toType.typeofName;
434 if (typeofName != null) { 448 if (typeofName != null) {
435 testCode = "(typeof($code) ${isTrue ? '==' : '!='} '$typeofName')"; 449 testCode = "(typeof($code) ${isTrue ? '==' : '!='} '$typeofName')";
436 } 450 }
437 } 451 }
438 if (toType.isClass && toType is !ConcreteType 452 if (toType.isClass && toType is !ConcreteType
(...skipping 63 matching lines...) Expand 10 before | Expand all | Expand 10 after
502 '\$map(${Strings.join(names, ", ")})')); 516 '\$map(${Strings.join(names, ", ")})'));
503 }*/ 517 }*/
504 518
505 // Finally, invoke noSuchMethod 519 // Finally, invoke noSuchMethod
506 return _resolveMember(context, 'noSuchMethod', node).invoke( 520 return _resolveMember(context, 'noSuchMethod', node).invoke(
507 context, node, this, new Arguments(null, noSuchArgs)); 521 context, node, this, new Arguments(null, noSuchArgs));
508 } 522 }
509 523
510 524
511 static Value fromBool(bool value, SourceSpan span) { 525 static Value fromBool(bool value, SourceSpan span) {
512 return new EvaluatedValue(world.nonNullBool, value, value.toString(), 526 return new BoolValue(value, true, span);
513 span);
514 } 527 }
515 528
516 static Value fromInt(int value, SourceSpan span) { 529 static Value fromInt(int value, SourceSpan span) {
517 final strValue = value.toString(); 530 return new IntValue(value, true, span);
518 assert(strValue.indexOf('.') == -1);
519 return new EvaluatedValue(world.numType, value, strValue, span);
520 } 531 }
521 532
522 static Value fromDouble(double value, SourceSpan span) { 533 static Value fromDouble(double value, SourceSpan span) {
523 var strValue = value.toString(); 534 return new DoubleValue(value, true, span);
524 // Ensure that string version looks different from int
525 if (strValue.indexOf('.') == -1 && strValue.indexOf('e') == -1) {
526 strValue = strValue + '.0';
527 }
528 return new EvaluatedValue(world.numType, value, strValue, span);
529 } 535 }
530 536
531 static Value fromString(String value, SourceSpan span) { 537 static Value fromString(String value, SourceSpan span) {
538 return new StringValue(value, true, span);
539 }
540
541 static Value fromNull(SourceSpan span) {
542 return new NullValue(true, span);
543 }
544 }
545
546
547 // rename to PrimitiveValue
548 class EvaluatedValue extends Value implements Hashable {
549 /** Is this value treated as const by dart language? */
550 bool isConst;
551
552 EvaluatedValue(this.isConst, Type type, SourceSpan span):
553 super(type, '@@@', span, false);
554
555 String get code() => '@@@';
Jennifer Messerly 2012/01/09 19:06:54 Maybe this should include the type name? e.g. '@@@
jimhug 2012/01/09 21:34:30 Really, this should just throw - the point is to e
556
557 EvaluatedValue get constValue() => this;
558
559 // TODO(jimhug): Using computed code here with caching is major perf fear.
560 int hashCode() => code.hashCode();
561
562 bool operator ==(var other) {
563 return other is EvaluatedValue && other.type == this.type &&
564 other.code == this.code;
565 }
566 }
567
568 class NullValue extends EvaluatedValue {
569 NullValue(bool isConst, SourceSpan span):
570 super(isConst, world.varType, span);
571
572 get actualValue() => null;
573
574 String get code() => 'null';
575
576 Value binop(int kind, var other, MethodGenerator context, var node) {
577 // TODO(jimhug): Support int/double better
578 if (other is! ListValue) return super.binop(kind, other, context, node);
579
580 switch (kind) {
581 case TokenKind.EQ_STRICT:
582 return new BoolValue(type == other.type && code == other.code,
583 isConst && other.isConst, node.span);
584 case TokenKind.NE_STRICT:
585 return new BoolValue(type != other.type || code != other.code,
586 isConst && other.isConst, node.span);
587 }
588
589 // TODO(jimhug): Will flesh out ops here!
590 return super.binop(kind, other, context, node);
591 }
592 }
593
594 class BoolValue extends EvaluatedValue {
595 bool actualValue;
596
597 BoolValue(this.actualValue, bool isConst, SourceSpan span):
598 super(isConst, world.nonNullBool, span);
599
600 String get code() => actualValue ? 'true' : 'false';
601
602 Value binop(int kind, var other, MethodGenerator context, var node) {
603 if (other is! BoolValue) return super.binop(kind, other, context, node);
604
605 switch (kind) {
606 case TokenKind.AND:
607 return new BoolValue(actualValue && other.actualValue,
608 isConst && other.isConst, node.span);
609 case TokenKind.OR:
610 return new BoolValue(actualValue || other.actualValue,
611 isConst && other.isConst, node.span);
612 case TokenKind.EQ_STRICT:
613 return new BoolValue(actualValue == other.actualValue,
614 isConst && other.isConst, node.span);
615 case TokenKind.NE_STRICT:
616 return new BoolValue(actualValue != other.actualValue,
617 isConst && other.isConst, node.span);
618 }
619
620 // TODO(jimhug): Could handle more ops here, but does it matter?
621 return super.binop(kind, other, context, node);
622 }
623 }
624
625 class IntValue extends EvaluatedValue {
626 int actualValue;
627
628 IntValue(this.actualValue, bool isConst, SourceSpan span):
629 super(isConst, world.intType, span);
630
631 // TODO(jimhug): Only add parens when needed.
632 String get code() => '(${actualValue})';
633
634 Value binop(int kind, var other, MethodGenerator context, var node) {
635 // TODO(jimhug): Support int/double better
636 if (other is! IntValue) return super.binop(kind, other, context, node);
637
638 switch (kind) {
639 case TokenKind.EQ_STRICT:
640 return new BoolValue(actualValue == other.actualValue,
641 isConst && other.isConst, node.span);
642 case TokenKind.NE_STRICT:
643 return new BoolValue(actualValue != other.actualValue,
644 isConst && other.isConst, node.span);
645 }
646
647 // TODO(jimhug): Will flesh out ops here!
648 return super.binop(kind, other, context, node);
649 }
650 }
651
652 class DoubleValue extends EvaluatedValue {
653 double actualValue;
654
655 DoubleValue(this.actualValue, bool isConst, SourceSpan span):
656 super(isConst, world.doubleType, span);
657
658 String get code() => '(${actualValue})';
659
660 Value binop(int kind, var other, MethodGenerator context, var node) {
661 // TODO(jimhug): Support int/double better
662 if (other is! DoubleValue) return super.binop(kind, other, context, node);
663
664 switch (kind) {
665 case TokenKind.EQ_STRICT:
666 return new BoolValue(actualValue == other.actualValue,
667 isConst && other.isConst, node.span);
668 case TokenKind.NE_STRICT:
669 return new BoolValue(actualValue != other.actualValue,
670 isConst && other.isConst, node.span);
671 }
672
673 // TODO(jimhug): Will flesh out ops here!
674 return super.binop(kind, other, context, node);
675 }
676 }
677
678 class StringValue extends EvaluatedValue {
679 String actualValue;
680
681 StringValue(this.actualValue, bool isConst, SourceSpan span):
682 super(isConst, world.stringType, span);
683
684 Value binop(int kind, var other, MethodGenerator context, var node) {
685 // TODO(jimhug): Support int/double better
686 if (other is! StringValue) return super.binop(kind, other, context, node);
687
688 switch (kind) {
689 case TokenKind.EQ_STRICT:
690 return new BoolValue(actualValue == other.actualValue,
691 isConst && other.isConst, node.span);
692 case TokenKind.NE_STRICT:
693 return new BoolValue(actualValue != other.actualValue,
694 isConst && other.isConst, node.span);
695 }
696
697 // TODO(jimhug): Will flesh out ops here!
698 return super.binop(kind, other, context, node);
699 }
700
701
702 // This is expensive and we may want to cache its value if called often
703 String get code() {
532 // TODO(jimhug): This could be much more efficient 704 // TODO(jimhug): This could be much more efficient
533 StringBuffer buf = new StringBuffer(); 705 StringBuffer buf = new StringBuffer();
534 buf.add('"'); 706 buf.add('"');
535 for (int i=0; i < value.length; i++) { 707 for (int i=0; i < actualValue.length; i++) {
536 var ch = value.charCodeAt(i); 708 var ch = actualValue.charCodeAt(i);
537 switch (ch) { 709 switch (ch) {
538 case 9/*'\t'*/: buf.add(@'\t'); break; 710 case 9/*'\t'*/: buf.add(@'\t'); break;
539 case 10/*'\n'*/: buf.add(@'\n'); break; 711 case 10/*'\n'*/: buf.add(@'\n'); break;
540 case 13/*'\r'*/: buf.add(@'\r'); break; 712 case 13/*'\r'*/: buf.add(@'\r'); break;
541 case 34/*"*/: buf.add(@'\"'); break; 713 case 34/*"*/: buf.add(@'\"'); break;
542 case 92/*\*/: buf.add(@'\\'); break; 714 case 92/*\*/: buf.add(@'\\'); break;
543 default: 715 default:
544 if (ch >= 32 && ch <= 126) { 716 if (ch >= 32 && ch <= 126) {
545 buf.add(value[i]); 717 buf.add(actualValue[i]);
546 } else { 718 } else {
547 final hex = ch.toRadixString(16); 719 final hex = ch.toRadixString(16);
548 switch (hex.length) { 720 switch (hex.length) {
549 case 1: buf.add(@'\x0'); buf.add(hex); break; 721 case 1: buf.add(@'\x0'); buf.add(hex); break;
550 case 2: buf.add(@'\x'); buf.add(hex); break; 722 case 2: buf.add(@'\x'); buf.add(hex); break;
551 case 3: buf.add(@'\u0'); buf.add(hex); break; 723 case 3: buf.add(@'\u0'); buf.add(hex); break;
552 case 4: buf.add(@'\u'); buf.add(hex); break; 724 case 4: buf.add(@'\u'); buf.add(hex); break;
553 default: 725 default:
554 world.internalError( 726 world.internalError(
555 'unicode values greater than 2 bytes not implemented'); 727 'unicode values greater than 2 bytes not implemented');
556 break; 728 break;
557 } 729 }
558 } 730 }
559 break; 731 break;
560 } 732 }
561 } 733 }
562 buf.add('"'); 734 buf.add('"');
563 735 return buf.toString();
564 return new EvaluatedValue(world.stringType, value, buf.toString(), span);
565 }
566
567 static Value fromNull(SourceSpan span) {
568 return new EvaluatedValue(world.varType, null, 'null', span);
569 } 736 }
570 } 737 }
571 738
572 739
573 // TODO(jmesserly): the subtypes of Value require a lot of type checks and 740 class ListValue extends EvaluatedValue {
Jennifer Messerly 2012/01/09 19:06:54 awesome!
574 // downcasts to use; can we make that cleaner? (search for ".dynamic") 741 List<Value> values;
575 742
576 /** A value that can has been evaluated statically. */ 743 ListValue(this.values, bool isConst, Type type, SourceSpan span):
577 class EvaluatedValue extends Value { 744 super(isConst, type, span);
578 745
579 var actualValue; 746 String get code() {
747 final buf = new StringBuffer();
748 buf.add('[');
749 for (var i=0; i < values.length; i++) {
Jennifer Messerly 2012/01/09 19:06:54 nit: spacing on i=0;
jimhug 2012/01/09 21:34:30 Done.
750 if (i > 0) buf.add(', ');
751 buf.add(values[i].code);
752 }
753 buf.add(']');
754 var listCode = buf.toString();
580 755
581 bool get isConst() => true; 756 if (!isConst) return listCode;
582 757
583 EvaluatedValue get constValue() => this; 758 var v = new Value(world.listType, listCode, span);
584 759 final immutableListCtor = world.immutableListType.getConstructor('from');
585 /** 760 final result = immutableListCtor.invoke(null, null,
586 * A canonicalized form of the code. Two const expressions that result in the 761 new Value.type(v.type, span), new Arguments(null, [v]));
587 * same instance should have the same [canonicalCode]. 762 return result.code;
588 */
589 String canonicalCode;
590
591 factory EvaluatedValue(Type type, actualValue, String canonicalCode,
592 SourceSpan span) {
593 return new EvaluatedValue._internal(type, actualValue,
594 canonicalCode, span, codeWithComments(canonicalCode, span));
595 } 763 }
596 764
597 EvaluatedValue._internal(Type type, this.actualValue, this.canonicalCode, 765 Value binop(int kind, var other, MethodGenerator context, var node) {
598 SourceSpan span, String code) 766 // TODO(jimhug): Support int/double better
599 : super(type, code, span, false); 767 if (other is! ListValue) return super.binop(kind, other, context, node);
600 768
601 static String codeWithComments(String canonicalCode, SourceSpan span) { 769 switch (kind) {
602 return canonicalCode; 770 case TokenKind.EQ_STRICT:
771 return new BoolValue(type == other.type && code == other.code,
772 isConst && other.isConst, node.span);
773 case TokenKind.NE_STRICT:
774 return new BoolValue(type != other.type || code != other.code,
775 isConst && other.isConst, node.span);
776 }
777
778 return super.binop(kind, other, context, node);
779 }
780
781 GlobalValue getGlobalValue() {
782 assert(isConst);
783
784 return world.gen.globalForConst(this, values);
603 } 785 }
604 } 786 }
605 787
606 /** An evaluated constant list expression. */
607 class ConstListValue extends EvaluatedValue {
608 List<EvaluatedValue> values;
609 788
610 factory ConstListValue(Type type, List<EvaluatedValue> values, 789 class MapValue extends EvaluatedValue {
611 String actualValue, String canonicalCode, SourceSpan span) { 790 List<Value> values;
612 return new ConstListValue._internal(type, values, actualValue, 791
613 canonicalCode, span, codeWithComments(canonicalCode, span)); 792 MapValue(this.values, bool isConst, Type type, SourceSpan span):
793 super(isConst, type, span);
794
795 String get code() {
796 // Cache?
797 var items = new ListValue(values, false, world.listType, span);
798 var tp = world.corelib.topType;
799 Member f = isConst ? tp.getMember('_constMap') : tp.getMember('_map');
800 // TODO(jimhug): Clean up invoke signature
801 var value = f.invoke(null, null, new Value.type(tp, null),
802 new Arguments(null, [items]));
803 return value.code;
614 } 804 }
615 805
616 ConstListValue._internal(type, this.values, 806 GlobalValue getGlobalValue() {
617 actualValue, canonicalCode, span, code) : 807 assert(isConst);
618 super._internal(type, actualValue, canonicalCode, span, code); 808
809 return world.gen.globalForConst(this, values);
810 }
811
812 Value binop(int kind, var other, MethodGenerator context, var node) {
813 if (other is! MapValue) return super.binop(kind, other, context, node);
814
815 switch (kind) {
816 case TokenKind.EQ_STRICT:
817 return new BoolValue(type == other.type && code == other.code,
818 isConst && other.isConst, node.span);
819 case TokenKind.NE_STRICT:
820 return new BoolValue(type != other.type || code != other.code,
821 isConst && other.isConst, node.span);
822 }
823
824 return super.binop(kind, other, context, node);
825 }
619 } 826 }
620 827
621 /** An evaluated constant map expression. */
622 class ConstMapValue extends EvaluatedValue {
623 Map<String, EvaluatedValue> values;
624 828
625 factory ConstMapValue(Type type, List<EvaluatedValue> keyValuePairs, 829 class ObjectValue extends EvaluatedValue {
626 String actualValue, String canonicalCode, SourceSpan span) { 830 Map<String, Value> fields;
627 final values = new Map<String, EvaluatedValue>(); 831 String _code;
628 for (int i = 0; i < keyValuePairs.length; i += 2) { 832
629 values[keyValuePairs[i].actualValue] = keyValuePairs[i + 1]; 833 ObjectValue(this.fields, bool isConst, Type type, this._code, SourceSpan span) :
630 } 834 super(isConst, type, span);
631 return new ConstMapValue._internal(type, values, actualValue, 835
632 canonicalCode, span, codeWithComments(canonicalCode, span)); 836 String get code() {
837 return _code;
633 } 838 }
634 839
635 ConstMapValue._internal(type, this.values, 840 Value binop(int kind, var other, MethodGenerator context, var node) {
636 actualValue, canonicalCode, span, code) : 841 if (other is! ObjectValue) return super.binop(kind, other, context, node);
637 super._internal(type, actualValue, canonicalCode, span, code); 842
843 switch (kind) {
844 case TokenKind.EQ_STRICT:
845 return new BoolValue(type == other.type && code == other.code,
846 isConst && other.isConst, node.span);
847 case TokenKind.NE_STRICT:
848 return new BoolValue(type != other.type || code != other.code,
849 isConst && other.isConst, node.span);
850 }
851
852 return super.binop(kind, other, context, node);
853 }
854
638 } 855 }
639 856
857
640 /** An evaluated constant object expression. */ 858 /** An evaluated constant object expression. */
859 /*
Jennifer Messerly 2012/01/09 19:06:54 remove?
jimhug 2012/01/09 21:34:30 Done.
641 class ConstObjectValue extends EvaluatedValue { 860 class ConstObjectValue extends EvaluatedValue {
642 Map<String, EvaluatedValue> fields; 861 Map<String, EvaluatedValue> fields;
643 862
644 factory ConstObjectValue( 863 factory ConstObjectValue(
645 Type type, Map<String, EvaluatedValue> fields, 864 Type type, Map<String, EvaluatedValue> fields,
646 String canonicalCode, SourceSpan span) { 865 String canonicalCode, SourceSpan span) {
647 // compute a unique-string form used to index this value in the global const 866 // compute a unique-string form used to index this value in the global const
648 // map. This is used to ensure that multiple const object values are 867 // map. This is used to ensure that multiple const object values are
649 // equivalent if they have the same type name and values on each field. 868 // equivalent if they have the same type name and values on each field.
650 final fieldValues = []; 869 final fieldValues = [];
651 for (var f in fields.getKeys()) { 870 for (var f in fields.getKeys()) {
652 fieldValues.add('$f = ${fields[f].actualValue}'); 871 fieldValues.add('$f = ${fields[f].actualValue}');
653 } 872 }
654 fieldValues.sort((a, b) => a.compareTo(b)); 873 fieldValues.sort((a, b) => a.compareTo(b));
655 final actualValue = 'const ${type.jsname} [' 874 final actualValue = 'const ${type.jsname} ['
656 + Strings.join(fieldValues, ',') + ']'; 875 + Strings.join(fieldValues, ',') + ']';
657 return new ConstObjectValue._internal(type, fields, actualValue, 876 return new ConstObjectValue._internal(type, fields, actualValue,
658 canonicalCode, span, codeWithComments(canonicalCode, span)); 877 canonicalCode, span, codeWithComments(canonicalCode, span));
659 } 878 }
660 879
661 ConstObjectValue._internal(type, this.fields, 880 ConstObjectValue._internal(type, this.fields,
662 actualValue, canonicalCode, span, code) : 881 actualValue, canonicalCode, span, code) :
663 super._internal(type, actualValue, canonicalCode, span, code); 882 super._internal(type, actualValue, canonicalCode, span, code);
664
665 } 883 }
884 */
666 885
667 /** 886 /**
668 * A global value in the generated code, which corresponds to either a static 887 * A global value in the generated code, which corresponds to either a static
669 * field or a memoized const expressions. 888 * field or a memoized const expressions.
670 */ 889 */
671 class GlobalValue extends Value implements Comparable { 890 class GlobalValue extends Value implements Comparable {
672 /** Static field definition (null for constant exp). */ 891 /** Static field definition (null for constant exp). */
673 FieldMember field; 892 FieldMember field;
674 893
675 /** 894 /**
676 * When [this] represents a constant expression, the global variable name 895 * When [this] represents a constant expression, the global variable name
677 * generated for it. 896 * generated for it.
678 */ 897 */
679 String name; 898 String name;
680 899
681 /** The value of the field or constant expression to declare. */ 900 /** The value of the field or constant expression to declare. */
682 Value exp; 901 Value exp;
683 902
684 /**
685 * A canonicalized form of the code. Two const expressions that result in the
686 * same instance should have the same [canonicalCode].
687 */
688 String canonicalCode;
689 903
690 /** True for either cont expressions or a final static field. */ 904 /** True for either cont expressions or a final static field. */
691 bool get isConst() => exp.isConst && (field == null || field.isFinal); 905 bool get isConst() => exp.isConst && (field == null || field.isFinal);
692 906
693 /** The actual constant value, when [isConst] is true. */ 907 /** The actual constant value, when [isConst] is true. */
694 get actualValue() => exp.dynamic.actualValue; 908 get actualValue() => exp.dynamic.actualValue;
695 909
696 /** If [isConst], the [EvaluatedValue] that defines this value. */ 910 /** If [isConst], the [EvaluatedValue] that defines this value. */
697 EvaluatedValue get constValue() => isConst ? exp.constValue : null; 911 EvaluatedValue get constValue() => isConst ? exp.constValue : null;
698 912
699 /** Other globals that should be defined before this global. */ 913 /** Other globals that should be defined before this global. */
700 List<GlobalValue> dependencies; 914 List<GlobalValue> dependencies;
701 915
702 factory GlobalValue.fromStatic(field, Value exp, dependencies) {
703 var code = (exp.isConst ? exp.canonicalCode : exp.code);
704 var codeWithComment = '$code/*${field.declaringType.name}.${field.name}*/';
705 return new GlobalValue(
706 exp.type, codeWithComment, field.isFinal, field, null, exp,
707 code, exp.span, dependencies.filter((d) => d is GlobalValue));
708 }
709
710 factory GlobalValue.fromConst(uniqueId, Value exp, dependencies) {
711 var name = "const\$$uniqueId";
712 var codeWithComment = "$name/*${_escapeForComment(exp.span.text)}*/";
713 return new GlobalValue(
714 exp.type, codeWithComment, true, null, name, exp, name,
715 exp.span,
716 dependencies.filter((d) => d is GlobalValue));
717 }
718
719 GlobalValue(Type type, String code, bool isConst, 916 GlobalValue(Type type, String code, bool isConst,
720 this.field, this.name, this.exp, this.canonicalCode, 917 this.field, this.name, this.exp,
721 SourceSpan span, List<GlobalValue> _dependencies) 918 SourceSpan span, List<Value> _dependencies)
722 : super(type, code, span, !isConst), dependencies = [] { 919 : super(type, code, span, !isConst), dependencies = [] {
723 // store transitive-dependencies so sorting algorithm works correctly. 920 // store transitive-dependencies so sorting algorithm works correctly.
724 for (final dep in _dependencies) { 921 for (var dep in _dependencies) {
725 dependencies.add(dep); 922 if (dep is GlobalValue) {
726 dependencies.addAll(dep.dependencies); 923 dependencies.add(dep);
924 dependencies.addAll(dep.dependencies);
925 }
727 } 926 }
728 } 927 }
729 928
730 int compareTo(GlobalValue other) { 929 int compareTo(GlobalValue other) {
731 // order by dependencies, o.w. by name 930 // order by dependencies, o.w. by name
732 if (other == this) { 931 if (other == this) {
733 return 0; 932 return 0;
734 } else if (dependencies.indexOf(other) >= 0) { 933 } else if (dependencies.indexOf(other) >= 0) {
735 return 1; 934 return 1;
736 } else if (other.dependencies.indexOf(this) >= 0) { 935 } else if (other.dependencies.indexOf(this) >= 0) {
(...skipping 62 matching lines...) Expand 10 before | Expand all | Expand 10 after
799 } 998 }
800 999
801 _ensureCode(); 1000 _ensureCode();
802 return null; 1001 return null;
803 } 1002 }
804 } 1003 }
805 1004
806 String _escapeForComment(String text) { 1005 String _escapeForComment(String text) {
807 return text.replaceAll('/*', '/ *').replaceAll('*/', '* /'); 1006 return text.replaceAll('/*', '/ *').replaceAll('*/', '* /');
808 } 1007 }
OLDNEW
« frog/minfrog ('K') | « frog/tree.g.dart ('k') | tests/isolate/isolate.status » ('j') | no next file with comments »

Powered by Google App Engine
This is Rietveld 408576698