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