| 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:_async_await_error_codes' as async_error_codes; |
| 8 |
| 7 import 'dart:_js_embedded_names' show | 9 import 'dart:_js_embedded_names' show |
| 8 GET_TYPE_FROM_NAME, | 10 GET_TYPE_FROM_NAME, |
| 9 GET_ISOLATE_TAG, | 11 GET_ISOLATE_TAG, |
| 10 INTERCEPTED_NAMES, | 12 INTERCEPTED_NAMES, |
| 11 INTERCEPTORS_BY_TAG, | 13 INTERCEPTORS_BY_TAG, |
| 12 LEAF_TAGS, | 14 LEAF_TAGS, |
| 13 METADATA, | 15 METADATA, |
| 14 DEFERRED_LIBRARY_URIS, | 16 DEFERRED_LIBRARY_URIS, |
| 15 DEFERRED_LIBRARY_HASHES, | 17 DEFERRED_LIBRARY_HASHES, |
| 16 INITIALIZE_LOADED_HUNK, | 18 INITIALIZE_LOADED_HUNK, |
| 17 IS_HUNK_LOADED, | 19 IS_HUNK_LOADED, |
| 18 IS_HUNK_INITIALIZED, | 20 IS_HUNK_INITIALIZED, |
| 19 NATIVE_SUPERCLASS_TAG_NAME; | 21 NATIVE_SUPERCLASS_TAG_NAME; |
| 20 | 22 |
| 21 import 'dart:collection'; | 23 import 'dart:collection'; |
| 22 import 'dart:_isolate_helper' show | 24 import 'dart:_isolate_helper' show |
| 23 IsolateNatives, | 25 IsolateNatives, |
| 24 enterJsAsync, | 26 enterJsAsync, |
| 25 isWorker, | 27 isWorker, |
| 26 leaveJsAsync; | 28 leaveJsAsync; |
| 27 | 29 |
| 28 import 'dart:async' show | 30 import 'dart:async' show |
| 29 Future, | 31 Future, |
| 30 DeferredLoadException, | 32 DeferredLoadException, |
| 31 Completer, | 33 Completer, |
| 32 StreamController, | 34 StreamController, |
| 33 Stream, | 35 Stream, |
| 34 StreamSubscription, | 36 StreamSubscription, |
| 35 scheduleMicrotask; | 37 scheduleMicrotask; |
| 36 | 38 |
| 37 import 'dart:_foreign_helper' show | 39 import 'dart:_foreign_helper' show |
| 38 DART_CLOSURE_TO_JS, | 40 DART_CLOSURE_TO_JS, |
| 39 JS, | 41 JS, |
| 40 JS_CALL_IN_ISOLATE, | 42 JS_CALL_IN_ISOLATE, |
| 41 JS_CONST, | 43 JS_CONST, |
| 42 JS_CURRENT_ISOLATE, | 44 JS_CURRENT_ISOLATE, |
| 43 JS_CURRENT_ISOLATE_CONTEXT, | 45 JS_CURRENT_ISOLATE_CONTEXT, |
| 44 JS_DART_OBJECT_CONSTRUCTOR, | 46 JS_DART_OBJECT_CONSTRUCTOR, |
| 45 JS_EFFECT, | 47 JS_EFFECT, |
| (...skipping 3424 matching lines...) Expand 10 before | Expand all | Expand 10 after Loading... |
| 3470 throw new MainError("'main' expects too many parameters."); | 3472 throw new MainError("'main' expects too many parameters."); |
| 3471 } | 3473 } |
| 3472 | 3474 |
| 3473 /// Runtime support for async-await transformation. | 3475 /// Runtime support for async-await transformation. |
| 3474 /// | 3476 /// |
| 3475 /// This function is called by a transformed function on each await and return | 3477 /// This function is called by a transformed function on each await and return |
| 3476 /// in the untransformed function, and before starting. | 3478 /// in the untransformed function, and before starting. |
| 3477 /// | 3479 /// |
| 3478 /// If [object] is not a future it will be wrapped in a `new Future.value`. | 3480 /// If [object] is not a future it will be wrapped in a `new Future.value`. |
| 3479 /// | 3481 /// |
| 3480 /// If [helperCallback] is null it indicates a return from the async function, | 3482 /// If [asyncBody] is [async_error_codes.SUCCESS]/[async_error_codes.ERROR] it |
| 3481 /// and we complete the completer with object. | 3483 /// indicates a return or throw from the async function, and |
| 3484 /// complete/completeError is called on [completer] with [object]. |
| 3482 /// | 3485 /// |
| 3483 /// Otherwise [helperCallback] is set up to be called when the future is | 3486 /// Otherwise [asyncBody] is set up to be called when the future is completed |
| 3484 /// successfull and [errorCallback] if it is completed with an error. | 3487 /// with a code [async_error_codes.SUCCESS]/[async_error_codes.ERROR] depending |
| 3485 /// | 3488 /// on the success of the future. |
| 3486 /// If helperCallback or errorCallback throws we complete the completer with the | |
| 3487 /// error. | |
| 3488 /// | 3489 /// |
| 3489 /// Returns the future of the completer for convenience of the first call. | 3490 /// Returns the future of the completer for convenience of the first call. |
| 3490 dynamic thenHelper(dynamic object, | 3491 dynamic asyncHelper(dynamic object, |
| 3491 dynamic /* js function */ helperCallback, | 3492 dynamic /* js function */ bodyFunctionOrErrorCode, |
| 3492 Completer completer, | 3493 Completer completer) { |
| 3493 dynamic /* js function */ errorCallback) { | 3494 if (identical(bodyFunctionOrErrorCode, async_error_codes.SUCCESS)) { |
| 3494 if (helperCallback == null) { | |
| 3495 completer.complete(object); | 3495 completer.complete(object); |
| 3496 return; | 3496 return; |
| 3497 } else if (identical(bodyFunctionOrErrorCode, async_error_codes.ERROR)) { |
| 3498 // The error is a js-error. |
| 3499 completer.completeError(unwrapException(object), |
| 3500 getTraceFromException(object)); |
| 3501 return; |
| 3497 } | 3502 } |
| 3498 Future future = object is Future ? object : new Future.value(object); | 3503 Future future = object is Future ? object : new Future.value(object); |
| 3499 future.then(_wrapJsFunctionForThenHelper(helperCallback, completer), | 3504 future.then(_wrapJsFunctionForAsync(bodyFunctionOrErrorCode, |
| 3500 onError: (errorCallback == null) | 3505 async_error_codes.SUCCESS), |
| 3501 ? null | 3506 onError: _wrapJsFunctionForAsync(bodyFunctionOrErrorCode, |
| 3502 : _wrapJsFunctionForThenHelper(errorCallback, completer)); | 3507 async_error_codes.ERROR)); |
| 3503 return completer.future; | 3508 return completer.future; |
| 3504 } | 3509 } |
| 3505 | 3510 |
| 3506 Function _wrapJsFunctionForThenHelper(dynamic /* js function */ function, | 3511 Function _wrapJsFunctionForAsync(dynamic /* js function */ function, |
| 3507 Completer completer) { | 3512 int errorCode) { |
| 3508 return (result) { | 3513 return (result) { |
| 3509 try { | 3514 JS('', '#(#, #)', function, errorCode, result); |
| 3510 JS('', '#(#)', function, result); | |
| 3511 } catch (e, st) { | |
| 3512 completer.completeError(e, st); | |
| 3513 } | |
| 3514 }; | 3515 }; |
| 3515 } | 3516 } |
| 3516 | 3517 |
| 3517 | |
| 3518 /// Implements the runtime support for async* functions. | 3518 /// Implements the runtime support for async* functions. |
| 3519 /// | 3519 /// |
| 3520 /// Called by the transformed function for each original return, await, yield, | 3520 /// Called by the transformed function for each original return, await, yield, |
| 3521 /// yield* and before starting the function. | 3521 /// yield* and before starting the function. |
| 3522 /// | 3522 /// |
| 3523 /// When the async* function wants to return it calls this function. with | 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 | 3524 /// [asyncBody] == [async_error_codes.SUCCESS], the asyncStarHelper takes this |
| 3525 /// stream. | 3525 /// as signal to close the stream. |
| 3526 /// | 3526 /// |
| 3527 /// If the async* function wants to do a yield or yield* it calls this function | 3527 /// When the async* function wants to signal that an uncaught error was thrown, |
| 3528 /// with [object] being an [IterationMarker]. In this case [errorCallback] has a | 3528 /// it calls this function with [asyncBody] == [async_error_codes.ERROR], |
| 3529 /// special meaning; it is a callback that will run all enclosing finalizers. | 3529 /// the streamHelper takes this as signal to addError [object] to the |
| 3530 /// [controller] and close it. |
| 3531 /// |
| 3532 /// If the async* function wants to do a yield or yield*, it calls this function |
| 3533 /// with [object] being an [IterationMarker]. |
| 3530 /// | 3534 /// |
| 3531 /// In the case of a yield or yield*, if the stream subscription has been | 3535 /// In the case of a yield or yield*, if the stream subscription has been |
| 3532 /// canceled [errorCallback] is scheduled. | 3536 /// canceled, schedules [asyncBody] to be called with |
| 3537 /// [async_error_codes.STREAM_WAS_CANCELED]. |
| 3533 /// | 3538 /// |
| 3534 /// If [object] is a single-yield [IterationMarker], adds the value of the | 3539 /// If [object] is a single-yield [IterationMarker], adds the value of the |
| 3535 /// [IterationMarker] to the stream. If the stream subscription has been | 3540 /// [IterationMarker] to the stream. If the stream subscription has been |
| 3536 /// paused, return early. Otherwise schedule the helper function to be | 3541 /// paused, return early. Otherwise schedule the helper function to be |
| 3537 /// executed again. | 3542 /// executed again. |
| 3538 /// | 3543 /// |
| 3539 /// If [object] is a yield-star [IterationMarker], starts listening to the | 3544 /// 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 | 3545 /// 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 | 3546 /// care if the subscription has been paused or canceled) - when the sub-stream |
| 3542 /// is done, schedules [helperCallback] again. | 3547 /// is done, schedules [asyncBody] again. |
| 3543 /// | 3548 /// |
| 3544 /// If the async* function wants to do an await it calls this function with | 3549 /// If the async* function wants to do an await it calls this function with |
| 3545 /// [object] not and [IterationMarker]. | 3550 /// [object] not and [IterationMarker]. |
| 3546 /// | 3551 /// |
| 3547 /// If [object] is not a [Future], it is wrapped in a `Future.value`. | 3552 /// If [object] is not a [Future], it is wrapped in a `Future.value`. |
| 3548 /// The [helperCallback] is called on successfull completion of the | 3553 /// The [asyncBody] is called on completion of the future (see [asyncHelper]. |
| 3549 /// future. | 3554 void asyncStarHelper(dynamic object, |
| 3550 /// | 3555 dynamic /* int | js function */ bodyFunctionOrErrorCode, |
| 3551 /// If [helperCallback] or [errorCallback] throws the error is added to the | 3556 AsyncStarStreamController controller) { |
| 3552 /// stream. | 3557 if (identical(bodyFunctionOrErrorCode, async_error_codes.SUCCESS)) { |
| 3553 void 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. | 3558 // This happens on return from the async* function. |
| 3559 controller.close(); | 3559 controller.close(); |
| 3560 return; | 3560 return; |
| 3561 } else if (identical(bodyFunctionOrErrorCode, async_error_codes.ERROR)) { |
| 3562 // The error is a js-error. |
| 3563 controller.addError(unwrapException(object), |
| 3564 getTraceFromException(object)); |
| 3565 controller.close(); |
| 3566 return; |
| 3561 } | 3567 } |
| 3562 | 3568 |
| 3563 if (object is IterationMarker) { | 3569 if (object is IterationMarker) { |
| 3564 if (controller.stopRunning) { | 3570 if (controller.stopRunning) { |
| 3565 _wrapJsFunctionForStream(errorCallback, controller)(); | 3571 _wrapJsFunctionForAsync(bodyFunctionOrErrorCode, |
| 3572 async_error_codes.STREAM_WAS_CANCELED)(null); |
| 3566 return; | 3573 return; |
| 3567 } | 3574 } |
| 3568 if (object.state == IterationMarker.YIELD_SINGLE) { | 3575 if (object.state == IterationMarker.YIELD_SINGLE) { |
| 3569 controller.add(object.value); | 3576 controller.add(object.value); |
| 3570 // If the controller is paused we stop producing more values. | 3577 // If the controller is paused we stop producing more values. |
| 3571 if (controller.isPaused) { | 3578 if (controller.isPaused) { |
| 3572 return; | 3579 return; |
| 3573 } | 3580 } |
| 3574 // TODO(sigurdm): We should not suspend here according to the spec. | 3581 // TODO(sigurdm): We should not suspend here according to the spec. |
| 3575 scheduleMicrotask(() { | 3582 scheduleMicrotask(() { |
| 3576 _wrapJsFunctionForStream(helperCallback, controller)(null); | 3583 _wrapJsFunctionForAsync(bodyFunctionOrErrorCode, |
| 3584 async_error_codes.SUCCESS) |
| 3585 (null); |
| 3577 }); | 3586 }); |
| 3578 return; | 3587 return; |
| 3579 } else if (object.state == IterationMarker.YIELD_STAR) { | 3588 } else if (object.state == IterationMarker.YIELD_STAR) { |
| 3580 Stream stream = object.value; | 3589 Stream stream = object.value; |
| 3581 controller.isAdding = true; | 3590 controller.isAdding = true; |
| 3582 // Errors of [stream] are passed though to the main stream. (see | 3591 // Errors of [stream] are passed though to the main stream. (see |
| 3583 // [AsyncStreamController.addStream]. | 3592 // [AsyncStreamController.addStream]. |
| 3584 // TODO(sigurdm): The spec is not very clear here. Clarify with Gilad. | 3593 // TODO(sigurdm): The spec is not very clear here. Clarify with Gilad. |
| 3585 controller.addStream(stream).then((_) { | 3594 controller.addStream(stream).then((_) { |
| 3586 controller.isAdding = false; | 3595 controller.isAdding = false; |
| 3587 _wrapJsFunctionForStream(helperCallback, controller)(null); | 3596 _wrapJsFunctionForAsync(bodyFunctionOrErrorCode, |
| 3597 async_error_codes.SUCCESS)(null); |
| 3588 }); | 3598 }); |
| 3589 return; | 3599 return; |
| 3590 } | 3600 } |
| 3591 } | 3601 } |
| 3592 | 3602 |
| 3593 Future future = object is Future ? object : new Future.value(object); | 3603 Future future = object is Future ? object : new Future.value(object); |
| 3594 future.then(_wrapJsFunctionForStream(helperCallback, controller), | 3604 future.then(_wrapJsFunctionForAsync(bodyFunctionOrErrorCode, |
| 3595 onError: errorCallback == null | 3605 async_error_codes.SUCCESS), |
| 3596 ? null | 3606 onError: _wrapJsFunctionForAsync(bodyFunctionOrErrorCode, |
| 3597 : _wrapJsFunctionForStream(errorCallback, controller)); | 3607 async_error_codes.ERROR)); |
| 3598 } | 3608 } |
| 3599 | 3609 |
| 3600 Stream streamOfController(AsyncStarStreamController controller) { | 3610 Stream streamOfController(AsyncStarStreamController controller) { |
| 3601 return controller.stream; | 3611 return controller.stream; |
| 3602 } | 3612 } |
| 3603 | 3613 |
| 3604 /// A wrapper around a [StreamController] that remembers if that controller | 3614 /// A wrapper around a [StreamController] that remembers if that controller |
| 3605 /// got a cancel. | 3615 /// got a cancel. |
| 3606 /// | 3616 /// |
| 3607 /// Also has a subSubscription that when not null will provide events for the | 3617 /// Also has a subSubscription that when not null will provide events for the |
| 3608 /// stream, and will be paused and resumed along with this controller. | 3618 /// stream, and will be paused and resumed along with this controller. |
| 3609 class AsyncStarStreamController { | 3619 class AsyncStarStreamController { |
| 3610 StreamController controller; | 3620 StreamController controller; |
| 3611 Stream get stream => controller.stream; | 3621 Stream get stream => controller.stream; |
| 3612 bool stopRunning = false; | 3622 bool stopRunning = false; |
| 3613 bool isAdding = false; | 3623 bool isAdding = false; |
| 3614 bool get isPaused => controller.isPaused; | 3624 bool get isPaused => controller.isPaused; |
| 3615 add(event) => controller.add(event); | 3625 add(event) => controller.add(event); |
| 3616 addStream(Stream stream) { | 3626 addStream(Stream stream) { |
| 3617 return controller.addStream(stream, cancelOnError: false); | 3627 return controller.addStream(stream, cancelOnError: false); |
| 3618 } | 3628 } |
| 3619 addError(error, stackTrace) => controller.addError(error, stackTrace); | 3629 addError(error, stackTrace) => controller.addError(error, stackTrace); |
| 3620 close() => controller.close(); | 3630 close() => controller.close(); |
| 3621 | 3631 |
| 3622 AsyncStarStreamController(helperCallback) { | 3632 AsyncStarStreamController(helperCallback) { |
| 3623 controller = new StreamController( | 3633 controller = new StreamController( |
| 3624 onListen: () { | 3634 onListen: () { |
| 3625 scheduleMicrotask(() => JS('', '#(null)', helperCallback)); | 3635 scheduleMicrotask(() { |
| 3636 JS('', '#(#, null)', helperCallback, async_error_codes.SUCCESS); |
| 3637 }); |
| 3626 }, | 3638 }, |
| 3627 onResume: () { | 3639 onResume: () { |
| 3628 if (!isAdding) { | 3640 if (!isAdding) { |
| 3629 streamHelper(null, helperCallback, this, null); | 3641 asyncStarHelper(null, helperCallback, this); |
| 3630 } | 3642 } |
| 3631 }, onCancel: () { | 3643 }, onCancel: () { |
| 3632 stopRunning = true; | 3644 stopRunning = true; |
| 3633 }); | 3645 }); |
| 3634 } | 3646 } |
| 3635 } | 3647 } |
| 3636 | 3648 |
| 3637 makeAsyncStarController(helperCallback) { | 3649 makeAsyncStarController(helperCallback) { |
| 3638 return new AsyncStarStreamController(helperCallback); | 3650 return new AsyncStarStreamController(helperCallback); |
| 3639 } | 3651 } |
| 3640 | 3652 |
| 3641 Function _wrapJsFunctionForStream(dynamic /* js function */ function, | |
| 3642 AsyncStarStreamController controller) { | |
| 3643 return (result) { | |
| 3644 try { | |
| 3645 JS('', '#(#)', function, result); | |
| 3646 } catch (e, st) { | |
| 3647 controller.addError(e, st); | |
| 3648 } | |
| 3649 }; | |
| 3650 } | |
| 3651 | |
| 3652 | |
| 3653 class IterationMarker { | 3653 class IterationMarker { |
| 3654 static const YIELD_SINGLE = 0; | 3654 static const YIELD_SINGLE = 0; |
| 3655 static const YIELD_STAR = 1; | 3655 static const YIELD_STAR = 1; |
| 3656 static const ITERATION_ENDED = 2; | 3656 static const ITERATION_ENDED = 2; |
| 3657 static const UNCAUGHT_ERROR = 3; |
| 3657 | 3658 |
| 3658 final value; | 3659 final value; |
| 3659 final int state; | 3660 final int state; |
| 3660 | 3661 |
| 3661 IterationMarker._(this.state, this.value); | 3662 IterationMarker._(this.state, this.value); |
| 3662 | 3663 |
| 3663 static yieldStar(dynamic /* Iterable or Stream */ values) { | 3664 static yieldStar(dynamic /* Iterable or Stream */ values) { |
| 3664 return new IterationMarker._(YIELD_STAR, values); | 3665 return new IterationMarker._(YIELD_STAR, values); |
| 3665 } | 3666 } |
| 3666 | 3667 |
| 3667 static endOfIteration() { | 3668 static endOfIteration() { |
| 3668 return new IterationMarker._(ITERATION_ENDED, null); | 3669 return new IterationMarker._(ITERATION_ENDED, null); |
| 3669 } | 3670 } |
| 3670 | 3671 |
| 3671 static yieldSingle(dynamic value) { | 3672 static yieldSingle(dynamic value) { |
| 3672 return new IterationMarker._(YIELD_SINGLE, value); | 3673 return new IterationMarker._(YIELD_SINGLE, value); |
| 3673 } | 3674 } |
| 3674 | 3675 |
| 3676 static uncaughtError(dynamic error) { |
| 3677 return new IterationMarker._(UNCAUGHT_ERROR, error); |
| 3678 } |
| 3679 |
| 3675 toString() => "IterationMarker($state, $value)"; | 3680 toString() => "IterationMarker($state, $value)"; |
| 3676 } | 3681 } |
| 3677 | 3682 |
| 3678 class SyncStarIterator implements Iterator { | 3683 class SyncStarIterator implements Iterator { |
| 3679 final Function _helper; | 3684 final Function _body; |
| 3680 | 3685 |
| 3681 // If [runningNested] this is the nested iterator, otherwise it is the | 3686 // If [runningNested] this is the nested iterator, otherwise it is the |
| 3682 // current value. | 3687 // current value. |
| 3683 dynamic _current = null; | 3688 dynamic _current = null; |
| 3684 bool _runningNested = false; | 3689 bool _runningNested = false; |
| 3685 | 3690 |
| 3686 get current => _runningNested ? _current.current : _current; | 3691 get current => _runningNested ? _current.current : _current; |
| 3687 | 3692 |
| 3688 SyncStarIterator(helper) | 3693 SyncStarIterator(body) |
| 3689 : _helper = ((arg) => JS('', '#(#)', helper, arg)); | 3694 : _body = (() => JS('', '#()', body)); |
| 3690 | 3695 |
| 3691 bool moveNext() { | 3696 bool moveNext() { |
| 3692 if (_runningNested) { | 3697 if (_runningNested) { |
| 3693 if (_current.moveNext()) { | 3698 if (_current.moveNext()) { |
| 3694 return true; | 3699 return true; |
| 3695 } else { | 3700 } else { |
| 3696 _runningNested = false; | 3701 _runningNested = false; |
| 3697 } | 3702 } |
| 3698 } | 3703 } |
| 3699 _current = _helper(null); | 3704 _current = _body(); |
| 3700 if (_current is IterationMarker) { | 3705 if (_current is IterationMarker) { |
| 3701 if (_current.state == IterationMarker.ITERATION_ENDED) { | 3706 if (_current.state == IterationMarker.ITERATION_ENDED) { |
| 3702 _current = null; | 3707 _current = null; |
| 3703 // Rely on [_helper] to repeatedly return `ITERATION_ENDED`. | 3708 // Rely on [_body] to repeatedly return `ITERATION_ENDED`. |
| 3704 return false; | 3709 return false; |
| 3710 } else if (_current.state == IterationMarker.UNCAUGHT_ERROR) { |
| 3711 // Rely on [_body] to repeatedly return `UNCAUGHT_ERROR`. |
| 3712 // This is a wrapped exception, so we use JavaScript throw to throw it. |
| 3713 JS('', 'throw #', _current.value); |
| 3705 } else { | 3714 } else { |
| 3706 assert(_current.state == IterationMarker.YIELD_STAR); | 3715 assert(_current.state == IterationMarker.YIELD_STAR); |
| 3707 _current = _current.value.iterator; | 3716 _current = _current.value.iterator; |
| 3708 _runningNested = true; | 3717 _runningNested = true; |
| 3709 return moveNext(); | 3718 return moveNext(); |
| 3710 } | 3719 } |
| 3711 } | 3720 } |
| 3712 return true; | 3721 return true; |
| 3713 } | 3722 } |
| 3714 } | 3723 } |
| 3715 | 3724 |
| 3716 /// An Iterable corresponding to a sync* method. | 3725 /// An Iterable corresponding to a sync* method. |
| 3717 /// | 3726 /// |
| 3718 /// Each invocation of a sync* method will return a new instance of this class. | 3727 /// Each invocation of a sync* method will return a new instance of this class. |
| 3719 class SyncStarIterable extends IterableBase { | 3728 class SyncStarIterable extends IterableBase { |
| 3720 // This is a function that will return a helper function that does the | 3729 // This is a function that will return a helper function that does the |
| 3721 // iteration of the sync*. | 3730 // iteration of the sync*. |
| 3722 // | 3731 // |
| 3723 // Each invocation should give a helper with fresh state. | 3732 // Each invocation should give a body with fresh state. |
| 3724 final dynamic /* js function */ _outerHelper; | 3733 final dynamic /* js function */ _outerHelper; |
| 3725 | 3734 |
| 3726 SyncStarIterable(this._outerHelper); | 3735 SyncStarIterable(this._outerHelper); |
| 3727 | 3736 |
| 3728 Iterator get iterator => new SyncStarIterator(JS('', '#()', _outerHelper)); | 3737 Iterator get iterator => new SyncStarIterator(JS('', '#()', _outerHelper)); |
| 3729 } | 3738 } |
| OLD | NEW |