subscript
Version:
Modular expression parser & evaluator
36 lines (33 loc) • 1.27 kB
JavaScript
// Arrow function operator - eval half
import { operator, compile } from '../../parse.js';
// RETURN: array to hold value - reused, no allocation per throw
export const RETURN = [];
operator('=>', (a, b) => {
// Normalize params: () → [], x → [x], (a, b) → [a, b]
a = a?.[0] === '()' ? a[1] : a;
const ps = !a ? [] : a[0] === ',' ? a.slice(1) : [a];
// Check for rest param
let restIdx = -1, restName = null;
const last = ps[ps.length - 1];
if (Array.isArray(last) && last[0] === '...') {
restIdx = ps.length - 1;
restName = last[1];
ps.length--;
}
// Arrow body: {} is always block (need parens for object: ({...}))
// Block body returns undefined unless explicit return
const isBlock = b?.[0] === '{}';
b = compile(isBlock ? ['{', b[1]] : b);
return ctx => (...args) => {
const l = {};
ps.forEach((p, i) => l[p] = args[i]);
if (restName) l[restName] = args.slice(restIdx);
const fnCtx = new Proxy(l, {
get: (l, k) => k in l ? l[k] : ctx?.[k],
set: (l, k, v) => ((k in l ? l : ctx)[k] = v, true),
has: (l, k) => k in l || (ctx ? k in ctx : false)
});
try { const r = b(fnCtx); return isBlock ? undefined : r; }
catch (e) { if (e === RETURN) return e[0]; throw e; }
};
});