Chromium Code Reviews
chromiumcodereview-hr@appspot.gserviceaccount.com (chromiumcodereview-hr) | Please choose your nickname with Settings | Help | Chromium Project | Gerrit Changes | Sign out
(4)

Side by Side Diff: frog/gen.dart

Issue 8523012: first stage of Value cleanups (Closed) Base URL: https://dart.googlecode.com/svn/branches/bleeding_edge/dart
Patch Set: rebased Created 9 years, 1 month ago
Use n/p to move between diff chunks; N/P to move between comments. Draft comments are only viewable by you.
Jump to:
View unified diff | Download patch | Annotate | Revision Log
« no previous file with comments | « frog/frogsh ('k') | frog/member.dart » ('j') | frog/member.dart » ('J')
Toggle Intra-line Diffs ('i') | Expand Comments ('e') | Collapse Comments ('c') | Show Comments Hide Comments ('s')
OLDNEW
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
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
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
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
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
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
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
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
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
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
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
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 }
OLDNEW
« no previous file with comments | « frog/frogsh ('k') | frog/member.dart » ('j') | frog/member.dart » ('J')

Powered by Google App Engine
This is Rietveld 408576698