Skip to content

Instantly share code, notes, and snippets.

@stuxcrystal
Last active December 8, 2018 17:36
Show Gist options
  • Save stuxcrystal/f7b7fe67dcb2b7d8cbba62b1d96763cb to your computer and use it in GitHub Desktop.
Save stuxcrystal/f7b7fe67dcb2b7d8cbba62b1d96763cb to your computer and use it in GitHub Desktop.
const _patch_ll = function(list) {
list.split = function() {
return _patch_ll({node: list.node});
}
list.append = function(data) {
list.node = {
target: data
prev: list.node
}
};
list.push = function(data) {
let sp = list.split();
sp.append(data);
return sp;
};
list.each = function*() {
let node = list.node;
if (node === null) return;
while (node.prev !== null) {
yield node.target;
node = node.prev;
}
};
return list;
}
const _make_ll = function() {
return _patch_ll({node: null});
}
const RETURN = 0;
const BUBBLE = 1;
const RETRY = 2;
const _runner = function(fn, catcher, async_) {
let _fore;
if (async_) {
_fore = async function(...args) {
let retry = 0;
while (true) {
try {
return await fn(...args);
} catch (e) {
const op = catcher._handle(e, retry);
}
if (op.op === RETRY) {
retry += 1;
continue;
}
if (op.op === BUBBLE)
throw op.e;
return op.result;
}
}
} else {
_fore = function(...args) {
let retry = 0;
while (true) {
try {
return fn(...args);
} catch (e) {
const op = catcher._handle(e, retry);
}
if (op.op === RETRY) {
retry += 1;
continue;
}
if (op.op === BUBBLE)
throw op.e;
return op.result;
}
}
}
return _fore;
}
const _catcher = function(_ball, ops) {
const _handler = {
fn: _ball.fn,
async_: _ball.async_
ops: ops
};
_handler._handle = function(e, retry) {
const op = {
op: RETURN,
e: e,
result: undefined,
retry: retry
}
for (let cb of _handler.ops.each()) {
cb(op);
}
return op;
}
const _caught = _runner(_ball.catcher, _handler.async_);
_caught.push = function(fn) {
return _catcher(_handler, _ball.ops.push(fn));
}
_caught.except = function(...errors) {
return _caught.push((op) => {
for (let error of errors) {
if (op.e instanceof error)
op.op = BUBBLE;
}
});
}
_caught.on = function(err, fn) {
return _caught.push((op) => {
if (err===null || op.e instanceof err) {
op.op = RETURN;
op.result = fn(op.e);
}
})
}
_caught.retry_on = function(err, count) {
return _caught.push((op) => {
if (op.e instanceof err) {
if (!count || op.retry+1 < count) {
op.op = RETRY;
}
}
});
}
_caught.retry = function(count) {
return _caught.push((op) => {
if (op.retry+1 < count)
op.op = RETRY;
});
}
_caught.default = function(fn) {
return _caught.on(null, fn);
}
_caught.async = function() {
const _catcher_async = {
fn: _ball.fn,
async_: true
ops: _catcher.ops
};
return _catcher(_catcher_async, _catcher.ops);
}
_caught.encapsulate = function() {
return (...args) => _caught(...args);
}
return _caught;
}
const pokeball = function(fn) {
return _catcher({fn, _make_ll()});
}
pokeball.IGNORE = IGNORE;
pokeball.BUBBLE = BUBBLE;
pokeball.RETRY = RETRY;
pokeball.default = pokeball;
// Example:
// let p = pokeball(() => {throw new Error();})
// .on(SomeSpecialError, (e) => e.valueOf())
// .default((e) => e))
// .except(SomeErrorType);
// .retry(3);
// .encapsulate();
// p();
module.exports = pokeball;
Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment