@thi.ng/pointfree
Version:
Pointfree functional composition / Forth style stack execution engine
50 lines (49 loc) • 1.51 kB
JavaScript
import { isArray } from "@thi.ng/checks/is-array";
import { isFunction } from "@thi.ng/checks/is-function";
import { compL } from "@thi.ng/compose/comp";
import { $ } from "./safe.js";
import { tos } from "./stack.js";
const $stackFn = (f) => isArray(f) ? defWord(f) : f;
const __compile = (prog) => prog.length > 0 ? compL.apply(
null,
prog.map(
(w) => !isFunction(w) ? (ctx) => (ctx[0].push(w), ctx) : w
)
) : (ctx) => ctx;
const unwrap = ([stack], n = 1) => n === 1 ? tos(stack) : stack.slice(Math.max(0, stack.length - n));
const defWord = (prog, env, mergeEnv = true) => {
const w = __compile(prog);
return env ? mergeEnv ? (ctx) => (w([ctx[0], ctx[1], { ...ctx[2], ...env }]), ctx) : (ctx) => (w([ctx[0], ctx[1], { ...env }]), ctx) : w;
};
const defWordU = (prog, n = 1, env, mergeEnv = true) => {
const w = __compile(prog);
return env ? mergeEnv ? (ctx) => unwrap(w([ctx[0], ctx[1], { ...ctx[2], ...env }]), n) : (ctx) => unwrap(w([ctx[0], ctx[1], { ...env }]), n) : (ctx) => unwrap(w(ctx), n);
};
const exec = (ctx) => ($(ctx[0], 1), $stackFn(ctx[0].pop())(ctx));
const $try = (ctx) => {
const stack = ctx[0];
$(stack, 2);
const err = stack.pop();
try {
return exec(ctx);
} catch (e) {
stack.push(e, err);
return exec(ctx);
}
};
const execjs = (ctx) => {
const stack = ctx[0];
$(stack, 1);
const [fn, ...args] = stack.pop();
stack.push(fn(...args));
return ctx;
};
export {
$stackFn,
$try,
defWord,
defWordU,
exec,
execjs,
unwrap
};