aboutsummaryrefslogtreecommitdiff
path: root/src
diff options
context:
space:
mode:
authorBenoit Giannangeli <benoit.giannangeli@boursorama.fr>2017-03-01 10:23:32 +0100
committerBenoit Giannangeli <benoit.giannangeli@boursorama.fr>2017-03-01 10:56:03 +0100
commitae8b95ee9c3871f506b20c74367fdc9e8cb098e2 (patch)
tree6348ab52aad93905af66196f5d071628ac60adb5 /src
parent74dda64eab7951da520dc451a1f3bbb8c7d62706 (diff)
downloadfengari-ae8b95ee9c3871f506b20c74367fdc9e8cb098e2.tar.gz
fengari-ae8b95ee9c3871f506b20c74367fdc9e8cb098e2.tar.bz2
fengari-ae8b95ee9c3871f506b20c74367fdc9e8cb098e2.zip
lua_load will load both binary and text
Diffstat (limited to 'src')
-rw-r--r--src/lapi.js31
-rw-r--r--src/lcode.js50
-rw-r--r--src/ldo.js78
-rw-r--r--src/llex.js46
-rw-r--r--src/lobject.js50
-rw-r--r--src/lparser.js44
-rw-r--r--src/lua.js32
-rw-r--r--src/lundump.js3
8 files changed, 214 insertions, 120 deletions
diff --git a/src/lapi.js b/src/lapi.js
index 9a05638..36da7c6 100644
--- a/src/lapi.js
+++ b/src/lapi.js
@@ -2,16 +2,17 @@
const assert = require('assert');
+const ldebug = require('./ldebug.js');
const ldo = require('./ldo.js');
+const lfunc = require('./lfunc.js');
+const llex = require('./llex.js');
const lobject = require('./lobject.js');
+const lstate = require('./lstate.js');
const ltm = require('./ltm.js');
-const lfunc = require('./lfunc.js');
const lua = require('./lua.js');
const luaconf = require('./luaconf.js');
-const lstate = require('./lstate.js');
-const lvm = require('./lvm.js');
const lundump = require('./lundump.js');
-const ldebug = require('./ldebug.js');
+const lvm = require('./lvm.js');
const MAXUPVAL = lfunc.MAXUPVAL;
const CT = lua.constant_types;
const TS = lua.thread_status;
@@ -137,7 +138,7 @@ const lua_settop = function(L, idx) {
const lua_pop = function(L, n) {
lua_settop(L, -n - 1);
-}
+};
const reverse = function(L, from, to) {
for (; from < to; from++, to--) {
@@ -356,7 +357,7 @@ const lua_settable = function(L, idx) {
};
const lua_setfield = function(L, idx, k) {
- auxsetstr(L, index2addr(L, idx), k)
+ auxsetstr(L, index2addr(L, idx), k);
};
const lua_seti = function(L, idx, n) {
@@ -514,11 +515,11 @@ const lua_rawlen = function(L, idx) {
};
const lua_tointeger = function(L, idx) {
- return lvm.tointeger(index2addr(L, idx))
+ return lvm.tointeger(index2addr(L, idx));
};
const lua_tonumber = function(L, idx) {
- return lvm.tonumber(index2addr(L, idx))
+ return lvm.tonumber(index2addr(L, idx));
};
const lua_tothread = function(L, idx) {
@@ -596,7 +597,7 @@ const lua_typename = function(L, t) {
const lua_isnoneornil = function(L, n) {
return lua_type(L, n) <= 0;
-}
+};
const lua_istable = function(L, idx) {
return index2addr(L, idx).ttistable();
@@ -625,13 +626,14 @@ const lua_rawequal = function(L, index1, index2) {
** 'load' and 'call' functions (run Lua code)
*/
-const lua_load = function(L, data, chunckname) {
+// TODO: reader is ignored because we don't implement ZIO
+const lua_load = function(L, reader, data, chunckname, mode) {
+ let z = new llex.MBuffer(data);
if (!chunckname) chunckname = "?";
-
- let status = ldo.luaD_protectedparser(L, data, chunckname);
- if (status === TS.LUA_OK) {
+ let status = ldo.luaD_protectedparser(L, z, chunckname, mode);
+ if (status === TS.LUA_OK) { /* no errors? */
let f = L.stack[L.top - 1]; /* get newly created function */
- if (f.nupvalues >= 1) { /* does it have an upvalue? */
+ if (f.nupvalues >= 1) { /* does it have an upvalue? */
/* get global table from registry */
let reg = L.l_G.l_registry;
let gt = reg.value.get(lua.LUA_RIDX_GLOBALS - 1);
@@ -639,7 +641,6 @@ const lua_load = function(L, data, chunckname) {
f.upvals[0].u.value = gt;
}
}
-
return status;
};
diff --git a/src/lcode.js b/src/lcode.js
index c2134ff..9b48d4d 100644
--- a/src/lcode.js
+++ b/src/lcode.js
@@ -5,14 +5,60 @@ const assert = require('assert');
const llex = require('./llex.js');
const llimit = require('./llimit.js');
const lobject = require('./lobject.js');
-const lopcode = require('./lopcode.js');
+const lopcode = require('./lopcodes.js');
const lparser = require('./lparser.js');
+const ltm = require('./ltm.js');
const lua = require('./lua.js');
const lvm = require('./lvm.js');
const CT = lua.constants_type;
const OpCodesI = lopcode.OpCodesI;
const TValue = lobject.TValue;
+const luaO_arith = function(L, op, p1, p2, res) {
+ switch (op) {
+ case lvm.LUA_OPBAND: case lvm.LUA_OPBOR: case lvm.LUA_OPBXOR:
+ case lvm.LUA_OPSHL: case lvm.LUA_OPSHR:
+ case lvm.LUA_OPBNOT: { /* operate only on integers */
+ let i1 = lvm.tointeger(p1);
+ let i2 = lvm.tointeger(p2);
+ if (i1 !== false && i2 !== false) {
+ res.type = CT.LUA_TNUMINT;
+ res.value = lobject.intarith(L, op, i1, i2);
+ return;
+ }
+ else break; /* go to the end */
+ }
+ case lvm.LUA_OPDIV: case lvm.LUA_OPPOW: { /* operate only on floats */
+ let n1 = lvm.tonumber(p1);
+ let n2 = lvm.tonumber(p2);
+ if (n1 !== false && n2 !== false) {
+ res.type = CT.LUA_TNUMFLT;
+ res.value = lobject.numarith(L, op, n1, n2);
+ return;
+ }
+ else break; /* go to the end */
+ }
+ default: { /* other operations */
+ let n1 = lvm.tonumber(p1);
+ let n2 = lvm.tonumber(p2);
+ if (p1.ttisinteger() && p2.ttisinteger()) {
+ res.type = CT.LUA_TNUMINT;
+ res.value = lobject.intarith(L, op, p1.value, p2.value);
+ return;
+ }
+ else if (n1 !== false && n2 !== false) {
+ res.type = CT.LUA_TNUMFLT;
+ res.value = lobject.numarith(L, op, n1, n2);
+ return;
+ }
+ else break; /* go to the end */
+ }
+ }
+ /* could not perform raw operation; try metamethod */
+ assert(L !== null); /* should not fail when folding (compile time) */
+ ltm.luaT_trybinTM(L, p1, p2, res, (op - lua.LUA_OPADD) + ltm.TMS.TM_ADD);
+};
+
/* Maximum number of registers in a Lua function (must fit in 8 bits) */
const MAXREGS = 255;
@@ -964,7 +1010,7 @@ const constfolding = function(fs, op, e1, e2) {
let res = new TValue();
if (!tonumeral(e1, v1) || !tonumeral(e2, v2) || !validop(op, v1, v2))
return 0; /* non-numeric operands or not safe to fold */
- lobject.luaO_arith(fs.ls.L, op, v1, v2, res); /* does operation */
+ luaO_arith(fs.ls.L, op, v1, v2, res); /* does operation */
if (res.ttisinteger()) {
e1.k = ek.VKINT;
e1.u.ival = res.value;
diff --git a/src/ldo.js b/src/ldo.js
index 4345b15..f78cc9c 100644
--- a/src/ldo.js
+++ b/src/ldo.js
@@ -3,15 +3,18 @@
const assert = require('assert');
-const lua = require('./lua.js');
+const BytecodeParser = require('./lundump.js');
+const lapi = require('./lapi.js');
+const ldebug = require('./ldebug.js');
+const lfunc = require('./lfunc.js');
+const llex = require('./llex.js');
+const llimit = require('./llimit.js');
const lobject = require('./lobject.js');
+const lparser = require('./lparser.js');
const lstate = require('./lstate.js');
-const llimit = require('./llimit.js');
const ltm = require('./ltm.js');
+const lua = require('./lua.js');
const lvm = require('./lvm.js');
-const lfunc = require('./lfunc.js');
-const BytecodeParser = require('./lundump.js');
-const ldebug = require('./ldebug.js');
const CT = lua.constant_types;
const TS = lua.thread_status;
const LUA_MULTRET = lua.LUA_MULTRET;
@@ -475,7 +478,7 @@ const lua_yield = function(L, n) {
const luaD_pcall = function(L, func, u, old_top, ef) {
let old_ci = L.ci;
- // TODO: lu_byte old_allowhooks = L->allowhook;
+ let old_allowhooks = L.allowhook;
let old_nny = L.nny;
let old_errfunc = L.errfunc;
L.errfunc = ef;
@@ -486,7 +489,7 @@ const luaD_pcall = function(L, func, u, old_top, ef) {
lfunc.luaF_close(L, old_top);
seterrorobj(L, status, old_top);
L.ci = old_ci;
- // TODO: L->allowhook = old_allowhooks;
+ L.allowhook = old_allowhooks;
L.nny = old_nny;
}
@@ -504,31 +507,64 @@ const luaD_callnoyield = function(L, off, nResults) {
L.nny--;
};
-// TODO: since we only handle binary, no need for a reader or mode
-const f_parser = function(L, data) {
- let p = new BytecodeParser(data);
- let cl = p.luaU_undump(L);
+/*
+** Execute a protected parser.
+*/
+class SParser {
+ constructor() { /* data to 'f_parser' */
+ this.z = new llex.MBuffer();
+ this.buff = new llex.MBuffer(); /* dynamic structure used by the scanner */
+ this.dyd = new lparser.Dyndata(); /* dynamic structures used by the parser */
+ this.mode = null;
+ this.name = null;
+ }
+}
- assert(cl.nupvalues === cl.p.upvalues.length);
+const checkmode = function(L, mode, x) {
+ if (mode && mode !== x) {
+ lapi.lua_pushstring(L, `attempt to load a ${x} chunk (mode is '${mode}')`);
+ luaD_throw(L, TS.LUA_ERRSYNTAX);
+ }
+};
+
+const f_parser = function(L, p) {
+ let cl;
+ let c = p.z.getc(); /* read first character */
+ if (String.fromCharCode(c) === lua.LUA_SIGNATURE.charAt(0)) {
+ checkmode(L, p.mode, "binary");
+ cl = new BytecodeParser(p.z.buffer).luaU_undump(L);
+ } else {
+ checkmode(L, p.mode, "text");
+ cl = lparser.luaY_parser(L, p.z, p.buff, p.dyd, p.name, c);
+ }
+ assert(cl.nupvalues === cl.p.upvalues.length);
lfunc.luaF_initupvals(L, cl);
};
-const luaD_protectedparser = function(L, data, name) {
- L.nny++;
+const luaD_protectedparser = function(L, z, name, mode) {
+ let p = new SParser();
+ L.nny++; /* cannot yield during parsing */
+
+ p.z = z;
+ p.name = name;
+ p.mode = mode;
+ p.dyd.actvar.arr = null;
+ p.dyd.actvar.size = 0;
+ p.dyd.gt.arr = null;
+ p.dyd.gt.size = 0;
+ p.dyd.label.arr = null;
+ p.dyd.label.size = 0;
- let status = luaD_pcall(L, f_parser, data, L.top, L.errfunc);
+ let status = luaD_pcall(L, f_parser, p, L.top, L.errfunc);
L.nny--;
return status;
};
+module.exports.SParser = SParser;
module.exports.adjust_varargs = adjust_varargs;
-module.exports.lua_isyieldable = lua_isyieldable;
-module.exports.lua_resume = lua_resume;
-module.exports.lua_yield = lua_yield;
-module.exports.lua_yieldk = lua_yieldk;
module.exports.luaD_call = luaD_call;
module.exports.luaD_callnoyield = luaD_callnoyield;
module.exports.luaD_pcall = luaD_pcall;
@@ -537,6 +573,10 @@ module.exports.luaD_precall = luaD_precall;
module.exports.luaD_protectedparser = luaD_protectedparser;
module.exports.luaD_rawrunprotected = luaD_rawrunprotected;
module.exports.luaD_throw = luaD_throw;
+module.exports.lua_isyieldable = lua_isyieldable;
+module.exports.lua_resume = lua_resume;
+module.exports.lua_yield = lua_yield;
+module.exports.lua_yieldk = lua_yieldk;
module.exports.moveresults = moveresults;
module.exports.nil = nil;
module.exports.stackerror = stackerror;
diff --git a/src/llex.js b/src/llex.js
index 59bc4a4..73cda58 100644
--- a/src/llex.js
+++ b/src/llex.js
@@ -1,17 +1,18 @@
"use strict";
-const assert = require('assert');
-
-const lapi = require('./lapi.js');
-const lauxlib = require('./lauxlib.js');
-const ldebug = require('./ldebug.js');
-const ldo = require('./ldo.js');
-const ljstype = require('./ljstype');
-const lobject = require('./lobject');
-const lua = require('./lua.js');
-const TValue = lobject.TValue;
-const CT = lua.constant_types;
-const TS = lua.thread_status;
+const DataView = require('buffer-dataview');
+const assert = require('assert');
+
+const lapi = require('./lapi.js');
+const lauxlib = require('./lauxlib.js');
+const ldebug = require('./ldebug.js');
+const ldo = require('./ldo.js');
+const ljstype = require('./ljstype');
+const lobject = require('./lobject');
+const lua = require('./lua.js');
+const TValue = lobject.TValue;
+const CT = lua.constant_types;
+const TS = lua.thread_status;
const FIRST_RESERVED = 257;
@@ -72,11 +73,18 @@ const luaX_tokens = [
const NUM_RESERVED = Object.keys(RESERVED).length;
class MBuffer {
- constructor(string) {
- this.buffer = string ? string.split('') : [];
- this.n = this.buffer.length;
+ constructor(data) {
+ this.buffer = typeof data === "string" ? data.split('') : (data ? data : []);
+ this.n = this.buffer instanceof DataView ? this.buffer.byteLength : this.buffer.length;
this.off = 0;
}
+
+ getc() {
+ if (this.buffer instanceof DataView)
+ return this.n-- > 0 ? this.buffer.getUint8(this.off++, true) : -1;
+
+ return this.n-- > 0 ? this.buffer[this.off++] : -1;
+ }
}
class SemInfo {
@@ -90,7 +98,7 @@ class SemInfo {
class Token {
constructor() {
this.token = NaN;
- this.seminfo = null;
+ this.seminfo = new SemInfo();
}
}
@@ -101,8 +109,8 @@ class LexState {
this.current = NaN; /* current character (charint) */
this.linenumber = NaN; /* input line counter */
this.lastline = NaN; /* line of last token 'consumed' */
- this.t = null; /* current token */
- this.lookahead = null; /* look ahead token */
+ this.t = new Token(); /* current token */
+ this.lookahead = new Token(); /* look ahead token */
this.fs = null; /* current function (parser) */
this.L = null;
this.z = new MBuffer();
@@ -140,7 +148,7 @@ const currIsNewline = function(ls) {
};
const next = function(ls) {
- ls.current = ls.z.n-- > 0 ? ls.z.buffer[ls.z.off++] : -1;
+ ls.current = ls.z.getc();
};
const save_and_next = function(ls) {
diff --git a/src/lobject.js b/src/lobject.js
index f3078d1..f748416 100644
--- a/src/lobject.js
+++ b/src/lobject.js
@@ -4,10 +4,8 @@
const assert = require('assert');
const ljstype = require('./ljstype.js');
-const ltm = require('./ltm.js');
const lua = require('./lua.js');
-const lvm = require('./lvm.js');
-const CT = require('./lua.js').constant_types;
+const CT = lua.constant_types;
const UpVal = require('./lfunc.js').UpVal;
class TValue {
@@ -400,57 +398,11 @@ const numarith = function(L, op, v1, v2) {
}
};
-const luaO_arith = function(L, op, p1, p2, res) {
- switch (op) {
- case lvm.LUA_OPBAND: case lvm.LUA_OPBOR: case lvm.LUA_OPBXOR:
- case lvm.LUA_OPSHL: case lvm.LUA_OPSHR:
- case lvm.LUA_OPBNOT: { /* operate only on integers */
- let i1 = lvm.tointeger(p1);
- let i2 = lvm.tointeger(p2);
- if (i1 !== false && i2 !== false) {
- res.type = CT.LUA_TNUMINT;
- res.value = intarith(L, op, i1, i2);
- return;
- }
- else break; /* go to the end */
- }
- case lvm.LUA_OPDIV: case lvm.LUA_OPPOW: { /* operate only on floats */
- let n1 = lvm.tonumber(p1);
- let n2 = lvm.tonumber(p2);
- if (n1 !== false && n2 !== false) {
- res.type = CT.LUA_TNUMFLT;
- res.value = numarith(L, op, n1, n2);
- return;
- }
- else break; /* go to the end */
- }
- default: { /* other operations */
- let n1 = lvm.tonumber(p1);
- let n2 = lvm.tonumber(p2);
- if (p1.ttisinteger() && p2.ttisinteger()) {
- res.type = CT.LUA_TNUMINT;
- res.value = intarith(L, op, p1.value, p2.value);
- return;
- }
- else if (n1 !== false && n2 !== false) {
- res.type = CT.LUA_TNUMFLT;
- res.value = numarith(L, op, n1, n2);
- return;
- }
- else break; /* go to the end */
- }
- }
- /* could not perform raw operation; try metamethod */
- assert(L !== null); /* should not fail when folding (compile time) */
- ltm.luaT_trybinTM(L, p1, p2, res, (op - lua.LUA_OPADD) + ltm.TMS.TM_ADD);
-};
-
module.exports.CClosure = CClosure;
module.exports.LClosure = LClosure;
module.exports.TValue = TValue;
module.exports.Table = Table;
module.exports.UTF8BUFFSZ = UTF8BUFFSZ;
-module.exports.luaO_arith = luaO_arith;
module.exports.luaO_chunkid = luaO_chunkid;
module.exports.luaO_hexavalue = luaO_hexavalue;
module.exports.luaO_int2fb = luaO_int2fb;
diff --git a/src/lparser.js b/src/lparser.js
index 074542a..40d6c88 100644
--- a/src/lparser.js
+++ b/src/lparser.js
@@ -7,7 +7,7 @@ const lfunc = require('./lfunc.js');
const llex = require('./llex.js');
const llimit = require('./llimit.js');
const lobject = require('./lobject.js');
-const lopcode = require('./lopcode.js');
+const lopcode = require('./lopcodes.js');
const lua = require('./lua.js');
const BinOpr = lcode.BinOpr;
const CT = lua.constants_type;
@@ -106,6 +106,47 @@ class FuncState {
}
}
+ /* description of active local variable */
+class Vardesc {
+ constructor() {
+ this.idx = NaN; /* variable index in stack */
+ }
+}
+
+
+/* description of pending goto statements and label statements */
+class Labeldesc {
+ constructor() {
+ this.name = null; /* label identifier */
+ this.pc = NaN; /* position in code */
+ this.line = NaN; /* line where it appeared */
+ this.nactvar = NaN; /* local level where it appears in current block */
+ }
+}
+
+
+/* list of labels or gotos */
+class Labellist {
+ constructor() {
+ this.arr = []; /* array */
+ this.n = NaN; /* number of entries in use */
+ this.size = NaN; /* array size */
+ }
+}
+
+/* dynamic structures used by the parser */
+class Dyndata {
+ constructor() {
+ this.actvar = { /* list of active local variables */
+ arr: [],
+ n: NaN,
+ size: NaN
+ };
+ this.gt = new Labellist();
+ this.label = new Labellist();
+ }
+}
+
const semerror = function(ls, msg) {
ls.t.token = 0; /* remove "near <token>" from final message */
llex.luaX_syntaxerror(ls, msg);
@@ -1511,6 +1552,7 @@ const luaY_parser = function(L, z, buff, dyd, name, firstchar) {
};
+module.exports.Dyndata = Dyndata;
module.exports.expkind = expkind;
module.exports.luaY_parser = luaY_parser;
module.exports.vkisinreg = vkisinreg; \ No newline at end of file
diff --git a/src/lua.js b/src/lua.js
index 60cc78e..9367746 100644
--- a/src/lua.js
+++ b/src/lua.js
@@ -5,6 +5,9 @@ const assert = require('assert');
const lualib = require('./lualib.js');
const luaconf = require('./luaconf.js');
+/* mark for precompiled code ('<esc>Lua') */
+const LUA_SIGNATURE = "\x1bLua";
+
const LUA_VERSION_MAJOR = "5";
const LUA_VERSION_MINOR = "3";
const LUA_VERSION_NUM = 503;
@@ -106,21 +109,21 @@ const print_version = function() {
class lua_Debug {
constructor() {
- // int event;
- // const char *name; /* (n) */
- // const char *namewhat; /* (n) 'global', 'local', 'field', 'method' */
- // const char *what; /* (S) 'Lua', 'C', 'main', 'tail' */
- // const char *source; /* (S) */
- // int currentline; /* (l) */
- // int linedefined; /* (S) */
- // int lastlinedefined; /* (S) */
- // unsigned char nups; /* (u) number of upvalues */
- // unsigned char nparams;/* (u) number of parameters */
- // char isvararg; /* (u) */
- // char istailcall; /* (t) */
- // char short_src[LUA_IDSIZE]; /* (S) */
+ this.event = NaN;
+ this.name = null; /* (n) */
+ this.namewhat = null; /* (n) 'global', 'local', 'field', 'method' */
+ this.what = null; /* (S) 'Lua', 'C', 'main', 'tail' */
+ this.source = null; /* (S) */
+ this.currentline = NaN; /* (l) */
+ this.linedefined = NaN; /* (S) */
+ this.lastlinedefined = NaN; /* (S) */
+ this.nups = NaN; /* (u) number of upvalues */
+ this.nparams = NaN; /* (u) number of parameters */
+ this.isvararg = NaN; /* (u) */
+ this.istailcall = NaN; /* (t) */
+ this.short_src = null; /* (S) */
/* private part */
- // struct CallInfo *i_ci; /* active function */
+ this.i_ci = null; /* active function */
}
}
@@ -162,6 +165,7 @@ module.exports.LUA_RELEASE = LUA_RELEASE;
module.exports.LUA_RIDX_GLOBALS = LUA_RIDX_GLOBALS;
module.exports.LUA_RIDX_LAST = LUA_RIDX_LAST;
module.exports.LUA_RIDX_MAINTHREAD = LUA_RIDX_MAINTHREAD;
+module.exports.LUA_SIGNATURE = LUA_SIGNATURE;
module.exports.LUA_VERSION = LUA_VERSION;
module.exports.LUA_VERSION_MAJOR = LUA_VERSION_MAJOR;
module.exports.LUA_VERSION_MINOR = LUA_VERSION_MINOR;
diff --git a/src/lundump.js b/src/lundump.js
index b79e6ea..5a6d8c4 100644
--- a/src/lundump.js
+++ b/src/lundump.js
@@ -5,6 +5,7 @@ const DataView = require('buffer-dataview');
const fs = require('fs');
const assert = require('assert');
+const lua = require('./lua.js');
const LClosure = require('./lobject.js').LClosure;
const TValue = require('./lobject.js').TValue;
const Proto = require('./lfunc.js').Proto;
@@ -256,7 +257,7 @@ class BytecodeParser {
}
checkHeader() {
- if (this.readString(4) !== "\x1bLua")
+ if (this.readString(4) !== lua.LUA_SIGNATURE)
throw new Error("bad LUA_SIGNATURE, expected '<esc>Lua'");
if (this.readByte() !== 0x53)