Chromium Code Reviews| 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 /** A formal parameter to a [Method]. */ | 5 /** A formal parameter to a [Method]. */ |
| 6 class Parameter { | 6 class Parameter { |
| 7 FormalNode definition; | 7 FormalNode definition; |
| 8 | 8 |
| 9 String name; | 9 String name; |
| 10 Type type; | 10 Type type; |
| (...skipping 122 matching lines...) Expand 10 before | Expand all | Expand 10 after Loading... | |
| 133 | 133 |
| 134 Definition get initDelegate() => | 134 Definition get initDelegate() => |
| 135 world.internalError('cannot have initializers', span); | 135 world.internalError('cannot have initializers', span); |
| 136 Definition set initDelegate(ctor) => | 136 Definition set initDelegate(ctor) => |
| 137 world.internalError('cannot have initializers', span); | 137 world.internalError('cannot have initializers', span); |
| 138 | 138 |
| 139 Definition get definition() => null; | 139 Definition get definition() => null; |
| 140 | 140 |
| 141 List<Parameter> get parameters() => []; | 141 List<Parameter> get parameters() => []; |
| 142 | 142 |
| 143 // TODO(jimhug): Fix these names once get/set are truly pseudo-keywords. | |
| 144 // TODO(jmesserly): isDynamic isn't a great name for this, something better? | 143 // TODO(jmesserly): isDynamic isn't a great name for this, something better? |
| 145 abstract Value get_(MethodGenerator context, Node node, Value target, | 144 abstract Value _get(MethodGenerator context, Node node, Value target, |
| 146 [bool isDynamic]); | 145 [bool isDynamic]); |
| 147 | 146 |
| 148 abstract Value set_(MethodGenerator context, Node node, Value target, | 147 abstract Value _set(MethodGenerator context, Node node, Value target, |
| 149 Value value, [bool isDynamic]); | 148 Value value, [bool isDynamic]); |
| 150 | 149 |
| 151 bool canInvoke(MethodGenerator context, Arguments args) { | 150 bool canInvoke(MethodGenerator context, Arguments args) { |
| 152 return canGet && new Value(returnType, null).canInvoke(context, '\$call', ar gs); | 151 // TODO(jimhug): Needs better source location? |
|
Jennifer Messerly
2011/11/10 22:50:39
I would hope that "canInvoke" can't emit errors.
| |
| 152 return canGet && | |
| 153 new Value(returnType, null, null).canInvoke(context, '\$call', args); | |
| 153 } | 154 } |
| 154 | 155 |
| 155 Value invoke(MethodGenerator context, Node node, Value target, Arguments args, | 156 Value invoke(MethodGenerator context, Node node, Value target, Arguments args, |
| 156 [bool isDynamic=false]) { | 157 [bool isDynamic=false]) { |
| 157 var newTarget = get_(context, node, target, isDynamic); | 158 var newTarget = _get(context, node, target, isDynamic); |
| 158 return newTarget.invoke(context, '\$call', node, args, isDynamic); | 159 return newTarget.invoke(context, '\$call', node, args, isDynamic); |
| 159 } | 160 } |
| 160 | 161 |
| 161 bool override(Member other) { | 162 bool override(Member other) { |
| 162 if (isStatic) { | 163 if (isStatic) { |
| 163 world.error('static members can not hide parent members', | 164 world.error('static members can not hide parent members', |
| 164 span, other.span); | 165 span, other.span); |
| 165 return false; | 166 return false; |
| 166 } else if (other.isStatic) { | 167 } else if (other.isStatic) { |
| 167 world.error('can not override static member', span, other.span); | 168 world.error('can not override static member', span, other.span); |
| (...skipping 42 matching lines...) Expand 10 before | Expand all | Expand 10 after Loading... | |
| 210 | 211 |
| 211 // If this really becomes first class, this should return typeof(Type) | 212 // If this really becomes first class, this should return typeof(Type) |
| 212 Type get returnType() => world.varType; | 213 Type get returnType() => world.varType; |
| 213 | 214 |
| 214 bool canInvoke(MethodGenerator context, Arguments args) => false; | 215 bool canInvoke(MethodGenerator context, Arguments args) => false; |
| 215 bool get canGet() => true; | 216 bool get canGet() => true; |
| 216 bool get canSet() => false; | 217 bool get canSet() => false; |
| 217 | 218 |
| 218 void resolve(Type inType) {} | 219 void resolve(Type inType) {} |
| 219 | 220 |
| 220 Value get_(MethodGenerator context, Node node, Value target, | 221 Value _get(MethodGenerator context, Node node, Value target, |
| 221 [bool isDynamic=false]) { | 222 [bool isDynamic=false]) { |
| 222 assert(target == null || target.type.isTop); | |
| 223 // TODO(jmesserly): named args | 223 // TODO(jmesserly): named args |
|
Jennifer Messerly
2011/11/10 22:50:39
btw, I think the VM is the main blocker here. Mayb
| |
| 224 return new Value(type, type.jsname, false, false, true); | 224 return new Value(type, type.jsname, node.span, false, false, true); |
| 225 } | 225 } |
| 226 | 226 |
| 227 Value set_(MethodGenerator context, Node node, Value target, Value value, | 227 Value _set(MethodGenerator context, Node node, Value target, Value value, |
| 228 [bool isDynamic=false]) { | 228 [bool isDynamic=false]) { |
| 229 world.error('can not set type', type.definition.span); | 229 world.error('can not set type', type.definition.span); |
| 230 } | 230 } |
| 231 | 231 |
| 232 Value invoke(MethodGenerator context, Node node, Value target, Arguments args, | 232 Value invoke(MethodGenerator context, Node node, Value target, Arguments args, |
| 233 [bool isDynamic=false]) { | 233 [bool isDynamic=false]) { |
| 234 world.error('can not invoke type', type.definition.span); | 234 world.error('can not invoke type', type.definition.span); |
| 235 } | 235 } |
| 236 } | 236 } |
| 237 | 237 |
| (...skipping 122 matching lines...) Expand 10 before | Expand all | Expand 10 after Loading... | |
| 360 | 360 |
| 361 if (isStatic) { | 361 if (isStatic) { |
| 362 _computedValue = world.gen.globalForStaticField( | 362 _computedValue = world.gen.globalForStaticField( |
| 363 this, _computedValue, [_computedValue]); | 363 this, _computedValue, [_computedValue]); |
| 364 } | 364 } |
| 365 _computing = false; | 365 _computing = false; |
| 366 } | 366 } |
| 367 return _computedValue; | 367 return _computedValue; |
| 368 } | 368 } |
| 369 | 369 |
| 370 Value get_(MethodGenerator context, Node node, Value target, | 370 Value _get(MethodGenerator context, Node node, Value target, |
| 371 [bool isDynamic=false]) { | 371 [bool isDynamic=false]) { |
| 372 if (!isDynamic) { | 372 if (!isDynamic) { |
| 373 declaringType.markUsed(); | 373 declaringType.markUsed(); |
| 374 } | 374 } |
| 375 if (isStatic) { | 375 if (isStatic) { |
| 376 // Make sure to compute the value of all static fields, even if we don't | 376 // Make sure to compute the value of all static fields, even if we don't |
| 377 // use this value immediately. | 377 // use this value immediately. |
| 378 var cv = computeValue(); | 378 var cv = computeValue(); |
| 379 if (isFinal) { | 379 if (isFinal) { |
| 380 return cv; | 380 return cv; |
| 381 } | 381 } |
| 382 if (declaringType.isTop) { | 382 if (declaringType.isTop) { |
| 383 return new Value(type, '$jsname'); | 383 return new Value(type, '$jsname', node.span); |
| 384 } else { | 384 } else { |
| 385 return new Value(type, '${declaringType.jsname}.$jsname'); | 385 return new Value(type, '${declaringType.jsname}.$jsname', node.span); |
| 386 } | 386 } |
| 387 } else if (target.isConst && isFinal) { | 387 } else if (target.isConst && isFinal) { |
| 388 // take advantage of consts and retrieve the value directly if possible | 388 // take advantage of consts and retrieve the value directly if possible |
| 389 var constTarget = target is GlobalValue ? target.dynamic.exp : target; | 389 var constTarget = target is GlobalValue ? target.dynamic.exp : target; |
| 390 if (constTarget is ConstObjectValue) { | 390 if (constTarget is ConstObjectValue) { |
| 391 return constTarget.fields[name]; | 391 return constTarget.fields[name]; |
| 392 } else if (constTarget.type == world.stringType && name == 'length') { | 392 } else if (constTarget.type == world.stringType && name == 'length') { |
| 393 return new Value(type, '${constTarget.actualValue.length}'); | 393 return new Value(type, '${constTarget.actualValue.length}', node.span); |
| 394 } | 394 } |
| 395 } | 395 } |
| 396 return new Value(type, '${target.code}.$jsname'); | 396 return new Value(type, '${target.code}.$jsname', node.span); |
| 397 } | 397 } |
| 398 | 398 |
| 399 Value set_(MethodGenerator context, Node node, Value target, Value value, | 399 Value _set(MethodGenerator context, Node node, Value target, Value value, |
| 400 [bool isDynamic=false]) { | 400 [bool isDynamic=false]) { |
| 401 var lhs = get_(context, node, target, isDynamic); | 401 var lhs = _get(context, node, target, isDynamic); |
| 402 value = value.convertTo(context, type, node, isDynamic); | 402 value = value.convertTo(context, type, node, isDynamic); |
| 403 return new Value(type, '${lhs.code} = ${value.code}'); | 403 return new Value(type, '${lhs.code} = ${value.code}', node.span); |
| 404 } | 404 } |
| 405 } | 405 } |
| 406 | 406 |
| 407 class PropertyMember extends Member { | 407 class PropertyMember extends Member { |
| 408 MethodMember getter; | 408 MethodMember getter; |
| 409 MethodMember setter; | 409 MethodMember setter; |
| 410 | 410 |
| 411 Member _overriddenField; | 411 Member _overriddenField; |
| 412 | 412 |
| 413 bool _provideFieldSyntax = false; | 413 bool _provideFieldSyntax = false; |
| (...skipping 31 matching lines...) Expand 10 before | Expand all | Expand 10 after Loading... | |
| 445 if (other.isProperty) addFromParent(other); | 445 if (other.isProperty) addFromParent(other); |
| 446 else _overriddenField = other; | 446 else _overriddenField = other; |
| 447 return true; | 447 return true; |
| 448 } else { | 448 } else { |
| 449 world.error('property can only override field or property', | 449 world.error('property can only override field or property', |
| 450 span, other.span); | 450 span, other.span); |
| 451 return false; | 451 return false; |
| 452 } | 452 } |
| 453 } | 453 } |
| 454 | 454 |
| 455 Value get_(MethodGenerator context, Node node, Value target, | 455 Value _get(MethodGenerator context, Node node, Value target, |
| 456 [bool isDynamic=false]) { | 456 [bool isDynamic=false]) { |
| 457 if (getter == null) { | 457 if (getter == null) { |
| 458 if (_overriddenField != null) { | 458 if (_overriddenField != null) { |
| 459 return _overriddenField.get_(context, node, target, isDynamic); | 459 return _overriddenField._get(context, node, target, isDynamic); |
| 460 } | 460 } |
| 461 return target.invokeNoSuchMethod(context, 'get:$name', node); | 461 return target.invokeNoSuchMethod(context, 'get:$name', node); |
| 462 } | 462 } |
| 463 return getter.invoke(context, node, target, Arguments.EMPTY); | 463 return getter.invoke(context, node, target, Arguments.EMPTY); |
| 464 } | 464 } |
| 465 | 465 |
| 466 Value set_(MethodGenerator context, Node node, Value target, Value value, | 466 Value _set(MethodGenerator context, Node node, Value target, Value value, |
| 467 [bool isDynamic=false]) { | 467 [bool isDynamic=false]) { |
| 468 if (setter == null) { | 468 if (setter == null) { |
| 469 if (_overriddenField != null) { | 469 if (_overriddenField != null) { |
| 470 return _overriddenField.set_(context, node, target, value, isDynamic); | 470 return _overriddenField._set(context, node, target, value, isDynamic); |
| 471 } | 471 } |
| 472 return target.invokeNoSuchMethod(context, 'set:$name', node, | 472 return target.invokeNoSuchMethod(context, 'set:$name', node, |
| 473 new Arguments(null, [value])); | 473 new Arguments(null, [value])); |
| 474 } | 474 } |
| 475 return setter.invoke(context, node, target, new Arguments(null, [value]), | 475 return setter.invoke(context, node, target, new Arguments(null, [value]), |
| 476 isDynamic); | 476 isDynamic); |
| 477 } | 477 } |
| 478 | 478 |
| 479 addFromParent(Member parentMember) { | 479 addFromParent(Member parentMember) { |
| 480 // TODO(jimhug): Egregious Hack! | 480 // TODO(jimhug): Egregious Hack! |
| (...skipping 76 matching lines...) Expand 10 before | Expand all | Expand 10 after Loading... | |
| 557 Definition set initDelegate(ctor) { baseMember.initDelegate = ctor; } | 557 Definition set initDelegate(ctor) { baseMember.initDelegate = ctor; } |
| 558 | 558 |
| 559 Type resolveType(TypeReference node, bool isRequired) { | 559 Type resolveType(TypeReference node, bool isRequired) { |
| 560 var type = baseMember.resolveType(node, isRequired); | 560 var type = baseMember.resolveType(node, isRequired); |
| 561 return type.resolveTypeParams(declaringType); | 561 return type.resolveTypeParams(declaringType); |
| 562 } | 562 } |
| 563 | 563 |
| 564 // TODO(jimhug): Add support for type params. | 564 // TODO(jimhug): Add support for type params. |
| 565 bool override(Member other) => baseMember.override(other); | 565 bool override(Member other) => baseMember.override(other); |
| 566 | 566 |
| 567 Value get_(MethodGenerator context, Node node, Value target, | 567 Value _get(MethodGenerator context, Node node, Value target, |
| 568 [bool isDynamic=false]) { | 568 [bool isDynamic=false]) { |
| 569 Value ret = baseMember.get_(context, node, target, isDynamic); | 569 Value ret = baseMember._get(context, node, target, isDynamic); |
| 570 return new Value(returnType, ret.code); | 570 return new Value(returnType, ret.code, node.span); |
| 571 } | 571 } |
| 572 | 572 |
| 573 Value set_(MethodGenerator context, Node node, Value target, Value value, | 573 Value _set(MethodGenerator context, Node node, Value target, Value value, |
| 574 [bool isDynamic=false]) { | 574 [bool isDynamic=false]) { |
| 575 // TODO(jimhug): Check arg types in context of concrete type. | 575 // TODO(jimhug): Check arg types in context of concrete type. |
| 576 Value ret = baseMember.set_(context, node, target, value, isDynamic); | 576 Value ret = baseMember._set(context, node, target, value, isDynamic); |
| 577 return new Value(returnType, ret.code); | 577 return new Value(returnType, ret.code, node.span); |
| 578 } | 578 } |
| 579 | 579 |
| 580 Value invoke(MethodGenerator context, Node node, Value target, Arguments args, | 580 Value invoke(MethodGenerator context, Node node, Value target, Arguments args, |
| 581 [bool isDynamic=false]) { | 581 [bool isDynamic=false]) { |
| 582 // TODO(jimhug): Check arg types in context of concrete type. | 582 // TODO(jimhug): Check arg types in context of concrete type. |
| 583 Value ret = baseMember.invoke(context, node, target, args, isDynamic); | 583 Value ret = baseMember.invoke(context, node, target, args, isDynamic); |
| 584 var code = ret.code; | 584 var code = ret.code; |
| 585 if (isConstructor) { | 585 if (isConstructor) { |
| 586 // TODO(jimhug): Egregious hack - won't live through the weekend. | 586 // TODO(jimhug): Egregious hack - won't live through the weekend. |
| 587 code = code.replaceFirst( | 587 code = code.replaceFirst( |
| 588 declaringType.genericType.jsname, declaringType.jsname); | 588 declaringType.genericType.jsname, declaringType.jsname); |
| 589 } | 589 } |
| 590 declaringType.genMethod(this); | 590 declaringType.genMethod(this); |
| 591 return new Value(returnType, code); | 591 return new Value(returnType, code, node.span); |
| 592 } | 592 } |
| 593 } | 593 } |
| 594 | 594 |
| 595 | 595 |
| 596 /** Represents a Dart method or top-level function. */ | 596 /** Represents a Dart method or top-level function. */ |
| 597 class MethodMember extends Member { | 597 class MethodMember extends Member { |
| 598 FunctionDefinition definition; | 598 FunctionDefinition definition; |
| 599 Type returnType; | 599 Type returnType; |
| 600 List<Parameter> parameters; | 600 List<Parameter> parameters; |
| 601 | 601 |
| (...skipping 108 matching lines...) Expand 10 before | Expand all | Expand 10 after Loading... | |
| 710 } | 710 } |
| 711 return -1; | 711 return -1; |
| 712 } | 712 } |
| 713 | 713 |
| 714 bool get prefersPropertySyntax() => true; | 714 bool get prefersPropertySyntax() => true; |
| 715 bool get requiresFieldSyntax() => false; | 715 bool get requiresFieldSyntax() => false; |
| 716 | 716 |
| 717 void provideFieldSyntax() => _provideFieldSyntax = true; | 717 void provideFieldSyntax() => _provideFieldSyntax = true; |
| 718 void providePropertySyntax() => _providePropertySyntax = true; | 718 void providePropertySyntax() => _providePropertySyntax = true; |
| 719 | 719 |
| 720 Value set_(MethodGenerator context, Node, Value target, Value value, | 720 Value _set(MethodGenerator context, Node, Value target, Value value, |
| 721 [bool isDynamic=false]) { | 721 [bool isDynamic=false]) { |
| 722 world.error('can not set method', definition.span); | 722 world.error('can not set method', definition.span); |
| 723 } | 723 } |
| 724 | 724 |
| 725 Value get_(MethodGenerator context, Node node, Value target, | 725 Value _get(MethodGenerator context, Node node, Value target, |
| 726 [bool isDynamic=false]) { | 726 [bool isDynamic=false]) { |
| 727 // TODO(jimhug): Would prefer to invoke! | 727 // TODO(jimhug): Would prefer to invoke! |
| 728 declaringType.genMethod(this); | 728 declaringType.genMethod(this); |
| 729 _provideOptionalParamInfo = true; | 729 _provideOptionalParamInfo = true; |
| 730 if (isStatic) { | 730 if (isStatic) { |
| 731 var type = declaringType.isTop ? '' : '${declaringType.jsname}.'; | 731 var type = declaringType.isTop ? '' : '${declaringType.jsname}.'; |
| 732 return new Value(functionType, '$type$jsname'); | 732 return new Value(functionType, '$type$jsname', node.span); |
| 733 } | 733 } |
| 734 _providePropertySyntax = true; | 734 _providePropertySyntax = true; |
| 735 return new Value(functionType, '${target.code}.get\$$jsname()'); | 735 return new Value(functionType, '${target.code}.get\$$jsname()', node.span); |
| 736 } | 736 } |
| 737 | 737 |
| 738 bool namesInOrder(Arguments args) { | 738 bool namesInOrder(Arguments args) { |
| 739 if (!args.hasNames) return true; | 739 if (!args.hasNames) return true; |
| 740 | 740 |
| 741 int lastParameter = null; | 741 int lastParameter = null; |
| 742 for (int i = args.bareCount; i < parameters.length; i++) { | 742 for (int i = args.bareCount; i < parameters.length; i++) { |
| 743 var p = args.getIndexOfName(parameters[i].name); | 743 var p = args.getIndexOfName(parameters[i].name); |
| 744 // Only worry about parameters that needTemps. Otherwise it's fine to | 744 // Only worry about parameters that needTemps. Otherwise it's fine to |
| 745 // reorder. | 745 // reorder. |
| (...skipping 148 matching lines...) Expand 10 before | Expand all | Expand 10 after Loading... | |
| 894 | 894 |
| 895 var argsString = Strings.join(argsCode, ', '); | 895 var argsString = Strings.join(argsCode, ', '); |
| 896 | 896 |
| 897 if (isConstructor) { | 897 if (isConstructor) { |
| 898 return _invokeConstructor(context, node, target, args, argsString); | 898 return _invokeConstructor(context, node, target, args, argsString); |
| 899 } | 899 } |
| 900 | 900 |
| 901 // TODO(jimhug): target really shouldn't ever be null... | 901 // TODO(jimhug): target really shouldn't ever be null... |
| 902 if (target != null && target.isSuper) { | 902 if (target != null && target.isSuper) { |
| 903 return new Value(returnType, | 903 return new Value(returnType, |
| 904 '${declaringType.jsname}.prototype.$jsname.call($argsString)'); | 904 '${declaringType.jsname}.prototype.$jsname.call($argsString)', |
| 905 node.span); | |
| 905 } | 906 } |
| 906 | 907 |
| 907 if (name.startsWith('\$')) { | 908 if (name.startsWith('\$')) { |
| 908 return _invokeBuiltin(context, node, target, args, argsCode); | 909 return _invokeBuiltin(context, node, target, args, argsCode); |
| 909 } | 910 } |
| 910 | 911 |
| 911 if (isFactory) { | 912 if (isFactory) { |
| 912 return new Value(returnType, '$generatedFactoryName($argsString)'); | 913 return new Value(returnType, '$generatedFactoryName($argsString)', |
| 914 node.span); | |
| 913 } | 915 } |
| 914 | 916 |
| 915 if (isStatic) { | 917 if (isStatic) { |
| 916 if (declaringType.isTop) { | 918 if (declaringType.isTop) { |
| 917 // TODO(jimhug): Explore moving libraries into their own namespaces | 919 // TODO(jimhug): Explore moving libraries into their own namespaces |
| 918 return new Value(returnType, '$jsname($argsString)'); | 920 return new Value(returnType, '$jsname($argsString)', node != null ? node .span : node); |
| 919 } | 921 } |
| 920 return new Value(returnType, | 922 return new Value(returnType, |
| 921 '${declaringType.jsname}.$jsname($argsString)'); | 923 '${declaringType.jsname}.$jsname($argsString)', node.span); |
| 922 } | 924 } |
| 923 | 925 |
| 924 var code = '${target.code}.$jsname($argsString)'; | 926 var code = '${target.code}.$jsname($argsString)'; |
| 925 // optimize expressions which we know statically their value. | 927 // optimize expressions which we know statically their value. |
| 926 if (target.isConst) { | 928 if (target.isConst) { |
| 927 if (target is GlobalValue) { | 929 if (target is GlobalValue) { |
| 928 target = target.dynamic.exp; // TODO: an inline "cast" would be nice. | 930 target = target.dynamic.exp; // TODO: an inline "cast" would be nice. |
| 929 } | 931 } |
| 930 if (name == 'get\$length') { | 932 if (name == 'get\$length') { |
| 931 if (target is ConstListValue || target is ConstMapValue) { | 933 if (target is ConstListValue || target is ConstMapValue) { |
| 932 code = '${target.dynamic.values.length}'; | 934 code = '${target.dynamic.values.length}'; |
| 933 } | 935 } |
| 934 } else if (name == 'isEmpty') { | 936 } else if (name == 'isEmpty') { |
| 935 if (target is ConstListValue || target is ConstMapValue) { | 937 if (target is ConstListValue || target is ConstMapValue) { |
| 936 code = '${target.dynamic.values.isEmpty()}'; | 938 code = '${target.dynamic.values.isEmpty()}'; |
| 937 } | 939 } |
| 938 } | 940 } |
| 939 } | 941 } |
| 940 | 942 |
| 941 // TODO(jmesserly): factor this better | 943 // TODO(jmesserly): factor this better |
| 942 if (name == 'get\$typeName' && declaringType.library == world.dom) { | 944 if (name == 'get\$typeName' && declaringType.library == world.dom) { |
| 943 world.gen.corejs.useTypeNameOf = true; | 945 world.gen.corejs.useTypeNameOf = true; |
| 944 } | 946 } |
| 945 | 947 |
| 946 return new Value(returnType, code); | 948 return new Value(returnType, code, node.span); |
| 947 } | 949 } |
| 948 | 950 |
| 949 Value _invokeConstructor(MethodGenerator context, Node node, | 951 Value _invokeConstructor(MethodGenerator context, Node node, |
| 950 Value target, Arguments args, argsString) { | 952 Value target, Arguments args, argsString) { |
| 951 declaringType.markUsed(); | 953 declaringType.markUsed(); |
| 952 | 954 |
| 953 if (target != null) { | 955 if (target != null) { |
| 954 // initializer call to another constructor | 956 // initializer call to another constructor |
| 955 var code = (constructorName != '') | 957 var code = (constructorName != '') |
| 956 ? '${declaringType.jsname}.${constructorName}\$ctor.call($argsString)' | 958 ? '${declaringType.jsname}.${constructorName}\$ctor.call($argsString)' |
| 957 : '${declaringType.jsname}.call($argsString)'; | 959 : '${declaringType.jsname}.call($argsString)'; |
| 958 return new Value(declaringType, code); | 960 return new Value(declaringType, code, node.span); |
| 959 } else { | 961 } else { |
| 960 var code = (constructorName != '') | 962 var code = (constructorName != '') |
| 961 ? 'new ${declaringType.jsname}.${constructorName}\$ctor($argsString)' | 963 ? 'new ${declaringType.jsname}.${constructorName}\$ctor($argsString)' |
| 962 : 'new ${declaringType.jsname}($argsString)'; | 964 : 'new ${declaringType.jsname}($argsString)'; |
| 963 // TODO(jmesserly): using the "node" here feels really hacky | 965 // TODO(jmesserly): using the "node" here feels really hacky |
| 964 if (isConst && node is NewExpression && node.dynamic.isConst) { | 966 if (isConst && node is NewExpression && node.dynamic.isConst) { |
| 965 return _invokeConstConstructor(node, code, target, args); | 967 return _invokeConstConstructor(node, code, target, args); |
| 966 } else { | 968 } else { |
| 967 return new Value(declaringType, code); | 969 return new Value(declaringType, code, node.span); |
| 968 } | 970 } |
| 969 } | 971 } |
| 970 } | 972 } |
| 971 | 973 |
| 972 /** | 974 /** |
| 973 * Special handling for const constructors so that so that: | 975 * Special handling for const constructors so that so that: |
| 974 * [: const B() === const B.a(0, 1) === const B.b(0) :] | 976 * [: const B() === const B.a(0, 1) === const B.b(0) :] |
| 975 * where: [: | 977 * where: [: |
| 976 * class A { | 978 * class A { |
| 977 * final int x; | 979 * final int x; |
| (...skipping 109 matching lines...) Expand 10 before | Expand all | Expand 10 after Loading... | |
| 1087 } else if (name == '\$bit_not') { | 1089 } else if (name == '\$bit_not') { |
| 1088 code = '~${target.code}'; | 1090 code = '~${target.code}'; |
| 1089 } else if (name == '\$truncdiv' || name == '\$mod') { | 1091 } else if (name == '\$truncdiv' || name == '\$mod') { |
| 1090 world.gen.corejs.useOperator(name); | 1092 world.gen.corejs.useOperator(name); |
| 1091 code = '$name(${target.code}, ${argsCode[0]})'; | 1093 code = '$name(${target.code}, ${argsCode[0]})'; |
| 1092 } else { | 1094 } else { |
| 1093 var op = TokenKind.rawOperatorFromMethod(name); | 1095 var op = TokenKind.rawOperatorFromMethod(name); |
| 1094 code = '${target.code} $op ${argsCode[0]}'; | 1096 code = '${target.code} $op ${argsCode[0]}'; |
| 1095 } | 1097 } |
| 1096 | 1098 |
| 1097 return new Value(returnType, code); | 1099 return new Value(returnType, code, node.span); |
| 1098 } else { | 1100 } else { |
| 1099 var value; | 1101 var value; |
| 1100 num val0, val1, ival0, ival1; | 1102 num val0, val1, ival0, ival1; |
| 1101 val0 = target.dynamic.actualValue; | 1103 val0 = target.dynamic.actualValue; |
| 1102 ival0 = val0.toInt(); | 1104 ival0 = val0.toInt(); |
| 1103 if (args.values.length > 0) { | 1105 if (args.values.length > 0) { |
| 1104 val1 = args.values[0].dynamic.actualValue; | 1106 val1 = args.values[0].dynamic.actualValue; |
| 1105 ival1 = val1.toInt(); | 1107 ival1 = val1.toInt(); |
| 1106 } | 1108 } |
| 1107 switch (name) { | 1109 switch (name) { |
| (...skipping 19 matching lines...) Expand all Loading... | |
| 1127 case '\$shl': value = (ival0 << ival1).toDouble(); break; | 1129 case '\$shl': value = (ival0 << ival1).toDouble(); break; |
| 1128 case '\$sar': value = (ival0 >> ival1).toDouble(); break; | 1130 case '\$sar': value = (ival0 >> ival1).toDouble(); break; |
| 1129 case '\$shr': value = (ival0 >>> ival1).toDouble(); break; | 1131 case '\$shr': value = (ival0 >>> ival1).toDouble(); break; |
| 1130 } | 1132 } |
| 1131 return new EvaluatedValue(returnType, value, "$value", node.span); | 1133 return new EvaluatedValue(returnType, value, "$value", node.span); |
| 1132 } | 1134 } |
| 1133 } else if (declaringType.isString) { | 1135 } else if (declaringType.isString) { |
| 1134 if (name == '\$index') { | 1136 if (name == '\$index') { |
| 1135 // Note: this could technically propagate constness, but that's not | 1137 // Note: this could technically propagate constness, but that's not |
| 1136 // specified explicitly and the VM doesn't do that. | 1138 // specified explicitly and the VM doesn't do that. |
| 1137 return new Value(declaringType, '${target.code}[${argsCode[0]}]'); | 1139 return new Value(declaringType, '${target.code}[${argsCode[0]}]', |
| 1140 node.span); | |
| 1138 } else if (name == '\$add') { | 1141 } else if (name == '\$add') { |
| 1139 if (allConst) { | 1142 if (allConst) { |
| 1140 var val0 = target.dynamic.actualValue; | 1143 var val0 = target.dynamic.actualValue; |
| 1141 val0 = val0.substring(1, val0.length - 1); | 1144 val0 = val0.substring(1, val0.length - 1); |
| 1142 var val1 = args.values[0].dynamic.actualValue; | 1145 var val1 = args.values[0].dynamic.actualValue; |
| 1143 if (args.values[0].type.isString) { | 1146 if (args.values[0].type.isString) { |
| 1144 val1 = val1.substring(1, val1.length - 1); | 1147 val1 = val1.substring(1, val1.length - 1); |
| 1145 } | 1148 } |
| 1146 var value = '${val0}${val1}'; | 1149 var value = '${val0}${val1}'; |
| 1147 value = '"' + value.replaceAll('"', '\\"') + '"'; | 1150 value = '"' + value.replaceAll('"', '\\"') + '"'; |
| 1148 return new EvaluatedValue(world.stringType, value, value, node.span); | 1151 return new EvaluatedValue(world.stringType, value, value, node.span); |
| 1149 } | 1152 } |
| 1150 | 1153 |
| 1151 // Ensure we generate toString on the right side | 1154 // Ensure we generate toString on the right side |
| 1152 args.values[0].invoke(context, 'toString', node, Arguments.EMPTY); | 1155 args.values[0].invoke(context, 'toString', node, Arguments.EMPTY); |
| 1153 return new Value(declaringType, '${target.code} + ${argsCode[0]}'); | 1156 return new Value(declaringType, '${target.code} + ${argsCode[0]}', |
| 1157 node.span); | |
| 1154 } | 1158 } |
| 1155 } else if (declaringType.isNativeType) { | 1159 } else if (declaringType.isNativeType) { |
| 1156 if (name == '\$index') { | 1160 if (name == '\$index') { |
| 1157 // Note: this could technically propagate constness, but that's not | 1161 // Note: this could technically propagate constness, but that's not |
| 1158 // specified explicitly and the VM doesn't do that. | 1162 // specified explicitly and the VM doesn't do that. |
| 1159 // TODO(jmesserly): why are we using a return type of "var"? | 1163 // TODO(jmesserly): why are we using a return type of "var"? |
| 1160 return new Value(null, '${target.code}[${argsCode[0]}]'); | 1164 return new Value(null, '${target.code}[${argsCode[0]}]', node.span); |
| 1161 } else if (name == '\$setindex') { | 1165 } else if (name == '\$setindex') { |
| 1162 return new Value(null, | 1166 return new Value(null, |
| 1163 '${target.code}[${argsCode[0]}] = ${argsCode[1]}'); | 1167 '${target.code}[${argsCode[0]}] = ${argsCode[1]}', node.span); |
| 1164 } | 1168 } |
| 1165 } | 1169 } |
| 1166 | 1170 |
| 1167 // TODO(jimhug): Optimize null on lhs as well. | 1171 // TODO(jimhug): Optimize null on lhs as well. |
| 1168 if (name == '\$eq' || name == '\$ne') { | 1172 if (name == '\$eq' || name == '\$ne') { |
| 1169 final op = name == '\$eq' ? '==' : '!='; | 1173 final op = name == '\$eq' ? '==' : '!='; |
| 1170 if (allConst) { | 1174 if (allConst) { |
| 1171 var val0 = target.dynamic.actualValue; | 1175 var val0 = target.dynamic.actualValue; |
| 1172 var val1 = args.values[0].dynamic.actualValue; | 1176 var val1 = args.values[0].dynamic.actualValue; |
| 1173 var newVal = name == '\$eq' ? val0 == val1 : val0 != val1; | 1177 var newVal = name == '\$eq' ? val0 == val1 : val0 != val1; |
| 1174 return new EvaluatedValue(world.boolType, | 1178 return new EvaluatedValue(world.boolType, |
| 1175 newVal, "$newVal", node.span); | 1179 newVal, "$newVal", node.span); |
| 1176 } | 1180 } |
| 1177 // Optimize test when null is on the rhs. | 1181 // Optimize test when null is on the rhs. |
| 1178 if (argsCode[0] == 'null') { | 1182 if (argsCode[0] == 'null') { |
| 1179 return new Value(returnType, '${target.code} $op null'); | 1183 return new Value(returnType, '${target.code} $op null', node.span); |
| 1180 } else if (target.type.isNum || target.type.isString) { | 1184 } else if (target.type.isNum || target.type.isString) { |
| 1181 // TODO(jimhug): Maybe check rhs. | 1185 // TODO(jimhug): Maybe check rhs. |
| 1182 return new Value(returnType, '${target.code} $op ${argsCode[0]}'); | 1186 return new Value(returnType, '${target.code} $op ${argsCode[0]}', |
| 1187 node.span); | |
| 1183 } | 1188 } |
| 1184 world.gen.corejs.useOperator(name); | 1189 world.gen.corejs.useOperator(name); |
| 1185 return new Value(returnType, '$name(${target.code}, ${argsCode[0]})'); | 1190 return new Value(returnType, '$name(${target.code}, ${argsCode[0]})', |
| 1191 node.span); | |
| 1186 } | 1192 } |
| 1187 | 1193 |
| 1188 if (name == '\$call') { | 1194 if (name == '\$call') { |
| 1189 declaringType.markUsed(); | 1195 declaringType.markUsed(); |
| 1190 return new Value(returnType, | 1196 return new Value(returnType, |
| 1191 '${target.code}(${Strings.join(argsCode, ", ")})'); | 1197 '${target.code}(${Strings.join(argsCode, ", ")})', node.span); |
| 1192 } | 1198 } |
| 1193 | 1199 |
| 1194 if (name == '\$index') { | 1200 if (name == '\$index') { |
| 1195 world.gen.corejs.useIndex = true; | 1201 world.gen.corejs.useIndex = true; |
| 1196 } else if (name == '\$setindex') { | 1202 } else if (name == '\$setindex') { |
| 1197 world.gen.corejs.useSetIndex = true; | 1203 world.gen.corejs.useSetIndex = true; |
| 1198 } | 1204 } |
| 1199 | 1205 |
| 1200 // Fall back to normal method invocation. | 1206 // Fall back to normal method invocation. |
| 1201 var argsString = Strings.join(argsCode, ', '); | 1207 var argsString = Strings.join(argsCode, ', '); |
| 1202 return new Value(returnType, '${target.code}.$jsname($argsString)'); | 1208 return new Value(returnType, '${target.code}.$jsname($argsString)', |
| 1209 node.span); | |
| 1203 } | 1210 } |
| 1204 | 1211 |
| 1205 | 1212 |
| 1206 resolve(Type inType) { | 1213 resolve(Type inType) { |
| 1207 // TODO(jimhug): cut-and-paste-and-edit from Field.resolve | 1214 // TODO(jimhug): cut-and-paste-and-edit from Field.resolve |
| 1208 isStatic = inType.isTop; | 1215 isStatic = inType.isTop; |
| 1209 isConst = false; | 1216 isConst = false; |
| 1210 isFactory = false; | 1217 isFactory = false; |
| 1211 isAbstract = !declaringType.isClass; | 1218 isAbstract = !declaringType.isClass; |
| 1212 if (definition.modifiers != null) { | 1219 if (definition.modifiers != null) { |
| (...skipping 100 matching lines...) Expand 10 before | Expand all | Expand 10 after Loading... | |
| 1313 // TODO(jimhug): Always false, or is this needed? | 1320 // TODO(jimhug): Always false, or is this needed? |
| 1314 bool get isStatic() => members.length == 1 && members[0].isStatic; | 1321 bool get isStatic() => members.length == 1 && members[0].isStatic; |
| 1315 | 1322 |
| 1316 bool canInvoke(MethodGenerator context, Arguments args) => | 1323 bool canInvoke(MethodGenerator context, Arguments args) => |
| 1317 members.some((m) => m.canInvoke(context, args)); | 1324 members.some((m) => m.canInvoke(context, args)); |
| 1318 | 1325 |
| 1319 Value _makeError(Node node, Value target, String action) { | 1326 Value _makeError(Node node, Value target, String action) { |
| 1320 if (!target.type.isVar) { | 1327 if (!target.type.isVar) { |
| 1321 world.warning('could not find applicable $action for "$name"', node.span); | 1328 world.warning('could not find applicable $action for "$name"', node.span); |
| 1322 } | 1329 } |
| 1323 return new Value(null, '${target.code}.$jsname() /*no applicable $action*/') ; | 1330 return new Value(null, '${target.code}.$jsname() /*no applicable $action*/', |
| 1331 node.span); | |
| 1324 } | 1332 } |
| 1325 | 1333 |
| 1326 bool _treatAsField; | 1334 bool _treatAsField; |
| 1327 bool get treatAsField() { | 1335 bool get treatAsField() { |
| 1328 if (_treatAsField == null) { | 1336 if (_treatAsField == null) { |
| 1329 _treatAsField = true; | 1337 _treatAsField = true; |
| 1330 for (var member in members) { | 1338 for (var member in members) { |
| 1331 if (member.requiresFieldSyntax) { | 1339 if (member.requiresFieldSyntax) { |
| 1332 _treatAsField = true; | 1340 _treatAsField = true; |
| 1333 break; | 1341 break; |
| 1334 } | 1342 } |
| 1335 if (member.prefersPropertySyntax) { | 1343 if (member.prefersPropertySyntax) { |
| 1336 _treatAsField = false; | 1344 _treatAsField = false; |
| 1337 } | 1345 } |
| 1338 } | 1346 } |
| 1339 for (var member in members) { | 1347 for (var member in members) { |
| 1340 if (_treatAsField) { | 1348 if (_treatAsField) { |
| 1341 member.provideFieldSyntax(); | 1349 member.provideFieldSyntax(); |
| 1342 } else { | 1350 } else { |
| 1343 member.providePropertySyntax(); | 1351 member.providePropertySyntax(); |
| 1344 } | 1352 } |
| 1345 } | 1353 } |
| 1346 } | 1354 } |
| 1347 return _treatAsField; | 1355 return _treatAsField; |
| 1348 } | 1356 } |
| 1349 | 1357 |
| 1350 Value get_(MethodGenerator context, Node node, Value target, | 1358 Value _get(MethodGenerator context, Node node, Value target, |
| 1351 [bool isDynamic=false]) { | 1359 [bool isDynamic=false]) { |
| 1352 if (members.length == 1) { | 1360 if (members.length == 1) { |
| 1353 return members[0].get_(context, node, target, isDynamic); | 1361 return members[0]._get(context, node, target, isDynamic); |
| 1354 } | 1362 } |
| 1355 final targets = members.filter((m) => m.canGet); | 1363 final targets = members.filter((m) => m.canGet); |
| 1356 if (targets.length == 1) { | 1364 if (targets.length == 1) { |
| 1357 return targets[0].get_(context, node, target, isDynamic); | 1365 return targets[0]._get(context, node, target, isDynamic); |
| 1358 } | 1366 } |
| 1359 | 1367 |
| 1360 Value returnValue = null; | 1368 Value returnValue = null; |
| 1361 for (var member in targets) { | 1369 for (var member in targets) { |
| 1362 final value = member.get_(context, node, target, isDynamic:true); | 1370 final value = member._get(context, node, target, isDynamic:true); |
| 1363 returnValue = _tryUnion(returnValue, value, node); | 1371 returnValue = _tryUnion(returnValue, value, node); |
| 1364 } | 1372 } |
| 1365 if (returnValue == null) { | 1373 if (returnValue == null) { |
| 1366 return _makeError(node, target, 'getter'); | 1374 return _makeError(node, target, 'getter'); |
| 1367 } | 1375 } |
| 1368 if (returnValue.code == null) { | 1376 if (returnValue.code == null) { |
| 1369 if (treatAsField) { | 1377 if (treatAsField) { |
| 1370 return new Value(returnValue.type, '${target.code}.$jsname'); | 1378 return new Value(returnValue.type, '${target.code}.$jsname', |
| 1379 node.span); | |
| 1371 } else { | 1380 } else { |
| 1372 return new Value(returnValue.type, '${target.code}.get\$$jsname()'); | 1381 return new Value(returnValue.type, '${target.code}.get\$$jsname()', |
| 1382 node.span); | |
| 1373 } | 1383 } |
| 1374 } | 1384 } |
| 1375 return returnValue; | 1385 return returnValue; |
| 1376 } | 1386 } |
| 1377 | 1387 |
| 1378 Value set_(MethodGenerator context, Node node, Value target, Value value, | 1388 Value _set(MethodGenerator context, Node node, Value target, Value value, |
| 1379 [bool isDynamic=false]) { | 1389 [bool isDynamic=false]) { |
| 1380 if (members.length == 1) { | 1390 if (members.length == 1) { |
| 1381 return members[0].set_(context, node, target, value, isDynamic); | 1391 return members[0]._set(context, node, target, value, isDynamic); |
| 1382 } | 1392 } |
| 1383 final targets = members.filter((m) => m.canSet); | 1393 final targets = members.filter((m) => m.canSet); |
| 1384 if (targets.length == 1) { | 1394 if (targets.length == 1) { |
| 1385 return targets[0].set_(context, node, target, value, isDynamic); | 1395 return targets[0]._set(context, node, target, value, isDynamic); |
| 1386 } | 1396 } |
| 1387 | 1397 |
| 1388 Value returnValue = null; | 1398 Value returnValue = null; |
| 1389 for (var member in targets) { | 1399 for (var member in targets) { |
| 1390 final res = member.set_(context, node, target, value, isDynamic:true); | 1400 final res = member._set(context, node, target, value, isDynamic:true); |
| 1391 returnValue = _tryUnion(returnValue, res, node); | 1401 returnValue = _tryUnion(returnValue, res, node); |
| 1392 } | 1402 } |
| 1393 if (returnValue == null) { | 1403 if (returnValue == null) { |
| 1394 return _makeError(node, target, 'setter'); | 1404 return _makeError(node, target, 'setter'); |
| 1395 } | 1405 } |
| 1396 if (returnValue.code == null) { | 1406 if (returnValue.code == null) { |
| 1397 if (treatAsField) { | 1407 if (treatAsField) { |
| 1398 return new Value(returnValue.type, | 1408 return new Value(returnValue.type, |
| 1399 '${target.code}.$jsname = ${value.code}'); | 1409 '${target.code}.$jsname = ${value.code}', node.span); |
| 1400 } else { | 1410 } else { |
| 1401 return new Value(returnValue.type, | 1411 return new Value(returnValue.type, |
| 1402 '${target.code}.set\$$jsname(${value.code})'); | 1412 '${target.code}.set\$$jsname(${value.code})', node.span); |
| 1403 } | 1413 } |
| 1404 } | 1414 } |
| 1405 return returnValue; | 1415 return returnValue; |
| 1406 } | 1416 } |
| 1407 | 1417 |
| 1408 Value invoke(MethodGenerator context, Node node, Value target, | 1418 Value invoke(MethodGenerator context, Node node, Value target, |
| 1409 Arguments args, [bool isDynamic=false]) { | 1419 Arguments args, [bool isDynamic=false]) { |
| 1410 if (members.length == 1) { | 1420 if (members.length == 1) { |
| 1411 return members[0].invoke(context, node, target, args, isDynamic); | 1421 return members[0].invoke(context, node, target, args, isDynamic); |
| 1412 } | 1422 } |
| (...skipping 40 matching lines...) Expand 10 before | Expand all | Expand 10 after Loading... | |
| 1453 | 1463 |
| 1454 Value _tryUnion(Value x, Value y, Node node) { | 1464 Value _tryUnion(Value x, Value y, Node node) { |
| 1455 if (x == null) return y; | 1465 if (x == null) return y; |
| 1456 var type = Type.union(x.type, y.type); | 1466 var type = Type.union(x.type, y.type); |
| 1457 if (x.code == y.code) { | 1467 if (x.code == y.code) { |
| 1458 if (type == x.type) { | 1468 if (type == x.type) { |
| 1459 return x; | 1469 return x; |
| 1460 } else if (x.isConst || y.isConst) { | 1470 } else if (x.isConst || y.isConst) { |
| 1461 world.internalError("unexpected: union of const values "); | 1471 world.internalError("unexpected: union of const values "); |
| 1462 } else { | 1472 } else { |
| 1463 return new Value(type, x.code, | 1473 return new Value(type, x.code, node.span, |
| 1464 x.isSuper && y.isSuper, | 1474 x.isSuper && y.isSuper, |
| 1465 x.needsTemp || y.needsTemp, | 1475 x.needsTemp || y.needsTemp, |
| 1466 x.isType && y.isType); | 1476 x.isType && y.isType); |
| 1467 } | 1477 } |
| 1468 } else { | 1478 } else { |
| 1469 return new Value(type, null); | 1479 return new Value(type, null, node.span); |
| 1470 } | 1480 } |
| 1471 } | 1481 } |
| 1472 | 1482 |
| 1473 dumpAllMembers() { | 1483 dumpAllMembers() { |
| 1474 for (var member in members) { | 1484 for (var member in members) { |
| 1475 world.warning('hard-multi $name on ${member.declaringType.name}', | 1485 world.warning('hard-multi $name on ${member.declaringType.name}', |
| 1476 member.span); | 1486 member.span); |
| 1477 } | 1487 } |
| 1478 } | 1488 } |
| 1479 | 1489 |
| (...skipping 81 matching lines...) Expand 10 before | Expand all | Expand 10 after Loading... | |
| 1561 } | 1571 } |
| 1562 | 1572 |
| 1563 void forEach(void f(Member member)) { | 1573 void forEach(void f(Member member)) { |
| 1564 factories.forEach((_, Map constructors) { | 1574 factories.forEach((_, Map constructors) { |
| 1565 constructors.forEach((_, Member member) { | 1575 constructors.forEach((_, Member member) { |
| 1566 f(member); | 1576 f(member); |
| 1567 }); | 1577 }); |
| 1568 }); | 1578 }); |
| 1569 } | 1579 } |
| 1570 } | 1580 } |
| OLD | NEW |