From a4c8705bf943f6aa4db745ac07167086f6be9f41 Mon Sep 17 00:00:00 2001 From: Jordan Eldredge Date: Sun, 23 Jun 2019 22:15:21 -0700 Subject: [PATCH] Improve variable parsing --- experiments/maki-interpreter/cli.js | 74 +++++++++++++++++----- experiments/maki-interpreter/index.js | 51 ++++++++++++--- experiments/maki-interpreter/index.test.js | 61 ++++++++++++++++++ experiments/maki-interpreter/variable.js | 31 +++++++++ 4 files changed, 192 insertions(+), 25 deletions(-) diff --git a/experiments/maki-interpreter/cli.js b/experiments/maki-interpreter/cli.js index a914f4b5..d76383f8 100644 --- a/experiments/maki-interpreter/cli.js +++ b/experiments/maki-interpreter/cli.js @@ -2,57 +2,99 @@ 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); } -class Group {} - -const System = { - getScriptGroup() { - return new Group(); - } -}; - function interpret({ commands: rawCommands, variables, types }) { - const commands = rawCommands.slice(0, 5); - const environment = { - System - }; + // 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; + } + + 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]; - console.log(variable); stack.push(variable); break; } + // pop + case 2: { + stack.pop(); + break; + } // call case 24: { const funcDefinition = command.arguments[0]; - const { name } = funcDefinition; + const { name, parameters } = funcDefinition; + const methodArgs = []; + // This might be the wrong order + parameters.forEach(() => { + methodArgs.push(stack.pop()); + }); const variable = stack.pop(); - const type = types[variable.type]; - const obj = environment[type.name]; + const obj = variable.getValue(); stack.push(obj[name]()); 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); + }); + } } } diff --git a/experiments/maki-interpreter/index.js b/experiments/maki-interpreter/index.js index 9281f04a..99255d4a 100644 --- a/experiments/maki-interpreter/index.js +++ b/experiments/maki-interpreter/index.js @@ -5,6 +5,14 @@ const Variable = require("./variable"); const MAGIC = "FG"; const ENCODING = "binary"; +const PRIMITIVE_TYPES = { + 5: "BOOLEAN", + 2: "INT", + 3: "FLOAT", + 4: "DOUBLE", + 6: "STRING" +}; + class Parser { _readMagic() { const magic = this._readStringOfLength(MAGIC.length); @@ -97,25 +105,50 @@ class Parser { } variables.push(new Variable({ ...props, type })); } else { - const type = types[typeOffset]; - if (type == null) { + const typeName = PRIMITIVE_TYPES[typeOffset]; + if (typeName == null) { throw new Error("Invalid type"); } - console.log(type.name); - variables.push(new Variable({ ...props, type })); + let value = null; + + switch (typeName) { + // BOOLEAN + case PRIMITIVE_TYPES[5]: + // INT + case PRIMITIVE_TYPES[2]: + value = uinit1; + break; + case PRIMITIVE_TYPES[3]: + case PRIMITIVE_TYPES[4]: + const exponent = (uint2 & 0xff80) >> 7; + const mantisse = ((0x80 | (uint2 & 0x7f)) << 16) | uint1; + value = mantisse * 2.0 ** (exponent - 0x96); + break; + case PRIMITIVE_TYPES[6]: + // This will likely get set by constants later on. + break; + } + if (value == null) { + // throw new Error("Failed to set value"); + } + const variable = new Variable({ ...props, type: { name: typeName } }); + variable.setValue(value); + variables.push(variable); } } return variables; } - _readConstants() { + _readConstants({ variables }) { let count = this._readUInt32LE(); const constants = []; while (count--) { - // This is an index into the variables array. - const varNum = this._readUInt32LE(); + const i = this._readUInt32LE(); + const variable = variables[i]; const value = this._readString(); - constants.push({ varNum, value }); + // TODO: Don't mutate + variable.setValue(value); + constants.push({ varNum: i, value }); } return constants; } @@ -230,7 +263,7 @@ class Parser { const types = this._readTypes(); const functionNames = this._readFunctionsNames({ types }); const variables = this._readVariables({ types }); - const constants = this._readConstants(); + const constants = this._readConstants({ variables }); const functions = this._readFunctions(); const commands = this._decodeCode({ types, diff --git a/experiments/maki-interpreter/index.test.js b/experiments/maki-interpreter/index.test.js index 3d2c7e1e..227b0e07 100644 --- a/experiments/maki-interpreter/index.test.js +++ b/experiments/maki-interpreter/index.test.js @@ -76,6 +76,67 @@ describe("standardframe.maki", () => { test("can read variables", () => { expect(maki.variables.length).toBe(56); + expect(maki.variables.map(variable => variable.type.name)) + .toMatchInlineSnapshot(` + Array [ + "System", + "INT", + "Group", + "Group", + "Group", + "STRING", + "STRING", + "STRING", + "STRING", + "STRING", + "STRING", + "STRING", + "STRING", + "Layer", + "Button", + "STRING", + "STRING", + "INT", + "INT", + "INT", + "INT", + "INT", + "INT", + "INT", + "INT", + "STRING", + "STRING", + "STRING", + "STRING", + "STRING", + "STRING", + "STRING", + "STRING", + "STRING", + "STRING", + "STRING", + "STRING", + "STRING", + "STRING", + "STRING", + "INT", + "INT", + "STRING", + "STRING", + "STRING", + "STRING", + "STRING", + "STRING", + "STRING", + "STRING", + "STRING", + "STRING", + "STRING", + "STRING", + "STRING", + "STRING", + ] + `); maki.variables.forEach(variable => { expect(variable.type).not.toBe(undefined); }); diff --git a/experiments/maki-interpreter/variable.js b/experiments/maki-interpreter/variable.js index c14d8ee0..b9f42399 100644 --- a/experiments/maki-interpreter/variable.js +++ b/experiments/maki-interpreter/variable.js @@ -1,7 +1,38 @@ +class GuiObject {} +class Group extends GuiObject {} +class PopupMenu {} +class Container {} + +const System = { + getScriptGroup() { + return new Group(); + }, + getToken(str, separator, tokennum) { + return "Some Token String"; + }, + getParam() { + return "Some String"; + } +}; + +const environment = { + System, + Group, + GuiObject, + PopupMenu, + Container +}; + class Variable { constructor(props) { this._props = props; this.type = props.type; + if (props.system) { + if (this.type.name != "System") { + throw new Error("Can variables other than System be system variables?"); + } + this._value = System; + } } getValue() {