diff options
Diffstat (limited to 'src')
-rw-r--r-- | src/lapi.js | 4 | ||||
-rw-r--r-- | src/lauxlib.js | 11 | ||||
-rw-r--r-- | src/lbaselib.js | 4 | ||||
-rw-r--r-- | src/lcode.js | 2 | ||||
-rw-r--r-- | src/ldebug.js | 4 | ||||
-rw-r--r-- | src/ldo.js | 10 | ||||
-rw-r--r-- | src/linit.js | 5 | ||||
-rw-r--r-- | src/llex.js | 113 | ||||
-rw-r--r-- | src/lobject.js | 6 | ||||
-rw-r--r-- | src/lparser.js | 124 | ||||
-rw-r--r-- | src/lstrlib.js | 2 | ||||
-rw-r--r-- | src/ltablib.js | 2 | ||||
-rw-r--r-- | src/ltm.js | 2 | ||||
-rw-r--r-- | src/lua.js | 2 | ||||
-rw-r--r-- | src/lundump.js | 30 | ||||
-rw-r--r-- | src/lutf8lib.js | 63 | ||||
-rw-r--r-- | src/lvm.js | 16 |
17 files changed, 201 insertions, 199 deletions
diff --git a/src/lapi.js b/src/lapi.js index 6e1471d..e7fbf4f 100644 --- a/src/lapi.js +++ b/src/lapi.js @@ -678,7 +678,7 @@ const lua_compare_ = function(L, o1, o2, op) { }; const lua_stringtonumber = function(L, s) { - let number = parseFloat(s); + let number = parseFloat(lobject.jsstring(s)); L.stack[L.top++] = new TValue(number % 1 !== 0 ? CT.LUA_TNUMFLT : CT.LUA_TNUMINT, number); assert(L.top <= L.ci.top, "stack overflow"); return s.length; @@ -980,6 +980,8 @@ module.exports.lua_toboolean = lua_toboolean; module.exports.lua_todataview = lua_todataview; module.exports.lua_tointeger = lua_tointeger; module.exports.lua_tointegerx = lua_tointegerx; +module.exports.lua_tojsstring = lua_tojsstring; +module.exports.lua_toljsstring = lua_toljsstring; module.exports.lua_tolstring = lua_tolstring; module.exports.lua_tonumber = lua_tonumber; module.exports.lua_topointer = lua_topointer; diff --git a/src/lauxlib.js b/src/lauxlib.js index f60bd8c..9813095 100644 --- a/src/lauxlib.js +++ b/src/lauxlib.js @@ -55,7 +55,7 @@ const findfield = function(L, objidx, level) { const pushglobalfuncname = function(L, ar) { let top = lapi.lua_gettop(L); ldebug.lua_getinfo(L, 'f', ar); /* push function */ - lapi.lua_getfield(L, lua.LUA_REGISTRYINDEX, LUA_LOADED_TABLE); + lapi.lua_getfield(L, lua.LUA_REGISTRYINDEX, lua.to_luastring(LUA_LOADED_TABLE)); if (findfield(L, top + 1, 2)) { let name = lapi.lua_tostring(L, -1); if (name.jsstring().startsWith("_G.")) { @@ -333,7 +333,7 @@ const luaL_tolstring = function(L, idx) { ** Leaves resulting module on the top. */ const luaL_requiref = function(L, modname, openf, glb) { - luaL_getsubtable(L, lua.LUA_REGISTRYINDEX, LUA_LOADED_TABLE); + luaL_getsubtable(L, lua.LUA_REGISTRYINDEX, lua.to_luastring(LUA_LOADED_TABLE)); lapi.lua_getfield(L, -1, modname); /* LOADED[modname] */ if (!lapi.lua_toboolean(L, -1)) { /* package not already loaded? */ lapi.lua_pop(L, 1); /* remove field */ @@ -441,7 +441,7 @@ if (typeof require === "function") { lf.pos += bytes; } if (bytes > 0) - return lf.binary ? toDataView(lf.buff) : lf.buff; + return lf.binary ? toDataView(lf.buff) : lf.buff.slice(0, bytes); else return null; }; @@ -502,15 +502,16 @@ if (typeof require === "function") { }; const luaL_loadfilex = function(L, filename, mode) { + let jsfilename = lobject.jsstring(filename); let lf = new LoadF(); let fnameindex = lapi.lua_gettop(L) + 1; /* index of filename on the stack */ if (filename === null) { lapi.lua_pushliteral(L, "=stdin"); lf.f = process.stdin.fd; } else { - lapi.lua_pushliteral(L, `@${filename}`); + lapi.lua_pushliteral(L, `@${jsfilename}`); try { - lf.f = fs.openSync(filename, "r"); + lf.f = fs.openSync(jsfilename, "r"); } catch (e) { return errfile(L, lua.to_luastring("open"), fnameindex, e); } diff --git a/src/lbaselib.js b/src/lbaselib.js index 8420672..4d0fb9c 100644 --- a/src/lbaselib.js +++ b/src/lbaselib.js @@ -11,7 +11,7 @@ const TS = lua.thread_status; const luaB_print = function(L) { let n = lapi.lua_gettop(L); /* number of arguments */ - let str = ""; + let str = []; lapi.lua_getglobal(L, lua.to_luastring("tostring")); for (let i = 1; i <= n; i++) { @@ -201,7 +201,7 @@ const luaB_assert = function(L) { const luaB_select = function(L) { let n = lapi.lua_gettop(L); - if (lapi.lua_type(L, 1) === CT.LUA_TSTRING && lapi.lua_tostring(L, 1) === "#") { + if (lapi.lua_type(L, 1) === CT.LUA_TSTRING && lapi.lua_tostring(L, 1)[0] === "#".charCodeAt(0)) { lapi.lua_pushinteger(L, n - 1); return 1; } else { diff --git a/src/lcode.js b/src/lcode.js index 8b4a57c..752eedf 100644 --- a/src/lcode.js +++ b/src/lcode.js @@ -1231,7 +1231,7 @@ const luaK_setlist = function(fs, base, nelems, tostore) { codeextraarg(fs, c); } else - llex.luaX_syntaxerror(fs.ls, "constructor too long"); + llex.luaX_syntaxerror(fs.ls, lua.to_luastring("constructor too long")); fs.freereg = base + 1; /* free registers with list values */ }; diff --git a/src/ldebug.js b/src/ldebug.js index 507e764..0fba4cb 100644 --- a/src/ldebug.js +++ b/src/ldebug.js @@ -431,7 +431,7 @@ const varinfo = function(L, o) { kind = getobjname(ci.func.p, ci.pcOff, stkid - ci.u.l.base); } - return lua.to_luastring(kind ? ` (${lobject.jsstring(kind.funcname)} '${lobject.jsstring(kind.name)}')` : ``); + return lua.to_luastring(kind ? ` (${lobject.jsstring(kind.funcname)} '${kind.name.jsstring()}')` : ``); }; const luaG_typeerror = function(L, o, op) { @@ -457,7 +457,7 @@ const luaG_opinterror = function(L, p1, p2, msg) { const luaG_ordererror = function(L, p1, p2) { let t1 = ltm.luaT_objtypename(L, p1); let t2 = ltm.luaT_objtypename(L, p2); - if (t1 === t2) + if (t1.join() === t2.join()) luaG_runerror(L, lua.to_luastring(`attempt to compare two ${lobject.jsstring(t1)} values`)); else luaG_runerror(L, lua.to_luastring(`attempt to compare ${lobject.jsstring(t1)} with ${lobject.jsstring(t2)}`)); @@ -519,8 +519,8 @@ class SParser { } const checkmode = function(L, mode, x) { - if (mode && mode.indexOf(x.charCodeAt(0)) === -1) { - lapi.lua_pushstring(L, lua.to_luastring(`attempt to load a ${lobject.jsstring(x)} chunk (mode is '${mode}')`)); + if (mode && mode.indexOf(x[0]) === -1) { + lapi.lua_pushstring(L, lua.to_luastring(`attempt to load a ${lobject.jsstring(x)} chunk (mode is '${lobject.jsstring(mode)}')`)); luaD_throw(L, TS.LUA_ERRSYNTAX); } }; @@ -528,11 +528,11 @@ const checkmode = function(L, mode, x) { 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"); + if (c === lua.LUA_SIGNATURE.charCodeAt(0)) { + checkmode(L, p.mode, lua.to_luastring("binary")); cl = new BytecodeParser(L, p.z.buffer).luaU_undump(); } else { - checkmode(L, p.mode, "text"); + checkmode(L, p.mode, lua.to_luastring("text")); cl = lparser.luaY_parser(L, p.z, p.buff, p.dyd, p.name, c); } diff --git a/src/linit.js b/src/linit.js index 4d50f8b..3e9b1af 100644 --- a/src/linit.js +++ b/src/linit.js @@ -2,6 +2,7 @@ const assert = require('assert'); +const lua = require('./lua.js'); const lapi = require('./lapi.js'); const lauxlib = require('./lauxlib.js'); const lbaselib = require('./lbaselib.js'); @@ -24,9 +25,9 @@ const loadedlibs = { const luaL_openlibs = function(L) { /* "require" functions from 'loadedlibs' and set results to global table */ for (let lib in loadedlibs) { - lauxlib.luaL_requiref(L, lib, loadedlibs[lib], 1); + lauxlib.luaL_requiref(L, lua.to_luastring(lib), loadedlibs[lib], 1); lapi.lua_pop(L, 1); /* remove lib */ } }; -module.exports.luaL_openlibs = luaL_openlibs;
\ No newline at end of file +module.exports.luaL_openlibs = luaL_openlibs; diff --git a/src/llex.js b/src/llex.js index 9b81cd7..e043c17 100644 --- a/src/llex.js +++ b/src/llex.js @@ -15,6 +15,12 @@ const TS = lua.thread_status; const FIRST_RESERVED = 257; +// To avoid charCodeAt everywhere +const char = []; +for (let i = 0; i < 127; i++) + char[String.fromCharCode(i)] = i; +module.exports.char = char; + const RESERVED = { /* terminal symbols denoted by reserved words */ TK_AND: FIRST_RESERVED, @@ -157,7 +163,7 @@ const save = function(ls, c) { const luaX_token2str = function(ls, token) { if (typeof token === "string" || token < FIRST_RESERVED) { /* single-byte symbols? */ - return lua.to_luastring(`'${typeof token === "string" ? token : lobject.jsstring(token)}'`); + return lua.to_luastring(`'${typeof token === "string" ? token : lobject.jsstring([token])}'`); } else { let s = luaX_tokens[token - FIRST_RESERVED]; if (token < R.TK_EOS) /* fixed format (symbols and reserved words)? */ @@ -168,7 +174,7 @@ const luaX_token2str = function(ls, token) { }; const currIsNewline = function(ls) { - return ls.current === '\n'.charCodeAt(0) || ls.current === '\r'.charCodeAt(0); + return ls.current === char['\n'] || ls.current === char['\r']; }; const next = function(ls) { @@ -235,7 +241,7 @@ const check_next1 = function(ls, c) { ** saves it */ const check_next2 = function(ls, set) { - if (ls.current === set.charAt(0).charCodeAt(0) || ls.current === set.charAt(1).charCodeAt(0)) { + if (ls.current === set[0].charCodeAt(0) || ls.current === set[1].charCodeAt(0)) { save_and_next(ls); return true; } @@ -248,7 +254,7 @@ const read_numeral = function(ls, seminfo) { let first = ls.current; assert(ljstype.lisdigit(ls.current)); save_and_next(ls); - if (first === '0' && check_next2(ls, "xX")) /* hexadecimal? */ + if (first === char['0'] && check_next2(ls, "xX")) /* hexadecimal? */ expo = "Pp"; for (;;) { @@ -256,7 +262,7 @@ const read_numeral = function(ls, seminfo) { check_next2(ls, "-+"); /* optional exponent sign */ if (ljstype.lisxdigit(ls.current)) save_and_next(ls); - else if (ls.current === '.') + else if (ls.current === char['.']) save_and_next(ls); else break; } @@ -295,7 +301,6 @@ const lexerror = function(ls, msg, token) { }; const luaX_syntaxerror = function(ls, msg) { - msg = msg instanceof TValue ? msg.value : lua.to_luastring(msg); lexerror(ls, msg, ls.t.token); }; @@ -307,9 +312,9 @@ const luaX_syntaxerror = function(ls, msg) { const skip_sep = function(ls) { let count = 0; let s = ls.current; - assert(s === '['.charCodeAt(0) || s === ']'.charCodeAt(0)); + assert(s === char['['] || s === char[']']); save_and_next(ls); - while (ls.current === '='.charCodeAt(0)) { + while (ls.current === char['=']) { save_and_next(ls); count++; } @@ -332,15 +337,15 @@ const read_long_string = function(ls, seminfo, sep) { lexerror(ls, lua.to_luastring(msg), R.TK_EOS); break; } - case ']'.charCodeAt(0): { + case char[']']: { if (skip_sep(ls) === sep) { save_and_next(ls); /* skip 2nd ']' */ skip = true; } break; } - case '\n'.charCodeAt(0): case '\r'.charCodeAt(0): { - save(ls, '\n'.charCodeAt(0)); + case char['\n']: case char['\r']: { + save(ls, char['\n']); inclinenumber(ls); if (!seminfo) { ls.buff.n = 0; @@ -386,7 +391,7 @@ const readhexaesc = function(ls) { const readutf8desc = function(ls) { let i = 4; /* chars to be removed: '\', 'u', '{', and first digit */ save_and_next(ls); /* skip 'u' */ - esccheck(ls, ls.current === '{'.charCodeAt(0), lua.to_luastring("missing '{'")); + esccheck(ls, ls.current === char['{'], lua.to_luastring("missing '{'")); let r = gethexa(ls); /* must have at least one digit */ save_and_next(ls); @@ -396,7 +401,7 @@ const readutf8desc = function(ls) { esccheck(ls, r <= 0x10FFFF, lua.to_luastring("UTF-8 value too large")); save_and_next(ls); } - esccheck(ls, ls.current === '}'.charCodeAt(0), lua.to_luastring("missing '}'")); + esccheck(ls, ls.current === char['}'], lua.to_luastring("missing '}'")); next(ls); /* skip '}' */ ls.buff.n -= i; /* remove saved chars from buffer */ return r; @@ -429,30 +434,30 @@ const read_string = function(ls, del, seminfo) { case -1: lexerror(ls, lua.to_luastring("unfinished string"), R.TK_EOS); break; - case '\n'.charCodeAt(0): - case '\r'.charCodeAt(0): + case char['\n']: + case char['\r']: lexerror(ls, lua.to_luastring("unfinished string"), R.TK_STRING); break; - case '\\'.charCodeAt(0): { /* escape sequences */ + case char['\\']: { /* escape sequences */ save_and_next(ls); /* keep '\\' for error messages */ let will; let c; switch(ls.current) { - case 'a': c = '\a'.charCodeAt(0); will = 'read_save'; break; - case 'b': c = '\b'.charCodeAt(0); will = 'read_save'; break; - case 'f': c = '\f'.charCodeAt(0); will = 'read_save'; break; - case 'n': c = '\n'.charCodeAt(0); will = 'read_save'; break; - case 'r': c = '\r'.charCodeAt(0); will = 'read_save'; break; - case 't': c = '\t'.charCodeAt(0); will = 'read_save'; break; - case 'v': c = '\v'.charCodeAt(0); will = 'read_save'; break; - case 'x': c = readhexaesc(ls); will = 'read_save'; break; - case 'u': utf8esc(ls); will = 'no_save'; break; - case '\n'.charCodeAt(0): case '\r'.charCodeAt(0): - inclinenumber(ls); c = '\n'; will = 'only_save'; break; - case '\\'.charCodeAt(0): case '\"'.charCodeAt(0): case '\''.charCodeAt(0): + case char['a']: c = char['\a']; will = 'read_save'; break; + case char['b']: c = char['\b']; will = 'read_save'; break; + case char['f']: c = char['\f']; will = 'read_save'; break; + case char['n']: c = char['\n']; will = 'read_save'; break; + case char['r']: c = char['\r']; will = 'read_save'; break; + case char['t']: c = char['\t']; will = 'read_save'; break; + case char['v']: c = char['\v']; will = 'read_save'; break; + case char['x']: c = readhexaesc(ls); will = 'read_save'; break; + case char['u']: utf8esc(ls); will = 'no_save'; break; + case char['\n']: case char['\r']: + inclinenumber(ls); c = char['\n']; will = 'only_save'; break; + case char['\\']: case char['\"']: case char['\'']: c = ls.current; will = 'read_save'; break; case -1: will = 'no_save'; break; /* will raise an error next loop */ - case 'z': { /* zap following span of spaces */ + case char['z']: { /* zap following span of spaces */ ls.buff.n -= 1; /* remove '\\' */ next(ls); /* skip the 'z' */ while (ljstype.lisspace(ls.current)) { @@ -500,20 +505,20 @@ const llex = function(ls, seminfo) { for (;;) { switch (ls.current) { - case '\n'.charCodeAt(0): case '\r'.charCodeAt(0): { /* line breaks */ + case char['\n']: case char['\r']: { /* line breaks */ inclinenumber(ls); break; } - case ' '.charCodeAt(0): case '\f'.charCodeAt(0): case '\t'.charCodeAt(0): case '\v'.charCodeAt(0): { /* spaces */ + case char[' ']: case char['\f']: case char['\t']: case char['\v']: { /* spaces */ next(ls); break; } - case '-'.charCodeAt(0): { /* '-' or '--' (comment) */ + case char['-']: { /* '-' or '--' (comment) */ next(ls); - if (ls.current !== '-'.charCodeAt(0)) return '-'; + if (ls.current !== char['-']) return char['-']; /* else is a comment */ next(ls); - if (ls.current === '['.charCodeAt(0)) { /* long comment? */ + if (ls.current === char['[']) { /* long comment? */ let sep = skip_sep(ls); ls.buff.n = 0; /* 'skip_sep' may dirty the buffer */ ls.buff.buffer = []; @@ -530,63 +535,63 @@ const llex = function(ls, seminfo) { next(ls); /* skip until end of line (or end of file) */ break; } - case '['.charCodeAt(0): { /* long string or simply '[' */ + case char['[']: { /* long string or simply '[' */ let sep = skip_sep(ls); if (sep >= 0) { read_long_string(ls, seminfo, sep); return R.TK_STRING; } else if (sep !== -1) /* '[=...' missing second bracket */ lexerror(ls, lua.to_luastring("invalid long string delimiter"), R.TK_STRING); - return '['; + return char['[']; } - case '='.charCodeAt(0): { + case char['=']: { next(ls); if (check_next1(ls, '=')) return R.TK_EQ; - else return '='; + else return char['=']; } - case '<'.charCodeAt(0): { + case char['<']: { next(ls); if (check_next1(ls, '=')) return R.TK_LE; else if (check_next1(ls, '<')) return R.TK_SHL; - else return '<'; + else return char['<']; } - case '>'.charCodeAt(0): { + case char['>']: { next(ls); if (check_next1(ls, '=')) return R.TK_GE; else if (check_next1(ls, '>')) return R.TK_SHR; - else return '>'; + else return char['>']; } - case '/'.charCodeAt(0): { + case char['/']: { next(ls); if (check_next1(ls, '/')) return R.TK_IDIV; - else return '/'; + else return char['/']; } - case '~'.charCodeAt(0): { + case char['~']: { next(ls); if (check_next1(ls, '=')) return R.TK_NE; - else return '~'; + else return char['~']; } - case ':'.charCodeAt(0): { + case char[':']: { next(ls); if (check_next1(ls, ':')) return R.TK_DBCOLON; - else return ':'; + else return char[':']; } - case '"'.charCodeAt(0): case '\''.charCodeAt(0): { /* short literal strings */ + case char['"']: case char['\'']: { /* short literal strings */ read_string(ls, ls.current, seminfo); return R.TK_STRING; } - case '.'.charCodeAt(0): { /* '.', '..', '...', or number */ + case char['.']: { /* '.', '..', '...', or number */ save_and_next(ls); if (check_next1(ls, '.')) { if (check_next1(ls, '.')) return R.TK_DOTS; /* '...' */ else return R.TK_CONCAT; /* '..' */ } - else if (!ljstype.lisdigit(ls.current)) return '.'; + else if (!ljstype.lisdigit(ls.current)) return char['.']; else return read_numeral(ls, seminfo); } - case '0': case '1': case '2': case '3': case '4': - case '5': case '6': case '7': case '8': case '9': { + case char['0']: case char['1']: case char['2']: case char['3']: case char['4']: + case char['5']: case char['6']: case char['7']: case char['8']: case char['9']: { return read_numeral(ls, seminfo); } case -1: { @@ -598,7 +603,7 @@ const llex = function(ls, seminfo) { save_and_next(ls); } while (ljstype.lislalnum(ls.current)); - let ts = new TValue(CT.LUA_TLNGSTR, lua.to_luastring(ls.buff.buffer.join(''))); + let ts = new TValue(CT.LUA_TLNGSTR, ls.buff.buffer); seminfo.ts = ts; let kidx = luaX_tokens.slice(0, 22).indexOf(ts.jsstring()); if (kidx >= 0) /* reserved word? */ diff --git a/src/lobject.js b/src/lobject.js index 812ac6a..e958975 100644 --- a/src/lobject.js +++ b/src/lobject.js @@ -132,6 +132,8 @@ const luaO_nilobject = new TValue(CT.LUA_TNIL, null); module.exports.luaO_nilobject = luaO_nilobject; const jsstring = function(value, from, to) { + assert(Array.isArray(value), "jsstring expect a array of bytes"); + let u0, u1, u2, u3, u4, u5; let idx = 0; value = value.slice(from ? from : 0, to); @@ -194,6 +196,8 @@ class Table extends TValue { } } else if (typeof key === "string") { // To avoid key = lua.to_luastring(key).map(e => `${e}|`).join(''); + } else if (Array.isArray(key)) { + key = key.map(e => `${e}|`).join(''); } return key; @@ -293,7 +297,7 @@ const luaO_chunkid = function(source, bufflen) { else { /* truncate it */ out = out.concat(source.slice(1, bufflen)); } - } else if (source.charAt(0) === '@') { /* file name */ + } else if (source[0] === '@'.charCodeAt(0)) { /* file name */ if (l <= bufflen) /* small enough? */ out = source.slice(1); else { /* add '...' before rest of name */ diff --git a/src/lparser.js b/src/lparser.js index 01b9a08..249d51f 100644 --- a/src/lparser.js +++ b/src/lparser.js @@ -18,6 +18,8 @@ const Table = lobject.Table; const UnOpr = lcode.UnOpr; const UpVal = lfunc.UpVal; +const char = llex.char; + const MAXVARS = 200; const hasmultret = function(k) { @@ -248,7 +250,7 @@ const new_localvar = function(ls, name) { }; const new_localvarliteral = function(ls, name) { - new_localvar(ls, new TValue(lua.CT.LUA_TLNGSTR, lua.to_luastring(name))); + new_localvar(ls, new TValue(lua.CT.LUA_TLNGSTR, name)); }; const getlocvar = function(fs, i) { @@ -273,7 +275,7 @@ const removevars = function(fs, tolevel) { const searchupvalue = function(fs, name) { let up = fs.f.upvalues; for (let i = 0; i < fs.nups; i++) { - if (up[i].name.join() === name.join()) + if (up[i].name.value.join() === name.value.join()) return i; } return -1; /* not found */ @@ -291,7 +293,7 @@ const newupvalue = function(fs, name, v) { const searchvar = function(fs, n) { for (let i = fs.nactvar - 1; i >= 0; i--) { - if (n.join() === getlocvar(fs, i).varname.join()) + if (n.value.join() === getlocvar(fs, i).varname.value.join()) return i; } @@ -611,7 +613,7 @@ const yindex = function(ls, v) { llex.luaX_next(ls); /* skip the '[' */ expr(ls, v); lcode.luaK_exp2val(ls.fs, v); - checknext(ls, ']'); + checknext(ls, char[']']); }; /* @@ -643,7 +645,7 @@ const recfield = function(ls, cc) { } else /* ls->t.token === '[' */ yindex(ls, key); cc.nh++; - checknext(ls, '='); + checknext(ls, char['=']); let rkkey = lcode.luaK_exp2RK(fs, key); expr(ls, val); lcode.luaK_codeABC(fs, OpCodesI.OP_SETTABLE, cc.t.u.info, rkkey, lcode.luaK_exp2RK(fs, val)); @@ -685,13 +687,13 @@ const field = function(ls, cc) { /* field -> listfield | recfield */ switch (ls.t.token) { case R.TK_NAME: { /* may be 'listfield' or 'recfield' */ - if (llex.luaX_lookahead(ls) !== '=') /* expression? */ + if (llex.luaX_lookahead(ls) !== char['=']) /* expression? */ listfield(ls, cc); else recfield(ls, cc); break; } - case '[': { + case char['[']: { recfield(ls, cc); break; } @@ -714,14 +716,14 @@ const constructor = function(ls, t) { init_exp(t, expkind.VRELOCABLE, pc); init_exp(cc.v, expkind.VVOID, 0); /* no value (yet) */ lcode.luaK_exp2nextreg(ls.fs, t); /* fix it at stack top */ - checknext(ls, '{'); + checknext(ls, char['{']); do { assert(cc.v.k === expkind.VVOID || cc.tostore > 0); - if (ls.t.token === '}') break; + if (ls.t.token === char['}']) break; closelistfield(fs, cc); field(ls, cc); - } while (testnext(ls, ',') || testnext(ls, ';')); - check_match(ls, '}', '{', line); + } while (testnext(ls, char[',']) || testnext(ls, char[';'])); + check_match(ls, char['}'], char['{'], line); lastlistfield(fs, cc); lopcode.SETARG_B(fs.f.code[pc], lobject.luaO_int2fb(cc.na)); /* set initial array size */ lopcode.SETARG_C(fs.f.code[pc], lobject.luaO_int2fb(cc.nh)); /* set initial table size */ @@ -735,7 +737,7 @@ const parlist = function(ls) { let f = fs.f; let nparams = 0; f.is_vararg = 0; - if (ls.t.token !== ')') { /* is 'parlist' not empty? */ + if (ls.t.token !== char[')']) { /* is 'parlist' not empty? */ do { switch (ls.t.token) { case R.TK_NAME: { /* param -> NAME */ @@ -750,7 +752,7 @@ const parlist = function(ls) { } default: llex.luaX_syntaxerror(ls, lua.to_luastring("<name> or '...' expected")); } - } while(!f.is_vararg && testnext(ls, ',')); + } while(!f.is_vararg && testnext(ls, char[','])); } adjustlocalvars(ls, nparams); f.numparams = fs.nactvar; @@ -764,13 +766,13 @@ const body = function(ls, e, ismethod, line) { new_fs.f = addprototype(ls); new_fs.f.linedefined = line; open_func(ls, new_fs, bl); - checknext(ls, '('); + checknext(ls, char['(']); if (ismethod) { new_localvarliteral(ls, lua.to_luastring("self")); /* create 'self' parameter */ adjustlocalvars(ls, 1); } parlist(ls); - checknext(ls, ')'); + checknext(ls, char[')']); statlist(ls); new_fs.f.lastlinedefined = ls.linenumber; check_match(ls, R.TK_END, R.TK_FUNCTION, line); @@ -782,7 +784,7 @@ const explist = function(ls, v) { /* explist -> expr { ',' expr } */ let n = 1; /* at least one expression */ expr(ls, v); - while (testnext(ls, ',')) { + while (testnext(ls, char[','])) { lcode.luaK_exp2nextreg(ls.fs, v); expr(ls, v); n++; @@ -794,18 +796,18 @@ const funcargs = function(ls, f, line) { let fs = ls.fs; let args = new expdesc(); switch (ls.t.token) { - case '(': { /* funcargs -> '(' [ explist ] ')' */ + case char['(']: { /* funcargs -> '(' [ explist ] ')' */ llex.luaX_next(ls); - if (ls.t.token === ')') /* arg list is empty? */ + if (ls.t.token === char[')']) /* arg list is empty? */ args.k = expkind.VVOID; else { explist(ls, args); lcode.luaK_setmultret(fs, args); } - check_match(ls, ')', '(', line); + check_match(ls, char[')'], char['('], line); break; } - case '{': { /* funcargs -> constructor */ + case char['{']: { /* funcargs -> constructor */ constructor(ls, args); break; } @@ -842,11 +844,11 @@ const funcargs = function(ls, f, line) { const primaryexp = function(ls, v) { /* primaryexp -> NAME | '(' expr ')' */ switch (ls.t.token) { - case '(': { + case char['(']: { let line = ls.linenumber; llex.luaX_next(ls); expr(ls, v); - check_match(ls, ')', '(', line); + check_match(ls, char[')'], char['('], line); lcode.luaK_dischargevars(ls.fs, v); return; } @@ -868,18 +870,18 @@ const suffixedexp = function(ls, v) { primaryexp(ls, v); for (;;) { switch (ls.t.token) { - case '.': { /* fieldsel */ + case char['.']: { /* fieldsel */ fieldsel(ls, v); break; } - case '[': { /* '[' exp1 ']' */ + case char['[']: { /* '[' exp1 ']' */ let key = new expdesc(); lcode.luaK_exp2anyregup(fs, v); yindex(ls, key); lcode.luaK_indexed(fs, v, key); break; } - case ':': { /* ':' NAME funcargs */ + case char[':']: { /* ':' NAME funcargs */ let key = new expdesc(); llex.luaX_next(ls); checkname(ls, key); @@ -887,7 +889,7 @@ const suffixedexp = function(ls, v) { funcargs(ls, v, line); break; } - case '(': case R.TK_STRING: case '{': { /* funcargs */ + case char['(']: case R.TK_STRING: case char['{']: { /* funcargs */ lcode.luaK_exp2nextreg(fs, v); funcargs(ls, v, line); break; @@ -933,7 +935,7 @@ const simpleexp = function(ls, v) { init_exp(v, expkind.VVARARG, lcode.luaK_codeABC(fs, OpCodesI.OP_VARARG, 0, 1, 0)); break; } - case '{': { /* constructor */ + case char['{']: { /* constructor */ constructor(ls, v); return; } @@ -952,34 +954,34 @@ const simpleexp = function(ls, v) { const getunopr = function(op) { switch (op) { - case R.TK_NOT: return UnOpr.OPR_NOT; - case '-': return UnOpr.OPR_MINUS; - case '~': return UnOpr.OPR_BNOT; - case '#': return UnOpr.OPR_LEN; - default: return UnOpr.OPR_NOUNOPR; + case R.TK_NOT: return UnOpr.OPR_NOT; + case char['-']: return UnOpr.OPR_MINUS; + case char['~']: return UnOpr.OPR_BNOT; + case char['#']: return UnOpr.OPR_LEN; + default: return UnOpr.OPR_NOUNOPR; } }; const getbinopr = function(op) { switch (op) { - case '+': return BinOpr.OPR_ADD; - case '-': return BinOpr.OPR_SUB; - case '*': return BinOpr.OPR_MUL; - case '%': return BinOpr.OPR_MOD; - case '^': return BinOpr.OPR_POW; - case '/': return BinOpr.OPR_DIV; + case char['+']: return BinOpr.OPR_ADD; + case char['-']: return BinOpr.OPR_SUB; + case char['*']: return BinOpr.OPR_MUL; + case char['%']: return BinOpr.OPR_MOD; + case char['^']: return BinOpr.OPR_POW; + case char['/']: return BinOpr.OPR_DIV; case R.TK_IDIV: return BinOpr.OPR_IDIV; - case '&': return BinOpr.OPR_BAND; - case '|': return BinOpr.OPR_BOR; - case '~': return BinOpr.OPR_BXOR; + case char['&']: return BinOpr.OPR_BAND; + case char['|']: return BinOpr.OPR_BOR; + case char['~']: return BinOpr.OPR_BXOR; case R.TK_SHL: return BinOpr.OPR_SHL; case R.TK_SHR: return BinOpr.OPR_SHR; case R.TK_CONCAT: return BinOpr.OPR_CONCAT; case R.TK_NE: return BinOpr.OPR_NE; case R.TK_EQ: return BinOpr.OPR_EQ; - case '<': return BinOpr.OPR_LT; + case char['<']: return BinOpr.OPR_LT; case R.TK_LE: return BinOpr.OPR_LE; - case '>': return BinOpr.OPR_GT; + case char['>']: return BinOpr.OPR_GT; case R.TK_GE: return BinOpr.OPR_GE; case R.TK_AND: return BinOpr.OPR_AND; case R.TK_OR: return BinOpr.OPR_OR; @@ -1102,7 +1104,7 @@ const check_conflict = function(ls, lh, v) { const assignment = function(ls, lh, nvars) { let e = new expdesc(); check_condition(ls, vkisvar(lh.v.k), lua.to_luastring("syntax error")); - if (testnext(ls, ',')) { /* assignment -> ',' suffixedexp assignment */ + if (testnext(ls, char[','])) { /* assignment -> ',' suffixedexp assignment */ let nv = new LHS_assign(); nv.prev = lh; suffixedexp(ls, nv.v); @@ -1111,7 +1113,7 @@ const assignment = function(ls, lh, nvars) { checklimit(ls.fs, nvars + ls.L.nCcalls, llimit.LUAI_MAXCCALLS, lua.to_luastring("JS levels")); assignment(ls, nv, nvars + 1); } else { /* assignment -> '=' explist */ - checknext(ls, '='); + checknext(ls, char['=']); let nexps = explist(ls, e); if (nexps !== nvars) adjust_assign(ls, nvars, nexps, e); @@ -1158,7 +1160,7 @@ const checkrepeated = function(fs, ll, label) { /* skip no-op statements */ const skipnoopstat = function(ls) { - while (ls.t.token === ';' || ls.t.token === R.TK_DBCOLON) + while (ls.t.token === char[';'] || ls.t.token === R.TK_DBCOLON) statement(ls); }; @@ -1256,11 +1258,11 @@ const fornum = function(ls, varname, line) { new_localvarliteral(ls, lua.to_luastring("(for limit)")); new_localvarliteral(ls, lua.to_luastring("(for step)")); new_localvar(ls, varname); - checknext(ls, '='); + checknext(ls, char['=']); exp1(ls); /* initial value */ - checknext(ls, ','); + checknext(ls, char[',']); exp1(ls); /* limit */ - if (testnext(ls, ',')) + if (testnext(ls, char[','])) exp1(ls); /* optional step */ else { /* default step = 1 */ lcode.luaK_codek(fs, fs.freereg, lcode.luaK_intK(fs, 1)); @@ -1281,7 +1283,7 @@ const forlist = function(ls, indexname) { new_localvarliteral(ls, lua.to_luastring("(for control)")); /* create declared variables */ new_localvar(ls, indexname); - while (testnext(ls, ',')) { + while (testnext(ls, char[','])) { new_localvar(ls, str_checkname(ls)); nvars++; } @@ -1300,8 +1302,8 @@ const forstat = function(ls, line) { llex.luaX_next(ls); /* skip 'for' */ let varname = str_checkname(ls); /* first variable name */ switch (ls.t.token) { - case '=': fornum(ls, varname, line); break; - case ',': case R.TK_IN: forlist(ls, varname); break; + case char['=']: fornum(ls, varname, line); break; + case char[',']: case R.TK_IN: forlist(ls, varname); break; default: llex.luaX_syntaxerror(ls, lua.to_luastring("'=' or 'in' expected")); } check_match(ls, R.TK_END, R.TK_FOR, line); @@ -1373,8 +1375,8 @@ const localstat = function(ls) { do { new_localvar(ls, str_checkname(ls)); nvars++; - } while (testnext(ls, ',')); - if (testnext(ls, '=')) + } while (testnext(ls, char[','])); + if (testnext(ls, char['='])) nexps = explist(ls, e); else { e.k = expkind.VVOID; @@ -1388,9 +1390,9 @@ const funcname = function(ls, v) { /* funcname -> NAME {fieldsel} [':' NAME] */ let ismethod = 0; singlevar(ls, v); - while (ls.t.token === '.') + while (ls.t.token === char['.']) fieldsel(ls, v); - if (ls.t.token === ':') { + if (ls.t.token === char[':']) { ismethod = 1; fieldsel(ls, v); } @@ -1413,7 +1415,7 @@ const exprstat= function(ls) { let fs = ls.fs; let v = new LHS_assign(); suffixedexp(ls, v.v); - if (ls.t.token === '=' || ls.t.token === ',') { /* stat . assignment ? */ + if (ls.t.token === char['='] || ls.t.token === char[',']) { /* stat . assignment ? */ v.prev = null; assignment(ls, v, 1); } @@ -1428,7 +1430,7 @@ const retstat = function(ls) { let fs = ls.fs; let e = new expdesc(); let first, nret; /* registers with returned values */ - if (block_follow(ls, 1) || ls.t.token === ';') + if (block_follow(ls, 1) || ls.t.token === char[';']) first = nret = 0; /* return no values */ else { nret = explist(ls, e); /* optional return values */ @@ -1451,14 +1453,14 @@ const retstat = function(ls) { } } lcode.luaK_ret(fs, first, nret); - testnext(ls, ';'); /* skip optional semicolon */ + testnext(ls, char[';']); /* skip optional semicolon */ }; const statement = function(ls) { let line = ls.linenumber; /* may be needed for error messages */ enterlevel(ls); switch(ls.t.token) { - case ';': { /* stat -> ';' (empty statement) */ + case char[';']: { /* stat -> ';' (empty statement) */ llex.luaX_next(ls); /* skip ';' */ break; } @@ -1547,7 +1549,7 @@ const luaY_parser = function(L, z, buff, dyd, name, firstchar) { lexstate.h = new Table(); /* create table for scanner */ L.stack[L.top++] = lexstate.h; funcstate.f = cl.p = new Proto(L); - funcstate.f.source = new TValue(lua.CT.LUA_TLNGSTR, lua.to_luastring(name)); + funcstate.f.source = new TValue(lua.CT.LUA_TLNGSTR, name); lexstate.buff = buff; lexstate.dyd = dyd; dyd.actvar.n = dyd.gt.n = dyd.label.n = 0; diff --git a/src/lstrlib.js b/src/lstrlib.js index 471187b..e163485 100644 --- a/src/lstrlib.js +++ b/src/lstrlib.js @@ -1372,7 +1372,7 @@ const createmetatable = function(L) { lapi.lua_setmetatable(L, -2); /* set table as metatable for strings */ lapi.lua_pop(L, 1); /* pop dummy string */ lapi.lua_pushvalue(L, -2); /* get string library */ - lapi.lua_setfield(L, -2, "__index"); /* metatable.__index = string */ + lapi.lua_setfield(L, -2, lua.to_luastring("__index")); /* metatable.__index = string */ lapi.lua_pop(L, 1); /* pop metatable */ }; diff --git a/src/ltablib.js b/src/ltablib.js index c45f7e5..eaaf24d 100644 --- a/src/ltablib.js +++ b/src/ltablib.js @@ -163,7 +163,7 @@ const pack = function(L) { for (let i = n; i >= 1; i--) /* assign elements */ lapi.lua_seti(L, 1, i); lapi.lua_pushinteger(L, n); - lapi.lua_setfield(L, 1, "n"); /* t.n = number of elements */ + lapi.lua_setfield(L, 1, ["n".charCodeAt(0)]); /* t.n = number of elements */ return 1; /* return table */ }; @@ -53,7 +53,7 @@ const luaT_typenames_ = [ "userdata", "thread", "proto" /* this last case is used for tests only */ -]; +].map(e => lua.to_luastring(e)); const ttypename = function(t) { return luaT_typenames_[t + 1]; @@ -135,6 +135,8 @@ class lua_Debug { } const to_luastring = function(str, maxBytesToWrite) { + assert(typeof str === "string", "to_luastring expect a js string"); + maxBytesToWrite = maxBytesToWrite !== undefined ? maxBytesToWrite : Number.MAX_SAFE_INTEGER; let outU8Array = []; diff --git a/src/lundump.js b/src/lundump.js index 7452c43..36fd674 100644 --- a/src/lundump.js +++ b/src/lundump.js @@ -5,10 +5,8 @@ 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 lobject = require('./lobject.js'); const Proto = require('./lfunc.js').Proto; -const constant_types = require('./lua.js').constant_types; const OpCodes = require('./lopcodes.js'); const LUAI_MAXSHORTLEN = 40; @@ -167,20 +165,20 @@ class BytecodeParser { let t = this.readByte(); switch (t) { - case constant_types.LUA_TNIL: - f.k.push(new TValue(constant_types.LUA_TNIL, null)); + case lua.CT.LUA_TNIL: + f.k.push(new lobject.TValue(lua.CT.LUA_TNIL, null)); break; - case constant_types.LUA_TBOOLEAN: - f.k.push(new TValue(constant_types.LUA_TBOOLEAN, this.readByte())); + case lua.CT.LUA_TBOOLEAN: + f.k.push(new lobject.TValue(lua.CT.LUA_TBOOLEAN, this.readByte())); break; - case constant_types.LUA_TNUMFLT: - f.k.push(new TValue(constant_types.LUA_TNUMFLT, this.readNumber())); + case lua.CT.LUA_TNUMFLT: + f.k.push(new lobject.TValue(lua.CT.LUA_TNUMFLT, this.readNumber())); break; - case constant_types.LUA_TNUMINT: - f.k.push(new TValue(constant_types.LUA_TNUMINT, this.readInteger())); + case lua.CT.LUA_TNUMINT: + f.k.push(new lobject.TValue(lua.CT.LUA_TNUMINT, this.readInteger())); break; - case constant_types.LUA_TSHRSTR: - case constant_types.LUA_TLNGSTR: + case lua.CT.LUA_TSHRSTR: + case lua.CT.LUA_TLNGSTR: f.k.push(this.L.l_G.intern(this.read8bitString())); break; default: @@ -206,7 +204,7 @@ class BytecodeParser { n = this.readInt(); for (let i = 0; i < n; i++) { f.locvars[i] = { - varname: this.readString(), + varname: new lobject.TValue(lua.CT.LUA_TLNGSTR, lua.to_luastring(this.readString())), startpc: this.readInt(), endpc: this.readInt() }; @@ -264,7 +262,7 @@ class BytecodeParser { luaU_undump() { this.checkHeader(); - let cl = new LClosure(this.L, this.readByte()); + let cl = new lobject.LClosure(this.L, this.readByte()); this.L.stack[this.L.top] = cl; this.L.top++; @@ -280,4 +278,4 @@ class BytecodeParser { } -module.exports = BytecodeParser;
\ No newline at end of file +module.exports = BytecodeParser; diff --git a/src/lutf8lib.js b/src/lutf8lib.js index 1df6096..ef9739f 100644 --- a/src/lutf8lib.js +++ b/src/lutf8lib.js @@ -58,50 +58,37 @@ const utf8_decode = function(s, val) { ** range [i,j], or nil + current position if 's' is not well formed in ** that interval */ -// const utflen = function(L) { -// let n = 0; -// let s = lauxlib.luaL_checkstring(L, 1); -// s = L.stack[lapi.index2addr_(L, 1)].value; -// let len = s.length; -// let posi = u_posrelat(lauxlib.luaL_optinteger(L, 2, 1), len); -// let posj = u_posrelat(lauxlib.luaL_optinteger(L, 3, -1), len); -// -// lauxlib.luaL_argcheck(L, 1 <= posi && --posi <= len, 2, "initial position out of string"); -// lauxlib.luaL_argcheck(L, --posj < len, 3, "final position out of string"); -// -// while (posi <= posj) { -// let dec = utf8_decode(s[posi]); -// let s1 = dec ? dec.string : null; -// if (s1 === null) { -// /* conversion error? */ -// lapi.lua_pushnil(L); /* return nil ... */ -// lapi.lua_pushinteger(L, posi + 1); /* ... and current position */ -// return 2; -// } -// posi = dec.pos; -// n++; -// } -// lapi.lua_pushinteger(L, n); -// return 1; -// }; - -// Shorter JSesque solution but doesn't take invalid UTF-8 sequence (but how can we get one ?) const utflen = function(L) { + let n = 0; let s = lauxlib.luaL_checkstring(L, 1); - let posi = u_posrelat(lauxlib.luaL_optinteger(L, 2, 1), s.length); - let posj = u_posrelat(lauxlib.luaL_optinteger(L, 3, -1), s.length); - - lauxlib.luaL_argcheck(L, 1 <= posi && --posi <= s.length, 2, lua.to_luastring("initial position out of string")); - lauxlib.luaL_argcheck(L, --posj < s.length, 3, lua.to_luastring("final position out of string")); - - lapi.lua_pushinteger(L, s.slice(posi, posj + 1).length); + s = L.stack[lapi.index2addr_(L, 1)].value; + let len = s.length; + let posi = u_posrelat(lauxlib.luaL_optinteger(L, 2, 1), len); + let posj = u_posrelat(lauxlib.luaL_optinteger(L, 3, -1), len); + + lauxlib.luaL_argcheck(L, 1 <= posi && --posi <= len, 2, "initial position out of string"); + lauxlib.luaL_argcheck(L, --posj < len, 3, "final position out of string"); + + while (posi <= posj) { + let dec = utf8_decode(s.slice(posi)); + let s1 = dec ? dec.string : null; + if (s1 === null) { + /* conversion error? */ + lapi.lua_pushnil(L); /* return nil ... */ + lapi.lua_pushinteger(L, posi + 1); /* ... and current position */ + return 2; + } + posi = s.length - s1.length; + n++; + } + lapi.lua_pushinteger(L, n); return 1; }; const pushutfchar = function(L, arg) { let code = lauxlib.luaL_checkinteger(L, arg); lauxlib.luaL_argcheck(L, 0 <= code && code <= MAXUNICODE, arg, lua.to_luastring("value out of range")); - lapi.lua_pushstring(L, `${String.fromCharCode(code)}`); + lapi.lua_pushstring(L, lua.to_luastring(String.fromCharCode(code))); }; /* @@ -248,8 +235,8 @@ const UTF8PATT = "[\0-\x7F\xC2-\xF4][\x80-\xBF]*"; const luaopen_utf8 = function(L) { lauxlib.luaL_newlib(L, funcs); - lapi.lua_pushstring(L, UTF8PATT); - lapi.lua_setfield(L, -2, "charpattern"); + lapi.lua_pushstring(L, lua.to_luastring(UTF8PATT)); + lapi.lua_setfield(L, -2, lua.to_luastring("charpattern")); return 1; }; @@ -592,19 +592,19 @@ const luaV_execute = function(L) { let nstep = tonumber(pstep); if (nlimit === false) - ldebug.luaG_runerror(L, "'for' limit must be a number"); + ldebug.luaG_runerror(L, lua.to_luastring("'for' limit must be a number")); plimit.type = CT.LUA_TNUMFLT; plimit.value = nlimit; if (nstep === false) - ldebug.luaG_runerror(L, "'for' step must be a number"); + ldebug.luaG_runerror(L, lua.to_luastring("'for' step must be a number")); pstep.type = CT.LUA_TNUMFLT; pstep.value = nstep; if (ninit === false) - ldebug.luaG_runerror(L, "'for' initial value must be a number"); + ldebug.luaG_runerror(L, lua.to_luastring("'for' initial value must be a number")); init.type = CT.LUA_TNUMFLT; init.value = ninit - nstep; @@ -977,7 +977,7 @@ const luaV_objlen = function(L, ra, rb) { default: { tm = ltm.luaT_gettmbyobj(L, rb, ltm.TMS.TM_LEN); if (tm.ttisnil()) - ldebug.luaG_typeerror(L, rb, "get length of"); + ldebug.luaG_typeerror(L, rb, lua.to_luastring("get length of")); break; } } @@ -1042,7 +1042,7 @@ const gettable = function(L, table, key, ra, recur) { recur = recur ? recur : 0; if (recur >= MAXTAGRECUR) - ldebug.luaG_runerror(L, "'__index' chain too long; possible loop"); + ldebug.luaG_runerror(L, lua.to_luastring("'__index' chain too long; possible loop")); if (table.ttistable()) { let element = table.__index(table, key); @@ -1063,7 +1063,7 @@ const luaV_finishget = function(L, t, key, val, slot, recur) { assert(!t.ttistable()); tm = ltm.luaT_gettmbyobj(L, t, ltm.TMS.TM_INDEX); if (tm.ttisnil()) - ldebug.luaG_typeerror(L, t, 'index'); + ldebug.luaG_typeerror(L, t, lua.to_luastring('index')); } else { /* 't' is a table */ assert(slot.ttisnil()); tm = ltm.luaT_gettmbyobj(L, t, ltm.TMS.TM_INDEX); // TODO: fasttm @@ -1085,7 +1085,7 @@ const settable = function(L, table, key, v, recur) { recur = recur ? recur : 0; if (recur >= MAXTAGRECUR) - ldebug.luaG_runerror(L, "'__newindex' chain too long; possible loop"); + ldebug.luaG_runerror(L, lua.to_luastring("'__newindex' chain too long; possible loop")); if (table.ttistable()) { let element = table.__index(table, key); @@ -1112,7 +1112,7 @@ const luaV_finishset = function(L, t, key, val, slot, recur) { } else { /* not a table; check metamethod */ tm = ltm.luaT_gettmbyobj(L, t, ltm.TMS.TM_NEWINDEX); if (tm.ttisnil()) - ldebug.luaG_typeerror(L, t, 'index'); + ldebug.luaG_typeerror(L, t, lua.to_luastring('index')); } if (tm.ttisfunction()) { |