axos
Version:
JIT-friendly, multiparadigm asynchronous programming
350 lines (309 loc) • 8.55 kB
JavaScript
(function() {
var CATCH, Cell, ERROR, FINAL_ERROR, FINAL_VALUE, NO_MORE, Operator, Strategy, TRY, VALUE, afterIO, axos, current_receiver, drain, draining, io_send, mq, receive, ref, ref1, schedule, scheduled, send, throwingFunction, tryingFunction,
hasProp = {}.hasOwnProperty;
Strategy = (function() {
function Strategy(opts) {
var k;
if (opts == null) {
opts = {};
}
this.kind = opts.kind;
this.initState = opts.initState;
this.onReceive = opts.onReceive;
this.onDispose = opts.onDispose;
for (k in opts) {
if (!hasProp.call(opts, k)) continue;
if (!this.hasOwnProperty(k)) {
throw new TypeError("invalid Strategy option: " + k);
}
}
}
Strategy.prototype.cell = function() {
var cell, initState;
cell = new Cell(this.kind, this);
if (initState = this.initState) {
cell.state = initState.apply(cell, arguments);
}
return cell;
};
Strategy.prototype.withKind = function(kind) {
this.kind = kind;
return this;
};
return Strategy;
})();
Cell = (function() {
function Cell(kind1, strategy, state) {
this.kind = kind1;
this.strategy = strategy;
this.state = state;
this.op = this.arg = this.sink = this.tag = null;
this.length = 0;
}
Cell.prototype.setValue = function(val) {
return this.set(VALUE, val);
};
Cell.prototype.setError = function(err) {
return this.set(ERROR, err);
};
Cell.prototype.finish = function(val) {
return this.set(FINAL_VALUE, val);
};
Cell.prototype.abort = function(err) {
return this.set(FINAL_ERROR, err);
};
Cell.prototype.set = function(op, arg) {
var ref;
if (this !== current_receiver) {
throw new TypeError("set() must be called from onReceive() or onRecalc()");
}
if ((ref = this.op) != null ? ref.isFinal : void 0) {
return;
}
this.op = op;
this.arg = arg;
};
Cell.prototype.hasSink = function(cell, tag) {
var any_tag, c, i, j, len;
if (this.sink == null) {
return false;
}
any_tag = arguments.length < 2;
if (this.sink === cell && (any_tag || this.tag === tag)) {
return true;
}
if (!this.length) {
return false;
}
for (i = j = 0, len = this.length; j < len; i = j += 2) {
c = this[i];
if (c === cell && (any_tag || this[i + 1] === tag)) {
return true;
}
}
return false;
};
Cell.prototype.addSink = function(cell, tag) {
var ref;
if (this.sink != null) {
this[this.length++] = cell;
this[this.length++] = tag;
} else {
this.sink = cell;
this.tag = tag;
}
if ((ref = this.op) != null ? ref.isFinal : void 0) {
return send(cell, tag, this.op, this.arg);
}
};
Cell.prototype.removeSink = function(cell, tag) {
var any_tag, c, i, j, len, out;
if (this.sink == null) {
return;
}
any_tag = arguments.length < 2;
out = 0;
if (this.sink === cell && (any_tag || this.tag === tag)) {
out = -2;
}
if (this.length) {
for (i = j = 0, len = this.length; j < len; i = j += 2) {
c = this[i];
if (c === cell && (any_tag || this[i + 1] === tag)) {
continue;
}
if (out < 0) {
this.sink = c;
this.tag = this[i + 1];
out = 0;
} else {
this[out++] = c;
this[out++] = this[i + 1];
}
}
}
if (out < 0) {
this.sink = this.tag = null;
out = 0;
}
return this.length = out;
};
Cell.prototype.notify = function() {
var arg, c, i, isFinal, j, len, op, out;
op = this.op;
arg = this.arg;
isFinal = op != null ? op.isFinal : void 0;
out = 0;
if (receive(this.sink, this.tag, op, arg) === NO_MORE || isFinal) {
out = -2;
}
if (this.length) {
for (i = j = 0, len = this.length; j < len; i = j += 2) {
c = this[i];
if (receive(c, this[i + 1], op, arg) === NO_MORE || isFinal) {
if (out < 0) {
this.sink = c;
this.tag = this[i + 1];
out = 0;
} else {
this[out++] = c;
this[out++] = this[i + 1];
}
}
}
}
if (out < 0) {
this.sink = this.tag = null;
out = 0;
}
this.length = isFinal ? 0 : out;
};
return Cell;
})();
afterIO = (ref = (ref1 = typeof process !== "undefined" && process !== null ? process.nextTick : void 0) != null ? ref1 : setImmediate) != null ? ref : function(fn) {
return setTimeout(fn, 0);
};
mq = [];
scheduled = draining = false;
send = function(cell, tag, op, arg) {
mq[mq.length] = cell;
mq[mq.length] = tag;
mq[mq.length] = op;
mq[mq.length] = arg;
if (!(scheduled || draining)) {
return schedule();
}
};
schedule = function() {
if (!scheduled) {
axos.afterIO(drain);
}
return scheduled = true;
};
drain = function() {
scheduled = false;
return io_send();
};
io_send = function() {
var pos;
if (draining) {
throw new Error("io_send() must be invoked in a Zalgo-safe way");
}
draining = true;
if (arguments.length) {
send.apply(null, arguments);
}
pos = 0;
while (pos < mq.length) {
receive(mq[pos++], mq[pos++], mq[pos++], mq[pos++]);
}
mq.length = 0;
return draining = false;
};
current_receiver = null;
receive = function(cell, tag, op, arg) {
var old_receiver, rcv, ref2;
if ((ref2 = cell.op) != null ? ref2.isFinal : void 0) {
return NO_MORE;
}
old_receiver = current_receiver;
current_receiver = cell;
if ((rcv = cell.strategy.onReceive) != null) {
rcv = rcv.call(cell.state, cell, tag, op, arg);
} else {
cell.set(op, arg);
}
if ((cell.op != null) && (cell.sink != null)) {
cell.notify();
}
current_receiver = old_receiver;
return rcv;
};
Operator = (function() {
function Operator(opts) {
var isError, isFinal, isValue, ref2, ref3, ref4;
if (opts == null) {
opts = {};
}
this.isValue = isValue = (ref2 = opts.isValue) != null ? ref2 : false;
this.isError = isError = (ref3 = opts.isError) != null ? ref3 : !isError;
this.isFinal = isFinal = (ref4 = opts.isFinal) != null ? ref4 : false;
this.final = this.isFinal ? this : opts.final;
this.nonFinal = this.isFinal ? opts.nonFinal : this;
this.value = this.isValue ? this : opts.value;
this.error = this.isError ? this : opts.error;
if (this.value == null) {
this.value = new Operator({
isValue: true,
isError: false,
isFinal: isFinal,
error: this
});
}
if (this.error == null) {
this.error = new Operator({
isValue: false,
isError: true,
isFinal: isFinal,
value: this
});
}
if (isError) {
if (this.final == null) {
this.final = this.value.final.error;
}
}
if (this.final == null) {
this.final = new Operator({
isValue: isValue,
isError: isError,
isFinal: true,
nonFinal: this
});
}
if (isError) {
if (this.nonFinal == null) {
this.nonFinal = this.value.nonFinal.error;
}
}
}
return Operator;
})();
ERROR = new Operator();
VALUE = ERROR.value;
FINAL_ERROR = ERROR.final;
FINAL_VALUE = VALUE.final;
NO_MORE = {};
throwingFunction = function() {};
TRY = function(fn) {
throwingFunction = fn;
return tryingFunction;
};
CATCH = {
err: null
};
tryingFunction = function() {
var e;
try {
return throwingFunction.apply(this, arguments);
} catch (_error) {
e = _error;
CATCH.err = e;
return CATCH;
}
};
module.exports = axos = {
Strategy: Strategy,
Cell: Cell,
TRY: TRY,
CATCH: CATCH,
send: send,
io_send: io_send,
afterIO: afterIO,
ERROR: ERROR,
VALUE: VALUE,
FINAL_ERROR: FINAL_ERROR,
FINAL_VALUE: FINAL_VALUE,
NO_MORE: NO_MORE
};
}).call(this);