UNPKG

subscript

Version:

Modular expression parser & evaluator

67 lines (63 loc) 2.36 kB
// Variable declarations: let, const, var - eval half import { operator, compile } from '../parse.js'; // Flatten comma into array: [',', a, b, c] → [a, b, c] const flatten = items => items[0]?.[0] === ',' ? items[0].slice(1) : items; // Destructure value into context export const destructure = (pattern, value, ctx) => { if (typeof pattern === 'string') { ctx[pattern] = value; return; } const [op, ...raw] = pattern; const items = flatten(raw); if (op === '{}') { const used = []; for (const item of items) { // Rest: {...rest} if (Array.isArray(item) && item[0] === '...') { const rest = {}; for (const k in value) if (!used.includes(k)) rest[k] = value[k]; ctx[item[1]] = rest; break; } let key, binding, def; // Shorthand: {x} → item is 'x' // With default: {x = 1} → ['=', 'x', default] // Rename: {x: y} → [':', 'x', 'y'] if (typeof item === 'string') { key = binding = item } else if (item[0] === '=') { typeof item[1] === 'string' ? (key = binding = item[1]) : ([, key, binding] = item[1]); def = item[2] } else { [, key, binding] = item } used.push(key); let val = value[key]; if (val === undefined && def) val = compile(def)(ctx); destructure(binding, val, ctx); } } else if (op === '[]') { let i = 0; for (const item of items) { if (item === null) { i++; continue; } if (Array.isArray(item) && item[0] === '...') { ctx[item[1]] = value.slice(i); break; } let binding = item, def; if (Array.isArray(item) && item[0] === '=') [, binding, def] = item; let val = value[i++]; if (val === undefined && def) val = compile(def)(ctx); destructure(binding, val, ctx); } } }; const varOp = (...decls) => { decls = decls.map(d => { // Just identifier: let x if (typeof d === 'string') return ctx => { ctx[d] = undefined; }; // Assignment: let x = 1 if (d[0] === '=') { const [, pattern, val] = d; const v = compile(val); if (typeof pattern === 'string') return ctx => { ctx[pattern] = v(ctx); }; return ctx => destructure(pattern, v(ctx), ctx); } return compile(d); }); return ctx => { for (const d of decls) d(ctx); }; }; operator('let', varOp); operator('const', varOp); operator('var', varOp);