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 109 matching lines...) Expand 10 before | Expand all | Expand 10 after Loading... | |
120 /// | 120 /// |
121 /// To "goto" a label, the label is assigned to this variable, and break out | 121 /// To "goto" a label, the label is assigned to this variable, and break out |
122 /// of the switch to take another iteration in the while loop. See [addGoto] | 122 /// of the switch to take another iteration in the while loop. See [addGoto] |
123 js.VariableUse get goto => new js.VariableUse(gotoName); | 123 js.VariableUse get goto => new js.VariableUse(gotoName); |
124 String gotoName; | 124 String gotoName; |
125 | 125 |
126 /// Variable containing the label of the current error handler. | 126 /// Variable containing the label of the current error handler. |
127 js.VariableUse get handler => new js.VariableUse(handlerName); | 127 js.VariableUse get handler => new js.VariableUse(handlerName); |
128 String handlerName; | 128 String handlerName; |
129 | 129 |
130 /// Set to `true` if any of the switch statement labels is a handler. | |
131 bool hasHandlerLabels = false; | |
132 | |
130 /// A stack of labels of finally blocks to visit, and the label to go to after | 133 /// A stack of labels of finally blocks to visit, and the label to go to after |
131 /// the last. | 134 /// the last. |
132 js.VariableUse get next => new js.VariableUse(nextName); | 135 js.VariableUse get next => new js.VariableUse(nextName); |
133 String nextName; | 136 String nextName; |
134 | 137 |
135 /// The current returned value (a finally block may overwrite it). | 138 /// The current returned value (a finally block may overwrite it). |
136 js.VariableUse get returnValue => new js.VariableUse(returnValueName); | 139 js.VariableUse get returnValue => new js.VariableUse(returnValueName); |
137 String returnValueName; | 140 String returnValueName; |
138 | 141 |
139 /// Stores the current error when we are in the process of handling an error. | 142 /// Stores the current error when we are in the process of handling an error. |
(...skipping 538 matching lines...) Expand 10 before | Expand all | Expand 10 after Loading... | |
678 }).toList(); | 681 }).toList(); |
679 js.Statement rewrittenBody = new js.Switch(goto, clauses); | 682 js.Statement rewrittenBody = new js.Switch(goto, clauses); |
680 if (hasJumpThoughOuterLabel) { | 683 if (hasJumpThoughOuterLabel) { |
681 rewrittenBody = new js.LabeledStatement(outerLabelName, rewrittenBody); | 684 rewrittenBody = new js.LabeledStatement(outerLabelName, rewrittenBody); |
682 } | 685 } |
683 rewrittenBody = js.js.statement('while (true) {#}', rewrittenBody); | 686 rewrittenBody = js.js.statement('while (true) {#}', rewrittenBody); |
684 List<js.VariableInitialization> variables = <js.VariableInitialization>[]; | 687 List<js.VariableInitialization> variables = <js.VariableInitialization>[]; |
685 | 688 |
686 variables.add(_makeVariableInitializer(goto, js.number(0))); | 689 variables.add(_makeVariableInitializer(goto, js.number(0))); |
687 variables.addAll(variableInitializations()); | 690 variables.addAll(variableInitializations()); |
688 variables.add(_makeVariableInitializer(handler, js.number(rethrowLabel))); | 691 if (hasHandlerLabels) { |
689 variables.add(_makeVariableInitializer(currentError, null)); | 692 variables.add(_makeVariableInitializer(handler, js.number(rethrowLabel))); |
693 variables.add(_makeVariableInitializer(currentError, null)); | |
694 } | |
690 if (analysis.hasFinally || (isAsyncStar && analysis.hasYield)) { | 695 if (analysis.hasFinally || (isAsyncStar && analysis.hasYield)) { |
691 variables.add(_makeVariableInitializer( | 696 variables.add(_makeVariableInitializer( |
692 next, new js.ArrayInitializer(<js.Expression>[]))); | 697 next, new js.ArrayInitializer(<js.Expression>[]))); |
693 } | 698 } |
694 if (analysis.hasThis && !isSyncStar) { | 699 if (analysis.hasThis && !isSyncStar) { |
695 // Sync* functions must remember `this` on the level of the outer | 700 // Sync* functions must remember `this` on the level of the outer |
696 // function. | 701 // function. |
697 variables.add(_makeVariableInitializer(self, js.js('this'))); | 702 variables.add(_makeVariableInitializer(self, js.js('this'))); |
698 } | 703 } |
699 variables.addAll(localVariables.map((js.VariableDeclaration declaration) { | 704 variables.addAll(localVariables.map((js.VariableDeclaration declaration) { |
(...skipping 705 matching lines...) Expand 10 before | Expand all | Expand 10 after Loading... | |
1405 | 1410 |
1406 @override | 1411 @override |
1407 void visitThrow(js.Throw node) { | 1412 void visitThrow(js.Throw node) { |
1408 withExpression(node.expression, (js.Expression expression) { | 1413 withExpression(node.expression, (js.Expression expression) { |
1409 addStatement(new js.Throw(expression) | 1414 addStatement(new js.Throw(expression) |
1410 .withSourceInformation(node.sourceInformation)); | 1415 .withSourceInformation(node.sourceInformation)); |
1411 }, store: false); | 1416 }, store: false); |
1412 } | 1417 } |
1413 | 1418 |
1414 setErrorHandler([int errorHandler]) { | 1419 setErrorHandler([int errorHandler]) { |
1420 hasHandlerLabels = true; | |
1415 js.Expression label = | 1421 js.Expression label = |
1416 (errorHandler == null) ? currentErrorHandler : js.number(errorHandler); | 1422 (errorHandler == null) ? currentErrorHandler : js.number(errorHandler); |
1417 addStatement(js.js.statement('# = #;', [handler, label])); | 1423 addStatement(js.js.statement('# = #;', [handler, label])); |
1418 } | 1424 } |
1419 | 1425 |
1420 List<int> _finalliesUpToAndEnclosingHandler() { | 1426 List<int> _finalliesUpToAndEnclosingHandler() { |
1421 List<int> result = <int>[]; | 1427 List<int> result = <int>[]; |
1422 for (int i = jumpTargets.length - 1; i >= 0; i--) { | 1428 for (int i = jumpTargets.length - 1; i >= 0; i--) { |
1423 js.Node node = jumpTargets[i]; | 1429 js.Node node = jumpTargets[i]; |
1424 int handlerLabel = handlerLabels[node]; | 1430 int handlerLabel = handlerLabels[node]; |
(...skipping 276 matching lines...) Expand 10 before | Expand all | Expand 10 after Loading... | |
1701 String safeVariableName(String proposedName), | 1707 String safeVariableName(String proposedName), |
1702 js.Name bodyName}) | 1708 js.Name bodyName}) |
1703 : super(reporter, spannable, safeVariableName, bodyName); | 1709 : super(reporter, spannable, safeVariableName, bodyName); |
1704 | 1710 |
1705 @override | 1711 @override |
1706 void addYield(js.DartYield node, js.Expression expression) { | 1712 void addYield(js.DartYield node, js.Expression expression) { |
1707 reporter.internalError(spannable, "Yield in non-generating async function"); | 1713 reporter.internalError(spannable, "Yield in non-generating async function"); |
1708 } | 1714 } |
1709 | 1715 |
1710 void addErrorExit() { | 1716 void addErrorExit() { |
1717 if (!hasHandlerLabels) return; | |
1711 beginLabel(rethrowLabel); | 1718 beginLabel(rethrowLabel); |
1712 addStatement(js.js.statement( | 1719 addStatement(js.js.statement( |
1713 "return #thenHelper(#currentError, #completer);", { | 1720 "return #thenHelper(#currentError, #completer);", { |
1714 "thenHelper": asyncRethrow, | 1721 "thenHelper": asyncRethrow, |
1715 "currentError": currentError, | 1722 "currentError": currentError, |
1716 "completer": completer | 1723 "completer": completer |
1717 })); | 1724 })); |
1718 } | 1725 } |
1719 | 1726 |
1720 /// Returning from an async method calls [asyncStarHelper] with the result. | 1727 /// Returning from an async method calls [asyncStarHelper] with the result. |
(...skipping 49 matching lines...) Expand 10 before | Expand all | Expand 10 after Loading... | |
1770 List<js.Parameter> parameters, | 1777 List<js.Parameter> parameters, |
1771 js.Statement rewrittenBody, | 1778 js.Statement rewrittenBody, |
1772 js.VariableDeclarationList variableDeclarations, | 1779 js.VariableDeclarationList variableDeclarations, |
1773 SourceInformation sourceInformation) { | 1780 SourceInformation sourceInformation) { |
1774 return js.js( | 1781 return js.js( |
1775 """ | 1782 """ |
1776 function (#parameters) { | 1783 function (#parameters) { |
1777 #variableDeclarations; | 1784 #variableDeclarations; |
1778 var #bodyName = #wrapBody(function (#errorCode, #result) { | 1785 var #bodyName = #wrapBody(function (#errorCode, #result) { |
1779 if (#errorCode === #ERROR) { | 1786 if (#errorCode === #ERROR) { |
1780 #currentError = #result; | 1787 if (#hasHandlerLabels) { |
1781 #goto = #handler; | 1788 #currentError = #result; |
1789 #goto = #handler; | |
1790 } else | |
1791 return #asyncRethrow(#result, #completer); | |
1782 } | 1792 } |
1783 #rewrittenBody; | 1793 #rewrittenBody; |
1784 }); | 1794 }); |
1785 return #asyncStart(#bodyName, #completer); | 1795 return #asyncStart(#bodyName, #completer); |
1786 }""", | 1796 }""", |
1787 { | 1797 { |
1788 "parameters": parameters, | 1798 "parameters": parameters, |
1789 "variableDeclarations": variableDeclarations, | 1799 "variableDeclarations": variableDeclarations, |
1790 "ERROR": js.number(error_codes.ERROR), | 1800 "ERROR": js.number(error_codes.ERROR), |
1791 "rewrittenBody": rewrittenBody, | 1801 "rewrittenBody": rewrittenBody, |
1792 "bodyName": bodyName, | 1802 "bodyName": bodyName, |
1793 "currentError": currentError, | 1803 "currentError": currentError, |
1794 "goto": goto, | 1804 "goto": goto, |
1795 "handler": handler, | 1805 "handler": handler, |
1796 "errorCode": errorCodeName, | 1806 "errorCode": errorCodeName, |
1797 "result": resultName, | 1807 "result": resultName, |
1798 "asyncStart": asyncStart, | 1808 "asyncStart": asyncStart, |
1809 "asyncRethrow": asyncRethrow, | |
1810 "hasHandlerLabels": hasHandlerLabels, | |
1799 "completer": completer, | 1811 "completer": completer, |
1800 "wrapBody": wrapBody, | 1812 "wrapBody": wrapBody, |
1801 }).withSourceInformation(sourceInformation); | 1813 }).withSourceInformation(sourceInformation); |
1802 } | 1814 } |
1803 } | 1815 } |
1804 | 1816 |
1805 class SyncStarRewriter extends AsyncRewriterBase { | 1817 class SyncStarRewriter extends AsyncRewriterBase { |
1806 bool get isSyncStar => true; | 1818 bool get isSyncStar => true; |
1807 | 1819 |
1808 /// Constructor creating the Iterable for a sync* method. Called with | 1820 /// Constructor creating the Iterable for a sync* method. Called with |
(...skipping 91 matching lines...) Expand 10 before | Expand all | Expand 10 after Loading... | |
1900 "self": selfName, | 1912 "self": selfName, |
1901 "result": resultName, | 1913 "result": resultName, |
1902 "goto": goto, | 1914 "goto": goto, |
1903 "handler": handler, | 1915 "handler": handler, |
1904 "currentError": currentErrorName, | 1916 "currentError": currentErrorName, |
1905 "ERROR": js.number(error_codes.ERROR), | 1917 "ERROR": js.number(error_codes.ERROR), |
1906 }).withSourceInformation(sourceInformation); | 1918 }).withSourceInformation(sourceInformation); |
1907 } | 1919 } |
1908 | 1920 |
1909 void addErrorExit() { | 1921 void addErrorExit() { |
1922 hasHandlerLabels = true; | |
floitsch
2017/05/04 08:52:05
This is too confusing, but I'm guessing this is ju
sra1
2017/05/05 21:52:34
I added a field comment and a TODO comment here to
| |
1910 beginLabel(rethrowLabel); | 1923 beginLabel(rethrowLabel); |
1911 addStatement(js.js | 1924 addStatement(js.js |
1912 .statement('return #(#);', [uncaughtErrorExpression, currentError])); | 1925 .statement('return #(#);', [uncaughtErrorExpression, currentError])); |
1913 } | 1926 } |
1914 | 1927 |
1915 /// Returning from a sync* function returns an [endOfIteration] marker. | 1928 /// Returning from a sync* function returns an [endOfIteration] marker. |
1916 void addSuccesExit() { | 1929 void addSuccesExit() { |
1917 if (analysis.hasExplicitReturns) { | 1930 if (analysis.hasExplicitReturns) { |
1918 beginLabel(exitLabel); | 1931 beginLabel(exitLabel); |
1919 } else { | 1932 } else { |
(...skipping 164 matching lines...) Expand 10 before | Expand all | Expand 10 after Loading... | |
2084 "errorCode": errorCodeName, | 2097 "errorCode": errorCodeName, |
2085 "result": resultName, | 2098 "result": resultName, |
2086 "streamOfController": streamOfController, | 2099 "streamOfController": streamOfController, |
2087 "controller": controllerName, | 2100 "controller": controllerName, |
2088 "wrapBody": wrapBody, | 2101 "wrapBody": wrapBody, |
2089 }).withSourceInformation(sourceInformation); | 2102 }).withSourceInformation(sourceInformation); |
2090 } | 2103 } |
2091 | 2104 |
2092 @override | 2105 @override |
2093 void addErrorExit() { | 2106 void addErrorExit() { |
2107 hasHandlerLabels = true; | |
floitsch
2017/05/04 08:52:05
ditto.
| |
2094 beginLabel(rethrowLabel); | 2108 beginLabel(rethrowLabel); |
2095 addStatement(js.js.statement( | 2109 addStatement(js.js.statement( |
2096 "return #asyncHelper(#currentError, #errorCode, #controller);", { | 2110 "return #asyncHelper(#currentError, #errorCode, #controller);", { |
2097 "asyncHelper": asyncStarHelper, | 2111 "asyncHelper": asyncStarHelper, |
2098 "errorCode": js.number(error_codes.ERROR), | 2112 "errorCode": js.number(error_codes.ERROR), |
2099 "currentError": currentError, | 2113 "currentError": currentError, |
2100 "controller": controllerName | 2114 "controller": controllerName |
2101 })); | 2115 })); |
2102 } | 2116 } |
2103 | 2117 |
(...skipping 491 matching lines...) Expand 10 before | Expand all | Expand 10 after Loading... | |
2595 return condition || body; | 2609 return condition || body; |
2596 } | 2610 } |
2597 | 2611 |
2598 @override | 2612 @override |
2599 bool visitDartYield(js.DartYield node) { | 2613 bool visitDartYield(js.DartYield node) { |
2600 hasYield = true; | 2614 hasYield = true; |
2601 visit(node.expression); | 2615 visit(node.expression); |
2602 return true; | 2616 return true; |
2603 } | 2617 } |
2604 } | 2618 } |
OLD | NEW |