@thi.ng/pointfree
Version:
Pointfree functional composition / Forth style stack execution engine
170 lines (169 loc) • 3.86 kB
JavaScript
import { isArray } from "@thi.ng/checks/is-array";
import { isPlainObject } from "@thi.ng/checks/is-plain-object";
import { illegalArgs } from "@thi.ng/errors/illegal-arguments";
import { illegalState } from "@thi.ng/errors/illegal-state";
import { defOp1, defOp2, defOp2v } from "./ops.js";
import { $, $n } from "./safe.js";
import { invrot, swap } from "./stack.js";
import { $stackFn, defWord } from "./word.js";
const list = (ctx) => (ctx[0].push([]), ctx);
const obj = (ctx) => (ctx[0].push({}), ctx);
const pushl = (ctx) => {
$(ctx[0], 2);
const stack = ctx[0];
const a = stack.pop();
a.unshift(stack.pop());
stack.push(a);
return ctx;
};
const pushr = (ctx) => {
const stack = ctx[0];
const n = stack.length - 2;
$n(n, 0);
stack[n].push(stack[n + 1]);
stack.length--;
return ctx;
};
const popr = (ctx) => {
const stack = ctx[0];
const n = stack.length - 1;
$n(n, 0);
const a = stack[n];
!a.length && illegalState("can't pop empty array");
stack.push(a.pop());
return ctx;
};
const pull = defWord([popr, swap]);
const pull2 = defWord([pull, pull]);
const pull3 = defWord([pull2, pull]);
const pull4 = defWord([pull2, pull2]);
const vadd = defOp2v((b, a) => a + b);
const vsub = defOp2v((b, a) => a - b);
const vmul = defOp2v((b, a) => a * b);
const vdiv = defOp2v((b, a) => a / b);
const split = (ctx) => {
const stack = ctx[0];
const n = stack.length - 2;
$n(n, 0);
const a = stack[n];
const b = stack[n + 1];
stack[n + 1] = a.splice(b, a.length - b);
return ctx;
};
const cat = (ctx) => {
const stack = ctx[0];
const n = stack.length - 2;
$n(n, 0);
stack[n] = stack[n].concat(stack.pop());
return ctx;
};
const catr = (ctx) => {
const stack = ctx[0];
const n = stack.length - 2;
$n(n, 0);
stack[n] = stack.pop().concat(stack[n]);
return ctx;
};
const mapl = (ctx) => {
$(ctx[0], 2);
const stack = ctx[0];
const w = $stackFn(stack.pop());
const list2 = stack.pop();
const n = list2.length;
for (let i = 0; i < n; i++) {
ctx[0].push(list2[i]);
ctx = w(ctx);
}
return ctx;
};
const mapll = (ctx) => {
$(ctx[0], 2);
let stack = ctx[0];
const w = $stackFn(stack.pop());
const list2 = stack.pop();
const n = list2.length;
let r = 0;
for (let i = 0; i < n; i++) {
let m = stack.length;
stack.push(list2[i]);
ctx = w(ctx);
stack = ctx[0];
r += stack.length - m;
}
stack.push(stack.splice(stack.length - r, r));
return ctx;
};
const foldl = defWord([invrot, mapl]);
const collect = (ctx) => {
const stack = ctx[0];
let n = stack.length - 1, m;
$n(n, 0);
$n(n -= m = stack.pop(), 0);
stack.push(stack.splice(n, m));
return ctx;
};
const defTuple = (n) => defWord([n, collect]);
const vec2 = defTuple(2);
const vec3 = defTuple(3);
const vec4 = defTuple(4);
const defJoin = (sep = "") => defOp1((x) => x.join(sep));
const join = defOp2((sep, buf) => buf.join(sep));
const length = defOp1((x) => x.length);
const copy = defOp1(
(x) => isArray(x) ? x.slice() : isPlainObject(x) ? { ...x } : illegalArgs(`can't copy type ${typeof x}`)
);
const at = defOp2((b, a) => a[b]);
const setat = (ctx) => {
const stack = ctx[0];
const n = stack.length - 3;
$n(n, 0);
stack[n + 1][stack[n + 2]] = stack[n];
stack[n] = stack[n + 1];
stack.length -= 2;
return ctx;
};
const bindkeys = (ctx) => {
const stack = ctx[0];
$(stack, 2);
const obj2 = stack.pop();
const keys = stack.pop();
$(stack, keys.length);
for (let i = keys.length - 1; i >= 0; i--) {
obj2[keys[i]] = stack.pop();
}
stack.push(obj2);
return ctx;
};
export {
at,
bindkeys,
cat,
catr,
collect,
copy,
defJoin,
defTuple,
foldl,
join,
length,
list,
mapl,
mapll,
obj,
popr,
pull,
pull2,
pull3,
pull4,
pushl,
pushr,
setat,
split,
vadd,
vdiv,
vec2,
vec3,
vec4,
vmul,
vsub
};