function stackMachine(program) {
if(!Array.isArray(program)) {
throw new Error('Expected array');
}
let counter = 0;
let stack = [];
let debug = [];
for(let counter = 0, loops = 0; counter < program.length && loops < 200; ++loops) {
const op = program[counter];
const debugEntry = [counter, op];
switch(op) {
case 'duplicate': {
const value = stack.pop();
stack.push(value, value);
break;
}
case 'discard': {
stack.pop();
break;
}
case 'increment': {
const value = stack.pop();
stack.push(value + 1);
break;
}
case 'decrement': {
const value = stack.pop();
stack.push(value - 1);
break;
}
case 'when': {
const predicate = stack.pop();
if(predicate === false) {
counter += 2;
}
break;
}
case 'unless': {
const predicate = stack.pop();
if(predicate === true) {
counter += 2;
}
break;
}
case 'jump': {
const index = stack.pop();
counter = index - 1;
break;
}
case 'is-zero': {
const value = stack.pop();
stack.push(value === 0);
break;
}
case 'is-signed': {
const value = stack.pop();
stack.push(value < 0);
break;
}
default: {
stack.push(op);
break;
}
}
++counter;
debugEntry.push(stack.slice());
debug.push(debugEntry);
}
return debug;
}