webamp/experiments/maki-interpreter/command.js
Jordan Eldredge 000f369751 Correctly parse command opcodes
This moves to using a node Buffer to hold the command bytecode which resolves a character encoding issue we were having
2019-11-30 13:42:53 -08:00

117 lines
2.7 KiB
JavaScript

const { COMMANDS } = require("./constants");
class Variable {
constructor(a, b, name) {
this.a = a;
this.b = b;
this.name = name;
}
}
class Command {
constructor({
commandsBuffer,
pos,
types,
variables,
functionNames,
localFunctions
}) {
const opcode = commandsBuffer.readInt8(pos);
this.pos = pos;
this.opcode = opcode;
this.arguments = [];
this.command = COMMANDS[opcode];
this.size = 1;
if (this.command == null) {
// I don't think this ever happens in a real .maki file
// throw new Error(`Unknown opcode "${opcode}"`);
// But the decompiler tries to do something...
this.command = {
name: `unknown ${opcode}`,
in: 0,
out: 0
};
return;
}
if (this.command.arg == null) {
this.size = 1;
return;
}
const argType = this.command.arg;
let arg = null;
switch (argType) {
case "var": {
const variable = commandsBuffer.readUInt32LE(pos + 1);
if (variables[variable] != null) {
arg = variables[variable];
} else {
arg = new Variable(-1, -0, "unknown");
}
arg.name = `Unknown ${variable}`;
break;
}
case "line": {
const variable = commandsBuffer.readUInt32LE(pos + 1) + 5;
arg = { name: variable, line: variable };
break;
}
case "objFunc": {
const variable = commandsBuffer.readUInt32LE(pos + 1);
if (functionNames[variable] != null) {
arg = functionNames[variable].function;
} else {
arg = {
name: `unknown Object function ${variable}`,
parameters: [],
return: "unknown"
};
}
break;
}
case "func": {
// Note in the perl code here: "todo, something strange going on here..."
const variable = commandsBuffer.readUInt32LE(pos + 1) + 5;
const offset = variable + pos;
arg = {
name: `func${offset}`,
code: [],
offset
};
if (localFunctions[offset] == null) {
localFunctions[offset] = {
function: arg,
offset
};
}
break;
}
case "obj": {
const variable = commandsBuffer.readUInt32LE(pos + 1);
arg = types[variable];
break;
}
}
this.arguments = [arg];
this.size = 5;
// From perl: look forward for a stack protection block
// (why do I have to look FORWARD. stupid nullsoft)
if (
commandsBuffer.length > pos + 5 + 4 &&
commandsBuffer.readUInt32LE(pos + 5) >= 0xffff0000
) {
this.size += 4;
}
if (opcode === 112) {
this.size += 1;
}
}
}
module.exports = Command;