const { Glib, fn } = require('../../lib'); const COMMANDS = { AND: Symbol('AND'), OR: Symbol('OR'), LSHIFT: Symbol('LSHIFT'), RSHIFT: Symbol('RSHIFT'), NOT: Symbol('NOT'), _NO_OP: Symbol('_NO_OP'), }; const NO_OP = /^(\w+|\d+) -> (\w+)/; const UNARY_OP = /^(\w+) (\w+) -> (\w+)/; const BINARY_OP = /^(\w+) (\w+) (\w+|\d+) -> (\w+)$/; const parse = (input) => Glib.fromLines(input) .map((l) => { if (l.match(NO_OP)) { const [str, value, target] = NO_OP.exec(l); return [target, { command: COMMANDS._NO_OP, args: [value] }]; } if (l.match(UNARY_OP)) { const [str, cmd, input, target] = UNARY_OP.exec(l); return [target, { command: COMMANDS[cmd], args: [input] }]; } if (l.match(BINARY_OP)) { const [str, left, cmd, right, target] = BINARY_OP.exec(l); return [target, { command: COMMANDS[cmd], args: [left, right] }]; } throw new Error('unable to parse'); }) .toMap(); const ops = { [COMMANDS.AND](lookup, l, r) { return lookup(l) & lookup(r); }, [COMMANDS.OR](lookup, l, r) { return lookup(l) | lookup(r); }, [COMMANDS.LSHIFT](lookup, l, r) { return lookup(l) << BigInt(r); }, [COMMANDS.RSHIFT](lookup, l, r) { return lookup(l) >> BigInt(r); }, [COMMANDS.NOT](lookup, v) { return lookup(v) ^ 65535n; }, [COMMANDS._NO_OP](lookup, v) { return lookup(v); }, }; const makeLookup = (input) => { const lookup = fn.memo((v) => { if (v.match(/^\d+$/)) { return BigInt(v); } if (!input.has(v)) { throw new Error('invalid lookup'); } const { command, args } = input.get(v); return ops[command](lookup, ...args); }); return lookup; }; module.exports = { '1': (input) => { return makeLookup(parse(input))('a'); }, '2': (input) => { input = parse(input); const override = makeLookup(input)('a'); input.set('b', { command: COMMANDS._NO_OP, args: [override.toString(10)] }); return makeLookup(input)('a'); }, };