Move offset mapping entirely into the parser

This commit is contained in:
Jordan Eldredge 2019-07-20 18:18:19 -07:00
parent 8529d948ec
commit c61fbb952d
2 changed files with 34 additions and 21 deletions

View file

@ -10,6 +10,22 @@ const PRIMITIVE_TYPES = {
6: "STRING",
};
// TODO: Don't depend upon COMMANDS
function opcodeToArgType(opcode) {
const argType = COMMANDS[opcode].arg;
switch (argType) {
case "func":
case "line":
return "COMMAND_OFFSET";
case "var":
case "objFunc":
case "obj":
return "VARIABLE_OFFSET";
default:
return "NONE";
}
}
// Holds a buffer and a pointer. Consumers can consume bytesoff the end of the
// file. When we want to run in the browser, we can refactor this class to use a
// typed array: https://developer.mozilla.org/en-US/docs/Web/JavaScript/Typed_arrays
@ -232,23 +248,20 @@ function parseComand({ start, makiFile, length, pos }) {
pos,
opcode,
arg: null,
argType: opcodeToArgType(opcode),
};
const argType = COMMANDS[opcode].arg;
if (argType == null) {
if (command.argType == "NONE") {
return command;
}
let arg = null;
switch (argType) {
case "func":
case "line":
switch (command.argType) {
case "COMMAND_OFFSET":
// Note in the perl code here: "todo, something strange going on here..."
arg = makiFile.readInt32LE() + 5 + pos;
break;
case "var":
case "objFunc":
case "obj":
case "VARIABLE_OFFSET":
arg = makiFile.readUInt32LE();
break;
default:
@ -314,16 +327,22 @@ function parse(buffer) {
binaryOffset: undefined,
});
});
const resolvedCommands = commands.map(command => {
if (command.argType === "COMMAND_OFFSET") {
return Object.assign({}, command, { arg: offsetToCommand[command.arg] });
}
return command;
});
return {
magic,
classes,
methods,
variables,
bindings: resolvedBindings,
commands,
commands: resolvedCommands,
version,
extraVersion,
offsetToCommand,
};
}

View file

@ -11,7 +11,7 @@ function coerceTypes(var1, var2, val1, val2) {
}
async function interpret(start, program, stack = [], { logger = null }) {
const { commands, methods, variables, classes, offsetToCommand } = program;
const { commands, methods, variables, classes } = program;
function twoArgCoercingOperator(operator) {
const a = stack.pop();
@ -32,11 +32,6 @@ async function interpret(start, program, stack = [], { logger = null }) {
stack.push(operator(bValue, aValue));
}
function jumpToOffset(offset) {
const nextCommandIndex = offsetToCommand[offset];
return nextCommandIndex - 1;
}
let i = start;
while (i < commands.length) {
const command = commands[i];
@ -105,7 +100,7 @@ async function interpret(start, program, stack = [], { logger = null }) {
if (value) {
break;
}
i = jumpToOffset(command.arg);
i = command.arg - 1;
break;
}
// jumpIfNot
@ -115,12 +110,12 @@ async function interpret(start, program, stack = [], { logger = null }) {
if (!value) {
break;
}
i = jumpToOffset(command.arg);
i = command.arg - 1;
break;
}
// jump
case 18: {
i = jumpToOffset(command.arg);
i = command.arg - 1;
break;
}
// call
@ -149,10 +144,9 @@ async function interpret(start, program, stack = [], { logger = null }) {
// callGlobal
case 25: {
const offset = command.arg;
const nextCommandIndex = offsetToCommand[offset];
// Remove this await when we can run the VM synchronously.
// See GitHub issue #814
const value = await interpret(nextCommandIndex, program, stack, {
const value = await interpret(offset, program, stack, {
logger,
});
stack.push(value);