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 102 matching lines...) Expand 10 before | Expand all | Expand 10 after Loading... | |
113 bool get isField() => false; | 113 bool get isField() => false; |
114 bool get isMethod() => false; | 114 bool get isMethod() => false; |
115 bool get isProperty() => false; | 115 bool get isProperty() => false; |
116 bool get isAbstract() => false; | 116 bool get isAbstract() => false; |
117 | 117 |
118 // TODO(jmesserly): these only makes sense on methods, but because of | 118 // TODO(jmesserly): these only makes sense on methods, but because of |
119 // ConcreteMember we need to support them on Member. | 119 // ConcreteMember we need to support them on Member. |
120 bool get isConst() => false; | 120 bool get isConst() => false; |
121 bool get isFactory() => false; | 121 bool get isFactory() => false; |
122 | 122 |
123 bool get isOperator() => name.startsWith('\$'); | |
124 bool get isCallMethod() => name == '\$call'; | |
125 | |
123 bool get prefersPropertySyntax() => true; | 126 bool get prefersPropertySyntax() => true; |
124 bool get requiresFieldSyntax() => false; | 127 bool get requiresFieldSyntax() => false; |
125 | 128 |
126 bool get isNative() => false; | 129 bool get isNative() => false; |
127 String get constructorName() { | 130 String get constructorName() { |
128 world.internalError('can not be a constructor', span); | 131 world.internalError('can not be a constructor', span); |
129 } | 132 } |
130 | 133 |
131 void provideFieldSyntax() => world.internalError('can not be field', span); | 134 void provideFieldSyntax() => world.internalError('can not be field', span); |
132 void providePropertySyntax() => | 135 void providePropertySyntax() => |
(...skipping 787 matching lines...) Expand 10 before | Expand all | Expand 10 after Loading... | |
920 return _invokeConstructor(context, node, target, args, argsString); | 923 return _invokeConstructor(context, node, target, args, argsString); |
921 } | 924 } |
922 | 925 |
923 // TODO(jimhug): target really shouldn't ever be null... | 926 // TODO(jimhug): target really shouldn't ever be null... |
924 if (target != null && target.isSuper) { | 927 if (target != null && target.isSuper) { |
925 return new Value(inferredResult, | 928 return new Value(inferredResult, |
926 '${declaringType.jsname}.prototype.$jsname.call($argsString)', | 929 '${declaringType.jsname}.prototype.$jsname.call($argsString)', |
927 node.span); | 930 node.span); |
928 } | 931 } |
929 | 932 |
930 if (name.startsWith('\$')) { | 933 if (isOperator) { |
931 return _invokeBuiltin(context, node, target, args, argsCode, isDynamic); | 934 return _invokeBuiltin(context, node, target, args, argsCode, isDynamic); |
932 } | 935 } |
933 | 936 |
934 if (isFactory) { | 937 if (isFactory) { |
935 return new Value(inferredResult, '$generatedFactoryName($argsString)', | 938 return new Value(inferredResult, '$generatedFactoryName($argsString)', |
936 node.span); | 939 node.span); |
937 } | 940 } |
938 | 941 |
939 if (isStatic) { | 942 if (isStatic) { |
940 if (declaringType.isTop) { | 943 if (declaringType.isTop) { |
(...skipping 271 matching lines...) Expand 10 before | Expand all | Expand 10 after Loading... | |
1212 } else if (target.type.isNum || target.type.isString) { | 1215 } else if (target.type.isNum || target.type.isString) { |
1213 // TODO(jimhug): Maybe check rhs. | 1216 // TODO(jimhug): Maybe check rhs. |
1214 return new Value(inferredResult, '${target.code} $op ${argsCode[0]}', | 1217 return new Value(inferredResult, '${target.code} $op ${argsCode[0]}', |
1215 node.span); | 1218 node.span); |
1216 } | 1219 } |
1217 world.gen.corejs.useOperator(name); | 1220 world.gen.corejs.useOperator(name); |
1218 return new Value(inferredResult, '$name(${target.code}, ${argsCode[0]})', | 1221 return new Value(inferredResult, '$name(${target.code}, ${argsCode[0]})', |
1219 node.span); | 1222 node.span); |
1220 } | 1223 } |
1221 | 1224 |
1222 if (name == '\$call') { | 1225 if (isCallMethod) { |
1223 declaringType.markUsed(); | 1226 declaringType.markUsed(); |
1224 return new Value(inferredResult, | 1227 return new Value(inferredResult, |
1225 '${target.code}(${Strings.join(argsCode, ", ")})', node.span); | 1228 '${target.code}(${Strings.join(argsCode, ", ")})', node.span); |
1226 } | 1229 } |
1227 | 1230 |
1228 if (name == '\$index') { | 1231 if (name == '\$index') { |
1229 world.gen.corejs.useIndex = true; | 1232 world.gen.corejs.useIndex = true; |
1230 } else if (name == '\$setindex') { | 1233 } else if (name == '\$setindex') { |
1231 world.gen.corejs.useSetIndex = true; | 1234 world.gen.corejs.useSetIndex = true; |
1232 } | 1235 } |
(...skipping 42 matching lines...) Expand 10 before | Expand all | Expand 10 after Loading... | |
1275 world.error('${mod} modifier not allowed on method', mod.span); | 1278 world.error('${mod} modifier not allowed on method', mod.span); |
1276 } | 1279 } |
1277 } | 1280 } |
1278 } | 1281 } |
1279 | 1282 |
1280 if (isFactory) { | 1283 if (isFactory) { |
1281 isStatic = true; | 1284 isStatic = true; |
1282 } | 1285 } |
1283 | 1286 |
1284 // TODO(jimhug): need a better annotation for being an operator method | 1287 // TODO(jimhug): need a better annotation for being an operator method |
1285 if (name.startsWith('\$') && !name.startsWith('\$call') && isStatic) { | 1288 if (isOperator && isStatic && !isCallMethod) { |
1286 world.error('operator method may not be static "${name}"', span); | 1289 world.error('operator method may not be static "${name}"', span); |
1287 } | 1290 } |
1288 | 1291 |
1289 if (isAbstract) { | 1292 if (isAbstract) { |
1290 if (definition.body != null && | 1293 if (definition.body != null && |
1291 declaringType.definition is! FunctionTypeDefinition) { | 1294 declaringType.definition is! FunctionTypeDefinition) { |
1292 // TODO(jimhug): Creating function types for concrete methods is | 1295 // TODO(jimhug): Creating function types for concrete methods is |
1293 // steadily feeling uglier... | 1296 // steadily feeling uglier... |
1294 world.error('abstract method can not have a body', span); | 1297 world.error('abstract method can not have a body', span); |
1295 } | 1298 } |
(...skipping 30 matching lines...) Expand all Loading... | |
1326 library._addMember(this); | 1329 library._addMember(this); |
1327 } | 1330 } |
1328 } | 1331 } |
1329 } | 1332 } |
1330 | 1333 |
1331 | 1334 |
1332 class MemberSet { | 1335 class MemberSet { |
1333 final String name; | 1336 final String name; |
1334 final List<Member> members; | 1337 final List<Member> members; |
1335 final String jsname; | 1338 final String jsname; |
1339 final bool isVar; | |
1336 | 1340 |
1337 MemberSet(Member member): | 1341 MemberSet(Member member, [bool isVar=false]): |
nweiz
2011/11/14 21:28:15
Does isVar also need to be set for the library-loc
| |
1338 name = member.name, members = [member], jsname = member.jsname; | 1342 name = member.name, members = [member], jsname = member.jsname, |
1343 isVar = isVar; | |
1339 | 1344 |
1340 toString() => '$name:${members.length}'; | 1345 toString() => '$name:${members.length}'; |
1341 | 1346 |
1342 // TODO(jimhug): Still working towards the right logic for conflicts... | 1347 // TODO(jimhug): Still working towards the right logic for conflicts... |
1343 bool get containsProperties() => members.some((m) => m is PropertyMember); | 1348 bool get containsProperties() => members.some((m) => m is PropertyMember); |
1344 bool get containsMethods() => members.some((m) => m is MethodMember); | 1349 bool get containsMethods() => members.some((m) => m is MethodMember); |
1345 | 1350 |
1351 | |
1346 void add(Member member) => members.add(member); | 1352 void add(Member member) => members.add(member); |
1347 | 1353 |
1348 // TODO(jimhug): Always false, or is this needed? | 1354 // TODO(jimhug): Always false, or is this needed? |
1349 bool get isStatic() => members.length == 1 && members[0].isStatic; | 1355 bool get isStatic() => members.length == 1 && members[0].isStatic; |
1356 bool get isOperator() => members[0].isOperator; | |
1350 | 1357 |
1351 bool canInvoke(MethodGenerator context, Arguments args) => | 1358 bool canInvoke(MethodGenerator context, Arguments args) => |
1352 members.some((m) => m.canInvoke(context, args)); | 1359 members.some((m) => m.canInvoke(context, args)); |
1353 | 1360 |
1354 Value _makeError(Node node, Value target, String action) { | 1361 Value _makeError(Node node, Value target, String action) { |
1355 if (!target.type.isVar) { | 1362 if (!target.type.isVar) { |
1356 world.warning('could not find applicable $action for "$name"', node.span); | 1363 world.warning('could not find applicable $action for "$name"', node.span); |
1357 } | 1364 } |
1358 return new Value(world.varType, | 1365 return new Value(world.varType, |
1359 '${target.code}.$jsname() /*no applicable $action*/', node.span); | 1366 '${target.code}.$jsname() /*no applicable $action*/', node.span); |
(...skipping 78 matching lines...) Expand 10 before | Expand all | Expand 10 after Loading... | |
1438 } else { | 1445 } else { |
1439 return new Value(returnValue.type, | 1446 return new Value(returnValue.type, |
1440 '${target.code}.set\$$jsname(${value.code})', node.span); | 1447 '${target.code}.set\$$jsname(${value.code})', node.span); |
1441 } | 1448 } |
1442 } | 1449 } |
1443 return returnValue; | 1450 return returnValue; |
1444 } | 1451 } |
1445 | 1452 |
1446 Value invoke(MethodGenerator context, Node node, Value target, | 1453 Value invoke(MethodGenerator context, Node node, Value target, |
1447 Arguments args, [bool isDynamic=false]) { | 1454 Arguments args, [bool isDynamic=false]) { |
1455 // If this is the global MemberSet from world, always bind dynamically. | |
1456 // Note: we need this for proper noSuchMethod and REPL behavior. | |
1457 if (isVar && !isOperator) { | |
1458 return invokeOnVar(context, node, target, args); | |
1459 } | |
1460 | |
1448 if (members.length == 1) { | 1461 if (members.length == 1) { |
1449 return members[0].invoke(context, node, target, args, isDynamic); | 1462 return members[0].invoke(context, node, target, args, isDynamic); |
1450 } | 1463 } |
1451 final targets = members.filter((m) => m.canInvoke(context, args)); | 1464 final targets = members.filter((m) => m.canInvoke(context, args)); |
1452 if (targets.length == 1) { | 1465 if (targets.length == 1) { |
1453 return targets[0].invoke(context, node, target, args, isDynamic); | 1466 return targets[0].invoke(context, node, target, args, isDynamic); |
1454 } | 1467 } |
1455 | 1468 |
1456 Value returnValue = null; | 1469 Value returnValue = null; |
1457 for (var member in targets) { | 1470 for (var member in targets) { |
1458 final res = member.invoke(context, node, target, args, isDynamic:true); | 1471 final res = member.invoke(context, node, target, args, isDynamic:true); |
1459 returnValue = _tryUnion(returnValue, res, node); | 1472 returnValue = _tryUnion(returnValue, res, node); |
1460 } | 1473 } |
1461 | 1474 |
1462 if (returnValue == null) { | 1475 if (returnValue == null) { |
1463 return _makeError(node, target, 'method'); | 1476 return _makeError(node, target, 'method'); |
1464 } | 1477 } |
1465 | 1478 |
1466 // If we fail to unify the resulting code, implement as a var call. | |
1467 if (returnValue.code == null) { | 1479 if (returnValue.code == null) { |
1468 if (name.startsWith('\$')) { | 1480 // TODO(jmesserly): make operators less special. |
1481 if (isOperator) { | |
1469 return target.invokeSpecial(name, args, returnValue.type); | 1482 return target.invokeSpecial(name, args, returnValue.type); |
1470 } else { | 1483 } else { |
1471 return invokeOnVar(context, node, target, args); | 1484 return invokeOnVar(context, node, target, args); |
1472 } | 1485 } |
1473 } | 1486 } |
1474 | 1487 |
1475 return returnValue; | 1488 return returnValue; |
1476 } | 1489 } |
1477 | 1490 |
1478 Value invokeOnVar(MethodGenerator context, Node node, Value target, | 1491 Value invokeOnVar(MethodGenerator context, Node node, Value target, |
1479 Arguments args) { | 1492 Arguments args) { |
1480 return getVarMember(context, node, args).invoke(context, node, target, args) ; | 1493 var member = getVarMember(context, node, args); |
1494 return member.invoke(context, node, target, args); | |
1481 } | 1495 } |
1482 | 1496 |
1483 Value _union(Value x, Value y, Node node) { | 1497 Value _union(Value x, Value y, Node node) { |
1484 var result = _tryUnion(x, y, node); | 1498 var result = _tryUnion(x, y, node); |
1485 if (result.code == null) { | 1499 if (result.code == null) { |
1486 world.internalError('mismatched code for $name (${x.code}, ${y.code})', | 1500 world.internalError('mismatched code for $name (${x.code}, ${y.code})', |
1487 node.span); | 1501 node.span); |
1488 } | 1502 } |
1489 return result; | 1503 return result; |
1490 } | 1504 } |
(...skipping 110 matching lines...) Expand 10 before | Expand all | Expand 10 after Loading... | |
1601 } | 1615 } |
1602 | 1616 |
1603 void forEach(void f(Member member)) { | 1617 void forEach(void f(Member member)) { |
1604 factories.forEach((_, Map constructors) { | 1618 factories.forEach((_, Map constructors) { |
1605 constructors.forEach((_, Member member) { | 1619 constructors.forEach((_, Member member) { |
1606 f(member); | 1620 f(member); |
1607 }); | 1621 }); |
1608 }); | 1622 }); |
1609 } | 1623 } |
1610 } | 1624 } |
OLD | NEW |