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)); |
+} |
+ |