Chromium Code Reviews
chromiumcodereview-hr@appspot.gserviceaccount.com (chromiumcodereview-hr) | Please choose your nickname with Settings | Help | Chromium Project | Gerrit Changes | Sign out
(378)

Side by Side Diff: pkg/compiler/lib/src/js/rewrite_async.dart

Issue 1859343004: dartfmt pkg/compiler (Closed) Base URL: git@github.com:dart-lang/sdk.git@master
Patch Set: Created 4 years, 8 months ago
Use n/p to move between diff chunks; N/P to move between comments. Draft comments are only viewable by you.
Jump to:
View unified diff | Download patch
OLDNEW
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:math" show max; 7 import "dart:math" show max;
8 import 'dart:collection'; 8 import 'dart:collection';
9 9
10 import 'package:js_runtime/shared/async_await_error_codes.dart' 10 import 'package:js_runtime/shared/async_await_error_codes.dart' as error_codes;
11 as error_codes;
12 11
13 import "js.dart" as js; 12 import "js.dart" as js;
14 13
15 import '../common.dart'; 14 import '../common.dart';
16 import '../util/util.dart' show 15 import '../util/util.dart' show Pair;
17 Pair;
18 16
19 /// Rewrites a [js.Fun] with async/sync*/async* functions and await and yield 17 /// Rewrites a [js.Fun] with async/sync*/async* functions and await and yield
20 /// (with dart-like semantics) to an equivalent function without these. 18 /// (with dart-like semantics) to an equivalent function without these.
21 /// await-for is not handled and must be rewritten before. (Currently handled 19 /// await-for is not handled and must be rewritten before. (Currently handled
22 /// in ssa/builder.dart). 20 /// in ssa/builder.dart).
23 /// 21 ///
24 /// 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
25 /// 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.
26 /// (Currently handled in closure.dart). 24 /// (Currently handled in closure.dart).
27 /// 25 ///
28 /// Look at [rewriteFunction], [visitDartYield] and [visitAwait] for more 26 /// Look at [rewriteFunction], [visitDartYield] and [visitAwait] for more
29 /// explanation. 27 /// explanation.
30 abstract class AsyncRewriterBase extends js.NodeVisitor { 28 abstract class AsyncRewriterBase extends js.NodeVisitor {
31
32 // 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
33 // collected here. 30 // collected here.
34 List<js.VariableDeclaration> localVariables = 31 List<js.VariableDeclaration> localVariables =
35 new List<js.VariableDeclaration>(); 32 new List<js.VariableDeclaration>();
36 33
37 Map<js.Node, int> continueLabels = new Map<js.Node, int>(); 34 Map<js.Node, int> continueLabels = new Map<js.Node, int>();
38 Map<js.Node, int> breakLabels = new Map<js.Node, int>(); 35 Map<js.Node, int> breakLabels = new Map<js.Node, int>();
39 36
40 /// The label of a finally part. 37 /// The label of a finally part.
41 Map<js.Block, int> finallyLabels = new Map<js.Block, int>(); 38 Map<js.Block, int> finallyLabels = new Map<js.Block, int>();
(...skipping 127 matching lines...) Expand 10 before | Expand all | Expand 10 after
169 // The highest temporary variable index currently in use. 166 // The highest temporary variable index currently in use.
170 int currentTempVarIndex = 0; 167 int currentTempVarIndex = 0;
171 // The highest temporary variable index ever in use in this function. 168 // The highest temporary variable index ever in use in this function.
172 int tempVarHighWaterMark = 0; 169 int tempVarHighWaterMark = 0;
173 Map<int, js.Expression> tempVarNames = new Map<int, js.Expression>(); 170 Map<int, js.Expression> tempVarNames = new Map<int, js.Expression>();
174 171
175 bool get isAsync => false; 172 bool get isAsync => false;
176 bool get isSyncStar => false; 173 bool get isSyncStar => false;
177 bool get isAsyncStar => false; 174 bool get isAsyncStar => false;
178 175
179 AsyncRewriterBase(this.reporter, 176 AsyncRewriterBase(
180 this._spannable, 177 this.reporter, this._spannable, this.safeVariableName, this.bodyName);
181 this.safeVariableName,
182 this.bodyName);
183 178
184 /// Initialize names used by the subClass. 179 /// Initialize names used by the subClass.
185 void initializeNames(); 180 void initializeNames();
186 181
187 /// Main entry point. 182 /// Main entry point.
188 /// Rewrites a sync*/async/async* function to an equivalent normal function. 183 /// Rewrites a sync*/async/async* function to an equivalent normal function.
189 /// 184 ///
190 /// [spannable] can be passed to have a location for error messages. 185 /// [spannable] can be passed to have a location for error messages.
191 js.Fun rewrite(js.Fun node, [Spannable spannable]) { 186 js.Fun rewrite(js.Fun node, [Spannable spannable]) {
192 _spannable = spannable; 187 _spannable = spannable;
(...skipping 12 matching lines...) Expand all
205 currentErrorName = freshName("currentError"); 200 currentErrorName = freshName("currentError");
206 outerLabelName = freshName("outer"); 201 outerLabelName = freshName("outer");
207 selfName = freshName("self"); 202 selfName = freshName("self");
208 // Initialize names specific to the subclass. 203 // Initialize names specific to the subclass.
209 initializeNames(); 204 initializeNames();
210 205
211 return rewriteFunction(node); 206 return rewriteFunction(node);
212 } 207 }
213 208
214 js.Expression get currentErrorHandler { 209 js.Expression get currentErrorHandler {
215 return js.number(handlerLabels[jumpTargets.lastWhere( 210 return js.number(handlerLabels[
216 (node) => handlerLabels[node] != null)]); 211 jumpTargets.lastWhere((node) => handlerLabels[node] != null)]);
217 } 212 }
218 213
219 int allocateTempVar() { 214 int allocateTempVar() {
220 assert(tempVarHighWaterMark >= currentTempVarIndex); 215 assert(tempVarHighWaterMark >= currentTempVarIndex);
221 currentTempVarIndex++; 216 currentTempVarIndex++;
222 tempVarHighWaterMark = max(currentTempVarIndex, tempVarHighWaterMark); 217 tempVarHighWaterMark = max(currentTempVarIndex, tempVarHighWaterMark);
223 return currentTempVarIndex; 218 return currentTempVarIndex;
224 } 219 }
225 220
226 js.VariableUse useTempVar(int i) { 221 js.VariableUse useTempVar(int i) {
(...skipping 115 matching lines...) Expand 10 before | Expand all | Expand 10 after
342 bool shouldTransform(js.Node node) { 337 bool shouldTransform(js.Node node) {
343 return analysis.hasAwaitOrYield.contains(node); 338 return analysis.hasAwaitOrYield.contains(node);
344 } 339 }
345 340
346 void unsupported(js.Node node) { 341 void unsupported(js.Node node) {
347 throw new UnsupportedError( 342 throw new UnsupportedError(
348 "Node $node cannot be transformed by the await-sync transformer"); 343 "Node $node cannot be transformed by the await-sync transformer");
349 } 344 }
350 345
351 void unreachable(js.Node node) { 346 void unreachable(js.Node node) {
352 reporter.internalError( 347 reporter.internalError(spannable, "Internal error, trying to visit $node");
353 spannable, "Internal error, trying to visit $node");
354 } 348 }
355 349
356 visitStatement(js.Statement node) { 350 visitStatement(js.Statement node) {
357 node.accept(this); 351 node.accept(this);
358 } 352 }
359 353
360 /// Visits [node] to ensure its sideeffects are performed, but throwing away 354 /// Visits [node] to ensure its sideeffects are performed, but throwing away
361 /// the result. 355 /// the result.
362 /// 356 ///
363 /// If the return value of visiting [node] is an expression guaranteed to have 357 /// If the return value of visiting [node] is an expression guaranteed to have
364 /// no side effect, it is dropped. 358 /// no side effect, it is dropped.
365 void visitExpressionIgnoreResult(js.Expression node) { 359 void visitExpressionIgnoreResult(js.Expression node) {
366 js.Expression result = node.accept(this); 360 js.Expression result = node.accept(this);
367 if (!(result is js.Literal || result is js.VariableUse)) { 361 if (!(result is js.Literal || result is js.VariableUse)) {
368 addExpressionStatement(result); 362 addExpressionStatement(result);
369 } 363 }
370 } 364 }
371 365
372 js.Expression visitExpression(js.Expression node) { 366 js.Expression visitExpression(js.Expression node) {
373 return node.accept(this); 367 return node.accept(this);
374 } 368 }
375 369
376
377 /// Calls [fn] with the value of evaluating [node1] and [node2]. 370 /// Calls [fn] with the value of evaluating [node1] and [node2].
378 /// 371 ///
379 /// Both nodes are evaluated in order. 372 /// Both nodes are evaluated in order.
380 /// 373 ///
381 /// If node2 must be transformed (see [shouldTransform]), then the evaluation 374 /// If node2 must be transformed (see [shouldTransform]), then the evaluation
382 /// of node1 is added to the current statement-list and the result is stored 375 /// of node1 is added to the current statement-list and the result is stored
383 /// in a temporary variable. The evaluation of node2 is then free to emit 376 /// in a temporary variable. The evaluation of node2 is then free to emit
384 /// statements without affecting the result of node1. 377 /// statements without affecting the result of node1.
385 /// 378 ///
386 /// This is necessary, because await or yield expressions have to emit 379 /// This is necessary, because await or yield expressions have to emit
(...skipping 35 matching lines...) Expand 10 before | Expand all | Expand 10 after
422 /// If [store] is true the result of evaluating [node] is stored in a 415 /// If [store] is true the result of evaluating [node] is stored in a
423 /// temporary. 416 /// temporary.
424 /// 417 ///
425 /// We cannot rewrite `<receiver>.m()` to: 418 /// We cannot rewrite `<receiver>.m()` to:
426 /// temp = <receiver>.m; 419 /// temp = <receiver>.m;
427 /// temp(); 420 /// temp();
428 /// Because this leaves `this` unbound in the call. But because of dart 421 /// Because this leaves `this` unbound in the call. But because of dart
429 /// evaluation order we can write: 422 /// evaluation order we can write:
430 /// temp = <receiver>; 423 /// temp = <receiver>;
431 /// temp.m(); 424 /// temp.m();
432 withCallTargetExpression(js.Expression node, 425 withCallTargetExpression(js.Expression node, fn(js.Expression result),
433 fn(js.Expression result), {bool store}) { 426 {bool store}) {
434 int oldTempVarIndex = currentTempVarIndex; 427 int oldTempVarIndex = currentTempVarIndex;
435 js.Expression visited = visitExpression(node); 428 js.Expression visited = visitExpression(node);
436 js.Expression selector; 429 js.Expression selector;
437 js.Expression storedIfNeeded; 430 js.Expression storedIfNeeded;
438 if (store) { 431 if (store) {
439 if (visited is js.PropertyAccess) { 432 if (visited is js.PropertyAccess) {
440 js.PropertyAccess propertyAccess = visited; 433 js.PropertyAccess propertyAccess = visited;
441 selector = propertyAccess.selector; 434 selector = propertyAccess.selector;
442 visited = propertyAccess.receiver; 435 visited = propertyAccess.receiver;
443 } 436 }
444 storedIfNeeded = _storeIfNecessary(visited); 437 storedIfNeeded = _storeIfNecessary(visited);
445 } else { 438 } else {
446 storedIfNeeded = visited; 439 storedIfNeeded = visited;
447 } 440 }
448 js.Expression result; 441 js.Expression result;
449 if (selector == null) { 442 if (selector == null) {
450 result = fn(storedIfNeeded); 443 result = fn(storedIfNeeded);
451 } else { 444 } else {
452 result = fn(new js.PropertyAccess(storedIfNeeded, selector)); 445 result = fn(new js.PropertyAccess(storedIfNeeded, selector));
453 } 446 }
454 currentTempVarIndex = oldTempVarIndex; 447 currentTempVarIndex = oldTempVarIndex;
455 return result; 448 return result;
456 } 449 }
457 450
458
459 /// Calls [fn] with the value of evaluating [node1] and [node2]. 451 /// Calls [fn] with the value of evaluating [node1] and [node2].
460 /// 452 ///
461 /// If `shouldTransform(node2)` the first expression is stored in a temporary 453 /// If `shouldTransform(node2)` the first expression is stored in a temporary
462 /// variable. 454 /// variable.
463 /// 455 ///
464 /// This is because node1 must be evaluated before visiting node2, 456 /// This is because node1 must be evaluated before visiting node2,
465 /// because the evaluation of an await or yield cannot be expressed as 457 /// because the evaluation of an await or yield cannot be expressed as
466 /// an expression, visiting node2 it will output statements that 458 /// an expression, visiting node2 it will output statements that
467 /// might have an influence on the value of node1. 459 /// might have an influence on the value of node1.
468 withExpression2(js.Expression node1, js.Expression node2, 460 withExpression2(js.Expression node1, js.Expression node2,
(...skipping 49 matching lines...) Expand 10 before | Expand all | Expand 10 after
518 /// Emits the block that control flows to if an error has been thrown 510 /// Emits the block that control flows to if an error has been thrown
519 /// but not caught. (after going through all the enclosing finally blocks). 511 /// but not caught. (after going through all the enclosing finally blocks).
520 void addErrorExit(); 512 void addErrorExit();
521 513
522 void addFunctionExits() { 514 void addFunctionExits() {
523 addSuccesExit(); 515 addSuccesExit();
524 addErrorExit(); 516 addErrorExit();
525 } 517 }
526 518
527 /// Returns the rewritten function. 519 /// Returns the rewritten function.
528 js.Fun finishFunction(List<js.Parameter> parameters, 520 js.Fun finishFunction(
529 js.Statement rewrittenBody, 521 List<js.Parameter> parameters,
530 js.VariableDeclarationList variableDeclarations); 522 js.Statement rewrittenBody,
523 js.VariableDeclarationList variableDeclarations);
531 524
532 Iterable<js.VariableInitialization> variableInitializations(); 525 Iterable<js.VariableInitialization> variableInitializations();
533 526
534 /// Rewrites an async/sync*/async* function to a normal Javascript function. 527 /// Rewrites an async/sync*/async* function to a normal Javascript function.
535 /// 528 ///
536 /// The control flow is flattened by simulating 'goto' using a switch in a 529 /// The control flow is flattened by simulating 'goto' using a switch in a
537 /// loop and a state variable [goto] inside a nested function [body] 530 /// loop and a state variable [goto] inside a nested function [body]
538 /// that can be called back by [asyncStarHelper]/[asyncStarHelper]/the 531 /// that can be called back by [asyncStarHelper]/[asyncStarHelper]/the
539 /// [Iterator]. 532 /// [Iterator].
540 /// 533 ///
(...skipping 136 matching lines...) Expand 10 before | Expand all | Expand 10 after
677 handlerLabels[node] = rethrowLabel; 670 handlerLabels[node] = rethrowLabel;
678 js.Statement body = node.body; 671 js.Statement body = node.body;
679 jumpTargets.add(node); 672 jumpTargets.add(node);
680 visitStatement(body); 673 visitStatement(body);
681 jumpTargets.removeLast(); 674 jumpTargets.removeLast();
682 addFunctionExits(); 675 addFunctionExits();
683 676
684 List<js.SwitchClause> clauses = labelledParts.keys.map((label) { 677 List<js.SwitchClause> clauses = labelledParts.keys.map((label) {
685 return new js.Case(js.number(label), new js.Block(labelledParts[label])); 678 return new js.Case(js.number(label), new js.Block(labelledParts[label]));
686 }).toList(); 679 }).toList();
687 js.Statement rewrittenBody = 680 js.Statement rewrittenBody = new js.Switch(goto, clauses);
688 new js.Switch(goto, clauses);
689 if (hasJumpThoughOuterLabel) { 681 if (hasJumpThoughOuterLabel) {
690 rewrittenBody = new js.LabeledStatement(outerLabelName, rewrittenBody); 682 rewrittenBody = new js.LabeledStatement(outerLabelName, rewrittenBody);
691 } 683 }
692 rewrittenBody = js.js.statement('while (true) {#}', rewrittenBody); 684 rewrittenBody = js.js.statement('while (true) {#}', rewrittenBody);
693 List<js.VariableInitialization> variables = 685 List<js.VariableInitialization> variables =
694 new List<js.VariableInitialization>(); 686 new List<js.VariableInitialization>();
695 687
696 variables.add(_makeVariableInitializer(goto, js.number(0))); 688 variables.add(_makeVariableInitializer(goto, js.number(0)));
697 variables.addAll(variableInitializations()); 689 variables.addAll(variableInitializations());
698 variables.add( 690 variables.add(_makeVariableInitializer(handler, js.number(rethrowLabel)));
699 _makeVariableInitializer(handler, js.number(rethrowLabel)));
700 variables.add(_makeVariableInitializer(currentError, null)); 691 variables.add(_makeVariableInitializer(currentError, null));
701 if (analysis.hasFinally || (isAsyncStar && analysis.hasYield)) { 692 if (analysis.hasFinally || (isAsyncStar && analysis.hasYield)) {
702 variables.add(_makeVariableInitializer(next, 693 variables.add(_makeVariableInitializer(
703 new js.ArrayInitializer(<js.Expression>[]))); 694 next, new js.ArrayInitializer(<js.Expression>[])));
704 } 695 }
705 if (analysis.hasThis && !isSyncStar) { 696 if (analysis.hasThis && !isSyncStar) {
706 // Sync* functions must remember `this` on the level of the outer 697 // Sync* functions must remember `this` on the level of the outer
707 // function. 698 // function.
708 variables.add(_makeVariableInitializer(self, js.js('this'))); 699 variables.add(_makeVariableInitializer(self, js.js('this')));
709 } 700 }
710 variables.addAll(localVariables.map( 701 variables.addAll(localVariables.map((js.VariableDeclaration declaration) {
711 (js.VariableDeclaration declaration) {
712 return new js.VariableInitialization(declaration, null); 702 return new js.VariableInitialization(declaration, null);
713 })); 703 }));
714 variables.addAll(new Iterable.generate(tempVarHighWaterMark, 704 variables.addAll(new Iterable.generate(tempVarHighWaterMark,
715 (int i) => _makeVariableInitializer(useTempVar(i + 1).name, null))); 705 (int i) => _makeVariableInitializer(useTempVar(i + 1).name, null)));
716 js.VariableDeclarationList variableDeclarations = 706 js.VariableDeclarationList variableDeclarations =
717 new js.VariableDeclarationList(variables); 707 new js.VariableDeclarationList(variables);
718 708
719 return finishFunction(node.params, rewrittenBody, variableDeclarations); 709 return finishFunction(node.params, rewrittenBody, variableDeclarations);
720 } 710 }
721 711
722 @override 712 @override
723 js.Expression visitFun(js.Fun node) { 713 js.Expression visitFun(js.Fun node) {
724 if (node.asyncModifier.isAsync || node.asyncModifier.isYielding) { 714 if (node.asyncModifier.isAsync || node.asyncModifier.isYielding) {
725 // The translation does not handle nested functions that are generators 715 // The translation does not handle nested functions that are generators
726 // or asynchronous. These functions should only be ones that are 716 // or asynchronous. These functions should only be ones that are
727 // introduced by JS foreign code from our own libraries. 717 // introduced by JS foreign code from our own libraries.
728 reporter.internalError(spannable, 718 reporter.internalError(
729 'Nested function is a generator or asynchronous.'); 719 spannable, 'Nested function is a generator or asynchronous.');
730 } 720 }
731 return node; 721 return node;
732 } 722 }
733 723
734 @override 724 @override
735 js.Expression visitAccess(js.PropertyAccess node) { 725 js.Expression visitAccess(js.PropertyAccess node) {
736 return withExpression2(node.receiver, node.selector, 726 return withExpression2(node.receiver, node.selector,
737 (receiver, selector) => js.js('#[#]', [receiver, selector])); 727 (receiver, selector) => js.js('#[#]', [receiver, selector]));
738 } 728 }
739 729
(...skipping 14 matching lines...) Expand all
754 if (!shouldTransform(node)) { 744 if (!shouldTransform(node)) {
755 return new js.Assignment.compound(visitExpression(node.leftHandSide), 745 return new js.Assignment.compound(visitExpression(node.leftHandSide),
756 node.op, visitExpression(node.value)); 746 node.op, visitExpression(node.value));
757 } 747 }
758 js.Expression leftHandSide = node.leftHandSide; 748 js.Expression leftHandSide = node.leftHandSide;
759 if (leftHandSide is js.VariableUse) { 749 if (leftHandSide is js.VariableUse) {
760 return withExpression(node.value, (js.Expression value) { 750 return withExpression(node.value, (js.Expression value) {
761 // A non-compound [js.Assignment] has `op==null`. So it works out to 751 // A non-compound [js.Assignment] has `op==null`. So it works out to
762 // use [js.Assignment.compound] for all cases. 752 // use [js.Assignment.compound] for all cases.
763 // Visit the [js.VariableUse] to ensure renaming is done correctly. 753 // Visit the [js.VariableUse] to ensure renaming is done correctly.
764 return new js.Assignment.compound(visitExpression(leftHandSide), 754 return new js.Assignment.compound(
765 node.op, 755 visitExpression(leftHandSide), node.op, value);
766 value);
767 }, store: false); 756 }, store: false);
768 } else if (leftHandSide is js.PropertyAccess) { 757 } else if (leftHandSide is js.PropertyAccess) {
769 return withExpressions([ 758 return withExpressions(
770 leftHandSide.receiver, 759 [leftHandSide.receiver, leftHandSide.selector, node.value],
771 leftHandSide.selector, 760 (evaluated) {
772 node.value
773 ], (evaluated) {
774 return new js.Assignment.compound( 761 return new js.Assignment.compound(
775 new js.PropertyAccess(evaluated[0], evaluated[1]), node.op, 762 new js.PropertyAccess(evaluated[0], evaluated[1]),
763 node.op,
776 evaluated[2]); 764 evaluated[2]);
777 }); 765 });
778 } else { 766 } else {
779 throw "Unexpected assignment left hand side $leftHandSide"; 767 throw "Unexpected assignment left hand side $leftHandSide";
780 } 768 }
781 } 769 }
782 770
783 js.Statement awaitStatement(js.Expression value); 771 js.Statement awaitStatement(js.Expression value);
784 772
785 /// An await is translated to an [awaitStatement]. 773 /// An await is translated to an [awaitStatement].
(...skipping 94 matching lines...) Expand 10 before | Expand all | Expand 10 after
880 } 868 }
881 869
882 @override 870 @override
883 void visitComment(js.Comment node) { 871 void visitComment(js.Comment node) {
884 addStatement(node); 872 addStatement(node);
885 } 873 }
886 874
887 @override 875 @override
888 js.Expression visitConditional(js.Conditional node) { 876 js.Expression visitConditional(js.Conditional node) {
889 if (!shouldTransform(node.then) && !shouldTransform(node.otherwise)) { 877 if (!shouldTransform(node.then) && !shouldTransform(node.otherwise)) {
890 return js.js('# ? # : #', [visitExpression(node.condition), 878 return js.js('# ? # : #', [
891 visitExpression(node.then), 879 visitExpression(node.condition),
892 visitExpression(node.otherwise)]); 880 visitExpression(node.then),
881 visitExpression(node.otherwise)
882 ]);
893 } 883 }
894 int thenLabel = newLabel("then"); 884 int thenLabel = newLabel("then");
895 int joinLabel = newLabel("join"); 885 int joinLabel = newLabel("join");
896 int elseLabel = newLabel("else"); 886 int elseLabel = newLabel("else");
897 withExpression(node.condition, (js.Expression condition) { 887 withExpression(node.condition, (js.Expression condition) {
898 addStatement(js.js.statement('# = # ? # : #;', 888 addStatement(js.js.statement('# = # ? # : #;',
899 [goto, condition, js.number(thenLabel), js.number(elseLabel)])); 889 [goto, condition, js.number(thenLabel), js.number(elseLabel)]));
900 }, store: false); 890 }, store: false);
901 addBreak(); 891 addBreak();
902 beginLabel(thenLabel); 892 beginLabel(thenLabel);
(...skipping 67 matching lines...) Expand 10 before | Expand all | Expand 10 after
970 960
971 @override 961 @override
972 void visitDefault(js.Default node) => unreachable(node); 962 void visitDefault(js.Default node) => unreachable(node);
973 963
974 @override 964 @override
975 void visitDo(js.Do node) { 965 void visitDo(js.Do node) {
976 if (!shouldTransform(node)) { 966 if (!shouldTransform(node)) {
977 bool oldInsideUntranslatedBreakable = insideUntranslatedBreakable; 967 bool oldInsideUntranslatedBreakable = insideUntranslatedBreakable;
978 insideUntranslatedBreakable = true; 968 insideUntranslatedBreakable = true;
979 addStatement(js.js.statement('do {#} while (#)', 969 addStatement(js.js.statement('do {#} while (#)',
980 [translateInBlock(node.body), 970 [translateInBlock(node.body), visitExpression(node.condition)]));
981 visitExpression(node.condition)]));
982 insideUntranslatedBreakable = oldInsideUntranslatedBreakable; 971 insideUntranslatedBreakable = oldInsideUntranslatedBreakable;
983 return; 972 return;
984 } 973 }
985 int startLabel = newLabel("do body"); 974 int startLabel = newLabel("do body");
986 975
987 int continueLabel = newLabel("do condition"); 976 int continueLabel = newLabel("do condition");
988 continueLabels[node] = continueLabel; 977 continueLabels[node] = continueLabel;
989 978
990 int afterLabel = newLabel("after do"); 979 int afterLabel = newLabel("after do");
991 breakLabels[node] = afterLabel; 980 breakLabels[node] = afterLabel;
992 981
993 beginLabel(startLabel); 982 beginLabel(startLabel);
994 983
995 jumpTargets.add(node); 984 jumpTargets.add(node);
996 visitStatement(node.body); 985 visitStatement(node.body);
997 jumpTargets.removeLast(); 986 jumpTargets.removeLast();
998 987
999 beginLabel(continueLabel); 988 beginLabel(continueLabel);
1000 withExpression(node.condition, (js.Expression condition) { 989 withExpression(node.condition, (js.Expression condition) {
1001 addStatement(js.js.statement('if (#) #', 990 addStatement(
1002 [condition, gotoAndBreak(startLabel)])); 991 js.js.statement('if (#) #', [condition, gotoAndBreak(startLabel)]));
1003 }, store: false); 992 }, store: false);
1004 beginLabel(afterLabel); 993 beginLabel(afterLabel);
1005 } 994 }
1006 995
1007 @override 996 @override
1008 void visitEmptyStatement(js.EmptyStatement node) { 997 void visitEmptyStatement(js.EmptyStatement node) {
1009 addStatement(node); 998 addStatement(node);
1010 } 999 }
1011 1000
1012
1013 @override 1001 @override
1014 void visitExpressionStatement(js.ExpressionStatement node) { 1002 void visitExpressionStatement(js.ExpressionStatement node) {
1015 visitExpressionIgnoreResult(node.expression); 1003 visitExpressionIgnoreResult(node.expression);
1016 } 1004 }
1017 1005
1018 @override 1006 @override
1019 void visitFor(js.For node) { 1007 void visitFor(js.For node) {
1020 if (!shouldTransform(node)) { 1008 if (!shouldTransform(node)) {
1021 bool oldInsideUntranslated = insideUntranslatedBreakable; 1009 bool oldInsideUntranslated = insideUntranslatedBreakable;
1022 insideUntranslatedBreakable = true; 1010 insideUntranslatedBreakable = true;
1023 // Note that node.init, node.condition, node.update all can be null, but 1011 // Note that node.init, node.condition, node.update all can be null, but
1024 // withExpressions handles that. 1012 // withExpressions handles that.
1025 withExpressions([ 1013 withExpressions([node.init, node.condition, node.update],
1026 node.init, 1014 (List<js.Expression> transformed) {
1027 node.condition,
1028 node.update
1029 ], (List<js.Expression> transformed) {
1030 addStatement(new js.For(transformed[0], transformed[1], transformed[2], 1015 addStatement(new js.For(transformed[0], transformed[1], transformed[2],
1031 translateInBlock(node.body))); 1016 translateInBlock(node.body)));
1032 }); 1017 });
1033 insideUntranslatedBreakable = oldInsideUntranslated; 1018 insideUntranslatedBreakable = oldInsideUntranslated;
1034 return; 1019 return;
1035 } 1020 }
1036 1021
1037 if (node.init != null) { 1022 if (node.init != null) {
1038 visitExpressionIgnoreResult(node.init); 1023 visitExpressionIgnoreResult(node.init);
1039 } 1024 }
1040 int startLabel = newLabel("for condition"); 1025 int startLabel = newLabel("for condition");
1041 // If there is no update, continuing the loop is the same as going to the 1026 // If there is no update, continuing the loop is the same as going to the
(...skipping 51 matching lines...) Expand 10 before | Expand all | Expand 10 after
1093 void visitIf(js.If node) { 1078 void visitIf(js.If node) {
1094 if (!shouldTransform(node.then) && !shouldTransform(node.otherwise)) { 1079 if (!shouldTransform(node.then) && !shouldTransform(node.otherwise)) {
1095 withExpression(node.condition, (js.Expression condition) { 1080 withExpression(node.condition, (js.Expression condition) {
1096 addStatement(new js.If(condition, translateInBlock(node.then), 1081 addStatement(new js.If(condition, translateInBlock(node.then),
1097 translateInBlock(node.otherwise))); 1082 translateInBlock(node.otherwise)));
1098 }, store: false); 1083 }, store: false);
1099 return; 1084 return;
1100 } 1085 }
1101 int thenLabel = newLabel("then"); 1086 int thenLabel = newLabel("then");
1102 int joinLabel = newLabel("join"); 1087 int joinLabel = newLabel("join");
1103 int elseLabel = (node.otherwise is js.EmptyStatement) 1088 int elseLabel =
1104 ? joinLabel 1089 (node.otherwise is js.EmptyStatement) ? joinLabel : newLabel("else");
1105 : newLabel("else");
1106 1090
1107 withExpression(node.condition, (js.Expression condition) { 1091 withExpression(node.condition, (js.Expression condition) {
1108 addExpressionStatement( 1092 addExpressionStatement(new js.Assignment(
1109 new js.Assignment( 1093 goto,
1110 goto, 1094 new js.Conditional(
1111 new js.Conditional( 1095 condition, js.number(thenLabel), js.number(elseLabel))));
1112 condition,
1113 js.number(thenLabel),
1114 js.number(elseLabel))));
1115 }, store: false); 1096 }, store: false);
1116 addBreak(); 1097 addBreak();
1117 beginLabel(thenLabel); 1098 beginLabel(thenLabel);
1118 visitStatement(node.then); 1099 visitStatement(node.then);
1119 if (node.otherwise is! js.EmptyStatement) { 1100 if (node.otherwise is! js.EmptyStatement) {
1120 addGoto(joinLabel); 1101 addGoto(joinLabel);
1121 beginLabel(elseLabel); 1102 beginLabel(elseLabel);
1122 visitStatement(node.otherwise); 1103 visitStatement(node.otherwise);
1123 } 1104 }
1124 beginLabel(joinLabel); 1105 beginLabel(joinLabel);
(...skipping 163 matching lines...) Expand 10 before | Expand all | Expand 10 after
1288 store: false); 1269 store: false);
1289 } 1270 }
1290 1271
1291 @override 1272 @override
1292 js.Expression visitRegExpLiteral(js.RegExpLiteral node) => node; 1273 js.Expression visitRegExpLiteral(js.RegExpLiteral node) => node;
1293 1274
1294 @override 1275 @override
1295 void visitReturn(js.Return node) { 1276 void visitReturn(js.Return node) {
1296 js.Node target = analysis.targets[node]; 1277 js.Node target = analysis.targets[node];
1297 if (node.value != null) { 1278 if (node.value != null) {
1298 if(isSyncStar || isAsyncStar) { 1279 if (isSyncStar || isAsyncStar) {
1299 // Even though `return expr;` is not allowed in the dart sync* and 1280 // Even though `return expr;` is not allowed in the dart sync* and
1300 // async* code, the backend sometimes generates code like this, but 1281 // async* code, the backend sometimes generates code like this, but
1301 // only when it is known that the 'expr' throws, and the return is just 1282 // only when it is known that the 'expr' throws, and the return is just
1302 // to tell the JavaScript VM that the code won't continue here. 1283 // to tell the JavaScript VM that the code won't continue here.
1303 // It is therefore interpreted as `expr; return;` 1284 // It is therefore interpreted as `expr; return;`
1304 visitExpressionIgnoreResult(node.value); 1285 visitExpressionIgnoreResult(node.value);
1305 } else { 1286 } else {
1306 withExpression(node.value, (js.Expression value) { 1287 withExpression(node.value, (js.Expression value) {
1307 addStatement(js.js.statement("# = #;", [returnValue, value])); 1288 addStatement(js.js.statement("# = #;", [returnValue, value]));
1308 }, store: false); 1289 }, store: false);
(...skipping 61 matching lines...) Expand 10 before | Expand all | Expand 10 after
1370 } else { 1351 } else {
1371 addGoto(labels[defaultIndex]); 1352 addGoto(labels[defaultIndex]);
1372 } 1353 }
1373 } else { 1354 } else {
1374 bool hasDefault = false; 1355 bool hasDefault = false;
1375 int i = 0; 1356 int i = 0;
1376 List<js.SwitchClause> clauses = new List<js.SwitchClause>(); 1357 List<js.SwitchClause> clauses = new List<js.SwitchClause>();
1377 for (js.SwitchClause clause in node.cases) { 1358 for (js.SwitchClause clause in node.cases) {
1378 if (clause is js.Case) { 1359 if (clause is js.Case) {
1379 labels[i] = newLabel("case"); 1360 labels[i] = newLabel("case");
1380 clauses.add(new js.Case(visitExpression(clause.expression), 1361 clauses.add(new js.Case(
1381 gotoAndBreak(labels[i]))); 1362 visitExpression(clause.expression), gotoAndBreak(labels[i])));
1382 } else if (clause is js.Default) { 1363 } else if (clause is js.Default) {
1383 labels[i] = newLabel("default"); 1364 labels[i] = newLabel("default");
1384 clauses.add(new js.Default(gotoAndBreak(labels[i]))); 1365 clauses.add(new js.Default(gotoAndBreak(labels[i])));
1385 hasDefault = true; 1366 hasDefault = true;
1386 } else { 1367 } else {
1387 reporter.internalError( 1368 reporter.internalError(spannable, "Unknown clause type $clause");
1388 spannable, "Unknown clause type $clause");
1389 } 1369 }
1390 i++; 1370 i++;
1391 } 1371 }
1392 if (!hasDefault) { 1372 if (!hasDefault) {
1393 clauses.add(new js.Default(gotoAndBreak(after))); 1373 clauses.add(new js.Default(gotoAndBreak(after)));
1394 } 1374 }
1395 withExpression(node.key, (js.Expression key) { 1375 withExpression(node.key, (js.Expression key) {
1396 addStatement(new js.Switch(key, clauses)); 1376 addStatement(new js.Switch(key, clauses));
1397 }, store: false); 1377 }, store: false);
1398 1378
(...skipping 15 matching lines...) Expand all
1414 } 1394 }
1415 1395
1416 @override 1396 @override
1417 void visitThrow(js.Throw node) { 1397 void visitThrow(js.Throw node) {
1418 withExpression(node.expression, (js.Expression expression) { 1398 withExpression(node.expression, (js.Expression expression) {
1419 addStatement(new js.Throw(expression)); 1399 addStatement(new js.Throw(expression));
1420 }, store: false); 1400 }, store: false);
1421 } 1401 }
1422 1402
1423 setErrorHandler([int errorHandler]) { 1403 setErrorHandler([int errorHandler]) {
1424 js.Expression label = (errorHandler == null) 1404 js.Expression label =
1425 ? currentErrorHandler 1405 (errorHandler == null) ? currentErrorHandler : js.number(errorHandler);
1426 : js.number(errorHandler); 1406 addStatement(js.js.statement('# = #;', [handler, label]));
1427 addStatement(js.js.statement('# = #;',[handler, label]));
1428 } 1407 }
1429 1408
1430 List<int> _finalliesUpToAndEnclosingHandler() { 1409 List<int> _finalliesUpToAndEnclosingHandler() {
1431 List<int> result = new List<int>(); 1410 List<int> result = new List<int>();
1432 for (int i = jumpTargets.length - 1; i >= 0; i--) { 1411 for (int i = jumpTargets.length - 1; i >= 0; i--) {
1433 js.Node node = jumpTargets[i]; 1412 js.Node node = jumpTargets[i];
1434 int handlerLabel = handlerLabels[node]; 1413 int handlerLabel = handlerLabels[node];
1435 if (handlerLabel != null) { 1414 if (handlerLabel != null) {
1436 result.add(handlerLabel); 1415 result.add(handlerLabel);
1437 break; 1416 break;
(...skipping 16 matching lines...) Expand all
1454 translateInBlock(node.catchPart.body)); 1433 translateInBlock(node.catchPart.body));
1455 js.Block finallyPart = (node.finallyPart == null) 1434 js.Block finallyPart = (node.finallyPart == null)
1456 ? null 1435 ? null
1457 : translateInBlock(node.finallyPart); 1436 : translateInBlock(node.finallyPart);
1458 addStatement(new js.Try(body, catchPart, finallyPart)); 1437 addStatement(new js.Try(body, catchPart, finallyPart));
1459 return; 1438 return;
1460 } 1439 }
1461 1440
1462 hasTryBlocks = true; 1441 hasTryBlocks = true;
1463 int uncaughtLabel = newLabel("uncaught"); 1442 int uncaughtLabel = newLabel("uncaught");
1464 int handlerLabel = (node.catchPart == null) 1443 int handlerLabel =
1465 ? uncaughtLabel 1444 (node.catchPart == null) ? uncaughtLabel : newLabel("catch");
1466 : newLabel("catch");
1467 1445
1468 int finallyLabel = newLabel("finally"); 1446 int finallyLabel = newLabel("finally");
1469 int afterFinallyLabel = newLabel("after finally"); 1447 int afterFinallyLabel = newLabel("after finally");
1470 if (node.finallyPart != null) { 1448 if (node.finallyPart != null) {
1471 finallyLabels[node.finallyPart] = finallyLabel; 1449 finallyLabels[node.finallyPart] = finallyLabel;
1472 jumpTargets.add(node.finallyPart); 1450 jumpTargets.add(node.finallyPart);
1473 } 1451 }
1474 1452
1475 handlerLabels[node] = handlerLabel; 1453 handlerLabels[node] = handlerLabel;
1476 jumpTargets.add(node); 1454 jumpTargets.add(node);
(...skipping 30 matching lines...) Expand all
1507 String errorRename = freshName(node.catchPart.declaration.name); 1485 String errorRename = freshName(node.catchPart.declaration.name);
1508 localVariables.add(new js.VariableDeclaration(errorRename)); 1486 localVariables.add(new js.VariableDeclaration(errorRename));
1509 variableRenamings 1487 variableRenamings
1510 .add(new Pair(node.catchPart.declaration.name, errorRename)); 1488 .add(new Pair(node.catchPart.declaration.name, errorRename));
1511 addStatement(js.js.statement("# = #;", [errorRename, currentError])); 1489 addStatement(js.js.statement("# = #;", [errorRename, currentError]));
1512 visitStatement(node.catchPart.body); 1490 visitStatement(node.catchPart.body);
1513 variableRenamings.removeLast(); 1491 variableRenamings.removeLast();
1514 if (node.finallyPart != null) { 1492 if (node.finallyPart != null) {
1515 // The error has been caught, so after the finally, continue after the 1493 // The error has been caught, so after the finally, continue after the
1516 // try. 1494 // try.
1517 addStatement( 1495 addStatement(js.js
1518 js.js.statement("#.push(#);", 1496 .statement("#.push(#);", [next, js.number(afterFinallyLabel)]));
1519 [next, js.number(afterFinallyLabel)]));
1520 addGoto(finallyLabel); 1497 addGoto(finallyLabel);
1521 } else { 1498 } else {
1522 addGoto(afterFinallyLabel); 1499 addGoto(afterFinallyLabel);
1523 } 1500 }
1524 js.Node last = jumpTargets.removeLast(); 1501 js.Node last = jumpTargets.removeLast();
1525 assert(last == node.catchPart); 1502 assert(last == node.catchPart);
1526 } 1503 }
1527 1504
1528 // The "uncaught"-handler tells the finally-block to continue with 1505 // The "uncaught"-handler tells the finally-block to continue with
1529 // the enclosing finally-blocks until the current catch-handler. 1506 // the enclosing finally-blocks until the current catch-handler.
1530 beginLabel(uncaughtLabel); 1507 beginLabel(uncaughtLabel);
1531 1508
1532 List<int> enclosingFinallies = _finalliesUpToAndEnclosingHandler(); 1509 List<int> enclosingFinallies = _finalliesUpToAndEnclosingHandler();
1533 1510
1534 int nextLabel = enclosingFinallies.removeLast(); 1511 int nextLabel = enclosingFinallies.removeLast();
1535 if (enclosingFinallies.isNotEmpty) { 1512 if (enclosingFinallies.isNotEmpty) {
1536 // [enclosingFinallies] can be empty if there is no surrounding finally 1513 // [enclosingFinallies] can be empty if there is no surrounding finally
1537 // blocks. Then [nextLabel] will be [rethrowLabel]. 1514 // blocks. Then [nextLabel] will be [rethrowLabel].
1538 addStatement( 1515 addStatement(js.js.statement("# = #;", [
1539 js.js.statement("# = #;", [next, new js.ArrayInitializer( 1516 next,
1540 enclosingFinallies.map(js.number).toList())])); 1517 new js.ArrayInitializer(enclosingFinallies.map(js.number).toList())
1518 ]));
1541 } 1519 }
1542 if (node.finallyPart == null) { 1520 if (node.finallyPart == null) {
1543 // The finally-block belonging to [node] will be visited because of 1521 // The finally-block belonging to [node] will be visited because of
1544 // fallthrough. If it does not exist, add an explicit goto. 1522 // fallthrough. If it does not exist, add an explicit goto.
1545 addGoto(nextLabel); 1523 addGoto(nextLabel);
1546 } 1524 }
1547 if (node.finallyPart != null) { 1525 if (node.finallyPart != null) {
1548 js.Node last = jumpTargets.removeLast(); 1526 js.Node last = jumpTargets.removeLast();
1549 assert(last == node.finallyPart); 1527 assert(last == node.finallyPart);
1550 1528
(...skipping 28 matching lines...) Expand all
1579 } 1557 }
1580 1558
1581 @override 1559 @override
1582 void visitVariableInitialization(js.VariableInitialization node) { 1560 void visitVariableInitialization(js.VariableInitialization node) {
1583 unreachable(node); 1561 unreachable(node);
1584 } 1562 }
1585 1563
1586 @override 1564 @override
1587 js.Expression visitVariableUse(js.VariableUse node) { 1565 js.Expression visitVariableUse(js.VariableUse node) {
1588 Pair<String, String> renaming = variableRenamings.lastWhere( 1566 Pair<String, String> renaming = variableRenamings.lastWhere(
1589 (Pair renaming) => renaming.a == node.name, orElse: () => null); 1567 (Pair renaming) => renaming.a == node.name,
1568 orElse: () => null);
1590 if (renaming == null) return node; 1569 if (renaming == null) return node;
1591 return new js.VariableUse(renaming.b); 1570 return new js.VariableUse(renaming.b);
1592 } 1571 }
1593 1572
1594 @override 1573 @override
1595 void visitWhile(js.While node) { 1574 void visitWhile(js.While node) {
1596 if (!shouldTransform(node)) { 1575 if (!shouldTransform(node)) {
1597 bool oldInsideUntranslated = insideUntranslatedBreakable; 1576 bool oldInsideUntranslated = insideUntranslatedBreakable;
1598 insideUntranslatedBreakable = true; 1577 insideUntranslatedBreakable = true;
1599 withExpression(node.condition, (js.Expression condition) { 1578 withExpression(node.condition, (js.Expression condition) {
(...skipping 32 matching lines...) Expand 10 before | Expand all | Expand 10 after
1632 // Don't do a break here for the goto, but instead a return in either 1611 // Don't do a break here for the goto, but instead a return in either
1633 // addSynYield or addAsyncYield. 1612 // addSynYield or addAsyncYield.
1634 withExpression(node.expression, (js.Expression expression) { 1613 withExpression(node.expression, (js.Expression expression) {
1635 addStatement(setGotoVariable(label)); 1614 addStatement(setGotoVariable(label));
1636 addYield(node, expression); 1615 addYield(node, expression);
1637 }, store: false); 1616 }, store: false);
1638 beginLabel(label); 1617 beginLabel(label);
1639 } 1618 }
1640 } 1619 }
1641 1620
1642 js.VariableInitialization 1621 js.VariableInitialization _makeVariableInitializer(
1643 _makeVariableInitializer(dynamic variable, js.Expression initValue) { 1622 dynamic variable, js.Expression initValue) {
1644 js.VariableDeclaration declaration; 1623 js.VariableDeclaration declaration;
1645 if (variable is js.VariableUse) { 1624 if (variable is js.VariableUse) {
1646 declaration = new js.VariableDeclaration(variable.name); 1625 declaration = new js.VariableDeclaration(variable.name);
1647 } else if (variable is String) { 1626 } else if (variable is String) {
1648 declaration = new js.VariableDeclaration(variable); 1627 declaration = new js.VariableDeclaration(variable);
1649 } else { 1628 } else {
1650 assert(variable is js.VariableDeclaration); 1629 assert(variable is js.VariableDeclaration);
1651 declaration = variable; 1630 declaration = variable;
1652 } 1631 }
1653 return new js.VariableInitialization(declaration, initValue); 1632 return new js.VariableInitialization(declaration, initValue);
1654 } 1633 }
1655 1634
1656 class AsyncRewriter extends AsyncRewriterBase { 1635 class AsyncRewriter extends AsyncRewriterBase {
1657
1658 bool get isAsync => true; 1636 bool get isAsync => true;
1659 1637
1660 /// The Completer that will finish an async function. 1638 /// The Completer that will finish an async function.
1661 /// 1639 ///
1662 /// Not used for sync* or async* functions. 1640 /// Not used for sync* or async* functions.
1663 String completerName; 1641 String completerName;
1664 js.VariableUse get completer => new js.VariableUse(completerName); 1642 js.VariableUse get completer => new js.VariableUse(completerName);
1665 1643
1666 /// The function called by an async function to simulate an await or return. 1644 /// The function called by an async function to simulate an await or return.
1667 /// 1645 ///
(...skipping 16 matching lines...) Expand all
1684 /// - The completer object [completer] 1662 /// - The completer object [completer]
1685 final js.Expression asyncHelper; 1663 final js.Expression asyncHelper;
1686 1664
1687 /// Contructor used to initialize the [completer] variable. 1665 /// Contructor used to initialize the [completer] variable.
1688 /// 1666 ///
1689 /// Specific to async methods. 1667 /// Specific to async methods.
1690 final js.Expression newCompleter; 1668 final js.Expression newCompleter;
1691 1669
1692 final js.Expression wrapBody; 1670 final js.Expression wrapBody;
1693 1671
1694 AsyncRewriter(DiagnosticReporter reporter, 1672 AsyncRewriter(DiagnosticReporter reporter, Spannable spannable,
1695 Spannable spannable, 1673 {this.asyncHelper,
1696 {this.asyncHelper, 1674 this.newCompleter,
1697 this.newCompleter, 1675 this.wrapBody,
1698 this.wrapBody, 1676 String safeVariableName(String proposedName),
1699 String safeVariableName(String proposedName), 1677 js.Name bodyName})
1700 js.Name bodyName}) 1678 : super(reporter, spannable, safeVariableName, bodyName);
1701 : super(reporter,
1702 spannable,
1703 safeVariableName,
1704 bodyName);
1705 1679
1706 @override 1680 @override
1707 void addYield(js.DartYield node, js.Expression expression) { 1681 void addYield(js.DartYield node, js.Expression expression) {
1708 reporter.internalError(spannable, 1682 reporter.internalError(spannable, "Yield in non-generating async function");
1709 "Yield in non-generating async function");
1710 } 1683 }
1711 1684
1712 void addErrorExit() { 1685 void addErrorExit() {
1713 beginLabel(rethrowLabel); 1686 beginLabel(rethrowLabel);
1714 addStatement(js.js.statement( 1687 addStatement(js.js.statement(
1715 "return #thenHelper(#currentError, #errorCode, #completer);", { 1688 "return #thenHelper(#currentError, #errorCode, #completer);", {
1716 "thenHelper": asyncHelper, 1689 "thenHelper": asyncHelper,
1717 "errorCode": js.number(error_codes.ERROR), 1690 "errorCode": js.number(error_codes.ERROR),
1718 "currentError": currentError, 1691 "currentError": currentError,
1719 "completer": completer})); 1692 "completer": completer
1693 }));
1720 } 1694 }
1721 1695
1722 /// Returning from an async method calls [asyncStarHelper] with the result. 1696 /// Returning from an async method calls [asyncStarHelper] with the result.
1723 /// (the result might have been stored in [returnValue] by some finally 1697 /// (the result might have been stored in [returnValue] by some finally
1724 /// block). 1698 /// block).
1725 void addSuccesExit() { 1699 void addSuccesExit() {
1726 if (analysis.hasExplicitReturns) { 1700 if (analysis.hasExplicitReturns) {
1727 beginLabel(exitLabel); 1701 beginLabel(exitLabel);
1728 } else { 1702 } else {
1729 addStatement(new js.Comment("implicit return")); 1703 addStatement(new js.Comment("implicit return"));
1730 } 1704 }
1731 addStatement(js.js.statement( 1705 addStatement(js.js.statement(
1732 "return #runtimeHelper(#returnValue, #successCode, " 1706 "return #runtimeHelper(#returnValue, #successCode, "
1733 "#completer, null);", { 1707 "#completer, null);",
1734 "runtimeHelper": asyncHelper, 1708 {
1735 "successCode": js.number(error_codes.SUCCESS), 1709 "runtimeHelper": asyncHelper,
1736 "returnValue": analysis.hasExplicitReturns 1710 "successCode": js.number(error_codes.SUCCESS),
1737 ? returnValue 1711 "returnValue":
1738 : new js.LiteralNull(), 1712 analysis.hasExplicitReturns ? returnValue : new js.LiteralNull(),
1739 "completer": completer})); 1713 "completer": completer
1714 }));
1740 } 1715 }
1741 1716
1742 @override 1717 @override
1743 Iterable<js.VariableInitialization> variableInitializations() { 1718 Iterable<js.VariableInitialization> variableInitializations() {
1744 List<js.VariableInitialization> variables = 1719 List<js.VariableInitialization> variables =
1745 new List<js.VariableInitialization>(); 1720 new List<js.VariableInitialization>();
1746 variables.add(_makeVariableInitializer(completer, 1721 variables
1747 new js.New(newCompleter, []))); 1722 .add(_makeVariableInitializer(completer, new js.New(newCompleter, [])));
1748 if (analysis.hasExplicitReturns) { 1723 if (analysis.hasExplicitReturns) {
1749 variables.add(_makeVariableInitializer(returnValue, null)); 1724 variables.add(_makeVariableInitializer(returnValue, null));
1750 } 1725 }
1751 return variables; 1726 return variables;
1752 } 1727 }
1753 1728
1754 @override 1729 @override
1755 void initializeNames() { 1730 void initializeNames() {
1756 completerName = freshName("completer"); 1731 completerName = freshName("completer");
1757 } 1732 }
1758 1733
1759 @override 1734 @override
1760 js.Statement awaitStatement(js.Expression value) { 1735 js.Statement awaitStatement(js.Expression value) {
1761 return js.js.statement(""" 1736 return js.js.statement(
1737 """
1762 return #asyncHelper(#value, 1738 return #asyncHelper(#value,
1763 #bodyName, 1739 #bodyName,
1764 #completer); 1740 #completer);
1765 """, { 1741 """,
1766 "asyncHelper": asyncHelper, 1742 {
1767 "value": value, 1743 "asyncHelper": asyncHelper,
1768 "bodyName": bodyName, 1744 "value": value,
1769 "completer": completer}); 1745 "bodyName": bodyName,
1746 "completer": completer
1747 });
1770 } 1748 }
1771 1749
1772 @override 1750 @override
1773 js.Fun finishFunction(List<js.Parameter> parameters, 1751 js.Fun finishFunction(
1774 js.Statement rewrittenBody, 1752 List<js.Parameter> parameters,
1775 js.VariableDeclarationList variableDeclarations) { 1753 js.Statement rewrittenBody,
1776 return js.js(""" 1754 js.VariableDeclarationList variableDeclarations) {
1755 return js.js(
1756 """
1777 function (#parameters) { 1757 function (#parameters) {
1778 #variableDeclarations; 1758 #variableDeclarations;
1779 var #bodyName = #wrapBody(function (#errorCode, #result) { 1759 var #bodyName = #wrapBody(function (#errorCode, #result) {
1780 if (#errorCode === #ERROR) { 1760 if (#errorCode === #ERROR) {
1781 #currentError = #result; 1761 #currentError = #result;
1782 #goto = #handler; 1762 #goto = #handler;
1783 } 1763 }
1784 #rewrittenBody; 1764 #rewrittenBody;
1785 }); 1765 });
1786 return #asyncHelper(null, #bodyName, #completer, null); 1766 return #asyncHelper(null, #bodyName, #completer, null);
1787 }""", { 1767 }""",
1768 {
1788 "parameters": parameters, 1769 "parameters": parameters,
1789 "variableDeclarations": variableDeclarations, 1770 "variableDeclarations": variableDeclarations,
1790 "ERROR": js.number(error_codes.ERROR), 1771 "ERROR": js.number(error_codes.ERROR),
1791 "rewrittenBody": rewrittenBody, 1772 "rewrittenBody": rewrittenBody,
1792 "bodyName": bodyName, 1773 "bodyName": bodyName,
1793 "currentError": currentError, 1774 "currentError": currentError,
1794 "goto": goto, 1775 "goto": goto,
1795 "handler": handler, 1776 "handler": handler,
1796 "errorCode": errorCodeName, 1777 "errorCode": errorCodeName,
1797 "result": resultName, 1778 "result": resultName,
1798 "asyncHelper": asyncHelper, 1779 "asyncHelper": asyncHelper,
1799 "completer": completer, 1780 "completer": completer,
1800 "wrapBody": wrapBody, 1781 "wrapBody": wrapBody,
1801 }); 1782 });
1802 } 1783 }
1803 } 1784 }
1804 1785
1805 class SyncStarRewriter extends AsyncRewriterBase { 1786 class SyncStarRewriter extends AsyncRewriterBase {
1806
1807 bool get isSyncStar => true; 1787 bool get isSyncStar => true;
1808 1788
1809 /// Contructor creating the Iterable for a sync* method. Called with 1789 /// Contructor creating the Iterable for a sync* method. Called with
1810 /// [bodyName]. 1790 /// [bodyName].
1811 final js.Expression newIterable; 1791 final js.Expression newIterable;
1812 1792
1813 /// A JS Expression that creates a marker showing that iteration is over. 1793 /// A JS Expression that creates a marker showing that iteration is over.
1814 /// 1794 ///
1815 /// Called without arguments. 1795 /// Called without arguments.
1816 final js.Expression endOfIteration; 1796 final js.Expression endOfIteration;
1817 1797
1818 /// A JS Expression that creates a marker indication a 'yield*' statement. 1798 /// A JS Expression that creates a marker indication a 'yield*' statement.
1819 /// 1799 ///
1820 /// Called with the stream to yield from. 1800 /// Called with the stream to yield from.
1821 final js.Expression yieldStarExpression; 1801 final js.Expression yieldStarExpression;
1822 1802
1823 /// Used by sync* functions to throw exeptions. 1803 /// Used by sync* functions to throw exeptions.
1824 final js.Expression uncaughtErrorExpression; 1804 final js.Expression uncaughtErrorExpression;
1825 1805
1826 SyncStarRewriter(DiagnosticReporter diagnosticListener, 1806 SyncStarRewriter(DiagnosticReporter diagnosticListener, spannable,
1827 spannable, 1807 {this.endOfIteration,
1828 {this.endOfIteration, 1808 this.newIterable,
1829 this.newIterable, 1809 this.yieldStarExpression,
1830 this.yieldStarExpression, 1810 this.uncaughtErrorExpression,
1831 this.uncaughtErrorExpression, 1811 String safeVariableName(String proposedName),
1832 String safeVariableName(String proposedName), 1812 js.Name bodyName})
1833 js.Name bodyName}) 1813 : super(diagnosticListener, spannable, safeVariableName, bodyName);
1834 : super(diagnosticListener,
1835 spannable,
1836 safeVariableName,
1837 bodyName);
1838 1814
1839 /// Translates a yield/yield* in an sync*. 1815 /// Translates a yield/yield* in an sync*.
1840 /// 1816 ///
1841 /// `yield` in a sync* function just returns [value]. 1817 /// `yield` in a sync* function just returns [value].
1842 /// `yield*` wraps [value] in a [yieldStarExpression] and returns it. 1818 /// `yield*` wraps [value] in a [yieldStarExpression] and returns it.
1843 @override 1819 @override
1844 void addYield(js.DartYield node, js.Expression expression) { 1820 void addYield(js.DartYield node, js.Expression expression) {
1845 if (node.hasStar) { 1821 if (node.hasStar) {
1846 addStatement( 1822 addStatement(
1847 new js.Return(new js.Call(yieldStarExpression, [expression]))); 1823 new js.Return(new js.Call(yieldStarExpression, [expression])));
1848 } else { 1824 } else {
1849 addStatement(new js.Return(expression)); 1825 addStatement(new js.Return(expression));
1850 } 1826 }
1851 } 1827 }
1852 1828
1853 @override 1829 @override
1854 js.Fun finishFunction(List<js.Parameter> parameters, 1830 js.Fun finishFunction(
1855 js.Statement rewrittenBody, 1831 List<js.Parameter> parameters,
1856 js.VariableDeclarationList variableDeclarations) { 1832 js.Statement rewrittenBody,
1833 js.VariableDeclarationList variableDeclarations) {
1857 // Each iterator invocation on the iterable should work on its own copy of 1834 // Each iterator invocation on the iterable should work on its own copy of
1858 // the parameters. 1835 // the parameters.
1859 // TODO(sigurdm): We only need to do this copying for parameters that are 1836 // TODO(sigurdm): We only need to do this copying for parameters that are
1860 // mutated. 1837 // mutated.
1861 List<js.VariableInitialization> declarations = 1838 List<js.VariableInitialization> declarations =
1862 new List<js.VariableInitialization>(); 1839 new List<js.VariableInitialization>();
1863 List<js.Parameter> renamedParameters = new List<js.Parameter>(); 1840 List<js.Parameter> renamedParameters = new List<js.Parameter>();
1864 for (js.Parameter parameter in parameters) { 1841 for (js.Parameter parameter in parameters) {
1865 String name = parameter.name; 1842 String name = parameter.name;
1866 String renamedName = freshName(name); 1843 String renamedName = freshName(name);
1867 renamedParameters.add(new js.Parameter(renamedName)); 1844 renamedParameters.add(new js.Parameter(renamedName));
1868 declarations.add( 1845 declarations.add(new js.VariableInitialization(
1869 new js.VariableInitialization(new js.VariableDeclaration(name), 1846 new js.VariableDeclaration(name), new js.VariableUse(renamedName)));
1870 new js.VariableUse(renamedName)));
1871 } 1847 }
1872 js.VariableDeclarationList copyParameters = 1848 js.VariableDeclarationList copyParameters =
1873 new js.VariableDeclarationList(declarations); 1849 new js.VariableDeclarationList(declarations);
1874 return js.js(""" 1850 return js.js(
1851 """
1875 function (#renamedParameters) { 1852 function (#renamedParameters) {
1876 if (#needsThis) 1853 if (#needsThis)
1877 var #self = this; 1854 var #self = this;
1878 return new #newIterable(function () { 1855 return new #newIterable(function () {
1879 if (#hasParameters) { 1856 if (#hasParameters) {
1880 #copyParameters; 1857 #copyParameters;
1881 } 1858 }
1882 #varDecl; 1859 #varDecl;
1883 return function #body(#errorCode, #result) { 1860 return function #body(#errorCode, #result) {
1884 if (#errorCode === #ERROR) { 1861 if (#errorCode === #ERROR) {
1885 #currentError = #result; 1862 #currentError = #result;
1886 #goto = #handler; 1863 #goto = #handler;
1887 } 1864 }
1888 #helperBody; 1865 #helperBody;
1889 }; 1866 };
1890 }); 1867 });
1891 } 1868 }
1892 """, { 1869 """,
1893 "renamedParameters": renamedParameters, 1870 {
1894 "needsThis": analysis.hasThis, 1871 "renamedParameters": renamedParameters,
1895 "helperBody": rewrittenBody, 1872 "needsThis": analysis.hasThis,
1896 "hasParameters": parameters.isNotEmpty, 1873 "helperBody": rewrittenBody,
1897 "copyParameters": copyParameters, 1874 "hasParameters": parameters.isNotEmpty,
1898 "varDecl": variableDeclarations, 1875 "copyParameters": copyParameters,
1899 "errorCode": errorCodeName, 1876 "varDecl": variableDeclarations,
1900 "newIterable": newIterable, 1877 "errorCode": errorCodeName,
1901 "body": bodyName, 1878 "newIterable": newIterable,
1902 "self": selfName, 1879 "body": bodyName,
1903 "result": resultName, 1880 "self": selfName,
1904 "goto": goto, 1881 "result": resultName,
1905 "handler": handler, 1882 "goto": goto,
1906 "currentError": currentErrorName, 1883 "handler": handler,
1907 "ERROR": js.number(error_codes.ERROR), 1884 "currentError": currentErrorName,
1908 }); 1885 "ERROR": js.number(error_codes.ERROR),
1886 });
1909 } 1887 }
1910 1888
1911 void addErrorExit() { 1889 void addErrorExit() {
1912 beginLabel(rethrowLabel); 1890 beginLabel(rethrowLabel);
1913 addStatement(js.js.statement('return #(#);', 1891 addStatement(js.js
1914 [uncaughtErrorExpression, currentError])); 1892 .statement('return #(#);', [uncaughtErrorExpression, currentError]));
1915 } 1893 }
1916 1894
1917 /// Returning from a sync* function returns an [endOfIteration] marker. 1895 /// Returning from a sync* function returns an [endOfIteration] marker.
1918 void addSuccesExit() { 1896 void addSuccesExit() {
1919 if (analysis.hasExplicitReturns) { 1897 if (analysis.hasExplicitReturns) {
1920 beginLabel(exitLabel); 1898 beginLabel(exitLabel);
1921 } else { 1899 } else {
1922 addStatement(new js.Comment("implicit return")); 1900 addStatement(new js.Comment("implicit return"));
1923 } 1901 }
1924 addStatement(js.js.statement('return #();', [endOfIteration])); 1902 addStatement(js.js.statement('return #();', [endOfIteration]));
1925 } 1903 }
1926 1904
1927 @override 1905 @override
1928 Iterable<js.VariableInitialization> variableInitializations() { 1906 Iterable<js.VariableInitialization> variableInitializations() {
1929 List<js.VariableInitialization> variables = 1907 List<js.VariableInitialization> variables =
1930 new List<js.VariableInitialization>(); 1908 new List<js.VariableInitialization>();
1931 return variables; 1909 return variables;
1932 } 1910 }
1933 1911
1934 @override 1912 @override
1935 js.Statement awaitStatement(js.Expression value) { 1913 js.Statement awaitStatement(js.Expression value) {
1936 throw reporter.internalError(spannable, 1914 throw reporter.internalError(
1937 "Sync* functions cannot contain await statements."); 1915 spannable, "Sync* functions cannot contain await statements.");
1938 } 1916 }
1939 1917
1940 @override 1918 @override
1941 void initializeNames() {} 1919 void initializeNames() {}
1942 } 1920 }
1943 1921
1944 class AsyncStarRewriter extends AsyncRewriterBase { 1922 class AsyncStarRewriter extends AsyncRewriterBase {
1945
1946 bool get isAsyncStar => true; 1923 bool get isAsyncStar => true;
1947 1924
1948 /// The stack of labels of finally blocks to assign to [next] if the 1925 /// The stack of labels of finally blocks to assign to [next] if the
1949 /// async* [StreamSubscription] was canceled during a yield. 1926 /// async* [StreamSubscription] was canceled during a yield.
1950 js.VariableUse get nextWhenCanceled { 1927 js.VariableUse get nextWhenCanceled {
1951 return new js.VariableUse(nextWhenCanceledName); 1928 return new js.VariableUse(nextWhenCanceledName);
1952 } 1929 }
1930
1953 String nextWhenCanceledName; 1931 String nextWhenCanceledName;
1954 1932
1955 /// The StreamController that controls an async* function. 1933 /// The StreamController that controls an async* function.
1956 String controllerName; 1934 String controllerName;
1957 js.VariableUse get controller => new js.VariableUse(controllerName); 1935 js.VariableUse get controller => new js.VariableUse(controllerName);
1958 1936
1959 /// The function called by an async* function to simulate an await, yield or 1937 /// The function called by an async* function to simulate an await, yield or
1960 /// yield*. 1938 /// yield*.
1961 /// 1939 ///
1962 /// For an await/yield/yield* it is called with: 1940 /// For an await/yield/yield* it is called with:
(...skipping 24 matching lines...) Expand all
1987 /// Called with the value to yield. 1965 /// Called with the value to yield.
1988 final js.Expression yieldExpression; 1966 final js.Expression yieldExpression;
1989 1967
1990 /// A JS Expression that creates a marker indication a 'yield*' statement. 1968 /// A JS Expression that creates a marker indication a 'yield*' statement.
1991 /// 1969 ///
1992 /// Called with the stream to yield from. 1970 /// Called with the stream to yield from.
1993 final js.Expression yieldStarExpression; 1971 final js.Expression yieldStarExpression;
1994 1972
1995 final js.Expression wrapBody; 1973 final js.Expression wrapBody;
1996 1974
1997 AsyncStarRewriter(DiagnosticReporter reporter, 1975 AsyncStarRewriter(DiagnosticReporter reporter, Spannable spannable,
1998 Spannable spannable, 1976 {this.asyncStarHelper,
1999 {this.asyncStarHelper, 1977 this.streamOfController,
2000 this.streamOfController, 1978 this.newController,
2001 this.newController, 1979 this.yieldExpression,
2002 this.yieldExpression, 1980 this.yieldStarExpression,
2003 this.yieldStarExpression, 1981 this.wrapBody,
2004 this.wrapBody, 1982 String safeVariableName(String proposedName),
2005 String safeVariableName(String proposedName), 1983 js.Name bodyName})
2006 js.Name bodyName}) 1984 : super(reporter, spannable, safeVariableName, bodyName);
2007 : super(reporter,
2008 spannable,
2009 safeVariableName,
2010 bodyName);
2011
2012 1985
2013 /// Translates a yield/yield* in an async* function. 1986 /// Translates a yield/yield* in an async* function.
2014 /// 1987 ///
2015 /// yield/yield* in an async* function is translated much like the `await` is 1988 /// yield/yield* in an async* function is translated much like the `await` is
2016 /// translated in [visitAwait], only the object is wrapped in a 1989 /// translated in [visitAwait], only the object is wrapped in a
2017 /// [yieldExpression]/[yieldStarExpression] to let [asyncStarHelper] 1990 /// [yieldExpression]/[yieldStarExpression] to let [asyncStarHelper]
2018 /// distinguish them. 1991 /// distinguish them.
2019 /// Also [nextWhenCanceled] is set up to contain the finally blocks that 1992 /// Also [nextWhenCanceled] is set up to contain the finally blocks that
2020 /// must be run in case the stream was canceled. 1993 /// must be run in case the stream was canceled.
2021 @override 1994 @override
2022 void addYield(js.DartYield node, js.Expression expression) { 1995 void addYield(js.DartYield node, js.Expression expression) {
2023 // Find all the finally blocks that should be performed if the stream is 1996 // Find all the finally blocks that should be performed if the stream is
2024 // canceled during the yield. 1997 // canceled during the yield.
2025 // At the bottom of the stack is the return label. 1998 // At the bottom of the stack is the return label.
2026 List<int> enclosingFinallyLabels = <int>[exitLabel]; 1999 List<int> enclosingFinallyLabels = <int>[exitLabel];
2027 enclosingFinallyLabels.addAll(jumpTargets 2000 enclosingFinallyLabels.addAll(jumpTargets
2028 .where((js.Node node) => finallyLabels[node] != null) 2001 .where((js.Node node) => finallyLabels[node] != null)
2029 .map((js.Block node) => finallyLabels[node])); 2002 .map((js.Block node) => finallyLabels[node]));
2030 addStatement(js.js.statement("# = #;", 2003 addStatement(js.js.statement("# = #;", [
2031 [nextWhenCanceled, new js.ArrayInitializer( 2004 nextWhenCanceled,
2032 enclosingFinallyLabels.map(js.number).toList())])); 2005 new js.ArrayInitializer(enclosingFinallyLabels.map(js.number).toList())
2033 addStatement(js.js.statement(""" 2006 ]));
2007 addStatement(js.js.statement(
2008 """
2034 return #asyncStarHelper(#yieldExpression(#expression), #bodyName, 2009 return #asyncStarHelper(#yieldExpression(#expression), #bodyName,
2035 #controller);""", { 2010 #controller);""",
2036 "asyncStarHelper": asyncStarHelper, 2011 {
2037 "yieldExpression": node.hasStar ? yieldStarExpression : yieldExpression, 2012 "asyncStarHelper": asyncStarHelper,
2038 "expression": expression, 2013 "yieldExpression":
2039 "bodyName": bodyName, 2014 node.hasStar ? yieldStarExpression : yieldExpression,
2040 "controller": controllerName, 2015 "expression": expression,
2041 })); 2016 "bodyName": bodyName,
2017 "controller": controllerName,
2018 }));
2042 } 2019 }
2043 2020
2044 @override 2021 @override
2045 js.Fun finishFunction(List<js.Parameter> parameters, 2022 js.Fun finishFunction(
2046 js.Statement rewrittenBody, 2023 List<js.Parameter> parameters,
2047 js.VariableDeclarationList variableDeclarations) { 2024 js.Statement rewrittenBody,
2048 return js.js(""" 2025 js.VariableDeclarationList variableDeclarations) {
2026 return js.js(
2027 """
2049 function (#parameters) { 2028 function (#parameters) {
2050 var #bodyName = #wrapBody(function (#errorCode, #result) { 2029 var #bodyName = #wrapBody(function (#errorCode, #result) {
2051 if (#hasYield) { 2030 if (#hasYield) {
2052 switch (#errorCode) { 2031 switch (#errorCode) {
2053 case #STREAM_WAS_CANCELED: 2032 case #STREAM_WAS_CANCELED:
2054 #next = #nextWhenCanceled; 2033 #next = #nextWhenCanceled;
2055 #goto = #next.pop(); 2034 #goto = #next.pop();
2056 break; 2035 break;
2057 case #ERROR: 2036 case #ERROR:
2058 #currentError = #result; 2037 #currentError = #result;
2059 #goto = #handler; 2038 #goto = #handler;
2060 } 2039 }
2061 } else { 2040 } else {
2062 if (#errorCode === #ERROR) { 2041 if (#errorCode === #ERROR) {
2063 #currentError = #result; 2042 #currentError = #result;
2064 #goto = #handler; 2043 #goto = #handler;
2065 } 2044 }
2066 } 2045 }
2067 #rewrittenBody; 2046 #rewrittenBody;
2068 }); 2047 });
2069 #variableDeclarations; 2048 #variableDeclarations;
2070 return #streamOfController(#controller); 2049 return #streamOfController(#controller);
2071 }""", { 2050 }""",
2051 {
2072 "parameters": parameters, 2052 "parameters": parameters,
2073 "variableDeclarations": variableDeclarations, 2053 "variableDeclarations": variableDeclarations,
2074 "STREAM_WAS_CANCELED": js.number(error_codes.STREAM_WAS_CANCELED), 2054 "STREAM_WAS_CANCELED": js.number(error_codes.STREAM_WAS_CANCELED),
2075 "ERROR": js.number(error_codes.ERROR), 2055 "ERROR": js.number(error_codes.ERROR),
2076 "hasYield": analysis.hasYield, 2056 "hasYield": analysis.hasYield,
2077 "rewrittenBody": rewrittenBody, 2057 "rewrittenBody": rewrittenBody,
2078 "bodyName": bodyName, 2058 "bodyName": bodyName,
2079 "currentError": currentError, 2059 "currentError": currentError,
2080 "goto": goto, 2060 "goto": goto,
2081 "handler": handler, 2061 "handler": handler,
2082 "next": next, 2062 "next": next,
2083 "nextWhenCanceled": nextWhenCanceled, 2063 "nextWhenCanceled": nextWhenCanceled,
2084 "errorCode": errorCodeName, 2064 "errorCode": errorCodeName,
2085 "result": resultName, 2065 "result": resultName,
2086 "streamOfController": streamOfController, 2066 "streamOfController": streamOfController,
2087 "controller": controllerName, 2067 "controller": controllerName,
2088 "wrapBody": wrapBody, 2068 "wrapBody": wrapBody,
2089 }); 2069 });
2090 } 2070 }
2091 2071
2092 @override 2072 @override
2093 void addErrorExit() { 2073 void addErrorExit() {
2094 beginLabel(rethrowLabel); 2074 beginLabel(rethrowLabel);
2095 addStatement(js.js.statement( 2075 addStatement(js.js.statement(
2096 "return #asyncHelper(#currentError, #errorCode, #controller);", { 2076 "return #asyncHelper(#currentError, #errorCode, #controller);", {
2097 "asyncHelper": asyncStarHelper, 2077 "asyncHelper": asyncStarHelper,
2098 "errorCode": js.number(error_codes.ERROR), 2078 "errorCode": js.number(error_codes.ERROR),
2099 "currentError": currentError, 2079 "currentError": currentError,
2100 "controller": controllerName})); 2080 "controller": controllerName
2081 }));
2101 } 2082 }
2102 2083
2103 /// Returning from an async* function calls the [streamHelper] with an 2084 /// Returning from an async* function calls the [streamHelper] with an
2104 /// [endOfIteration] marker. 2085 /// [endOfIteration] marker.
2105 @override 2086 @override
2106 void addSuccesExit() { 2087 void addSuccesExit() {
2107 beginLabel(exitLabel); 2088 beginLabel(exitLabel);
2108 2089
2109 addStatement(js.js.statement( 2090 addStatement(js.js
2110 "return #streamHelper(null, #successCode, #controller);", { 2091 .statement("return #streamHelper(null, #successCode, #controller);", {
2111 "streamHelper": asyncStarHelper, 2092 "streamHelper": asyncStarHelper,
2112 "successCode": js.number(error_codes.SUCCESS), 2093 "successCode": js.number(error_codes.SUCCESS),
2113 "controller": controllerName})); 2094 "controller": controllerName
2095 }));
2114 } 2096 }
2115 2097
2116 @override 2098 @override
2117 Iterable<js.VariableInitialization> variableInitializations() { 2099 Iterable<js.VariableInitialization> variableInitializations() {
2118 List<js.VariableInitialization> variables = 2100 List<js.VariableInitialization> variables =
2119 new List<js.VariableInitialization>(); 2101 new List<js.VariableInitialization>();
2120 variables.add(_makeVariableInitializer(controller, 2102 variables.add(_makeVariableInitializer(
2121 js.js('#(#)', 2103 controller, js.js('#(#)', [newController, bodyName])));
2122 [newController, bodyName])));
2123 if (analysis.hasYield) { 2104 if (analysis.hasYield) {
2124 variables.add(_makeVariableInitializer(nextWhenCanceled, null)); 2105 variables.add(_makeVariableInitializer(nextWhenCanceled, null));
2125 } 2106 }
2126 return variables; 2107 return variables;
2127 } 2108 }
2128 2109
2129 @override 2110 @override
2130 void initializeNames() { 2111 void initializeNames() {
2131 controllerName = freshName("controller"); 2112 controllerName = freshName("controller");
2132 nextWhenCanceledName = freshName("nextWhenCanceled"); 2113 nextWhenCanceledName = freshName("nextWhenCanceled");
2133 } 2114 }
2134 2115
2135 @override 2116 @override
2136 js.Statement awaitStatement(js.Expression value) { 2117 js.Statement awaitStatement(js.Expression value) {
2137 return js.js.statement(""" 2118 return js.js.statement(
2119 """
2138 return #asyncHelper(#value, 2120 return #asyncHelper(#value,
2139 #bodyName, 2121 #bodyName,
2140 #controller); 2122 #controller);
2141 """, { 2123 """,
2142 "asyncHelper": asyncStarHelper, 2124 {
2143 "value": value, 2125 "asyncHelper": asyncStarHelper,
2144 "bodyName": bodyName, 2126 "value": value,
2145 "controller": controllerName}); 2127 "bodyName": bodyName,
2128 "controller": controllerName
2129 });
2146 } 2130 }
2147 } 2131 }
2148 2132
2149 /// Finds out 2133 /// Finds out
2150 /// 2134 ///
2151 /// - which expressions have yield or await nested in them. 2135 /// - which expressions have yield or await nested in them.
2152 /// - targets of jumps 2136 /// - targets of jumps
2153 /// - a set of used names. 2137 /// - a set of used names.
2154 /// - if any [This]-expressions are used. 2138 /// - if any [This]-expressions are used.
2155 class PreTranslationAnalysis extends js.NodeVisitor<bool> { 2139 class PreTranslationAnalysis extends js.NodeVisitor<bool> {
(...skipping 81 matching lines...) Expand 10 before | Expand all | Expand 10 after
2237 bool containsAwait = false; 2221 bool containsAwait = false;
2238 for (js.Statement statement in node.statements) { 2222 for (js.Statement statement in node.statements) {
2239 if (visit(statement)) containsAwait = true; 2223 if (visit(statement)) containsAwait = true;
2240 } 2224 }
2241 return containsAwait; 2225 return containsAwait;
2242 } 2226 }
2243 2227
2244 @override 2228 @override
2245 bool visitBreak(js.Break node) { 2229 bool visitBreak(js.Break node) {
2246 if (node.targetLabel != null) { 2230 if (node.targetLabel != null) {
2247 targets[node] = labelledStatements.lastWhere( 2231 targets[node] =
2248 (js.LabeledStatement statement) { 2232 labelledStatements.lastWhere((js.LabeledStatement statement) {
2249 return statement.label == node.targetLabel; 2233 return statement.label == node.targetLabel;
2250 }); 2234 });
2251 } else { 2235 } else {
2252 targets[node] = loopsAndSwitches.last; 2236 targets[node] = loopsAndSwitches.last;
2253 } 2237 }
2254 return false; 2238 return false;
2255 } 2239 }
2256 2240
2257 @override 2241 @override
2258 bool visitCall(js.Call node) { 2242 bool visitCall(js.Call node) {
(...skipping 334 matching lines...) Expand 10 before | Expand all | Expand 10 after
2593 return condition || body; 2577 return condition || body;
2594 } 2578 }
2595 2579
2596 @override 2580 @override
2597 bool visitDartYield(js.DartYield node) { 2581 bool visitDartYield(js.DartYield node) {
2598 hasYield = true; 2582 hasYield = true;
2599 visit(node.expression); 2583 visit(node.expression);
2600 return true; 2584 return true;
2601 } 2585 }
2602 } 2586 }
OLDNEW
« no previous file with comments | « pkg/compiler/lib/src/js/placeholder_safety.dart ('k') | pkg/compiler/lib/src/js_backend/backend.dart » ('j') | no next file with comments »

Powered by Google App Engine
This is Rietveld 408576698