aboutsummaryrefslogtreecommitdiff
diff options
context:
space:
mode:
-rw-r--r--README.md3
-rw-r--r--src/lapi.js23
-rw-r--r--src/ldump.js64
-rw-r--r--src/lstrlib.js18
-rw-r--r--src/lundump.js2
-rw-r--r--tests/lstrlib.js46
6 files changed, 129 insertions, 27 deletions
diff --git a/README.md b/README.md
index e8257cc..6de8cab 100644
--- a/README.md
+++ b/README.md
@@ -28,7 +28,6 @@
- [x] ...
- [ ] lua_arith
- [ ] lua_close
- - [ ] lua_dump
- [ ] lua_gethook
- [ ] lua_gethookcount
- [ ] lua_gethookmask
@@ -99,6 +98,7 @@
- [ ] String
- [x] string.byte
- [x] string.char
+ - [x] string.dump
- [x] string.format
- [x] string.len
- [x] string.lower
@@ -106,7 +106,6 @@
- [x] string.reverse
- [x] string.sub
- [x] string.upper
- - [ ] string.dump
- [ ] string.find
- [ ] string.gmatch
- [ ] string.gsub
diff --git a/src/lapi.js b/src/lapi.js
index 96fe207..a51796b 100644
--- a/src/lapi.js
+++ b/src/lapi.js
@@ -4,6 +4,7 @@ const assert = require('assert');
const ldebug = require('./ldebug.js');
const ldo = require('./ldo.js');
+const ldump = require('./ldump.js');
const lfunc = require('./lfunc.js');
const llex = require('./llex.js');
const lobject = require('./lobject.js');
@@ -239,6 +240,18 @@ const lua_pushstring = function (L, s) {
return s;
};
+// Push string without 8-bit conversion
+const lua_pushrawstring = function(L, s) {
+ if (typeof s !== "string")
+ L.stack[L.top] = ldo.nil;
+ else {
+ L.stack[L.top] = new TValue(CT.LUA_TLNGSTR, s.split('').map(e => e.charCodeAt(0)));
+ }
+ L.top++;
+ assert(L.top <= L.ci.top, "stack overflow");
+ return s;
+};
+
const lua_pushliteral = lua_pushstring;
const lua_pushcclosure = function(L, fn, n) {
@@ -693,6 +706,14 @@ const lua_load = function(L, reader, data, chunckname, mode) {
return status;
};
+const lua_dump = function(L, writer, data, strip) {
+ assert(1 < L.top - L.ci.funcOff, "not enough elements in the stack");
+ let o = L.stack[L.top -1];
+ if (o.ttisLclosure())
+ return ldump.luaU_dump(L, o.p, writer, data, strip);
+ return 1;
+};
+
const lua_status = function(L) {
return L.status;
};
@@ -835,6 +856,7 @@ module.exports.lua_compare_ = lua_compare_;
module.exports.lua_concat = lua_concat;
module.exports.lua_copy = lua_copy;
module.exports.lua_createtable = lua_createtable;
+module.exports.lua_dump = lua_dump;
module.exports.lua_error = lua_error;
module.exports.lua_gc = lua_gc;
module.exports.lua_getallocf = lua_getallocf;
@@ -871,6 +893,7 @@ module.exports.lua_pushliteral = lua_pushliteral;
module.exports.lua_pushlstring = lua_pushlstring;
module.exports.lua_pushnil = lua_pushnil;
module.exports.lua_pushnumber = lua_pushnumber;
+module.exports.lua_pushrawstring = lua_pushrawstring;
module.exports.lua_pushstring = lua_pushstring;
module.exports.lua_pushthread = lua_pushthread;
module.exports.lua_pushtvalue = lua_pushtvalue;
diff --git a/src/ldump.js b/src/ldump.js
index 795bd19..dd8eb29 100644
--- a/src/ldump.js
+++ b/src/ldump.js
@@ -10,7 +10,7 @@ const CT = lua.constant_types;
const LUAC_DATA = "\x19\x93\r\n\x1a\n";
const LUAC_INT = 0x5678;
const LUAC_NUM = 370.5;
-const LUAC_VERSION = lua.LUA_VERSION_MAJOR.charCodeAt(0) * 16 + lua.LUA_VERSION_MINOR.charCodeAt(0);
+const LUAC_VERSION = Number.parseInt(lua.LUA_VERSION_MAJOR) * 16 + Number.parseInt(lua.LUA_VERSION_MINOR);
const LUAC_FORMAT = 0; /* this is the official format */
class DumpState {
@@ -28,51 +28,66 @@ const DumpBlock = function(b, size, D) {
D.status = D.writer(D.L, b, size, D.data);
};
-const DumpVector = function(v, n, D) {
- DumpBlock(v, n, D);
-};
-
const DumpLiteral = function(s, D) {
+ s = lua.to_luastring(s);
DumpBlock(s, s.length, D);
};
-const DumpVar = function (x,D) {
- DumpVector(x, 1, D);
-};
-
const DumpByte = function(y, D) {
- DumpVar(y, D);
+ DumpBlock([y], 1, D);
};
const DumpInt = function(x, D) {
- DumpVar(x, D);
+ let dv = new DataView(new ArrayBuffer(4));
+ dv.setInt32(0, x, true);
+ let t = [];
+ for (let i = 0; i < 4; i++)
+ t.push(dv.getUint8(i, true));
+
+ DumpBlock(t, 4, D);
};
-const DumpInteger = DumpInt;
+const DumpInteger = function(x, D) {
+ let dv = new DataView(new ArrayBuffer(8));
+ dv.setInt32(0, x, true);
+ let t = [];
+ for (let i = 0; i < 8; i++)
+ t.push(dv.getUint8(i, true));
+ DumpBlock(t, 8, D);
+};
const DumpNumber = function(x, D) {
- DumpVar(x, D);
+ let dv = new DataView(new ArrayBuffer(8));
+ dv.setFloat64(0, x, true);
+ let t = [];
+ for (let i = 0; i < 8; i++)
+ t.push(dv.getUint8(i, true));
+
+ DumpBlock(t, 8, D);
};
const DumpString = function(s, D) {
if (s === null)
DumpByte(0, D);
else {
- let size = s.value.length + 1;
- let str = s.value;
+ let size = s.length + 1;
+ let str = s;
if (size < 0xFF)
DumpByte(size, D);
else {
DumpByte(0xFF, D);
- DumpVar(size, D);
+ DumpInt(size, D);
}
- DumpVector(str, size - 1, D); /* no need to save '\0' */
+ DumpBlock(str, size - 1, D); /* no need to save '\0' */
}
};
const DumpCode = function(f, D) {
- DumpInt(f.code.length, D);
- DumpVector(f.code, f.code.length, D);
+ let s = f.code.map(e => e.code);
+ DumpInt(s.length, D);
+
+ for (let i = 0; i < s.length; i++)
+ DumpInt(s[i], D);
};
const DumpConstants = function(f, D) {
@@ -120,25 +135,25 @@ const DumpUpvalues = function(f, D) {
const DumpDebug = function(f, D) {
let n = D.strip ? 0 : f.lineinfo.length;
DumpInt(n, D);
- DumpVector(f.lineinfo, n, D);
+ DumpBlock(f.lineinfo, n, D);
n = D.strip ? 0 : f.locvars.length;
DumpInt(n, D);
for (let i = 0; i < n; i++) {
- DumpString(f.locvars[i].varname, D);
+ DumpString(f.locvars[i].varname.value, D);
DumpInt(f.locvars[i].startpc, D);
DumpInt(f.locvars[i].endpc, D);
}
n = D.strip ? 0 : f.upvalues.length;
DumpInt(n, D);
for (let i = 0; i < n; i++)
- DumpString(f.upvalues[i].name, D);
+ DumpString(f.upvalues[i].name.value, D);
};
const DumpFunction = function(f, psource, D) {
if (D.strip || f.source === psource)
DumpString(null, D); /* no debug info or same source as its parent */
else
- DumpString(f.source, D);
+ DumpString(f.source.value, D);
DumpInt(f.linedefined, D);
DumpInt(f.lastlinedefined, D);
DumpByte(f.numparams, D);
@@ -155,7 +170,8 @@ const DumpHeader = function(D) {
DumpLiteral(lua.LUA_SIGNATURE, D);
DumpByte(LUAC_VERSION, D);
DumpByte(LUAC_FORMAT, D);
- DumpLiteral(LUAC_DATA, D);
+ let cdata = LUAC_DATA.split('').map(e => e.charCodeAt(0));
+ DumpBlock(cdata, cdata.length, D);
DumpByte(4, D); // intSize
DumpByte(8, D); // size_tSize
DumpByte(4, D); // instructionSize
diff --git a/src/lstrlib.js b/src/lstrlib.js
index b47138f..83e82b0 100644
--- a/src/lstrlib.js
+++ b/src/lstrlib.js
@@ -48,6 +48,23 @@ const str_char = function(L) {
return 1;
};
+const writer = function(L, b, size, B) {
+ assert(Array.isArray(b));
+ B.push(...b.slice(0, size));
+ return 0;
+};
+
+const str_dump = function(L) {
+ let b = [];
+ let strip = lapi.lua_toboolean(L, 2);
+ lauxlib.luaL_checktype(L, 1, CT.LUA_TFUNCTION);
+ lapi.lua_settop(L, 1);
+ if (lapi.lua_dump(L, writer, b, strip) !== 0)
+ return lauxlib.luaL_error(L, "unable to dump given function");
+ lapi.lua_pushrawstring(L, b.map(e => String.fromCharCode(e)).join(''));
+ return 1;
+};
+
const SIZELENMOD = luaconf.LUA_NUMBER_FRMLEN.length;
const L_NBFD = 16; // TODO: arbitrary
@@ -379,6 +396,7 @@ const str_byte = function(L) {
const strlib = {
"byte": str_byte,
"char": str_char,
+ "dump": str_dump,
"format": str_format,
"len": str_len,
"lower": str_lower,
diff --git a/src/lundump.js b/src/lundump.js
index c44c847..70adbec 100644
--- a/src/lundump.js
+++ b/src/lundump.js
@@ -38,7 +38,7 @@ class BytecodeParser {
}
peekInteger() {
- return this.dataView.getInt32(this.offset, true);
+ return this.dataView.getInt32(this.offset, true); // TODO: 64b ?
}
readInteger() {
diff --git a/tests/lstrlib.js b/tests/lstrlib.js
index 4df4283..aec8e2a 100644
--- a/tests/lstrlib.js
+++ b/tests/lstrlib.js
@@ -414,4 +414,50 @@ test('string.sub', function (t) {
"456",
"Correct element(s) on the stack"
);
+});
+
+
+test('string.dump', function (t) {
+ let luaCodeToDump = `
+ local todump = function(p1, p2, p3)
+ local s = "hello"
+ local i = 12
+ local f = 12.5
+ local b = true
+
+ return p1 + p2 + p3
+ end`,
+ luaCode = `
+ ${luaCodeToDump}
+
+ return string.dump(todump)
+ `, L, bytes = [];
+
+ t.plan(3);
+
+ t.doesNotThrow(function () {
+
+ let bc = toByteCode(luaCodeToDump).dataView;
+ for (let i = 0; i < bc.byteLength; i++)
+ bytes.push(bc.getUint8(i, true));
+
+ L = lauxlib.luaL_newstate();
+
+ linit.luaL_openlibs(L);
+
+ lauxlib.luaL_loadstring(L, luaCode);
+
+ }, "Lua program loaded without error");
+
+ t.doesNotThrow(function () {
+
+ lapi.lua_call(L, 0, -1);
+
+ }, "Lua program ran without error");
+
+ t.deepEqual(
+ L.stack[L.top -1].value,
+ bytes,
+ "Correct element(s) on the stack"
+ );
}); \ No newline at end of file