| 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 |
| 11 // We need to pass the exception and stack trace objects as second and third | |
| 12 // parameter to the continuation. See vm/ast_transformer.cc for usage. | |
| 13 void _asyncCatchHelper(catchFunction, continuation) { | |
| 14 catchFunction((e, s) => continuation(null, e, s)); | |
| 15 } | |
| 16 | |
| 17 // The members of this class are cloned and added to each class that | 11 // The members of this class are cloned and added to each class that |
| 18 // represents an enum type. | 12 // represents an enum type. |
| 19 class _EnumHelper { | 13 class _EnumHelper { |
| 20 // Declare the list of enum value names private. When this field is | 14 // Declare the list of enum value names private. When this field is |
| 21 // cloned into a user-defined enum class, the field will be inaccessible | 15 // cloned into a user-defined enum class, the field will be inaccessible |
| 22 // because of the library-specific name suffix. The toString() function | 16 // because of the library-specific name suffix. The toString() function |
| 23 // below can access it because it uses the same name suffix. | 17 // below can access it because it uses the same name suffix. |
| 24 static const List<String> _enum_names = null; | 18 static const List<String> _enum_names = null; |
| 25 String toString() => _enum_names[index]; | 19 String toString() => _enum_names[index]; |
| 26 int get hashCode => _enum_names[index].hashCode; | 20 int get hashCode => _enum_names[index].hashCode; |
| 27 } | 21 } |
| 28 | 22 |
| 29 | |
| 30 // _AsyncStarStreamController is used by the compiler to implement | |
| 31 // async* generator functions. | |
| 32 class _AsyncStarStreamController { | |
| 33 StreamController controller; | |
| 34 Function asyncStarBody; | |
| 35 bool isAdding = false; | |
| 36 bool onListenReceived = false; | |
| 37 bool isScheduled = false; | |
| 38 bool isSuspendedAtYield = false; | |
| 39 Completer cancellationCompleter = null; | |
| 40 | |
| 41 Stream get stream => controller.stream; | |
| 42 | |
| 43 void runBody() { | |
| 44 isScheduled = false; | |
| 45 isSuspendedAtYield = false; | |
| 46 asyncStarBody(); | |
| 47 } | |
| 48 | |
| 49 void scheduleGenerator() { | |
| 50 if (isScheduled || controller.isPaused || isAdding) { | |
| 51 return; | |
| 52 } | |
| 53 isScheduled = true; | |
| 54 scheduleMicrotask(runBody); | |
| 55 } | |
| 56 | |
| 57 // Adds element to steam, returns true if the caller should terminate | |
| 58 // execution of the generator. | |
| 59 // | |
| 60 // TODO(hausner): Per spec, the generator should be suspended before | |
| 61 // exiting when the stream is closed. We could add a getter like this: | |
| 62 // get isCancelled => controller.hasListener; | |
| 63 // The generator would translate a 'yield e' statement to | |
| 64 // controller.add(e); | |
| 65 // suspend; | |
| 66 // if (controller.isCancelled) return; | |
| 67 bool add(event) { | |
| 68 if (!onListenReceived) _fatal("yield before stream is listened to!"); | |
| 69 if (isSuspendedAtYield) _fatal("unexpected yield"); | |
| 70 // If stream is cancelled, tell caller to exit the async generator. | |
| 71 if (!controller.hasListener) { | |
| 72 return true; | |
| 73 } | |
| 74 controller.add(event); | |
| 75 scheduleGenerator(); | |
| 76 isSuspendedAtYield = true; | |
| 77 return false; | |
| 78 } | |
| 79 | |
| 80 // Adds the elements of stream into this controller's stream. | |
| 81 // The generator will be scheduled again when all of the | |
| 82 // elements of the added stream have been consumed. | |
| 83 // Returns true if the caller should terminate | |
| 84 // execution of the generator. | |
| 85 bool addStream(Stream stream) { | |
| 86 if (!onListenReceived) _fatal("yield before stream is listened to!"); | |
| 87 // If stream is cancelled, tell caller to exit the async generator. | |
| 88 if (!controller.hasListener) return true; | |
| 89 isAdding = true; | |
| 90 var whenDoneAdding = | |
| 91 controller.addStream(stream as Stream, cancelOnError: false); | |
| 92 whenDoneAdding.then((_) { | |
| 93 isAdding = false; | |
| 94 scheduleGenerator(); | |
| 95 }); | |
| 96 return false; | |
| 97 } | |
| 98 | |
| 99 void addError(error, stackTrace) { | |
| 100 if ((cancellationCompleter != null) && !cancellationCompleter.isCompleted) { | |
| 101 // If the stream has been cancelled, complete the cancellation future | |
| 102 // with the error. | |
| 103 cancellationCompleter.completeError(error, stackTrace); | |
| 104 return; | |
| 105 } | |
| 106 // If stream is cancelled, tell caller to exit the async generator. | |
| 107 if (!controller.hasListener) return; | |
| 108 controller.addError(error, stackTrace); | |
| 109 // No need to schedule the generator body here. This code is only | |
| 110 // called from the catch clause of the implicit try-catch-finally | |
| 111 // around the generator body. That is, we are on the error path out | |
| 112 // of the generator and do not need to run the generator again. | |
| 113 } | |
| 114 | |
| 115 close() { | |
| 116 if ((cancellationCompleter != null) && !cancellationCompleter.isCompleted) { | |
| 117 // If the stream has been cancelled, complete the cancellation future | |
| 118 // with the error. | |
| 119 cancellationCompleter.complete(); | |
| 120 } | |
| 121 controller.close(); | |
| 122 } | |
| 123 | |
| 124 _AsyncStarStreamController(this.asyncStarBody) { | |
| 125 controller = new StreamController(onListen: this.onListen, | |
| 126 onResume: this.onResume, | |
| 127 onCancel: this.onCancel); | |
| 128 } | |
| 129 | |
| 130 onListen() { | |
| 131 assert(!onListenReceived); | |
| 132 onListenReceived = true; | |
| 133 scheduleGenerator(); | |
| 134 } | |
| 135 | |
| 136 onResume() { | |
| 137 if (isSuspendedAtYield) { | |
| 138 scheduleGenerator(); | |
| 139 } | |
| 140 } | |
| 141 | |
| 142 onCancel() { | |
| 143 if (controller.isClosed) { | |
| 144 return null; | |
| 145 } | |
| 146 if (cancellationCompleter == null) { | |
| 147 cancellationCompleter = new Completer(); | |
| 148 scheduleGenerator(); | |
| 149 } | |
| 150 return cancellationCompleter.future; | |
| 151 } | |
| 152 } | |
| 153 | |
| 154 | |
| 155 // _SyncIterable and _syncIterator are used by the compiler to | 23 // _SyncIterable and _syncIterator are used by the compiler to |
| 156 // implement sync* generator functions. A sync* generator allocates | 24 // implement sync* generator functions. A sync* generator allocates |
| 157 // and returns a new _SyncIterable object. | 25 // and returns a new _SyncIterable object. |
| 158 | 26 |
| 159 typedef bool SyncGeneratorCallback(Iterator iterator); | 27 typedef bool SyncGeneratorCallback(Iterator iterator); |
| 160 | 28 |
| 161 class _SyncIterable extends IterableBase { | 29 class _SyncIterable extends IterableBase { |
| 162 // moveNextFn is the closurized body of the generator function. | 30 // moveNextFn is the closurized body of the generator function. |
| 163 final SyncGeneratorCallback moveNextFn; | 31 final SyncGeneratorCallback moveNextFn; |
| 164 | 32 |
| (...skipping 33 matching lines...) Expand 10 before | Expand all | Expand 10 after Loading... |
| 198 if (isYieldEach) { | 66 if (isYieldEach) { |
| 199 // Spec mandates: it is a dynamic error if the class of [the object | 67 // Spec mandates: it is a dynamic error if the class of [the object |
| 200 // returned by yield*] does not implement Iterable. | 68 // returned by yield*] does not implement Iterable. |
| 201 yieldEachIterator = (current as Iterable).iterator; | 69 yieldEachIterator = (current as Iterable).iterator; |
| 202 continue; | 70 continue; |
| 203 } | 71 } |
| 204 return true; | 72 return true; |
| 205 } | 73 } |
| 206 } | 74 } |
| 207 } | 75 } |
| OLD | NEW |