Start running basic test

This commit is contained in:
Jordan Eldredge 2019-07-11 20:57:18 -07:00
parent 28f5d0929b
commit b1fdd62410
5 changed files with 113 additions and 13 deletions

View file

@ -1,6 +1,7 @@
const parse = require("./parser");
const { getClass, getFormattedId } = require("./objects");
const interpret = require("./virtualMachine");
const { printCommand } = require("./prettyPrinter");
function main({ runtime, data, system, log }) {
const program = parse(data);
@ -32,6 +33,11 @@ function main({ runtime, data, system, log }) {
});
});
const { commands, variables } = program;
commands.forEach((command, i) => {
// printCommand({ i, command, stack: [], variables });
});
// Set the System global
// TODO: We could confirm that this variable has the "system" flag set.
program.variables[0].setValue(system);

View file

@ -4,10 +4,18 @@ const System = require("./runtime/System");
const runtime = require("./runtime");
const interpret = require("./interpreter");
const VERSIONS = {
WINAMP_3_ALPHA: "v1.1.0.a9 (Winamp 3 alpha 8r)",
WINAMP_3_BETA: "v1.1.1.b3 (Winamp 3.0 build 488d)",
WINAMP_3_FULL: "v1.1.1.b3 (Winamp 3.0 full)",
WINAMP_5_02: "v1.1.13 (Winamp 5.02)",
WINAMP_5_66: "v1.2.0 (Winamp 5.66)",
};
function runFile(relativePath) {
const system = new System();
const data = fs.readFileSync(path.join(__dirname, relativePath));
interpret({ runtime, data, system, log: false });
interpret({ runtime, data, system, log: true });
}
let mockMessageBox;
@ -22,11 +30,11 @@ beforeEach(() => {
describe("can call messageBox with hello World", () => {
const versions = [
// "v1.1.0.a9 (Winamp 3 alpha 8r)",
"v1.1.1.b3 (Winamp 3.0 build 488d)",
"v1.1.1.b3 (Winamp 3.0 full)",
// "v1.1.13 (Winamp 5.02)",
// "v1.2.0 (Winamp 5.66)"
// VERSIONS.WINAMP_3_ALPHA,
VERSIONS.WINAMP_3_BETA,
VERSIONS.WINAMP_3_FULL,
// VERSIONS.WINAMP_5_22,
// VERSIONS.WINAMP_5.66
];
versions.forEach(version => {
test(`with bytecode compiled by ${version}`, () => {
@ -41,3 +49,35 @@ describe("can call messageBox with hello World", () => {
});
});
});
describe("can use basic operators", () => {
const versions = [
// jberg could not get the script to compile on this version
// VERSIONS.WINAMP_3_ALPHA,
VERSIONS.WINAMP_3_BETA,
//VERSIONS.WINAMP_3_FULL,
// VERSIONS.WINAMP_5_22,
// VERSIONS.WINAMP_5.66
];
// The basicTest.m file that jberg prepared follows a convention for what a
// passing test looks like. This ultility function lets us just write the
// message, since the rest is common for all success messages.
function successOutputFromMessage(message) {
return [message, "Success", 0, ""];
}
versions.forEach(version => {
test.only(`with bytecode compiled by ${version}`, () => {
try {
runFile(`./reference/maki_compiler/${version}/basicTests.maki`);
} catch (e) {
// Uncomment this next line to find the next bug to work on.
console.error(e);
}
expect(mockMessageBox.mock.calls).toEqual(
["2 + 2 = 4"].map(successOutputFromMessage)
);
});
});
});

View file

@ -206,17 +206,20 @@ function decodeCode({ makiFile, classes, variables, methods }) {
const commands = [];
while (makiFile.getPosition() < start + length) {
const pos = makiFile.getPosition() - start;
commands.push(parseComand({ makiFile, length, pos, localFunctions }));
commands.push(
parseComand({ start, makiFile, length, pos, localFunctions })
);
}
return { commands, localFunctions };
}
// TODO: Refactor this to consume bytes directly off the end of MakiFile
function parseComand({ makiFile, length, pos, localFunctions }) {
function parseComand({ start, makiFile, length, pos, localFunctions }) {
const opcode = makiFile.readUInt8();
const command = {
offset: pos,
start,
pos,
opcode,
// TODO: This should just be a single nullable value I think
@ -241,7 +244,7 @@ function parseComand({ makiFile, length, pos, localFunctions }) {
break;
}
case "line": {
arg = argValue + 5;
arg = argValue + 5 + pos;
break;
}
case "objFunc": {
@ -345,6 +348,7 @@ function parse(buffer) {
localFunctions,
version,
extraVersion,
offsetToCommand,
};
}

View file

@ -24,6 +24,15 @@ function printValue(value) {
case "INT":
type = "INT";
break;
case "FLOAT":
type = "FLOAT";
break;
case "DOUBLE":
type = "DOUBLE";
break;
case "BOOLEAN":
type = "BOOLEAN";
break;
default:
throw new Error(`Unknown variable type ${variable.typeName}`);
}
@ -32,7 +41,7 @@ function printValue(value) {
function printCommand({ i, command, stack, variables }) {
console.log(
i,
`${i} (${command.start} + ${command.offset})`,
command.command.name.toUpperCase(),
command.opcode,
command.arguments.map(offset => {

View file

@ -1,12 +1,14 @@
const { printCommand } = require("./prettyPrinter");
function interpret(start, program, { log = false }) {
const { commands, methods, variables, classes } = program;
const { commands, methods, variables, classes, offsetToCommand } = program;
// Run all the commands that are safe to run. Increment this number to find
// the next bug.
const stack = [];
let i = start;
let i = start - 1;
while (i < commands.length) {
i++;
const command = commands[i];
switch (command.opcode) {
@ -21,6 +23,32 @@ function interpret(start, program, { log = false }) {
stack.pop();
break;
}
// ==
case 8: {
const a = stack.pop();
const b = stack.pop();
stack.push(a.getValue() === b.getValue());
break;
}
// jumpIf
case 16: {
const value = stack.pop();
// This seems backwards. Seems like we're doing a "jump if not"
if (value) {
break;
}
const offset = command.arguments[0];
const nextCommandIndex = offsetToCommand[offset];
i = nextCommandIndex;
break;
}
// jump
case 18: {
const offset = command.arguments[0];
const nextCommandIndex = offsetToCommand[offset];
i = nextCommandIndex;
break;
}
// call
case 24: {
const methodOffset = command.arguments[0];
@ -55,6 +83,20 @@ function interpret(start, program, { log = false }) {
stack.push(a);
break;
}
// + (add)
case 64: {
const a = stack.pop();
const b = stack.pop();
stack.push(a.getValue() + b.getValue());
break;
}
// >>
case 88: {
const a = stack.pop();
const b = stack.pop();
stack.push(a >> b);
break;
}
default:
throw new Error(`Unhandled opcode ${command.opcode}`);
}
@ -63,7 +105,6 @@ function interpret(start, program, { log = false }) {
if (log) {
printCommand({ i, command, stack, variables });
}
i++;
}
}