| OLD | NEW |
| 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 /** The [Type] of the [Value]. */ | 9 /** The [Type] of the [Value]. */ |
| 10 Type type; | 10 Type type; |
| 11 | 11 |
| 12 /** The code to generate this value. */ | 12 /** The javascript code to generate this value. */ |
| 13 String code; | 13 String code; |
| 14 | 14 |
| 15 /** The source location that created this value for error messages. */ | 15 /** The source location that created this value for error messages. */ |
| 16 SourceSpan span; | 16 SourceSpan span; |
| 17 | 17 |
| 18 /** Is this a reference to super? */ | 18 /** Is this a reference to super? */ |
| 19 bool isSuper; | 19 bool isSuper = false; |
| 20 | 20 |
| 21 /** Is this a pretend first-class type? */ | 21 /** Is this a pretend first-class type? */ |
| 22 bool isType; | 22 bool isType = false; |
| 23 | 23 |
| 24 /** If we reference this value multiple times, do we need a temp? */ | 24 /** If we reference this value multiple times, do we need a temp? */ |
| 25 bool needsTemp; | 25 bool needsTemp; |
| 26 | 26 |
| 27 // TODO(jmesserly): until reified generics are fixed, treat ParameterType as | 27 // TODO(jmesserly): until reified generics are fixed, treat ParameterType as |
| 28 // "var". | 28 // "var". |
| 29 bool get _typeIsVarOrParameterType() => type.isVar || type is ParameterType; | 29 bool get _typeIsVarOrParameterType() => type.isVar || type is ParameterType; |
| 30 | 30 |
| 31 Value(this.type, this.code, this.span, | 31 Value(this.type, this.code, this.span, [this.needsTemp = true]) { |
| 32 // TODO(sigmund): reorder, so that needsTemp comes first. | 32 if (type == null) world.internalError('type passed as null', span); |
| 33 [this.isSuper = false, this.needsTemp = true, this.isType = false]) { | |
| 34 if (type == null) type = world.varType; | |
| 35 } | 33 } |
| 36 | 34 |
| 37 /** Is this value a constant expression? */ | 35 /** Is this value a constant expression? */ |
| 38 bool get isConst() => false; | 36 bool get isConst() => false; |
| 39 | 37 |
| 40 /** | 38 /** |
| 41 * A canonicalized form of the code. Two const expressions that result in the | 39 * A canonicalized form of the code. Two const expressions that result in the |
| 42 * same instance should have the same [canonicalCode]. | 40 * same instance should have the same [canonicalCode]. |
| 43 */ | 41 */ |
| 44 String get canonicalCode() => null; | 42 String get canonicalCode() => null; |
| (...skipping 23 matching lines...) Expand all Loading... |
| 68 | 66 |
| 69 | 67 |
| 70 Value invoke(MethodGenerator context, String name, Node node, Arguments args, | 68 Value invoke(MethodGenerator context, String name, Node node, Arguments args, |
| 71 [bool isDynamic=false]) { | 69 [bool isDynamic=false]) { |
| 72 // TODO(jimhug): The != method is weird - understand it better. | 70 // TODO(jimhug): The != method is weird - understand it better. |
| 73 if (_typeIsVarOrParameterType && name == '\$ne') { | 71 if (_typeIsVarOrParameterType && name == '\$ne') { |
| 74 if (args.values.length != 1) { | 72 if (args.values.length != 1) { |
| 75 world.warning('wrong number of arguments for !=', node.span); | 73 world.warning('wrong number of arguments for !=', node.span); |
| 76 } | 74 } |
| 77 world.gen.corejs.useOperator('\$ne'); | 75 world.gen.corejs.useOperator('\$ne'); |
| 78 return new Value(null, '\$ne($code, ${args.values[0].code})', node.span); | 76 return new Value(world.varType, '\$ne($code, ${args.values[0].code})', |
| 77 node.span); |
| 79 } | 78 } |
| 80 | 79 |
| 81 // TODO(jmesserly): it'd be nice to remove these special cases | 80 // TODO(jmesserly): it'd be nice to remove these special cases |
| 82 // We could create a $call (and $ne) in world members, and have | 81 // We could create a $call (and $ne) in world members, and have |
| 83 // those guys handle the canInvoke/Invoke logic. | 82 // those guys handle the canInvoke/Invoke logic. |
| 84 | 83 |
| 85 // Note: this check is a little different than the one in canInvoke, because | 84 // Note: this check is a little different than the one in canInvoke, because |
| 86 // sometimes we need to call dynamically even if we found the $call method | 85 // sometimes we need to call dynamically even if we found the $call method |
| 87 // statically. | 86 // statically. |
| 88 | 87 |
| (...skipping 94 matching lines...) Expand 10 before | Expand all | Expand 10 after Loading... |
| 183 world.error('Types are not first class', span); | 182 world.error('Types are not first class', span); |
| 184 } | 183 } |
| 185 } | 184 } |
| 186 | 185 |
| 187 /** Generate a call to an unknown function type. */ | 186 /** Generate a call to an unknown function type. */ |
| 188 Value _varCall(MethodGenerator context, Arguments args) { | 187 Value _varCall(MethodGenerator context, Arguments args) { |
| 189 // TODO(jmesserly): calls to unknown functions will bypass type checks, | 188 // TODO(jmesserly): calls to unknown functions will bypass type checks, |
| 190 // which normally happen on the caller side, or in the generated stub for | 189 // which normally happen on the caller side, or in the generated stub for |
| 191 // dynamic method calls. What should we do? | 190 // dynamic method calls. What should we do? |
| 192 var stub = world.functionType.getCallStub(args); | 191 var stub = world.functionType.getCallStub(args); |
| 193 return new Value(null, '$code.${stub.name}(${args.getCode()})', span); | 192 return new Value(world.varType, '$code.${stub.name}(${args.getCode()})', |
| 193 span); |
| 194 } | 194 } |
| 195 | 195 |
| 196 /** True if convertTo would generate a conversion. */ | 196 /** True if convertTo would generate a conversion. */ |
| 197 // TODO(jmesserly): I don't like how this is coupled to convertTo. | 197 // TODO(jmesserly): I don't like how this is coupled to convertTo. |
| 198 bool needsConversion(Type toType) { | 198 bool needsConversion(Type toType) { |
| 199 var callMethod = toType.getCallMethod(); | 199 var callMethod = toType.getCallMethod(); |
| 200 if (callMethod != null) { | 200 if (callMethod != null) { |
| 201 int arity = callMethod.parameters.length; | 201 int arity = callMethod.parameters.length; |
| 202 var myCall = type.getCallMethod(); | 202 var myCall = type.getCallMethod(); |
| 203 if (myCall == null || myCall.parameters.length != arity) { | 203 if (myCall == null || myCall.parameters.length != arity) { |
| (...skipping 72 matching lines...) Expand 10 before | Expand all | Expand 10 after Loading... |
| 276 return _typeAssert(context, toType, node); | 276 return _typeAssert(context, toType, node); |
| 277 } else { | 277 } else { |
| 278 return this; | 278 return this; |
| 279 } | 279 } |
| 280 } | 280 } |
| 281 | 281 |
| 282 // TODO(jmesserly): this generates an unnecessary check for the 90% | 282 // TODO(jmesserly): this generates an unnecessary check for the 90% |
| 283 // case where the thing passed in was a non-overloaded == or != expression | 283 // case where the thing passed in was a non-overloaded == or != expression |
| 284 // We'll want to eliminate these, probably by tracking non-null bools in the | 284 // We'll want to eliminate these, probably by tracking non-null bools in the |
| 285 // type system. | 285 // type system. |
| 286 // This matches the interesting Boolean Conversion section of the spec. |
| 286 Value convertToNonNullBool(MethodGenerator context, Node node) { | 287 Value convertToNonNullBool(MethodGenerator context, Node node) { |
| 287 if (!type.isAssignable(world.boolType)) { | 288 if (!type.isAssignable(world.boolType)) { |
| 288 convertWarning(world.boolType, node); | 289 convertWarning(world.boolType, node); |
| 289 } | 290 } |
| 290 if (!options.enableTypeChecks) { | 291 if (!options.enableTypeChecks) { |
| 292 // TODO(jimhug): If type != world.boolType, this should return |
| 293 // this.code === true according to the spec. |
| 291 return this; | 294 return this; |
| 292 } else { | 295 } else { |
| 293 // TODO(jmesserly): this is hacky. | 296 // TODO(jmesserly): this is hacky. |
| 294 if (code.startsWith('\$notnull_bool')) { | 297 if (code.startsWith('\$notnull_bool')) { |
| 295 return this; | 298 return this; |
| 296 } else { | 299 } else { |
| 297 world.gen.corejs.useNotNullBool = true; | 300 world.gen.corejs.useNotNullBool = true; |
| 298 return new Value(world.boolType, '\$notnull_bool($code)', span); | 301 return new Value(world.boolType, '\$notnull_bool($code)', span); |
| 299 } | 302 } |
| 300 } | 303 } |
| (...skipping 194 matching lines...) Expand 10 before | Expand all | Expand 10 after Loading... |
| 495 String canonicalCode; | 498 String canonicalCode; |
| 496 | 499 |
| 497 factory EvaluatedValue(Type type, actualValue, String canonicalCode, | 500 factory EvaluatedValue(Type type, actualValue, String canonicalCode, |
| 498 SourceSpan span) { | 501 SourceSpan span) { |
| 499 return new EvaluatedValue._internal(type, actualValue, | 502 return new EvaluatedValue._internal(type, actualValue, |
| 500 canonicalCode, span, codeWithComments(canonicalCode, span)); | 503 canonicalCode, span, codeWithComments(canonicalCode, span)); |
| 501 } | 504 } |
| 502 | 505 |
| 503 EvaluatedValue._internal(Type type, this.actualValue, this.canonicalCode, | 506 EvaluatedValue._internal(Type type, this.actualValue, this.canonicalCode, |
| 504 SourceSpan span, String code) | 507 SourceSpan span, String code) |
| 505 : super(type, code, span, false, false, false); | 508 : super(type, code, span, false); |
| 506 | 509 |
| 507 static String codeWithComments(String canonicalCode, SourceSpan span) { | 510 static String codeWithComments(String canonicalCode, SourceSpan span) { |
| 508 return (span != null && span.text != canonicalCode) | 511 return (span != null && span.text != canonicalCode) |
| 509 ? '$canonicalCode/*${span.text}*/' : canonicalCode; | 512 ? '$canonicalCode/*${span.text}*/' : canonicalCode; |
| 510 } | 513 } |
| 511 } | 514 } |
| 512 | 515 |
| 513 /** An evaluated constant list expression. */ | 516 /** An evaluated constant list expression. */ |
| 514 class ConstListValue extends EvaluatedValue { | 517 class ConstListValue extends EvaluatedValue { |
| 515 List<EvaluatedValue> values; | 518 List<EvaluatedValue> values; |
| (...skipping 100 matching lines...) Expand 10 before | Expand all | Expand 10 after Loading... |
| 616 var codeWithComment = "$name/*${exp.span.text}*/"; | 619 var codeWithComment = "$name/*${exp.span.text}*/"; |
| 617 return new GlobalValue( | 620 return new GlobalValue( |
| 618 exp.type, codeWithComment, true, null, name, exp, name, | 621 exp.type, codeWithComment, true, null, name, exp, name, |
| 619 exp.span, | 622 exp.span, |
| 620 dependencies.filter((d) => d is GlobalValue)); | 623 dependencies.filter((d) => d is GlobalValue)); |
| 621 } | 624 } |
| 622 | 625 |
| 623 GlobalValue(Type type, String code, bool isConst, | 626 GlobalValue(Type type, String code, bool isConst, |
| 624 this.field, this.name, this.exp, this.canonicalCode, | 627 this.field, this.name, this.exp, this.canonicalCode, |
| 625 SourceSpan span, this.dependencies) | 628 SourceSpan span, this.dependencies) |
| 626 : super(type, code, span, false, !isConst, false); | 629 : super(type, code, span, !isConst); |
| 627 | 630 |
| 628 int compareTo(GlobalValue other) { | 631 int compareTo(GlobalValue other) { |
| 629 // order by dependencies, o.w. by name | 632 // order by dependencies, o.w. by name |
| 630 if (other == this) { | 633 if (other == this) { |
| 631 return 0; | 634 return 0; |
| 632 } else if (dependencies.indexOf(other, 0) >= 0) { | 635 } else if (dependencies.indexOf(other, 0) >= 0) { |
| 633 return 1; | 636 return 1; |
| 634 } else if (other.dependencies.indexOf(this, 0) >= 0) { | 637 } else if (other.dependencies.indexOf(this, 0) >= 0) { |
| 635 return -1; | 638 return -1; |
| 636 } else if (dependencies.length > other.dependencies.length) { | 639 } else if (dependencies.length > other.dependencies.length) { |
| (...skipping 13 matching lines...) Expand all Loading... |
| 650 } | 653 } |
| 651 | 654 |
| 652 /** | 655 /** |
| 653 * Represents the hidden or implicit value in a bare reference like 'a'. | 656 * Represents the hidden or implicit value in a bare reference like 'a'. |
| 654 * This could be this, the current type, or the current library for purposes | 657 * This could be this, the current type, or the current library for purposes |
| 655 * of resolving members. | 658 * of resolving members. |
| 656 */ | 659 */ |
| 657 class BareValue extends Value { | 660 class BareValue extends Value { |
| 658 MethodGenerator home; | 661 MethodGenerator home; |
| 659 | 662 |
| 660 BareValue(this.home, MethodGenerator outermost, SourceSpan span): | 663 BareValue(this.home, MethodGenerator outermost, SourceSpan span) |
| 661 super(outermost.method.declaringType, null, span, false, false, | 664 : super(outermost.method.declaringType, null, span, false) { |
| 662 outermost.isStatic); | 665 isType = outermost.isStatic; |
| 666 } |
| 663 | 667 |
| 664 _tryResolveMember(MethodGenerator context, String name) { | 668 _tryResolveMember(MethodGenerator context, String name) { |
| 665 assert(context == home); | 669 assert(context == home); |
| 666 | 670 |
| 667 // First look for members directly defined on my type. | 671 // First look for members directly defined on my type. |
| 668 var member = type.resolveMember(name); | 672 var member = type.resolveMember(name); |
| 669 if (member != null) { | 673 if (member != null) { |
| 670 assert(code == null); | 674 assert(code == null); |
| 671 // TODO(jimhug): Lazy initialization here is weird! | 675 // TODO(jimhug): Lazy initialization here is weird! |
| 672 if (isType) { | 676 if (isType) { |
| 673 code = type.jsname; | 677 code = type.jsname; |
| 674 } else { | 678 } else { |
| 675 code = home._makeThisCode(); | 679 code = home._makeThisCode(); |
| 676 } | 680 } |
| 677 return member; | 681 return member; |
| 678 } | 682 } |
| 679 | 683 |
| 680 // Then look for members in my library. | 684 // Then look for members in my library. |
| 681 member = home.library.lookup(name, span); | 685 member = home.library.lookup(name, span); |
| 682 if (member != null) { | 686 if (member != null) { |
| 683 return member; | 687 return member; |
| 684 } | 688 } |
| 685 | 689 |
| 686 return null; | 690 return null; |
| 687 } | 691 } |
| 688 } | 692 } |
| OLD | NEW |