|
|
||
|---|---|---|
| .. | ||
| fixtures | ||
| reference | ||
| runtime | ||
| tools | ||
| .gitignore | ||
| cli.js | ||
| constants.js | ||
| index.test.js | ||
| interpreter.js | ||
| interpreter.test.js | ||
| objects.js | ||
| package.json | ||
| parser.js | ||
| prettyPrinter.js | ||
| readme.md | ||
| variable.js | ||
| virtualMachine.js | ||
| yarn.lock | ||
Maki Interpreter
One possible future for Webamp would be to support "modern" skins. The biggest blocker to this is that modern skins suport a custom scripting language called Maki.
This project is an investigation into how feasible it would be to write a .maki interpreter in JavaScript. Maki is a compiled language, so this interpreter plans to parse/evaluate the compiled byte code. Most of the hard work of figuring out how to write the parser has already been done as part of Ralf Engels' Maki Decompiler. The first stage of this project is just to reimplement the parser portion of the decompiler in JavaScript.
Architecture
- Parser: Given a Buffer containing the binary data of a
.makifile, returns a JSON serializeable representation of the script. - Runtime: A JavaScript object mapping class unique ids to JavaScript implementations of those classes.
- Virtual Machine: Given a parsed
.makifile, and a command offset, exectues the.makiscript starting at that command, and returing the value returned from executing that function. - Interpreter: This ties all of the above pieces together. Given a Buffer containing a
.makiscript, a Runtime, and an instance ofSystem, it parses the.makifile, and then binds the runtime into the parsed.makiprogram. This consists of populating theSystemvariable, and binding the class ids defined in the script to the actual JavaScript implementations of those classes. Finally it kicks off execution by triggeringSystem.onScriptLoaded(). - Cli: A command line script that, given the path to a
.makifile will run it through the Interpreter.
Roadmap
- Parse top level bytecode (constants, types, variables)
- Evaluate function code
- Implement core of standard library
- ???
Tools
yarn parseRun the parser on the fixture .maki file. This is useful forconsole.logdebugging.yarn decompileRun the Perl decompiler on the fixture .maki file. This is useful for stickingprint();statements in the Perl and trying to figure out what exactly it does.yarn tddRun the tests in "watch" mode. Great for TDDyarn interpretInterpret the test script. Currently this just logs the commands and stack as they get executed.
Structure of a .maki file
The bytecode contained in a .maki file takes the following form (I think. I'm still trying to gock it). These are my notes trying to write down what I understand so far.
- The "magic" string "FG". This might be some kind attempt to validate that this is realy a
.makifile? - A version number (which we currently ignore)
- Some 32 bit something. We ignore this.
- Types
- A 32 bit number defines how many types there are.
- Each type consists of four 32 bit numbers.
- Function names
- A 32 bit number defines how many function names there are.
- Each funtion name consists of a 16 bit class code
- A 16 bit "dummy" (not sure what this is) and a name.
- The name is defined by a 16 bit number showing how long the name is, followed by that many ascii bytes.
- Variables
- A 32 bit number defines how many variables there are.
- Each variable consists of:
- A byte of what "type" it is.
- A byte of what object it refers to.
- 16 bits of what subclass it refers to.
- Four uinits (what are those?) each 16 bits long.
- A byte representing "global" (what? Maybe a boolean?)
- A byte representing "syste" (What? Maybe a boolean?)
- Constants
- A 32 bit number defines how many constants there are.
- Each constant consists of:
- A 32 bit number representing its number (is this just an ID?)
- The value is defined by a 16 bit number showing how long the name is, followed by that many ascii bytes.
- Functions
- A 32 bit number defines how many functions there are.
- Each constant consists of:
- A 32 bit number representing its variable number (is this just an ID?)
- A 32 bit number representing its function number (is this just an ID?)
- A 32 bit number representing its offset (offset into what?)
- Function Code
- A 32 bit number defines how many commands there are.
- Each command consists of:
- A byte representing that command's opcode