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

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: Address comments. Fix setting of the handler in finallies... 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'
floitsch 2015/02/05 20:17:23 maybe not your code, but should be easy: move "sho
sigurdm 2015/02/06 14:26:34 Done.
29 show Future,
30 DeferredLoadException,
31 Completer,
32 StreamController,
33 Stream,
34 StreamSubscription,
35 scheduleMicrotask;
29 36
30 import 'dart:_foreign_helper' show 37 import 'dart:_foreign_helper' show
31 DART_CLOSURE_TO_JS, 38 DART_CLOSURE_TO_JS,
32 JS, 39 JS,
33 JS_CALL_IN_ISOLATE, 40 JS_CALL_IN_ISOLATE,
34 JS_CONST, 41 JS_CONST,
35 JS_CURRENT_ISOLATE, 42 JS_CURRENT_ISOLATE,
36 JS_CURRENT_ISOLATE_CONTEXT, 43 JS_CURRENT_ISOLATE_CONTEXT,
37 JS_DART_OBJECT_CONSTRUCTOR, 44 JS_DART_OBJECT_CONSTRUCTOR,
38 JS_EFFECT, 45 JS_EFFECT,
(...skipping 3416 matching lines...) Expand 10 before | Expand all | Expand 10 after
3455 throw new MainError("No top-level function named 'main'."); 3462 throw new MainError("No top-level function named 'main'.");
3456 } 3463 }
3457 3464
3458 void badMain() { 3465 void badMain() {
3459 throw new MainError("'main' is not a function."); 3466 throw new MainError("'main' is not a function.");
3460 } 3467 }
3461 3468
3462 void mainHasTooManyParameters() { 3469 void mainHasTooManyParameters() {
3463 throw new MainError("'main' expects too many parameters."); 3470 throw new MainError("'main' expects too many parameters.");
3464 } 3471 }
3472
3473 /// Runtime support for async-await transformation.
3474 ///
3475 /// This function is called by a transformed function on each await and return
3476 /// in the untransformed function, and before starting.
3477 ///
3478 /// If [object] is not a future it will be wrapped in a `new Future.value`.
3479 ///
3480 /// If [helperCallback] is null it indicates a return from the async function,
3481 /// and we complete the completer with object.
3482 ///
3483 /// Otherwise [helperCallback] is set up to be called when the future is
3484 /// successfull and [errorCallback] if it is completed with an error.
3485 ///
3486 /// If helperCallback or errorCallback throws we complete the completer with the
3487 /// error.
3488 ///
3489 /// Returns the future of the completer for convenience of the first call.
3490 dynamic thenHelper(dynamic object,
3491 dynamic /* js function */ helperCallback,
3492 Completer completer,
3493 dynamic /* js function */ errorCallback) {
3494 if (helperCallback == null) {
3495 completer.complete(object);
3496 return;
3497 }
3498 Future future = object is Future ? object : new Future.value(object);
3499 future.then(_wrapJsFunctionForThenHelper(helperCallback, completer),
3500 onError: (errorCallback == null)
3501 ? null
3502 : _wrapJsFunctionForThenHelper(errorCallback, completer));
3503 return completer.future;
3504 }
3505
3506 Function _wrapJsFunctionForThenHelper(dynamic /* js function */ function,
3507 Completer completer) {
3508 return (result) {
3509 try {
3510 JS('', '#(#)', function, result);
3511 } catch (e, st) {
3512 completer.completeError(e, st);
3513 }
3514 };
3515 }
3516
3517
3518 /// Implements the runtime support for async* functions.
3519 ///
3520 /// Called by the transformed function for each original return, await, yield,
3521 /// yield* and before starting the function.
3522 ///
3523 /// When the async* function wants to return it call this with
floitsch 2015/02/05 20:17:23 calls this functions. The streamHelper takes this
sigurdm 2015/02/06 14:26:34 Done.
3524 /// [helperCallback] == null, and the stream is closed.
3525 ///
3526 /// If the async* function wants to do a yield or yield* it will call this with
floitsch 2015/02/05 20:17:23 it calls this function
sigurdm 2015/02/06 14:26:34 Done.
3527 /// [object] being an [IterationMarker]. In this case [errorCallback] has a
3528 /// special meaning; it is a callback that will run all enclosing finalizers.
3529 ///
3530 /// In the case of a yield or yield*, if the stream subscription has been
3531 /// canceled [errorCallback] is scheduled.
3532 ///
3533 /// If [object] is a single-yield [IterationMarker], add the value of the
floitsch 2015/02/05 20:17:23 adds
sigurdm 2015/02/06 14:26:34 Done.
3534 /// [IterationMarker] to the stream, next: if the stream subscription has been
floitsch 2015/02/05 20:17:23 to the stream. If the stream... (unless I'm misun
sigurdm 2015/02/06 14:26:34 Done.
3535 /// paused, return early. Otherwise schedule the helper function to be
3536 /// executed again.
3537 ///
3538 /// If [object] is a yield-star [IterationMarker], start listening to the
floitsch 2015/02/05 20:17:23 starts ... and adds ... schedules
sigurdm 2015/02/06 14:26:34 Done.
3539 /// yielded stream, and add all events and errors to our own controller (taking
3540 /// care if the subscription has been paused or canceled) - when the sub-stream
3541 /// is done, schedule [helperCallback] again.
3542 ///
3543 /// If the async* function wants to do an await it will call this with [object]
floitsch 2015/02/05 20:17:23 calls this function with [object] not an [Iteratio
sigurdm 2015/02/06 14:26:34 Done.
3544 /// not being an [IterationMarker].
3545 ///
3546 /// If [object] is not a [Future], it is wrapped in a `Future.value`.
3547 /// Then set up [helperCallback] to be called on successfull completion of the
floitsch 2015/02/05 20:17:23 The [helperCallback] is called on successful compl
sigurdm 2015/02/06 14:26:34 Done.
3548 /// future.
3549 ///
3550 /// If [helperCallback] or [errorCallback] throws the error is added to the
3551 /// stream.
3552 dynamic streamHelper(dynamic object,
3553 dynamic /* js function */ helperCallback,
3554 AsyncStarStreamController controller,
3555 dynamic /* js function */ errorCallback) {
3556 if (helperCallback == null) {
3557 // This happens on return from the async* function.
3558 controller.close();
3559 return null;
3560 }
3561
3562 if (object is IterationMarker) {
3563 if (controller.stopRunning) {
3564 _wrapJsFunctionForStream(errorCallback, controller)();
3565 return null;
3566 }
3567 if (object.state == IterationMarker.YIELD_SINGLE) {
3568 controller.add(object.value);
3569 if (controller.isPaused) {
3570 return null;
3571 }
3572 new Future.value(null).then(
floitsch 2015/02/05 20:17:23 Why? Do we have to wait a microtask before we can
sigurdm 2015/02/06 14:26:35 I thought that it was necessary to suspend executi
3573 _wrapJsFunctionForStream(helperCallback, controller));
3574 return;
3575 } else if (object.state == IterationMarker.YIELD_STAR) {
3576 Stream stream = object.value;
3577 controller.isAdding = true;
3578 controller.addStream(stream).then((_) {
floitsch 2015/02/05 20:17:23 You might need to listen to the error too. I'm not
sigurdm 2015/02/06 14:26:34 As you saw below, I explicitly ask errors to be pa
3579 controller.isAdding = false;
3580 _wrapJsFunctionForStream(helperCallback, controller)(null);
3581 });
3582 return null;
3583 }
3584 }
3585
3586 Future future = object is Future ? object : new Future.value(object);
3587 future.then(_wrapJsFunctionForStream(helperCallback, controller),
3588 onError: errorCallback == null
3589 ? null
3590 : _wrapJsFunctionForStream(errorCallback, controller));
3591 return controller.stream;
3592 }
3593
3594 /// A wrapper around a [StreamController] that remembers if that controller
3595 /// got a cancel.
3596 ///
3597 /// Also has a subSubscription that when not null will provide events for the
3598 /// stream, and will be paused and resumed along with this controller.
3599 class AsyncStarStreamController {
3600 StreamController controller;
3601 Stream get stream => controller.stream;
3602 bool stopRunning = false;
3603 bool isAdding = false;
3604 bool get isPaused => controller.isPaused;
3605 add(event) => controller.add(event);
3606 addStream(Stream stream) {
3607 return controller.addStream(stream, cancelOnError: false);
floitsch 2015/02/05 20:17:23 I see. So I guess the future cannot have an error.
sigurdm 2015/02/06 14:26:34 Done.
3608 }
3609 addError(error, stackTrace) => controller.addError(error, stackTrace);
3610 close() => controller.close();
3611
3612 AsyncStarStreamController(helperCallback) {
3613 controller = new StreamController(
3614 onResume: () {
3615 if (!isAdding) {
floitsch 2015/02/05 20:17:23 Check with Lasse, if 'isPaused' on the controller
floitsch 2015/02/05 20:17:23 Add comment.
sigurdm 2015/02/06 14:26:34 Done.
sigurdm 2015/02/06 14:26:34 According to him, it is just as good.
3616 streamHelper(null, helperCallback, this, null);
3617 }
3618 }, onCancel: () {
3619 stopRunning = true;
floitsch 2015/02/05 20:17:23 Please make sure (test), that an incoming stream i
sigurdm 2015/02/06 14:26:34 Modified asyncstar_yieldstar_test to do that.
3620 });
3621 }
3622 }
3623
3624 makeAsyncStarController(helperCallback) {
3625 return new AsyncStarStreamController(helperCallback);
3626 }
3627
3628 Function _wrapJsFunctionForStream(dynamic /* js function */ function,
3629 AsyncStarStreamController controller) {
3630 return (result) {
3631 try {
3632 JS('', '#(#)', function, result);
3633 } catch (e, st) {
3634 controller.addError(e, st);
3635 }
3636 };
3637 }
3638
3639
3640 class IterationMarker {
3641 static const YIELD_SINGLE = 0;
3642 static const YIELD_STAR = 1;
3643 static const ITERATION_ENDED = 2;
3644
3645 final value;
3646 final int state;
3647
3648 IterationMarker._(this.state, this.value);
3649
3650 static yieldStar(dynamic /* Iterable or Stream */ yielded) {
floitsch 2015/02/05 20:17:23 maybe just "values" ?
sigurdm 2015/02/06 14:26:34 Done.
3651 return new IterationMarker._(YIELD_STAR, yielded);
3652 }
3653
3654 static endOfIteration() {
3655 return new IterationMarker._(ITERATION_ENDED, null);
3656 }
3657
3658 static yieldSingle(dynamic value) {
3659 return new IterationMarker._(YIELD_SINGLE, value);
3660 }
3661
3662 toString() => "IterationMarker($state, $value)";
3663 }
3664
3665 class SyncStarIterator implements Iterator {
3666 final Function _helper;
3667
3668 // If [runningNested] this is the nested iterator, otherwise it is the
3669 // current value.
3670 dynamic _current = null;
3671 bool _runningNested = false;
3672
3673 get current => _runningNested ? _current.current : _current;
3674
3675 SyncStarIterator(helper)
3676 : _helper = ((arg) => JS('', '#(#)', helper, arg));
3677
3678 bool moveNext() {
3679 if (_runningNested) {
3680 if (_current.moveNext()) {
3681 return true;
3682 } else {
3683 _runningNested = false;
3684 }
3685 }
3686 _current = _helper(null);
3687 if (_current is IterationMarker) {
3688 if (_current.state == IterationMarker.ITERATION_ENDED) {
3689 _current = null;
3690 // Rely on [_helper] to repeatedly return `ITERATION_ENDED`.
3691 return false;
3692 } else {
3693 assert(_current.state == IterationMarker.YIELD_STAR);
3694 _current = _current.value.iterator;
3695 _runningNested = true;
3696 return moveNext();
3697 }
3698 }
3699 return true;
3700 }
3701 }
3702
3703 /// An Iterable corresponding to a sync* method.
3704 ///
3705 /// Each invocation of a sync* method will return a new instance of this class.
3706 class SyncStarIterable extends IterableBase {
3707 // This is a function that will return a helper function that does the
3708 // iteration of the sync*.
3709 //
3710 // Each invocation should give a helper with fresh state.
3711 final dynamic /* js function */ _outerHelper;
3712
3713 SyncStarIterable(this._outerHelper);
3714
3715 Iterator get iterator => new SyncStarIterator(JS('', '#()', _outerHelper));
3716 }
3717
OLDNEW

Powered by Google App Engine
This is Rietveld 408576698