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 import "dart:math"; | 5 import "dart:math"; |
6 import "dart:typed_data"; | 6 import "dart:typed_data"; |
7 | 7 |
8 // Equivalent of calling FATAL from C++ code. | 8 // Equivalent of calling FATAL from C++ code. |
9 _fatal(msg) native "DartCore_fatal"; | 9 _fatal(msg) native "DartCore_fatal"; |
10 | 10 |
(...skipping 18 matching lines...) Expand all Loading... | |
29 | 29 |
30 | 30 |
31 // _AsyncStarStreamController is used by the compiler to implement | 31 // _AsyncStarStreamController is used by the compiler to implement |
32 // async* generator functions. | 32 // async* generator functions. |
33 class _AsyncStarStreamController { | 33 class _AsyncStarStreamController { |
34 StreamController controller; | 34 StreamController controller; |
35 Function asyncStarBody; | 35 Function asyncStarBody; |
36 bool isAdding = false; | 36 bool isAdding = false; |
37 bool onListenReceived = false; | 37 bool onListenReceived = false; |
38 bool isScheduled = false; | 38 bool isScheduled = false; |
39 bool isSuspendedAtYield = false; | |
39 Completer cancellationCompleter = null; | 40 Completer cancellationCompleter = null; |
40 | 41 |
41 Stream get stream => controller.stream; | 42 Stream get stream => controller.stream; |
42 | 43 |
43 void runBody() { | 44 void runBody() { |
44 isScheduled = false; | 45 isScheduled = false; |
46 isSuspendedAtYield = false; | |
Lasse Reichstein Nielsen
2015/04/09 06:35:30
If I understand this correctly, your possible stat
hausner
2015/04/09 17:10:19
I agree that the code and comments could be cleare
| |
45 asyncStarBody(); | 47 asyncStarBody(); |
46 } | 48 } |
47 | 49 |
48 void scheduleGenerator() { | 50 void scheduleGenerator() { |
49 if (isScheduled || controller.isPaused || isAdding) { | 51 if (isScheduled || controller.isPaused || isAdding) { |
50 return; | 52 return; |
51 } | 53 } |
52 isScheduled = true; | 54 isScheduled = true; |
53 scheduleMicrotask(runBody); | 55 scheduleMicrotask(runBody); |
54 } | 56 } |
55 | 57 |
56 // Adds element to steam, returns true if the caller should terminate | 58 // Adds element to steam, returns true if the caller should terminate |
57 // execution of the generator. | 59 // execution of the generator. |
58 // | 60 // |
59 // TODO(hausner): Per spec, the generator should be suspended before | 61 // TODO(hausner): Per spec, the generator should be suspended before |
60 // exiting when the stream is closed. We could add a getter like this: | 62 // exiting when the stream is closed. We could add a getter like this: |
61 // get isCancelled => controller.hasListener; | 63 // get isCancelled => controller.hasListener; |
62 // The generator would translate a 'yield e' statement to | 64 // The generator would translate a 'yield e' statement to |
63 // controller.add(e); | 65 // controller.add(e); |
64 // suspend; | 66 // suspend; |
65 // if (controller.isCanelled) return; | 67 // if (controller.isCancelled) return; |
66 bool add(event) { | 68 bool add(event) { |
67 if (!onListenReceived) _fatal("yield before stream is listened to!"); | 69 if (!onListenReceived) _fatal("yield before stream is listened to!"); |
70 if (isSuspendedAtYield) _fatal("unexpected yield"); | |
68 // If stream is cancelled, tell caller to exit the async generator. | 71 // If stream is cancelled, tell caller to exit the async generator. |
69 if (!controller.hasListener) { | 72 if (!controller.hasListener) { |
70 return true; | 73 return true; |
71 } | 74 } |
72 controller.add(event); | 75 controller.add(event); |
73 scheduleGenerator(); | 76 scheduleGenerator(); |
77 isSuspendedAtYield = true; | |
74 return false; | 78 return false; |
75 } | 79 } |
76 | 80 |
77 // Adds the elements of stream into this controller's stream. | 81 // Adds the elements of stream into this controller's stream. |
78 // The generator will be scheduled again when all of the | 82 // The generator will be scheduled again when all of the |
79 // elements of the added stream have been consumed. | 83 // elements of the added stream have been consumed. |
80 // Returns true if the caller should terminate | 84 // Returns true if the caller should terminate |
81 // execution of the generator. | 85 // execution of the generator. |
82 bool addStream(Stream stream) { | 86 bool addStream(Stream stream) { |
83 if (!onListenReceived) _fatal("yield before stream is listened to!"); | 87 if (!onListenReceived) _fatal("yield before stream is listened to!"); |
(...skipping 40 matching lines...) Expand 10 before | Expand all | Expand 10 after Loading... | |
124 onCancel: this.onCancel); | 128 onCancel: this.onCancel); |
125 } | 129 } |
126 | 130 |
127 onListen() { | 131 onListen() { |
128 assert(!onListenReceived); | 132 assert(!onListenReceived); |
129 onListenReceived = true; | 133 onListenReceived = true; |
130 scheduleGenerator(); | 134 scheduleGenerator(); |
131 } | 135 } |
132 | 136 |
133 onResume() { | 137 onResume() { |
134 scheduleGenerator(); | 138 if (isSuspendedAtYield) { |
139 scheduleGenerator(); | |
140 } | |
135 } | 141 } |
136 | 142 |
137 onCancel() { | 143 onCancel() { |
138 if (controller.isClosed) { | 144 if (controller.isClosed) { |
139 return null; | 145 return null; |
140 } | 146 } |
141 if (cancellationCompleter == null) { | 147 if (cancellationCompleter == null) { |
142 cancellationCompleter = new Completer(); | 148 cancellationCompleter = new Completer(); |
143 scheduleGenerator(); | 149 scheduleGenerator(); |
144 } | 150 } |
(...skipping 48 matching lines...) Expand 10 before | Expand all | Expand 10 after Loading... | |
193 if (isYieldEach) { | 199 if (isYieldEach) { |
194 // Spec mandates: it is a dynamic error if the class of [the object | 200 // Spec mandates: it is a dynamic error if the class of [the object |
195 // returned by yield*] does not implement Iterable. | 201 // returned by yield*] does not implement Iterable. |
196 yieldEachIterator = (current as Iterable).iterator; | 202 yieldEachIterator = (current as Iterable).iterator; |
197 continue; | 203 continue; |
198 } | 204 } |
199 return true; | 205 return true; |
200 } | 206 } |
201 } | 207 } |
202 } | 208 } |
OLD | NEW |