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

Side by Side Diff: tool/input_sdk/private/generators.dart

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

Powered by Google App Engine
This is Rietveld 408576698