@effectful/transducers
Version:
JS syntax transformation framework for @effectful/js
183 lines (182 loc) • 5.59 kB
JavaScript
"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);