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

Side by Side Diff: lib/runtime/dart/_generators.js

Issue 1530563003: Generate all runtime files from dart. (Closed) Base URL: git@github.com:dart-lang/dev_compiler.git@master
Patch Set: Reverted to new .dart files in input_sdk: please compare them against previous patchset Created 5 years 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
OLDNEW
1 // Copyright (c) 2015, the Dart project authors. Please see the AUTHORS file
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.
4
5 /**
6 * This library adapts ES6 generators to implement Dart's async/await.
7 *
8 * It's designed to interact with Dart's Future/Stream and follow Dart
9 * async/await semantics.
10 *
11 * See https://github.com/dart-lang/dev_compiler/issues/245 for ideas on
12 * reconciling Dart's Future and ES6 Promise.
13 *
14 * Inspired by `co`: https://github.com/tj/co/blob/master/index.js, which is a
15 * stepping stone for proposed ES7 async/await, and uses ES6 Promises.
16 */
17 dart_library.library('dart/_generators', null, /* Imports */[ 1 dart_library.library('dart/_generators', null, /* Imports */[
18 ], /* Lazy Imports */[ 2 'dart/_classes'
3 ], /* Lazy imports */[
4 'dart/_js_helper',
19 'dart/_operations', 5 'dart/_operations',
20 'dart/_js_helper',
21 'dart/core',
22 'dart/collection',
23 'dart/async' 6 'dart/async'
24 ], function(exports, _operations, _js_helper, core, collection, async) { 7 ], function(exports, classes, _js_helper, _operations, async$) {
25 'use strict'; 8 'use strict';
26 9 const _jsIterator = Symbol("_jsIterator");
27 const _jsIterator = Symbol('_jsIterator'); 10 const _current = Symbol("_current");
28 const _current = Symbol('_current');
29
30 function syncStar(gen, E, ...args) { 11 function syncStar(gen, E, ...args) {
31 const SyncIterable_E = _js_helper.SyncIterable$(E); 12 const SyncIterable_E = _js_helper.SyncIterable$(E);
32 return new SyncIterable_E(gen, args); 13 return new SyncIterable_E(gen, args);
33 } 14 }
34 exports.syncStar = syncStar; 15 function async(gen, T, ...args) {
35
36 function async_(gen, T, ...args) {
37 let iter; 16 let iter;
38 function onValue(res) { 17 function onValue(res) {
39 if (res === void 0) res = null; 18 if (res === void 0) res = null;
40 return next(iter.next(res)); 19 return next(iter.next(res));
41 } 20 }
42 function onError(err) { 21 function onError(err) {
43 // If the awaited Future throws, we want to convert this to an exception
44 // thrown from the `yield` point, as if it was thrown there.
45 //
46 // If the exception is not caught inside `gen`, it will emerge here, which
47 // will send it to anyone listening on this async function's Future<T>.
48 //
49 // In essence, we are giving the code inside the generator a chance to
50 // use try-catch-finally.
51 return next(iter.throw(err)); 22 return next(iter.throw(err));
52 } 23 }
53 function next(ret) { 24 function next(ret) {
54 if (ret.done) return ret.value; 25 if (ret.done) return ret.value;
55 // Checks if the awaited value is a Future.
56 let future = ret.value; 26 let future = ret.value;
57 if (!_operations.instanceOf(future, async.Future$)) { 27 if (!_operations.instanceOf(future, async$.Future$)) {
58 future = async.Future.value(future); 28 future = async$.Future.value(future);
59 } 29 }
60 // Chain the Future so `await` receives the Future's value.
61 return future.then(onValue, {onError: onError}); 30 return future.then(onValue, {onError: onError});
62 } 31 }
63 return async.Future$(T).new(function() { 32 return async$.Future$(T).new(function() {
64 iter = gen(...args)[Symbol.iterator](); 33 iter = gen(...args)[Symbol.iterator]();
65 return onValue(); 34 return onValue();
66 }); 35 });
67 } 36 }
68 exports.async = async_; 37 const _AsyncStarStreamController = class _AsyncStarStreamController {
69
70 // Implementation inspired by _AsyncStarStreamController in
71 // dart-lang/sdk's runtime/lib/core_patch.dart
72 //
73 // Given input like:
74 //
75 // foo() async* {
76 // yield 1;
77 // yield* bar();
78 // print(await baz());
79 // }
80 //
81 // This generates as:
82 //
83 // function foo() {
84 // return dart.asyncStar(function*(stream) {
85 // if (stream.add(1)) return;
86 // yield;
87 // if (stream.addStream(bar()) return;
88 // yield;
89 // print(yield baz());
90 // });
91 // }
92 class _AsyncStarStreamController {
93 constructor(generator, T, args) { 38 constructor(generator, T, args) {
94 this.isAdding = false; 39 this.isAdding = false;
95 this.isWaiting = false; 40 this.isWaiting = false;
96 this.isScheduled = false; 41 this.isScheduled = false;
97 this.isSuspendedAtYield = false; 42 this.isSuspendedAtYield = false;
98 this.canceler = null; 43 this.canceler = null;
99 this.iterator = generator(this, ...args)[Symbol.iterator](); 44 this.iterator = generator(this, ...args)[Symbol.iterator]();
100 this.controller = async.StreamController$(T).new({ 45 this.controller = async$.StreamController$(T).new({
101 onListen: () => this.scheduleGenerator(), 46 onListen: (() => this.scheduleGenerator()).bind(this),
102 onResume: () => this.onResume(), 47 onResume: (() => this.onResume()).bind(this),
103 onCancel: () => this.onCancel() 48 onCancel: (() => this.onCancel()).bind(this)
104 }); 49 });
105 } 50 }
106
107 onResume() { 51 onResume() {
108 if (this.isSuspendedAtYield) { 52 if (this.isSuspendedAtYield) {
109 this.scheduleGenerator(); 53 this.scheduleGenerator();
110 } 54 }
111 } 55 }
112
113 onCancel() { 56 onCancel() {
114 if (this.controller.isClosed) { 57 if (this.controller.isClosed) {
115 return null; 58 return null;
116 } 59 }
117 if (this.canceler == null) { 60 if (this.canceler == null) {
118 this.canceler = async.Completer.new(); 61 this.canceler = async$.Completer.new();
119 this.scheduleGenerator(); 62 this.scheduleGenerator();
120 } 63 }
121 return this.canceler.future; 64 return this.canceler.future;
122 } 65 }
123
124 close() { 66 close() {
125 if (this.canceler != null && !this.canceler.isCompleted) { 67 if (this.canceler != null && !this.canceler.isCompleted) {
126 // If the stream has been cancelled, complete the cancellation future
127 // with the error.
128 this.canceler.complete(); 68 this.canceler.complete();
129 } 69 }
130 this.controller.close(); 70 this.controller.close();
131 } 71 }
132
133 scheduleGenerator() { 72 scheduleGenerator() {
134 // TODO(jmesserly): is this paused check in the right place? Assuming the 73 if (this.isScheduled || this.controller.isPaused || this.isAdding || this. isWaiting) {
135 // async* Stream yields, then is paused (by other code), the body will
136 // already be scheduled. This will cause at least one more iteration to
137 // run (adding another data item to the Stream) before actually pausing.
138 // It could be fixed by moving the `isPaused` check inside `runBody`.
139 if (this.isScheduled || this.controller.isPaused ||
140 this.isAdding || this.isWaiting) {
141 return; 74 return;
142 } 75 }
143 this.isScheduled = true; 76 this.isScheduled = true;
144 async.scheduleMicrotask(() => this.runBody()); 77 async$.scheduleMicrotask((() => this.runBody()).bind(this));
145 } 78 }
146
147 runBody(opt_awaitValue) { 79 runBody(opt_awaitValue) {
148 this.isScheduled = false; 80 this.isScheduled = false;
149 this.isSuspendedAtYield = false; 81 this.isSuspendedAtYield = false;
150 this.isWaiting = false; 82 this.isWaiting = false;
151 let iter; 83 let iter;
152 try { 84 try {
153 iter = this.iterator.next(opt_awaitValue); 85 iter = this.iterator.next(opt_awaitValue);
154 } catch (e) { 86 } catch (e) {
155 this.addError(e, _operations.stackTrace(e)); 87 this.addError(e, _operations.stackTrace(e));
156 this.close(); 88 this.close();
157 return; 89 return;
158 } 90 }
91
159 if (iter.done) { 92 if (iter.done) {
160 this.close(); 93 this.close();
161 return; 94 return;
162 } 95 }
163
164 // If we're suspended at a yield/yield*, we're done for now.
165 if (this.isSuspendedAtYield || this.isAdding) return; 96 if (this.isSuspendedAtYield || this.isAdding) return;
166
167 // Handle `await`: if we get a value passed to `yield` it means we are
168 // waiting on this Future. Make sure to prevent scheduling, and pass the
169 // value back as the result of the `yield`.
170 //
171 // TODO(jmesserly): is the timing here correct? The assumption here is
172 // that we should schedule `await` in `async*` the same as in `async`.
173 this.isWaiting = true; 97 this.isWaiting = true;
174 let future = iter.value; 98 let future = iter.value;
175 if (!_operations.instanceOf(future, async.Future$)) { 99 if (!_operations.instanceOf(future, async$.Future$)) {
176 future = async.Future.value(future); 100 future = async$.Future.value(future);
177 } 101 }
178 return future.then((x) => this.runBody(x), 102 return future.then((x => this.runBody(x)).bind(this), {
179 { onError: (e, s) => this.throwError(e, s) }); 103 onError: ((e, s) => this.throwError(e, s)).bind(this)
104 });
180 } 105 }
181
182 // Adds element to stream, returns true if the caller should terminate
183 // execution of the generator.
184 add(event) { 106 add(event) {
185 // If stream is cancelled, tell caller to exit the async generator.
186 if (!this.controller.hasListener) return true; 107 if (!this.controller.hasListener) return true;
187 this.controller.add(event); 108 this.controller.add(event);
188 this.scheduleGenerator(); 109 this.scheduleGenerator();
189 this.isSuspendedAtYield = true; 110 this.isSuspendedAtYield = true;
190 return false; 111 return false;
191 } 112 }
192
193 // Adds the elements of stream into this controller's stream.
194 // The generator will be scheduled again when all of the
195 // elements of the added stream have been consumed.
196 // Returns true if the caller should terminate
197 // execution of the generator.
198 addStream(stream) { 113 addStream(stream) {
199 // If stream is cancelled, tell caller to exit the async generator.
200 if (!this.controller.hasListener) return true; 114 if (!this.controller.hasListener) return true;
201
202 this.isAdding = true; 115 this.isAdding = true;
203 this.controller.addStream(stream, {cancelOnError: false}).then(() => { 116 this.controller.addStream(stream, {cancelOnError: false}).then((() => {
204 this.isAdding = false; 117 this.isAdding = false;
205 this.scheduleGenerator(); 118 this.scheduleGenerator();
206 }, { onError: (e, s) => this.throwError(e, s) }); 119 }).bind(this), {
120 onError: ((e, s) => this.throwError(e, s)).bind(this)
121 });
207 } 122 }
208
209 throwError(error, stackTrace) { 123 throwError(error, stackTrace) {
210 try { 124 try {
211 this.iterator.throw(error); 125 this.iterator.throw(error);
212 } catch (e) { 126 } catch (e) {
213 this.addError(e, stackTrace); 127 this.addError(e, stackTrace);
214 } 128 }
129
215 } 130 }
216
217 addError(error, stackTrace) { 131 addError(error, stackTrace) {
218 if ((this.canceler != null) && !this.canceler.isCompleted) { 132 if (this.canceler != null && !this.canceler.isCompleted) {
219 // If the stream has been cancelled, complete the cancellation future
220 // with the error.
221 this.canceler.completeError(error, stackTrace); 133 this.canceler.completeError(error, stackTrace);
222 return; 134 return;
223 } 135 }
224 if (!this.controller.hasListener) return; 136 if (!this.controller.hasListener) return;
225 this.controller.addError(error, stackTrace); 137 this.controller.addError(error, stackTrace);
226 } 138 }
227 } 139 };
228
229 /** Returns a Stream of T implemented by an async* function. */
230 function asyncStar(gen, T, ...args) { 140 function asyncStar(gen, T, ...args) {
231 return new _AsyncStarStreamController(gen, T, args).controller.stream; 141 return new _AsyncStarStreamController(gen, T, args).controller.stream;
232 } 142 }
143 // Exports:
144 exports.syncStar = syncStar;
145 exports.async = async;
233 exports.asyncStar = asyncStar; 146 exports.asyncStar = asyncStar;
234 }); 147 });
OLDNEW

Powered by Google App Engine
This is Rietveld 408576698