| 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 476 matching lines...) Expand 10 before | Expand all | Expand 10 after Loading... |
| 487 if (y.span == null) return -1; | 487 if (y.span == null) return -1; |
| 488 | 488 |
| 489 // If that fails, compare by name. | 489 // If that fails, compare by name. |
| 490 return x.name.compareTo(y.name); | 490 return x.name.compareTo(y.name); |
| 491 } | 491 } |
| 492 | 492 |
| 493 /** Marks that a map literal is used, e.g. a call to $map. */ | 493 /** Marks that a map literal is used, e.g. a call to $map. */ |
| 494 Type useMapFactory() { | 494 Type useMapFactory() { |
| 495 corejs.useMap = true; | 495 corejs.useMap = true; |
| 496 var factType = world.coreimpl.types['HashMapImplementation']; | 496 var factType = world.coreimpl.types['HashMapImplementation']; |
| 497 var m = factType.resolveMember('\$setindex'); | 497 var m = factType.resolveMember(':setindex'); |
| 498 genMethod(m.members[0]); // TODO(jimhug): Clean up initializing. | 498 genMethod(m.members[0]); // TODO(jimhug): Clean up initializing. |
| 499 var c = factType.getConstructor(''); | 499 var c = factType.getConstructor(''); |
| 500 genMethod(c); | 500 genMethod(c); |
| 501 return factType; | 501 return factType; |
| 502 } | 502 } |
| 503 } | 503 } |
| 504 | 504 |
| 505 | 505 |
| 506 class BlockScope { | 506 class BlockScope { |
| 507 MethodGenerator enclosingMethod; | 507 MethodGenerator enclosingMethod; |
| (...skipping 77 matching lines...) Expand 10 before | Expand all | Expand 10 after Loading... |
| 585 if (isMethodScope && _closedOver.contains(name)) return true; | 585 if (isMethodScope && _closedOver.contains(name)) return true; |
| 586 | 586 |
| 587 for (var s = parent; s != null; s = s.parent) { | 587 for (var s = parent; s != null; s = s.parent) { |
| 588 if (s._vars.containsKey(name)) return true; | 588 if (s._vars.containsKey(name)) return true; |
| 589 if (s._jsNames.contains(name)) return true; | 589 if (s._jsNames.contains(name)) return true; |
| 590 // Don't reuse a name that's been closed over | 590 // Don't reuse a name that's been closed over |
| 591 if (s.isMethodScope && s._closedOver.contains(name)) return true; | 591 if (s.isMethodScope && s._closedOver.contains(name)) return true; |
| 592 } | 592 } |
| 593 | 593 |
| 594 // Ensure that we don't shadow another name that would've been accessible, | 594 // Ensure that we don't shadow another name that would've been accessible, |
| 595 // like to level names. | 595 // like top level names. |
| 596 // (This lookup might report errors, which is a bit strange. | 596 // (This lookup might report errors, which is a bit strange. |
| 597 // But probably harmless since we have to pay for the lookup anyway.) | 597 // But probably harmless since we have to pay for the lookup anyway.) |
| 598 // TODO(jmesserly): does this work right if JS name of the top-level thing |
| 599 // is different from Dart name? |
| 598 final type = enclosingMethod.method.declaringType; | 600 final type = enclosingMethod.method.declaringType; |
| 599 if (type.library.lookup(name, null) != null) return true; | 601 if (type.library.lookup(name, null) != null) return true; |
| 600 | 602 |
| 601 // Nobody else needs this name. It's safe to reuse. | 603 // Nobody else needs this name. It's safe to reuse. |
| 602 return false; | 604 return false; |
| 603 } | 605 } |
| 604 | 606 |
| 605 | 607 |
| 606 Value create(String name, Type type, SourceSpan span, | 608 Value create(String name, Type type, SourceSpan span, |
| 607 [bool isFinal = false, bool isParameter = false]) { | 609 [bool isFinal = false, bool isParameter = false]) { |
| (...skipping 797 matching lines...) Expand 10 before | Expand all | Expand 10 after Loading... |
| 1405 if (list.needsTemp) { | 1407 if (list.needsTemp) { |
| 1406 listVar = _scope.create('\$list', list.type, null); | 1408 listVar = _scope.create('\$list', list.type, null); |
| 1407 writer.writeln('var ${listVar.code} = ${list.code};'); | 1409 writer.writeln('var ${listVar.code} = ${list.code};'); |
| 1408 } | 1410 } |
| 1409 | 1411 |
| 1410 // Special path for list for readability and perf optimization. | 1412 // Special path for list for readability and perf optimization. |
| 1411 if (list.type.isList) { | 1413 if (list.type.isList) { |
| 1412 var tmpi = _scope.create('\$i', world.numType, null); | 1414 var tmpi = _scope.create('\$i', world.numType, null); |
| 1413 writer.enterBlock('for (var ${tmpi.code} = 0;' + | 1415 writer.enterBlock('for (var ${tmpi.code} = 0;' + |
| 1414 '${tmpi.code} < ${listVar.code}.length; ${tmpi.code}++) {'); | 1416 '${tmpi.code} < ${listVar.code}.length; ${tmpi.code}++) {'); |
| 1415 var value = listVar.invoke(this, '\$index', node.list, | 1417 var value = listVar.invoke(this, ':index', node.list, |
| 1416 new Arguments(null, [tmpi])); | 1418 new Arguments(null, [tmpi])); |
| 1417 writer.writeln('var ${item.code} = ${value.code};'); | 1419 writer.writeln('var ${item.code} = ${value.code};'); |
| 1418 } else { | 1420 } else { |
| 1419 _pushBlock(); | 1421 _pushBlock(); |
| 1420 var iterator = list.invoke(this, 'iterator', node.list, Arguments.EMPTY); | 1422 var iterator = list.invoke(this, 'iterator', node.list, Arguments.EMPTY); |
| 1421 var tmpi = _scope.create('\$i', iterator.type, null); | 1423 var tmpi = _scope.create('\$i', iterator.type, null); |
| 1422 | 1424 |
| 1423 var hasNext = tmpi.invoke(this, 'hasNext', node.list, Arguments.EMPTY); | 1425 var hasNext = tmpi.invoke(this, 'hasNext', node.list, Arguments.EMPTY); |
| 1424 var next = tmpi.invoke(this, 'next', node.list, Arguments.EMPTY); | 1426 var next = tmpi.invoke(this, 'next', node.list, Arguments.EMPTY); |
| 1425 | 1427 |
| (...skipping 275 matching lines...) Expand 10 before | Expand all | Expand 10 after Loading... |
| 1701 | 1703 |
| 1702 var w = new CodeWriter(); | 1704 var w = new CodeWriter(); |
| 1703 meth.generator.writeDefinition(w, node); | 1705 meth.generator.writeDefinition(w, node); |
| 1704 | 1706 |
| 1705 return new Value(meth.functionType, w.text, node.span); | 1707 return new Value(meth.functionType, w.text, node.span); |
| 1706 } | 1708 } |
| 1707 | 1709 |
| 1708 visitCallExpression(CallExpression node) { | 1710 visitCallExpression(CallExpression node) { |
| 1709 var target; | 1711 var target; |
| 1710 var position = node.target; | 1712 var position = node.target; |
| 1711 var name = '\$call'; | 1713 var name = ':call'; |
| 1712 if (node.target is DotExpression) { | 1714 if (node.target is DotExpression) { |
| 1713 DotExpression dot = node.target; | 1715 DotExpression dot = node.target; |
| 1714 target = dot.self.visit(this); | 1716 target = dot.self.visit(this); |
| 1715 name = dot.name.name; | 1717 name = dot.name.name; |
| 1716 position = dot.name; | 1718 position = dot.name; |
| 1717 } else if (node.target is VarExpression) { | 1719 } else if (node.target is VarExpression) { |
| 1718 VarExpression varExpr = node.target; | 1720 VarExpression varExpr = node.target; |
| 1719 name = varExpr.name.name; | 1721 name = varExpr.name.name; |
| 1720 // First check in block scopes. | 1722 // First check in block scopes. |
| 1721 target = _scope.lookup(name); | 1723 target = _scope.lookup(name); |
| 1722 if (target != null) { | 1724 if (target != null) { |
| 1723 return target.invoke(this, '\$call', node, _makeArgs(node.arguments)); | 1725 return target.invoke(this, ':call', node, _makeArgs(node.arguments)); |
| 1724 } | 1726 } |
| 1725 | 1727 |
| 1726 target = _makeThisOrType(varExpr.span); | 1728 target = _makeThisOrType(varExpr.span); |
| 1727 return target.invoke(this, name, node, _makeArgs(node.arguments)); | 1729 return target.invoke(this, name, node, _makeArgs(node.arguments)); |
| 1728 } else { | 1730 } else { |
| 1729 target = node.target.visit(this); | 1731 target = node.target.visit(this); |
| 1730 } | 1732 } |
| 1731 | 1733 |
| 1732 return target.invoke(this, name, position, _makeArgs(node.arguments)); | 1734 return target.invoke(this, name, position, _makeArgs(node.arguments)); |
| 1733 } | 1735 } |
| 1734 | 1736 |
| 1735 visitIndexExpression(IndexExpression node) { | 1737 visitIndexExpression(IndexExpression node) { |
| 1736 var target = visitValue(node.target); | 1738 var target = visitValue(node.target); |
| 1737 var index = visitValue(node.index); | 1739 var index = visitValue(node.index); |
| 1738 return target.invoke(this, '\$index', node, new Arguments(null, [index])); | 1740 return target.invoke(this, ':index', node, new Arguments(null, [index])); |
| 1739 } | 1741 } |
| 1740 | 1742 |
| 1741 visitBinaryExpression(BinaryExpression node) { | 1743 visitBinaryExpression(BinaryExpression node) { |
| 1742 final kind = node.op.kind; | 1744 final kind = node.op.kind; |
| 1743 // TODO(jimhug): Ensure these have same semantics as JS! | 1745 // TODO(jimhug): Ensure these have same semantics as JS! |
| 1744 if (kind == TokenKind.AND || kind == TokenKind.OR) { | 1746 if (kind == TokenKind.AND || kind == TokenKind.OR) { |
| 1745 var x = visitTypedValue(node.x, world.nonNullBool); | 1747 var x = visitTypedValue(node.x, world.nonNullBool); |
| 1746 var y = visitTypedValue(node.y, world.nonNullBool); | 1748 var y = visitTypedValue(node.y, world.nonNullBool); |
| 1747 final code = '${x.code} ${node.op} ${y.code}'; | 1749 final code = '${x.code} ${node.op} ${y.code}'; |
| 1748 if (x.isConst && y.isConst) { | 1750 if (x.isConst && y.isConst) { |
| (...skipping 41 matching lines...) Expand 10 before | Expand all | Expand 10 after Loading... |
| 1790 node.span); | 1792 node.span); |
| 1791 } | 1793 } |
| 1792 } | 1794 } |
| 1793 | 1795 |
| 1794 final assignKind = TokenKind.kindFromAssign(node.op.kind); | 1796 final assignKind = TokenKind.kindFromAssign(node.op.kind); |
| 1795 if (assignKind == -1) { | 1797 if (assignKind == -1) { |
| 1796 final x = visitValue(node.x); | 1798 final x = visitValue(node.x); |
| 1797 final y = visitValue(node.y); | 1799 final y = visitValue(node.y); |
| 1798 var name = TokenKind.binaryMethodName(node.op.kind); | 1800 var name = TokenKind.binaryMethodName(node.op.kind); |
| 1799 if (node.op.kind == TokenKind.NE) { | 1801 if (node.op.kind == TokenKind.NE) { |
| 1800 name = '\$ne'; | 1802 name = ':ne'; |
| 1801 } | 1803 } |
| 1802 if (name == null) { | 1804 if (name == null) { |
| 1803 world.internalError('unimplemented binary op ${node.op}', node.span); | 1805 world.internalError('unimplemented binary op ${node.op}', node.span); |
| 1804 return; | 1806 return; |
| 1805 } | 1807 } |
| 1806 return x.invoke(this, name, node, new Arguments(null, [y])); | 1808 return x.invoke(this, name, node, new Arguments(null, [y])); |
| 1807 } else { | 1809 } else { |
| 1808 return _visitAssign(assignKind, node.x, node.y, node, null); | 1810 return _visitAssign(assignKind, node.x, node.y, node, null); |
| 1809 } | 1811 } |
| 1810 } | 1812 } |
| (...skipping 107 matching lines...) Expand 10 before | Expand all | Expand 10 after Loading... |
| 1918 var target = visitValue(xn.target); | 1920 var target = visitValue(xn.target); |
| 1919 var index = visitValue(xn.index); | 1921 var index = visitValue(xn.index); |
| 1920 var y = visitValue(yn); | 1922 var y = visitValue(yn); |
| 1921 | 1923 |
| 1922 var tmptarget = target; | 1924 var tmptarget = target; |
| 1923 var tmpindex = index; | 1925 var tmpindex = index; |
| 1924 if (kind != 0) { | 1926 if (kind != 0) { |
| 1925 tmptarget = getTemp(target); | 1927 tmptarget = getTemp(target); |
| 1926 tmpindex = getTemp(index); | 1928 tmpindex = getTemp(index); |
| 1927 index = assignTemp(tmpindex, index); | 1929 index = assignTemp(tmpindex, index); |
| 1928 var right = tmptarget.invoke(this, '\$index', | 1930 var right = tmptarget.invoke(this, ':index', |
| 1929 position, new Arguments(null, [tmpindex])); | 1931 position, new Arguments(null, [tmpindex])); |
| 1930 right = captureOriginal(right); | 1932 right = captureOriginal(right); |
| 1931 y = right.invoke(this, TokenKind.binaryMethodName(kind), | 1933 y = right.invoke(this, TokenKind.binaryMethodName(kind), |
| 1932 position, new Arguments(null, [y])); | 1934 position, new Arguments(null, [y])); |
| 1933 } | 1935 } |
| 1934 var ret = assignTemp(tmptarget, target).invoke(this, '\$setindex', | 1936 var ret = assignTemp(tmptarget, target).invoke(this, ':setindex', |
| 1935 position, new Arguments(null, [index, y])); | 1937 position, new Arguments(null, [index, y])); |
| 1936 if (tmptarget != target) freeTemp(tmptarget); | 1938 if (tmptarget != target) freeTemp(tmptarget); |
| 1937 if (tmpindex != index) freeTemp(tmpindex); | 1939 if (tmpindex != index) freeTemp(tmpindex); |
| 1938 return ret; | 1940 return ret; |
| 1939 } | 1941 } |
| 1940 | 1942 |
| 1941 _visitDotAssign(int kind, DotExpression xn, Expression yn, Node position, | 1943 _visitDotAssign(int kind, DotExpression xn, Expression yn, Node position, |
| 1942 Value captureOriginal(Value right)) { | 1944 Value captureOriginal(Value right)) { |
| 1943 | 1945 |
| 1944 // This is not visitValue because types are assignable through . | 1946 // This is not visitValue because types are assignable through . |
| (...skipping 42 matching lines...) Expand 10 before | Expand all | Expand 10 after Loading... |
| 1987 return new Value(newVal.type, '!${newVal.code}', node.span); | 1989 return new Value(newVal.type, '!${newVal.code}', node.span); |
| 1988 } | 1990 } |
| 1989 | 1991 |
| 1990 case TokenKind.ADD: | 1992 case TokenKind.ADD: |
| 1991 // TODO(jimhug): Issue #359 seeks to clarify this behavior. | 1993 // TODO(jimhug): Issue #359 seeks to clarify this behavior. |
| 1992 return value.convertTo(this, world.numType, node); | 1994 return value.convertTo(this, world.numType, node); |
| 1993 | 1995 |
| 1994 case TokenKind.SUB: | 1996 case TokenKind.SUB: |
| 1995 case TokenKind.BIT_NOT: | 1997 case TokenKind.BIT_NOT: |
| 1996 if (node.op.kind == TokenKind.BIT_NOT) { | 1998 if (node.op.kind == TokenKind.BIT_NOT) { |
| 1997 return value.invoke(this, '\$bit_not', node, Arguments.EMPTY); | 1999 return value.invoke(this, ':bit_not', node, Arguments.EMPTY); |
| 1998 } else if (node.op.kind == TokenKind.SUB) { | 2000 } else if (node.op.kind == TokenKind.SUB) { |
| 1999 return value.invoke(this, '\$negate', node, Arguments.EMPTY); | 2001 return value.invoke(this, ':negate', node, Arguments.EMPTY); |
| 2000 } else { | 2002 } else { |
| 2001 world.internalError('unimplemented: unary ${node.op}', | 2003 world.internalError('unimplemented: unary ${node.op}', |
| 2002 node.span); | 2004 node.span); |
| 2003 } | 2005 } |
| 2004 default: | 2006 default: |
| 2005 world.internalError('unimplemented: ${node.op}', node.span); | 2007 world.internalError('unimplemented: ${node.op}', node.span); |
| 2006 } | 2008 } |
| 2007 } | 2009 } |
| 2008 | 2010 |
| 2009 visitAwaitExpression(AwaitExpression node) { | 2011 visitAwaitExpression(AwaitExpression node) { |
| (...skipping 419 matching lines...) Expand 10 before | Expand all | Expand 10 after Loading... |
| 2429 result.add(new Value(world.varType, '\$$i', null, /*needsTemp:*/false)); | 2431 result.add(new Value(world.varType, '\$$i', null, /*needsTemp:*/false)); |
| 2430 } | 2432 } |
| 2431 for (int i = bareCount; i < length; i++) { | 2433 for (int i = bareCount; i < length; i++) { |
| 2432 var name = getName(i); | 2434 var name = getName(i); |
| 2433 if (name == null) name = '\$$i'; | 2435 if (name == null) name = '\$$i'; |
| 2434 result.add(new Value(world.varType, name, null, /*needsTemp:*/false)); | 2436 result.add(new Value(world.varType, name, null, /*needsTemp:*/false)); |
| 2435 } | 2437 } |
| 2436 return new Arguments(nodes, result); | 2438 return new Arguments(nodes, result); |
| 2437 } | 2439 } |
| 2438 } | 2440 } |
| OLD | NEW |