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

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 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
« no previous file with comments | « pkg/compiler/lib/src/warnings.dart ('k') | tests/compiler/dart2js/analyze_helper.dart » ('j') | no next file with comments »
Toggle Intra-line Diffs ('i') | Expand Comments ('e') | Collapse Comments ('c') | Show Comments Hide Comments ('s')
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,
25 enterJsAsync, 24 enterJsAsync,
26 isWorker; 25 isWorker,
26 leaveJsAsync;
27 27
28 import 'dart:async' show Future, DeferredLoadException, Completer; 28 import 'dart:async' show
29 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 calls this function. with
3524 /// [helperCallback] == null, the streamHelper takes this as signal to close the
3525 /// stream.
3526 ///
3527 /// If the async* function wants to do a yield or yield* it calls this function
3528 /// with [object] being an [IterationMarker]. In this case [errorCallback] has a
3529 /// special meaning; it is a callback that will run all enclosing finalizers.
3530 ///
3531 /// In the case of a yield or yield*, if the stream subscription has been
3532 /// canceled [errorCallback] is scheduled.
3533 ///
3534 /// If [object] is a single-yield [IterationMarker], adds the value of the
3535 /// [IterationMarker] to the stream. If the stream subscription has been
3536 /// paused, return early. Otherwise schedule the helper function to be
3537 /// executed again.
3538 ///
3539 /// If [object] is a yield-star [IterationMarker], starts listening to the
3540 /// yielded stream, and adds all events and errors to our own controller (taking
3541 /// care if the subscription has been paused or canceled) - when the sub-stream
3542 /// is done, schedules [helperCallback] again.
3543 ///
3544 /// If the async* function wants to do an await it calls this function with
3545 /// [object] not and [IterationMarker].
3546 ///
3547 /// If [object] is not a [Future], it is wrapped in a `Future.value`.
3548 /// The [helperCallback] is called on successfull completion of the
3549 /// future.
3550 ///
3551 /// If [helperCallback] or [errorCallback] throws the error is added to the
3552 /// stream.
3553 dynamic streamHelper(dynamic object,
3554 dynamic /* js function */ helperCallback,
3555 AsyncStarStreamController controller,
3556 dynamic /* js function */ errorCallback) {
3557 if (helperCallback == null) {
3558 // This happens on return from the async* function.
3559 controller.close();
3560 return null;
3561 }
3562
3563 if (object is IterationMarker) {
3564 if (controller.stopRunning) {
3565 _wrapJsFunctionForStream(errorCallback, controller)();
3566 return null;
3567 }
3568 if (object.state == IterationMarker.YIELD_SINGLE) {
3569 controller.add(object.value);
3570 // If the controller is paused we stop producing more values.
3571 if (controller.isPaused) {
3572 return null;
3573 }
3574 // TODO(sigurdm): We should not suspend here according to the spec.
3575 scheduleMicrotask(() {
3576 _wrapJsFunctionForStream(helperCallback, controller)(null);
3577 });
3578 return;
3579 } else if (object.state == IterationMarker.YIELD_STAR) {
3580 Stream stream = object.value;
3581 controller.isAdding = true;
3582 // Errors of [stream] are passed though to the main stream. (see
3583 // [AsyncStreamController.addStream].
3584 // TODO(sigurdm): The spec is not very clear here. Clarify with Gilad.
3585 controller.addStream(stream).then((_) {
3586 controller.isAdding = false;
3587 _wrapJsFunctionForStream(helperCallback, controller)(null);
3588 });
3589 return null;
3590 }
3591 }
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 Stream get stream => controller.stream;
3609 bool stopRunning = false;
3610 bool isAdding = false;
3611 bool get isPaused => controller.isPaused;
3612 add(event) => controller.add(event);
3613 addStream(Stream stream) {
3614 return controller.addStream(stream, cancelOnError: false);
3615 }
3616 addError(error, stackTrace) => controller.addError(error, stackTrace);
3617 close() => controller.close();
3618
3619 AsyncStarStreamController(helperCallback) {
3620 controller = new StreamController(
3621 onResume: () {
3622 if (!isAdding) {
3623 streamHelper(null, helperCallback, this, null);
3624 }
3625 }, onCancel: () {
3626 stopRunning = true;
3627 });
3628 }
3629 }
3630
3631 makeAsyncStarController(helperCallback) {
3632 return new AsyncStarStreamController(helperCallback);
3633 }
3634
3635 Function _wrapJsFunctionForStream(dynamic /* js function */ function,
3636 AsyncStarStreamController controller) {
3637 return (result) {
3638 try {
3639 JS('', '#(#)', function, result);
3640 } catch (e, st) {
3641 controller.addError(e, st);
3642 }
3643 };
3644 }
3645
3646
3647 class IterationMarker {
3648 static const YIELD_SINGLE = 0;
3649 static const YIELD_STAR = 1;
3650 static const ITERATION_ENDED = 2;
3651
3652 final value;
3653 final int state;
3654
3655 IterationMarker._(this.state, this.value);
3656
3657 static yieldStar(dynamic /* Iterable or Stream */ values) {
3658 return new IterationMarker._(YIELD_STAR, values);
3659 }
3660
3661 static endOfIteration() {
3662 return new IterationMarker._(ITERATION_ENDED, null);
3663 }
3664
3665 static yieldSingle(dynamic value) {
3666 return new IterationMarker._(YIELD_SINGLE, value);
3667 }
3668
3669 toString() => "IterationMarker($state, $value)";
3670 }
3671
3672 class SyncStarIterator implements Iterator {
3673 final Function _helper;
3674
3675 // If [runningNested] this is the nested iterator, otherwise it is the
3676 // current value.
3677 dynamic _current = null;
3678 bool _runningNested = false;
3679
3680 get current => _runningNested ? _current.current : _current;
3681
3682 SyncStarIterator(helper)
3683 : _helper = ((arg) => JS('', '#(#)', helper, arg));
3684
3685 bool moveNext() {
3686 if (_runningNested) {
3687 if (_current.moveNext()) {
3688 return true;
3689 } else {
3690 _runningNested = false;
3691 }
3692 }
3693 _current = _helper(null);
3694 if (_current is IterationMarker) {
3695 if (_current.state == IterationMarker.ITERATION_ENDED) {
3696 _current = null;
3697 // Rely on [_helper] to repeatedly return `ITERATION_ENDED`.
3698 return false;
3699 } else {
3700 assert(_current.state == IterationMarker.YIELD_STAR);
3701 _current = _current.value.iterator;
3702 _runningNested = true;
3703 return moveNext();
3704 }
3705 }
3706 return true;
3707 }
3708 }
3709
3710 /// An Iterable corresponding to a sync* method.
3711 ///
3712 /// Each invocation of a sync* method will return a new instance of this class.
3713 class SyncStarIterable extends IterableBase {
3714 // This is a function that will return a helper function that does the
3715 // iteration of the sync*.
3716 //
3717 // Each invocation should give a helper with fresh state.
3718 final dynamic /* js function */ _outerHelper;
3719
3720 SyncStarIterable(this._outerHelper);
3721
3722 Iterator get iterator => new SyncStarIterator(JS('', '#()', _outerHelper));
3723 }
OLDNEW
« no previous file with comments | « pkg/compiler/lib/src/warnings.dart ('k') | tests/compiler/dart2js/analyze_helper.dart » ('j') | no next file with comments »

Powered by Google App Engine
This is Rietveld 408576698