diff --git a/lib/coro.js b/lib/coro.js index 629f625..c3723c5 100644 --- a/lib/coro.js +++ b/lib/coro.js @@ -10,10 +10,15 @@ function currentCoro () { exports.resume = function () { var coro = currentCoro(); return function (error) { + var result = error ? null : Array.prototype.slice.call(arguments, 1); + if (coros.length && coro === coros[coros.length - 1]) { + coro.save(error, result); + return; + } var val, err; coros.push(coro); try { - val = error ? coro.generator.throw(error) : coro.generator.next(Array.prototype.slice.call(arguments, 1)); + val = error ? coro.generator.throw(error) : coro.generator.next(result); } catch (e) { err = e; @@ -24,11 +29,15 @@ exports.resume = function () { exports.resumeFirst = function () { var coro = currentCoro(); - return function (error, res) { + return function (error, result) { + if (coros.length && coro === coros[coros.length - 1]) { + coro.save(error, result); + return; + } var val, err; coros.push(coro); try { - val = error ? coro.generator.throw(error) : coro.generator.next(res); + val = error ? coro.generator.throw(error) : coro.generator.next(result); } catch (e) { err = e; @@ -40,10 +49,15 @@ exports.resumeFirst = function () { exports.resumeNth = function (n) { var coro = currentCoro(); return function (error) { + var result = error ? null : arguments[n]; + if (coros.length && coro === coros[coros.length - 1]) { + coro.save(error, result); + return; + } var val, err; coros.push(coro); try { - val = error ? coro.generator.throw(error) : coro.generator.next(arguments[n]); + val = error ? coro.generator.throw(error) : coro.generator.next(result); } catch (e) { err = e; @@ -55,10 +69,15 @@ exports.resumeNth = function (n) { exports.resumeNoThrow = function () { var coro = currentCoro(); return function () { + var result = Array.prototype.slice.call(arguments, 0); + if (coros.length && coro === coros[coros.length - 1]) { + coro.save(null, result); + return; + } var val, err; coros.push(coro); try { - val = coro.generator.next(Array.prototype.slice.call(arguments, 0)); + val = coro.generator.next(result); } catch (e) { err = e; @@ -70,6 +89,10 @@ exports.resumeNoThrow = function () { exports.resumeNoThrowFirst = function () { var coro = currentCoro(); return function (first) { + if (coros.length && coro === coros[coros.length - 1]) { + coro.save(null, first); + return; + } var val, err; coros.push(coro); try { @@ -85,10 +108,15 @@ exports.resumeNoThrowFirst = function () { exports.resumeNoThrowNth = function (n) { var coro = currentCoro(); return function () { + var result = arguments[n]; + if (coros.length && coro === coros[coros.length - 1]) { + coro.save(null, result); + return; + } var val, err; coros.push(coro); try { - val = coro.generator.next(arguments[n]); + val = coro.generator.next(result); } catch (e) { err = e; @@ -100,6 +128,10 @@ exports.resumeNoThrowNth = function (n) { exports.resumeThrow = function () { var coro = currentCoro(); return function (error) { + if (coros.length && coro === coros[coros.length - 1]) { + coro.save(error); + return; + } var val, err; coros.push(coro); try { @@ -119,13 +151,25 @@ var Coro = function (generator, deferred, callback) { }; Coro.prototype.handle = function (err, result) { + var val, err; coros.pop(); - if (err || result.done) { - this.handleResult(err, result); + if (err || this.savedError || result.done) { + this.handleResult(err || this.savedError, result); } else if (result.value && result.value.then) { this.handlePromise(result.value); } + else if (this.savedResult) { + coros.push(this); + try { + val = this.generator.next(this.savedResult); + } + catch (e) { + err = e; + } + this.savedResult = null; + this.handle(err, val); + } }; Coro.prototype.handleResult = function (err, result) { @@ -168,6 +212,14 @@ Coro.prototype.handlePromise = function (promise) { ); }; +Coro.prototype.save = function (error, result) { + if (this.savedResult || this.savedError) { + throw new Error('more than one coro callback called without yield'); + } + this.savedError = error; + this.savedResult = result; +}; + exports.run = function (makeGenerator, args, callback) { var deferred = callback ? null : p.defer(),