summaryrefslogtreecommitdiff
diff options
context:
space:
mode:
-rw-r--r--src/lfunc.js27
-rw-r--r--src/lobject.js2
-rw-r--r--src/lstate.js38
-rw-r--r--src/lua.js16
-rw-r--r--src/lundump.js85
5 files changed, 128 insertions, 40 deletions
diff --git a/src/lfunc.js b/src/lfunc.js
new file mode 100644
index 0000000..faa0887
--- /dev/null
+++ b/src/lfunc.js
@@ -0,0 +1,27 @@
+/*jshint esversion: 6 */
+"use strict";
+
+class Proto {
+
+ constructor(L) {
+ this.k = []; // constants used by the function
+ this.p = []; // functions defined inside the function
+ this.code = []; // opcodes
+ this.cache = null; // last-created closure with this prototype
+ this.lineinfo = []; // map from opcodes to source lines (debug information)
+ this.upvalues = []; // upvalue information
+ this.numparams = 0; // number of fixed parameters
+ this.is_vararg = 0;
+ this.maxstacksize = 0; // number of registers needed by this function
+ this.locvars = []; // information about local variables (debug information)
+ this.linedefined = 0; // debug information
+ this.lastlinedefined = 0; // debug information
+ this.source = null; // used for debug information
+ }
+
+}
+
+
+module.exports = {
+ Proto: Proto
+}; \ No newline at end of file
diff --git a/src/lobject.js b/src/lobject.js
index 2e21f16..1858fd3 100644
--- a/src/lobject.js
+++ b/src/lobject.js
@@ -4,7 +4,7 @@
class LClosure {
constructor(L, n) {
- this.p = [];
+ this.p = null;
this.nupvalues = n;
}
diff --git a/src/lstate.js b/src/lstate.js
index b0002c3..979b89c 100644
--- a/src/lstate.js
+++ b/src/lstate.js
@@ -1,32 +1,24 @@
/*jshint esversion: 6 */
"use strict";
+const thread_status = require('./lua.js').thread_status;
+
class lua_State {
constructor() {
- // CommonHeader;
- // unsigned short nci; /* number of items in 'ci' list */
- // lu_byte status;
- // StkId top; /* first free slot in the stack */
- // global_State *l_G;
- // CallInfo *ci; /* call info for current function */
- // const Instruction *oldpc; /* last pc traced */
- // StkId stack_last; /* last free slot in the stack */
- // StkId stack; /* stack base */
- // UpVal *openupval; /* list of open upvalues in this stack */
- // GCObject *gclist;
- // struct lua_State *twups; list of threads with open upvalues
- // struct lua_longjmp *errorJmp; /* current error recover point */
- // CallInfo base_ci; /* CallInfo for first level (C calling Lua) */
- // volatile lua_Hook hook;
- // ptrdiff_t errfunc; /* current error handling function (stack index) */
- // int stacksize;
- // int basehookcount;
- // int hookcount;
- // unsigned short nny; /* number of non-yieldable calls in stack */
- // unsigned short nCcalls; /* number of nested C calls */
- // l_signalT hookmask;
- // lu_byte allowhook;
+ this.next = null;
+ this.stack = null;
+ this.ci = null;
+ this.nci = 0;
+ this.stacksize = 0;
+ this.twups = [this];
+ this.errorJmp = null;
+ this.hook = null;
+ this.allowhook = true;
+ this.openupval = null;
+ this.nny = 1;
+ this.status = thread_status.LUA_OK;
+ this.errfunc = 0;
}
}
diff --git a/src/lua.js b/src/lua.js
new file mode 100644
index 0000000..f41991e
--- /dev/null
+++ b/src/lua.js
@@ -0,0 +1,16 @@
+/*jshint esversion: 6 */
+"use strict";
+
+const thread_status = {
+ LUA_OK: 0,
+ LUA_YIELD: 1,
+ LUA_ERRRUN: 2,
+ LUA_ERRSYNTAX: 3,
+ LUA_ERRMEM: 4,
+ LUA_ERRGCMM: 5,
+ LUA_ERRERR: 6
+};
+
+module.exports = {
+ thread_status: thread_status
+}; \ No newline at end of file
diff --git a/src/lundump.js b/src/lundump.js
index 69445d4..1d1a959 100644
--- a/src/lundump.js
+++ b/src/lundump.js
@@ -3,8 +3,11 @@
const DataView = require('buffer-dataview');
const fs = require('fs');
+const assert = require('assert');
+
const lua_State = require('./lstate.js').lua_State;
const LClosure = require('./lobject.js').LClosure;
+const Proto = require('./lfunc.js').Proto;
/**
* Parse Lua 5.3 bytecode
@@ -15,9 +18,17 @@ class BytecodeParser {
/**
* Initilialize bytecode parser
* @constructor
+ * @param {lua_State} Lua state object
* @param {DataView} dataView Contains the binary data
*/
- constructor(dataView) {
+ constructor(L, dataView) {
+ this.intSize = 4;
+ this.size_tSize = 8;
+ this.instructionSize = 4;
+ this.integerSize = 8;
+ this.numberSize = 8;
+
+ this.L = L;
this.dataView = dataView;
this.offset = 0;
}
@@ -32,36 +43,78 @@ class BytecodeParser {
return byte;
}
- peekWord() {
- return this.dataView.getUint32(this.offset, true);
+ peekInteger() {
+ return this.dataView.getInt32(this.offset, true);
+ }
+
+ readInteger() {
+ let integer = this.peekInteger();
+ this.offset += this.integerSize;
+
+ return integer;
+ }
+
+ peekNumber() {
+ return this.dataView.getFloat64(this.offset, true);
+ }
+
+ readNumber() {
+ let number = this.peekNumber();
+ this.offset += this.numberSize;
+
+ return number;
}
- readWord() {
- let word = this.peekWord();
- this.offset += 4;
+ readString(n) {
+ let string = "";
- return word;
+ for (let i = 0; i < n; i++)
+ string += String.fromCharCode(this.readByte());
+
+ return string;
}
checkHeader() {
- if (this.readByte() !== 0x1b
- || this.readByte() !== 0x4c
- || this.readByte() !== 0x75
- || this.readByte() !== 0x61)
- throw new Error("Bad LUA_SIGNATURE, expected [1b 4c 75 61]");
+ if (this.readString(4) !== "\x1bLua")
+ throw new Error("bad LUA_SIGNATURE, expected '<esc>Lua'");
if (this.readByte() !== 0x53)
- throw new Error("Bad Lua version, expected 5.3");
+ throw new Error("bad Lua version, expected 5.3");
if (this.readByte() !== 0)
- throw new Error("Supports only official PUC-Rio implementation")
+ throw new Error("supports only official PUC-Rio implementation");
+
+ if (this.readString(6) !== "\x19\x93\r\n\x1a\n")
+ throw new Error("bytecode corrupted");
+
+ this.intSize = this.readByte();
+ this.size_tSize = this.readByte();
+ this.instructionSize = this.readByte();
+ this.integerSize = this.readByte();
+ this.numberSize = this.readByte();
+
+ if (this.readInteger() !== 0x5678)
+ throw new Error("endianness mismatch");
+
+ if (this.readNumber() !== 370.5)
+ throw new Error("float format mismatch in");
+
}
luaU_undump() {
checkHeader();
- let cl = new LClosure(L, this.readByte());
+
+ let cl = new LClosure(this.L, this.readByte());
+ L.top++;
+ cl.p = new Proto(this.L);
+
+ loadFunction(cl.p);
+
+ assert(cl.nupvalues === cl.p.upvalues.length);
return cl;
}
-} \ No newline at end of file
+}
+
+module.exports = BytecodeParser; \ No newline at end of file