UNPKG

@effectful/transducers

Version:

JS syntax transformation framework for @effectful/js

183 lines (182 loc) 5.59 kB
"use strict"; exports.__esModule = true; exports.run = exports.inject = exports.commit = exports.clean = exports.Root = exports.Placeholder = void 0; var Kit = require("./kit"); var _core = require("./core"); const Root = exports.Root = (0, _core.symbol)("match.root", "ctrl"); const Placeholder = exports.Placeholder = (0, _core.symbol)("match.placeholder", "ctrl"); const commit = exports.commit = Kit.pipe(Array.from, function* (s) { for (let i of s) { switch (i.type) { case Root: if (!i.value.v.match) continue; i = i.value.s ? (0, _core.enter)(i.pos, i.type, i.value.v) : (0, _core.leave)(i.pos, i.type, i.value.v); break; case Placeholder: if (!i.value.v.match) continue; } yield i; } }); const clean = function* (s) { for (const i of s) { switch (i.type) { case Root: case Placeholder: break; default: yield i; } } }; exports.clean = clean; const inject = exports.inject = Kit.curry(function* matchInject(pattern, si) { const pats = (Array.isArray(pattern) ? pattern : [pattern]).map(i => Kit.toArray(Kit.toks(_core.Tag.top, i))); const starts = pats.map(i => i[0].type); const plen = pats.length; const plens = pats.map(i => i.length); (0, _core.invariant)(plens.filter(v => v === 0).length === 0); const s = Kit.auto(si); const activePos = []; const activeTok = []; const activePh = []; const activePat = []; let level = 0; for (let i of s) { if (i.enter) { level++; } let aplen = activePos.length; for (let p = 0; p < aplen; ++p) { let x = activePos[p]; const pat = activePat[p]; const plen = pat.length; const v = activeTok[p]; if (x !== plen && x !== -1 && activePh[p] == null) { let j = pat[x++]; //during generation we may neglect emitting empty arrays if (j.pos !== i.pos && j.type === _core.Tag.Array && j.enter && !j.leave && pat[x].value === j.value) { x++; j = pat[x++]; } if (x < plen && j.pos != i.pos && j.enter === i.enter) { activePos[p] = -1; v.match = false; continue; } if (j.enter) { switch (j.type) { case _core.Tag.ExpressionStatement: const k = pat[x]; if (k.type === _core.Tag.Identifier) { if (k.value.node.name[0] === "$") { const ph = activePh[p] = { v, level, name: k.value.node.name.substr(1) }; yield (0, _core.enter)(i.pos, Placeholder, ph); x++; (0, _core.invariant)(pat[x].value === k.value); x++; (0, _core.invariant)(pat[x].value === j.value); x++; activePos[p] = x; continue; } } break; case _core.Tag.Identifier: case _core.Tag.StringLiteral: const name = j.value.node.name || j.value.node.value; if (name[0] === "$") { const ph = activePh[p] = { v, level, name: name.substr(1) }; yield (0, _core.enter)(i.pos, Placeholder, ph); if (!j.leave) { (0, _core.invariant)(pat[x].value === j.value); x++; } activePos[p] = x; continue; } break; } } if (j.type !== i.type || j.value.node.name !== i.value.node.name || j.value.node.value !== i.value.node.value) { activePos[p] = -1; v.match = false; continue; } if (i.enter) { (0, _core.invariant)(j.enter); if (i.leave && !j.leave) { if (pat[x++].value !== j.value) { activePos[p] = -1; v.match = false; continue; } } else if (j.leave) { if (s.cur().value === i.value) s.read(); } } activePos[p] = x; } } if (i.enter) { for (let s = 0; s < plen; ++s) { if (starts[s] == i.type) { const v = { match: null, index: s }; yield (0, _core.tok)(i.pos, Root, { s: true, v }); activePos.push(1); activeTok.push(v); activePat.push(pats[s]); } } } yield i; if (i.leave) { let aplen = activePos.length; for (let p = aplen - 1; p >= 0; --p) { let ph = activePh[p]; if (ph != null) { if (ph.level === level) { yield (0, _core.leave)(i.pos, Placeholder, ph); ph = activePh[p] = null; } } if (ph == null) { let x = activePos[p]; if (x >= 0 && x === activePat[p].length) { activePos[p] = -1; const v = activeTok[p]; v.match = true; while (activePos[0] === -1) { activePos.shift(); activePh.shift(); activeTok.shift(); activePat.shift(); } yield (0, _core.tok)(i.pos, Root, { s: false, v }); } } } level--; } } }); const run = exports.run = Kit.curry(function (pat, si) { return commit(inject(pat, si)); }, true);