2 module.exports = function(Promise,
8 var errors = require("./errors");
9 var TypeError = errors.TypeError;
10 var util = require("./util");
11 var errorObj = util.errorObj;
12 var tryCatch = util.tryCatch;
13 var yieldHandlers = [];
15 function promiseFromYieldHandler(value, yieldHandlers, traceParent) {
16 for (var i = 0; i < yieldHandlers.length; ++i) {
17 traceParent._pushContext();
18 var result = tryCatch(yieldHandlers[i])(value);
19 traceParent._popContext();
20 if (result === errorObj) {
21 traceParent._pushContext();
22 var ret = Promise.reject(errorObj.e);
23 traceParent._popContext();
26 var maybePromise = tryConvertToPromise(result, traceParent);
27 if (maybePromise instanceof Promise) return maybePromise;
32 function PromiseSpawn(generatorFunction, receiver, yieldHandler, stack) {
33 var promise = this._promise = new Promise(INTERNAL);
34 promise._captureStackTrace();
35 promise._setOnCancel(this);
37 this._generatorFunction = generatorFunction;
38 this._receiver = receiver;
39 this._generator = undefined;
40 this._yieldHandlers = typeof yieldHandler === "function"
41 ? [yieldHandler].concat(yieldHandlers)
43 this._yieldedPromise = null;
45 util.inherits(PromiseSpawn, Proxyable);
47 PromiseSpawn.prototype._isResolved = function() {
48 return this._promise === null;
51 PromiseSpawn.prototype._cleanup = function() {
52 this._promise = this._generator = null;
55 PromiseSpawn.prototype._promiseCancelled = function() {
56 if (this._isResolved()) return;
57 var implementsReturn = typeof this._generator["return"] !== "undefined";
60 if (!implementsReturn) {
61 var reason = new Promise.CancellationError(
62 "generator .return() sentinel");
63 Promise.coroutine.returnSentinel = reason;
64 this._promise._attachExtraTrace(reason);
65 this._promise._pushContext();
66 result = tryCatch(this._generator["throw"]).call(this._generator,
68 this._promise._popContext();
69 if (result === errorObj && result.e === reason) {
73 this._promise._pushContext();
74 result = tryCatch(this._generator["return"]).call(this._generator,
76 this._promise._popContext();
78 var promise = this._promise;
80 if (result === errorObj) {
81 promise._rejectCallback(result.e, false);
87 PromiseSpawn.prototype._promiseFulfilled = function(value) {
88 this._yieldedPromise = null;
89 this._promise._pushContext();
90 var result = tryCatch(this._generator.next).call(this._generator, value);
91 this._promise._popContext();
92 this._continue(result);
95 PromiseSpawn.prototype._promiseRejected = function(reason) {
96 this._yieldedPromise = null;
97 this._promise._attachExtraTrace(reason);
98 this._promise._pushContext();
99 var result = tryCatch(this._generator["throw"])
100 .call(this._generator, reason);
101 this._promise._popContext();
102 this._continue(result);
105 PromiseSpawn.prototype._resultCancelled = function() {
106 if (this._yieldedPromise instanceof Promise) {
107 var promise = this._yieldedPromise;
108 this._yieldedPromise = null;
113 PromiseSpawn.prototype.promise = function () {
114 return this._promise;
117 PromiseSpawn.prototype._run = function () {
118 this._generator = this._generatorFunction.call(this._receiver);
120 this._generatorFunction = undefined;
121 this._promiseFulfilled(undefined);
124 PromiseSpawn.prototype._continue = function (result) {
125 var promise = this._promise;
126 if (result === errorObj) {
128 return promise._rejectCallback(result.e, false);
131 var value = result.value;
132 if (result.done === true) {
134 return promise._resolveCallback(value);
136 var maybePromise = tryConvertToPromise(value, this._promise);
137 if (!(maybePromise instanceof Promise)) {
139 promiseFromYieldHandler(maybePromise,
142 if (maybePromise === null) {
143 this._promiseRejected(
145 "A value %s was yielded that could not be treated as a promise\u000a\u000a See http://goo.gl/MqrFmX\u000a\u000a".replace("%s", value) +
146 "From coroutine:\u000a" +
147 this._stack.split("\n").slice(1, -7).join("\n")
153 maybePromise = maybePromise._target();
154 var bitField = maybePromise._bitField;
156 if (((bitField & 50397184) === 0)) {
157 this._yieldedPromise = maybePromise;
158 maybePromise._proxy(this, null);
159 } else if (((bitField & 33554432) !== 0)) {
160 this._promiseFulfilled(maybePromise._value());
161 } else if (((bitField & 16777216) !== 0)) {
162 this._promiseRejected(maybePromise._reason());
164 this._promiseCancelled();
169 Promise.coroutine = function (generatorFunction, options) {
170 if (typeof generatorFunction !== "function") {
171 throw new TypeError("generatorFunction must be a function\u000a\u000a See http://goo.gl/MqrFmX\u000a");
173 var yieldHandler = Object(options).yieldHandler;
174 var PromiseSpawn$ = PromiseSpawn;
175 var stack = new Error().stack;
177 var generator = generatorFunction.apply(this, arguments);
178 var spawn = new PromiseSpawn$(undefined, undefined, yieldHandler,
180 var ret = spawn.promise();
181 spawn._generator = generator;
182 spawn._promiseFulfilled(undefined);
187 Promise.coroutine.addYieldHandler = function(fn) {
188 if (typeof fn !== "function") {
189 throw new TypeError("expecting a function but got " + util.classString(fn));
191 yieldHandlers.push(fn);
194 Promise.spawn = function (generatorFunction) {
195 debug.deprecated("Promise.spawn()", "Promise.coroutine()");
196 if (typeof generatorFunction !== "function") {
197 return apiRejection("generatorFunction must be a function\u000a\u000a See http://goo.gl/MqrFmX\u000a");
199 var spawn = new PromiseSpawn(generatorFunction, this);
200 var ret = spawn.promise();
201 spawn._run(Promise.spawn);