OLD | NEW |
1 // Copyright (c) 2015, the Dart project authors. Please see the AUTHORS file | 1 // Copyright (c) 2015, 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 library rewrite_async; | 5 library rewrite_async; |
6 | 6 |
7 import 'dart:collection'; | 7 import 'dart:collection'; |
8 import 'dart:math' show max; | 8 import 'dart:math' show max; |
9 | 9 |
10 import 'package:js_runtime/shared/async_await_error_codes.dart' as error_codes; | 10 import 'package:js_runtime/shared/async_await_error_codes.dart' as error_codes; |
(...skipping 1634 matching lines...) Expand 10 before | Expand all | Expand 10 after Loading... |
1645 | 1645 |
1646 class AsyncRewriter extends AsyncRewriterBase { | 1646 class AsyncRewriter extends AsyncRewriterBase { |
1647 bool get isAsync => true; | 1647 bool get isAsync => true; |
1648 | 1648 |
1649 /// The Completer that will finish an async function. | 1649 /// The Completer that will finish an async function. |
1650 /// | 1650 /// |
1651 /// Not used for sync* or async* functions. | 1651 /// Not used for sync* or async* functions. |
1652 String completerName; | 1652 String completerName; |
1653 js.VariableUse get completer => new js.VariableUse(completerName); | 1653 js.VariableUse get completer => new js.VariableUse(completerName); |
1654 | 1654 |
1655 /// The function called by an async function to simulate an await or return. | 1655 /// The function called by an async function to initiate asynchronous |
| 1656 /// execution of the body. This is called with: |
1656 /// | 1657 /// |
1657 /// For an await it is called with: | 1658 /// - The body function [bodyName]. |
| 1659 /// - the completer object [completer]. |
| 1660 /// |
| 1661 /// It returns the completer's future. Passing the completer and returning its |
| 1662 /// future is a convenience to allow both the initiation and fetching the |
| 1663 /// future to be compactly encoded in a return statement's expression. |
| 1664 final js.Expression asyncStart; |
| 1665 |
| 1666 /// Function called by the async function to simulate an `await` |
| 1667 /// expression. It is called with: |
1658 /// | 1668 /// |
1659 /// - The value to await | 1669 /// - The value to await |
1660 /// - The body function [bodyName] | 1670 /// - The body function [bodyName] |
| 1671 final js.Expression asyncAwait; |
| 1672 |
| 1673 /// Function called by the async function to simulate a return. |
| 1674 /// It is called with: |
| 1675 /// |
| 1676 /// - The value to return |
1661 /// - The completer object [completer] | 1677 /// - The completer object [completer] |
| 1678 final js.Expression asyncReturn; |
| 1679 |
| 1680 /// Function called by the async function to simulate a rethrow. |
| 1681 /// It is called with: |
1662 /// | 1682 /// |
1663 /// For a return it is called with: | 1683 /// - The value containing the exception and stack |
1664 /// | |
1665 /// - The value to complete the completer with. | |
1666 /// - [error_codes.SUCCESS] | |
1667 /// - The completer object [completer] | 1684 /// - The completer object [completer] |
1668 /// | 1685 final js.Expression asyncRethrow; |
1669 /// For a throw it is called with: | |
1670 /// | |
1671 /// - The error to complete the completer with. | |
1672 /// - [error_codes.ERROR] | |
1673 /// - The completer object [completer] | |
1674 final js.Expression asyncHelper; | |
1675 | 1686 |
1676 /// Constructor used to initialize the [completer] variable. | 1687 /// Constructor used to initialize the [completer] variable. |
1677 /// | 1688 /// |
1678 /// Specific to async methods. | 1689 /// Specific to async methods. |
1679 final js.Expression completerFactory; | 1690 final js.Expression completerFactory; |
1680 | 1691 |
1681 final js.Expression wrapBody; | 1692 final js.Expression wrapBody; |
1682 | 1693 |
1683 AsyncRewriter(DiagnosticReporter reporter, Spannable spannable, | 1694 AsyncRewriter(DiagnosticReporter reporter, Spannable spannable, |
1684 {this.asyncHelper, | 1695 {this.asyncStart, |
| 1696 this.asyncAwait, |
| 1697 this.asyncReturn, |
| 1698 this.asyncRethrow, |
1685 this.completerFactory, | 1699 this.completerFactory, |
1686 this.wrapBody, | 1700 this.wrapBody, |
1687 String safeVariableName(String proposedName), | 1701 String safeVariableName(String proposedName), |
1688 js.Name bodyName}) | 1702 js.Name bodyName}) |
1689 : super(reporter, spannable, safeVariableName, bodyName); | 1703 : super(reporter, spannable, safeVariableName, bodyName); |
1690 | 1704 |
1691 @override | 1705 @override |
1692 void addYield(js.DartYield node, js.Expression expression) { | 1706 void addYield(js.DartYield node, js.Expression expression) { |
1693 reporter.internalError(spannable, "Yield in non-generating async function"); | 1707 reporter.internalError(spannable, "Yield in non-generating async function"); |
1694 } | 1708 } |
1695 | 1709 |
1696 void addErrorExit() { | 1710 void addErrorExit() { |
1697 beginLabel(rethrowLabel); | 1711 beginLabel(rethrowLabel); |
1698 addStatement(js.js.statement( | 1712 addStatement(js.js.statement( |
1699 "return #thenHelper(#currentError, #errorCode, #completer);", { | 1713 "return #thenHelper(#currentError, #completer);", { |
1700 "thenHelper": asyncHelper, | 1714 "thenHelper": asyncRethrow, |
1701 "errorCode": js.number(error_codes.ERROR), | |
1702 "currentError": currentError, | 1715 "currentError": currentError, |
1703 "completer": completer | 1716 "completer": completer |
1704 })); | 1717 })); |
1705 } | 1718 } |
1706 | 1719 |
1707 /// Returning from an async method calls [asyncStarHelper] with the result. | 1720 /// Returning from an async method calls [asyncStarHelper] with the result. |
1708 /// (the result might have been stored in [returnValue] by some finally | 1721 /// (the result might have been stored in [returnValue] by some finally |
1709 /// block). | 1722 /// block). |
1710 void addSuccesExit() { | 1723 void addSuccesExit() { |
1711 if (analysis.hasExplicitReturns) { | 1724 if (analysis.hasExplicitReturns) { |
1712 beginLabel(exitLabel); | 1725 beginLabel(exitLabel); |
1713 } else { | 1726 } else { |
1714 addStatement(new js.Comment("implicit return")); | 1727 addStatement(new js.Comment("implicit return")); |
1715 } | 1728 } |
1716 addStatement(js.js.statement( | 1729 addStatement( |
1717 "return #runtimeHelper(#returnValue, #successCode, #completer);", { | 1730 js.js.statement("return #runtimeHelper(#returnValue, #completer);", { |
1718 "runtimeHelper": asyncHelper, | 1731 "runtimeHelper": asyncReturn, |
1719 "successCode": js.number(error_codes.SUCCESS), | |
1720 "returnValue": | 1732 "returnValue": |
1721 analysis.hasExplicitReturns ? returnValue : new js.LiteralNull(), | 1733 analysis.hasExplicitReturns ? returnValue : new js.LiteralNull(), |
1722 "completer": completer | 1734 "completer": completer |
1723 })); | 1735 })); |
1724 } | 1736 } |
1725 | 1737 |
1726 @override | 1738 @override |
1727 Iterable<js.VariableInitialization> variableInitializations() { | 1739 Iterable<js.VariableInitialization> variableInitializations() { |
1728 List<js.VariableInitialization> variables = <js.VariableInitialization>[]; | 1740 List<js.VariableInitialization> variables = <js.VariableInitialization>[]; |
1729 variables.add( | 1741 variables.add( |
1730 _makeVariableInitializer(completer, new js.Call(completerFactory, []))); | 1742 _makeVariableInitializer(completer, new js.Call(completerFactory, []))); |
1731 if (analysis.hasExplicitReturns) { | 1743 if (analysis.hasExplicitReturns) { |
1732 variables.add(_makeVariableInitializer(returnValue, null)); | 1744 variables.add(_makeVariableInitializer(returnValue, null)); |
1733 } | 1745 } |
1734 return variables; | 1746 return variables; |
1735 } | 1747 } |
1736 | 1748 |
1737 @override | 1749 @override |
1738 void initializeNames() { | 1750 void initializeNames() { |
1739 completerName = freshName("completer"); | 1751 completerName = freshName("completer"); |
1740 } | 1752 } |
1741 | 1753 |
1742 @override | 1754 @override |
1743 js.Statement awaitStatement(js.Expression value) { | 1755 js.Statement awaitStatement(js.Expression value) { |
1744 return js.js.statement( | 1756 return js.js.statement( |
1745 """ | 1757 """ |
1746 return #asyncHelper(#value, | 1758 return #asyncHelper(#value, |
1747 #bodyName, | 1759 #bodyName); |
1748 #completer); | |
1749 """, | 1760 """, |
1750 { | 1761 { |
1751 "asyncHelper": asyncHelper, | 1762 "asyncHelper": asyncAwait, |
1752 "value": value, | 1763 "value": value, |
1753 "bodyName": bodyName, | 1764 "bodyName": bodyName, |
1754 "completer": completer | |
1755 }); | 1765 }); |
1756 } | 1766 } |
1757 | 1767 |
1758 @override | 1768 @override |
1759 js.Fun finishFunction( | 1769 js.Fun finishFunction( |
1760 List<js.Parameter> parameters, | 1770 List<js.Parameter> parameters, |
1761 js.Statement rewrittenBody, | 1771 js.Statement rewrittenBody, |
1762 js.VariableDeclarationList variableDeclarations, | 1772 js.VariableDeclarationList variableDeclarations, |
1763 SourceInformation sourceInformation) { | 1773 SourceInformation sourceInformation) { |
1764 return js.js( | 1774 return js.js( |
1765 """ | 1775 """ |
1766 function (#parameters) { | 1776 function (#parameters) { |
1767 #variableDeclarations; | 1777 #variableDeclarations; |
1768 var #bodyName = #wrapBody(function (#errorCode, #result) { | 1778 var #bodyName = #wrapBody(function (#errorCode, #result) { |
1769 if (#errorCode === #ERROR) { | 1779 if (#errorCode === #ERROR) { |
1770 #currentError = #result; | 1780 #currentError = #result; |
1771 #goto = #handler; | 1781 #goto = #handler; |
1772 } | 1782 } |
1773 #rewrittenBody; | 1783 #rewrittenBody; |
1774 }); | 1784 }); |
1775 return #asyncHelper(null, #bodyName, #completer); | 1785 return #asyncStart(#bodyName, #completer); |
1776 }""", | 1786 }""", |
1777 { | 1787 { |
1778 "parameters": parameters, | 1788 "parameters": parameters, |
1779 "variableDeclarations": variableDeclarations, | 1789 "variableDeclarations": variableDeclarations, |
1780 "ERROR": js.number(error_codes.ERROR), | 1790 "ERROR": js.number(error_codes.ERROR), |
1781 "rewrittenBody": rewrittenBody, | 1791 "rewrittenBody": rewrittenBody, |
1782 "bodyName": bodyName, | 1792 "bodyName": bodyName, |
1783 "currentError": currentError, | 1793 "currentError": currentError, |
1784 "goto": goto, | 1794 "goto": goto, |
1785 "handler": handler, | 1795 "handler": handler, |
1786 "errorCode": errorCodeName, | 1796 "errorCode": errorCodeName, |
1787 "result": resultName, | 1797 "result": resultName, |
1788 "asyncHelper": asyncHelper, | 1798 "asyncStart": asyncStart, |
1789 "completer": completer, | 1799 "completer": completer, |
1790 "wrapBody": wrapBody, | 1800 "wrapBody": wrapBody, |
1791 }).withSourceInformation(sourceInformation); | 1801 }).withSourceInformation(sourceInformation); |
1792 } | 1802 } |
1793 } | 1803 } |
1794 | 1804 |
1795 class SyncStarRewriter extends AsyncRewriterBase { | 1805 class SyncStarRewriter extends AsyncRewriterBase { |
1796 bool get isSyncStar => true; | 1806 bool get isSyncStar => true; |
1797 | 1807 |
1798 /// Constructor creating the Iterable for a sync* method. Called with | 1808 /// Constructor creating the Iterable for a sync* method. Called with |
(...skipping 786 matching lines...) Expand 10 before | Expand all | Expand 10 after Loading... |
2585 return condition || body; | 2595 return condition || body; |
2586 } | 2596 } |
2587 | 2597 |
2588 @override | 2598 @override |
2589 bool visitDartYield(js.DartYield node) { | 2599 bool visitDartYield(js.DartYield node) { |
2590 hasYield = true; | 2600 hasYield = true; |
2591 visit(node.expression); | 2601 visit(node.expression); |
2592 return true; | 2602 return true; |
2593 } | 2603 } |
2594 } | 2604 } |
OLD | NEW |