| OLD | NEW |
| 1 // Copyright (c) 2016, the Dart project authors. Please see the AUTHORS file | 1 // Copyright (c) 2016, 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 kernel.transformations.continuation; | 5 library kernel.transformations.continuation; |
| 6 | 6 |
| 7 import 'dart:math' as math; | 7 import 'dart:math' as math; |
| 8 | 8 |
| 9 import '../ast.dart'; | 9 import '../ast.dart'; |
| 10 import '../visitor.dart'; | 10 import '../visitor.dart'; |
| (...skipping 163 matching lines...) Expand 10 before | Expand all | Expand 10 after Loading... |
| 174 } | 174 } |
| 175 | 175 |
| 176 abstract class AsyncRewriterBase extends ContinuationRewriterBase { | 176 abstract class AsyncRewriterBase extends ContinuationRewriterBase { |
| 177 final VariableDeclaration nestedClosureVariable = | 177 final VariableDeclaration nestedClosureVariable = |
| 178 new VariableDeclaration(":async_op"); | 178 new VariableDeclaration(":async_op"); |
| 179 final VariableDeclaration thenContinuationVariable = | 179 final VariableDeclaration thenContinuationVariable = |
| 180 new VariableDeclaration(":async_op_then"); | 180 new VariableDeclaration(":async_op_then"); |
| 181 final VariableDeclaration catchErrorContinuationVariable = | 181 final VariableDeclaration catchErrorContinuationVariable = |
| 182 new VariableDeclaration(":async_op_error"); | 182 new VariableDeclaration(":async_op_error"); |
| 183 | 183 |
| 184 LabeledStatement labeledBody; |
| 185 |
| 184 ExpressionLifter expressionRewriter; | 186 ExpressionLifter expressionRewriter; |
| 185 | 187 |
| 186 AsyncRewriterBase(helper, enclosingFunction) | 188 AsyncRewriterBase(helper, enclosingFunction) |
| 187 // Body is wrapped in the try-catch so initial currentTryDepth is 1. | 189 // Body is wrapped in the try-catch so initial currentTryDepth is 1. |
| 188 : super(helper, enclosingFunction, currentTryDepth: 1) {} | 190 : super(helper, enclosingFunction, currentTryDepth: 1) {} |
| 189 | 191 |
| 190 void setupAsyncContinuations(List<Statement> statements) { | 192 void setupAsyncContinuations(List<Statement> statements) { |
| 191 expressionRewriter = new ExpressionLifter(this); | 193 expressionRewriter = new ExpressionLifter(this); |
| 192 | 194 |
| 193 // var :async_op_then; | 195 // var :async_op_then; |
| (...skipping 38 matching lines...) Expand 10 before | Expand all | Expand 10 after Loading... |
| 232 final boundCatchErrorClosure = new StaticInvocation( | 234 final boundCatchErrorClosure = new StaticInvocation( |
| 233 helper.asyncErrorWrapper, | 235 helper.asyncErrorWrapper, |
| 234 new Arguments(<Expression>[new VariableGet(nestedClosureVariable)])); | 236 new Arguments(<Expression>[new VariableGet(nestedClosureVariable)])); |
| 235 final catchErrorClosureVariableAssign = new ExpressionStatement( | 237 final catchErrorClosureVariableAssign = new ExpressionStatement( |
| 236 new VariableSet( | 238 new VariableSet( |
| 237 catchErrorContinuationVariable, boundCatchErrorClosure)); | 239 catchErrorContinuationVariable, boundCatchErrorClosure)); |
| 238 statements.add(catchErrorClosureVariableAssign); | 240 statements.add(catchErrorClosureVariableAssign); |
| 239 } | 241 } |
| 240 | 242 |
| 241 Statement buildWrappedBody() { | 243 Statement buildWrappedBody() { |
| 242 // No explicit return at the end of the body => we will add one! | 244 labeledBody = new LabeledStatement(null); |
| 243 var body = addReturnStatementIfNecessary(enclosingFunction.body); | 245 labeledBody.body = visitDelimited(enclosingFunction.body) |
| 244 var userBody = visitDelimited(body); | 246 ..parent = labeledBody; |
| 245 | 247 |
| 246 var exceptionVariable = new VariableDeclaration(":exception"); | 248 var exceptionVariable = new VariableDeclaration(":exception"); |
| 247 var stackTraceVariable = new VariableDeclaration(":stack_trace"); | 249 var stackTraceVariable = new VariableDeclaration(":stack_trace"); |
| 248 | 250 |
| 249 var completeErrorStatement = | 251 return new TryCatch(buildReturn(labeledBody), <Catch>[ |
| 250 buildCatchBody(exceptionVariable, stackTraceVariable); | 252 new Catch( |
| 251 | 253 exceptionVariable, |
| 252 var catchBody = new Block(<Statement>[completeErrorStatement]); | 254 new Block(<Statement>[ |
| 253 var catches = <Catch>[ | 255 buildCatchBody(exceptionVariable, stackTraceVariable) |
| 254 new Catch(exceptionVariable, catchBody, stackTrace: stackTraceVariable) | 256 ]), |
| 255 ]; | 257 stackTrace: stackTraceVariable) |
| 256 return new TryCatch(userBody, catches); | 258 ]); |
| 257 } | |
| 258 | |
| 259 Statement addReturnStatementIfNecessary(Statement body) { | |
| 260 if (body is Block) { | |
| 261 Block block = body; | |
| 262 if (block.statements.isEmpty || | |
| 263 block.statements.last is! ReturnStatement) { | |
| 264 var returnStatement = new ReturnStatement(); | |
| 265 block.statements.add(returnStatement); | |
| 266 returnStatement.parent = block; | |
| 267 } | |
| 268 } else if (body is! ReturnStatement) { | |
| 269 var returnStatement = new ReturnStatement(); | |
| 270 body = new Block(<Statement>[body, returnStatement]); | |
| 271 } | |
| 272 return body; | |
| 273 } | 259 } |
| 274 | 260 |
| 275 Statement buildCatchBody( | 261 Statement buildCatchBody( |
| 276 Statement exceptionVariable, Statement stackTraceVariable); | 262 Statement exceptionVariable, Statement stackTraceVariable); |
| 277 | 263 |
| 264 Statement buildReturn(Statement body); |
| 265 |
| 278 List<Statement> statements = <Statement>[]; | 266 List<Statement> statements = <Statement>[]; |
| 279 | 267 |
| 280 TreeNode visitInvalidStatement(InvalidStatement stmt) { | 268 TreeNode visitInvalidStatement(InvalidStatement stmt) { |
| 281 statements.add(stmt); | 269 statements.add(stmt); |
| 282 return null; | 270 return null; |
| 283 } | 271 } |
| 284 | 272 |
| 285 TreeNode visitExpressionStatement(ExpressionStatement stmt) { | 273 TreeNode visitExpressionStatement(ExpressionStatement stmt) { |
| 286 stmt.expression = expressionRewriter.rewrite(stmt.expression, statements) | 274 stmt.expression = expressionRewriter.rewrite(stmt.expression, statements) |
| 287 ..parent = stmt; | 275 ..parent = stmt; |
| (...skipping 309 matching lines...) Expand 10 before | Expand all | Expand 10 after Loading... |
| 597 stmt.condition = expressionRewriter.rewrite(stmt.condition, statements) | 585 stmt.condition = expressionRewriter.rewrite(stmt.condition, statements) |
| 598 ..parent = stmt; | 586 ..parent = stmt; |
| 599 stmt.then = visitDelimited(stmt.then)..parent = stmt; | 587 stmt.then = visitDelimited(stmt.then)..parent = stmt; |
| 600 if (stmt.otherwise != null) { | 588 if (stmt.otherwise != null) { |
| 601 stmt.otherwise = visitDelimited(stmt.otherwise)..parent = stmt; | 589 stmt.otherwise = visitDelimited(stmt.otherwise)..parent = stmt; |
| 602 } | 590 } |
| 603 statements.add(stmt); | 591 statements.add(stmt); |
| 604 return null; | 592 return null; |
| 605 } | 593 } |
| 606 | 594 |
| 607 TreeNode visitReturnStatement(ReturnStatement stmt) { | |
| 608 if (stmt.expression != null) { | |
| 609 stmt.expression = expressionRewriter.rewrite(stmt.expression, statements) | |
| 610 ..parent = stmt; | |
| 611 } | |
| 612 statements.add(stmt); | |
| 613 return null; | |
| 614 } | |
| 615 | |
| 616 TreeNode visitTryCatch(TryCatch stmt) { | 595 TreeNode visitTryCatch(TryCatch stmt) { |
| 617 ++currentTryDepth; | 596 ++currentTryDepth; |
| 618 stmt.body = visitDelimited(stmt.body)..parent = stmt; | 597 stmt.body = visitDelimited(stmt.body)..parent = stmt; |
| 619 --currentTryDepth; | 598 --currentTryDepth; |
| 620 | 599 |
| 621 ++currentCatchDepth; | 600 ++currentCatchDepth; |
| 622 for (var clause in stmt.catches) { | 601 for (var clause in stmt.catches) { |
| 623 clause.body = visitDelimited(clause.body)..parent = clause; | 602 clause.body = visitDelimited(clause.body)..parent = clause; |
| 624 } | 603 } |
| 625 --currentCatchDepth; | 604 --currentCatchDepth; |
| (...skipping 41 matching lines...) Expand 10 before | Expand all | Expand 10 after Loading... |
| 667 AsyncStarFunctionRewriter(helper, enclosingFunction) | 646 AsyncStarFunctionRewriter(helper, enclosingFunction) |
| 668 : super(helper, enclosingFunction); | 647 : super(helper, enclosingFunction); |
| 669 | 648 |
| 670 FunctionNode rewrite() { | 649 FunctionNode rewrite() { |
| 671 var statements = <Statement>[]; | 650 var statements = <Statement>[]; |
| 672 | 651 |
| 673 // var :controller; | 652 // var :controller; |
| 674 controllerVariable = new VariableDeclaration(":controller"); | 653 controllerVariable = new VariableDeclaration(":controller"); |
| 675 statements.add(controllerVariable); | 654 statements.add(controllerVariable); |
| 676 | 655 |
| 677 super.setupAsyncContinuations(statements); | 656 setupAsyncContinuations(statements); |
| 678 | 657 |
| 679 // :controller = new _AsyncController(:async_op); | 658 // :controller = new _AsyncController(:async_op); |
| 680 var arguments = | 659 var arguments = |
| 681 new Arguments(<Expression>[new VariableGet(nestedClosureVariable)]); | 660 new Arguments(<Expression>[new VariableGet(nestedClosureVariable)]); |
| 682 var buildController = new ConstructorInvocation( | 661 var buildController = new ConstructorInvocation( |
| 683 helper.streamControllerConstructor, arguments); | 662 helper.streamControllerConstructor, arguments); |
| 684 var setController = new ExpressionStatement( | 663 var setController = new ExpressionStatement( |
| 685 new VariableSet(controllerVariable, buildController)); | 664 new VariableSet(controllerVariable, buildController)); |
| 686 statements.add(setController); | 665 statements.add(setController); |
| 687 | 666 |
| (...skipping 12 matching lines...) Expand all Loading... |
| 700 Statement buildCatchBody(exceptionVariable, stackTraceVariable) { | 679 Statement buildCatchBody(exceptionVariable, stackTraceVariable) { |
| 701 return new ExpressionStatement(new MethodInvocation( | 680 return new ExpressionStatement(new MethodInvocation( |
| 702 new VariableGet(controllerVariable), | 681 new VariableGet(controllerVariable), |
| 703 new Name("completeError", helper.asyncLibrary), | 682 new Name("completeError", helper.asyncLibrary), |
| 704 new Arguments(<Expression>[ | 683 new Arguments(<Expression>[ |
| 705 new VariableGet(exceptionVariable), | 684 new VariableGet(exceptionVariable), |
| 706 new VariableGet(stackTraceVariable) | 685 new VariableGet(stackTraceVariable) |
| 707 ]))); | 686 ]))); |
| 708 } | 687 } |
| 709 | 688 |
| 689 Statement buildReturn(Statement body) { |
| 690 // Async* functions cannot return a value. The returns from the function |
| 691 // have been translated into breaks from the labeled body. |
| 692 return new Block(<Statement>[ |
| 693 body, |
| 694 new ExpressionStatement(new MethodInvocation( |
| 695 new VariableGet(controllerVariable), |
| 696 new Name("close", helper.asyncLibrary), |
| 697 new Arguments(<Expression>[]))), |
| 698 new ReturnStatement() |
| 699 ]); |
| 700 } |
| 701 |
| 710 TreeNode visitYieldStatement(YieldStatement stmt) { | 702 TreeNode visitYieldStatement(YieldStatement stmt) { |
| 711 Expression expr = expressionRewriter.rewrite(stmt.expression, statements); | 703 Expression expr = expressionRewriter.rewrite(stmt.expression, statements); |
| 712 | 704 |
| 713 var addExpression = new MethodInvocation( | 705 var addExpression = new MethodInvocation( |
| 714 new VariableGet(controllerVariable), | 706 new VariableGet(controllerVariable), |
| 715 new Name(stmt.isYieldStar ? 'addStream' : 'add', helper.asyncLibrary), | 707 new Name(stmt.isYieldStar ? 'addStream' : 'add', helper.asyncLibrary), |
| 716 new Arguments(<Expression>[expr])); | 708 new Arguments(<Expression>[expr])); |
| 717 | 709 |
| 718 statements.add(new IfStatement(addExpression, | 710 statements.add(new IfStatement(addExpression, |
| 719 new ReturnStatement(new NullLiteral()), createContinuationPoint())); | 711 new ReturnStatement(new NullLiteral()), createContinuationPoint())); |
| 720 return null; | 712 return null; |
| 721 } | 713 } |
| 722 | 714 |
| 723 TreeNode visitReturnStatement(ReturnStatement node) { | 715 TreeNode visitReturnStatement(ReturnStatement node) { |
| 724 // async* functions cannot have normal [ReturnStatement]s in them. | 716 // Async* functions cannot return a value. |
| 725 assert(node.expression == null || node.expression is NullLiteral); | 717 assert(node.expression == null || node.expression is NullLiteral); |
| 726 | 718 statements |
| 727 statements.add(new ExpressionStatement(new MethodInvocation( | 719 .add(new BreakStatement(labeledBody)..fileOffset = node.fileOffset); |
| 728 new VariableGet(controllerVariable), | |
| 729 new Name("close", helper.asyncLibrary), | |
| 730 new Arguments(<Expression>[])))); | |
| 731 statements.add(new ReturnStatement()); | |
| 732 return null; | 720 return null; |
| 733 } | 721 } |
| 734 } | 722 } |
| 735 | 723 |
| 736 class AsyncFunctionRewriter extends AsyncRewriterBase { | 724 class AsyncFunctionRewriter extends AsyncRewriterBase { |
| 737 VariableDeclaration completerVariable; | 725 VariableDeclaration completerVariable; |
| 726 VariableDeclaration returnVariable; |
| 738 | 727 |
| 739 AsyncFunctionRewriter(helper, enclosingFunction) | 728 AsyncFunctionRewriter(helper, enclosingFunction) |
| 740 : super(helper, enclosingFunction); | 729 : super(helper, enclosingFunction); |
| 741 | 730 |
| 742 FunctionNode rewrite() { | 731 FunctionNode rewrite() { |
| 743 var statements = <Statement>[]; | 732 var statements = <Statement>[]; |
| 744 | 733 |
| 745 // var :completer = new Completer.sync(); | 734 // var :completer = new Completer.sync(); |
| 746 completerVariable = new VariableDeclaration(":completer", | 735 completerVariable = new VariableDeclaration(":completer", |
| 747 initializer: new StaticInvocation( | 736 initializer: new StaticInvocation( |
| 748 helper.completerConstructor, new Arguments([])), | 737 helper.completerConstructor, new Arguments([])), |
| 749 isFinal: true); | 738 isFinal: true); |
| 750 statements.add(completerVariable); | 739 statements.add(completerVariable); |
| 751 | 740 |
| 752 super.setupAsyncContinuations(statements); | 741 returnVariable = new VariableDeclaration(":return_value"); |
| 742 statements.add(returnVariable); |
| 743 |
| 744 setupAsyncContinuations(statements); |
| 753 | 745 |
| 754 // new Future.microtask(:async_op); | 746 // new Future.microtask(:async_op); |
| 755 var newMicrotaskStatement = new ExpressionStatement(new StaticInvocation( | 747 var newMicrotaskStatement = new ExpressionStatement(new StaticInvocation( |
| 756 helper.futureMicrotaskConstructor, | 748 helper.futureMicrotaskConstructor, |
| 757 new Arguments([new VariableGet(nestedClosureVariable)]))); | 749 new Arguments([new VariableGet(nestedClosureVariable)]))); |
| 758 statements.add(newMicrotaskStatement); | 750 statements.add(newMicrotaskStatement); |
| 759 | 751 |
| 760 // return :completer.future; | 752 // return :completer.future; |
| 761 var completerGet = new VariableGet(completerVariable); | 753 var completerGet = new VariableGet(completerVariable); |
| 762 var returnStatement = new ReturnStatement( | 754 var returnStatement = new ReturnStatement( |
| 763 new PropertyGet(completerGet, new Name('future', helper.asyncLibrary))); | 755 new PropertyGet(completerGet, new Name('future', helper.asyncLibrary))); |
| 764 statements.add(returnStatement); | 756 statements.add(returnStatement); |
| 765 | 757 |
| 766 enclosingFunction.body = new Block(statements); | 758 enclosingFunction.body = new Block(statements); |
| 767 enclosingFunction.body.parent = enclosingFunction; | 759 enclosingFunction.body.parent = enclosingFunction; |
| 768 enclosingFunction.asyncMarker = AsyncMarker.Sync; | 760 enclosingFunction.asyncMarker = AsyncMarker.Sync; |
| 769 return enclosingFunction; | 761 return enclosingFunction; |
| 770 } | 762 } |
| 771 | 763 |
| 772 Statement buildCatchBody(exceptionVariable, stackTraceVariable) { | 764 Statement buildCatchBody(exceptionVariable, stackTraceVariable) { |
| 773 return new ExpressionStatement(new MethodInvocation( | 765 return new ExpressionStatement(new MethodInvocation( |
| 774 new VariableGet(completerVariable), | 766 new VariableGet(completerVariable), |
| 775 new Name("completeError", helper.asyncLibrary), | 767 new Name("completeError", helper.asyncLibrary), |
| 776 new Arguments([ | 768 new Arguments([ |
| 777 new VariableGet(exceptionVariable), | 769 new VariableGet(exceptionVariable), |
| 778 new VariableGet(stackTraceVariable) | 770 new VariableGet(stackTraceVariable) |
| 779 ]))); | 771 ]))); |
| 780 } | 772 } |
| 781 | 773 |
| 774 Statement buildReturn(Statement body) { |
| 775 // Returns from the body have all been translated into assignments to the |
| 776 // return value variable followed by a break from the labeled body. |
| 777 return new Block(<Statement>[ |
| 778 body, |
| 779 new ExpressionStatement(new MethodInvocation( |
| 780 new VariableGet(completerVariable), |
| 781 new Name("complete", helper.asyncLibrary), |
| 782 new Arguments([new VariableGet(returnVariable)]))), |
| 783 new ReturnStatement() |
| 784 ]); |
| 785 } |
| 786 |
| 782 visitReturnStatement(ReturnStatement node) { | 787 visitReturnStatement(ReturnStatement node) { |
| 783 var expr; | 788 var expr = node.expression == null |
| 784 if (node.expression == null) { | 789 ? new NullLiteral() |
| 785 expr = new NullLiteral(); | 790 : expressionRewriter.rewrite(node.expression, statements); |
| 786 } else { | 791 statements |
| 787 expr = expressionRewriter.rewrite(node.expression, statements); | 792 .add(new ExpressionStatement(new VariableSet(returnVariable, expr))); |
| 788 } | 793 statements |
| 789 | 794 .add(new BreakStatement(labeledBody)..fileOffset = node.fileOffset); |
| 790 statements.add(new ExpressionStatement(new MethodInvocation( | |
| 791 new VariableGet(completerVariable), | |
| 792 new Name("complete", helper.asyncLibrary), | |
| 793 new Arguments([expr])))); | |
| 794 statements.add(new ReturnStatement(new NullLiteral())); | |
| 795 return null; | 795 return null; |
| 796 } | 796 } |
| 797 } | 797 } |
| 798 | 798 |
| 799 class HelperNodes { | 799 class HelperNodes { |
| 800 final Library asyncLibrary; | 800 final Library asyncLibrary; |
| 801 final Library coreLibrary; | 801 final Library coreLibrary; |
| 802 final Procedure printProcedure; | 802 final Procedure printProcedure; |
| 803 final Procedure completerConstructor; | 803 final Procedure completerConstructor; |
| 804 final Procedure futureMicrotaskConstructor; | 804 final Procedure futureMicrotaskConstructor; |
| (...skipping 84 matching lines...) Expand 10 before | Expand all | Expand 10 after Loading... |
| 889 findFactoryConstructor(completerClass, 'sync'), | 889 findFactoryConstructor(completerClass, 'sync'), |
| 890 findConstructor(syncIterableClass, ''), | 890 findConstructor(syncIterableClass, ''), |
| 891 findConstructor(streamIteratorClass, ''), | 891 findConstructor(streamIteratorClass, ''), |
| 892 findFactoryConstructor(futureClass, 'microtask'), | 892 findFactoryConstructor(futureClass, 'microtask'), |
| 893 findConstructor(streamControllerClass, ''), | 893 findConstructor(streamControllerClass, ''), |
| 894 findProcedure(asyncLibrary, '_asyncThenWrapperHelper'), | 894 findProcedure(asyncLibrary, '_asyncThenWrapperHelper'), |
| 895 findProcedure(asyncLibrary, '_asyncErrorWrapperHelper'), | 895 findProcedure(asyncLibrary, '_asyncErrorWrapperHelper'), |
| 896 findProcedure(asyncLibrary, '_awaitHelper')); | 896 findProcedure(asyncLibrary, '_awaitHelper')); |
| 897 } | 897 } |
| 898 } | 898 } |
| OLD | NEW |