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

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: Add missing functions to the MockCompiler's library 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,
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 3409 matching lines...) Expand 10 before | Expand all | Expand 10 after
3448 throw new MainError("No top-level function named 'main'."); 3454 throw new MainError("No top-level function named 'main'.");
3449 } 3455 }
3450 3456
3451 void badMain() { 3457 void badMain() {
3452 throw new MainError("'main' is not a function."); 3458 throw new MainError("'main' is not a function.");
3453 } 3459 }
3454 3460
3455 void mainHasTooManyParameters() { 3461 void mainHasTooManyParameters() {
3456 throw new MainError("'main' expects too many parameters."); 3462 throw new MainError("'main' expects too many parameters.");
3457 } 3463 }
3464
3465 /// Runtime support for async-await transformation.
3466 ///
3467 /// This function is called by a transformed function on each await and return
3468 /// in the untransformed function, and before starting.
3469 ///
3470 /// If [object] is not a future it will be wrapped in a `new Future.value`.
3471 ///
3472 /// If [helperCallback] is null it indicates a return from the async function,
3473 /// and we complete the completer with object.
3474 ///
3475 /// Otherwise [helperCallback] is set up to be called when the future is
3476 /// successfull and [errorCallback] if it is completed with an error.
3477 ///
3478 /// If helperCallback or errorCallback throws we complete the completer with the
3479 /// error.
3480 ///
3481 /// Returns the future of the completer for convenience of the first call.
3482 dynamic thenHelper(dynamic object,
3483 dynamic /* js function */ helperCallback,
3484 Completer completer,
3485 dynamic /* js function */ errorCallback) {
3486 if (helperCallback == null) {
3487 completer.complete(object);
3488 return;
3489 }
3490 Future future = object is Future ? object : new Future.value(object);
3491 future.then(_wrapJsFunction(helperCallback, completer),
3492 onError: _wrapJsFunction(errorCallback, completer));
3493 return completer.future;
3494 }
3495
3496 // Used to avoid creating two identical closure classes in [thenHelper].
3497 Function _wrapJsFunction(dynamic /* js function */ function,
3498 Completer completer) {
3499 return (result) {
3500 try {
3501 JS('', '#(#)', function, result);
3502 } catch (e, st) {
3503 completer.completeError(e, st);
3504 }
3505 };
3506 }
3507
3508
3509 /// Runtime support for async*.
3510 ///
3511 /// Called by the transformed function for each original return, await, yield,
3512 /// yield* and before starting the function.
3513 ///
3514 /// On a return call with helperCallback == null, and we close the stream.
3515 ///
3516 /// If object is an [IterationMarker] it indicates a yield or yield*.
3517 /// If the stream subscription has been canceled we schedule the errorCallback
3518 /// that should run through enclosing finally blocks before exiting.
3519 ///
3520 /// If it is a single-yield we add the value to the stream.
3521 /// If the stream subscription has been paused we return early, otherwise
3522 /// we schedule the helper function to be executed again.
3523 ///
3524 /// If it is a yield* we start listening to the yielded stream, and add all
3525 /// events and errors to our own controller (taking care if the subscription has
3526 /// been paused or canceled) - when the sub-stream is done we schedule the
3527 /// helper function again.
3528 ///
3529 /// If object is not and [IterationMarker] it indicates an await.
3530 /// If object is not a Future, it is wrapped in a `Future.value`.
3531 /// Then set up helperCallBack to be called on successfull completion of the
3532 /// error
3533 ///
3534 /// If helperCallback or errorCallback throws we add the error to the stream
3535 /// If the object is a YIELD_SINGLE we add the object to the stream, and if the
3536 /// stream has been canceled call the errorCallBack.
3537 dynamic streamHelper(dynamic object,
3538 dynamic /* js function */ helperCallback,
3539 AsyncStarStreamController controller,
3540 dynamic /* js function */ errorCallback) {
3541 if (helperCallback == null) {
3542 // This happens on return from the async* function.
3543 controller.close();
3544 return;
3545 }
3546
3547 if (object is IterationMarker) {
3548 if (controller.stopRunning) {
3549 _wrapJsFunctionForStream(errorCallback, controller)();
3550 return;
3551 }
3552 if (object.state == IterationMarker.YIELD_SINGLE) {
3553 controller.add(object.value);
3554 } else if (object.state == IterationMarker.YIELD_STAR) {
3555 Stream stream = object.value;
3556 controller.subSubscription = stream.listen((value) {
3557 if (controller.stopRunning) {
3558 controller.subSubscription.cancel();
3559 _wrapJsFunctionForStream(errorCallback, controller)(null);
3560 return;
3561 }
3562 controller.add(value);
3563 }, onError: (error, stackTrace) {
3564 if (controller.stopRunning) {
3565 controller.subSubscription.cancel();
3566 // This will run the enclosing finally blocks.
3567 _wrapJsFunctionForStream(errorCallback, controller)(null);
3568 return;
3569 }
3570 controller.addError(error, stackTrace);
3571 if (controller.isPaused) {
3572 controller.subSubscription.pause();
3573 }
3574 }, onDone: () {
3575 controller.subSubscription = null;
3576 // Resume producing.
3577 streamHelper(null, helperCallback, controller, null);
3578 });
3579 return;
3580 }
3581 if (controller.isPaused) {
3582 return;
3583 }
3584 object = null;
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 StreamSubscription subSubscription = null;
3602 Stream get stream => controller.stream;
3603 bool stopRunning = false;
3604 bool get isPaused => controller.isPaused;
3605 add(event) => controller.add(event);
3606 addError(error, stackTrace) => controller.addError(error, stackTrace);
3607 close() => controller.close();
3608
3609 AsyncStarStreamController(helperCallBack) {
3610 controller = new StreamController(
3611 onPause: () {
3612 if (subSubscription != null) {
3613 subSubscription.pause();
3614 }
3615 },
3616 onResume: () {
3617 if (subSubscription == null) {
3618 helperCallBack(null, helperCallBack, controller, null);
3619 } else {
3620 subSubscription.resume();
3621 }
3622 }, onCancel: () {
3623 stopRunning = true;
3624 });
3625 }
3626 }
3627
3628 makeAsyncStarController(helperCallback) {
3629 return new AsyncStarStreamController(helperCallback);
3630 }
3631
3632 // Used to avoid creating identical closure classes in [streamHelper].
3633 Function _wrapJsFunctionForStream(dynamic /* js function */ function,
3634 AsyncStarStreamController controller) {
3635 return (result) {
3636 try {
3637 JS('', '#(#)', function, result);
3638 } catch (e, st) {
3639 controller.addError(e, st);
3640 }
3641 };
3642 }
3643
3644
3645 class IterationMarker {
3646 static const YIELD_SINGLE = 0;
3647 static const YIELD_STAR = 1;
3648 static const ITERATION_ENDED = 2;
3649
3650 final value;
3651 final int state;
3652
3653 IterationMarker._(this.state, this.value);
3654
3655 static yieldStar(Iterable iterable) {
3656 return new IterationMarker._(YIELD_STAR, iterable);
3657 }
3658
3659 static endOfIteration() {
3660 return new IterationMarker._(ITERATION_ENDED, null);
3661 }
3662
3663 static yieldSingle(value) {
3664 return new IterationMarker._(YIELD_SINGLE, value);
3665 }
3666
3667 toString() => "IterationMarker($state, $value)";
3668 }
3669
3670 class SyncStarIterator implements Iterator {
3671 final Function _helper;
3672
3673 // if [runningNested] this will be the nested iterator, otherwise it will be
3674 // the current value.
3675 dynamic _current = null;
3676 bool _runningNested = false;
3677
3678 get current => _runningNested ? _current.current : _current;
3679
3680 SyncStarIterator(helper)
3681 : _helper = ((arg) => JS('', '#(#)', helper, arg));
3682
3683 bool moveNext() {
3684 if (_runningNested) {
3685 if (_current.moveNext()) {
3686 return true;
3687 } else {
3688 _runningNested = false;
3689 }
3690 }
3691 _current = _helper(null);
3692 if (_current is IterationMarker) {
3693 if (_current.state == IterationMarker.ITERATION_ENDED) {
3694 _current = null;
3695 // We rely on [_helper] to repeatedly return `ITERATION_ENDED`.
3696 return false;
3697 } else {
3698 assert(_current.state == IterationMarker.YIELD_STAR);
3699 _current = _current.value.iterator;
3700 _runningNested = true;
3701 return moveNext();
3702 }
3703 }
3704 return true;
3705 }
3706 }
3707
3708 /// An Iterable corresponding to a sync* method.
3709 ///
3710 /// Each invocation of a sync* method will return a new instance of this class.
3711 class SyncStarIterable extends IterableBase {
3712 // This is a function that will return a helper function that does the
3713 // iteration of the sync*.
3714 //
3715 // Each invocation should give a helper with fresh state.
3716 final dynamic /* js function */ _outerHelper;
3717
3718 SyncStarIterable(this._outerHelper);
3719
3720 Iterator get iterator => new SyncStarIterator(JS('', '#()', _outerHelper));
3721 }
3722
OLDNEW

Powered by Google App Engine
This is Rietveld 408576698