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 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 |