webamp/experiments/maki-interpreter/cli.js
Jordan Eldredge 7868ba9681 Add comments
2019-11-30 13:42:53 -08:00

112 lines
2.8 KiB
JavaScript

const fs = require("fs");
const path = require("path");
const { parse } = require("./");
const log = true;
function parseFile(relativePath) {
const buffer = fs.readFileSync(path.join(__dirname, relativePath));
return parse(buffer);
}
function interpret({ commands: rawCommands, variables, types }) {
// Debug utility to pretty print a value/variable
function prettyPrint(offset) {
const value = variables[offset] || offset;
if (value == null) {
return "NULL";
}
let name = value;
if (value.type) {
name = `Variable(${value.type.name}) ${
value.getValue() ? "" : "(empty)"
}`;
}
return name;
}
// Run all the commands that are safe to run. Increment this number to find
// the next bug.
const commands = rawCommands.slice(0, 86);
const stack = [];
let i = 0;
while (i < commands.length) {
const command = commands[i];
switch (command.opcode) {
// push
case 1: {
// What are these? Do they have names?
const offsetIntoVariables = command.arguments[0];
const variable = variables[offsetIntoVariables];
// Maybe we should be pushing the actual value on the stack?
// Do we ever assign to a variable that we get from the stack?
// Or do all variables come in via arguments?
stack.push(variable);
break;
}
// pop
case 2: {
stack.pop();
break;
}
// call
case 24: {
const funcDefinition = command.arguments[0];
const { name, parameters } = funcDefinition;
const methodArgs = [];
// This might be in reverse order
parameters.forEach(() => {
methodArgs.push(stack.pop());
});
const variable = stack.pop();
const obj = variable.getValue();
stack.push(obj[name](...methodArgs));
break;
}
// return
case 33: {
const posVar = stack.pop();
const pos = posVar.getValue();
// TODO: What is this supposed to do?
i += pos;
break;
}
// mov
case 48: {
const a = stack.pop();
const b = stack.pop();
b.setValue(a);
stack.push(a);
break;
}
default:
throw new Error(`Unhandled opcode ${command.opcode}`);
}
i++;
// Print some debug info
if (log) {
console.log(
i + 1,
command.command.name.toUpperCase(),
command.opcode,
command.arguments.map(offset => {
return prettyPrint(offset);
})
);
stack.forEach((value, i) => {
const name = prettyPrint(value);
console.log(" ", i + 1, name);
});
}
}
}
function main() {
const relativePath = process.argv[2];
const { commands, variables, types } = parseFile(relativePath);
interpret({ commands, variables, types });
}
main();