84 lines
2 KiB
JavaScript
84 lines
2 KiB
JavaScript
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');
|
|
},
|
|
};
|