Chromium Code Reviews| Index: sdk/lib/_internal/compiler/js_lib/js_helper.dart |
| diff --git a/sdk/lib/_internal/compiler/js_lib/js_helper.dart b/sdk/lib/_internal/compiler/js_lib/js_helper.dart |
| index 97b1a9d9ef1a2dcf9162f8dd4af58573679c137d..38e94d539a22b0ead30c11d9969c0ff605bcd6a9 100644 |
| --- a/sdk/lib/_internal/compiler/js_lib/js_helper.dart |
| +++ b/sdk/lib/_internal/compiler/js_lib/js_helper.dart |
| @@ -25,7 +25,8 @@ import 'dart:_isolate_helper' show |
| enterJsAsync, |
| isWorker; |
| -import 'dart:async' show Future, DeferredLoadException, Completer; |
| +import 'dart:async' |
| + show Future, DeferredLoadException, Completer, StreamController; |
| import 'dart:_foreign_helper' show |
| DART_CLOSURE_TO_JS, |
| @@ -3456,3 +3457,173 @@ void badMain() { |
| void mainHasTooManyParameters() { |
| throw new MainError("'main' expects too many parameters."); |
| } |
| + |
| +/// Runtime support for async-await transformation. |
| +// If helperCallback is null we complete the completer with object. |
|
floitsch
2015/02/02 22:00:12
Explain more.
Is errorCallback necessary?...
sigurdm
2015/02/03 16:59:32
The error callback will redirect the control flow
floitsch
2015/02/04 12:31:27
Yes. I was talking about another implementation. F
|
| +// If helperCallback or errorCallback throws we complete the completer with |
| +// the error. |
| +thenHelper(object, |
|
floitsch
2015/02/02 22:00:11
Types.
sigurdm
2015/02/03 16:59:32
Done.
|
| + helperCallback, |
| + Completer completer, |
| + errorCallback) { |
| + if (helperCallback == null) { |
| + completer.complete(object); |
| + return; |
| + } |
| + Future future = object is Future ? object : new Future.value(object); |
| + future.then(new WrappedJsFunction(helperCallback, completer), |
| + onError: new WrappedJsFunction(errorCallback, completer)); |
| + return completer.future; |
| +} |
| + |
| +// Used to avoid creating two identical closure classes in [thenHelper]. |
| +class WrappedJsFunction { |
|
floitsch
2015/02/02 22:00:11
I don't understand this.
Why not:
Function _wrapJ
sigurdm
2015/02/03 16:59:32
That is better, thanks
|
| + final function; |
| + final Completer completer; |
| + |
| + WrappedJsFunction(this.function, this.completer); |
| + |
| + call(result) { |
| + try { |
| + JS('', '#(#)', function, result); |
| + } catch (e, st) { |
| + completer.completeError(e, st); |
| + } |
| + } |
| +} |
| + |
| +// If helperCallback is null we close the stream. |
| +// If helperCallback or errorCallback throws we add the error to the stream |
|
floitsch
2015/02/02 22:00:11
Add more documentation what exactly is expected an
sigurdm
2015/02/03 16:59:32
Done.
|
| +// If the object is a YIELD_SINGLE we add the object to the stream. |
| +streamHelper(object, |
|
floitsch
2015/02/02 22:00:12
add real dartdoc.
types.
sigurdm
2015/02/03 16:59:32
Done.
|
| + helperCallback, |
| + StreamController controller, |
| + errorCallback) { |
| + print("Called with $controller"); |
|
floitsch
2015/02/02 22:00:11
debug line.
sigurdm
2015/02/03 16:59:32
Done.
|
| + if (helperCallback == null) { |
| + // This happens on return from the async* function. |
| + controller.close(); |
| + return; |
| + } |
| + |
| + if (object is IterationMarker) { |
| + if (object.state == IterationMarker.YIELD_SINGLE) { |
| + controller.add(object.value); |
| + } else if (object.state == IterationMarker.YIELD_STAR) { |
| + // TODO(sigurdm): Handle yield star from async*. |
|
floitsch
2015/02/02 22:00:11
Don't silently ignore the value.
sigurdm
2015/02/03 16:59:32
Done.
|
| + } |
| + if (controller.isPaused) { |
| + return; |
| + } else if (controller.isCanceled) { |
| + // TODO(sigurdm): Handle cancelled streams. |
| + } |
| + object = null; |
| + } |
| + |
| + Future future = object is Future ? object : new Future.value(object); |
| + future.then(new WrappedJsFunctionForStream(helperCallback, controller), |
| + onError: errorCallback = null |
| + ? null |
| + : new WrappedJsFunctionForStream(errorCallback, |
| + controller)); |
| + return controller.stream; |
| +} |
| + |
| + |
| +makeAsyncStarController(helperCallBack) { |
| + StreamControllor c; |
| + c = new StreamController( |
| + onResume: () { |
| + // TODO(sigurdm): The errorCallback should not be null. |
| + streamHelper(null, helperCallBack, c, null); |
| + }); |
| + return c; |
| +} |
| + |
| +// Used to avoid creating two identical closure classes in [streamHelper]. |
|
floitsch
2015/02/02 22:00:12
Ditto: I don't like "call" classes. Never sure if
sigurdm
2015/02/03 16:59:32
Done.
|
| +class WrappedJsFunctionForStream { |
| + final function; |
| + final StreamController controller; |
| + |
| + WrappedJsFunctionForStream(this.function, this.controller); |
| + |
| + call(result) { |
| + print(controller); |
|
floitsch
2015/02/02 22:00:11
debugprint.
sigurdm
2015/02/03 16:59:32
Done.
|
| + try { |
| + JS('', "#(#)", function, result); |
| + } catch (e, st) { |
| + controller.addError(e, st); |
| + } |
| + } |
| +} |
| + |
| +class IterationMarker { |
| + static const YIELD_SINGLE = 0; |
| + static const YIELD_STAR = 1; |
| + static const ITERATION_ENDED = 2; |
| + |
| + final value; |
| + final int state; |
| + |
| + IterationMarker._(this.state, this.value); |
| + |
| + static yieldStar(Iterable iterable) { |
| + return new IterationMarker._(YIELD_STAR, iterable); |
| + } |
| + |
| + static endOfIteration() { |
| + return new IterationMarker._(ITERATION_ENDED, null); |
| + } |
| + |
| + static yieldSingle(value) { |
| + return new IterationMarker._(YIELD_SINGLE, value); |
| + } |
| + |
| + toString() => "IterationMarker($state, $value)"; |
| +} |
| + |
| +class SyncStarIterator implements Iterator { |
| + final helper; |
|
floitsch
2015/02/02 22:00:11
should not be public.
sigurdm
2015/02/03 16:59:32
Done.
|
| + |
| + var _current = null; |
| + bool stillRunning = true; |
|
floitsch
2015/02/02 22:00:11
Should not be public.
floitsch
2015/02/02 22:00:12
I don't think we use "stillRunning" in other itera
sigurdm
2015/02/03 16:59:32
Done.
sigurdm
2015/02/03 16:59:32
None of the other Iterators I could find maintains
|
| + bool runningNested = false; |
|
floitsch
2015/02/02 22:00:12
should not be public.
sigurdm
2015/02/03 16:59:33
Done.
|
| + |
| + get current => runningNested ? _current.current : _current; |
| + |
| + SyncStarIterator(helper) |
| + : helper = ((arg) => JS('', '#(#)', helper, arg)); |
|
floitsch
2015/02/02 22:00:11
don't call them the same.
Call the argument jsHel
sigurdm
2015/02/03 16:59:33
Done.
|
| + |
| + bool moveNext() { |
| + if (!stillRunning) return false; |
| + if (runningNested) { |
| + if (_current.moveNext()) { |
| + return true; |
| + } else { |
| + runningNested = false; |
| + } |
| + } |
| + _current = helper(null); |
| + if (_current is IterationMarker) { |
| + if (_current.state == IterationMarker.ITERATION_ENDED) { |
| + _current = null; |
| + stillRunning = false; |
| + } else { |
| + assert(_current.state == IterationMarker.YIELD_STAR); |
| + _current = _current.value.iterator; |
| + runningNested = true; |
| + return moveNext(); |
| + } |
| + } |
| + return stillRunning; |
| + } |
| +} |
| + |
| +class SyncStarIterable extends IterableBase { |
| + final outerHelper; |
|
floitsch
2015/02/02 22:00:11
should not be public.
sigurdm
2015/02/03 16:59:33
Done.
|
| + |
| + SyncStarIterable(this.outerHelper); |
|
floitsch
2015/02/02 22:00:12
Document what this is.
sigurdm
2015/02/03 16:59:32
Done.
|
| + |
| + Iterator get iterator => new SyncStarIterator(JS('', '#()', outerHelper)); |
| +} |
| + |