| 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 10 matching lines...) Expand all Loading... |
| 21 /// | 21 /// |
| 22 /// When generating the input to this, special care must be taken that | 22 /// When generating the input to this, special care must be taken that |
| 23 /// parameters to sync* functions that are mutated in the body must be boxed. | 23 /// parameters to sync* functions that are mutated in the body must be boxed. |
| 24 /// (Currently handled in closure.dart). | 24 /// (Currently handled in closure.dart). |
| 25 /// | 25 /// |
| 26 /// Look at [rewriteFunction], [visitDartYield] and [visitAwait] for more | 26 /// Look at [rewriteFunction], [visitDartYield] and [visitAwait] for more |
| 27 /// explanation. | 27 /// explanation. |
| 28 abstract class AsyncRewriterBase extends js.NodeVisitor { | 28 abstract class AsyncRewriterBase extends js.NodeVisitor { |
| 29 // Local variables are hoisted to the top of the function, so they are | 29 // Local variables are hoisted to the top of the function, so they are |
| 30 // collected here. | 30 // collected here. |
| 31 List<js.VariableDeclaration> localVariables = | 31 List<js.VariableDeclaration> localVariables = <js.VariableDeclaration>[]; |
| 32 new List<js.VariableDeclaration>(); | |
| 33 | 32 |
| 34 Map<js.Node, int> continueLabels = new Map<js.Node, int>(); | 33 Map<js.Node, int> continueLabels = new Map<js.Node, int>(); |
| 35 Map<js.Node, int> breakLabels = new Map<js.Node, int>(); | 34 Map<js.Node, int> breakLabels = new Map<js.Node, int>(); |
| 36 | 35 |
| 37 /// The label of a finally part. | 36 /// The label of a finally part. |
| 38 Map<js.Block, int> finallyLabels = new Map<js.Block, int>(); | 37 Map<js.Block, int> finallyLabels = new Map<js.Block, int>(); |
| 39 | 38 |
| 40 /// The label of the catch handler of a [js.Try] or a [js.Fun] or [js.Catch]. | 39 /// The label of the catch handler of a [js.Try] or a [js.Fun] or [js.Catch]. |
| 41 /// | 40 /// |
| 42 /// These mark the points an error can be consumed. | 41 /// These mark the points an error can be consumed. |
| (...skipping 15 matching lines...) Expand all Loading... |
| 58 /// * The function, signalling a return or uncaught throw. | 57 /// * The function, signalling a return or uncaught throw. |
| 59 /// * Loops. | 58 /// * Loops. |
| 60 /// * LabeledStatements (also used for 'continue' when attached to loops). | 59 /// * LabeledStatements (also used for 'continue' when attached to loops). |
| 61 /// * Try statements, for catch and finally handlers. | 60 /// * Try statements, for catch and finally handlers. |
| 62 /// * Catch handlers, when inside a catch-part of a try, the catch-handler is | 61 /// * Catch handlers, when inside a catch-part of a try, the catch-handler is |
| 63 /// used to associate with a synthetic handler that will ensure the right | 62 /// used to associate with a synthetic handler that will ensure the right |
| 64 /// finally blocks are visited. | 63 /// finally blocks are visited. |
| 65 /// | 64 /// |
| 66 /// When jumping to a target it is necessary to visit all finallies that | 65 /// When jumping to a target it is necessary to visit all finallies that |
| 67 /// are on the way to target (i.e. more nested than the jump target). | 66 /// are on the way to target (i.e. more nested than the jump target). |
| 68 List<js.Node> jumpTargets = new List<js.Node>(); | 67 List<js.Node> jumpTargets = <js.Node>[]; |
| 69 | 68 |
| 70 List<int> continueStack = new List<int>(); | 69 List<int> continueStack = <int>[]; |
| 71 List<int> breakStack = new List<int>(); | 70 List<int> breakStack = <int>[]; |
| 72 List<int> returnStack = new List<int>(); | 71 List<int> returnStack = <int>[]; |
| 73 | 72 |
| 74 List<Pair<String, String>> variableRenamings = | 73 List<Pair<String, String>> variableRenamings = <Pair<String, String>>[]; |
| 75 new List<Pair<String, String>>(); | |
| 76 | 74 |
| 77 PreTranslationAnalysis analysis; | 75 PreTranslationAnalysis analysis; |
| 78 | 76 |
| 79 final Function safeVariableName; | 77 final Function safeVariableName; |
| 80 | 78 |
| 81 // All the <x>Name variables are names of Javascript variables used in the | 79 // All the <x>Name variables are names of Javascript variables used in the |
| 82 // transformed code. | 80 // transformed code. |
| 83 | 81 |
| 84 /// Contains the result of an awaited expression, or a conditional or | 82 /// Contains the result of an awaited expression, or a conditional or |
| 85 /// lazy boolean operator. | 83 /// lazy boolean operator. |
| (...skipping 206 matching lines...) Expand 10 before | Expand all | Expand 10 after Loading... |
| 292 /// This should be followed by a break for the goto to be executed. Use | 290 /// This should be followed by a break for the goto to be executed. Use |
| 293 /// [gotoWithBreak] or [addGoto] for this. | 291 /// [gotoWithBreak] or [addGoto] for this. |
| 294 js.Statement setGotoVariable(int label) { | 292 js.Statement setGotoVariable(int label) { |
| 295 return js.js.statement('# = #;', [goto, js.number(label)]); | 293 return js.js.statement('# = #;', [goto, js.number(label)]); |
| 296 } | 294 } |
| 297 | 295 |
| 298 /// Returns a block that has a goto to [label] including the break. | 296 /// Returns a block that has a goto to [label] including the break. |
| 299 /// | 297 /// |
| 300 /// Also inserts a comment describing the label if available. | 298 /// Also inserts a comment describing the label if available. |
| 301 js.Block gotoAndBreak(int label) { | 299 js.Block gotoAndBreak(int label) { |
| 302 List<js.Statement> statements = new List<js.Statement>(); | 300 List<js.Statement> statements = <js.Statement>[]; |
| 303 if (labelComments.containsKey(label)) { | 301 if (labelComments.containsKey(label)) { |
| 304 statements.add(new js.Comment("goto ${labelComments[label]}")); | 302 statements.add(new js.Comment("goto ${labelComments[label]}")); |
| 305 } | 303 } |
| 306 statements.add(setGotoVariable(label)); | 304 statements.add(setGotoVariable(label)); |
| 307 if (insideUntranslatedBreakable) { | 305 if (insideUntranslatedBreakable) { |
| 308 hasJumpThoughOuterLabel = true; | 306 hasJumpThoughOuterLabel = true; |
| 309 statements.add(new js.Break(outerLabelName)); | 307 statements.add(new js.Break(outerLabelName)); |
| 310 } else { | 308 } else { |
| 311 statements.add(new js.Break(null)); | 309 statements.add(new js.Break(null)); |
| 312 } | 310 } |
| (...skipping 363 matching lines...) Expand 10 before | Expand all | Expand 10 after Loading... |
| 676 addFunctionExits(); | 674 addFunctionExits(); |
| 677 | 675 |
| 678 List<js.SwitchClause> clauses = labelledParts.keys.map((label) { | 676 List<js.SwitchClause> clauses = labelledParts.keys.map((label) { |
| 679 return new js.Case(js.number(label), new js.Block(labelledParts[label])); | 677 return new js.Case(js.number(label), new js.Block(labelledParts[label])); |
| 680 }).toList(); | 678 }).toList(); |
| 681 js.Statement rewrittenBody = new js.Switch(goto, clauses); | 679 js.Statement rewrittenBody = new js.Switch(goto, clauses); |
| 682 if (hasJumpThoughOuterLabel) { | 680 if (hasJumpThoughOuterLabel) { |
| 683 rewrittenBody = new js.LabeledStatement(outerLabelName, rewrittenBody); | 681 rewrittenBody = new js.LabeledStatement(outerLabelName, rewrittenBody); |
| 684 } | 682 } |
| 685 rewrittenBody = js.js.statement('while (true) {#}', rewrittenBody); | 683 rewrittenBody = js.js.statement('while (true) {#}', rewrittenBody); |
| 686 List<js.VariableInitialization> variables = | 684 List<js.VariableInitialization> variables = <js.VariableInitialization>[]; |
| 687 new List<js.VariableInitialization>(); | |
| 688 | 685 |
| 689 variables.add(_makeVariableInitializer(goto, js.number(0))); | 686 variables.add(_makeVariableInitializer(goto, js.number(0))); |
| 690 variables.addAll(variableInitializations()); | 687 variables.addAll(variableInitializations()); |
| 691 variables.add(_makeVariableInitializer(handler, js.number(rethrowLabel))); | 688 variables.add(_makeVariableInitializer(handler, js.number(rethrowLabel))); |
| 692 variables.add(_makeVariableInitializer(currentError, null)); | 689 variables.add(_makeVariableInitializer(currentError, null)); |
| 693 if (analysis.hasFinally || (isAsyncStar && analysis.hasYield)) { | 690 if (analysis.hasFinally || (isAsyncStar && analysis.hasYield)) { |
| 694 variables.add(_makeVariableInitializer( | 691 variables.add(_makeVariableInitializer( |
| 695 next, new js.ArrayInitializer(<js.Expression>[]))); | 692 next, new js.ArrayInitializer(<js.Expression>[]))); |
| 696 } | 693 } |
| 697 if (analysis.hasThis && !isSyncStar) { | 694 if (analysis.hasThis && !isSyncStar) { |
| (...skipping 234 matching lines...) Expand 10 before | Expand all | Expand 10 after Loading... |
| 932 /// Common code for handling break, continue, return. | 929 /// Common code for handling break, continue, return. |
| 933 /// | 930 /// |
| 934 /// It is necessary to run all nesting finally-handlers between the jump and | 931 /// It is necessary to run all nesting finally-handlers between the jump and |
| 935 /// the target. For that [next] is used as a stack of places to go. | 932 /// the target. For that [next] is used as a stack of places to go. |
| 936 /// | 933 /// |
| 937 /// See also [rewriteFunction]. | 934 /// See also [rewriteFunction]. |
| 938 void translateJump(js.Node target, int targetLabel) { | 935 void translateJump(js.Node target, int targetLabel) { |
| 939 // Compute a stack of all the 'finally' nodes that must be visited before | 936 // Compute a stack of all the 'finally' nodes that must be visited before |
| 940 // the jump. | 937 // the jump. |
| 941 // The bottom of the stack is the label where the jump goes to. | 938 // The bottom of the stack is the label where the jump goes to. |
| 942 List<int> jumpStack = new List<int>(); | 939 List<int> jumpStack = <int>[]; |
| 943 for (js.Node node in jumpTargets.reversed) { | 940 for (js.Node node in jumpTargets.reversed) { |
| 944 if (finallyLabels[node] != null) { | 941 if (finallyLabels[node] != null) { |
| 945 jumpStack.add(finallyLabels[node]); | 942 jumpStack.add(finallyLabels[node]); |
| 946 } else if (node == target) { | 943 } else if (node == target) { |
| 947 jumpStack.add(targetLabel); | 944 jumpStack.add(targetLabel); |
| 948 break; | 945 break; |
| 949 } | 946 } |
| 950 // Ignore other nodes. | 947 // Ignore other nodes. |
| 951 } | 948 } |
| 952 jumpStack = jumpStack.reversed.toList(); | 949 jumpStack = jumpStack.reversed.toList(); |
| (...skipping 407 matching lines...) Expand 10 before | Expand all | Expand 10 after Loading... |
| 1360 }, store: true); | 1357 }, store: true); |
| 1361 | 1358 |
| 1362 if (defaultIndex == null) { | 1359 if (defaultIndex == null) { |
| 1363 addGoto(after); | 1360 addGoto(after); |
| 1364 } else { | 1361 } else { |
| 1365 addGoto(labels[defaultIndex]); | 1362 addGoto(labels[defaultIndex]); |
| 1366 } | 1363 } |
| 1367 } else { | 1364 } else { |
| 1368 bool hasDefault = false; | 1365 bool hasDefault = false; |
| 1369 int i = 0; | 1366 int i = 0; |
| 1370 List<js.SwitchClause> clauses = new List<js.SwitchClause>(); | 1367 List<js.SwitchClause> clauses = <js.SwitchClause>[]; |
| 1371 for (js.SwitchClause clause in node.cases) { | 1368 for (js.SwitchClause clause in node.cases) { |
| 1372 if (clause is js.Case) { | 1369 if (clause is js.Case) { |
| 1373 labels[i] = newLabel("case"); | 1370 labels[i] = newLabel("case"); |
| 1374 clauses.add(new js.Case( | 1371 clauses.add(new js.Case( |
| 1375 visitExpression(clause.expression), gotoAndBreak(labels[i]))); | 1372 visitExpression(clause.expression), gotoAndBreak(labels[i]))); |
| 1376 } else if (clause is js.Default) { | 1373 } else if (clause is js.Default) { |
| 1377 labels[i] = newLabel("default"); | 1374 labels[i] = newLabel("default"); |
| 1378 clauses.add(new js.Default(gotoAndBreak(labels[i]))); | 1375 clauses.add(new js.Default(gotoAndBreak(labels[i]))); |
| 1379 hasDefault = true; | 1376 hasDefault = true; |
| 1380 } else { | 1377 } else { |
| (...skipping 33 matching lines...) Expand 10 before | Expand all | Expand 10 after Loading... |
| 1414 }, store: false); | 1411 }, store: false); |
| 1415 } | 1412 } |
| 1416 | 1413 |
| 1417 setErrorHandler([int errorHandler]) { | 1414 setErrorHandler([int errorHandler]) { |
| 1418 js.Expression label = | 1415 js.Expression label = |
| 1419 (errorHandler == null) ? currentErrorHandler : js.number(errorHandler); | 1416 (errorHandler == null) ? currentErrorHandler : js.number(errorHandler); |
| 1420 addStatement(js.js.statement('# = #;', [handler, label])); | 1417 addStatement(js.js.statement('# = #;', [handler, label])); |
| 1421 } | 1418 } |
| 1422 | 1419 |
| 1423 List<int> _finalliesUpToAndEnclosingHandler() { | 1420 List<int> _finalliesUpToAndEnclosingHandler() { |
| 1424 List<int> result = new List<int>(); | 1421 List<int> result = <int>[]; |
| 1425 for (int i = jumpTargets.length - 1; i >= 0; i--) { | 1422 for (int i = jumpTargets.length - 1; i >= 0; i--) { |
| 1426 js.Node node = jumpTargets[i]; | 1423 js.Node node = jumpTargets[i]; |
| 1427 int handlerLabel = handlerLabels[node]; | 1424 int handlerLabel = handlerLabels[node]; |
| 1428 if (handlerLabel != null) { | 1425 if (handlerLabel != null) { |
| 1429 result.add(handlerLabel); | 1426 result.add(handlerLabel); |
| 1430 break; | 1427 break; |
| 1431 } | 1428 } |
| 1432 int finallyLabel = finallyLabels[node]; | 1429 int finallyLabel = finallyLabels[node]; |
| 1433 if (finallyLabel != null) { | 1430 if (finallyLabel != null) { |
| 1434 result.add(finallyLabel); | 1431 result.add(finallyLabel); |
| (...skipping 237 matching lines...) Expand 10 before | Expand all | Expand 10 after Loading... |
| 1672 /// For a throw it is called with: | 1669 /// For a throw it is called with: |
| 1673 /// | 1670 /// |
| 1674 /// - The error to complete the completer with. | 1671 /// - The error to complete the completer with. |
| 1675 /// - [error_codes.ERROR] | 1672 /// - [error_codes.ERROR] |
| 1676 /// - The completer object [completer] | 1673 /// - The completer object [completer] |
| 1677 final js.Expression asyncHelper; | 1674 final js.Expression asyncHelper; |
| 1678 | 1675 |
| 1679 /// Contructor used to initialize the [completer] variable. | 1676 /// Contructor used to initialize the [completer] variable. |
| 1680 /// | 1677 /// |
| 1681 /// Specific to async methods. | 1678 /// Specific to async methods. |
| 1682 final js.Expression newCompleter; | 1679 final js.Expression completerFactory; |
| 1683 | 1680 |
| 1684 final js.Expression wrapBody; | 1681 final js.Expression wrapBody; |
| 1685 | 1682 |
| 1686 AsyncRewriter(DiagnosticReporter reporter, Spannable spannable, | 1683 AsyncRewriter(DiagnosticReporter reporter, Spannable spannable, |
| 1687 {this.asyncHelper, | 1684 {this.asyncHelper, |
| 1688 this.newCompleter, | 1685 this.completerFactory, |
| 1689 this.wrapBody, | 1686 this.wrapBody, |
| 1690 String safeVariableName(String proposedName), | 1687 String safeVariableName(String proposedName), |
| 1691 js.Name bodyName}) | 1688 js.Name bodyName}) |
| 1692 : super(reporter, spannable, safeVariableName, bodyName); | 1689 : super(reporter, spannable, safeVariableName, bodyName); |
| 1693 | 1690 |
| 1694 @override | 1691 @override |
| 1695 void addYield(js.DartYield node, js.Expression expression) { | 1692 void addYield(js.DartYield node, js.Expression expression) { |
| 1696 reporter.internalError(spannable, "Yield in non-generating async function"); | 1693 reporter.internalError(spannable, "Yield in non-generating async function"); |
| 1697 } | 1694 } |
| 1698 | 1695 |
| (...skipping 22 matching lines...) Expand all Loading... |
| 1721 "runtimeHelper": asyncHelper, | 1718 "runtimeHelper": asyncHelper, |
| 1722 "successCode": js.number(error_codes.SUCCESS), | 1719 "successCode": js.number(error_codes.SUCCESS), |
| 1723 "returnValue": | 1720 "returnValue": |
| 1724 analysis.hasExplicitReturns ? returnValue : new js.LiteralNull(), | 1721 analysis.hasExplicitReturns ? returnValue : new js.LiteralNull(), |
| 1725 "completer": completer | 1722 "completer": completer |
| 1726 })); | 1723 })); |
| 1727 } | 1724 } |
| 1728 | 1725 |
| 1729 @override | 1726 @override |
| 1730 Iterable<js.VariableInitialization> variableInitializations() { | 1727 Iterable<js.VariableInitialization> variableInitializations() { |
| 1731 List<js.VariableInitialization> variables = | 1728 List<js.VariableInitialization> variables = <js.VariableInitialization>[]; |
| 1732 new List<js.VariableInitialization>(); | 1729 variables.add( |
| 1733 variables | 1730 _makeVariableInitializer(completer, new js.Call(completerFactory, []))); |
| 1734 .add(_makeVariableInitializer(completer, new js.New(newCompleter, []))); | |
| 1735 if (analysis.hasExplicitReturns) { | 1731 if (analysis.hasExplicitReturns) { |
| 1736 variables.add(_makeVariableInitializer(returnValue, null)); | 1732 variables.add(_makeVariableInitializer(returnValue, null)); |
| 1737 } | 1733 } |
| 1738 return variables; | 1734 return variables; |
| 1739 } | 1735 } |
| 1740 | 1736 |
| 1741 @override | 1737 @override |
| 1742 void initializeNames() { | 1738 void initializeNames() { |
| 1743 completerName = freshName("completer"); | 1739 completerName = freshName("completer"); |
| 1744 } | 1740 } |
| (...skipping 49 matching lines...) Expand 10 before | Expand all | Expand 10 after Loading... |
| 1794 "wrapBody": wrapBody, | 1790 "wrapBody": wrapBody, |
| 1795 }).withSourceInformation(sourceInformation); | 1791 }).withSourceInformation(sourceInformation); |
| 1796 } | 1792 } |
| 1797 } | 1793 } |
| 1798 | 1794 |
| 1799 class SyncStarRewriter extends AsyncRewriterBase { | 1795 class SyncStarRewriter extends AsyncRewriterBase { |
| 1800 bool get isSyncStar => true; | 1796 bool get isSyncStar => true; |
| 1801 | 1797 |
| 1802 /// Contructor creating the Iterable for a sync* method. Called with | 1798 /// Contructor creating the Iterable for a sync* method. Called with |
| 1803 /// [bodyName]. | 1799 /// [bodyName]. |
| 1804 final js.Expression newIterable; | 1800 final js.Expression iterableFactory; |
| 1805 | 1801 |
| 1806 /// A JS Expression that creates a marker showing that iteration is over. | 1802 /// A JS Expression that creates a marker showing that iteration is over. |
| 1807 /// | 1803 /// |
| 1808 /// Called without arguments. | 1804 /// Called without arguments. |
| 1809 final js.Expression endOfIteration; | 1805 final js.Expression endOfIteration; |
| 1810 | 1806 |
| 1811 /// A JS Expression that creates a marker indication a 'yield*' statement. | 1807 /// A JS Expression that creates a marker indication a 'yield*' statement. |
| 1812 /// | 1808 /// |
| 1813 /// Called with the stream to yield from. | 1809 /// Called with the stream to yield from. |
| 1814 final js.Expression yieldStarExpression; | 1810 final js.Expression yieldStarExpression; |
| 1815 | 1811 |
| 1816 /// Used by sync* functions to throw exeptions. | 1812 /// Used by sync* functions to throw exeptions. |
| 1817 final js.Expression uncaughtErrorExpression; | 1813 final js.Expression uncaughtErrorExpression; |
| 1818 | 1814 |
| 1819 SyncStarRewriter(DiagnosticReporter diagnosticListener, spannable, | 1815 SyncStarRewriter(DiagnosticReporter diagnosticListener, spannable, |
| 1820 {this.endOfIteration, | 1816 {this.endOfIteration, |
| 1821 this.newIterable, | 1817 this.iterableFactory, |
| 1822 this.yieldStarExpression, | 1818 this.yieldStarExpression, |
| 1823 this.uncaughtErrorExpression, | 1819 this.uncaughtErrorExpression, |
| 1824 String safeVariableName(String proposedName), | 1820 String safeVariableName(String proposedName), |
| 1825 js.Name bodyName}) | 1821 js.Name bodyName}) |
| 1826 : super(diagnosticListener, spannable, safeVariableName, bodyName); | 1822 : super(diagnosticListener, spannable, safeVariableName, bodyName); |
| 1827 | 1823 |
| 1828 /// Translates a yield/yield* in an sync*. | 1824 /// Translates a yield/yield* in an sync*. |
| 1829 /// | 1825 /// |
| 1830 /// `yield` in a sync* function just returns [value]. | 1826 /// `yield` in a sync* function just returns [value]. |
| 1831 /// `yield*` wraps [value] in a [yieldStarExpression] and returns it. | 1827 /// `yield*` wraps [value] in a [yieldStarExpression] and returns it. |
| (...skipping 11 matching lines...) Expand all Loading... |
| 1843 js.Fun finishFunction( | 1839 js.Fun finishFunction( |
| 1844 List<js.Parameter> parameters, | 1840 List<js.Parameter> parameters, |
| 1845 js.Statement rewrittenBody, | 1841 js.Statement rewrittenBody, |
| 1846 js.VariableDeclarationList variableDeclarations, | 1842 js.VariableDeclarationList variableDeclarations, |
| 1847 SourceInformation sourceInformation) { | 1843 SourceInformation sourceInformation) { |
| 1848 // Each iterator invocation on the iterable should work on its own copy of | 1844 // Each iterator invocation on the iterable should work on its own copy of |
| 1849 // the parameters. | 1845 // the parameters. |
| 1850 // TODO(sigurdm): We only need to do this copying for parameters that are | 1846 // TODO(sigurdm): We only need to do this copying for parameters that are |
| 1851 // mutated. | 1847 // mutated. |
| 1852 List<js.VariableInitialization> declarations = | 1848 List<js.VariableInitialization> declarations = |
| 1853 new List<js.VariableInitialization>(); | 1849 <js.VariableInitialization>[]; |
| 1854 List<js.Parameter> renamedParameters = new List<js.Parameter>(); | 1850 List<js.Parameter> renamedParameters = <js.Parameter>[]; |
| 1855 for (js.Parameter parameter in parameters) { | 1851 for (js.Parameter parameter in parameters) { |
| 1856 String name = parameter.name; | 1852 String name = parameter.name; |
| 1857 String renamedName = freshName(name); | 1853 String renamedName = freshName(name); |
| 1858 renamedParameters.add(new js.Parameter(renamedName)); | 1854 renamedParameters.add(new js.Parameter(renamedName)); |
| 1859 declarations.add(new js.VariableInitialization( | 1855 declarations.add(new js.VariableInitialization( |
| 1860 new js.VariableDeclaration(name), new js.VariableUse(renamedName))); | 1856 new js.VariableDeclaration(name), new js.VariableUse(renamedName))); |
| 1861 } | 1857 } |
| 1862 js.VariableDeclarationList copyParameters = | 1858 js.VariableDeclarationList copyParameters = |
| 1863 new js.VariableDeclarationList(declarations); | 1859 new js.VariableDeclarationList(declarations); |
| 1864 return js.js( | 1860 return js.js( |
| 1865 """ | 1861 """ |
| 1866 function (#renamedParameters) { | 1862 function (#renamedParameters) { |
| 1867 if (#needsThis) | 1863 if (#needsThis) |
| 1868 var #self = this; | 1864 var #self = this; |
| 1869 return new #newIterable(function () { | 1865 return #iterableFactory(function () { |
| 1870 if (#hasParameters) { | 1866 if (#hasParameters) { |
| 1871 #copyParameters; | 1867 #copyParameters; |
| 1872 } | 1868 } |
| 1873 #varDecl; | 1869 #varDecl; |
| 1874 return function #body(#errorCode, #result) { | 1870 return function #body(#errorCode, #result) { |
| 1875 if (#errorCode === #ERROR) { | 1871 if (#errorCode === #ERROR) { |
| 1876 #currentError = #result; | 1872 #currentError = #result; |
| 1877 #goto = #handler; | 1873 #goto = #handler; |
| 1878 } | 1874 } |
| 1879 #helperBody; | 1875 #helperBody; |
| 1880 }; | 1876 }; |
| 1881 }); | 1877 }); |
| 1882 } | 1878 } |
| 1883 """, | 1879 """, |
| 1884 { | 1880 { |
| 1885 "renamedParameters": renamedParameters, | 1881 "renamedParameters": renamedParameters, |
| 1886 "needsThis": analysis.hasThis, | 1882 "needsThis": analysis.hasThis, |
| 1887 "helperBody": rewrittenBody, | 1883 "helperBody": rewrittenBody, |
| 1888 "hasParameters": parameters.isNotEmpty, | 1884 "hasParameters": parameters.isNotEmpty, |
| 1889 "copyParameters": copyParameters, | 1885 "copyParameters": copyParameters, |
| 1890 "varDecl": variableDeclarations, | 1886 "varDecl": variableDeclarations, |
| 1891 "errorCode": errorCodeName, | 1887 "errorCode": errorCodeName, |
| 1892 "newIterable": newIterable, | 1888 "iterableFactory": iterableFactory, |
| 1893 "body": bodyName, | 1889 "body": bodyName, |
| 1894 "self": selfName, | 1890 "self": selfName, |
| 1895 "result": resultName, | 1891 "result": resultName, |
| 1896 "goto": goto, | 1892 "goto": goto, |
| 1897 "handler": handler, | 1893 "handler": handler, |
| 1898 "currentError": currentErrorName, | 1894 "currentError": currentErrorName, |
| 1899 "ERROR": js.number(error_codes.ERROR), | 1895 "ERROR": js.number(error_codes.ERROR), |
| 1900 }).withSourceInformation(sourceInformation); | 1896 }).withSourceInformation(sourceInformation); |
| 1901 } | 1897 } |
| 1902 | 1898 |
| 1903 void addErrorExit() { | 1899 void addErrorExit() { |
| 1904 beginLabel(rethrowLabel); | 1900 beginLabel(rethrowLabel); |
| 1905 addStatement(js.js | 1901 addStatement(js.js |
| 1906 .statement('return #(#);', [uncaughtErrorExpression, currentError])); | 1902 .statement('return #(#);', [uncaughtErrorExpression, currentError])); |
| 1907 } | 1903 } |
| 1908 | 1904 |
| 1909 /// Returning from a sync* function returns an [endOfIteration] marker. | 1905 /// Returning from a sync* function returns an [endOfIteration] marker. |
| 1910 void addSuccesExit() { | 1906 void addSuccesExit() { |
| 1911 if (analysis.hasExplicitReturns) { | 1907 if (analysis.hasExplicitReturns) { |
| 1912 beginLabel(exitLabel); | 1908 beginLabel(exitLabel); |
| 1913 } else { | 1909 } else { |
| 1914 addStatement(new js.Comment("implicit return")); | 1910 addStatement(new js.Comment("implicit return")); |
| 1915 } | 1911 } |
| 1916 addStatement(js.js.statement('return #();', [endOfIteration])); | 1912 addStatement(js.js.statement('return #();', [endOfIteration])); |
| 1917 } | 1913 } |
| 1918 | 1914 |
| 1919 @override | 1915 @override |
| 1920 Iterable<js.VariableInitialization> variableInitializations() { | 1916 Iterable<js.VariableInitialization> variableInitializations() { |
| 1921 List<js.VariableInitialization> variables = | 1917 List<js.VariableInitialization> variables = <js.VariableInitialization>[]; |
| 1922 new List<js.VariableInitialization>(); | |
| 1923 return variables; | 1918 return variables; |
| 1924 } | 1919 } |
| 1925 | 1920 |
| 1926 @override | 1921 @override |
| 1927 js.Statement awaitStatement(js.Expression value) { | 1922 js.Statement awaitStatement(js.Expression value) { |
| 1928 throw reporter.internalError( | 1923 throw reporter.internalError( |
| 1929 spannable, "Sync* functions cannot contain await statements."); | 1924 spannable, "Sync* functions cannot contain await statements."); |
| 1930 } | 1925 } |
| 1931 | 1926 |
| 1932 @override | 1927 @override |
| (...skipping 172 matching lines...) Expand 10 before | Expand all | Expand 10 after Loading... |
| 2105 addStatement(js.js | 2100 addStatement(js.js |
| 2106 .statement("return #streamHelper(null, #successCode, #controller);", { | 2101 .statement("return #streamHelper(null, #successCode, #controller);", { |
| 2107 "streamHelper": asyncStarHelper, | 2102 "streamHelper": asyncStarHelper, |
| 2108 "successCode": js.number(error_codes.SUCCESS), | 2103 "successCode": js.number(error_codes.SUCCESS), |
| 2109 "controller": controllerName | 2104 "controller": controllerName |
| 2110 })); | 2105 })); |
| 2111 } | 2106 } |
| 2112 | 2107 |
| 2113 @override | 2108 @override |
| 2114 Iterable<js.VariableInitialization> variableInitializations() { | 2109 Iterable<js.VariableInitialization> variableInitializations() { |
| 2115 List<js.VariableInitialization> variables = | 2110 List<js.VariableInitialization> variables = <js.VariableInitialization>[]; |
| 2116 new List<js.VariableInitialization>(); | |
| 2117 variables.add(_makeVariableInitializer( | 2111 variables.add(_makeVariableInitializer( |
| 2118 controller, js.js('#(#)', [newController, bodyName]))); | 2112 controller, js.js('#(#)', [newController, bodyName]))); |
| 2119 if (analysis.hasYield) { | 2113 if (analysis.hasYield) { |
| 2120 variables.add(_makeVariableInitializer(nextWhenCanceled, null)); | 2114 variables.add(_makeVariableInitializer(nextWhenCanceled, null)); |
| 2121 } | 2115 } |
| 2122 return variables; | 2116 return variables; |
| 2123 } | 2117 } |
| 2124 | 2118 |
| 2125 @override | 2119 @override |
| 2126 void initializeNames() { | 2120 void initializeNames() { |
| (...skipping 21 matching lines...) Expand all Loading... |
| 2148 /// Finds out | 2142 /// Finds out |
| 2149 /// | 2143 /// |
| 2150 /// - which expressions have yield or await nested in them. | 2144 /// - which expressions have yield or await nested in them. |
| 2151 /// - targets of jumps | 2145 /// - targets of jumps |
| 2152 /// - a set of used names. | 2146 /// - a set of used names. |
| 2153 /// - if any [This]-expressions are used. | 2147 /// - if any [This]-expressions are used. |
| 2154 class PreTranslationAnalysis extends js.NodeVisitor<bool> { | 2148 class PreTranslationAnalysis extends js.NodeVisitor<bool> { |
| 2155 Set<js.Node> hasAwaitOrYield = new Set<js.Node>(); | 2149 Set<js.Node> hasAwaitOrYield = new Set<js.Node>(); |
| 2156 | 2150 |
| 2157 Map<js.Node, js.Node> targets = new Map<js.Node, js.Node>(); | 2151 Map<js.Node, js.Node> targets = new Map<js.Node, js.Node>(); |
| 2158 List<js.Node> loopsAndSwitches = new List<js.Node>(); | 2152 List<js.Node> loopsAndSwitches = <js.Node>[]; |
| 2159 List<js.LabeledStatement> labelledStatements = | 2153 List<js.LabeledStatement> labelledStatements = <js.LabeledStatement>[]; |
| 2160 new List<js.LabeledStatement>(); | |
| 2161 Set<String> usedNames = new Set<String>(); | 2154 Set<String> usedNames = new Set<String>(); |
| 2162 | 2155 |
| 2163 bool hasExplicitReturns = false; | 2156 bool hasExplicitReturns = false; |
| 2164 | 2157 |
| 2165 bool hasThis = false; | 2158 bool hasThis = false; |
| 2166 | 2159 |
| 2167 bool hasYield = false; | 2160 bool hasYield = false; |
| 2168 | 2161 |
| 2169 bool hasFinally = false; | 2162 bool hasFinally = false; |
| 2170 | 2163 |
| (...skipping 421 matching lines...) Expand 10 before | Expand all | Expand 10 after Loading... |
| 2592 return condition || body; | 2585 return condition || body; |
| 2593 } | 2586 } |
| 2594 | 2587 |
| 2595 @override | 2588 @override |
| 2596 bool visitDartYield(js.DartYield node) { | 2589 bool visitDartYield(js.DartYield node) { |
| 2597 hasYield = true; | 2590 hasYield = true; |
| 2598 visit(node.expression); | 2591 visit(node.expression); |
| 2599 return true; | 2592 return true; |
| 2600 } | 2593 } |
| 2601 } | 2594 } |
| OLD | NEW |