diff options
Diffstat (limited to 'src')
-rw-r--r-- | src/lapi.js | 31 | ||||
-rw-r--r-- | src/lcode.js | 50 | ||||
-rw-r--r-- | src/ldo.js | 78 | ||||
-rw-r--r-- | src/llex.js | 46 | ||||
-rw-r--r-- | src/lobject.js | 50 | ||||
-rw-r--r-- | src/lparser.js | 44 | ||||
-rw-r--r-- | src/lua.js | 32 | ||||
-rw-r--r-- | src/lundump.js | 3 |
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; @@ -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 @@ -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) |