axos
Version:
JIT-friendly, multiparadigm asynchronous programming
217 lines (198 loc) • 5.82 kB
JavaScript
(function() {
var CATCH, Cell, FINAL_ERROR, FINAL_VALUE, NO_MORE, Promise, Strategy, TRY, TRY1, axos, empty, getThen, io_send, promiseResolver, ref, runInitializer, send;
ref = axos = require('./'), Cell = ref.Cell, Strategy = ref.Strategy, NO_MORE = ref.NO_MORE, FINAL_VALUE = ref.FINAL_VALUE, FINAL_ERROR = ref.FINAL_ERROR, TRY = ref.TRY, CATCH = ref.CATCH, send = ref.send, io_send = ref.io_send;
empty = new Strategy();
Cell.prototype.then = function(onF, onR) {
return promiseResolver.cell(this, onF, onR);
};
module.exports = axos.Promise = Promise = (function() {
var arrayResolver;
function Promise(init) {
if (init == null) {
init = empty.cell();
}
if (init instanceof Cell) {
this.__cell__ = init;
} else if (typeof init === "function") {
runInitializer(init, null, this.__cell__ = empty.cell(), 1);
} else {
throw new TypeError("Promise must be created from cell or function");
}
}
Promise.prototype.then = function(onF, onR) {
return new Promise(promiseResolver.cell(this.__cell__, onF, onR));
};
Promise.deferred = function() {
var d;
d = {};
d.promise = empty.cell();
runInitializer((function(res, rej) {
d.resolve = res;
return d.reject = rej;
}), null, d.promise, 1);
return d;
};
Promise.promisify = function(fn) {
return function() {
var a, args, cell, i, j, len;
cell = empty.cell();
args = Array(arguments.length + 1);
for (i = j = 0, len = arguments.length; j < len; i = ++j) {
a = arguments[i];
args[i] = a;
}
args[arguments.length] = function(e, v) {
if (e) {
return send(cell, 1, FINAL_ERROR, e);
} else {
return send(cell, 1, FINAL_VALUE, v);
}
};
fn.apply(this, args);
return cell;
};
};
Promise.prototype["catch"] = function(onR) {
return this.then(null, onR);
};
Promise.all = function(promises) {
return new arrayResolver.cell(promises).state;
};
arrayResolver = new Strategy({
onDispose: function() {
return this.seen = this.result = null;
},
initState: function(promises) {
var i, j, len, p, state;
state = new Promise(this);
state.seen = new Array(state.pending = promises.length);
state.result = new Array(state.pending);
for (i = j = 0, len = promises.length; j < len; i = ++j) {
p = promises[i];
p.__cell__.addSink(this, i);
}
return state;
},
onReceive: function(cell, tag, op, arg) {
if (!this.seen[tag]) {
if (op.isError) {
return cell.abort(arg);
}
this.seen[tag] = true;
this.result[tag] = arg;
if (!--this.pending) {
return cell.finish(this.result);
}
}
return NO_MORE;
}
});
return Promise;
})();
promiseResolver = new Strategy({
onReceive: function(cell, tag, op, arg) {
var ref1, ref2, thenF;
if (typeof tag === "function") {
if (op.isError) {
return cell.abort(arg);
}
arg = TRY1(tag, arg);
if (arg === CATCH) {
return cell.abort(CATCH.err);
}
op = FINAL_VALUE;
} else if (typeof tag === "object") {
tag = op.isError ? tag.onR : tag.onF;
if (typeof tag === "function") {
arg = TRY1(tag, arg);
if (arg === CATCH) {
return cell.abort(CATCH.err);
}
op = FINAL_VALUE;
}
}
if (op.isError) {
return cell.abort(arg);
}
if (arg instanceof Promise) {
arg = arg.__cell__;
}
while (arg instanceof Cell) {
if (arg === cell) {
return cell.abort(new TypeError("Can't resolve promise to itself"));
} else {
if (arg.op == null) {
arg.addSink(cell, 0);
return NO_MORE;
}
ref1 = arg, op = ref1.op, arg = ref1.arg;
if (op.isError) {
return cell.abort(arg);
}
if (arg instanceof Promise) {
arg = arg.__cell__;
}
}
}
if (((ref2 = typeof arg) === "object" || ref2 === "function") && arg !== null) {
if ((thenF = TRY1(getThen, arg)) === CATCH) {
return cell.abort(CATCH.err);
}
if (typeof thenF === "function") {
runInitializer(thenF, arg, cell, 0);
return NO_MORE;
}
}
return cell.finish(arg);
},
initState: function(other, onF, onR) {
var tag;
if (other instanceof Cell) {
if (typeof onR !== "function") {
if (typeof onF !== "function") {
tag = 0;
} else {
tag = onF;
}
} else {
tag = {
onF: onF,
onR: onR
};
}
other.addSink(this, tag);
}
}
});
getThen = function(x) {
return x.then;
};
runInitializer = function(init, rcv, cell, step) {
var reject, resolve;
resolve = function(v) {
if (cell !== null) {
send(cell, step, FINAL_VALUE, v);
return cell = null;
}
};
reject = function(e) {
if (cell !== null) {
send(cell, step, FINAL_ERROR, e);
return cell = null;
}
};
if (TRY(init).call(rcv, resolve, reject) === CATCH && cell !== null) {
cell.abort(CATCH.err);
}
};
TRY1 = function(cb, arg) {
var e;
try {
return cb(arg);
} catch (_error) {
e = _error;
CATCH.err = e;
return CATCH;
}
};
}).call(this);