UNPKG

inet-lib

Version:

JavaScript Engine for Interaction Nets

502 lines (402 loc) 8.16 kB
"use strict"; const compile = require("./compile"); const verbatim = require("./verbatim"); const parser = new compile.Parser(); const generate = verbatim.generate; const mkeffect = verbatim.mkeffect; const ambtype = 1; const wiretype = 0; const lpaxtype = -1; const rpaxtype = -2; const eqntype = -3; let inqueue, inenv, ntypes, types, table; function addtypes(tree) { const agent = tree.node.agent; if ("wire" == agent) return; if (!types[agent]) { types[agent] = ntypes; ++ntypes; } tree.pax.forEach(sub => { addtypes(sub); }); } function indwire(wire, agent) { const dst = wire.twin; const twin = agent.twin; dst.twin = twin; twin.twin = dst; wire.parent = void(0); wire.twin = void(0); agent.parent = void(0); agent.twin = void(0); } function inderiw(agent, wire) { return indwire(wire, agent); } function indamb(wire, agent) { const dst = wire.twin; const twin = agent.twin; const main = agent.main; const aux = agent.aux; dst.twin = twin; twin.twin = dst; dst.type = ambtype; dst.main = main; dst.aux = aux; main.parent = dst; aux.parent = dst; if (agent.need) delegate(dst); wire.parent = void(0); wire.twin = void(0); agent.parent = void(0); agent.twin = void(0); agent.main = void(0); agent.aux = void(0); } function indbma(agent, wire) { return indamb(wire, agent); } function indagent(wire, agent) { const dst = wire.twin; const pax = agent.pax; const plen = pax.length; dst.type = agent.type; dst.data = agent.data; dst.pax = pax; for (let i = 0; i < plen; i++) pax[i].parent = dst; if (agent.need) delegate(dst); wire.parent = void(0); wire.twin = void(0); agent.parent = void(0); agent.data = void(0); agent.pax = void(0); } function indtnega(agent, wire) { return indagent(wire, agent); } function delegate(node) { do { const type = node.type; node.need = true; if (eqntype == type) { inqueue.push(node); return; } if (ambtype == type) { const twin = node.twin; twin.need = true; delegate(twin.parent); } node = node.parent; } while (node && !node.need); } function getindir(type) { if ("wire" == type) return indwire; else if ("amb" == type) return indamb; else return indagent; } function getridni(type) { if ("wire" == type) return inderiw; else if ("amb" == type) return indbma; else return indtnega; } function determ(amb, agent) { const twin = amb.twin; const main = amb.main; const aux = amb.aux; amb.type = wiretype; amb.main = void(0); amb.aux = void(0); twin.type = wiretype; twin.main = void(0); twin.aux = void(0); flush(amb, aux); flush(main, agent); } function mreted(agent, amb) { return determ(amb, agent); } function getqueue(lval, rval, left, right, wires) { const getpair = type => (tree, i) => { tree = encode(lval, rval, tree, wires); adopt(tree); return { left: { type: type, id: i }, right: tree }; }; left = left.pax.map(getpair(lpaxtype)); right = right.pax.map(getpair(rpaxtype)); return left.concat(right); } function apply(left, right, code, rl) { const lnode = left.node; const rnode = right.node; const human = lnode.agent + "><" + rnode.agent; const lval = rl ? rnode.code : lnode.code; const rval = rl ? lnode.code : rnode.code; const effect = mkeffect(lval, rval, code); const wires = {}; const wlist = []; const alist = []; const img = getqueue(lval, rval, left, right, wires); let interact; for (const name in wires) { const wire = wires[name]; const twin = wire.twin; wire.id = wlist.length; wlist.push(wire); twin.id = wlist.length; wlist.push(twin); if (ambtype == wire.type) { const main = wire.main; const aux = wire.aux; wire.main = alist.length; twin.main = alist.length; alist.push(main); wire.aux = alist.length; twin.aux = alist.length; alist.push(aux); } } interact = generate(img, wlist, alist, effect, rl); interact = interact.bind(inenv, flush); interact.human = human; return interact; } function adopt(agent, parent) { const type = agent.type; let need = agent.need; if (ambtype == type) { if (adopt(agent.main, agent)) need = true; if (adopt(agent.aux, agent)) need = true; } else if (wiretype != type) { agent.pax.forEach(tree => { if (adopt(tree, agent)) need = true; }); } agent.parent = parent; agent.need = need; return need; } function addpair(left, right, rule) { const need = left.need || right.need; const pair = { need: need, type: eqntype, left: left, right: right, rule: rule }; left.parent = pair; right.parent = pair; if (need) inqueue.push(pair); } function flush(left, right) { const row = table[left.type]; const rule = row[right.type]; if (rule.pseudo) rule(left, right); else addpair(left, right, rule); } function addrule(dict, rule) { const human = rule.human; const entry = dict[human]; if (entry) entry.push(rule); else dict[human] = [rule]; } function copyamb(dst, src) { dst.need = src.need; dst.type = src.type; dst.main = src.main; dst.aux = src.aux; } function encode(lval, rval, root, wires, rt) { const node = root.node; const need = node.need; const type = types[node.agent]; const pax = root.pax.map(sub => { return encode(lval, rval, sub, wires, rt); }); if (wiretype == type) { const name = node.name; const wire = wires[name]; const tree = { type: type }; if (wire) { wire.twin = tree; tree.twin = wire; copyamb(tree, wire); } wires[name] = tree; return tree; } else if (ambtype == type) { const wire = pax.shift(); const main = pax.shift(); const aux = pax.shift(); const twin = wire.twin; const tree = { need: need, type: type, main: main, aux: aux }; copyamb(wire, tree); if (twin) copyamb(twin, tree); return wire; } else { const code = node.code; const effect = mkeffect(lval, rval, code, true); const tree = { need: need, type: type, pax: pax }; if (rt) tree.data = effect.call(inenv); else tree.effect = effect; return tree; } } function traverse(list, pair) { const n = list.length; function compound(left, right) { for (let i = 0; i < n; i++) { const rule = list[i]; if (rule(left, right)) return true; } } compound.human = pair; compound.count = 0; return compound; } function setup(src, env) { const system = parser.parse(src); const inconf = system.conf; const custom = {}; const wires = {}; const effect = mkeffect(0, 0, system.code); table = []; inqueue = []; inenv = env; ntypes = 2; types = { wire: wiretype, amb: ambtype }; system.rules.forEach(rule => { const left = rule.left; const right = rule.right; const code = rule.code; let lrfunc, rlfunc; addtypes(left); addtypes(right); lrfunc = apply(left, right, code); addrule(custom, lrfunc); rlfunc = apply(right, left, code, true); addrule(custom, rlfunc); }); for (const pair in custom) custom[pair] = traverse(custom[pair], pair); inconf.forEach(eqn => { addtypes(eqn.left); addtypes(eqn.right); }); for (const left in types) { const row = []; for (const right in types) { let rule = custom[left + "><" + right]; if (!rule) { if ("wire" == left) rule = getindir(right); else if ("wire" == right) rule = getridni(left); else if ("amb" == left) rule = determ; else if ("amb" == right) rule = mreted; else rule = () => {}; } row[types[right]] = rule; } table[types[left]] = row; } effect.call(inenv); inconf.map(eqn => { const left = eqn.left; const right = eqn.right; return { left: encode(0, 0, left, wires, true), right: encode(0, 0, right, wires, true) }; }).forEach(pair => { const left = pair.left; const right = pair.right; adopt(left); adopt(right); flush(left, right); }); return { queue: inqueue, rules: table, types: types }; } determ.pseudo = true; mreted.pseudo = true; indwire.pseudo = true; inderiw.pseudo = true; indamb.pseudo = true; indbma.pseudo = true; indagent.pseudo = true; indtnega.pseudo = true; module.exports = setup;