Chromium Code Reviews| OLD | NEW |
|---|---|
| 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 3416 matching lines...) Expand 10 before | Expand all | Expand 10 after Loading... | |
| 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); | |
| 3498 future.then(_wrapJsFunction(helperCallback, completer), | |
| 3499 onError: _wrapJsFunction(errorCallback, completer)); | |
|
floitsch
2015/02/04 12:31:29
this loses the stacktrace.
sigurdm
2015/02/05 14:06:06
True - this won't work. We have to find a good sol
| |
| 3500 return completer.future; | |
| 3501 } | |
| 3502 | |
| 3503 // Used to avoid creating two identical closure classes in [thenHelper]. | |
|
floitsch
2015/02/04 12:31:29
Remove comment.
sigurdm
2015/02/05 14:06:05
Done.
| |
| 3504 Function _wrapJsFunction(dynamic /* js function */ function, | |
|
floitsch
2015/02/04 12:31:29
name is too general.
sigurdm
2015/02/05 14:06:05
Made it more specific.
| |
| 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, | |
|
floitsch
2015/02/04 12:31:29
Start by explaining what it does, not who uses it.
sigurdm
2015/02/05 14:06:05
Done.
| |
| 3519 /// yield* and before starting the function. | |
| 3520 /// | |
| 3521 /// On a return call with helperCallback == null, and we close the stream. | |
|
floitsch
2015/02/04 12:31:29
?
sigurdm
2015/02/05 14:06:06
Reworded
| |
| 3522 /// | |
| 3523 /// If object is an [IterationMarker] it indicates a yield or yield*. | |
|
floitsch
2015/02/04 12:31:29
what indicates?
floitsch
2015/02/04 12:31:29
reference [object]
sigurdm
2015/02/05 14:06:05
Done.
sigurdm
2015/02/05 14:06:05
Done.
sigurdm
2015/02/05 14:06:06
Tried to reword.
| |
| 3524 /// If the stream subscription has been canceled we schedule the errorCallback | |
|
floitsch
2015/02/04 12:31:29
don't use "we" (here and in the rest of the docume
floitsch
2015/02/04 12:31:29
has been canceled when?
floitsch
2015/02/04 12:31:29
new line before? or "In that case..." ?
sigurdm
2015/02/05 14:06:05
Done.
sigurdm
2015/02/05 14:06:06
I will try to avoid it in the future. I use it to
| |
| 3525 /// that should run through enclosing finally blocks before exiting. | |
|
floitsch
2015/02/04 12:31:29
that feels weird. A 'cancel' is not an error. Why
sigurdm
2015/02/05 14:06:05
errorCallback is used for running the finallies in
| |
| 3526 /// | |
| 3527 /// If it is a single-yield we add the value to the stream. | |
|
floitsch
2015/02/04 12:31:29
If what is a single-yield? I assume it's the [obje
sigurdm
2015/02/05 14:06:05
Reworded
| |
| 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. | |
|
floitsch
2015/02/04 12:31:29
not what?
Reference [object].
(Whenever you would
sigurdm
2015/02/05 14:06:04
Acknowledged.
| |
| 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. | |
| 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; | |
|
floitsch
2015/02/04 12:31:29
can't you just controller.addStream(object.value).
sigurdm
2015/02/05 14:06:04
Brilliant - had not seen that!
| |
| 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]. | |
|
floitsch
2015/02/04 12:31:29
Remove comment.
sigurdm
2015/02/05 14:06:04
Done.
| |
| 3640 Function _wrapJsFunctionForStream(dynamic /* js function */ function, | |
| 3641 AsyncStarStreamController controller) { | |
| 3642 return (result) { | |
| 3643 try { | |
| 3644 JS('', '#(#)', function, result); | |
| 3645 } catch (e, st) { | |
|
floitsch
2015/02/04 12:31:29
I believe that errors in async* are fatal.
Maybe L
sigurdm
2015/02/05 14:06:05
Acknowledged.
We will have to find out.
| |
| 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 | |
|
floitsch
2015/02/04 12:31:29
no need for future tense.
Start sentence with capi
sigurdm
2015/02/05 14:06:06
Done.
| |
| 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 | |
| OLD | NEW |