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 /** | 5 /** |
| 6 * Top level generator object for writing code and keeping track of | 6 * Top level generator object for writing code and keeping track of |
| 7 * dependencies. | 7 * dependencies. |
| 8 * | 8 * |
| 9 * Should have two compilation models, but only one implemented so far. | 9 * Should have two compilation models, but only one implemented so far. |
| 10 * | 10 * |
| (...skipping 489 matching lines...) Expand 10 before | Expand all | Expand 10 after Loading... | |
| 500 } | 500 } |
| 501 | 501 |
| 502 // Make sure variables don't shadow any names we might need to access. | 502 // Make sure variables don't shadow any names we might need to access. |
| 503 if (!isParameter) { | 503 if (!isParameter) { |
| 504 int index = 0; | 504 int index = 0; |
| 505 while (_isDefinedInParent(jsName)) { | 505 while (_isDefinedInParent(jsName)) { |
| 506 jsName = '$name${index++}'; | 506 jsName = '$name${index++}'; |
| 507 } | 507 } |
| 508 } | 508 } |
| 509 | 509 |
| 510 var ret = new Value(type, jsName, false, false); // TODO: needsTemp:false); | 510 var ret = new Value(type, jsName, location != null ? location.span : null, |
| 511 false, false); | |
| 511 _vars[name] = ret; | 512 _vars[name] = ret; |
| 512 return ret; | 513 return ret; |
| 513 } | 514 } |
| 514 | 515 |
| 515 Value declareParameter(Parameter p) { | 516 Value declareParameter(Parameter p) { |
| 516 return create(p.name, p.type, p.definition, isParameter:true); | 517 return create(p.name, p.type, p.definition, isParameter:true); |
| 517 } | 518 } |
| 518 | 519 |
| 519 /** Declares a variable in the current scope for this identifier. */ | 520 /** Declares a variable in the current scope for this identifier. */ |
| 520 Value declare(DeclaredIdentifier id) { | 521 Value declare(DeclaredIdentifier id) { |
| (...skipping 51 matching lines...) Expand 10 before | Expand all | Expand 10 after Loading... | |
| 572 // For named lambdas, add the name to this scope so we can call it | 573 // For named lambdas, add the name to this scope so we can call it |
| 573 // recursively. | 574 // recursively. |
| 574 if (enclosingMethod != null && method.name != '') { | 575 if (enclosingMethod != null && method.name != '') { |
| 575 MethodMember m = method; // lambdas must be MethodMembers | 576 MethodMember m = method; // lambdas must be MethodMembers |
| 576 _scope.create(m.name, m.functionType, m.definition); | 577 _scope.create(m.name, m.functionType, m.definition); |
| 577 } | 578 } |
| 578 _usedTemps = new Set(); | 579 _usedTemps = new Set(); |
| 579 _freeTemps = []; | 580 _freeTemps = []; |
| 580 } | 581 } |
| 581 | 582 |
| 583 Library get library() => method.library; | |
| 584 | |
| 582 // TODO(jimhug): Where does this really belong? | 585 // TODO(jimhug): Where does this really belong? |
| 583 MemberSet findMembers(String name) { | 586 MemberSet findMembers(String name) { |
| 584 return method.library._findMembers(name); | 587 return library._findMembers(name); |
| 585 } | 588 } |
| 586 | 589 |
| 587 bool get isClosure() => (enclosingMethod != null); | 590 bool get isClosure() => (enclosingMethod != null); |
| 588 | 591 |
| 589 bool get isStatic() => method.isStatic; | 592 bool get isStatic() => method.isStatic; |
| 590 | 593 |
| 591 Value getTemp(Value value) { | 594 Value getTemp(Value value) { |
| 592 return value.needsTemp ? forceTemp(value) : value; | 595 return value.needsTemp ? forceTemp(value) : value; |
| 593 } | 596 } |
| 594 | 597 |
| 595 Value forceTemp(Value value) { | 598 Value forceTemp(Value value) { |
| 596 String name; | 599 String name; |
| 597 if (_freeTemps.length > 0) { | 600 if (_freeTemps.length > 0) { |
| 598 name = _freeTemps.removeLast(); | 601 name = _freeTemps.removeLast(); |
| 599 } else { | 602 } else { |
| 600 name = '\$' + _usedTemps.length; | 603 name = '\$' + _usedTemps.length; |
| 601 } | 604 } |
| 602 _usedTemps.add(name); | 605 _usedTemps.add(name); |
| 603 return new Value(value.type, name, /*isSuper:*/false, /*needsTemp:*/false); | 606 return new Value(value.type, name, value.span, |
| 607 /*isSuper:*/false, /*needsTemp:*/false); | |
| 604 } | 608 } |
| 605 | 609 |
| 606 Value assignTemp(Value tmp, Value v) { | 610 Value assignTemp(Value tmp, Value v) { |
| 607 if (tmp == v) { | 611 if (tmp == v) { |
| 608 return v; | 612 return v; |
| 609 } else { | 613 } else { |
| 610 // TODO(jmesserly): we should mark this returned value with the temp | 614 // TODO(jmesserly): we should mark this returned value with the temp |
| 611 // somehow, so getTemp will reuse it instead of allocating a new one. | 615 // somehow, so getTemp will reuse it instead of allocating a new one. |
| 612 return new Value(v.type, '(${tmp.code} = ${v.code})'); | 616 return new Value(v.type, '(${tmp.code} = ${v.code})', v.span); |
| 613 } | 617 } |
| 614 } | 618 } |
| 615 | 619 |
| 616 void freeTemp(Value value) { | 620 void freeTemp(Value value) { |
| 617 if (_usedTemps.remove(value.code)) { | 621 if (_usedTemps.remove(value.code)) { |
| 618 _freeTemps.add(value.code); | 622 _freeTemps.add(value.code); |
| 619 } else { | 623 } else { |
| 620 world.internalError( | 624 world.internalError( |
| 621 'tried to free unused value or non-temp "${value.code}"'); | 625 'tried to free unused value or non-temp "${value.code}"'); |
| 622 } | 626 } |
| (...skipping 172 matching lines...) Expand 10 before | Expand all | Expand 10 after Loading... | |
| 795 if (initializers != null && p.isInitializer) { | 799 if (initializers != null && p.isInitializer) { |
| 796 var field = method.declaringType.getMember(p.name); | 800 var field = method.declaringType.getMember(p.name); |
| 797 if (field == null) { | 801 if (field == null) { |
| 798 world.error('bad this parameter - no matching field', | 802 world.error('bad this parameter - no matching field', |
| 799 p.definition.span); | 803 p.definition.span); |
| 800 } | 804 } |
| 801 if (!field.isField) { | 805 if (!field.isField) { |
| 802 world.error('"this.${p.name}" does not refer to a field', | 806 world.error('"this.${p.name}" does not refer to a field', |
| 803 p.definition.span); | 807 p.definition.span); |
| 804 } | 808 } |
| 805 var paramValue = new Value(field.returnType, p.name, false, false); | 809 var paramValue = new Value(field.returnType, p.name, |
| 810 p.definition.span, false, false); | |
| 806 _paramCode.add(paramValue.code); | 811 _paramCode.add(paramValue.code); |
| 807 | 812 |
| 808 initializers.add('this.${field.jsname} = ${paramValue.code};'); | 813 initializers.add('this.${field.jsname} = ${paramValue.code};'); |
| 809 initializedFields.add(p.name); | 814 initializedFields.add(p.name); |
| 810 } else { | 815 } else { |
| 811 var paramValue = _scope.declareParameter(p); | 816 var paramValue = _scope.declareParameter(p); |
| 812 _paramCode.add(paramValue.code); | 817 _paramCode.add(paramValue.code); |
| 813 } | 818 } |
| 814 } | 819 } |
| 815 | 820 |
| (...skipping 427 matching lines...) Expand 10 before | Expand all | Expand 10 after Loading... | |
| 1243 writer.enterBlock('for (var ${tmpi.code} = 0;' + | 1248 writer.enterBlock('for (var ${tmpi.code} = 0;' + |
| 1244 '${tmpi.code} < ${listVar.code}.length; ${tmpi.code}++) {'); | 1249 '${tmpi.code} < ${listVar.code}.length; ${tmpi.code}++) {'); |
| 1245 var value = listVar.invoke(this, '\$index', node.list, | 1250 var value = listVar.invoke(this, '\$index', node.list, |
| 1246 new Arguments(null, [tmpi])); | 1251 new Arguments(null, [tmpi])); |
| 1247 writer.writeln('var ${item.code} = ${value.code};'); | 1252 writer.writeln('var ${item.code} = ${value.code};'); |
| 1248 } else { | 1253 } else { |
| 1249 _pushBlock(); | 1254 _pushBlock(); |
| 1250 // Needed to tell the runtime that we're doing this behind its back. | 1255 // Needed to tell the runtime that we're doing this behind its back. |
| 1251 var c = world.coreimpl.types['ListIterator'].getConstructor(''); | 1256 var c = world.coreimpl.types['ListIterator'].getConstructor(''); |
| 1252 c.invoke(this, node, null, | 1257 c.invoke(this, node, null, |
| 1253 new Arguments(null, [new Value(null, 'l')])); | 1258 new Arguments(null, [new Value(null, 'l', node.list.span)])); |
| 1254 | 1259 |
| 1255 var iterator = list.invoke(this, 'iterator', node.list, | 1260 var iterator = list.invoke(this, 'iterator', node.list, |
| 1256 Arguments.EMPTY); | 1261 Arguments.EMPTY); |
| 1257 var tmpi = _scope.create('\$i', iterator.type, null); | 1262 var tmpi = _scope.create('\$i', iterator.type, null); |
| 1258 | 1263 |
| 1259 var hasNext = tmpi.invoke(this, 'hasNext', node.list, Arguments.EMPTY); | 1264 var hasNext = tmpi.invoke(this, 'hasNext', node.list, Arguments.EMPTY); |
| 1260 var next = tmpi.invoke(this, 'next', node.list, Arguments.EMPTY); | 1265 var next = tmpi.invoke(this, 'next', node.list, Arguments.EMPTY); |
| 1261 | 1266 |
| 1262 writer.enterBlock( | 1267 writer.enterBlock( |
| 1263 'for (var ${tmpi.code} = ${iterator.code}; ${hasNext.code}; ) {'); | 1268 'for (var ${tmpi.code} = ${iterator.code}; ${hasNext.code}; ) {'); |
| 1264 writer.writeln('var ${item.code} = ${next.code};'); | 1269 writer.writeln('var ${item.code} = ${next.code};'); |
| 1265 } | 1270 } |
| 1266 | 1271 |
| 1267 visitStatementsInBlock(node.body); | 1272 visitStatementsInBlock(node.body); |
| 1268 writer.exitBlock('}'); | 1273 writer.exitBlock('}'); |
| 1269 _popBlock(); | 1274 _popBlock(); |
| 1270 return false; | 1275 return false; |
| 1271 } | 1276 } |
| 1272 | 1277 |
| 1273 void _genToDartException(String ex, Node node) { | 1278 void _genToDartException(String ex, Node node) { |
| 1274 var types = const [ | 1279 var types = const [ |
| 1275 'NullPointerException', 'ObjectNotClosureException', | 1280 'NullPointerException', 'ObjectNotClosureException', |
| 1276 'NoSuchMethodException', 'StackOverflowException']; | 1281 'NoSuchMethodException', 'StackOverflowException']; |
| 1277 var target = new Value(null, 'this'); | 1282 var target = new Value(null, 'this', node.span); |
| 1278 for (var name in types) { | 1283 for (var name in types) { |
| 1279 world.corelib.types[name].markUsed(); | 1284 world.corelib.types[name].markUsed(); |
| 1280 world.corelib.types[name].members['toString'].invoke( | 1285 world.corelib.types[name].members['toString'].invoke( |
| 1281 this, node, target, Arguments.EMPTY); | 1286 this, node, target, Arguments.EMPTY); |
| 1282 } | 1287 } |
| 1283 writer.writeln('$ex = \$toDartException($ex);'); | 1288 writer.writeln('$ex = \$toDartException($ex);'); |
| 1284 world.gen.corejs.useToDartException = true; | 1289 world.gen.corejs.useToDartException = true; |
| 1285 } | 1290 } |
| 1286 | 1291 |
| 1287 bool visitTryStatement(TryStatement node) { | 1292 bool visitTryStatement(TryStatement node) { |
| (...skipping 197 matching lines...) Expand 10 before | Expand all | Expand 10 after Loading... | |
| 1485 world.warning('not allowed in static method', node.span); | 1490 world.warning('not allowed in static method', node.span); |
| 1486 } | 1491 } |
| 1487 } | 1492 } |
| 1488 | 1493 |
| 1489 _makeSuperValue(Node node) { | 1494 _makeSuperValue(Node node) { |
| 1490 var parentType = method.declaringType.parent; | 1495 var parentType = method.declaringType.parent; |
| 1491 _checkNonStatic(node); | 1496 _checkNonStatic(node); |
| 1492 if (parentType == null) { | 1497 if (parentType == null) { |
| 1493 world.error('no super class', node.span); | 1498 world.error('no super class', node.span); |
| 1494 } | 1499 } |
| 1495 return new Value(parentType, 'this', | 1500 return new Value(parentType, 'this', node.span, |
| 1496 /*isSuper:*/true, /*needsTemp:*/false); | 1501 /*isSuper:*/true, /*needsTemp:*/false); |
| 1497 } | 1502 } |
| 1498 | 1503 |
| 1499 _getOutermostMethod() { | 1504 _getOutermostMethod() { |
| 1500 var result = this; | 1505 var result = this; |
| 1501 while (result.enclosingMethod != null) { | 1506 while (result.enclosingMethod != null) { |
| 1502 result = result.enclosingMethod; | 1507 result = result.enclosingMethod; |
| 1503 } | 1508 } |
| 1504 return result; | 1509 return result; |
| 1505 } | 1510 } |
| 1506 | 1511 |
| 1512 | |
| 1513 // TODO(jimhug): Share code better with _makeThisValue. | |
| 1514 String _makeThisCode() { | |
| 1515 if (enclosingMethod != null) { | |
| 1516 _getOutermostMethod().needsThis = true; | |
| 1517 return '\$this'; | |
| 1518 } else { | |
| 1519 return 'this'; | |
| 1520 } | |
| 1521 } | |
| 1522 | |
| 1507 /** | 1523 /** |
| 1508 * Creates a reference to the enclosing type ('this') that can be used within | 1524 * Creates a reference to the enclosing type ('this') that can be used within |
| 1509 * closures. | 1525 * closures. |
| 1510 */ | 1526 */ |
| 1511 _makeThisValue(Node node) { | 1527 Value _makeThisValue(Node node) { |
| 1512 if (enclosingMethod != null) { | 1528 if (enclosingMethod != null) { |
| 1513 var outermostMethod = _getOutermostMethod(); | 1529 var outermostMethod = _getOutermostMethod(); |
| 1514 outermostMethod._checkNonStatic(node); | 1530 outermostMethod._checkNonStatic(node); |
| 1515 outermostMethod.needsThis = true; | 1531 outermostMethod.needsThis = true; |
| 1516 return new Value(outermostMethod.method.declaringType, '\$this', | 1532 return new Value(outermostMethod.method.declaringType, '\$this', |
| 1517 /*isSuper:*/false, /*needsTemp:*/false); | 1533 node != null ? node.span : null, /*isSuper:*/false, /*needsTemp:*/false) ; |
| 1518 } else { | 1534 } else { |
| 1519 _checkNonStatic(node); | 1535 _checkNonStatic(node); |
| 1520 return new Value(method.declaringType, 'this', | 1536 return new Value(method.declaringType, 'this', node != null ? node.span : null, |
|
Jennifer Messerly
2011/11/10 22:50:39
this code is screaming for a ?. operator :)
Maybe
| |
| 1521 /*isSuper:*/false, /*needsTemp:*/false); | 1537 /*isSuper:*/false, /*needsTemp:*/false); |
| 1522 } | 1538 } |
| 1523 } | 1539 } |
| 1524 | 1540 |
| 1525 // ******************* Expressions ******************* | 1541 // ******************* Expressions ******************* |
| 1526 visitLambdaExpression(LambdaExpression node) { | 1542 visitLambdaExpression(LambdaExpression node) { |
| 1527 var name = ''; | 1543 var name = ''; |
| 1528 if (node.func.name != null) { | 1544 if (node.func.name != null) { |
| 1529 name = world.toJsIdentifier(node.func.name.name); | 1545 name = world.toJsIdentifier(node.func.name.name); |
| 1530 } | 1546 } |
| 1531 | 1547 |
| 1532 var meth = _makeLambdaMethod(name, node.func); | 1548 var meth = _makeLambdaMethod(name, node.func); |
| 1533 | 1549 |
| 1534 var w = new CodeWriter(); | 1550 var w = new CodeWriter(); |
| 1535 meth.generator.writeDefinition(w, node); | 1551 meth.generator.writeDefinition(w, node); |
| 1536 | 1552 |
| 1537 return new Value(meth.functionType, w.text); | 1553 return new Value(meth.functionType, w.text, node.span); |
| 1538 } | 1554 } |
| 1539 | 1555 |
| 1540 visitCallExpression(CallExpression node) { | 1556 visitCallExpression(CallExpression node) { |
| 1541 var target; | 1557 var target; |
| 1542 var position = node.target; | 1558 var position = node.target; |
| 1543 var name = '\$call'; | 1559 var name = '\$call'; |
| 1544 if (node.target is DotExpression) { | 1560 if (node.target is DotExpression) { |
| 1545 DotExpression dot = node.target; | 1561 DotExpression dot = node.target; |
| 1546 target = dot.self.visit(this); | 1562 target = dot.self.visit(this); |
| 1547 name = dot.name.name; | 1563 name = dot.name.name; |
| 1548 position = dot.name; | 1564 position = dot.name; |
| 1549 } else if (node.target is VarExpression) { | 1565 } else if (node.target is VarExpression) { |
| 1550 VarExpression varExpr = node.target; | 1566 VarExpression varExpr = node.target; |
| 1551 name = varExpr.name.name; | 1567 name = varExpr.name.name; |
| 1552 var meth = method.declaringType.resolveMember(name); | 1568 // First check in block scopes. |
| 1553 if (meth != null) { | 1569 target = _scope.lookup(name); |
| 1554 target = _makeThisOrType(); | 1570 if (target != null) { |
| 1555 return meth.invoke(this, varExpr, target, | 1571 return target.invoke(this, '\$call', node, _makeArgs(node.arguments)); |
| 1556 _makeArgs(node.arguments)); | |
| 1557 } | |
| 1558 // Look for members of the top-level type (or imported libs). | |
| 1559 meth = method.declaringType.library.lookup(name, varExpr.span); | |
| 1560 if (meth != null) { | |
| 1561 return meth.invoke(this, varExpr, null, _makeArgs(node.arguments)); | |
| 1562 } | 1572 } |
| 1563 | 1573 |
| 1564 name = '\$call'; | 1574 target = _makeThisOrType(varExpr.span); |
| 1565 target = varExpr.visit(this); | 1575 return target.invoke(this, name, node, _makeArgs(node.arguments)); |
| 1566 } else { | 1576 } else { |
| 1567 target = node.target.visit(this); | 1577 target = node.target.visit(this); |
| 1568 } | 1578 } |
| 1569 | 1579 |
| 1570 return target.invoke(this, name, position, _makeArgs(node.arguments)); | 1580 return target.invoke(this, name, position, _makeArgs(node.arguments)); |
| 1571 } | 1581 } |
| 1572 | 1582 |
| 1573 visitIndexExpression(IndexExpression node) { | 1583 visitIndexExpression(IndexExpression node) { |
| 1574 var target = visitValue(node.target); | 1584 var target = visitValue(node.target); |
| 1575 var index = visitValue(node.index); | 1585 var index = visitValue(node.index); |
| 1576 return target.invoke(this, '\$index', node, new Arguments(null, [index])); | 1586 return target.invoke(this, '\$index', node, new Arguments(null, [index])); |
| 1577 } | 1587 } |
| 1578 | 1588 |
| 1579 visitBinaryExpression(BinaryExpression node) { | 1589 visitBinaryExpression(BinaryExpression node) { |
| 1580 final kind = node.op.kind; | 1590 final kind = node.op.kind; |
| 1581 // TODO(jimhug): Ensure these have same semantics as JS! | 1591 // TODO(jimhug): Ensure these have same semantics as JS! |
| 1582 if (kind == TokenKind.AND || kind == TokenKind.OR) { | 1592 if (kind == TokenKind.AND || kind == TokenKind.OR) { |
| 1583 var x = visitValue(node.x); | 1593 var x = visitValue(node.x); |
| 1584 var y = visitValue(node.y); | 1594 var y = visitValue(node.y); |
| 1585 final code = '${x.code} ${node.op} ${y.code}'; | 1595 final code = '${x.code} ${node.op} ${y.code}'; |
| 1586 if (x.isConst && y.isConst) { | 1596 if (x.isConst && y.isConst) { |
| 1587 var value = (kind == TokenKind.AND) | 1597 var value = (kind == TokenKind.AND) |
| 1588 ? x.actualValue && y.actualValue : x.actualValue || y.actualValue; | 1598 ? x.actualValue && y.actualValue : x.actualValue || y.actualValue; |
| 1589 return new EvaluatedValue(x.type, value, '$value', node.span); | 1599 return new EvaluatedValue(x.type, value, '$value', node.span); |
| 1590 } | 1600 } |
| 1591 return new Value(null, code); | 1601 return new Value(null, code, node.span); |
| 1592 } else if (kind == TokenKind.EQ_STRICT || kind == TokenKind.NE_STRICT) { | 1602 } else if (kind == TokenKind.EQ_STRICT || kind == TokenKind.NE_STRICT) { |
| 1593 var x = visitValue(node.x); | 1603 var x = visitValue(node.x); |
| 1594 var y = visitValue(node.y); | 1604 var y = visitValue(node.y); |
| 1595 if (x.isConst && y.isConst) { | 1605 if (x.isConst && y.isConst) { |
| 1596 var value = kind == TokenKind.EQ_STRICT | 1606 var value = kind == TokenKind.EQ_STRICT |
| 1597 // Note: it is ok to use == and not === here since all of these | 1607 // Note: it is ok to use == and not === here since all of these |
| 1598 // constant comparisons are applied to doubles, bool, or strings. | 1608 // constant comparisons are applied to doubles, bool, or strings. |
| 1599 // We need it for the compile-time evaluator because | 1609 // We need it for the compile-time evaluator because |
| 1600 // (9).toDouble() === 9.0 is false in dartvm. | 1610 // (9).toDouble() === 9.0 is false in dartvm. |
| 1601 ? x.actualValue == y.actualValue : x.actualValue != y.actualValue; | 1611 ? x.actualValue == y.actualValue : x.actualValue != y.actualValue; |
| 1602 return new EvaluatedValue(world.boolType, value, "$value", node.span); | 1612 return new EvaluatedValue(world.boolType, value, "$value", node.span); |
| 1603 } | 1613 } |
| 1604 if (x.code == 'null' || y.code == 'null') { | 1614 if (x.code == 'null' || y.code == 'null') { |
| 1605 // Switching to == ensures that null and undefined are interchangable. | 1615 // Switching to == ensures that null and undefined are interchangable. |
| 1606 final op = node.op.toString().substring(0,2); | 1616 final op = node.op.toString().substring(0,2); |
| 1607 return new Value(null, '${x.code} $op ${y.code}'); | 1617 return new Value(null, '${x.code} $op ${y.code}', node.span); |
| 1608 } else { | 1618 } else { |
| 1609 // TODO(jimhug): Resolve issue with undefined and null here. | 1619 // TODO(jimhug): Resolve issue with undefined and null here. |
| 1610 return new Value(null, '${x.code} ${node.op} ${y.code}'); | 1620 return new Value(null, '${x.code} ${node.op} ${y.code}', node.span); |
| 1611 } | 1621 } |
| 1612 } | 1622 } |
| 1613 | 1623 |
| 1614 final assignKind = TokenKind.kindFromAssign(node.op.kind); | 1624 final assignKind = TokenKind.kindFromAssign(node.op.kind); |
| 1615 if (assignKind == -1) { | 1625 if (assignKind == -1) { |
| 1616 final x = visitValue(node.x); | 1626 final x = visitValue(node.x); |
| 1617 final y = visitValue(node.y); | 1627 final y = visitValue(node.y); |
| 1618 var name = TokenKind.binaryMethodName(node.op.kind); | 1628 var name = TokenKind.binaryMethodName(node.op.kind); |
| 1619 if (node.op.kind == TokenKind.NE) { | 1629 if (node.op.kind == TokenKind.NE) { |
| 1620 name = '\$ne'; | 1630 name = '\$ne'; |
| (...skipping 30 matching lines...) Expand all Loading... | |
| 1651 return _visitDotAssign(kind, xn, yn, position, captureOriginal); | 1661 return _visitDotAssign(kind, xn, yn, position, captureOriginal); |
| 1652 } else { | 1662 } else { |
| 1653 world.error('illegal lhs', position.span); | 1663 world.error('illegal lhs', position.span); |
| 1654 } | 1664 } |
| 1655 } | 1665 } |
| 1656 | 1666 |
| 1657 // TODO(jmesserly): it'd be nice if we didn't have to deal directly with | 1667 // TODO(jmesserly): it'd be nice if we didn't have to deal directly with |
| 1658 // MemberSets here and in visitVarExpression. | 1668 // MemberSets here and in visitVarExpression. |
| 1659 _visitVarAssign(int kind, VarExpression xn, Expression yn, Node position, | 1669 _visitVarAssign(int kind, VarExpression xn, Expression yn, Node position, |
| 1660 Value captureOriginal(Value right)) { | 1670 Value captureOriginal(Value right)) { |
| 1671 final name = xn.name.name; | |
| 1661 | 1672 |
| 1662 // First check in block scopes. | 1673 // First check in block scopes. |
| 1663 var x = _scope.lookup(xn.name.name); | 1674 var x = _scope.lookup(name); |
| 1664 var y = visitValue(yn); | 1675 var y = visitValue(yn); |
| 1665 | 1676 |
| 1666 if (x == null) { | 1677 if (x == null) { |
| 1667 // Look for a setter in the class | 1678 // Look for a setter in the class |
| 1668 var members = method.declaringType.resolveMember(xn.name.name); | 1679 var members = method.declaringType.resolveMember(name); |
| 1669 if (members != null) { | 1680 if (members != null) { |
| 1670 x = _makeThisOrType(); | 1681 x = _makeThisOrType(position.span); |
| 1671 } else { | 1682 if (kind == 0) { |
| 1672 // Look for a top-level setter | 1683 return x.set_(this, name, position, y); |
| 1673 final member = method.declaringType.library.lookup( | 1684 } else if (!members.treatAsField || members.containsMethods) { |
| 1674 xn.name.name, xn.name.span); | 1685 var right = x.get_(this, name, position); |
| 1675 if (member == null) { | 1686 //var right = members._get(this, position, x); |
|
Jennifer Messerly
2011/11/10 22:50:39
remove? Or make a TODO?
| |
| 1676 world.warning('can not resolve ${xn.name.name}', xn.span); | |
| 1677 return _makeMissingValue(xn.name.name); | |
| 1678 } | |
| 1679 members = new MemberSet(member); | |
| 1680 } | |
| 1681 | |
| 1682 // If we can't treat it as a field, generate a setter call. | |
| 1683 // Also make sure we dont't try to set a method. | |
| 1684 if (!members.treatAsField || members.containsMethods) { | |
| 1685 if (kind != 0) { | |
| 1686 var right = members.get_(this, position, x); | |
| 1687 right = captureOriginal(right); | 1687 right = captureOriginal(right); |
| 1688 y = right.invoke(this, TokenKind.binaryMethodName(kind), | 1688 y = right.invoke(this, TokenKind.binaryMethodName(kind), |
| 1689 position, new Arguments(null, [y])); | 1689 position, new Arguments(null, [y])); |
| 1690 return x.set_(this, name, position, y); | |
| 1691 } else { | |
| 1692 x = x.get_(this, name, position); | |
| 1690 } | 1693 } |
| 1691 return members.set_(this, position, x, y); | 1694 } else { |
| 1695 // Look for a top-level setter | |
| 1696 final member = library.lookup(name, xn.name.span); | |
| 1697 if (member == null) { | |
| 1698 world.warning('can not resolve ${name}', xn.span); | |
| 1699 return _makeMissingValue(name); | |
| 1700 } | |
| 1701 members = new MemberSet(member); | |
| 1702 // If we can't treat it as a field, generate a setter call. | |
| 1703 // Also make sure we dont't try to set a method. | |
|
Jennifer Messerly
2011/11/10 22:50:39
guessing we're on a path to removing this duplicat
| |
| 1704 if (!members.treatAsField || members.containsMethods) { | |
| 1705 if (kind != 0) { | |
| 1706 var right = members._get(this, position, x); | |
| 1707 right = captureOriginal(right); | |
| 1708 y = right.invoke(this, TokenKind.binaryMethodName(kind), | |
| 1709 position, new Arguments(null, [y])); | |
| 1710 } | |
| 1711 return members._set(this, position, x, y); | |
| 1712 } else { | |
| 1713 x = members._get(this, position, x); | |
| 1714 } | |
| 1692 } | 1715 } |
| 1693 | 1716 |
| 1694 // Otherwise treat it as a field. | 1717 // Otherwise treat it as a field. |
| 1695 // This makes for nicer code in the $op= case | 1718 // This makes for nicer code in the $op= case |
| 1696 x = members.get_(this, position, x); | |
| 1697 } | 1719 } |
| 1698 | 1720 |
| 1699 // TODO(jimhug): Needs checks for final and other rules to enforce. | 1721 // TODO(jimhug): Needs checks for final and other rules to enforce. |
| 1700 y = y.convertTo(this, x.type, yn); | 1722 y = y.convertTo(this, x.type, yn); |
| 1701 | 1723 |
| 1702 if (kind == 0) { | 1724 if (kind == 0) { |
| 1703 x = captureOriginal(x); | 1725 x = captureOriginal(x); |
| 1704 return new Value(y.type, '${x.code} = ${y.code}'); | 1726 return new Value(y.type, '${x.code} = ${y.code}', position.span); |
| 1705 } else if (x.type.isNum && y.type.isNum && (kind != TokenKind.TRUNCDIV)) { | 1727 } else if (x.type.isNum && y.type.isNum && (kind != TokenKind.TRUNCDIV)) { |
| 1706 // Process everything but ~/ , which has no equivalent JS operator | 1728 // Process everything but ~/ , which has no equivalent JS operator |
| 1707 x = captureOriginal(x); | 1729 x = captureOriginal(x); |
| 1708 // Very localized optimization for numbers! | 1730 // Very localized optimization for numbers! |
| 1709 final op = TokenKind.kindToString(kind); | 1731 final op = TokenKind.kindToString(kind); |
| 1710 return new Value(y.type, '${x.code} $op= ${y.code}'); | 1732 return new Value(y.type, '${x.code} $op= ${y.code}', position.span); |
| 1711 } else { | 1733 } else { |
| 1712 var right = x; | 1734 var right = x; |
| 1713 right = captureOriginal(right); | 1735 right = captureOriginal(right); |
| 1714 y = right.invoke(this, TokenKind.binaryMethodName(kind), | 1736 y = right.invoke(this, TokenKind.binaryMethodName(kind), |
| 1715 position, new Arguments(null, [y])); | 1737 position, new Arguments(null, [y])); |
| 1716 return new Value(y.type, '${x.code} = ${y.code}'); | 1738 return new Value(y.type, '${x.code} = ${y.code}', position.span); |
| 1717 } | 1739 } |
| 1718 } | 1740 } |
| 1719 | 1741 |
| 1720 _visitIndexAssign(int kind, IndexExpression xn, Expression yn, Node position, | 1742 _visitIndexAssign(int kind, IndexExpression xn, Expression yn, Node position, |
| 1721 Value captureOriginal(Value right)) { | 1743 Value captureOriginal(Value right)) { |
| 1722 var target = visitValue(xn.target); | 1744 var target = visitValue(xn.target); |
| 1723 var index = visitValue(xn.index); | 1745 var index = visitValue(xn.index); |
| 1724 var y = visitValue(yn); | 1746 var y = visitValue(yn); |
| 1725 | 1747 |
| 1726 var tmptarget = target; | 1748 var tmptarget = target; |
| (...skipping 35 matching lines...) Expand 10 before | Expand all | Expand 10 after Loading... | |
| 1762 if (tmptarget != target) freeTemp(tmptarget); | 1784 if (tmptarget != target) freeTemp(tmptarget); |
| 1763 return ret; | 1785 return ret; |
| 1764 } | 1786 } |
| 1765 | 1787 |
| 1766 visitUnaryExpression(UnaryExpression node) { | 1788 visitUnaryExpression(UnaryExpression node) { |
| 1767 var value = visitValue(node.self); | 1789 var value = visitValue(node.self); |
| 1768 switch (node.op.kind) { | 1790 switch (node.op.kind) { |
| 1769 case TokenKind.INCR: | 1791 case TokenKind.INCR: |
| 1770 case TokenKind.DECR: | 1792 case TokenKind.DECR: |
| 1771 if (value.type.isNum) { | 1793 if (value.type.isNum) { |
| 1772 return new Value(value.type, '${node.op}${value.code}'); | 1794 return new Value(value.type, '${node.op}${value.code}', node.span); |
| 1773 } else { | 1795 } else { |
| 1774 // ++x becomes x += 1 | 1796 // ++x becomes x += 1 |
| 1775 // --x becomes x -= 1 | 1797 // --x becomes x -= 1 |
| 1776 // TODO(jimhug): Confirm that --x becomes x -= 1 as it is in VM. | 1798 // TODO(jimhug): Confirm that --x becomes x -= 1 as it is in VM. |
| 1777 var kind = (TokenKind.INCR == node.op.kind ? | 1799 var kind = (TokenKind.INCR == node.op.kind ? |
| 1778 TokenKind.ADD : TokenKind.SUB); | 1800 TokenKind.ADD : TokenKind.SUB); |
| 1779 var operand = new LiteralExpression(1, | 1801 var operand = new LiteralExpression(1, |
| 1780 new TypeReference(node.span, world.numType), '1', node.span); | 1802 new TypeReference(node.span, world.numType), '1', node.span); |
| 1781 | 1803 |
| 1782 return _visitAssign(kind, node.self, operand, node, null); | 1804 return _visitAssign(kind, node.self, operand, node, null); |
| 1783 } | 1805 } |
| 1784 case TokenKind.NOT: | 1806 case TokenKind.NOT: |
| 1785 // TODO(jimhug): Issue #359 seeks to clarify this behavior. | 1807 // TODO(jimhug): Issue #359 seeks to clarify this behavior. |
| 1786 if (value.type.isBool && value.isConst) { | 1808 if (value.type.isBool && value.isConst) { |
| 1787 var newVal = !value.actualValue; | 1809 var newVal = !value.actualValue; |
| 1788 return new EvaluatedValue(value.type, newVal, '${newVal}', node.span); | 1810 return new EvaluatedValue(value.type, newVal, '${newVal}', node.span); |
| 1789 } else { | 1811 } else { |
| 1790 var newVal = value.convertToNonNullBool(this, node); | 1812 var newVal = value.convertToNonNullBool(this, node); |
| 1791 return new Value(world.boolType, '!${newVal.code}'); | 1813 return new Value(world.boolType, '!${newVal.code}', node.span); |
| 1792 } | 1814 } |
| 1793 | 1815 |
| 1794 case TokenKind.ADD: | 1816 case TokenKind.ADD: |
| 1795 // TODO(jimhug): Issue #359 seeks to clarify this behavior. | 1817 // TODO(jimhug): Issue #359 seeks to clarify this behavior. |
| 1796 return value.convertTo(this, world.numType, node); | 1818 return value.convertTo(this, world.numType, node); |
| 1797 | 1819 |
| 1798 case TokenKind.SUB: | 1820 case TokenKind.SUB: |
| 1799 case TokenKind.BIT_NOT: | 1821 case TokenKind.BIT_NOT: |
| 1800 if (node.op.kind == TokenKind.BIT_NOT) { | 1822 if (node.op.kind == TokenKind.BIT_NOT) { |
| 1801 return value.invoke(this, '\$bit_not', node, Arguments.EMPTY); | 1823 return value.invoke(this, '\$bit_not', node, Arguments.EMPTY); |
| 1802 } else if (node.op.kind == TokenKind.SUB) { | 1824 } else if (node.op.kind == TokenKind.SUB) { |
| 1803 return value.invoke(this, '\$negate', node, Arguments.EMPTY); | 1825 return value.invoke(this, '\$negate', node, Arguments.EMPTY); |
| 1804 } else { | 1826 } else { |
| 1805 world.internalError('unimplemented: unary ${node.op}', | 1827 world.internalError('unimplemented: unary ${node.op}', |
| 1806 node.span); | 1828 node.span); |
| 1807 } | 1829 } |
| 1808 default: | 1830 default: |
| 1809 world.internalError('unimplemented: ${node.op}', node.span); | 1831 world.internalError('unimplemented: ${node.op}', node.span); |
| 1810 } | 1832 } |
| 1811 } | 1833 } |
| 1812 | 1834 |
| 1813 visitPostfixExpression(PostfixExpression node, [bool isVoid = false]) { | 1835 visitPostfixExpression(PostfixExpression node, [bool isVoid = false]) { |
| 1814 var value = visitValue(node.body); | 1836 var value = visitValue(node.body); |
| 1815 if (value.type.isNum) { | 1837 if (value.type.isNum) { |
| 1816 return new Value(value.type, '${value.code}${node.op}'); | 1838 return new Value(value.type, '${value.code}${node.op}', node.span); |
| 1817 } | 1839 } |
| 1818 | 1840 |
| 1819 // x++ is equivalent to (t = x, x = t + 1, t), where we capture all temps | 1841 // x++ is equivalent to (t = x, x = t + 1, t), where we capture all temps |
| 1820 // needed to evaluate x so we're not evaluating multiple times. Likewise, | 1842 // needed to evaluate x so we're not evaluating multiple times. Likewise, |
| 1821 // x-- is equivalent to (t = x, x = t - 1, t). | 1843 // x-- is equivalent to (t = x, x = t - 1, t). |
| 1822 var kind = (TokenKind.INCR == node.op.kind) ? TokenKind.ADD : TokenKind.SUB; | 1844 var kind = (TokenKind.INCR == node.op.kind) ? TokenKind.ADD : TokenKind.SUB; |
| 1823 var operand = new LiteralExpression(1, | 1845 var operand = new LiteralExpression(1, |
| 1824 new TypeReference(node.span, world.numType), '1', node.span); | 1846 new TypeReference(node.span, world.numType), '1', node.span); |
| 1825 | 1847 |
| 1826 // Use _visitAssign to do most of the work, but save the right side in a | 1848 // Use _visitAssign to do most of the work, but save the right side in a |
| 1827 // temporary variable if needed. | 1849 // temporary variable if needed. |
| 1828 // TODO(jmesserly): I don't like passing function args like this, but the | 1850 // TODO(jmesserly): I don't like passing function args like this, but the |
| 1829 // alternative is duplicating most of the _visitAssign logic. Needs cleanup. | 1851 // alternative is duplicating most of the _visitAssign logic. Needs cleanup. |
| 1830 var tmpleft = null, left = null; | 1852 var tmpleft = null, left = null; |
| 1831 var ret = _visitAssign(kind, node.body, operand, node, (l) { | 1853 var ret = _visitAssign(kind, node.body, operand, node, (l) { |
| 1832 if (isVoid) { | 1854 if (isVoid) { |
| 1833 // No need for a temp if we're throwing away the result. | 1855 // No need for a temp if we're throwing away the result. |
| 1834 return l; | 1856 return l; |
| 1835 } else { | 1857 } else { |
| 1836 // We always need a temp to capture the old value | 1858 // We always need a temp to capture the old value |
| 1837 left = l; | 1859 left = l; |
| 1838 tmpleft = forceTemp(l); | 1860 tmpleft = forceTemp(l); |
| 1839 return assignTemp(tmpleft, left); | 1861 return assignTemp(tmpleft, left); |
| 1840 } | 1862 } |
| 1841 }); | 1863 }); |
| 1842 | 1864 |
| 1843 if (tmpleft != null) { | 1865 if (tmpleft != null) { |
| 1844 ret = new Value(ret.type, "(${ret.code}, ${tmpleft.code})"); | 1866 ret = new Value(ret.type, "(${ret.code}, ${tmpleft.code})", node.span); |
| 1845 } | 1867 } |
| 1846 if (tmpleft != left) { | 1868 if (tmpleft != left) { |
| 1847 freeTemp(tmpleft); | 1869 freeTemp(tmpleft); |
| 1848 } | 1870 } |
| 1849 return ret; | 1871 return ret; |
| 1850 } | 1872 } |
| 1851 | 1873 |
| 1852 visitNewExpression(NewExpression node) { | 1874 visitNewExpression(NewExpression node) { |
| 1853 var typeRef = node.type; | 1875 var typeRef = node.type; |
| 1854 | 1876 |
| (...skipping 60 matching lines...) Expand 10 before | Expand all | Expand 10 after Loading... | |
| 1915 argsCode.add(arg.canonicalCode); | 1937 argsCode.add(arg.canonicalCode); |
| 1916 } | 1938 } |
| 1917 } else { | 1939 } else { |
| 1918 argsCode.add(arg.code); | 1940 argsCode.add(arg.code); |
| 1919 } | 1941 } |
| 1920 } | 1942 } |
| 1921 | 1943 |
| 1922 world.coreimpl.types['ListFactory'].markUsed(); | 1944 world.coreimpl.types['ListFactory'].markUsed(); |
| 1923 | 1945 |
| 1924 final code = '[${Strings.join(argsCode, ", ")}]'; | 1946 final code = '[${Strings.join(argsCode, ", ")}]'; |
| 1925 var value = new Value(world.listType, code); | 1947 var value = new Value(world.listType, code, node.span); |
| 1926 if (node.isConst) { | 1948 if (node.isConst) { |
| 1927 final immutableList = world.coreimpl.types['ImmutableList']; | 1949 final immutableList = world.coreimpl.types['ImmutableList']; |
| 1928 final immutableListCtor = immutableList.getConstructor('from'); | 1950 final immutableListCtor = immutableList.getConstructor('from'); |
| 1929 final result = immutableListCtor.invoke( | 1951 final result = immutableListCtor.invoke( |
| 1930 this, node, null, new Arguments(null, [value])); | 1952 this, node, null, new Arguments(null, [value])); |
| 1931 value = world.gen.globalForConst( | 1953 value = world.gen.globalForConst( |
| 1932 new ConstListValue(immutableList, argValues, 'const $code', | 1954 new ConstListValue(immutableList, argValues, 'const $code', |
| 1933 result.code, node.span), | 1955 result.code, node.span), |
| 1934 argValues); | 1956 argValues); |
| 1935 } | 1957 } |
| (...skipping 29 matching lines...) Expand all Loading... | |
| 1965 } else { | 1987 } else { |
| 1966 argsCode.add(key.code); | 1988 argsCode.add(key.code); |
| 1967 argsCode.add(value.code); | 1989 argsCode.add(value.code); |
| 1968 } | 1990 } |
| 1969 } | 1991 } |
| 1970 var argList = '[${Strings.join(argsCode, ", ")}]'; | 1992 var argList = '[${Strings.join(argsCode, ", ")}]'; |
| 1971 final code = '\$map($argList)'; | 1993 final code = '\$map($argList)'; |
| 1972 if (node.isConst) { | 1994 if (node.isConst) { |
| 1973 final immutableMap = world.coreimpl.types['ImmutableMap']; | 1995 final immutableMap = world.coreimpl.types['ImmutableMap']; |
| 1974 final immutableMapCtor = immutableMap.getConstructor(''); | 1996 final immutableMapCtor = immutableMap.getConstructor(''); |
| 1975 final argsValue = new Value(world.listType, argList); | 1997 final argsValue = new Value(world.listType, argList, node.span); |
| 1976 final result = immutableMapCtor.invoke( | 1998 final result = immutableMapCtor.invoke( |
| 1977 this, node, null, new Arguments(null, [argsValue])); | 1999 this, node, null, new Arguments(null, [argsValue])); |
| 1978 final value = new ConstMapValue( | 2000 final value = new ConstMapValue( |
| 1979 immutableMap, argValues, code, result.code, node.span); | 2001 immutableMap, argValues, code, result.code, node.span); |
| 1980 return world.gen.globalForConst(value, argValues); | 2002 return world.gen.globalForConst(value, argValues); |
| 1981 } | 2003 } |
| 1982 return new Value(mapImplType, code); | 2004 return new Value(mapImplType, code, node.span); |
| 1983 } | 2005 } |
| 1984 | 2006 |
| 1985 visitConditionalExpression(ConditionalExpression node) { | 2007 visitConditionalExpression(ConditionalExpression node) { |
| 1986 var test = visitBool(node.test); | 2008 var test = visitBool(node.test); |
| 1987 var trueBranch = visitValue(node.trueBranch); | 2009 var trueBranch = visitValue(node.trueBranch); |
| 1988 var falseBranch = visitValue(node.falseBranch); | 2010 var falseBranch = visitValue(node.falseBranch); |
| 1989 | 2011 |
| 1990 var code = '${test.code} ? ${trueBranch.code} : ${falseBranch.code}'; | 2012 var code = '${test.code} ? ${trueBranch.code} : ${falseBranch.code}'; |
| 1991 return new Value(Type.union(trueBranch.type, falseBranch.type), code); | 2013 return new Value(Type.union(trueBranch.type, falseBranch.type), code, |
| 2014 node.span); | |
| 1992 } | 2015 } |
| 1993 | 2016 |
| 1994 visitIsExpression(IsExpression node) { | 2017 visitIsExpression(IsExpression node) { |
| 1995 var value = visitValue(node.x); | 2018 var value = visitValue(node.x); |
| 1996 var type = method.resolveType(node.type, false); | 2019 var type = method.resolveType(node.type, false); |
| 1997 return value.instanceOf(this, type, node.span, node.isTrue); | 2020 return value.instanceOf(this, type, node.span, node.isTrue); |
| 1998 } | 2021 } |
| 1999 | 2022 |
| 2000 visitParenExpression(ParenExpression node) { | 2023 visitParenExpression(ParenExpression node) { |
| 2001 var body = visitValue(node.body); | 2024 var body = visitValue(node.body); |
| 2002 if (body.isConst) { | 2025 if (body.isConst) { |
| 2003 return new EvaluatedValue(body.type, body.actualValue, | 2026 return new EvaluatedValue(body.type, body.actualValue, |
| 2004 '(${body.canonicalCode})', node.span); | 2027 '(${body.canonicalCode})', node.span); |
| 2005 } | 2028 } |
| 2006 return new Value(body.type, '(${body.code})'); | 2029 return new Value(body.type, '(${body.code})', node.span); |
| 2007 } | 2030 } |
| 2008 | 2031 |
| 2009 visitDotExpression(DotExpression node) { | 2032 visitDotExpression(DotExpression node) { |
| 2010 // Types are legal targets of . | 2033 // Types are legal targets of . |
| 2011 var target = node.self.visit(this); | 2034 var target = node.self.visit(this); |
| 2012 return target.get_(this, node.name.name, node.name); | 2035 return target.get_(this, node.name.name, node.name); |
| 2013 } | 2036 } |
| 2014 | 2037 |
| 2015 visitVarExpression(VarExpression node) { | 2038 visitVarExpression(VarExpression node) { |
| 2039 final name = node.name.name; | |
| 2040 | |
| 2016 // First check in block scopes. | 2041 // First check in block scopes. |
| 2017 var ret = _scope.lookup(node.name.name); | 2042 var ret = _scope.lookup(name); |
| 2018 if (ret != null) return ret; | 2043 if (ret != null) return ret; |
| 2019 | 2044 |
| 2020 // Then check for members on my type - including supertypes. | 2045 return _makeThisOrType(node.span).get_(this, name, node); |
|
Jennifer Messerly
2011/11/10 22:50:39
awesome cleanup!
| |
| 2021 ret = method.declaringType.resolveMember(node.name.name); | |
| 2022 if (ret != null) { | |
| 2023 return ret.get_(this, node, _makeThisOrType()); | |
| 2024 } | |
| 2025 | |
| 2026 // Then look for members of the top-level type. | |
| 2027 // This will also match types in the library and any libraries imported | |
| 2028 // without a prefix. | |
| 2029 ret = method.declaringType.library.lookup(node.name.name, node.span); | |
| 2030 if (ret != null) { | |
| 2031 return ret.get_(this, node, null); | |
| 2032 } | |
| 2033 | |
| 2034 world.warning('can not resolve ${node.name.name}', node.span); | |
| 2035 return _makeMissingValue(node.name.name); | |
| 2036 } | 2046 } |
| 2037 | 2047 |
| 2038 _makeMissingValue(String name) { | 2048 _makeMissingValue(String name) { |
| 2039 // TODO(jimhug): Needs major revision to support doesNotUnderstand. | 2049 // TODO(jimhug): Probably goes away to be fully replaced by doesNotUnder |
|
Jennifer Messerly
2011/11/10 22:50:39
noSuchMethod?
| |
| 2040 return new Value(null, '$name()/*NotFound*/'); | 2050 return new Value(null, '$name()/*NotFound*/', null); |
| 2041 } | 2051 } |
| 2042 | 2052 |
| 2043 _makeThisOrType() { | 2053 _makeThisOrType(SourceSpan span) { |
| 2044 var outermost = _getOutermostMethod(); | 2054 return new BareValue(this, _getOutermostMethod(), span); |
| 2045 if (outermost.method.isStatic) { | |
| 2046 return _makeTypeValue(outermost.method.declaringType); | |
| 2047 } else { | |
| 2048 return _makeThisValue(null); | |
| 2049 } | |
| 2050 } | |
| 2051 | |
| 2052 _makeTypeValue(Type type) { | |
| 2053 // TODO(jimhug): Named args! | |
| 2054 return new Value(type, type.jsname, false, false, true); | |
| 2055 } | 2055 } |
| 2056 | 2056 |
| 2057 visitThisExpression(ThisExpression node) { | 2057 visitThisExpression(ThisExpression node) { |
| 2058 return _makeThisValue(node); | 2058 return _makeThisValue(node); |
| 2059 } | 2059 } |
| 2060 | 2060 |
| 2061 visitSuperExpression(SuperExpression node) { | 2061 visitSuperExpression(SuperExpression node) { |
| 2062 return _makeSuperValue(node); | 2062 return _makeSuperValue(node); |
| 2063 } | 2063 } |
| 2064 | 2064 |
| (...skipping 12 matching lines...) Expand all Loading... | |
| 2077 var val = visitValue(item); | 2077 var val = visitValue(item); |
| 2078 val.invoke(this, 'toString', item, Arguments.EMPTY); | 2078 val.invoke(this, 'toString', item, Arguments.EMPTY); |
| 2079 | 2079 |
| 2080 // TODO(jimhug): Ensure this solves all precedence problems. | 2080 // TODO(jimhug): Ensure this solves all precedence problems. |
| 2081 var code = val.code; | 2081 var code = val.code; |
| 2082 if (item is BinaryExpression || item is ConditionalExpression) { | 2082 if (item is BinaryExpression || item is ConditionalExpression) { |
| 2083 code = '(${code})'; | 2083 code = '(${code})'; |
| 2084 } | 2084 } |
| 2085 items.add(code); | 2085 items.add(code); |
| 2086 } | 2086 } |
| 2087 return new Value(type, '(${Strings.join(items, " + ")})'); | 2087 return new Value(type, '(${Strings.join(items, " + ")})', node.span); |
| 2088 } | 2088 } |
| 2089 | 2089 |
| 2090 var text = node.text; | 2090 var text = node.text; |
| 2091 // TODO(jimhug): Confirm that only strings need possible translation | 2091 // TODO(jimhug): Confirm that only strings need possible translation |
| 2092 if (type.isString) { | 2092 if (type.isString) { |
| 2093 if (text.startsWith('@')) { | 2093 if (text.startsWith('@')) { |
| 2094 text = _escapeString(parseStringLiteral(text)); | 2094 text = _escapeString(parseStringLiteral(text)); |
| 2095 text = '"$text"'; | 2095 text = '"$text"'; |
| 2096 } else if (isMultilineString(text)) { | 2096 } else if (isMultilineString(text)) { |
| 2097 // convert multi-line strings into single-line | 2097 // convert multi-line strings into single-line |
| 2098 text = parseStringLiteral(text); | 2098 text = parseStringLiteral(text); |
| 2099 // TODO(jimhug): What about \r? | 2099 // TODO(jimhug): What about \r? |
| 2100 text = text.replaceAll('\n', '\\n'); | 2100 text = text.replaceAll('\n', '\\n'); |
| 2101 text = text.replaceAll('"', '\\"'); | 2101 text = text.replaceAll('"', '\\"'); |
| 2102 text = '"$text"'; | 2102 text = '"$text"'; |
| 2103 } | 2103 } |
| 2104 if (text !== node.text) { | 2104 if (text !== node.text) { |
| 2105 node.value = text; | 2105 node.value = text; |
| 2106 node.text = text; | 2106 node.text = text; |
| 2107 } | 2107 } |
| 2108 } | 2108 } |
| 2109 | 2109 |
| 2110 // TODO(jimhug): Should pass node.span - but that breaks something... | |
| 2110 return new EvaluatedValue(type, node.value, node.text, null); | 2111 return new EvaluatedValue(type, node.value, node.text, null); |
| 2111 } | 2112 } |
| 2112 } | 2113 } |
| 2113 | 2114 |
| 2114 | 2115 |
| 2115 // TODO(jmesserly): move this into its own file? | 2116 // TODO(jmesserly): move this into its own file? |
| 2116 class Arguments { | 2117 class Arguments { |
| 2117 static Arguments _empty; | 2118 static Arguments _empty; |
| 2118 static Arguments get EMPTY() { | 2119 static Arguments get EMPTY() { |
| 2119 if (_empty == null) { | 2120 if (_empty == null) { |
| 2120 _empty = new Arguments(null, []); | 2121 _empty = new Arguments(null, []); |
| 2121 } | 2122 } |
| 2122 return _empty; | 2123 return _empty; |
| 2123 } | 2124 } |
| 2124 | 2125 |
| 2125 List<Value> values; | 2126 List<Value> values; |
| 2126 List<ArgumentNode> nodes; | 2127 List<ArgumentNode> nodes; |
| 2127 int _bareCount; | 2128 int _bareCount; |
| 2128 | 2129 |
| 2129 Arguments(this.nodes, this.values); | 2130 Arguments(this.nodes, this.values); |
| 2130 | 2131 |
| 2131 /** Constructs a bare list of arguments. */ | 2132 /** Constructs a bare list of arguments. */ |
| 2132 factory Arguments.bare(int arity) { | 2133 factory Arguments.bare(int arity) { |
| 2133 var values = []; | 2134 var values = []; |
| 2134 for (int i = 0; i < arity; i++) { | 2135 for (int i = 0; i < arity; i++) { |
| 2135 values.add(new Value(world.varType, '\$$i', false, /*needsTemp:*/false)); | 2136 // TODO(jimhug): Need source locations. |
| 2137 values.add(new Value(world.varType, '\$$i', null, false, /*needsTemp:*/fal se)); | |
| 2136 } | 2138 } |
| 2137 return new Arguments(null, values); | 2139 return new Arguments(null, values); |
| 2138 } | 2140 } |
| 2139 | 2141 |
| 2140 int get nameCount() => length - bareCount; | 2142 int get nameCount() => length - bareCount; |
| 2141 bool get hasNames() => bareCount < length; | 2143 bool get hasNames() => bareCount < length; |
| 2142 | 2144 |
| 2143 int get length() => values.length; | 2145 int get length() => values.length; |
| 2144 | 2146 |
| 2145 String getName(int i) => nodes[i].label.name; | 2147 String getName(int i) => nodes[i].label.name; |
| (...skipping 67 matching lines...) Expand 10 before | Expand all | Expand 10 after Loading... | |
| 2213 for (int i = bareCount; i < length; i++) { | 2215 for (int i = bareCount; i < length; i++) { |
| 2214 names.add(getName(i)); | 2216 names.add(getName(i)); |
| 2215 } | 2217 } |
| 2216 return names; | 2218 return names; |
| 2217 } | 2219 } |
| 2218 | 2220 |
| 2219 /** Gets the argument names used in a call stub; uses $0 $1 for bare args. */ | 2221 /** Gets the argument names used in a call stub; uses $0 $1 for bare args. */ |
| 2220 Arguments toCallStubArgs() { | 2222 Arguments toCallStubArgs() { |
| 2221 var result = []; | 2223 var result = []; |
| 2222 for (int i = 0; i < bareCount; i++) { | 2224 for (int i = 0; i < bareCount; i++) { |
| 2223 result.add(new Value(world.varType, '\$$i', false, /*needsTemp:*/false)); | 2225 // TODO(jimhug): Need source locations. |
|
Jennifer Messerly
2011/11/10 22:50:39
synthetic stubs shouldn't need them? The idea is t
| |
| 2226 result.add(new Value(world.varType, '\$$i', null, false, /*needsTemp:*/fal se)); | |
| 2224 } | 2227 } |
| 2225 for (int i = bareCount; i < length; i++) { | 2228 for (int i = bareCount; i < length; i++) { |
| 2226 var name = getName(i); | 2229 var name = getName(i); |
| 2227 if (name == null) name = '\$$i'; | 2230 if (name == null) name = '\$$i'; |
| 2228 result.add(new Value(world.varType, name, false, /*needsTemp:*/false)); | 2231 // TODO(jimhug): Need source locations. |
| 2232 result.add(new Value(world.varType, name, null, false, /*needsTemp:*/false )); | |
| 2229 } | 2233 } |
| 2230 return new Arguments(nodes, result); | 2234 return new Arguments(nodes, result); |
| 2231 } | 2235 } |
| 2232 } | 2236 } |
| OLD | NEW |