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

Side by Side Diff: sdk/lib/_internal/compiler/js_lib/js_helper.dart

Issue 839323003: Implementation of async-await transformation on js ast. (Closed) Base URL: https://dart.googlecode.com/svn/branches/bleeding_edge/dart
Patch Set: Removed the extra LocalsHandler Created 5 years, 10 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 | Annotate | Revision Log
OLDNEW
1 // Copyright (c) 2013, the Dart project authors. Please see the AUTHORS file 1 // Copyright (c) 2013, 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 _js_helper; 5 library _js_helper;
6 6
7 import 'dart:_js_embedded_names' show 7 import 'dart:_js_embedded_names' show
8 GET_TYPE_FROM_NAME, 8 GET_TYPE_FROM_NAME,
9 GET_ISOLATE_TAG, 9 GET_ISOLATE_TAG,
10 INTERCEPTED_NAMES, 10 INTERCEPTED_NAMES,
11 INTERCEPTORS_BY_TAG, 11 INTERCEPTORS_BY_TAG,
12 LEAF_TAGS, 12 LEAF_TAGS,
13 METADATA, 13 METADATA,
14 DEFERRED_LIBRARY_URIS, 14 DEFERRED_LIBRARY_URIS,
15 DEFERRED_LIBRARY_HASHES, 15 DEFERRED_LIBRARY_HASHES,
16 INITIALIZE_LOADED_HUNK, 16 INITIALIZE_LOADED_HUNK,
17 IS_HUNK_LOADED, 17 IS_HUNK_LOADED,
18 IS_HUNK_INITIALIZED, 18 IS_HUNK_INITIALIZED,
19 NATIVE_SUPERCLASS_TAG_NAME; 19 NATIVE_SUPERCLASS_TAG_NAME;
20 20
21 import 'dart:collection'; 21 import 'dart:collection';
22 import 'dart:_isolate_helper' show 22 import 'dart:_isolate_helper' show
23 IsolateNatives, 23 IsolateNatives,
24 leaveJsAsync, 24 leaveJsAsync,
25 enterJsAsync, 25 enterJsAsync,
26 isWorker; 26 isWorker;
27 27
28 import 'dart:async' show Future, DeferredLoadException, Completer; 28 import 'dart:async'
29 show Future,
30 DeferredLoadException,
Lasse Reichstein Nielsen 2015/02/13 11:13:20 Indent to align with Future? Or at least by four.
sigurdm 2015/02/13 11:40:16 Will do in future CL
31 Completer,
32 StreamController,
33 Stream,
34 StreamSubscription;
29 35
30 import 'dart:_foreign_helper' show 36 import 'dart:_foreign_helper' show
31 DART_CLOSURE_TO_JS, 37 DART_CLOSURE_TO_JS,
32 JS, 38 JS,
33 JS_CALL_IN_ISOLATE, 39 JS_CALL_IN_ISOLATE,
34 JS_CONST, 40 JS_CONST,
35 JS_CURRENT_ISOLATE, 41 JS_CURRENT_ISOLATE,
36 JS_CURRENT_ISOLATE_CONTEXT, 42 JS_CURRENT_ISOLATE_CONTEXT,
37 JS_DART_OBJECT_CONSTRUCTOR, 43 JS_DART_OBJECT_CONSTRUCTOR,
38 JS_EFFECT, 44 JS_EFFECT,
(...skipping 3416 matching lines...) Expand 10 before | Expand all | Expand 10 after
3455 throw new MainError("No top-level function named 'main'."); 3461 throw new MainError("No top-level function named 'main'.");
3456 } 3462 }
3457 3463
3458 void badMain() { 3464 void badMain() {
3459 throw new MainError("'main' is not a function."); 3465 throw new MainError("'main' is not a function.");
3460 } 3466 }
3461 3467
3462 void mainHasTooManyParameters() { 3468 void mainHasTooManyParameters() {
3463 throw new MainError("'main' expects too many parameters."); 3469 throw new MainError("'main' expects too many parameters.");
3464 } 3470 }
3471
3472 /// Runtime support for async-await transformation.
3473 ///
3474 /// This function is called by a transformed function on each await and return
3475 /// in the untransformed function, and before starting.
3476 ///
3477 /// If [object] is not a future it will be wrapped in a `new Future.value`.
3478 ///
3479 /// If [helperCallback] is null it indicates a return from the async function,
3480 /// and we complete the completer with object.
3481 ///
3482 /// Otherwise [helperCallback] is set up to be called when the future is
3483 /// successfull and [errorCallback] if it is completed with an error.
3484 ///
3485 /// If helperCallback or errorCallback throws we complete the completer with the
3486 /// error.
3487 ///
3488 /// Returns the future of the completer for convenience of the first call.
3489 dynamic thenHelper(dynamic object,
3490 dynamic /* js function */ helperCallback,
3491 Completer completer,
3492 dynamic /* js function */ errorCallback) {
3493 if (helperCallback == null) {
3494 completer.complete(object);
3495 return;
3496 }
3497 Future future = object is Future ? object : new Future.value(object);
Lasse Reichstein Nielsen 2015/02/13 11:13:20 Maybe just: if (object is Future) { object.
sigurdm 2015/02/13 11:40:16 That would not suspend execution? The spec is spec
3498 future.then(_wrapJsFunction(helperCallback, completer),
3499 onError: _wrapJsFunction(errorCallback, completer));
3500 return completer.future;
3501 }
3502
3503 // Used to avoid creating two identical closure classes in [thenHelper].
3504 Function _wrapJsFunction(dynamic /* js function */ function,
3505 Completer completer) {
3506 return (result) {
3507 try {
3508 JS('', '#(#)', function, result);
3509 } catch (e, st) {
3510 completer.completeError(e, st);
3511 }
3512 };
3513 }
3514
3515
3516 /// Runtime support for async*.
3517 ///
3518 /// Called by the transformed function for each original return, await, yield,
3519 /// yield* and before starting the function.
3520 ///
3521 /// On a return call with helperCallback == null, and we close the stream.
3522 ///
3523 /// If object is an [IterationMarker] it indicates a yield or yield*.
3524 /// If the stream subscription has been canceled we schedule the errorCallback
3525 /// that should run through enclosing finally blocks before exiting.
3526 ///
3527 /// If it is a single-yield we add the value to the stream.
3528 /// If the stream subscription has been paused we return early, otherwise
3529 /// we schedule the helper function to be executed again.
3530 ///
3531 /// If it is a yield* we start listening to the yielded stream, and add all
3532 /// events and errors to our own controller (taking care if the subscription has
3533 /// been paused or canceled) - when the sub-stream is done we schedule the
3534 /// helper function again.
3535 ///
3536 /// If object is not and [IterationMarker] it indicates an await.
3537 /// If object is not a Future, it is wrapped in a `Future.value`.
3538 /// Then set up helperCallBack to be called on successfull completion of the
3539 /// error
3540 ///
3541 /// If helperCallback or errorCallback throws we add the error to the stream
3542 /// If the object is a YIELD_SINGLE we add the object to the stream, and if the
3543 /// stream has been canceled call the errorCallBack.
floitsch 2015/02/04 17:06:10 errorCallback
sigurdm 2015/02/05 14:06:07 Done.
3544 dynamic streamHelper(dynamic object,
3545 dynamic /* js function */ helperCallback,
3546 AsyncStarStreamController controller,
3547 dynamic /* js function */ errorCallback) {
3548 if (helperCallback == null) {
3549 // This happens on return from the async* function.
3550 controller.close();
3551 return;
3552 }
3553
3554 if (object is IterationMarker) {
3555 if (controller.stopRunning) {
3556 _wrapJsFunctionForStream(errorCallback, controller)();
3557 return;
3558 }
3559 if (object.state == IterationMarker.YIELD_SINGLE) {
3560 controller.add(object.value);
3561 } else if (object.state == IterationMarker.YIELD_STAR) {
3562 Stream stream = object.value;
3563 controller.subSubscription = stream.listen((value) {
3564 if (controller.stopRunning) {
3565 controller.subSubscription.cancel();
3566 _wrapJsFunctionForStream(errorCallback, controller)(null);
3567 return;
3568 }
3569 controller.add(value);
3570 }, onError: (error, stackTrace) {
3571 if (controller.stopRunning) {
3572 controller.subSubscription.cancel();
3573 // This will run the enclosing finally blocks.
3574 _wrapJsFunctionForStream(errorCallback, controller)(null);
3575 return;
3576 }
3577 controller.addError(error, stackTrace);
3578 if (controller.isPaused) {
3579 controller.subSubscription.pause();
3580 }
3581 }, onDone: () {
3582 controller.subSubscription = null;
3583 // Resume producing.
3584 streamHelper(null, helperCallback, controller, null);
3585 });
3586 return;
3587 }
3588 if (controller.isPaused) {
3589 return;
3590 }
3591 object = null;
3592 }
3593 Future future = object is Future ? object : new Future.value(object);
3594 future.then(_wrapJsFunctionForStream(helperCallback, controller),
3595 onError: errorCallback = null
3596 ? null
3597 : _wrapJsFunctionForStream(errorCallback, controller));
3598 return controller.stream;
3599 }
3600
3601 /// A wrapper around a [StreamController] that remembers if that controller
3602 /// got a cancel.
3603 ///
3604 /// Also has a subSubscription that when not null will provide events for the
3605 /// stream, and will be paused and resumed along with this controller.
3606 class AsyncStarStreamController {
3607 StreamController controller;
3608 StreamSubscription subSubscription = null;
3609 Stream get stream => controller.stream;
3610 bool stopRunning = false;
3611 bool get isPaused => controller.isPaused;
3612 add(event) => controller.add(event);
3613 addError(error, stackTrace) => controller.addError(error, stackTrace);
3614 close() => controller.close();
3615
3616 AsyncStarStreamController(helperCallBack) {
3617 controller = new StreamController(
3618 onPause: () {
3619 if (subSubscription != null) {
3620 subSubscription.pause();
3621 }
3622 },
3623 onResume: () {
3624 if (subSubscription == null) {
3625 helperCallBack(null, helperCallBack, controller, null);
3626 } else {
3627 subSubscription.resume();
3628 }
3629 }, onCancel: () {
3630 stopRunning = true;
3631 });
3632 }
3633 }
3634
3635 makeAsyncStarController(helperCallback) {
3636 return new AsyncStarStreamController(helperCallback);
3637 }
3638
3639 // Used to avoid creating identical closure classes in [streamHelper].
3640 Function _wrapJsFunctionForStream(dynamic /* js function */ function,
3641 AsyncStarStreamController controller) {
3642 return (result) {
3643 try {
3644 JS('', '#(#)', function, result);
3645 } catch (e, st) {
3646 controller.addError(e, st);
3647 }
3648 };
3649 }
3650
3651
3652 class IterationMarker {
3653 static const YIELD_SINGLE = 0;
3654 static const YIELD_STAR = 1;
3655 static const ITERATION_ENDED = 2;
3656
3657 final value;
3658 final int state;
3659
3660 IterationMarker._(this.state, this.value);
3661
3662 static yieldStar(Iterable iterable) {
3663 return new IterationMarker._(YIELD_STAR, iterable);
3664 }
3665
3666 static endOfIteration() {
3667 return new IterationMarker._(ITERATION_ENDED, null);
3668 }
3669
3670 static yieldSingle(value) {
3671 return new IterationMarker._(YIELD_SINGLE, value);
3672 }
3673
3674 toString() => "IterationMarker($state, $value)";
3675 }
3676
3677 class SyncStarIterator implements Iterator {
3678 final Function _helper;
3679
3680 // if [runningNested] this will be the nested iterator, otherwise it will be
3681 // the current value.
3682 dynamic _current = null;
3683 bool _runningNested = false;
3684
3685 get current => _runningNested ? _current.current : _current;
3686
3687 SyncStarIterator(helper)
3688 : _helper = ((arg) => JS('', '#(#)', helper, arg));
3689
3690 bool moveNext() {
3691 if (_runningNested) {
3692 if (_current.moveNext()) {
3693 return true;
3694 } else {
3695 _runningNested = false;
3696 }
3697 }
3698 _current = _helper(null);
3699 if (_current is IterationMarker) {
3700 if (_current.state == IterationMarker.ITERATION_ENDED) {
3701 _current = null;
3702 // We rely on [_helper] to repeatedly return `ITERATION_ENDED`.
3703 return false;
3704 } else {
3705 assert(_current.state == IterationMarker.YIELD_STAR);
3706 _current = _current.value.iterator;
3707 _runningNested = true;
3708 return moveNext();
3709 }
3710 }
3711 return true;
3712 }
3713 }
3714
3715 /// An Iterable corresponding to a sync* method.
3716 ///
3717 /// Each invocation of a sync* method will return a new instance of this class.
3718 class SyncStarIterable extends IterableBase {
3719 // This is a function that will return a helper function that does the
3720 // iteration of the sync*.
3721 //
3722 // Each invocation should give a helper with fresh state.
3723 final dynamic /* js function */ _outerHelper;
3724
3725 SyncStarIterable(this._outerHelper);
3726
3727 Iterator get iterator => new SyncStarIterator(JS('', '#()', _outerHelper));
3728 }
3729
OLDNEW

Powered by Google App Engine
This is Rietveld 408576698