diff options
Diffstat (limited to 'src')
-rw-r--r-- | src/defs.js | 382 | ||||
-rw-r--r-- | src/fengari.js | 18 | ||||
-rw-r--r-- | src/fengaricore.js | 36 | ||||
-rw-r--r-- | src/lapi.js | 465 | ||||
-rw-r--r-- | src/lauxlib.js | 610 | ||||
-rw-r--r-- | src/lbaselib.js | 431 | ||||
-rw-r--r-- | src/lcode.js | 113 | ||||
-rw-r--r-- | src/lcorolib.js | 133 | ||||
-rw-r--r-- | src/ldblib.js | 389 | ||||
-rw-r--r-- | src/ldebug.js | 172 | ||||
-rw-r--r-- | src/ldo.js | 245 | ||||
-rw-r--r-- | src/ldump.js | 43 | ||||
-rw-r--r-- | src/lfunc.js | 77 | ||||
-rw-r--r-- | src/linit.js | 60 | ||||
-rw-r--r-- | src/liolib.js | 124 | ||||
-rw-r--r-- | src/llex.js | 438 | ||||
-rw-r--r-- | src/llimits.js | 14 | ||||
-rw-r--r-- | src/lmathlib.js | 200 | ||||
-rw-r--r-- | src/loadlib.js | 370 | ||||
-rw-r--r-- | src/lobject.js | 437 | ||||
-rw-r--r-- | src/loslib.js | 164 | ||||
-rw-r--r-- | src/lparser.js | 527 | ||||
-rw-r--r-- | src/lstate.js | 45 | ||||
-rw-r--r-- | src/lstring.js | 32 | ||||
-rw-r--r-- | src/lstrlib.js | 864 | ||||
-rw-r--r-- | src/ltable.js | 84 | ||||
-rw-r--r-- | src/ltablib.js | 244 | ||||
-rw-r--r-- | src/ltm.js | 81 | ||||
-rw-r--r-- | src/lua.js | 33 | ||||
-rw-r--r-- | src/luaconf.js | 7 | ||||
-rw-r--r-- | src/lualib.js | 11 | ||||
-rw-r--r-- | src/lundump.js | 117 | ||||
-rw-r--r-- | src/lutf8lib.js | 121 | ||||
-rw-r--r-- | src/lvm.js | 349 | ||||
-rw-r--r-- | src/lzio.js | 7 |
35 files changed, 4313 insertions, 3130 deletions
diff --git a/src/defs.js b/src/defs.js index a2c5c75..70d0c73 100644 --- a/src/defs.js +++ b/src/defs.js @@ -1,16 +1,200 @@ "use strict"; -const assert = require('assert'); -const luaconf = require('./luaconf.js'); +const { LUAI_MAXSTACK } = require('./luaconf.js'); -// To avoid charCodeAt everywhere -const char = []; -for (let i = 0; i < 127; i++) - char[String.fromCharCode(i)] = i; -module.exports.char = char; +/* + * Fengari specific string conversion functions + */ + +let luastring_from; +if (typeof Uint8Array.from === "function") { + luastring_from = Uint8Array.from.bind(Uint8Array); +} else { + luastring_from = function(a) { + let i = 0; + let len = a.length; + let r = new Uint8Array(len); + while (len > i) r[i] = a[i++]; + return r; + }; +} + +let luastring_indexOf; +if (typeof (new Uint8Array().indexOf) === "function") { + luastring_indexOf = function(s, v, i) { + return s.indexOf(v, i); + }; +} else { + /* Browsers that don't support Uint8Array.indexOf seem to allow using Array.indexOf on Uint8Array objects e.g. IE11 */ + let array_indexOf = [].indexOf; + if (array_indexOf.call(new Uint8Array(1), 0) !== 0) throw Error("missing .indexOf"); + luastring_indexOf = function(s, v, i) { + return array_indexOf.call(s, v, i); + }; +} + +let luastring_of; +if (typeof Uint8Array.of === "function") { + luastring_of = Uint8Array.of.bind(Uint8Array); +} else { + luastring_of = function() { + return luastring_from(arguments); + }; +} + +const is_luastring = function(s) { + return s instanceof Uint8Array; +}; + +/* test two lua strings for equality */ +const luastring_eq = function(a, b) { + if (a !== b) { + let len = a.length; + if (len !== b.length) return false; + /* XXX: Should this be a constant time algorithm? */ + for (let i=0; i<len; i++) + if (a[i] !== b[i]) return false; + } + return true; +}; + +const to_jsstring = function(value, from, to) { + if (!is_luastring(value)) throw new TypeError("to_jsstring expects a Uint8Array"); + + if (to === void 0) { + to = value.length; + } else { + to = Math.min(value.length, to); + } + + let str = ""; + for (let i = (from!==void 0?from:0); i < to;) { + let u0 = value[i++]; + if (u0 < 0x80) { + /* single byte sequence */ + str += String.fromCharCode(u0); + } else if (u0 < 0xC2 || u0 > 0xF4) { + throw RangeError("cannot convert invalid utf8 to javascript string"); + } else if (u0 <= 0xDF) { + /* two byte sequence */ + if (i >= to) throw RangeError("cannot convert invalid utf8 to javascript string"); + let u1 = value[i++]; + if ((u1&0xC0) !== 0x80) throw RangeError("cannot convert invalid utf8 to javascript string"); + str += String.fromCharCode(((u0 & 0x1F) << 6) + (u1 & 0x3F)); + } else if (u0 <= 0xEF) { + /* three byte sequence */ + if (i+1 >= to) throw RangeError("cannot convert invalid utf8 to javascript string"); + let u1 = value[i++]; + if ((u1&0xC0) !== 0x80) throw RangeError("cannot convert invalid utf8 to javascript string"); + let u2 = value[i++]; + if ((u2&0xC0) !== 0x80) throw RangeError("cannot convert invalid utf8 to javascript string"); + let u = ((u0 & 0x0F) << 12) + ((u1 & 0x3F) << 6) + (u2 & 0x3F); + if (u <= 0xFFFF) { /* BMP codepoint */ + str += String.fromCharCode(u); + } else { /* Astral codepoint */ + u -= 0x10000; + let s1 = (u >> 10) + 0xD800; + let s2 = (u % 0x400) + 0xDC00; + str += String.fromCharCode(s1, s2); + } + } else { + /* four byte sequence */ + if (i+2 >= to) throw RangeError("cannot convert invalid utf8 to javascript string"); + let u1 = value[i++]; + if ((u1&0xC0) !== 0x80) throw RangeError("cannot convert invalid utf8 to javascript string"); + let u2 = value[i++]; + if ((u2&0xC0) !== 0x80) throw RangeError("cannot convert invalid utf8 to javascript string"); + let u3 = value[i++]; + if ((u3&0xC0) !== 0x80) throw RangeError("cannot convert invalid utf8 to javascript string"); + /* Has to be astral codepoint */ + let u = ((u0 & 0x07) << 18) + ((u1 & 0x3F) << 12) + ((u2 & 0x3F) << 6) + (u3 & 0x3F); + u -= 0x10000; + let s1 = (u >> 10) + 0xD800; + let s2 = (u % 0x400) + 0xDC00; + str += String.fromCharCode(s1, s2); + } + } + return str; +}; + +/* bytes allowed unescaped in a uri */ +const uri_allowed = (";,/?:@&=+$abcdefghijklmnopqrstuvwxyzABCDEFGHIJKLMNOPQRSTUVWXYZ0123456789,-_.!~*'()#").split('').reduce(function(uri_allowed, c) { + uri_allowed[c.charCodeAt(0)] = true; + return uri_allowed; +}, {}); + +/* utility function to convert a lua string to a js string with uri escaping */ +const to_uristring = function(a) { + if (!is_luastring(a)) throw new TypeError("to_uristring expects a Uint8Array"); + let s = ""; + for (let i=0; i<a.length; i++) { + let v = a[i]; + if (uri_allowed[v]) { + s += String.fromCharCode(v); + } else { + s += "%" + (v<0x10?"0":"") + v.toString(16); + } + } + return s; +}; + +const to_luastring_cache = {}; + +const to_luastring = function(str, cache) { + if (typeof str !== "string") throw new TypeError("to_luastring expects a javascript string"); + + if (cache) { + let cached = to_luastring_cache[str]; + if (is_luastring(cached)) return cached; + } + + let len = str.length; + let outU8Array = Array(len); /* array is at *least* going to be length of string */ + let outIdx = 0; + for (let i = 0; i < len; ++i) { + let u = str.charCodeAt(i); + if (u <= 0x7F) { + outU8Array[outIdx++] = u; + } else if (u <= 0x7FF) { + outU8Array[outIdx++] = 0xC0 | (u >> 6); + outU8Array[outIdx++] = 0x80 | (u & 63); + } else { + /* This part is to work around possible lack of String.codePointAt */ + if (u >= 0xD800 && u <= 0xDBFF && (i+1) < len) { + /* is first half of surrogate pair */ + let v = str.charCodeAt(i+1); + if (v >= 0xDC00 && v <= 0xDFFF) { + /* is valid low surrogate */ + i++; + u = (u - 0xD800) * 0x400 + v + 0x2400; + } + } + if (u <= 0xFFFF) { + outU8Array[outIdx++] = 0xE0 | (u >> 12); + outU8Array[outIdx++] = 0x80 | ((u >> 6) & 63); + outU8Array[outIdx++] = 0x80 | (u & 63); + } else { + outU8Array[outIdx++] = 0xF0 | (u >> 18); + outU8Array[outIdx++] = 0x80 | ((u >> 12) & 63); + outU8Array[outIdx++] = 0x80 | ((u >> 6) & 63); + outU8Array[outIdx++] = 0x80 | (u & 63); + } + } + } + outU8Array = luastring_from(outU8Array); + + if (cache) to_luastring_cache[str] = outU8Array; + + return outU8Array; +}; + +const from_userstring = function(str) { + if (!is_luastring(str)) throw new TypeError("expects an array of bytes"); + return str; +}; /* mark for precompiled code ('<esc>Lua') */ -const LUA_SIGNATURE = "\x1bLua"; +const LUA_SIGNATURE = to_luastring("\x1bLua"); const LUA_VERSION_MAJOR = "5"; const LUA_VERSION_MINOR = "3"; @@ -22,16 +206,6 @@ const LUA_RELEASE = LUA_VERSION + "." + LUA_VERSION_RELEASE; const LUA_COPYRIGHT = LUA_RELEASE + " Copyright (C) 1994-2017 Lua.org, PUC-Rio"; const LUA_AUTHORS = "R. Ierusalimschy, L. H. de Figueiredo, W. Celes"; -const FENGARI_VERSION_MAJOR = "0"; -const FENGARI_VERSION_MINOR = "0"; -const FENGARI_VERSION_NUM = 1; -const FENGARI_VERSION_RELEASE = "1"; - -const FENGARI_VERSION = "Fengari " + FENGARI_VERSION_MAJOR + "." + FENGARI_VERSION_MINOR; -const FENGARI_RELEASE = FENGARI_VERSION + "." + FENGARI_VERSION_RELEASE; -const FENGARI_AUTHORS = "B. Giannangeli, Daurnimator"; -const FENGARI_COPYRIGHT = FENGARI_RELEASE + " Copyright (C) 2017 " + FENGARI_AUTHORS + "\nBased on: " + LUA_COPYRIGHT; - const LUA_VERSUFFIX = "_" + LUA_VERSION_MAJOR + "_" + LUA_VERSION_MINOR; const LUA_INIT_VAR = "LUA_INIT"; @@ -71,8 +245,6 @@ constant_types.LUA_TLCL = constant_types.LUA_TFUNCTION | (0 << 4); /* Lua closu constant_types.LUA_TLCF = constant_types.LUA_TFUNCTION | (1 << 4); /* light C function */ constant_types.LUA_TCCL = constant_types.LUA_TFUNCTION | (2 << 4); /* C closure */ -const CT = constant_types; - /* ** Comparison and arithmetic functions */ @@ -98,7 +270,7 @@ const LUA_OPLE = 2; const LUA_MINSTACK = 20; -const LUA_REGISTRYINDEX = -luaconf.LUAI_MAXSTACK - 1000; +const LUA_REGISTRYINDEX = -LUAI_MAXSTACK - 1000; const lua_upvalueindex = function(i) { return LUA_REGISTRYINDEX - i; @@ -110,7 +282,6 @@ const LUA_RIDX_GLOBALS = 2; const LUA_RIDX_LAST = LUA_RIDX_GLOBALS; class lua_Debug { - constructor() { this.event = NaN; this.name = null; /* (n) */ @@ -128,130 +299,8 @@ class lua_Debug { /* private part */ this.i_ci = null; /* active function */ } - -} - -const string_of = Uint8Array.of.bind(Uint8Array); - -const is_luastring = function(s) { - return s instanceof Uint8Array; -}; - -/* test two lua strings for equality */ -const luastring_cmp = function(a, b) { - return a === b || (a.length === b.length && a.join() === b.join()); -}; - -const to_jsstring = function(value, from, to) { - assert(is_luastring(value), "jsstring expects a Uint8Array"); - - if (to === void 0) { - to = value.length; - } else { - to = Math.min(value.length, to); - } - - let str = ""; - for (let i = (from!==void 0?from:0); i < to;) { - let u; - let u0 = value[i++]; - if (u0 < 0x80) { - /* single byte sequence */ - u = u0; - } else if (u0 < 0xC2 || u0 > 0xF4) { - throw RangeError("cannot convert invalid utf8 to javascript string"); - } else if (u0 <= 0xDF) { - /* two byte sequence */ - if (i >= to) throw RangeError("cannot convert invalid utf8 to javascript string"); - let u1 = value[i++]; - if ((u1&0xC0) !== 0x80) throw RangeError("cannot convert invalid utf8 to javascript string"); - u = ((u0 & 0x1F) << 6) + (u1 & 0x3F); - } else if (u0 <= 0xEF) { - /* three byte sequence */ - if (i+1 >= to) throw RangeError("cannot convert invalid utf8 to javascript string"); - let u1 = value[i++]; - if ((u1&0xC0) !== 0x80) throw RangeError("cannot convert invalid utf8 to javascript string"); - let u2 = value[i++]; - if ((u2&0xC0) !== 0x80) throw RangeError("cannot convert invalid utf8 to javascript string"); - u = ((u0 & 0x0F) << 12) + ((u1 & 0x3F) << 6) + (u2 & 0x3F); - } else { - /* four byte sequence */ - if (i+2 >= to) throw RangeError("cannot convert invalid utf8 to javascript string"); - let u1 = value[i++]; - if ((u1&0xC0) !== 0x80) throw RangeError("cannot convert invalid utf8 to javascript string"); - let u2 = value[i++]; - if ((u2&0xC0) !== 0x80) throw RangeError("cannot convert invalid utf8 to javascript string"); - let u3 = value[i++]; - if ((u3&0xC0) !== 0x80) throw RangeError("cannot convert invalid utf8 to javascript string"); - u = ((u0 & 0x07) << 18) + ((u1 & 0x3F) << 12) + ((u2 & 0x3F) << 6) + (u3 & 0x3F); - } - str += String.fromCodePoint(u); - } - return str; -}; - -const uri_allowed = {}; /* bytes allowed unescaped in a uri */ -for (let c of ";,/?:@&=+$abcdefghijklmnopqrstuvwxyzABCDEFGHIJKLMNOPQRSTUVWXYZ0123456789,-_.!~*'()#") { - uri_allowed[c.charCodeAt(0)] = true; } -/* utility function to convert a lua string to a js string with uri escaping */ -const to_uristring = function(a) { - let s = ""; - for (let i=0; i<a.length; i++) { - let v = a[i]; - if (uri_allowed[v]) { - s += String.fromCharCode(v); - } else { - s += "%" + (v<0x10?"0":"") + v.toString(16); - } - } - return s; -}; - -const to_luastring_cache = {}; - -const to_luastring = function(str, cache) { - assert(typeof str === "string", "to_luastring expects a javascript string"); - - if (cache) { - let cached = to_luastring_cache[str]; - if (is_luastring(cached)) return cached; - } - - let outU8Array = Array(str.length); /* array is at *least* going to be length of string */ - let outIdx = 0; - for (let i = 0; i < str.length; ++i) { - let u = str.codePointAt(i); - if (u <= 0x7F) { - outU8Array[outIdx++] = u; - } else if (u <= 0x7FF) { - outU8Array[outIdx++] = 0xC0 | (u >> 6); - outU8Array[outIdx++] = 0x80 | (u & 63); - } else if (u <= 0xFFFF) { - outU8Array[outIdx++] = 0xE0 | (u >> 12); - outU8Array[outIdx++] = 0x80 | ((u >> 6) & 63); - outU8Array[outIdx++] = 0x80 | (u & 63); - } else { - i++; /* It was a surrogate pair and hence used up two javascript chars */ - outU8Array[outIdx++] = 0xF0 | (u >> 18); - outU8Array[outIdx++] = 0x80 | ((u >> 12) & 63); - outU8Array[outIdx++] = 0x80 | ((u >> 6) & 63); - outU8Array[outIdx++] = 0x80 | (u & 63); - } - } - outU8Array = Uint8Array.from(outU8Array); - - if (cache) to_luastring_cache[str] = outU8Array; - - return outU8Array; -}; - -const from_userstring = function(str) { - assert(is_luastring(str), "expects an array of bytes"); - return str; -}; - /* ** Event codes */ @@ -309,14 +358,16 @@ if (typeof process === "undefined") { const LUA_CDIR = "./lua/" + LUA_VDIR + "/"; module.exports.LUA_CDIR = LUA_CDIR; - const LUA_PATH_DEFAULT = + const LUA_PATH_DEFAULT = to_luastring( LUA_LDIR + "?.lua;" + LUA_LDIR + "?/init.lua;" + LUA_CDIR + "?.lua;" + LUA_CDIR + "?/init.lua;" + - "./?.lua;./?/init.lua"; + "./?.lua;./?/init.lua" + ); module.exports.LUA_PATH_DEFAULT = LUA_PATH_DEFAULT; - const LUA_CPATH_DEFAULT = - LUA_CDIR + "?.js;" + LUA_CDIR + "loadall.js;./?.js"; + const LUA_CPATH_DEFAULT = to_luastring( + LUA_CDIR + "?.js;" + LUA_CDIR + "loadall.js;./?.js" + ); module.exports.LUA_CPATH_DEFAULT = LUA_CPATH_DEFAULT; } else if (require('os').platform() === 'win32') { const LUA_DIRSEP = "\\"; @@ -335,17 +386,19 @@ if (typeof process === "undefined") { const LUA_SHRDIR = "!\\..\\share\\lua\\" + LUA_VDIR + "\\"; module.exports.LUA_SHRDIR = LUA_SHRDIR; - const LUA_PATH_DEFAULT = + const LUA_PATH_DEFAULT = to_luastring( LUA_LDIR + "?.lua;" + LUA_LDIR + "?\\init.lua;" + LUA_CDIR + "?.lua;" + LUA_CDIR + "?\\init.lua;" + LUA_SHRDIR + "?.lua;" + LUA_SHRDIR + "?\\init.lua;" + - ".\\?.lua;.\\?\\init.lua"; + ".\\?.lua;.\\?\\init.lua" + ); module.exports.LUA_PATH_DEFAULT = LUA_PATH_DEFAULT; - const LUA_CPATH_DEFAULT = + const LUA_CPATH_DEFAULT = to_luastring( LUA_CDIR + "?.dll;" + LUA_CDIR + "..\\lib\\lua\\" + LUA_VDIR + "\\?.dll;" + - LUA_CDIR + "loadall.dll;.\\?.dll"; + LUA_CDIR + "loadall.dll;.\\?.dll" + ); module.exports.LUA_CPATH_DEFAULT = LUA_CPATH_DEFAULT; } else { const LUA_DIRSEP = "/"; @@ -360,26 +413,19 @@ if (typeof process === "undefined") { const LUA_CDIR = LUA_ROOT + "lib/lua/" + LUA_VDIR + "/"; module.exports.LUA_CDIR = LUA_CDIR; - const LUA_PATH_DEFAULT = + const LUA_PATH_DEFAULT = to_luastring( LUA_LDIR + "?.lua;" + LUA_LDIR + "?/init.lua;" + LUA_CDIR + "?.lua;" + LUA_CDIR + "?/init.lua;" + - "./?.lua;./?/init.lua"; + "./?.lua;./?/init.lua" + ); module.exports.LUA_PATH_DEFAULT = LUA_PATH_DEFAULT; - const LUA_CPATH_DEFAULT = - LUA_CDIR + "?.so;" + LUA_CDIR + "loadall.so;./?.so"; + const LUA_CPATH_DEFAULT = to_luastring( + LUA_CDIR + "?.so;" + LUA_CDIR + "loadall.so;./?.so" + ); module.exports.LUA_CPATH_DEFAULT = LUA_CPATH_DEFAULT; } -module.exports.CT = CT; -module.exports.FENGARI_AUTHORS = FENGARI_AUTHORS; -module.exports.FENGARI_COPYRIGHT = FENGARI_COPYRIGHT; -module.exports.FENGARI_RELEASE = FENGARI_RELEASE; -module.exports.FENGARI_VERSION = FENGARI_VERSION; -module.exports.FENGARI_VERSION_MAJOR = FENGARI_VERSION_MAJOR; -module.exports.FENGARI_VERSION_MINOR = FENGARI_VERSION_MINOR; -module.exports.FENGARI_VERSION_NUM = FENGARI_VERSION_NUM; -module.exports.FENGARI_VERSION_RELEASE = FENGARI_VERSION_RELEASE; module.exports.LUA_AUTHORS = LUA_AUTHORS; module.exports.LUA_COPYRIGHT = LUA_COPYRIGHT; module.exports.LUA_HOOKCALL = LUA_HOOKCALL; @@ -429,8 +475,10 @@ module.exports.lua_Debug = lua_Debug; module.exports.lua_upvalueindex = lua_upvalueindex; module.exports.thread_status = thread_status; module.exports.is_luastring = is_luastring; -module.exports.luastring_cmp = luastring_cmp; -module.exports.string_of = string_of; +module.exports.luastring_eq = luastring_eq; +module.exports.luastring_from = luastring_from; +module.exports.luastring_indexOf = luastring_indexOf; +module.exports.luastring_of = luastring_of; module.exports.to_jsstring = to_jsstring; module.exports.to_luastring = to_luastring; module.exports.to_uristring = to_uristring; diff --git a/src/fengari.js b/src/fengari.js index 3d35334..b37f7d6 100644 --- a/src/fengari.js +++ b/src/fengari.js @@ -1,5 +1,23 @@ "use strict"; +const core = require("./fengaricore.js"); + +module.exports.FENGARI_AUTHORS = core.FENGARI_AUTHORS; +module.exports.FENGARI_COPYRIGHT = core.FENGARI_COPYRIGHT; +module.exports.FENGARI_RELEASE = core.FENGARI_RELEASE; +module.exports.FENGARI_VERSION = core.FENGARI_VERSION; +module.exports.FENGARI_VERSION_MAJOR = core.FENGARI_VERSION_MAJOR; +module.exports.FENGARI_VERSION_MINOR = core.FENGARI_VERSION_MINOR; +module.exports.FENGARI_VERSION_NUM = core.FENGARI_VERSION_NUM; +module.exports.FENGARI_VERSION_RELEASE = core.FENGARI_VERSION_RELEASE; + +module.exports.luastring_eq = core.luastring_eq; +module.exports.luastring_indexOf = core.luastring_indexOf; +module.exports.luastring_of = core.luastring_of; +module.exports.to_jsstring = core.to_jsstring; +module.exports.to_luastring = core.to_luastring; +module.exports.to_uristring = core.to_uristring; + const lua = require('./lua.js'); const lauxlib = require('./lauxlib.js'); const lualib = require('./lualib.js'); diff --git a/src/fengaricore.js b/src/fengaricore.js new file mode 100644 index 0000000..1fd0354 --- /dev/null +++ b/src/fengaricore.js @@ -0,0 +1,36 @@ +/* Fengari specific functions + * + * This file includes fengari-specific data or and functionality for users to + * manipulate fengari's string type. + * The fields are exposed to the user on the 'fengari' entry point; however to + * avoid a dependency on defs.js from lauxlib.js they are defined in this file. + */ + +const defs = require("./defs.js"); + +const FENGARI_VERSION_MAJOR = "0"; +const FENGARI_VERSION_MINOR = "0"; +const FENGARI_VERSION_NUM = 1; +const FENGARI_VERSION_RELEASE = "1"; +const FENGARI_VERSION = "Fengari " + FENGARI_VERSION_MAJOR + "." + FENGARI_VERSION_MINOR; +const FENGARI_RELEASE = FENGARI_VERSION + "." + FENGARI_VERSION_RELEASE; +const FENGARI_AUTHORS = "B. Giannangeli, Daurnimator"; +const FENGARI_COPYRIGHT = FENGARI_RELEASE + " Copyright (C) 2017-2018 " + FENGARI_AUTHORS + "\nBased on: " + defs.LUA_COPYRIGHT; + +module.exports.FENGARI_AUTHORS = FENGARI_AUTHORS; +module.exports.FENGARI_COPYRIGHT = FENGARI_COPYRIGHT; +module.exports.FENGARI_RELEASE = FENGARI_RELEASE; +module.exports.FENGARI_VERSION = FENGARI_VERSION; +module.exports.FENGARI_VERSION_MAJOR = FENGARI_VERSION_MAJOR; +module.exports.FENGARI_VERSION_MINOR = FENGARI_VERSION_MINOR; +module.exports.FENGARI_VERSION_NUM = FENGARI_VERSION_NUM; +module.exports.FENGARI_VERSION_RELEASE = FENGARI_VERSION_RELEASE; +module.exports.is_luastring = defs.is_luastring; +module.exports.luastring_eq = defs.luastring_eq; +module.exports.luastring_from = defs.luastring_from; +module.exports.luastring_indexOf = defs.luastring_indexOf; +module.exports.luastring_of = defs.luastring_of; +module.exports.to_jsstring = defs.to_jsstring; +module.exports.to_luastring = defs.to_luastring; +module.exports.to_uristring = defs.to_uristring; +module.exports.from_userstring = defs.from_userstring; diff --git a/src/lapi.js b/src/lapi.js index b42ad92..6196812 100644 --- a/src/lapi.js +++ b/src/lapi.js @@ -1,32 +1,76 @@ "use strict"; -const assert = require('assert'); - -const defs = require('./defs.js'); +const { + LUA_MULTRET, + LUA_OPBNOT, + LUA_OPEQ, + LUA_OPLE, + LUA_OPLT, + LUA_OPUNM, + LUA_REGISTRYINDEX, + LUA_RIDX_GLOBALS, + LUA_VERSION_NUM, + constant_types: { + LUA_NUMTAGS, + LUA_TBOOLEAN, + LUA_TCCL, + LUA_TFUNCTION, + LUA_TLCF, + LUA_TLCL, + LUA_TLIGHTUSERDATA, + LUA_TLNGSTR, + LUA_TNIL, + LUA_TNONE, + LUA_TNUMFLT, + LUA_TNUMINT, + LUA_TSHRSTR, + LUA_TTABLE, + LUA_TTHREAD, + LUA_TUSERDATA + }, + thread_status: { LUA_OK }, + from_userstring, + to_luastring, +} = require('./defs.js'); +const { api_check } = require('./llimits.js'); const ldebug = require('./ldebug.js'); const ldo = require('./ldo.js'); -const ldump = require('./ldump.js'); +const { luaU_dump } = require('./ldump.js'); const lfunc = require('./lfunc.js'); const lobject = require('./lobject.js'); const lstate = require('./lstate.js'); -const lstring = require('./lstring.js'); +const { + luaS_bless, + luaS_new, + luaS_newliteral +} = require('./lstring.js'); const ltm = require('./ltm.js'); -const luaconf = require('./luaconf.js'); +const { LUAI_MAXSTACK } = require('./luaconf.js'); const lvm = require('./lvm.js'); const ltable = require('./ltable.js'); -const lzio = require('./lzio.js'); -const MAXUPVAL = lfunc.MAXUPVAL; -const CT = defs.constant_types; -const TS = defs.thread_status; +const { ZIO } = require('./lzio.js'); const TValue = lobject.TValue; const CClosure = lobject.CClosure; +const api_incr_top = function(L) { + L.top++; + api_check(L, L.top <= L.ci.top, "stack overflow"); +}; + +const api_checknelems = function(L, n) { + api_check(L, n < (L.top - L.ci.funcOff), "not enough elements in the stack"); +}; + +const fengari_argcheck = function(c) { + if (!c) throw TypeError("invalid argument"); +}; + const isvalid = function(o) { return o !== lobject.luaO_nilobject; }; const lua_version = function(L) { - if (L === null) return defs.LUA_VERSION_NUM; + if (L === null) return LUA_VERSION_NUM; else return L.l_G.version; }; @@ -47,17 +91,17 @@ const index2addr = function(L, idx) { let ci = L.ci; if (idx > 0) { let o = ci.funcOff + idx; - assert(idx <= ci.top - (ci.funcOff + 1), "unacceptable index"); + api_check(L, idx <= ci.top - (ci.funcOff + 1), "unacceptable index"); if (o >= L.top) return lobject.luaO_nilobject; else return L.stack[o]; - } else if (idx > defs.LUA_REGISTRYINDEX) { - assert(idx !== 0 && -idx <= L.top, "invalid index"); + } else if (idx > LUA_REGISTRYINDEX) { + api_check(L, idx !== 0 && -idx <= L.top, "invalid index"); return L.stack[L.top + idx]; - } else if (idx === defs.LUA_REGISTRYINDEX) { + } else if (idx === LUA_REGISTRYINDEX) { return L.l_G.l_registry; } else { /* upvalues */ - idx = defs.LUA_REGISTRYINDEX - idx; - assert(idx <= MAXUPVAL + 1, "upvalue index too large"); + idx = LUA_REGISTRYINDEX - idx; + api_check(L, idx <= lfunc.MAXUPVAL + 1, "upvalue index too large"); if (ci.func.ttislcf()) /* light C function? */ return lobject.luaO_nilobject; /* it has no upvalues */ else { @@ -71,11 +115,11 @@ const index2addr_ = function(L, idx) { let ci = L.ci; if (idx > 0) { let o = ci.funcOff + idx; - assert(idx <= ci.top - (ci.funcOff + 1), "unacceptable index"); + api_check(L, idx <= ci.top - (ci.funcOff + 1), "unacceptable index"); if (o >= L.top) return null; else return o; - } else if (idx > defs.LUA_REGISTRYINDEX) { - assert(idx !== 0 && -idx <= L.top, "invalid index"); + } else if (idx > LUA_REGISTRYINDEX) { + api_check(L, idx !== 0 && -idx <= L.top, "invalid index"); return L.top + idx; } else { /* registry or upvalue */ throw Error("attempt to use pseudo-index"); @@ -85,12 +129,12 @@ const index2addr_ = function(L, idx) { const lua_checkstack = function(L, n) { let res; let ci = L.ci; - assert(n >= 0, "negative 'n'"); + api_check(L, n >= 0, "negative 'n'"); if (L.stack_last - L.top > n) /* stack large enough? */ res = true; else { /* no; need to grow stack */ let inuse = L.top + lstate.EXTRA_STACK; - if (inuse > luaconf.LUAI_MAXSTACK - n) /* can grow without overflow? */ + if (inuse > LUAI_MAXSTACK - n) /* can grow without overflow? */ res = false; /* no */ else { /* try to grow stack */ ldo.luaD_growstack(L, n); @@ -106,10 +150,9 @@ const lua_checkstack = function(L, n) { const lua_xmove = function(from, to, n) { if (from === to) return; - assert(n < (from.top - from.ci.funcOff), "not enough elements in the stack"); - assert(from.l_G === to.l_G, "moving among independent states"); - assert(to.ci.top - to.top >= n, "stack overflow"); - + api_checknelems(from, n); + api_check(from, from.l_G === to.l_G, "moving among independent states"); + api_check(from, to.ci.top - to.top >= n, "stack overflow"); from.top -= n; for (let i = 0; i < n; i++) { to.stack[to.top] = new lobject.TValue(); @@ -127,7 +170,7 @@ const lua_xmove = function(from, to, n) { ** convert an acceptable stack index into an absolute index */ const lua_absindex = function(L, idx) { - return (idx > 0 || idx <= defs.LUA_REGISTRYINDEX) + return (idx > 0 || idx <= LUA_REGISTRYINDEX) ? idx : (L.top - L.ci.funcOff) + idx; }; @@ -138,17 +181,17 @@ const lua_gettop = function(L) { const lua_pushvalue = function(L, idx) { lobject.pushobj2s(L, index2addr(L, idx)); - assert(L.top <= L.ci.top, "stack overflow"); + api_check(L, L.top <= L.ci.top, "stack overflow"); }; const lua_settop = function(L, idx) { let func = L.ci.funcOff; let newtop; if (idx >= 0) { - assert(idx <= L.stack_last - (func + 1), "new top too large"); + api_check(L, idx <= L.stack_last - (func + 1), "new top too large"); newtop = func + 1 + idx; } else { - assert(-(idx + 1) <= L.top - (func + 1), "invalid new top"); + api_check(L, -(idx + 1) <= L.top - (func + 1), "invalid new top"); newtop = L.top + idx + 1; /* 'subtract' index (index is negative) */ } ldo.adjust_top(L, newtop); @@ -175,12 +218,9 @@ const lua_rotate = function(L, idx, n) { let t = L.top - 1; let pIdx = index2addr_(L, idx); let p = L.stack[pIdx]; - - assert(isvalid(p) && idx > defs.LUA_REGISTRYINDEX, "index not in the stack"); - assert((n >= 0 ? n : -n) <= (t - pIdx + 1), "invalid 'n'"); - + api_check(L, isvalid(p) && idx > LUA_REGISTRYINDEX, "index not in the stack"); + api_check(L, (n >= 0 ? n : -n) <= (t - pIdx + 1), "invalid 'n'"); let m = n >= 0 ? t - n : pIdx - n - 1; /* end of prefix */ - reverse(L, pIdx, m); reverse(L, m + 1, L.top - 1); reverse(L, pIdx, L.top - 1); @@ -210,93 +250,84 @@ const lua_replace = function(L, idx) { */ const lua_pushnil = function(L) { - L.stack[L.top] = new TValue(CT.LUA_TNIL, null); - L.top++; - assert(L.top <= L.ci.top, "stack overflow"); + L.stack[L.top] = new TValue(LUA_TNIL, null); + api_incr_top(L); }; const lua_pushnumber = function(L, n) { - assert(typeof n === "number"); - - L.stack[L.top] = new TValue(CT.LUA_TNUMFLT, n); - L.top++; - assert(L.top <= L.ci.top, "stack overflow"); + fengari_argcheck(typeof n === "number"); + L.stack[L.top] = new TValue(LUA_TNUMFLT, n); + api_incr_top(L); }; const lua_pushinteger = function(L, n) { - assert(typeof n === "number" && (n|0) === n); - L.stack[L.top] = new TValue(CT.LUA_TNUMINT, n); - L.top++; - assert(L.top <= L.ci.top, "stack overflow"); + fengari_argcheck(typeof n === "number" && (n|0) === n); + L.stack[L.top] = new TValue(LUA_TNUMINT, n); + api_incr_top(L); }; const lua_pushlstring = function(L, s, len) { - assert(typeof len === "number"); + fengari_argcheck(typeof len === "number"); let ts; if (len === 0) { - s = defs.to_luastring("", true); + s = to_luastring("", true); + ts = luaS_bless(L, s); } else { - s = defs.from_userstring(s); - assert(s.length >= len, "invalid length to lua_pushlstring"); - s = s.slice(0, len); + s = from_userstring(s); + api_check(L, s.length >= len, "invalid length to lua_pushlstring"); + ts = luaS_new(L, s.subarray(0, len)); } - ts = lstring.luaS_bless(L, s); lobject.pushsvalue2s(L, ts); - assert(L.top <= L.ci.top, "stack overflow"); - + api_check(L, L.top <= L.ci.top, "stack overflow"); return ts.value; }; const lua_pushstring = function (L, s) { if (s === undefined || s === null) { - L.stack[L.top] = new TValue(CT.LUA_TNIL, null); + L.stack[L.top] = new TValue(LUA_TNIL, null); L.top++; } else { - let ts = lstring.luaS_new(L, defs.from_userstring(s)); + let ts = luaS_new(L, from_userstring(s)); lobject.pushsvalue2s(L, ts); s = ts.getstr(); /* internal copy */ } - assert(L.top <= L.ci.top, "stack overflow"); - + api_check(L, L.top <= L.ci.top, "stack overflow"); return s; }; const lua_pushvfstring = function (L, fmt, argp) { - fmt = defs.from_userstring(fmt); + fmt = from_userstring(fmt); return lobject.luaO_pushvfstring(L, fmt, argp); }; const lua_pushfstring = function (L, fmt, ...argp) { - fmt = defs.from_userstring(fmt); + fmt = from_userstring(fmt); return lobject.luaO_pushvfstring(L, fmt, argp); }; /* Similar to lua_pushstring, but takes a JS string */ const lua_pushliteral = function (L, s) { if (s === undefined || s === null) { - L.stack[L.top] = new TValue(CT.LUA_TNIL, null); + L.stack[L.top] = new TValue(LUA_TNIL, null); L.top++; } else { - assert(typeof s === "string", "lua_pushliteral expects a JS string"); - let ts = lstring.luaS_newliteral(L, s); + fengari_argcheck(typeof s === "string", "lua_pushliteral expects a JS string"); + let ts = luaS_newliteral(L, s); lobject.pushsvalue2s(L, ts); s = ts.getstr(); /* internal copy */ } - assert(L.top <= L.ci.top, "stack overflow"); + api_check(L, L.top <= L.ci.top, "stack overflow"); return s; }; const lua_pushcclosure = function(L, fn, n) { - assert(typeof fn === "function"); - assert(typeof n === "number"); - + fengari_argcheck(typeof fn === "function" || typeof n === "number"); if (n === 0) - L.stack[L.top] = new TValue(CT.LUA_TLCF, fn); + L.stack[L.top] = new TValue(LUA_TLCF, fn); else { - assert(n < L.top - L.ci.funcOff, "not enough elements in the stack"); - assert(n <= MAXUPVAL, "upvalue index too large"); - + api_checknelems(L, n); + api_check(L, n <= lfunc.MAXUPVAL, "upvalue index too large"); let cl = new CClosure(L, fn, n); for (let i=0; i<n; i++) cl.upvalue[i].setfrom(L.stack[L.top - n + i]); @@ -306,8 +337,7 @@ const lua_pushcclosure = function(L, fn, n) { --L.top; L.stack[L.top].setclCvalue(cl); } - L.top++; - assert(L.top <= L.ci.top, "stack overflow"); + api_incr_top(L); }; const lua_pushjsclosure = lua_pushcclosure; @@ -319,26 +349,23 @@ const lua_pushcfunction = function(L, fn) { const lua_pushjsfunction = lua_pushcfunction; const lua_pushboolean = function(L, b) { - L.stack[L.top] = new TValue(CT.LUA_TBOOLEAN, b ? true : false); - L.top++; - assert(L.top <= L.ci.top, "stack overflow"); + L.stack[L.top] = new TValue(LUA_TBOOLEAN, b ? true : false); + api_incr_top(L); }; const lua_pushlightuserdata = function(L, p) { - L.stack[L.top] = new TValue(CT.LUA_TLIGHTUSERDATA, p); - L.top++; - assert(L.top <= L.ci.top, "stack overflow"); + L.stack[L.top] = new TValue(LUA_TLIGHTUSERDATA, p); + api_incr_top(L); }; const lua_pushthread = function(L) { - L.stack[L.top] = new TValue(CT.LUA_TTHREAD, L); - L.top++; - assert(L.top <= L.ci.top, "stack overflow"); + L.stack[L.top] = new TValue(LUA_TTHREAD, L); + api_incr_top(L); return L.l_G.mainthread === L; }; const lua_pushglobaltable = function(L) { - lua_rawgeti(L, defs.LUA_REGISTRYINDEX, defs.LUA_RIDX_GLOBALS); + lua_rawgeti(L, LUA_REGISTRYINDEX, LUA_RIDX_GLOBALS); }; /* @@ -349,10 +376,10 @@ const lua_pushglobaltable = function(L) { ** t[k] = value at the top of the stack (where 'k' is a string) */ const auxsetstr = function(L, t, k) { - let str = lstring.luaS_new(L, defs.from_userstring(k)); - assert(1 < L.top - L.ci.funcOff, "not enough elements in the stack"); + let str = luaS_new(L, from_userstring(k)); + api_checknelems(L, 1); lobject.pushsvalue2s(L, str); /* push 'str' (to make it a TValue) */ - assert(L.top <= L.ci.top, "stack overflow"); + api_check(L, L.top <= L.ci.top, "stack overflow"); lvm.settable(L, t, L.stack[L.top - 1], L.stack[L.top - 2]); /* pop value and key */ delete L.stack[--L.top]; @@ -360,23 +387,23 @@ const auxsetstr = function(L, t, k) { }; const lua_setglobal = function(L, name) { - auxsetstr(L, ltable.luaH_getint(L.l_G.l_registry.value, defs.LUA_RIDX_GLOBALS), name); + auxsetstr(L, ltable.luaH_getint(L.l_G.l_registry.value, LUA_RIDX_GLOBALS), name); }; const lua_setmetatable = function(L, objindex) { - assert(1 < L.top - L.ci.funcOff, "not enough elements in the stack"); + api_checknelems(L, 1); let mt; let obj = index2addr(L, objindex); if (L.stack[L.top - 1].ttisnil()) mt = null; else { - assert(L.stack[L.top - 1].ttistable(), "table expected"); + api_check(L, L.stack[L.top - 1].ttistable(), "table expected"); mt = L.stack[L.top - 1].value; } switch (obj.ttnov()) { - case CT.LUA_TUSERDATA: - case CT.LUA_TTABLE: { + case LUA_TUSERDATA: + case LUA_TTABLE: { obj.value.metatable = mt; break; } @@ -391,8 +418,7 @@ const lua_setmetatable = function(L, objindex) { }; const lua_settable = function(L, idx) { - assert(2 < L.top - L.ci.funcOff, "not enough elements in the stack"); - + api_checknelems(L, 2); let t = index2addr(L, idx); lvm.settable(L, t, L.stack[L.top - 2], L.stack[L.top - 1]); delete L.stack[--L.top]; @@ -404,12 +430,11 @@ const lua_setfield = function(L, idx, k) { }; const lua_seti = function(L, idx, n) { - assert(typeof n === "number" && (n|0) === n); - assert(1 < L.top - L.ci.funcOff, "not enough elements in the stack"); + fengari_argcheck(typeof n === "number" && (n|0) === n); + api_checknelems(L, 1); let t = index2addr(L, idx); - L.stack[L.top] = new TValue(CT.LUA_TNUMINT, n); - L.top++; - assert(L.top <= L.ci.top, "stack overflow"); + L.stack[L.top] = new TValue(LUA_TNUMINT, n); + api_incr_top(L); lvm.settable(L, t, L.stack[L.top - 1], L.stack[L.top - 2]); /* pop value and key */ delete L.stack[--L.top]; @@ -417,9 +442,9 @@ const lua_seti = function(L, idx, n) { }; const lua_rawset = function(L, idx) { - assert(2 < L.top - L.ci.funcOff, "not enough elements in the stack"); + api_checknelems(L, 2); let o = index2addr(L, idx); - assert(o.ttistable(), "table expected"); + api_check(L, o.ttistable(), "table expected"); let k = L.stack[L.top - 2]; let v = L.stack[L.top - 1]; if (v.ttisnil()) { @@ -434,18 +459,18 @@ const lua_rawset = function(L, idx) { }; const lua_rawseti = function(L, idx, n) { - assert(1 < L.top - L.ci.funcOff, "not enough elements in the stack"); + api_checknelems(L, 1); let o = index2addr(L, idx); - assert(o.ttistable(), "table expected"); + api_check(L, o.ttistable(), "table expected"); ltable.luaH_setint(o.value, n, L.stack[L.top - 1]); delete L.stack[--L.top]; }; const lua_rawsetp = function(L, idx, p) { - assert(1 < L.top - L.ci.funcOff, "not enough elements in the stack"); + api_checknelems(L, 1); let o = index2addr(L, idx); - assert(L, o.ttistable(), "table expected"); - let k = new TValue(CT.LUA_TLIGHTUSERDATA, p); + api_check(L, o.ttistable(), "table expected"); + let k = new TValue(LUA_TLIGHTUSERDATA, p); let v = L.stack[L.top - 1]; if (v.ttisnil()) { ltable.luaH_delete(L, o.value, k); @@ -461,43 +486,42 @@ const lua_rawsetp = function(L, idx, p) { */ const auxgetstr = function(L, t, k) { - let str = lstring.luaS_new(L, defs.from_userstring(k)); + let str = luaS_new(L, from_userstring(k)); lobject.pushsvalue2s(L, str); - assert(L.top <= L.ci.top, "stack overflow"); + api_check(L, L.top <= L.ci.top, "stack overflow"); lvm.luaV_gettable(L, t, L.stack[L.top - 1], L.top - 1); return L.stack[L.top - 1].ttnov(); }; const lua_rawgeti = function(L, idx, n) { let t = index2addr(L, idx); - assert(t.ttistable(), "table expected"); + api_check(L, t.ttistable(), "table expected"); lobject.pushobj2s(L, ltable.luaH_getint(t.value, n)); - assert(L.top <= L.ci.top, "stack overflow"); + api_check(L, L.top <= L.ci.top, "stack overflow"); return L.stack[L.top - 1].ttnov(); }; const lua_rawgetp = function(L, idx, p) { let t = index2addr(L, idx); - assert(t.ttistable(), "table expected"); - let k = new TValue(CT.LUA_TLIGHTUSERDATA, p); + api_check(L, t.ttistable(), "table expected"); + let k = new TValue(LUA_TLIGHTUSERDATA, p); lobject.pushobj2s(L, ltable.luaH_get(L, t.value, k)); - assert(L.top <= L.ci.top, "stack overflow"); + api_check(L, L.top <= L.ci.top, "stack overflow"); return L.stack[L.top - 1].ttnov(); }; const lua_rawget = function(L, idx) { let t = index2addr(L, idx); - assert(t.ttistable(t), "table expected"); + api_check(L, t.ttistable(t), "table expected"); lobject.setobj2s(L, L.top - 1, ltable.luaH_get(L, t.value, L.stack[L.top - 1])); return L.stack[L.top - 1].ttnov(); }; // narray and nrec are mostly useless for this implementation const lua_createtable = function(L, narray, nrec) { - let t = new lobject.TValue(CT.LUA_TTABLE, ltable.luaH_new(L)); + let t = new lobject.TValue(LUA_TTABLE, ltable.luaH_new(L)); L.stack[L.top] = t; - L.top++; - assert(L.top <= L.ci.top, "stack overflow"); + api_incr_top(L); }; const luaS_newudata = function(L, size) { @@ -506,30 +530,29 @@ const luaS_newudata = function(L, size) { const lua_newuserdata = function(L, size) { let u = luaS_newudata(L, size); - L.stack[L.top] = new lobject.TValue(CT.LUA_TUSERDATA, u); - L.top++; - assert(L.top <= L.ci.top, "stack overflow"); + L.stack[L.top] = new lobject.TValue(LUA_TUSERDATA, u); + api_incr_top(L); return u.data; }; const aux_upvalue = function(L, fi, n) { switch(fi.ttype()) { - case CT.LUA_TCCL: { /* C closure */ + case LUA_TCCL: { /* C closure */ let f = fi.value; if (!(1 <= n && n <= f.nupvalues)) return null; return { - name: defs.to_luastring("", true), + name: to_luastring("", true), val: f.upvalue[n-1] }; } - case CT.LUA_TLCL: { /* Lua closure */ + case LUA_TLCL: { /* Lua closure */ let f = fi.value; let p = f.p; if (!(1 <= n && n <= p.upvalues.length)) return null; let name = p.upvalues[n-1].name; return { - name: name ? name.getstr() : defs.to_luastring("(*no name)", true), - val: f.upvals[n-1].v + name: name ? name.getstr() : to_luastring("(*no name)", true), + val: f.upvals[n-1] }; } default: return null; /* not a closure */ @@ -542,7 +565,7 @@ const lua_getupvalue = function(L, funcindex, n) { let name = up.name; let val = up.val; lobject.pushobj2s(L, val); - assert(L.top <= L.ci.top, "stack overflow"); + api_check(L, L.top <= L.ci.top, "stack overflow"); return name; } return null; @@ -550,7 +573,7 @@ const lua_getupvalue = function(L, funcindex, n) { const lua_setupvalue = function(L, funcindex, n) { let fi = index2addr(L, funcindex); - assert(1 < L.top - L.ci.funcOff, "not enough elements in the stack"); + api_checknelems(L, 1); let aux = aux_upvalue(L, fi, n); if (aux) { let name = aux.name; @@ -576,8 +599,8 @@ const lua_getmetatable = function(L, objindex) { let mt; let res = false; switch (obj.ttnov()) { - case CT.LUA_TTABLE: - case CT.LUA_TUSERDATA: + case LUA_TTABLE: + case LUA_TUSERDATA: mt = obj.value.metatable; break; default: @@ -586,9 +609,8 @@ const lua_getmetatable = function(L, objindex) { } if (mt !== null && mt !== undefined) { - L.stack[L.top] = new TValue(CT.LUA_TTABLE, mt); - L.top++; - assert(L.top <= L.ci.top, "stack overflow"); + L.stack[L.top] = new TValue(LUA_TTABLE, mt); + api_incr_top(L); res = true; } @@ -597,11 +619,10 @@ const lua_getmetatable = function(L, objindex) { const lua_getuservalue = function(L, idx) { let o = index2addr(L, idx); - assert(L, o.ttisfulluserdata(), "full userdata expected"); + api_check(L, o.ttisfulluserdata(), "full userdata expected"); let uv = o.value.uservalue; L.stack[L.top] = new TValue(uv.type, uv.value); - L.top++; - assert(L.top <= L.ci.top, "stack overflow"); + api_incr_top(L); return L.stack[L.top - 1].ttnov(); }; @@ -616,17 +637,16 @@ const lua_getfield = function(L, idx, k) { }; const lua_geti = function(L, idx, n) { - assert(typeof n === "number" && (n|0) === n); + fengari_argcheck(typeof n === "number" && (n|0) === n); let t = index2addr(L, idx); - L.stack[L.top] = new TValue(CT.LUA_TNUMINT, n); - L.top++; - assert(L.top <= L.ci.top, "stack overflow"); + L.stack[L.top] = new TValue(LUA_TNUMINT, n); + api_incr_top(L); lvm.luaV_gettable(L, t, L.stack[L.top - 1], L.top - 1); return L.stack[L.top - 1].ttnov(); }; const lua_getglobal = function(L, name) { - return auxgetstr(L, ltable.luaH_getint(L.l_G.l_registry.value, defs.LUA_RIDX_GLOBALS), name); + return auxgetstr(L, ltable.luaH_getint(L.l_G.l_registry.value, LUA_RIDX_GLOBALS), name); }; /* @@ -674,12 +694,12 @@ const lua_todataview = function(L, idx) { const lua_rawlen = function(L, idx) { let o = index2addr(L, idx); switch (o.ttype()) { - case CT.LUA_TSHRSTR: - case CT.LUA_TLNGSTR: + case LUA_TSHRSTR: + case LUA_TLNGSTR: return o.vslen(); - case CT.LUA_TUSERDATA: + case LUA_TUSERDATA: return o.value.len; - case CT.LUA_TTABLE: + case LUA_TTABLE: return ltable.luaH_getn(o.value); default: return 0; @@ -713,9 +733,9 @@ const lua_tonumberx = function(L, idx) { const lua_touserdata = function(L, idx) { let o = index2addr(L, idx); switch (o.ttnov()) { - case CT.LUA_TUSERDATA: + case LUA_TUSERDATA: return o.value.data; - case CT.LUA_TLIGHTUSERDATA: + case LUA_TLIGHTUSERDATA: return o.value; default: return null; } @@ -729,13 +749,13 @@ const lua_tothread = function(L, idx) { const lua_topointer = function(L, idx) { let o = index2addr(L, idx); switch (o.ttype()) { - case CT.LUA_TTABLE: - case CT.LUA_TLCL: - case CT.LUA_TCCL: - case CT.LUA_TLCF: - case CT.LUA_TTHREAD: - case CT.LUA_TUSERDATA: /* note: this differs in behaviour to reference lua implementation */ - case CT.LUA_TLIGHTUSERDATA: + case LUA_TTABLE: + case LUA_TLCL: + case LUA_TCCL: + case LUA_TLCF: + case LUA_TTHREAD: + case LUA_TUSERDATA: /* note: this differs in behaviour to reference lua implementation */ + case LUA_TLIGHTUSERDATA: return o.value; default: return null; @@ -759,10 +779,9 @@ const lua_isproxy = function(p, L) { /* Use 'create_proxy' helper function so that 'L' is not in scope */ const create_proxy = function(G, type, value) { let proxy = function(L) { - assert(L instanceof lstate.lua_State && G === L.l_G, "must be from same global state"); + api_check(L, L instanceof lstate.lua_State && G === L.l_G, "must be from same global state"); L.stack[L.top] = new TValue(type, value); - L.top++; - assert(L.top <= L.ci.top, "stack overflow"); + api_incr_top(L); }; seen.set(proxy, G); return proxy; @@ -783,10 +802,10 @@ const lua_compare = function(L, index1, index2, op) { if (isvalid(o1) && isvalid(o2)) { switch (op) { - case defs.LUA_OPEQ: i = lvm.luaV_equalobj(L, o1, o2); break; - case defs.LUA_OPLT: i = lvm.luaV_lessthan(L, o1, o2); break; - case defs.LUA_OPLE: i = lvm.luaV_lessequal(L, o1, o2); break; - default: assert(false, "invalid option"); + case LUA_OPEQ: i = lvm.luaV_equalobj(L, o1, o2); break; + case LUA_OPLT: i = lvm.luaV_lessthan(L, o1, o2); break; + case LUA_OPLE: i = lvm.luaV_lessequal(L, o1, o2); break; + default: api_check(L, false, "invalid option"); } } @@ -798,8 +817,7 @@ const lua_stringtonumber = function(L, s) { let sz = lobject.luaO_str2num(s, tv); if (sz !== 0) { L.stack[L.top] = tv; - L.top++; - assert(L.top <= L.ci.top, "stack overflow"); + api_incr_top(L); } return sz; }; @@ -810,11 +828,11 @@ const f_call = function(L, ud) { const lua_type = function(L, idx) { let o = index2addr(L, idx); - return isvalid(o) ? o.ttnov() : CT.LUA_TNONE; + return isvalid(o) ? o.ttnov() : LUA_TNONE; }; const lua_typename = function(L, t) { - assert(CT.LUA_TNONE <= t && t < CT.LUA_NUMTAGS, "invalid tag"); + api_check(L, LUA_TNONE <= t && t < LUA_NUMTAGS, "invalid tag"); return ltm.ttypename(t); }; @@ -824,15 +842,15 @@ const lua_iscfunction = function(L, idx) { }; const lua_isnil = function(L, n) { - return lua_type(L, n) === CT.LUA_TNIL; + return lua_type(L, n) === LUA_TNIL; }; const lua_isboolean = function(L, n) { - return lua_type(L, n) === CT.LUA_TBOOLEAN; + return lua_type(L, n) === LUA_TBOOLEAN; }; const lua_isnone = function(L, n) { - return lua_type(L, n) === CT.LUA_TNONE; + return lua_type(L, n) === LUA_TNONE; }; const lua_isnoneornil = function(L, n) { @@ -862,15 +880,15 @@ const lua_isuserdata = function(L, idx) { }; const lua_isthread = function(L, idx) { - return lua_type(L, idx) === CT.LUA_TTHREAD; + return lua_type(L, idx) === LUA_TTHREAD; }; const lua_isfunction = function(L, idx) { - return lua_type(L, idx) === CT.LUA_TFUNCTION; + return lua_type(L, idx) === LUA_TFUNCTION; }; const lua_islightuserdata = function(L, idx) { - return lua_type(L, idx) === CT.LUA_TLIGHTUSERDATA; + return lua_type(L, idx) === LUA_TLIGHTUSERDATA; }; const lua_rawequal = function(L, index1, index2) { @@ -880,12 +898,12 @@ const lua_rawequal = function(L, index1, index2) { }; const lua_arith = function(L, op) { - if (op !== defs.LUA_OPUNM && op !== defs.LUA_OPBNOT) - assert(2 < L.top - L.ci.funcOff, "not enough elements in the stack"); /* all other operations expect two operands */ + if (op !== LUA_OPUNM && op !== LUA_OPBNOT) + api_checknelems(L, 2); /* all other operations expect two operands */ else { /* for unary operations, add fake 2nd operand */ - assert(1 < L.top - L.ci.funcOff, "not enough elements in the stack"); + api_checknelems(L, 1); lobject.pushobj2s(L, L.stack[L.top-1]); - assert(L.top <= L.ci.top, "stack overflow"); + api_check(L, L.top <= L.ci.top, "stack overflow"); } /* first operand at top - 2, second at top - 1; result go to top - 2 */ lobject.luaO_arith(L, op, L.stack[L.top - 2], L.stack[L.top - 1], L.stack[L.top - 2]); @@ -896,30 +914,30 @@ const lua_arith = function(L, op) { ** 'load' and 'call' functions (run Lua code) */ -const default_chunkname = defs.to_luastring("?"); +const default_chunkname = to_luastring("?"); const lua_load = function(L, reader, data, chunkname, mode) { if (!chunkname) chunkname = default_chunkname; - else chunkname = defs.from_userstring(chunkname); - if (mode !== null) mode = defs.from_userstring(mode); - let z = new lzio.ZIO(L, reader, data); + else chunkname = from_userstring(chunkname); + if (mode !== null) mode = from_userstring(mode); + let z = new ZIO(L, reader, data); let status = ldo.luaD_protectedparser(L, z, chunkname, mode); - if (status === TS.LUA_OK) { /* no errors? */ + if (status === LUA_OK) { /* no errors? */ let f = L.stack[L.top - 1].value; /* get newly created function */ if (f.nupvalues >= 1) { /* does it have an upvalue? */ /* get global table from registry */ - let gt = ltable.luaH_getint(L.l_G.l_registry.value, defs.LUA_RIDX_GLOBALS); + let gt = ltable.luaH_getint(L.l_G.l_registry.value, LUA_RIDX_GLOBALS); /* set global table as 1st upvalue of 'f' (may be LUA_ENV) */ - f.upvals[0].v.setfrom(gt); + f.upvals[0].setfrom(gt); } } return status; }; const lua_dump = function(L, writer, data, strip) { - assert(1 < L.top - L.ci.funcOff, "not enough elements in the stack"); + api_checknelems(L, 1); let o = L.stack[L.top -1]; if (o.ttisLclosure()) - return ldump.luaU_dump(L, o.value.p, writer, data, strip); + return luaU_dump(L, o.value.p, writer, data, strip); return 1; }; @@ -928,19 +946,23 @@ const lua_status = function(L) { }; const lua_setuservalue = function(L, idx) { - assert(1 < L.top - L.ci.funcOff, "not enough elements in the stack"); + api_checknelems(L, 1); let o = index2addr(L, idx); - assert(L, o.ttisfulluserdata(), "full userdata expected"); + api_check(L, o.ttisfulluserdata(), "full userdata expected"); o.value.uservalue.setfrom(L.stack[L.top - 1]); delete L.stack[--L.top]; }; -const lua_callk = function(L, nargs, nresults, ctx, k) { - assert(k === null || !(L.ci.callstatus & lstate.CIST_LUA), "cannot use continuations inside hooks"); - assert(nargs + 1 < L.top - L.ci.funcOff, "not enough elements in the stack"); - assert(L.status === TS.LUA_OK, "cannot do calls on non-normal thread"); - assert(nargs === defs.LUA_MULTRET || (L.ci.top - L.top >= nargs - nresults), "results from function overflow current stack size"); +const checkresults = function(L,na,nr) { + api_check(L, (nr) == LUA_MULTRET || (L.ci.top - L.top >= (nr) - (na)), + "results from function overflow current stack size"); +}; +const lua_callk = function(L, nargs, nresults, ctx, k) { + api_check(L, k === null || !(L.ci.callstatus & lstate.CIST_LUA), "cannot use continuations inside hooks"); + api_checknelems(L, nargs + 1); + api_check(L, L.status === LUA_OK, "cannot do calls on non-normal thread"); + checkresults(L, nargs, nresults); let func = L.top - (nargs + 1); if (k !== null && L.nny === 0) { /* need to prepare continuation? */ L.ci.c_k = k; @@ -950,7 +972,7 @@ const lua_callk = function(L, nargs, nresults, ctx, k) { ldo.luaD_callnoyield(L, func, nresults); } - if (nresults === defs.LUA_MULTRET && L.ci.top < L.top) + if (nresults === LUA_MULTRET && L.ci.top < L.top) L.ci.top = L.top; }; @@ -959,10 +981,10 @@ const lua_call = function(L, n, r) { }; const lua_pcallk = function(L, nargs, nresults, errfunc, ctx, k) { - assert(nargs + 1 < L.top - L.ci.funcOff, "not enough elements in the stack"); - assert(L.status === TS.LUA_OK, "cannot do calls on non-normal thread"); - assert(nargs === defs.LUA_MULTRET || (L.ci.top - L.top >= nargs - nresults), "results from function overflow current stack size"); - + api_check(L, k === null || !(L.ci.callstatus & lstate.CIST_LUA), "cannot use continuations inside hooks"); + api_checknelems(L, nargs + 1); + api_check(L, L.status === LUA_OK, "cannot do calls on non-normal thread"); + checkresults(L, nargs, nresults); let c = { func: null, funcOff: NaN, @@ -998,10 +1020,10 @@ const lua_pcallk = function(L, nargs, nresults, errfunc, ctx, k) { ldo.luaD_call(L, c.funcOff, nresults); /* do the call */ ci.callstatus &= ~lstate.CIST_YPCALL; L.errfunc = ci.c_old_errfunc; - status = TS.LUA_OK; + status = LUA_OK; } - if (nresults === defs.LUA_MULTRET && L.ci.top < L.top) + if (nresults === LUA_MULTRET && L.ci.top < L.top) L.ci.top = L.top; return status; @@ -1016,18 +1038,17 @@ const lua_pcall = function(L, n, r, f) { */ const lua_error = function(L) { - assert(1 < L.top - L.ci.funcOff, "not enough elements in the stack"); + api_checknelems(L, 1); ldebug.luaG_errormsg(L); }; const lua_next = function(L, idx) { let t = index2addr(L, idx); - assert(t.ttistable(), "table expected"); + api_check(L, t.ttistable(), "table expected"); L.stack[L.top] = new TValue(); let more = ltable.luaH_next(L, t.value, L.top - 1); if (more) { - L.top++; - assert(L.top <= L.ci.top, "stack overflow"); + api_incr_top(L); return 1; } else { delete L.stack[L.top]; @@ -1037,12 +1058,12 @@ const lua_next = function(L, idx) { }; const lua_concat = function(L, n) { - assert(n < L.top - L.ci.funcOff, "not enough elements in the stack"); + api_checknelems(L, n); if (n >= 2) lvm.luaV_concat(L, n); else if (n === 0) { - lobject.pushsvalue2s(L, lstring.luaS_bless(L, defs.to_luastring("", true))); - assert(L.top <= L.ci.top, "stack overflow"); + lobject.pushsvalue2s(L, luaS_bless(L, to_luastring("", true))); + api_check(L, L.top <= L.ci.top, "stack overflow"); } }; @@ -1051,35 +1072,34 @@ const lua_len = function(L, idx) { let tv = new TValue(); lvm.luaV_objlen(L, tv, t); L.stack[L.top] = tv; - L.top++; - assert(L.top <= L.ci.top, "stack overflow"); + api_incr_top(L); }; const getupvalref = function(L, fidx, n) { let fi = index2addr(L, fidx); - assert(fi.ttisLclosure(), "Lua function expected"); + api_check(L, fi.ttisLclosure(), "Lua function expected"); let f = fi.value; - assert(1 <= n && n <= f.p.upvalues.length, "invalid upvalue index"); + api_check(L, n|0 === n && 1 <= n && n <= f.p.upvalues.length, "invalid upvalue index"); return { - closure: f, - upval: f.upvals[n - 1], - upvalOff: n - 1 + f: f, + i: n - 1 }; }; const lua_upvalueid = function(L, fidx, n) { let fi = index2addr(L, fidx); switch (fi.ttype()) { - case CT.LUA_TLCL: { /* lua closure */ - return getupvalref(L, fidx, n).upval; + case LUA_TLCL: { /* lua closure */ + let ref = getupvalref(L, fidx, n); + return ref.f.upvals[ref.i]; } - case CT.LUA_TCCL: { /* C closure */ + case LUA_TCCL: { /* C closure */ let f = fi.value; - assert(1 <= n && n <= f.nupvalues, "invalid upvalue index"); + api_check(L, n|0 === n && 1 <= n && n <= f.nupvalues, "invalid upvalue index"); return f.upvalue[n - 1]; } default: { - assert(false, "closure expected"); + api_check(L, false, "closure expected"); return null; } } @@ -1088,13 +1108,8 @@ const lua_upvalueid = function(L, fidx, n) { const lua_upvaluejoin = function(L, fidx1, n1, fidx2, n2) { let ref1 = getupvalref(L, fidx1, n1); let ref2 = getupvalref(L, fidx2, n2); - let up1 = ref1.upval; - let up2 = ref2.upval; - let f1 = ref1.closure; - assert(up1.refcount > 0); - up1.refcount--; - f1.upvals[ref1.upvalOff] = up2; - up2.refcount++; + let up2 = ref2.f.upvals[ref2.i]; + ref1.f.upvals[ref1.i] = up2; }; // This functions are only there for compatibility purposes @@ -1115,8 +1130,8 @@ const lua_getextraspace = function () { return 0; }; -module.exports.index2addr = index2addr; -module.exports.index2addr_ = index2addr_; +module.exports.api_incr_top = api_incr_top; +module.exports.api_checknelems = api_checknelems; module.exports.lua_absindex = lua_absindex; module.exports.lua_arith = lua_arith; module.exports.lua_atpanic = lua_atpanic; diff --git a/src/lauxlib.js b/src/lauxlib.js index e6d407f..437b6cf 100644 --- a/src/lauxlib.js +++ b/src/lauxlib.js @@ -1,25 +1,109 @@ "use strict"; -const lua = require('./lua.js'); +const { + LUA_ERRERR, + LUA_MULTRET, + LUA_REGISTRYINDEX, + LUA_SIGNATURE, + LUA_TBOOLEAN, + LUA_TLIGHTUSERDATA, + LUA_TNIL, + LUA_TNONE, + LUA_TNUMBER, + LUA_TSTRING, + LUA_TTABLE, + LUA_VERSION_NUM, + lua_Debug, + lua_absindex, + lua_atpanic, + lua_call, + lua_checkstack, + lua_concat, + lua_copy, + lua_createtable, + lua_error, + lua_getfield, + lua_getinfo, + lua_getmetatable, + lua_getstack, + lua_gettop, + lua_insert, + lua_isinteger, + lua_isnil, + lua_isnumber, + lua_isstring, + lua_istable, + lua_len, + lua_load, + lua_newstate, + lua_newtable, + lua_next, + lua_pcall, + lua_pop, + lua_pushboolean, + lua_pushcclosure, + lua_pushcfunction, + lua_pushfstring, + lua_pushinteger, + lua_pushliteral, + lua_pushlstring, + lua_pushnil, + lua_pushstring, + lua_pushvalue, + lua_pushvfstring, + lua_rawequal, + lua_rawget, + lua_rawgeti, + lua_rawlen, + lua_rawseti, + lua_remove, + lua_setfield, + lua_setglobal, + lua_setmetatable, + lua_settop, + lua_toboolean, + lua_tointeger, + lua_tointegerx, + lua_tojsstring, + lua_tolstring, + lua_tonumber, + lua_tonumberx, + lua_topointer, + lua_tostring, + lua_touserdata, + lua_type, + lua_typename, + lua_version +} = require('./lua.js'); +const { + luastring_eq, + to_luastring, + to_uristring +} = require("./fengaricore.js"); + +/* extra error code for 'luaL_loadfilex' */ +const LUA_ERRFILE = LUA_ERRERR+1; /* key, in the registry, for table of loaded modules */ -const LUA_LOADED_TABLE = lua.to_luastring("_LOADED"); +const LUA_LOADED_TABLE = to_luastring("_LOADED"); /* key, in the registry, for table of preloaded loaders */ -const LUA_PRELOAD_TABLE = lua.to_luastring("_PRELOAD"); +const LUA_PRELOAD_TABLE = to_luastring("_PRELOAD"); -const LUA_FILEHANDLE = lua.to_luastring("FILE*"); +const LUA_FILEHANDLE = to_luastring("FILE*"); const LUAL_NUMSIZES = 4*16 + 8; -const __name = lua.to_luastring("__name"); -const __tostring = lua.to_luastring("__tostring"); +const __name = to_luastring("__name"); +const __tostring = to_luastring("__tostring"); + +const empty = new Uint8Array(0); class luaL_Buffer { constructor() { - this.b = null; this.L = null; - this.initb = null; + this.b = empty; + this.n = 0; } } @@ -31,25 +115,25 @@ const LEVELS2 = 11; /* size of the second part of the stack */ ** return 1 + string at top if find a good name. */ const findfield = function(L, objidx, level) { - if (level === 0 || !lua.lua_istable(L, -1)) + if (level === 0 || !lua_istable(L, -1)) return 0; /* not found */ - lua.lua_pushnil(L); /* start 'next' loop */ + lua_pushnil(L); /* start 'next' loop */ - while (lua.lua_next(L, -2)) { /* for each pair in table */ - if (lua.lua_type(L, -2) === lua.LUA_TSTRING) { /* ignore non-string keys */ - if (lua.lua_rawequal(L, objidx, -1)) { /* found object? */ - lua.lua_pop(L, 1); /* remove value (but keep name) */ + while (lua_next(L, -2)) { /* for each pair in table */ + if (lua_type(L, -2) === LUA_TSTRING) { /* ignore non-string keys */ + if (lua_rawequal(L, objidx, -1)) { /* found object? */ + lua_pop(L, 1); /* remove value (but keep name) */ return 1; } else if (findfield(L, objidx, level - 1)) { /* try recursively */ - lua.lua_remove(L, -2); /* remove table (but keep name) */ - lua.lua_pushliteral(L, "."); - lua.lua_insert(L, -2); /* place '.' between the two names */ - lua.lua_concat(L, 3); + lua_remove(L, -2); /* remove table (but keep name) */ + lua_pushliteral(L, "."); + lua_insert(L, -2); /* place '.' between the two names */ + lua_concat(L, 3); return 1; } } - lua.lua_pop(L, 1); /* remove value */ + lua_pop(L, 1); /* remove value */ } return 0; /* not found */ @@ -59,155 +143,158 @@ const findfield = function(L, objidx, level) { ** Search for a name for a function in all loaded modules */ const pushglobalfuncname = function(L, ar) { - let top = lua.lua_gettop(L); - lua.lua_getinfo(L, lua.to_luastring("f"), ar); /* push function */ - lua.lua_getfield(L, lua.LUA_REGISTRYINDEX, LUA_LOADED_TABLE); + let top = lua_gettop(L); + lua_getinfo(L, to_luastring("f"), ar); /* push function */ + lua_getfield(L, LUA_REGISTRYINDEX, LUA_LOADED_TABLE); if (findfield(L, top + 1, 2)) { - let name = lua.lua_tostring(L, -1); - if (name[0] === "_".charCodeAt(0) && name[1] === "G".charCodeAt(0) && name[2] === ".".charCodeAt(0)) { /* name start with '_G.'? */ - lua.lua_pushstring(L, name.subarray(3)); /* push name without prefix */ - lua.lua_remove(L, -2); /* remove original name */ + let name = lua_tostring(L, -1); + if (name[0] === 95 /* '_'.charCodeAt(0) */ && + name[1] === 71 /* 'G'.charCodeAt(0) */ && + name[2] === 46 /* '.'.charCodeAt(0) */ + ) { /* name start with '_G.'? */ + lua_pushstring(L, name.subarray(3)); /* push name without prefix */ + lua_remove(L, -2); /* remove original name */ } - lua.lua_copy(L, -1, top + 1); /* move name to proper place */ - lua.lua_pop(L, 2); /* remove pushed values */ + lua_copy(L, -1, top + 1); /* move name to proper place */ + lua_pop(L, 2); /* remove pushed values */ return 1; } else { - lua.lua_settop(L, top); /* remove function and global table */ + lua_settop(L, top); /* remove function and global table */ return 0; } }; const pushfuncname = function(L, ar) { if (pushglobalfuncname(L, ar)) { /* try first a global name */ - lua.lua_pushfstring(L, lua.to_luastring("function '%s'"), lua.lua_tostring(L, -1)); - lua.lua_remove(L, -2); /* remove name */ + lua_pushfstring(L, to_luastring("function '%s'"), lua_tostring(L, -1)); + lua_remove(L, -2); /* remove name */ } else if (ar.namewhat.length !== 0) /* is there a name from code? */ - lua.lua_pushfstring(L, lua.to_luastring("%s '%s'"), ar.namewhat, ar.name); /* use it */ - else if (ar.what && ar.what[0] === 'm'.charCodeAt(0)) /* main? */ - lua.lua_pushliteral(L, "main chunk"); - else if (ar.what && ar.what[0] === 'L'.charCodeAt(0)) /* for Lua functions, use <file:line> */ - lua.lua_pushfstring(L, lua.to_luastring("function <%s:%d>"), ar.short_src, ar.linedefined); + lua_pushfstring(L, to_luastring("%s '%s'"), ar.namewhat, ar.name); /* use it */ + else if (ar.what && ar.what[0] === 109 /* 'm'.charCodeAt(0) */) /* main? */ + lua_pushliteral(L, "main chunk"); + else if (ar.what && ar.what[0] === 76 /* 'L'.charCodeAt(0) */) /* for Lua functions, use <file:line> */ + lua_pushfstring(L, to_luastring("function <%s:%d>"), ar.short_src, ar.linedefined); else /* nothing left... */ - lua.lua_pushliteral(L, "?"); + lua_pushliteral(L, "?"); }; const lastlevel = function(L) { - let ar = new lua.lua_Debug(); + let ar = new lua_Debug(); let li = 1; let le = 1; /* find an upper bound */ - while (lua.lua_getstack(L, le, ar)) { li = le; le *= 2; } + while (lua_getstack(L, le, ar)) { li = le; le *= 2; } /* do a binary search */ while (li < le) { let m = Math.floor((li + le)/2); - if (lua.lua_getstack(L, m, ar)) li = m + 1; + if (lua_getstack(L, m, ar)) li = m + 1; else le = m; } return le - 1; }; const luaL_traceback = function(L, L1, msg, level) { - let ar = new lua.lua_Debug(); - let top = lua.lua_gettop(L); + let ar = new lua_Debug(); + let top = lua_gettop(L); let last = lastlevel(L1); let n1 = last - level > LEVELS1 + LEVELS2 ? LEVELS1 : -1; if (msg) - lua.lua_pushfstring(L, lua.to_luastring("%s\n"), msg); + lua_pushfstring(L, to_luastring("%s\n"), msg); luaL_checkstack(L, 10, null); - lua.lua_pushliteral(L, "stack traceback:"); - while (lua.lua_getstack(L1, level++, ar)) { + lua_pushliteral(L, "stack traceback:"); + while (lua_getstack(L1, level++, ar)) { if (n1-- === 0) { /* too many levels? */ - lua.lua_pushliteral(L, "\n\t..."); /* add a '...' */ + lua_pushliteral(L, "\n\t..."); /* add a '...' */ level = last - LEVELS2 + 1; /* and skip to last ones */ } else { - lua.lua_getinfo(L1, lua.to_luastring("Slnt", true), ar); - lua.lua_pushfstring(L, lua.to_luastring("\n\t%s:"), ar.short_src); + lua_getinfo(L1, to_luastring("Slnt", true), ar); + lua_pushfstring(L, to_luastring("\n\t%s:"), ar.short_src); if (ar.currentline > 0) - lua.lua_pushliteral(L, `${ar.currentline}:`); - lua.lua_pushliteral(L, " in "); + lua_pushliteral(L, `${ar.currentline}:`); + lua_pushliteral(L, " in "); pushfuncname(L, ar); if (ar.istailcall) - lua.lua_pushliteral(L, "\n\t(...tail calls..)"); - lua.lua_concat(L, lua.lua_gettop(L) - top); + lua_pushliteral(L, "\n\t(...tail calls..)"); + lua_concat(L, lua_gettop(L) - top); } } - lua.lua_concat(L, lua.lua_gettop(L) - top); + lua_concat(L, lua_gettop(L) - top); }; const panic = function(L) { let msg = "PANIC: unprotected error in call to Lua API"; try { - msg += " (" + lua.lua_tojsstring(L, -1) + ")"; + msg += " (" + lua_tojsstring(L, -1) + ")"; } catch (e) { } throw new Error(msg); }; const luaL_argerror = function(L, arg, extramsg) { - let ar = new lua.lua_Debug(); + let ar = new lua_Debug(); - if (!lua.lua_getstack(L, 0, ar)) /* no stack frame? */ - return luaL_error(L, lua.to_luastring("bad argument #%d (%s)"), arg, extramsg); + if (!lua_getstack(L, 0, ar)) /* no stack frame? */ + return luaL_error(L, to_luastring("bad argument #%d (%s)"), arg, extramsg); - lua.lua_getinfo(L, lua.to_luastring("n"), ar); + lua_getinfo(L, to_luastring("n"), ar); - if (ar.namewhat.join() === lua.to_luastring("method").join()) { + if (luastring_eq(ar.namewhat, to_luastring("method"))) { arg--; /* do not count 'self' */ if (arg === 0) /* error is in the self argument itself? */ - return luaL_error(L, lua.to_luastring("calling '%s' on bad self (%s)"), ar.name, extramsg); + return luaL_error(L, to_luastring("calling '%s' on bad self (%s)"), ar.name, extramsg); } if (ar.name === null) - ar.name = pushglobalfuncname(L, ar) ? lua.lua_tostring(L, -1) : lua.to_luastring("?"); + ar.name = pushglobalfuncname(L, ar) ? lua_tostring(L, -1) : to_luastring("?"); - return luaL_error(L, lua.to_luastring("bad argument #%d to '%s' (%s)"), arg, ar.name, extramsg); + return luaL_error(L, to_luastring("bad argument #%d to '%s' (%s)"), arg, ar.name, extramsg); }; const typeerror = function(L, arg, tname) { let typearg; - if (luaL_getmetafield(L, arg, __name) === lua.LUA_TSTRING) - typearg = lua.lua_tostring(L, -1); - else if (lua.lua_type(L, arg) === lua.LUA_TLIGHTUSERDATA) - typearg = lua.to_luastring("light userdata", true); + if (luaL_getmetafield(L, arg, __name) === LUA_TSTRING) + typearg = lua_tostring(L, -1); + else if (lua_type(L, arg) === LUA_TLIGHTUSERDATA) + typearg = to_luastring("light userdata", true); else typearg = luaL_typename(L, arg); - let msg = lua.lua_pushfstring(L, lua.to_luastring("%s expected, got %s"), tname, typearg); + let msg = lua_pushfstring(L, to_luastring("%s expected, got %s"), tname, typearg); return luaL_argerror(L, arg, msg); }; const luaL_where = function(L, level) { - let ar = new lua.lua_Debug(); - if (lua.lua_getstack(L, level, ar)) { - lua.lua_getinfo(L, lua.to_luastring("Sl", true), ar); + let ar = new lua_Debug(); + if (lua_getstack(L, level, ar)) { + lua_getinfo(L, to_luastring("Sl", true), ar); if (ar.currentline > 0) { - lua.lua_pushfstring(L, lua.to_luastring("%s:%d: "), ar.short_src, ar.currentline); + lua_pushfstring(L, to_luastring("%s:%d: "), ar.short_src, ar.currentline); return; } } - lua.lua_pushstring(L, lua.to_luastring("")); + lua_pushstring(L, to_luastring("")); }; const luaL_error = function(L, fmt, ...argp) { luaL_where(L, 1); - lua.lua_pushvfstring(L, fmt, argp); - lua.lua_concat(L, 2); - return lua.lua_error(L); + lua_pushvfstring(L, fmt, argp); + lua_concat(L, 2); + return lua_error(L); }; /* Unlike normal lua, we pass in an error object */ const luaL_fileresult = function(L, stat, fname, e) { if (stat) { - lua.lua_pushboolean(L, 1); + lua_pushboolean(L, 1); return 1; } else { - lua.lua_pushnil(L); + lua_pushnil(L); if (fname) - lua.lua_pushfstring(L, lua.to_luastring("%s: %s"), fname, lua.to_luastring(e.message)); + lua_pushfstring(L, to_luastring("%s: %s"), fname, to_luastring(e.message)); else - lua.lua_pushstring(L, lua.to_luastring(e.message)); - lua.lua_pushinteger(L, -e.errno); + lua_pushstring(L, to_luastring(e.message)); + lua_pushinteger(L, -e.errno); return 3; } }; @@ -216,9 +303,9 @@ const luaL_fileresult = function(L, stat, fname, e) { const luaL_execresult = function(L, e) { let what, stat; if (e === null) { - lua.lua_pushboolean(L, 1); - lua.lua_pushliteral(L, "exit"); - lua.lua_pushinteger(L, 0); + lua_pushboolean(L, 1); + lua_pushliteral(L, "exit"); + lua_pushinteger(L, 0); return 3; } else if (e.status) { what = "exit"; @@ -230,42 +317,42 @@ const luaL_execresult = function(L, e) { /* XXX: node seems to have e.errno as a string instead of a number */ return luaL_fileresult(L, 0, null, e); } - lua.lua_pushnil(L); - lua.lua_pushliteral(L, what); - lua.lua_pushinteger(L, stat); + lua_pushnil(L); + lua_pushliteral(L, what); + lua_pushinteger(L, stat); return 3; }; const luaL_getmetatable = function(L, n) { - return lua.lua_getfield(L, lua.LUA_REGISTRYINDEX, n); + return lua_getfield(L, LUA_REGISTRYINDEX, n); }; const luaL_newmetatable = function(L, tname) { - if (luaL_getmetatable(L, tname) !== lua.LUA_TNIL) /* name already in use? */ + if (luaL_getmetatable(L, tname) !== LUA_TNIL) /* name already in use? */ return 0; /* leave previous value on top, but return 0 */ - lua.lua_pop(L, 1); - lua.lua_createtable(L, 0, 2); /* create metatable */ - lua.lua_pushstring(L, tname); - lua.lua_setfield(L, -2, __name); /* metatable.__name = tname */ - lua.lua_pushvalue(L, -1); - lua.lua_setfield(L, lua.LUA_REGISTRYINDEX, tname); /* registry.name = metatable */ + lua_pop(L, 1); + lua_createtable(L, 0, 2); /* create metatable */ + lua_pushstring(L, tname); + lua_setfield(L, -2, __name); /* metatable.__name = tname */ + lua_pushvalue(L, -1); + lua_setfield(L, LUA_REGISTRYINDEX, tname); /* registry.name = metatable */ return 1; }; const luaL_setmetatable = function(L, tname) { luaL_getmetatable(L, tname); - lua.lua_setmetatable(L, -2); + lua_setmetatable(L, -2); }; const luaL_testudata = function(L, ud, tname) { - let p = lua.lua_touserdata(L, ud); + let p = lua_touserdata(L, ud); if (p !== null) { /* value is a userdata? */ - if (lua.lua_getmetatable(L, ud)) { /* does it have a metatable? */ + if (lua_getmetatable(L, ud)) { /* does it have a metatable? */ luaL_getmetatable(L, tname); /* get correct metatable */ - if (!lua.lua_rawequal(L, -1, -2)) /* not the same? */ + if (!lua_rawequal(L, -1, -2)) /* not the same? */ p = null; /* value is a userdata with wrong metatable */ - lua.lua_pop(L, 2); /* remove both metatables */ + lua_pop(L, 2); /* remove both metatables */ return p; } } @@ -283,22 +370,22 @@ const luaL_checkoption = function(L, arg, def, lst) { for (let i = 0; lst[i]; i++) if (lst[i].join('|') === name.join('|')) return i; - return luaL_argerror(L, arg, lua.lua_pushfstring(L, lua.to_luastring("invalid option '%s'"), name)); + return luaL_argerror(L, arg, lua_pushfstring(L, to_luastring("invalid option '%s'"), name)); }; const tag_error = function(L, arg, tag) { - typeerror(L, arg, lua.lua_typename(L, tag)); + typeerror(L, arg, lua_typename(L, tag)); }; const luaL_newstate = function() { - let L = lua.lua_newstate(); - if (L) lua.lua_atpanic(L, panic); + let L = lua_newstate(); + if (L) lua_atpanic(L, panic); return L; }; const luaL_typename = function(L, i) { - return lua.lua_typename(L, lua.lua_type(L, i)); + return lua_typename(L, lua_type(L, i)); }; const luaL_argcheck = function(L, cond, arg, extramsg) { @@ -306,12 +393,12 @@ const luaL_argcheck = function(L, cond, arg, extramsg) { }; const luaL_checkany = function(L, arg) { - if (lua.lua_type(L, arg) === lua.LUA_TNONE) - luaL_argerror(L, arg, lua.to_luastring("value expected", true)); + if (lua_type(L, arg) === LUA_TNONE) + luaL_argerror(L, arg, to_luastring("value expected", true)); }; const luaL_checktype = function(L, arg, t) { - if (lua.lua_type(L, arg) !== t) + if (lua_type(L, arg) !== t) tag_error(L, arg, t); }; @@ -320,13 +407,13 @@ const luaL_checkstring = function(L, n) { }; const luaL_checklstring = function(L, arg) { - let s = lua.lua_tolstring(L, arg); - if (s === null || s === undefined) tag_error(L, arg, lua.LUA_TSTRING); + let s = lua_tolstring(L, arg); + if (s === null || s === undefined) tag_error(L, arg, LUA_TSTRING); return s; }; const luaL_optlstring = function(L, arg, def) { - if (lua.lua_type(L, arg) <= 0) { + if (lua_type(L, arg) <= 0) { return def; } else return luaL_checklstring(L, arg); }; @@ -334,16 +421,16 @@ const luaL_optlstring = function(L, arg, def) { const luaL_optstring = luaL_optlstring; const interror = function(L, arg) { - if (lua.lua_isnumber(L, arg)) - luaL_argerror(L, arg, lua.to_luastring("number has no integer representation", true)); + if (lua_isnumber(L, arg)) + luaL_argerror(L, arg, to_luastring("number has no integer representation", true)); else - tag_error(L, arg, lua.LUA_TNUMBER); + tag_error(L, arg, LUA_TNUMBER); }; const luaL_checknumber = function(L, arg) { - let d = lua.lua_tonumberx(L, arg); + let d = lua_tonumberx(L, arg); if (d === false) - tag_error(L, arg, lua.LUA_TNUMBER); + tag_error(L, arg, LUA_TNUMBER); return d; }; @@ -352,7 +439,7 @@ const luaL_optnumber = function(L, arg, def) { }; const luaL_checkinteger = function(L, arg) { - let d = lua.lua_tointegerx(L, arg); + let d = lua_tointegerx(L, arg); if (d === false) interror(L, arg); return d; @@ -363,13 +450,19 @@ const luaL_optinteger = function(L, arg, def) { }; const luaL_prepbuffsize = function(B, sz) { - B.initb = new Uint8Array(sz); - return B.initb; + let newend = B.n + sz; + if (B.b.length < newend) { + let newsize = Math.max(B.b.length * 2, newend); /* double buffer size */ + let newbuff = new Uint8Array(newsize); /* create larger buffer */ + newbuff.set(B.b); /* copy original content */ + B.b = newbuff; + } + return B.b.subarray(B.n, newend); }; const luaL_buffinit = function(L, B) { B.L = L; - B.b = []; + B.b = empty; }; const luaL_buffinitsize = function(L, B, sz) { @@ -384,24 +477,31 @@ const luaL_prepbuffer = function(B) { }; const luaL_addlstring = function(B, s, l) { - B.b = B.b.concat(Array.from(s.subarray(0, l))); + if (l > 0) { + let b = luaL_prepbuffsize(B, l); + b.set(s.subarray(0, l)); + luaL_addsize(B, l); + } }; -const luaL_addstring = luaL_addlstring; +const luaL_addstring = function(B, s) { + luaL_addlstring(B, s, s.length); +}; const luaL_pushresult = function(B) { - let L = B.L; - lua.lua_pushstring(L, Uint8Array.from(B.b)); + lua_pushlstring(B.L, B.b, B.n); + /* delete old buffer */ + B.n = 0; + B.b = empty; }; const luaL_addchar = function(B, c) { - B.b.push(c); + luaL_prepbuffsize(B, 1); + B.b[B.n++] = c; }; const luaL_addsize = function(B, s) { - B.b = B.b.concat(Array.from(B.initb.subarray(0, s))); B.n += s; - B.initb = null; }; const luaL_pushresultsize = function(B, sz) { @@ -411,14 +511,13 @@ const luaL_pushresultsize = function(B, sz) { const luaL_addvalue = function(B) { let L = B.L; - let s = lua.lua_tostring(L, -1); - // TODO: buffonstack ? necessary ? - luaL_addstring(B, s); - lua.lua_remove(L, -1); + let s = lua_tostring(L, -1); + luaL_addlstring(B, s, s.length); + lua_pop(L, 1); /* remove value */ }; const luaL_opt = function(L, f, n, d) { - return lua.lua_type(L, n) <= 0 ? d : f(L, n); + return lua_type(L, n) <= 0 ? d : f(L, n); }; const getS = function(L, ud) { @@ -428,7 +527,7 @@ const getS = function(L, ud) { }; const luaL_loadbufferx = function(L, buff, size, name, mode) { - return lua.lua_load(L, getS, {string: buff}, name, mode); + return lua_load(L, getS, {string: buff}, name, mode); }; const luaL_loadbuffer = function(L, s, sz, n) { @@ -440,80 +539,80 @@ const luaL_loadstring = function(L, s) { }; const luaL_dostring = function(L, s) { - return (luaL_loadstring(L, s) || lua.lua_pcall(L, 0, lua.LUA_MULTRET, 0)); + return (luaL_loadstring(L, s) || lua_pcall(L, 0, LUA_MULTRET, 0)); }; const luaL_getmetafield = function(L, obj, event) { - if (!lua.lua_getmetatable(L, obj)) /* no metatable? */ - return lua.LUA_TNIL; + if (!lua_getmetatable(L, obj)) /* no metatable? */ + return LUA_TNIL; else { - lua.lua_pushstring(L, event); - let tt = lua.lua_rawget(L, -2); - if (tt === lua.LUA_TNIL) /* is metafield nil? */ - lua.lua_pop(L, 2); /* remove metatable and metafield */ + lua_pushstring(L, event); + let tt = lua_rawget(L, -2); + if (tt === LUA_TNIL) /* is metafield nil? */ + lua_pop(L, 2); /* remove metatable and metafield */ else - lua.lua_remove(L, -2); /* remove only metatable */ + lua_remove(L, -2); /* remove only metatable */ return tt; /* return metafield type */ } }; const luaL_callmeta = function(L, obj, event) { - obj = lua.lua_absindex(L, obj); - if (luaL_getmetafield(L, obj, event) === lua.LUA_TNIL) + obj = lua_absindex(L, obj); + if (luaL_getmetafield(L, obj, event) === LUA_TNIL) return false; - lua.lua_pushvalue(L, obj); - lua.lua_call(L, 1, 1); + lua_pushvalue(L, obj); + lua_call(L, 1, 1); return true; }; const luaL_len = function(L, idx) { - lua.lua_len(L, idx); - let l = lua.lua_tointegerx(L, -1); + lua_len(L, idx); + let l = lua_tointegerx(L, -1); if (l === false) - luaL_error(L, lua.to_luastring("object length is not an integer", true)); - lua.lua_pop(L, 1); /* remove object */ + luaL_error(L, to_luastring("object length is not an integer", true)); + lua_pop(L, 1); /* remove object */ return l; }; -const p_I = lua.to_luastring("%I"); -const p_f = lua.to_luastring("%f"); +const p_I = to_luastring("%I"); +const p_f = to_luastring("%f"); const luaL_tolstring = function(L, idx) { if (luaL_callmeta(L, idx, __tostring)) { - if (!lua.lua_isstring(L, -1)) - luaL_error(L, lua.to_luastring("'__tostring' must return a string")); + if (!lua_isstring(L, -1)) + luaL_error(L, to_luastring("'__tostring' must return a string")); } else { - let t = lua.lua_type(L, idx); + let t = lua_type(L, idx); switch(t) { - case lua.LUA_TNUMBER: { - if (lua.lua_isinteger(L, idx)) - lua.lua_pushfstring(L, p_I, lua.lua_tointeger(L, idx)); + case LUA_TNUMBER: { + if (lua_isinteger(L, idx)) + lua_pushfstring(L, p_I, lua_tointeger(L, idx)); else - lua.lua_pushfstring(L, p_f, lua.lua_tonumber(L, idx)); + lua_pushfstring(L, p_f, lua_tonumber(L, idx)); break; } - case lua.LUA_TSTRING: - lua.lua_pushvalue(L, idx); + case LUA_TSTRING: + lua_pushvalue(L, idx); break; - case lua.LUA_TBOOLEAN: - lua.lua_pushliteral(L, (lua.lua_toboolean(L, idx) ? "true" : "false")); + case LUA_TBOOLEAN: + lua_pushliteral(L, (lua_toboolean(L, idx) ? "true" : "false")); break; - case lua.LUA_TNIL: - lua.lua_pushliteral(L, "nil"); + case LUA_TNIL: + lua_pushliteral(L, "nil"); break; default: { let tt = luaL_getmetafield(L, idx, __name); - let kind = tt === lua.LUA_TSTRING ? lua.lua_tostring(L, -1) : luaL_typename(L, idx); - lua.lua_pushfstring(L, lua.to_luastring("%s: %p"), kind, lua.lua_topointer(L, idx)); - if (tt !== lua.LUA_TNIL) - lua.lua_remove(L, -2); + let kind = tt === LUA_TSTRING ? lua_tostring(L, -1) : luaL_typename(L, idx); + lua_pushfstring(L, to_luastring("%s: %p"), kind, lua_topointer(L, idx)); + if (tt !== LUA_TNIL) + lua_remove(L, -2); break; } } } - return lua.lua_tolstring(L, -1); + return lua_tolstring(L, -1); }; /* @@ -523,20 +622,20 @@ 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); - lua.lua_getfield(L, -1, modname); /* LOADED[modname] */ - if (!lua.lua_toboolean(L, -1)) { /* package not already loaded? */ - lua.lua_pop(L, 1); /* remove field */ - lua.lua_pushcfunction(L, openf); - lua.lua_pushstring(L, modname); /* argument to open function */ - lua.lua_call(L, 1, 1); /* call 'openf' to open module */ - lua.lua_pushvalue(L, -1); /* make copy of module (call result) */ - lua.lua_setfield(L, -3, modname); /* LOADED[modname] = module */ + luaL_getsubtable(L, LUA_REGISTRYINDEX, LUA_LOADED_TABLE); + lua_getfield(L, -1, modname); /* LOADED[modname] */ + if (!lua_toboolean(L, -1)) { /* package not already loaded? */ + lua_pop(L, 1); /* remove field */ + lua_pushcfunction(L, openf); + lua_pushstring(L, modname); /* argument to open function */ + lua_call(L, 1, 1); /* call 'openf' to open module */ + lua_pushvalue(L, -1); /* make copy of module (call result) */ + lua_setfield(L, -3, modname); /* LOADED[modname] = module */ } - lua.lua_remove(L, -2); /* remove LOADED table */ + lua_remove(L, -2); /* remove LOADED table */ if (glb) { - lua.lua_pushvalue(L, -1); /* copy of module */ - lua.lua_setglobal(L, modname); /* _G[modname] = module */ + lua_pushvalue(L, -1); /* copy of module */ + lua_setglobal(L, modname); /* _G[modname] = module */ } }; @@ -556,15 +655,16 @@ const find_subarray = function(arr, subarr, from_index) { const luaL_gsub = function(L, s, p, r) { let wild; - let b = []; + let b = new luaL_Buffer(); + luaL_buffinit(L, b); while ((wild = find_subarray(s, p)) >= 0) { - b.push(...s.slice(0, wild)); /* push prefix */ - b.push(...r); /* push replacement in place of pattern */ - s = s.slice(wild + p.length); /* continue after 'p' */ + luaL_addlstring(b, s, wild); /* push prefix */ + luaL_addstring(b, r); /* push replacement in place of pattern */ + s = s.subarray(wild + p.length); /* continue after 'p' */ } - b.push(...s); /* push last suffix */ - lua.lua_pushstring(L, Uint8Array.from(b)); - return lua.lua_tostring(L, -1); + luaL_addstring(b, s); /* push last suffix */ + luaL_pushresult(b); + return lua_tostring(L, -1); }; /* @@ -572,14 +672,14 @@ const luaL_gsub = function(L, s, p, r) { ** into the stack */ const luaL_getsubtable = function(L, idx, fname) { - if (lua.lua_getfield(L, idx, fname) === lua.LUA_TTABLE) + if (lua_getfield(L, idx, fname) === LUA_TTABLE) return true; /* table already there */ else { - lua.lua_pop(L, 1); /* remove previous result */ - idx = lua.lua_absindex(L, idx); - lua.lua_newtable(L); - lua.lua_pushvalue(L, -1); /* copy to be left at top */ - lua.lua_setfield(L, idx, fname); /* assign new table to field */ + lua_pop(L, 1); /* remove previous result */ + idx = lua_absindex(L, idx); + lua_newtable(L); + lua_pushvalue(L, -1); /* copy to be left at top */ + lua_setfield(L, idx, fname); /* assign new table to field */ return false; /* false, because did not find table there */ } }; @@ -590,14 +690,14 @@ const luaL_getsubtable = function(L, idx, fname) { ** Returns with only the table at the stack. */ const luaL_setfuncs = function(L, l, nup) { - luaL_checkstack(L, nup, lua.to_luastring("too many upvalues", true)); + luaL_checkstack(L, nup, to_luastring("too many upvalues", true)); for (let lib in l) { /* fill the table with given functions */ for (let i = 0; i < nup; i++) /* copy upvalues to the top */ - lua.lua_pushvalue(L, -nup); - lua.lua_pushcclosure(L, l[lib], nup); /* closure with those upvalues */ - lua.lua_setfield(L, -(nup + 2), lua.to_luastring(lib)); + lua_pushvalue(L, -nup); + lua_pushcclosure(L, l[lib], nup); /* closure with those upvalues */ + lua_setfield(L, -(nup + 2), to_luastring(lib)); } - lua.lua_pop(L, nup); /* remove upvalues */ + lua_pop(L, nup); /* remove upvalues */ }; /* @@ -608,20 +708,20 @@ const luaL_setfuncs = function(L, l, nup) { ** but without 'msg'.) */ const luaL_checkstack = function(L, space, msg) { - if (!lua.lua_checkstack(L, space)) { + if (!lua_checkstack(L, space)) { if (msg) - luaL_error(L, lua.to_luastring("stack overflow (%s)"), msg); + luaL_error(L, to_luastring("stack overflow (%s)"), msg); else - luaL_error(L, lua.to_luastring('stack overflow', true)); + luaL_error(L, to_luastring('stack overflow', true)); } }; const luaL_newlibtable = function(L) { - lua.lua_createtable(L); + lua_createtable(L); }; const luaL_newlib = function(L, l) { - lua.lua_createtable(L); + lua_createtable(L); luaL_setfuncs(L, l, 0); }; @@ -631,42 +731,42 @@ const LUA_REFNIL = -1; const luaL_ref = function(L, t) { let ref; - if (lua.lua_isnil(L, -1)) { - lua.lua_pop(L, 1); /* remove from stack */ + if (lua_isnil(L, -1)) { + lua_pop(L, 1); /* remove from stack */ return LUA_REFNIL; /* 'nil' has a unique fixed reference */ } - t = lua.lua_absindex(L, t); - lua.lua_rawgeti(L, t, 0); /* get first free element */ - ref = lua.lua_tointeger(L, -1); /* ref = t[freelist] */ - lua.lua_pop(L, 1); /* remove it from stack */ + t = lua_absindex(L, t); + lua_rawgeti(L, t, 0); /* get first free element */ + ref = lua_tointeger(L, -1); /* ref = t[freelist] */ + lua_pop(L, 1); /* remove it from stack */ if (ref !== 0) { /* any free element? */ - lua.lua_rawgeti(L, t, ref); /* remove it from list */ - lua.lua_rawseti(L, t, 0); /* (t[freelist] = t[ref]) */ + lua_rawgeti(L, t, ref); /* remove it from list */ + lua_rawseti(L, t, 0); /* (t[freelist] = t[ref]) */ } else /* no free elements */ - ref = lua.lua_rawlen(L, t) + 1; /* get a new reference */ - lua.lua_rawseti(L, t, ref); + ref = lua_rawlen(L, t) + 1; /* get a new reference */ + lua_rawseti(L, t, ref); return ref; }; const luaL_unref = function(L, t, ref) { if (ref >= 0) { - t = lua.lua_absindex(L, t); - lua.lua_rawgeti(L, t, 0); - lua.lua_rawseti(L, t, ref); /* t[ref] = t[freelist] */ - lua.lua_pushinteger(L, ref); - lua.lua_rawseti(L, t, 0); /* t[freelist] = ref */ + t = lua_absindex(L, t); + lua_rawgeti(L, t, 0); + lua_rawseti(L, t, ref); /* t[ref] = t[freelist] */ + lua_pushinteger(L, ref); + lua_rawseti(L, t, 0); /* t[freelist] = ref */ } }; const errfile = function(L, what, fnameindex, error) { let serr = error.message; - let filename = lua.lua_tostring(L, fnameindex).slice(1); - lua.lua_pushfstring(L, lua.to_luastring("cannot %s %s: %s"), lua.to_luastring(what), filename, lua.to_luastring(serr)); - lua.lua_remove(L, fnameindex); - return lua.LUA_ERRFILE; + let filename = lua_tostring(L, fnameindex).subarray(1); + lua_pushfstring(L, to_luastring("cannot %s %s: %s"), to_luastring(what), filename, to_luastring(serr)); + lua_remove(L, fnameindex); + return LUA_ERRFILE; }; let getc; @@ -695,10 +795,10 @@ const skipBOM = function(lf) { */ const skipcomment = function(lf) { let c = skipBOM(lf); - if (c === '#'.charCodeAt(0)) { /* first line is a comment (Unix exec. file)? */ + if (c === 35 /* '#'.charCodeAt(0) */) { /* first line is a comment (Unix exec. file)? */ do { /* skip first line */ c = getc(lf); - } while (c && c !== '\n'.charCodeAt(0)); + } while (c && c !== 10 /* '\n'.charCodeAt(0) */); return { skipped: true, @@ -746,12 +846,12 @@ if (typeof process === "undefined") { luaL_loadfilex = function(L, filename, mode) { let lf = new LoadF(); - let fnameindex = lua.lua_gettop(L) + 1; /* index of filename on the stack */ + let fnameindex = lua_gettop(L) + 1; /* index of filename on the stack */ if (filename === null) { throw new Error("Can't read stdin in the browser"); } else { - lua.lua_pushfstring(L, lua.to_luastring("@%s"), filename); - let path = lua.to_uristring(filename); + lua_pushfstring(L, to_luastring("@%s"), filename); + let path = to_uristring(filename); let xhr = new XMLHttpRequest(); xhr.open("GET", path, false); /* XXX: Synchronous xhr in main thread always returns a js string @@ -763,7 +863,7 @@ if (typeof process === "undefined") { xhr.send(); if (xhr.status >= 200 && xhr.status <= 299) { if (typeof xhr.response === "string") { - lf.f = lua.to_luastring(xhr.response); + lf.f = to_luastring(xhr.response); } else { lf.f = new Uint8Array(xhr.response); } @@ -774,20 +874,20 @@ if (typeof process === "undefined") { } let com = skipcomment(lf); /* check for signature first, as we don't want to add line number corrections in binary case */ - if (com.c === lua.LUA_SIGNATURE.charCodeAt(0) && filename) { /* binary file? */ + if (com.c === LUA_SIGNATURE[0] && filename) { /* binary file? */ /* no need to re-open in node.js */ } else if (com.skipped) { /* read initial portion */ - lf.buff[lf.n++] = '\n'.charCodeAt(0); /* add line to correct line numbers */ + lf.buff[lf.n++] = 10 /* '\n'.charCodeAt(0) */; /* add line to correct line numbers */ } if (com.c !== null) lf.buff[lf.n++] = com.c; /* 'c' is the first character of the stream */ - let status = lua.lua_load(L, getF, lf, lua.lua_tostring(L, -1), mode); + let status = lua_load(L, getF, lf, lua_tostring(L, -1), mode); let readstatus = lf.err; if (readstatus) { - lua.lua_settop(L, fnameindex); /* ignore results from 'lua_load' */ + lua_settop(L, fnameindex); /* ignore results from 'lua_load' */ return errfile(L, "read", fnameindex, readstatus); } - lua.lua_remove(L, fnameindex); + lua_remove(L, fnameindex); return status; }; } else { @@ -809,7 +909,7 @@ if (typeof process === "undefined") { lf.pos += bytes; } if (bytes > 0) - return lf.buff.subarray(0, bytes); /* slice on a node.js Buffer is 'free' */ + return lf.buff.subarray(0, bytes); else return null; }; @@ -828,36 +928,35 @@ if (typeof process === "undefined") { luaL_loadfilex = function(L, filename, mode) { let lf = new LoadF(); - let fnameindex = lua.lua_gettop(L) + 1; /* index of filename on the stack */ + let fnameindex = lua_gettop(L) + 1; /* index of filename on the stack */ if (filename === null) { - lua.lua_pushliteral(L, "=stdin"); + lua_pushliteral(L, "=stdin"); lf.f = process.stdin.fd; } else { - lua.lua_pushfstring(L, lua.to_luastring("@%s"), filename); + lua_pushfstring(L, to_luastring("@%s"), filename); try { - let jsfilename = Uint8Array.from(filename); - lf.f = fs.openSync(jsfilename, "r"); + lf.f = fs.openSync(filename, "r"); } catch (e) { return errfile(L, "open", fnameindex, e); } } let com = skipcomment(lf); /* check for signature first, as we don't want to add line number corrections in binary case */ - if (com.c === lua.LUA_SIGNATURE.charCodeAt(0) && filename) { /* binary file? */ + if (com.c === LUA_SIGNATURE[0] && filename) { /* binary file? */ /* no need to re-open in node.js */ } else if (com.skipped) { /* read initial portion */ - lf.buff[lf.n++] = '\n'.charCodeAt(0); /* add line to correct line numbers */ + lf.buff[lf.n++] = 10 /* '\n'.charCodeAt(0) */; /* add line to correct line numbers */ } if (com.c !== null) lf.buff[lf.n++] = com.c; /* 'c' is the first character of the stream */ - let status = lua.lua_load(L, getF, lf, lua.lua_tostring(L, -1), mode); + let status = lua_load(L, getF, lf, lua_tostring(L, -1), mode); let readstatus = lf.err; if (filename) try { fs.closeSync(lf.f); } catch(e) {} /* close file (even in case of errors) */ if (readstatus) { - lua.lua_settop(L, fnameindex); /* ignore results from 'lua_load' */ + lua_settop(L, fnameindex); /* ignore results from 'lua_load' */ return errfile(L, "read", fnameindex, readstatus); } - lua.lua_remove(L, fnameindex); + lua_remove(L, fnameindex); return status; }; } @@ -867,7 +966,7 @@ const luaL_loadfile = function(L, filename) { }; const luaL_dofile = function(L, filename) { - return (luaL_loadfile(L, filename) || lua.lua_pcall(L, 0, lua.LUA_MULTRET, 0)); + return (luaL_loadfile(L, filename) || lua_pcall(L, 0, LUA_MULTRET, 0)); }; const lua_writestringerror = function() { @@ -888,18 +987,22 @@ const lua_writestringerror = function() { } }; -const luaL_checkversion = function(L) { - let ver = lua.LUA_VERSION_NUM; - let sz = LUAL_NUMSIZES; - let v = lua.lua_version(L); +const luaL_checkversion_ = function(L, ver, sz) { + let v = lua_version(L); if (sz != LUAL_NUMSIZES) /* check numeric types */ - luaL_error(L, lua.to_luastring("core and library have incompatible numeric types")); - if (v != lua.lua_version(null)) - luaL_error(L, lua.to_luastring("multiple Lua VMs detected")); + luaL_error(L, to_luastring("core and library have incompatible numeric types")); + if (v != lua_version(null)) + luaL_error(L, to_luastring("multiple Lua VMs detected")); else if (v !== ver) - luaL_error(L, lua.to_luastring("version mismatch: app. needs %f, Lua core provides %f"), ver, v); + luaL_error(L, to_luastring("version mismatch: app. needs %f, Lua core provides %f"), ver, v); +}; + +/* There is no point in providing this function... */ +const luaL_checkversion = function(L) { + luaL_checkversion_(L, LUA_VERSION_NUM, LUAL_NUMSIZES); }; +module.exports.LUA_ERRFILE = LUA_ERRFILE; module.exports.LUA_FILEHANDLE = LUA_FILEHANDLE; module.exports.LUA_LOADED_TABLE = LUA_LOADED_TABLE; module.exports.LUA_NOREF = LUA_NOREF; @@ -926,6 +1029,7 @@ module.exports.luaL_checkstring = luaL_checkstring; module.exports.luaL_checktype = luaL_checktype; module.exports.luaL_checkudata = luaL_checkudata; module.exports.luaL_checkversion = luaL_checkversion; +module.exports.luaL_checkversion_ = luaL_checkversion_; module.exports.luaL_dofile = luaL_dofile; module.exports.luaL_dostring = luaL_dostring; module.exports.luaL_error = luaL_error; diff --git a/src/lbaselib.js b/src/lbaselib.js index 86ba6cc..4212525 100644 --- a/src/lbaselib.js +++ b/src/lbaselib.js @@ -1,22 +1,115 @@ "use strict"; -const lua = require('./lua.js'); -const lauxlib = require('./lauxlib.js'); +const { + LUA_MULTRET, + LUA_OK, + LUA_TFUNCTION, + LUA_TNIL, + LUA_TNONE, + LUA_TNUMBER, + LUA_TSTRING, + LUA_TTABLE, + LUA_VERSION, + LUA_YIELD, + lua_call, + lua_callk, + lua_concat, + lua_error, + lua_getglobal, + lua_geti, + lua_getmetatable, + lua_gettop, + lua_insert, + lua_isnil, + lua_isnone, + lua_isstring, + lua_load, + lua_next, + lua_pcallk, + lua_pop, + lua_pushboolean, + lua_pushcfunction, + lua_pushglobaltable, + lua_pushinteger, + lua_pushliteral, + lua_pushnil, + lua_pushstring, + lua_pushvalue, + lua_rawequal, + lua_rawget, + lua_rawlen, + lua_rawset, + lua_remove, + lua_replace, + lua_rotate, + lua_setfield, + lua_setmetatable, + lua_settop, + lua_setupvalue, + lua_stringtonumber, + lua_toboolean, + lua_tolstring, + lua_tostring, + lua_type, + lua_typename +} = require('./lua.js'); +const { + luaL_argcheck, + luaL_checkany, + luaL_checkinteger, + luaL_checkoption, + luaL_checkstack, + luaL_checktype, + luaL_error, + luaL_getmetafield, + luaL_loadbufferx, + luaL_loadfile, + luaL_loadfilex, + luaL_optinteger, + luaL_optstring, + luaL_setfuncs, + luaL_tolstring, + luaL_where +} = require('./lauxlib.js'); +const { + to_jsstring, + to_luastring +} = require("./fengaricore.js"); let lua_writestring; let lua_writeline; if (typeof process === "undefined") { - let buff = ""; - let decoder = new TextDecoder("utf-8"); - lua_writestring = function(s) { - buff += decoder.decode(s, {stream: true}); - }; - let empty = new Uint8Array(0); - lua_writeline = function() { - buff += decoder.decode(empty); - console.log(buff); - buff = ""; - }; + if (typeof TextDecoder === "function") { /* Older browsers don't have TextDecoder */ + let buff = ""; + let decoder = new TextDecoder("utf-8"); + lua_writestring = function(s) { + buff += decoder.decode(s, {stream: true}); + }; + let empty = new Uint8Array(0); + lua_writeline = function() { + buff += decoder.decode(empty); + console.log(buff); + buff = ""; + }; + } else { + let buff = []; + lua_writestring = function(s) { + try { + /* If the string is valid utf8, then we can use to_jsstring */ + s = to_jsstring(s); + } catch(e) { + /* otherwise push copy of raw array */ + let copy = new Uint8Array(s.length); + copy.set(s); + s = copy; + } + buff.push(s); + }; + lua_writeline = function() { + console.log.apply(console.log, buff); + buff = []; + }; + } } else { lua_writestring = function(s) { process.stdout.write(Buffer.from(s)); @@ -26,79 +119,79 @@ if (typeof process === "undefined") { }; } const luaB_print = function(L) { - let n = lua.lua_gettop(L); /* number of arguments */ - lua.lua_getglobal(L, lua.to_luastring("tostring", true)); + let n = lua_gettop(L); /* number of arguments */ + lua_getglobal(L, to_luastring("tostring", true)); for (let i = 1; i <= n; i++) { - lua.lua_pushvalue(L, -1); /* function to be called */ - lua.lua_pushvalue(L, i); /* value to print */ - lua.lua_call(L, 1, 1); - let s = lua.lua_tolstring(L, -1); + lua_pushvalue(L, -1); /* function to be called */ + lua_pushvalue(L, i); /* value to print */ + lua_call(L, 1, 1); + let s = lua_tolstring(L, -1); if (s === null) - return lauxlib.luaL_error(L, lua.to_luastring("'tostring' must return a string to 'print'", true)); - if (i > 1) lua_writestring(lua.to_luastring("\t")); + return luaL_error(L, to_luastring("'tostring' must return a string to 'print'", true)); + if (i > 1) lua_writestring(to_luastring("\t")); lua_writestring(s); - lua.lua_pop(L, 1); + lua_pop(L, 1); } lua_writeline(); return 0; }; const luaB_tostring = function(L) { - lauxlib.luaL_checkany(L, 1); - lauxlib.luaL_tolstring(L, 1); + luaL_checkany(L, 1); + luaL_tolstring(L, 1); return 1; }; const luaB_getmetatable = function(L) { - lauxlib.luaL_checkany(L, 1); - if (!lua.lua_getmetatable(L, 1)) { - lua.lua_pushnil(L); + luaL_checkany(L, 1); + if (!lua_getmetatable(L, 1)) { + lua_pushnil(L); return 1; /* no metatable */ } - lauxlib.luaL_getmetafield(L, 1, lua.to_luastring("__metatable", true)); + luaL_getmetafield(L, 1, to_luastring("__metatable", true)); return 1; /* returns either __metatable field (if present) or metatable */ }; const luaB_setmetatable = function(L) { - let t = lua.lua_type(L, 2); - lauxlib.luaL_checktype(L, 1, lua.LUA_TTABLE); - lauxlib.luaL_argcheck(L, t === lua.LUA_TNIL || t === lua.LUA_TTABLE, 2, lua.to_luastring("nil or table expected", true)); - if (lauxlib.luaL_getmetafield(L, 1, lua.to_luastring("__metatable", true)) !== lua.LUA_TNIL) - return lauxlib.luaL_error(L, lua.to_luastring("cannot change a protected metatable", true)); - lua.lua_settop(L, 2); - lua.lua_setmetatable(L, 1); + let t = lua_type(L, 2); + luaL_checktype(L, 1, LUA_TTABLE); + luaL_argcheck(L, t === LUA_TNIL || t === LUA_TTABLE, 2, to_luastring("nil or table expected", true)); + if (luaL_getmetafield(L, 1, to_luastring("__metatable", true)) !== LUA_TNIL) + return luaL_error(L, to_luastring("cannot change a protected metatable", true)); + lua_settop(L, 2); + lua_setmetatable(L, 1); return 1; }; const luaB_rawequal = function(L) { - lauxlib.luaL_checkany(L, 1); - lauxlib.luaL_checkany(L, 2); - lua.lua_pushboolean(L, lua.lua_rawequal(L, 1, 2)); + luaL_checkany(L, 1); + luaL_checkany(L, 2); + lua_pushboolean(L, lua_rawequal(L, 1, 2)); return 1; }; const luaB_rawlen = function(L) { - let t = lua.lua_type(L, 1); - lauxlib.luaL_argcheck(L, t === lua.LUA_TTABLE || t === lua.LUA_TSTRING, 1, lua.to_luastring("table or string expected", true)); - lua.lua_pushinteger(L, lua.lua_rawlen(L, 1)); + let t = lua_type(L, 1); + luaL_argcheck(L, t === LUA_TTABLE || t === LUA_TSTRING, 1, to_luastring("table or string expected", true)); + lua_pushinteger(L, lua_rawlen(L, 1)); return 1; }; const luaB_rawget = function(L) { - lauxlib.luaL_checktype(L, 1, lua.LUA_TTABLE); - lauxlib.luaL_checkany(L, 2); - lua.lua_settop(L, 2); - lua.lua_rawget(L, 1); + luaL_checktype(L, 1, LUA_TTABLE); + luaL_checkany(L, 2); + lua_settop(L, 2); + lua_rawget(L, 1); return 1; }; const luaB_rawset = function(L) { - lauxlib.luaL_checktype(L, 1, lua.LUA_TTABLE); - lauxlib.luaL_checkany(L, 2); - lauxlib.luaL_checkany(L, 3); - lua.lua_settop(L, 3); - lua.lua_rawset(L, 1); + luaL_checktype(L, 1, LUA_TTABLE); + luaL_checkany(L, 2); + luaL_checkany(L, 3); + lua_settop(L, 3); + lua_rawset(L, 1); return 1; }; @@ -106,56 +199,56 @@ const opts = [ "stop", "restart", "collect", "count", "step", "setpause", "setstepmul", "isrunning" -].map((e) => lua.to_luastring(e)); +].map((e) => to_luastring(e)); const luaB_collectgarbage = function(L) { - lauxlib.luaL_checkoption(L, 1, lua.to_luastring("collect"), opts); - lauxlib.luaL_optinteger(L, 2, 0); - lauxlib.luaL_error(L, lua.to_luastring("lua_gc not implemented")); + luaL_checkoption(L, 1, to_luastring("collect"), opts); + luaL_optinteger(L, 2, 0); + luaL_error(L, to_luastring("lua_gc not implemented")); }; const luaB_type = function(L) { - let t = lua.lua_type(L, 1); - lauxlib.luaL_argcheck(L, t !== lua.LUA_TNONE, 1, lua.to_luastring("value expected", true)); - lua.lua_pushstring(L, lua.lua_typename(L, t)); + let t = lua_type(L, 1); + luaL_argcheck(L, t !== LUA_TNONE, 1, to_luastring("value expected", true)); + lua_pushstring(L, lua_typename(L, t)); return 1; }; const pairsmeta = function(L, method, iszero, iter) { - lauxlib.luaL_checkany(L, 1); - if (lauxlib.luaL_getmetafield(L, 1, method) === lua.LUA_TNIL) { /* no metamethod? */ - lua.lua_pushcfunction(L, iter); /* will return generator, */ - lua.lua_pushvalue(L, 1); /* state, */ - if (iszero) lua.lua_pushinteger(L, 0); /* and initial value */ - else lua.lua_pushnil(L); + luaL_checkany(L, 1); + if (luaL_getmetafield(L, 1, method) === LUA_TNIL) { /* no metamethod? */ + lua_pushcfunction(L, iter); /* will return generator, */ + lua_pushvalue(L, 1); /* state, */ + if (iszero) lua_pushinteger(L, 0); /* and initial value */ + else lua_pushnil(L); } else { - lua.lua_pushvalue(L, 1); /* argument 'self' to metamethod */ - lua.lua_call(L, 1, 3); /* get 3 values from metamethod */ + lua_pushvalue(L, 1); /* argument 'self' to metamethod */ + lua_call(L, 1, 3); /* get 3 values from metamethod */ } return 3; }; const luaB_next = function(L) { - lauxlib.luaL_checktype(L, 1, lua.LUA_TTABLE); - lua.lua_settop(L, 2); /* create a 2nd argument if there isn't one */ - if (lua.lua_next(L, 1)) + luaL_checktype(L, 1, LUA_TTABLE); + lua_settop(L, 2); /* create a 2nd argument if there isn't one */ + if (lua_next(L, 1)) return 2; else { - lua.lua_pushnil(L); + lua_pushnil(L); return 1; } }; const luaB_pairs = function(L) { - return pairsmeta(L, lua.to_luastring("__pairs", true), 0, luaB_next); + return pairsmeta(L, to_luastring("__pairs", true), 0, luaB_next); }; /* ** Traversal function for 'ipairs' */ const ipairsaux = function(L) { - let i = lauxlib.luaL_checkinteger(L, 2) + 1; - lua.lua_pushinteger(L, i); - return lua.lua_geti(L, 1, i) === lua.LUA_TNIL ? 1 : 2; + let i = luaL_checkinteger(L, 2) + 1; + lua_pushinteger(L, i); + return lua_geti(L, 1, i) === LUA_TNIL ? 1 : 2; }; /* @@ -166,94 +259,86 @@ const luaB_ipairs = function(L) { // Lua 5.2 // return pairsmeta(L, "__ipairs", 1, ipairsaux); - lauxlib.luaL_checkany(L, 1); - lua.lua_pushcfunction(L, ipairsaux); /* iteration function */ - lua.lua_pushvalue(L, 1); /* state */ - lua.lua_pushinteger(L, 0); /* initial value */ + luaL_checkany(L, 1); + lua_pushcfunction(L, ipairsaux); /* iteration function */ + lua_pushvalue(L, 1); /* state */ + lua_pushinteger(L, 0); /* initial value */ return 3; }; const b_str2int = function(s, base) { try { - s = lua.to_jsstring(s); + s = to_jsstring(s); } catch (e) { return null; } let r = /^[\t\v\f \n\r]*([+-]?)0*([0-9A-Za-z]+)[\t\v\f \n\r]*$/.exec(s); if (!r) return null; - let neg = r[1] === "-"; - let digits = r[2]; - let n = 0; - for (let si=0; si<digits.length; si++) { - let digit = /\d/.test(digits[si]) - ? (digits.charCodeAt(si) - '0'.charCodeAt(0)) - : (digits[si].toUpperCase().charCodeAt(0) - 'A'.charCodeAt(0) + 10); - if (digit >= base) return null; /* invalid numeral */ - n = ((n * base)|0) + digit; - } - return (neg ? -n : n)|0; + let v = parseInt(r[1]+r[2], base); + if (isNaN(v)) return null; + return v|0; }; const luaB_tonumber = function(L) { - if (lua.lua_type(L, 2) <= 0) { /* standard conversion? */ - lauxlib.luaL_checkany(L, 1); - if (lua.lua_type(L, 1) === lua.LUA_TNUMBER) { /* already a number? */ - lua.lua_settop(L, 1); + if (lua_type(L, 2) <= 0) { /* standard conversion? */ + luaL_checkany(L, 1); + if (lua_type(L, 1) === LUA_TNUMBER) { /* already a number? */ + lua_settop(L, 1); return 1; } else { - let s = lua.lua_tostring(L, 1); - if (s !== null && lua.lua_stringtonumber(L, s) === s.length+1) + let s = lua_tostring(L, 1); + if (s !== null && lua_stringtonumber(L, s) === s.length+1) return 1; /* successful conversion to number */ } } else { - let base = lauxlib.luaL_checkinteger(L, 2); - lauxlib.luaL_checktype(L, 1, lua.LUA_TSTRING); /* no numbers as strings */ - let s = lua.lua_tostring(L, 1); - lauxlib.luaL_argcheck(L, 2 <= base && base <= 36, 2, lua.to_luastring("base out of range", true)); + let base = luaL_checkinteger(L, 2); + luaL_checktype(L, 1, LUA_TSTRING); /* no numbers as strings */ + let s = lua_tostring(L, 1); + luaL_argcheck(L, 2 <= base && base <= 36, 2, to_luastring("base out of range", true)); let n = b_str2int(s, base); if (n !== null) { - lua.lua_pushinteger(L, n); + lua_pushinteger(L, n); return 1; } } - lua.lua_pushnil(L); + lua_pushnil(L); return 1; }; const luaB_error = function(L) { - let level = lauxlib.luaL_optinteger(L, 2, 1); - lua.lua_settop(L, 1); - if (lua.lua_type(L, 1) === lua.LUA_TSTRING && level > 0) { - lauxlib.luaL_where(L, level); /* add extra information */ - lua.lua_pushvalue(L, 1); - lua.lua_concat(L, 2); + let level = luaL_optinteger(L, 2, 1); + lua_settop(L, 1); + if (lua_type(L, 1) === LUA_TSTRING && level > 0) { + luaL_where(L, level); /* add extra information */ + lua_pushvalue(L, 1); + lua_concat(L, 2); } - return lua.lua_error(L); + return lua_error(L); }; const luaB_assert = function(L) { - if (lua.lua_toboolean(L, 1)) /* condition is true? */ - return lua.lua_gettop(L); /* return all arguments */ + if (lua_toboolean(L, 1)) /* condition is true? */ + return lua_gettop(L); /* return all arguments */ else { - lauxlib.luaL_checkany(L, 1); /* there must be a condition */ - lua.lua_remove(L, 1); /* remove it */ - lua.lua_pushliteral(L, "assertion failed!"); /* default message */ - lua.lua_settop(L, 1); /* leave only message (default if no other one) */ + luaL_checkany(L, 1); /* there must be a condition */ + lua_remove(L, 1); /* remove it */ + lua_pushliteral(L, "assertion failed!"); /* default message */ + lua_settop(L, 1); /* leave only message (default if no other one) */ return luaB_error(L); /* call 'error' */ } }; const luaB_select = function(L) { - let n = lua.lua_gettop(L); - if (lua.lua_type(L, 1) === lua.LUA_TSTRING && lua.lua_tostring(L, 1)[0] === "#".charCodeAt(0)) { - lua.lua_pushinteger(L, n - 1); + let n = lua_gettop(L); + if (lua_type(L, 1) === LUA_TSTRING && lua_tostring(L, 1)[0] === 35 /* '#'.charCodeAt(0) */) { + lua_pushinteger(L, n - 1); return 1; } else { - let i = lauxlib.luaL_checkinteger(L, 1); + let i = luaL_checkinteger(L, 1); if (i < 0) i = n + i; else if (i > n) i = n; - lauxlib.luaL_argcheck(L, 1 <= i, 1, lua.to_luastring("index out of range", true)); + luaL_argcheck(L, 1 <= i, 1, to_luastring("index out of range", true)); return n - i; } }; @@ -266,19 +351,19 @@ const luaB_select = function(L) { ** ignored). */ const finishpcall = function(L, status, extra) { - if (status !== lua.LUA_OK && status !== lua.LUA_YIELD) { /* error? */ - lua.lua_pushboolean(L, 0); /* first result (false) */ - lua.lua_pushvalue(L, -2); /* error message */ + if (status !== LUA_OK && status !== LUA_YIELD) { /* error? */ + lua_pushboolean(L, 0); /* first result (false) */ + lua_pushvalue(L, -2); /* error message */ return 2; /* return false, msg */ } else - return lua.lua_gettop(L) - extra; + return lua_gettop(L) - extra; }; const luaB_pcall = function(L) { - lauxlib.luaL_checkany(L, 1); - lua.lua_pushboolean(L, 1); /* first result if no errors */ - lua.lua_insert(L, 1); /* put it in place */ - let status = lua.lua_pcallk(L, lua.lua_gettop(L) - 2, lua.LUA_MULTRET, 0, 0, finishpcall); + luaL_checkany(L, 1); + lua_pushboolean(L, 1); /* first result if no errors */ + lua_insert(L, 1); /* put it in place */ + let status = lua_pcallk(L, lua_gettop(L) - 2, LUA_MULTRET, 0, 0, finishpcall); return finishpcall(L, status, 0); }; @@ -288,27 +373,27 @@ const luaB_pcall = function(L) { ** 2 to 'finishpcall' to skip the 2 first values when returning results. */ const luaB_xpcall = function(L) { - let n = lua.lua_gettop(L); - lauxlib.luaL_checktype(L, 2, lua.LUA_TFUNCTION); /* check error function */ - lua.lua_pushboolean(L, 1); /* first result */ - lua.lua_pushvalue(L, 1); /* function */ - lua.lua_rotate(L, 3, 2); /* move them below function's arguments */ - let status = lua.lua_pcallk(L, n - 2, lua.LUA_MULTRET, 2, 2, finishpcall); + let n = lua_gettop(L); + luaL_checktype(L, 2, LUA_TFUNCTION); /* check error function */ + lua_pushboolean(L, 1); /* first result */ + lua_pushvalue(L, 1); /* function */ + lua_rotate(L, 3, 2); /* move them below function's arguments */ + let status = lua_pcallk(L, n - 2, LUA_MULTRET, 2, 2, finishpcall); return finishpcall(L, status, 2); }; // TODO: does it overwrite the upvalue of the previous closure ? const load_aux = function(L, status, envidx) { - if (status === lua.LUA_OK) { + if (status === LUA_OK) { if (envidx !== 0) { /* 'env' parameter? */ - lua.lua_pushvalue(L, envidx); /* environment for loaded function */ - if (!lua.lua_setupvalue(L, -2, 1)) /* set it as 1st upvalue */ - lua.lua_pop(L, 1); /* remove 'env' if not used by previous call */ + lua_pushvalue(L, envidx); /* environment for loaded function */ + if (!lua_setupvalue(L, -2, 1)) /* set it as 1st upvalue */ + lua_pop(L, 1); /* remove 'env' if not used by previous call */ } return 1; } else { /* error (message is on top of the stack) */ - lua.lua_pushnil(L); - lua.lua_insert(L, -2); /* put before error message */ + lua_pushnil(L); + lua_insert(L, -2); /* put before error message */ return 2; /* return nil plus error message */ } }; @@ -327,53 +412,53 @@ const RESERVEDSLOT = 5; ** reserved slot inside the stack. */ const generic_reader = function(L, ud) { - lauxlib.luaL_checkstack(L, 2, lua.to_luastring("too many nested functions", true)); - lua.lua_pushvalue(L, 1); /* get function */ - lua.lua_call(L, 0, 1); /* call it */ - if (lua.lua_isnil(L, -1)) { - lua.lua_pop(L, 1); /* pop result */ + luaL_checkstack(L, 2, to_luastring("too many nested functions", true)); + lua_pushvalue(L, 1); /* get function */ + lua_call(L, 0, 1); /* call it */ + if (lua_isnil(L, -1)) { + lua_pop(L, 1); /* pop result */ return null; - } else if (!lua.lua_isstring(L, -1)) - lauxlib.luaL_error(L, lua.to_luastring("reader function must return a string", true)); - lua.lua_replace(L, RESERVEDSLOT); /* save string in reserved slot */ - return lua.lua_tostring(L, RESERVEDSLOT); + } else if (!lua_isstring(L, -1)) + luaL_error(L, to_luastring("reader function must return a string", true)); + lua_replace(L, RESERVEDSLOT); /* save string in reserved slot */ + return lua_tostring(L, RESERVEDSLOT); }; const luaB_load = function(L) { - let s = lua.lua_tostring(L, 1); - let mode = lauxlib.luaL_optstring(L, 3, lua.to_luastring("bt", true)); - let env = !lua.lua_isnone(L, 4) ? 4 : 0; /* 'env' index or 0 if no 'env' */ + let s = lua_tostring(L, 1); + let mode = luaL_optstring(L, 3, to_luastring("bt", true)); + let env = !lua_isnone(L, 4) ? 4 : 0; /* 'env' index or 0 if no 'env' */ let status; if (s !== null) { /* loading a string? */ - let chunkname = lauxlib.luaL_optstring(L, 2, s); - status = lauxlib.luaL_loadbufferx(L, s, s.length, chunkname, mode); + let chunkname = luaL_optstring(L, 2, s); + status = luaL_loadbufferx(L, s, s.length, chunkname, mode); } else { /* loading from a reader function */ - let chunkname = lauxlib.luaL_optstring(L, 2, lua.to_luastring("=(load)", true)); - lauxlib.luaL_checktype(L, 1, lua.LUA_TFUNCTION); - lua.lua_settop(L, RESERVEDSLOT); /* create reserved slot */ - status = lua.lua_load(L, generic_reader, null, chunkname, mode); + let chunkname = luaL_optstring(L, 2, to_luastring("=(load)", true)); + luaL_checktype(L, 1, LUA_TFUNCTION); + lua_settop(L, RESERVEDSLOT); /* create reserved slot */ + status = lua_load(L, generic_reader, null, chunkname, mode); } return load_aux(L, status, env); }; const luaB_loadfile = function(L) { - let fname = lauxlib.luaL_optstring(L, 1, null); - let mode = lauxlib.luaL_optstring(L, 2, null); - let env = !lua.lua_isnone(L, 3) ? 3 : 0; /* 'env' index or 0 if no 'env' */ - let status = lauxlib.luaL_loadfilex(L, fname, mode); + let fname = luaL_optstring(L, 1, null); + let mode = luaL_optstring(L, 2, null); + let env = !lua_isnone(L, 3) ? 3 : 0; /* 'env' index or 0 if no 'env' */ + let status = luaL_loadfilex(L, fname, mode); return load_aux(L, status, env); }; const dofilecont = function(L, d1, d2) { - return lua.lua_gettop(L) - 1; + return lua_gettop(L) - 1; }; const luaB_dofile = function(L) { - let fname = lauxlib.luaL_optstring(L, 1, null); - lua.lua_settop(L, 1); - if (lauxlib.luaL_loadfile(L, fname) !== lua.LUA_OK) - return lua.lua_error(L); - lua.lua_callk(L, 0, lua.LUA_MULTRET, 0, dofilecont); + let fname = luaL_optstring(L, 1, null); + lua_settop(L, 1); + if (luaL_loadfile(L, fname) !== LUA_OK) + return lua_error(L); + lua_callk(L, 0, LUA_MULTRET, 0, dofilecont); return dofilecont(L, 0, 0); }; @@ -404,14 +489,14 @@ const base_funcs = { const luaopen_base = function(L) { /* open lib into global table */ - lua.lua_pushglobaltable(L); - lauxlib.luaL_setfuncs(L, base_funcs, 0); + lua_pushglobaltable(L); + luaL_setfuncs(L, base_funcs, 0); /* set global _G */ - lua.lua_pushvalue(L, -1); - lua.lua_setfield(L, -2, lua.to_luastring("_G", true)); + lua_pushvalue(L, -1); + lua_setfield(L, -2, to_luastring("_G", true)); /* set global _VERSION */ - lua.lua_pushliteral(L, lua.LUA_VERSION); - lua.lua_setfield(L, -2, lua.to_luastring("_VERSION", true)); + lua_pushliteral(L, LUA_VERSION); + lua_setfield(L, -2, to_luastring("_VERSION", true)); return 1; }; diff --git a/src/lcode.js b/src/lcode.js index e7259f2..4d9689a 100644 --- a/src/lcode.js +++ b/src/lcode.js @@ -1,8 +1,30 @@ "use strict"; -const assert = require('assert'); - -const defs = require('./defs.js'); +const { + LUA_MULTRET, + LUA_OPADD, + LUA_OPBAND, + LUA_OPBNOT, + LUA_OPBOR, + LUA_OPBXOR, + LUA_OPDIV, + LUA_OPIDIV, + LUA_OPMOD, + LUA_OPSHL, + LUA_OPSHR, + LUA_OPUNM, + constant_types: { + LUA_TBOOLEAN, + LUA_TLIGHTUSERDATA, + LUA_TLNGSTR, + LUA_TNIL, + LUA_TNUMFLT, + LUA_TNUMINT, + LUA_TTABLE + }, + to_luastring +} = require('./defs.js'); +const { lua_assert } = require("./llimits.js"); const llex = require('./llex.js'); const lobject = require('./lobject.js'); const lopcodes = require('./lopcodes.js'); @@ -10,7 +32,6 @@ const lparser = require('./lparser.js'); const ltable = require('./ltable.js'); const lvm = require('./lvm.js'); -const CT = defs.CT; const OpCodesI = lopcodes.OpCodesI; const TValue = lobject.TValue; @@ -71,12 +92,12 @@ const tonumeral = function(e, make_tvalue) { switch (e.k) { case ek.VKINT: if (make_tvalue) { - return new TValue(CT.LUA_TNUMINT, e.u.ival); + return new TValue(LUA_TNUMINT, e.u.ival); } return true; case ek.VKFLT: if (make_tvalue) { - return new TValue(CT.LUA_TNUMFLT, e.u.nval); + return new TValue(LUA_TNUMFLT, e.u.nval); } return true; default: return false; @@ -133,9 +154,9 @@ const getjump = function(fs, pc) { const fixjump = function(fs, pc, dest) { let jmp = fs.f.code[pc]; let offset = dest - (pc + 1); - assert(dest !== NO_JUMP); + lua_assert(dest !== NO_JUMP); if (Math.abs(offset) > lopcodes.MAXARG_sBx) - llex.luaX_syntaxerror(fs.ls, defs.to_luastring("control structure too long", true)); + llex.luaX_syntaxerror(fs.ls, to_luastring("control structure too long", true)); lopcodes.SETARG_sBx(jmp, offset); }; @@ -291,7 +312,7 @@ const luaK_patchlist = function(fs, list, target) { if (target === fs.pc) /* 'target' is current position? */ luaK_patchtohere(fs, list); /* add list to pending jumps */ else { - assert(target < fs.pc); + lua_assert(target < fs.pc); patchlistaux(fs, list, target, lopcodes.NO_REG, target); } }; @@ -305,7 +326,7 @@ const luaK_patchclose = function(fs, list, level) { level++; /* argument is +1 to reserve 0 as non-op */ for (; list !== NO_JUMP; list = getjump(fs, list)) { let ins = fs.f.code[list]; - assert(ins.opcode === OpCodesI.OP_JMP && (ins.A === 0 || ins.A >= level)); + lua_assert(ins.opcode === OpCodesI.OP_JMP && (ins.A === 0 || ins.A >= level)); lopcodes.SETARG_A(ins, level); } }; @@ -328,10 +349,10 @@ const luaK_code = function(fs, i) { ** of parameters versus opcode.) */ const luaK_codeABC = function(fs, o, a, b, c) { - assert(lopcodes.getOpMode(o) === lopcodes.iABC); - assert(lopcodes.getBMode(o) !== lopcodes.OpArgN || b === 0); - assert(lopcodes.getCMode(o) !== lopcodes.OpArgN || c === 0); - assert(a <= lopcodes.MAXARG_A && b <= lopcodes.MAXARG_B && c <= lopcodes.MAXARG_C); + lua_assert(lopcodes.getOpMode(o) === lopcodes.iABC); + lua_assert(lopcodes.getBMode(o) !== lopcodes.OpArgN || b === 0); + lua_assert(lopcodes.getCMode(o) !== lopcodes.OpArgN || c === 0); + lua_assert(a <= lopcodes.MAXARG_A && b <= lopcodes.MAXARG_B && c <= lopcodes.MAXARG_C); return luaK_code(fs, lopcodes.CREATE_ABC(o, a, b, c)); }; @@ -339,9 +360,9 @@ const luaK_codeABC = function(fs, o, a, b, c) { ** Format and emit an 'iABx' instruction. */ const luaK_codeABx = function(fs, o, a, bc) { - assert(lopcodes.getOpMode(o) === lopcodes.iABx || lopcodes.getOpMode(o) === lopcodes.iAsBx); - assert(lopcodes.getCMode(o) === lopcodes.OpArgN); - assert(a <= lopcodes.MAXARG_A && bc <= lopcodes.MAXARG_Bx); + lua_assert(lopcodes.getOpMode(o) === lopcodes.iABx || lopcodes.getOpMode(o) === lopcodes.iAsBx); + lua_assert(lopcodes.getCMode(o) === lopcodes.OpArgN); + lua_assert(a <= lopcodes.MAXARG_A && bc <= lopcodes.MAXARG_Bx); return luaK_code(fs, lopcodes.CREATE_ABx(o, a, bc)); }; @@ -353,7 +374,7 @@ const luaK_codeAsBx = function(fs,o,A,sBx) { ** Emit an "extra argument" instruction (format 'iAx') */ const codeextraarg = function(fs, a) { - assert(a <= lopcodes.MAXARG_Ax); + lua_assert(a <= lopcodes.MAXARG_Ax); return luaK_code(fs, lopcodes.CREATE_Ax(OpCodesI.OP_EXTRAARG, a)); }; @@ -380,7 +401,7 @@ const luaK_checkstack = function(fs, n) { let newstack = fs.freereg + n; if (newstack > fs.f.maxstacksize) { if (newstack >= MAXREGS) - llex.luaX_syntaxerror(fs.ls, defs.to_luastring("function or expression needs too many registers", true)); + llex.luaX_syntaxerror(fs.ls, to_luastring("function or expression needs too many registers", true)); fs.f.maxstacksize = newstack; } }; @@ -400,7 +421,7 @@ const luaK_reserveregs = function(fs, n) { const freereg = function(fs, reg) { if (!lopcodes.ISK(reg) && reg >= fs.nactvar) { fs.freereg--; - assert(reg === fs.freereg); + lua_assert(reg === fs.freereg); } }; @@ -458,7 +479,7 @@ const addk = function(fs, key, v) { ** Add a string to list of constants and return its index. */ const luaK_stringK = function(fs, s) { - let o = new TValue(CT.LUA_TLNGSTR, s); + let o = new TValue(LUA_TLNGSTR, s); return addk(fs, o, o); /* use string itself as key */ }; @@ -469,8 +490,8 @@ const luaK_stringK = function(fs, s) { ** same value. */ const luaK_intK = function(fs, n) { - let k = new TValue(CT.LUA_TLIGHTUSERDATA, n); - let o = new TValue(CT.LUA_TNUMINT, n); + let k = new TValue(LUA_TLIGHTUSERDATA, n); + let o = new TValue(LUA_TNUMINT, n); return addk(fs, k, o); }; @@ -478,7 +499,7 @@ const luaK_intK = function(fs, n) { ** Add a float to list of constants and return its index. */ const luaK_numberK = function(fs, r) { - let o = new TValue(CT.LUA_TNUMFLT, r); + let o = new TValue(LUA_TNUMFLT, r); return addk(fs, o, o); /* use number itself as key */ }; @@ -487,7 +508,7 @@ const luaK_numberK = function(fs, r) { ** Add a boolean to list of constants and return its index. */ const boolK = function(fs, b) { - let o = new TValue(CT.LUA_TBOOLEAN, b); + let o = new TValue(LUA_TBOOLEAN, b); return addk(fs, o, o); /* use boolean itself as key */ }; @@ -496,8 +517,8 @@ const boolK = function(fs, b) { ** Add nil to list of constants and return its index. */ const nilK = function(fs) { - let v = new TValue(CT.LUA_TNIL, null); - let k = new TValue(CT.LUA_TTABLE, fs.ls.h); + let v = new TValue(LUA_TNIL, null); + let k = new TValue(LUA_TTABLE, fs.ls.h); /* cannot use nil as key; instead use table itself to represent nil */ return addk(fs, k, v); }; @@ -518,11 +539,11 @@ const luaK_setreturns = function(fs, e, nresults) { lopcodes.SETARG_A(pc, fs.freereg); luaK_reserveregs(fs, 1); } - else assert(nresults === defs.LUA_MULTRET); + else lua_assert(nresults === LUA_MULTRET); }; const luaK_setmultret = function(fs, e) { - luaK_setreturns(fs, e, defs.LUA_MULTRET); + luaK_setreturns(fs, e, LUA_MULTRET); }; /* @@ -539,7 +560,7 @@ const luaK_setoneret = function(fs, e) { let ek = lparser.expkind; if (e.k === ek.VCALL) { /* expression is an open function call? */ /* already returns 1 value */ - assert(getinstruction(fs, e).C === 2); + lua_assert(getinstruction(fs, e).C === 2); e.k = ek.VNONRELOC; /* result has fixed position */ e.u.info = getinstruction(fs, e).A; } else if (e.k === ek.VVARARG) { @@ -571,7 +592,7 @@ const luaK_dischargevars = function(fs, e) { freereg(fs, e.u.ind.t); op = OpCodesI.OP_GETTABLE; } else { - assert(e.u.ind.vt === ek.VUPVAL); + lua_assert(e.u.ind.vt === ek.VUPVAL); op = OpCodesI.OP_GETTABUP; /* 't' is in an upvalue */ } e.u.info = luaK_codeABC(fs, op, 0, e.u.ind.t, e.u.ind.idx); @@ -630,7 +651,7 @@ const discharge2reg = function(fs, e, reg) { break; } default: { - assert(e.k === ek.VJMP); + lua_assert(e.k === ek.VJMP); return; /* nothing to do... */ } } @@ -817,7 +838,7 @@ const luaK_self = function(fs, e, key) { */ const negatecondition = function(fs, e) { let pc = getjumpcontrol(fs, e.u.info); - assert(lopcodes.testTMode(pc.opcode) && pc.opcode !== OpCodesI.OP_TESTSET && pc.opcode !== OpCodesI.OP_TEST); + lua_assert(lopcodes.testTMode(pc.opcode) && pc.opcode !== OpCodesI.OP_TESTSET && pc.opcode !== OpCodesI.OP_TEST); lopcodes.SETARG_A(pc, !(pc.A)); }; @@ -934,7 +955,7 @@ const codenot = function(fs, e) { */ const luaK_indexed = function(fs, t, k) { let ek = lparser.expkind; - assert(!hasjumps(t) && (lparser.vkisinreg(t.k) || t.k === ek.VUPVAL)); + lua_assert(!hasjumps(t) && (lparser.vkisinreg(t.k) || t.k === ek.VUPVAL)); t.u.ind.t = t.u.info; /* register or upvalue index */ t.u.ind.idx = luaK_exp2RK(fs, k); /* R/K index for key */ t.u.ind.vt = (t.k === ek.VUPVAL) ? ek.VUPVAL : ek.VLOCAL; @@ -948,11 +969,11 @@ const luaK_indexed = function(fs, t, k) { */ const validop = function(op, v1, v2) { switch (op) { - case defs.LUA_OPBAND: case defs.LUA_OPBOR: case defs.LUA_OPBXOR: - case defs.LUA_OPSHL: case defs.LUA_OPSHR: case defs.LUA_OPBNOT: { /* conversion errors */ + case LUA_OPBAND: case LUA_OPBOR: case LUA_OPBXOR: + case LUA_OPSHL: case LUA_OPSHR: case LUA_OPBNOT: { /* conversion errors */ return (lvm.tointeger(v1) !== false && lvm.tointeger(v2) !== false); } - case defs.LUA_OPDIV: case defs.LUA_OPIDIV: case defs.LUA_OPMOD: /* division by 0 */ + case LUA_OPDIV: case LUA_OPIDIV: case LUA_OPMOD: /* division by 0 */ return (v2.value !== 0); default: return 1; /* everything else is valid */ } @@ -1026,7 +1047,7 @@ const codecomp = function(fs, opr, e1, e2) { if (e1.k === ek.VK) rk1 = lopcodes.RKASK(e1.u.info); else { - assert(e1.k === ek.VNONRELOC); + lua_assert(e1.k === ek.VNONRELOC); rk1 = e1.u.info; } @@ -1063,7 +1084,7 @@ const luaK_prefix = function(fs, op, e, line) { ef.f = NO_JUMP; switch (op) { case UnOpr.OPR_MINUS: case UnOpr.OPR_BNOT: /* use 'ef' as fake 2nd operand */ - if (constfolding(op + defs.LUA_OPUNM, e, ef)) + if (constfolding(op + LUA_OPUNM, e, ef)) break; /* FALLTHROUGH */ case UnOpr.OPR_LEN: @@ -1118,14 +1139,14 @@ const luaK_posfix = function(fs, op, e1, e2, line) { let ek = lparser.expkind; switch (op) { case BinOpr.OPR_AND: { - assert(e1.t === NO_JUMP); /* list closed by 'luK_infix' */ + lua_assert(e1.t === NO_JUMP); /* list closed by 'luK_infix' */ luaK_dischargevars(fs, e2); e2.f = luaK_concat(fs, e2.f, e1.f); e1.to(e2); break; } case BinOpr.OPR_OR: { - assert(e1.f === NO_JUMP); /* list closed by 'luK_infix' */ + lua_assert(e1.f === NO_JUMP); /* list closed by 'luK_infix' */ luaK_dischargevars(fs, e2); e2.t = luaK_concat(fs, e2.t, e1.t); e1.to(e2); @@ -1135,7 +1156,7 @@ const luaK_posfix = function(fs, op, e1, e2, line) { luaK_exp2val(fs, e2); let ins = getinstruction(fs, e2); if (e2.k === ek.VRELOCABLE && ins.opcode === OpCodesI.OP_CONCAT) { - assert(e1.u.info === ins.B - 1); + lua_assert(e1.u.info === ins.B - 1); freeexp(fs, e1); lopcodes.SETARG_B(ins, e1.u.info); e1.k = ek.VRELOCABLE; e1.u.info = e2.u.info; @@ -1150,7 +1171,7 @@ const luaK_posfix = function(fs, op, e1, e2, line) { case BinOpr.OPR_IDIV: case BinOpr.OPR_MOD: case BinOpr.OPR_POW: case BinOpr.OPR_BAND: case BinOpr.OPR_BOR: case BinOpr.OPR_BXOR: case BinOpr.OPR_SHL: case BinOpr.OPR_SHR: { - if (!constfolding(op + defs.LUA_OPADD, e1, e2)) + if (!constfolding(op + LUA_OPADD, e1, e2)) codebinexpval(fs, op + OpCodesI.OP_ADD, e1, e2, line); break; } @@ -1180,8 +1201,8 @@ const luaK_fixline = function(fs, line) { */ const luaK_setlist = function(fs, base, nelems, tostore) { let c = (nelems - 1)/lopcodes.LFIELDS_PER_FLUSH + 1; - let b = (tostore === defs.LUA_MULTRET) ? 0 : tostore; - assert(tostore !== 0 && tostore <= lopcodes.LFIELDS_PER_FLUSH); + let b = (tostore === LUA_MULTRET) ? 0 : tostore; + lua_assert(tostore !== 0 && tostore <= lopcodes.LFIELDS_PER_FLUSH); if (c <= lopcodes.MAXARG_C) luaK_codeABC(fs, OpCodesI.OP_SETLIST, base, b, c); else if (c <= lopcodes.MAXARG_Ax) { @@ -1189,7 +1210,7 @@ const luaK_setlist = function(fs, base, nelems, tostore) { codeextraarg(fs, c); } else - llex.luaX_syntaxerror(fs.ls, defs.to_luastring("constructor too long", true)); + llex.luaX_syntaxerror(fs.ls, to_luastring("constructor too long", true)); fs.freereg = base + 1; /* free registers with list values */ }; diff --git a/src/lcorolib.js b/src/lcorolib.js index a72d22b..eb402b8 100644 --- a/src/lcorolib.js +++ b/src/lcorolib.js @@ -1,111 +1,144 @@ "use strict"; -const lua = require('./lua.js'); -const lauxlib = require('./lauxlib.js'); +const { + LUA_OK, + LUA_TFUNCTION, + LUA_TSTRING, + LUA_YIELD, + lua_Debug, + lua_checkstack, + lua_concat, + lua_error, + lua_getstack, + lua_gettop, + lua_insert, + lua_isyieldable, + lua_newthread, + lua_pop, + lua_pushboolean, + lua_pushcclosure, + lua_pushliteral, + lua_pushthread, + lua_pushvalue, + lua_resume, + lua_status, + lua_tothread, + lua_type, + lua_upvalueindex, + lua_xmove, + lua_yield +} = require('./lua.js'); +const { + luaL_argcheck, + luaL_checktype, + luaL_newlib, + luaL_where +} = require('./lauxlib.js'); +const { to_luastring } = require("./fengaricore.js"); const getco = function(L) { - let co = lua.lua_tothread(L, 1); - lauxlib.luaL_argcheck(L, co, 1, lua.to_luastring("thread expected", true)); + let co = lua_tothread(L, 1); + luaL_argcheck(L, co, 1, to_luastring("thread expected", true)); return co; }; const auxresume = function(L, co, narg) { - if (!lua.lua_checkstack(co, narg)) { - lua.lua_pushliteral(L, "too many arguments to resume"); + if (!lua_checkstack(co, narg)) { + lua_pushliteral(L, "too many arguments to resume"); return -1; /* error flag */ } - if (lua.lua_status(co) === lua.LUA_OK && lua.lua_gettop(co) === 0) { - lua.lua_pushliteral(L, "cannot resume dead coroutine"); + if (lua_status(co) === LUA_OK && lua_gettop(co) === 0) { + lua_pushliteral(L, "cannot resume dead coroutine"); return -1; /* error flag */ } - lua.lua_xmove(L, co, narg); - let status = lua.lua_resume(co, L, narg); - if (status === lua.LUA_OK || status === lua.LUA_YIELD) { - let nres = lua.lua_gettop(co); - if (!lua.lua_checkstack(L, nres + 1)) { - lua.lua_pop(co, nres); /* remove results anyway */ - lua.lua_pushliteral(L, "too many results to resume"); + lua_xmove(L, co, narg); + let status = lua_resume(co, L, narg); + if (status === LUA_OK || status === LUA_YIELD) { + let nres = lua_gettop(co); + if (!lua_checkstack(L, nres + 1)) { + lua_pop(co, nres); /* remove results anyway */ + lua_pushliteral(L, "too many results to resume"); return -1; /* error flag */ } - lua.lua_xmove(co, L, nres); /* move yielded values */ + lua_xmove(co, L, nres); /* move yielded values */ return nres; } else { - lua.lua_xmove(co, L, 1); /* move error message */ + lua_xmove(co, L, 1); /* move error message */ return -1; /* error flag */ } }; const luaB_coresume = function(L) { let co = getco(L); - let r = auxresume(L, co, lua.lua_gettop(L) - 1); + let r = auxresume(L, co, lua_gettop(L) - 1); if (r < 0) { - lua.lua_pushboolean(L, 0); - lua.lua_insert(L, -2); + lua_pushboolean(L, 0); + lua_insert(L, -2); return 2; /* return false + error message */ } else { - lua.lua_pushboolean(L, 1); - lua.lua_insert(L, -(r + 1)); + lua_pushboolean(L, 1); + lua_insert(L, -(r + 1)); return r + 1; /* return true + 'resume' returns */ } }; const luaB_auxwrap = function(L) { - let co = lua.lua_tothread(L, lua.lua_upvalueindex(1)); - let r = auxresume(L, co, lua.lua_gettop(L)); + let co = lua_tothread(L, lua_upvalueindex(1)); + let r = auxresume(L, co, lua_gettop(L)); if (r < 0) { - if (lua.lua_type(L, -1) === lua.LUA_TSTRING) { /* error object is a string? */ - lauxlib.luaL_where(L, 1); /* add extra info */ - lua.lua_insert(L, -2); - lua.lua_concat(L, 2); + if (lua_type(L, -1) === LUA_TSTRING) { /* error object is a string? */ + luaL_where(L, 1); /* add extra info */ + lua_insert(L, -2); + lua_concat(L, 2); } - return lua.lua_error(L); /* propagate error */ + return lua_error(L); /* propagate error */ } return r; }; const luaB_cocreate = function(L) { - lauxlib.luaL_checktype(L, 1, lua.LUA_TFUNCTION); - let NL = lua.lua_newthread(L); - lua.lua_pushvalue(L, 1); /* move function to top */ - lua.lua_xmove(L, NL, 1); /* move function from L to NL */ + luaL_checktype(L, 1, LUA_TFUNCTION); + let NL = lua_newthread(L); + lua_pushvalue(L, 1); /* move function to top */ + lua_xmove(L, NL, 1); /* move function from L to NL */ return 1; }; const luaB_cowrap = function(L) { luaB_cocreate(L); - lua.lua_pushcclosure(L, luaB_auxwrap, 1); + lua_pushcclosure(L, luaB_auxwrap, 1); return 1; }; const luaB_yield = function(L) { - return lua.lua_yield(L, lua.lua_gettop(L)); + return lua_yield(L, lua_gettop(L)); }; const luaB_costatus = function(L) { let co = getco(L); - if (L === co) lua.lua_pushliteral(L, "running"); + if (L === co) lua_pushliteral(L, "running"); else { - switch (lua.lua_status(co)) { - case lua.LUA_YIELD: - lua.lua_pushliteral(L, "suspended"); + switch (lua_status(co)) { + case LUA_YIELD: + lua_pushliteral(L, "suspended"); break; - case lua.LUA_OK: { - let ar = new lua.lua_Debug(); - if (lua.lua_getstack(co, 0, ar) > 0) /* does it have frames? */ - lua.lua_pushliteral(L, "normal"); /* it is running */ - else if (lua.lua_gettop(co) === 0) - lua.lua_pushliteral(L, "dead"); + case LUA_OK: { + let ar = new lua_Debug(); + if (lua_getstack(co, 0, ar) > 0) /* does it have frames? */ + lua_pushliteral(L, "normal"); /* it is running */ + else if (lua_gettop(co) === 0) + lua_pushliteral(L, "dead"); else - lua.lua_pushliteral(L, "suspended"); /* initial state */ + lua_pushliteral(L, "suspended"); /* initial state */ break; } default: /* some error occurred */ - lua.lua_pushliteral(L, "dead"); + lua_pushliteral(L, "dead"); break; } } @@ -114,12 +147,12 @@ const luaB_costatus = function(L) { }; const luaB_yieldable = function(L) { - lua.lua_pushboolean(L, lua.lua_isyieldable(L)); + lua_pushboolean(L, lua_isyieldable(L)); return 1; }; const luaB_corunning = function(L) { - lua.lua_pushboolean(L, lua.lua_pushthread(L)); + lua_pushboolean(L, lua_pushthread(L)); return 2; }; @@ -134,7 +167,7 @@ const co_funcs = { }; const luaopen_coroutine = function(L) { - lauxlib.luaL_newlib(L, co_funcs); + luaL_newlib(L, co_funcs); return 1; }; diff --git a/src/ldblib.js b/src/ldblib.js index e687ec1..991f8cd 100644 --- a/src/ldblib.js +++ b/src/ldblib.js @@ -1,9 +1,86 @@ "use strict"; -const assert = require('assert'); - -const lua = require('./lua.js'); -const lauxlib = require('./lauxlib.js'); +const { + LUA_MASKCALL, + LUA_MASKCOUNT, + LUA_MASKLINE, + LUA_MASKRET, + LUA_REGISTRYINDEX, + LUA_TFUNCTION, + LUA_TNIL, + LUA_TTABLE, + LUA_TUSERDATA, + lua_Debug, + lua_call, + lua_checkstack, + lua_createtable, + lua_gethook, + lua_gethookcount, + lua_gethookmask, + lua_getinfo, + lua_getlocal, + lua_getmetatable, + lua_getstack, + lua_getupvalue, + lua_getuservalue, + lua_insert, + lua_iscfunction, + lua_isfunction, + lua_isnoneornil, + lua_isthread, + lua_newtable, + lua_pcall, + lua_pop, + lua_pushboolean, + lua_pushfstring, + lua_pushinteger, + lua_pushlightuserdata, + lua_pushliteral, + lua_pushnil, + lua_pushstring, + lua_pushthread, + lua_pushvalue, + lua_rawget, + lua_rawgetp, + lua_rawset, + lua_rawsetp, + lua_remove, + lua_rotate, + lua_setfield, + lua_sethook, + lua_setlocal, + lua_setmetatable, + lua_settop, + lua_setupvalue, + lua_setuservalue, + lua_tojsstring, + lua_tostring, + lua_tothread, + lua_type, + lua_upvalueid, + lua_upvaluejoin, + lua_xmove +} = require('./lua.js'); +const { + luaL_argcheck, + luaL_argerror, + luaL_checkany, + luaL_checkinteger, + luaL_checkstring, + luaL_checktype, + luaL_error, + luaL_loadbuffer, + luaL_newlib, + luaL_optinteger, + luaL_optstring, + luaL_traceback, + lua_writestringerror +} = require('./lauxlib.js'); +const lualib = require('./lualib.js'); +const { + luastring_indexOf, + to_luastring +} = require("./fengaricore.js"); /* ** If L1 != L, L1 can be in any state, and therefore there are no @@ -11,45 +88,45 @@ const lauxlib = require('./lauxlib.js'); ** checked. */ const checkstack = function(L, L1, n) { - if (L !== L1 && !lua.lua_checkstack(L1, n)) - lauxlib.luaL_error(L, lua.to_luastring("stack overflow", true)); + if (L !== L1 && !lua_checkstack(L1, n)) + luaL_error(L, to_luastring("stack overflow", true)); }; const db_getregistry = function(L) { - lua.lua_pushvalue(L, lua.LUA_REGISTRYINDEX); + lua_pushvalue(L, LUA_REGISTRYINDEX); return 1; }; const db_getmetatable = function(L) { - lauxlib.luaL_checkany(L, 1); - if (!lua.lua_getmetatable(L, 1)) { - lua.lua_pushnil(L); /* no metatable */ + luaL_checkany(L, 1); + if (!lua_getmetatable(L, 1)) { + lua_pushnil(L); /* no metatable */ } return 1; }; const db_setmetatable = function(L) { - const t = lua.lua_type(L, 2); - lauxlib.luaL_argcheck(L, t == lua.LUA_TNIL || t == lua.LUA_TTABLE, 2, lua.to_luastring("nil or table expected", true)); - lua.lua_settop(L, 2); - lua.lua_setmetatable(L, 1); + const t = lua_type(L, 2); + luaL_argcheck(L, t == LUA_TNIL || t == LUA_TTABLE, 2, to_luastring("nil or table expected", true)); + lua_settop(L, 2); + lua_setmetatable(L, 1); return 1; /* return 1st argument */ }; const db_getuservalue = function(L) { - if (lua.lua_type(L, 1) !== lua.LUA_TUSERDATA) - lua.lua_pushnil(L); + if (lua_type(L, 1) !== LUA_TUSERDATA) + lua_pushnil(L); else - lua.lua_getuservalue(L, 1); + lua_getuservalue(L, 1); return 1; }; const db_setuservalue = function(L) { - lauxlib.luaL_checktype(L, 1, lua.LUA_TUSERDATA); - lauxlib.luaL_checkany(L, 2); - lua.lua_settop(L, 2); - lua.lua_setuservalue(L, 1); + luaL_checktype(L, 1, LUA_TUSERDATA); + luaL_checkany(L, 2); + lua_settop(L, 2); + lua_setuservalue(L, 1); return 1; }; @@ -60,10 +137,10 @@ const db_setuservalue = function(L) { ** access their other arguments) */ const getthread = function(L) { - if (lua.lua_isthread(L, 1)) { + if (lua_isthread(L, 1)) { return { arg: 1, - thread: lua.lua_tothread(L, 1) + thread: lua_tothread(L, 1) }; } else { return { @@ -79,18 +156,18 @@ const getthread = function(L) { ** value can be a string, an int, or a boolean. */ const settabss = function(L, k, v) { - lua.lua_pushstring(L, v); - lua.lua_setfield(L, -2, k); + lua_pushstring(L, v); + lua_setfield(L, -2, k); }; const settabsi = function(L, k, v) { - lua.lua_pushinteger(L, v); - lua.lua_setfield(L, -2, k); + lua_pushinteger(L, v); + lua_setfield(L, -2, k); }; const settabsb = function(L, k, v) { - lua.lua_pushboolean(L, v); - lua.lua_setfield(L, -2, k); + lua_pushboolean(L, v); + lua_setfield(L, -2, k); }; @@ -103,10 +180,10 @@ const settabsb = function(L, k, v) { */ const treatstackoption = function(L, L1, fname) { if (L == L1) - lua.lua_rotate(L, -2, 1); /* exchange object and table */ + lua_rotate(L, -2, 1); /* exchange object and table */ else - lua.lua_xmove(L1, L, 1); /* move object to the "main" stack */ - lua.lua_setfield(L, -2, fname); /* put object into table */ + lua_xmove(L1, L, 1); /* move object to the "main" stack */ + lua_setfield(L, -2, fname); /* put object into table */ }; /* @@ -116,50 +193,50 @@ const treatstackoption = function(L, L1, fname) { ** 'lua_getinfo'. */ const db_getinfo = function(L) { - let ar = new lua.lua_Debug(); + let ar = new lua_Debug(); let thread = getthread(L); let arg = thread.arg; let L1 = thread.thread; - let options = lauxlib.luaL_optstring(L, arg + 2, lua.to_luastring("flnStu", true)); + let options = luaL_optstring(L, arg + 2, to_luastring("flnStu", true)); checkstack(L, L1, 3); - if (lua.lua_isfunction(L, arg + 1)) { /* info about a function? */ - options = lua.lua_pushfstring(L, lua.to_luastring(">%s"), options); /* add '>' to 'options' */ - lua.lua_pushvalue(L, arg + 1); /* move function to 'L1' stack */ - lua.lua_xmove(L, L1, 1); + if (lua_isfunction(L, arg + 1)) { /* info about a function? */ + options = lua_pushfstring(L, to_luastring(">%s"), options); /* add '>' to 'options' */ + lua_pushvalue(L, arg + 1); /* move function to 'L1' stack */ + lua_xmove(L, L1, 1); } else { /* stack level */ - if (!lua.lua_getstack(L1, lauxlib.luaL_checkinteger(L, arg + 1), ar)) { - lua.lua_pushnil(L); /* level out of range */ + if (!lua_getstack(L1, luaL_checkinteger(L, arg + 1), ar)) { + lua_pushnil(L); /* level out of range */ return 1; } } - if (!lua.lua_getinfo(L1, options, ar)) - lauxlib.luaL_argerror(L, arg + 2, lua.to_luastring("invalid option", true)); - lua.lua_newtable(L); /* table to collect results */ - if (options.indexOf('S'.charCodeAt(0)) > -1) { - settabss(L, lua.to_luastring("source", true), ar.source); - settabss(L, lua.to_luastring("short_src", true), ar.short_src); - settabsi(L, lua.to_luastring("linedefined", true), ar.linedefined); - settabsi(L, lua.to_luastring("lastlinedefined", true), ar.lastlinedefined); - settabss(L, lua.to_luastring("what", true), ar.what); + if (!lua_getinfo(L1, options, ar)) + luaL_argerror(L, arg + 2, to_luastring("invalid option", true)); + lua_newtable(L); /* table to collect results */ + if (luastring_indexOf(options, 83 /* 'S'.charCodeAt(0) */) > -1) { + settabss(L, to_luastring("source", true), ar.source); + settabss(L, to_luastring("short_src", true), ar.short_src); + settabsi(L, to_luastring("linedefined", true), ar.linedefined); + settabsi(L, to_luastring("lastlinedefined", true), ar.lastlinedefined); + settabss(L, to_luastring("what", true), ar.what); } - if (options.indexOf('l'.charCodeAt(0)) > -1) - settabsi(L, lua.to_luastring("currentline", true), ar.currentline); - if (options.indexOf('u'.charCodeAt(0)) > -1) { - settabsi(L, lua.to_luastring("nups", true), ar.nups); - settabsi(L, lua.to_luastring("nparams", true), ar.nparams); - settabsb(L, lua.to_luastring("isvararg", true), ar.isvararg); + if (luastring_indexOf(options, 108 /* 'l'.charCodeAt(0) */) > -1) + settabsi(L, to_luastring("currentline", true), ar.currentline); + if (luastring_indexOf(options, 117 /* 'u'.charCodeAt(0) */) > -1) { + settabsi(L, to_luastring("nups", true), ar.nups); + settabsi(L, to_luastring("nparams", true), ar.nparams); + settabsb(L, to_luastring("isvararg", true), ar.isvararg); } - if (options.indexOf('n'.charCodeAt(0)) > - 1) { - settabss(L, lua.to_luastring("name", true), ar.name); - settabss(L, lua.to_luastring("namewhat", true), ar.namewhat); + if (luastring_indexOf(options, 110 /* 'n'.charCodeAt(0) */) > -1) { + settabss(L, to_luastring("name", true), ar.name); + settabss(L, to_luastring("namewhat", true), ar.namewhat); } - if (options.indexOf('t'.charCodeAt(0)) > - 1) - settabsb(L, lua.to_luastring("istailcall", true), ar.istailcall); - if (options.indexOf('L'.charCodeAt(0)) > - 1) - treatstackoption(L, L1, lua.to_luastring("activelines", true)); - if (options.indexOf('f'.charCodeAt(0)) > - 1) - treatstackoption(L, L1, lua.to_luastring("func", true)); + if (luastring_indexOf(options, 116 /* 't'.charCodeAt(0) */) > -1) + settabsb(L, to_luastring("istailcall", true), ar.istailcall); + if (luastring_indexOf(options, 76 /* 'L'.charCodeAt(0) */) > -1) + treatstackoption(L, L1, to_luastring("activelines", true)); + if (luastring_indexOf(options, 102 /* 'f'.charCodeAt(0) */) > -1) + treatstackoption(L, L1, to_luastring("func", true)); return 1; /* return table */ }; @@ -167,26 +244,26 @@ const db_getlocal = function(L) { let thread = getthread(L); let L1 = thread.thread; let arg = thread.arg; - let ar = new lua.lua_Debug(); - let nvar = lauxlib.luaL_checkinteger(L, arg + 2); /* local-variable index */ - if (lua.lua_isfunction(L, arg + 1)) { - lua.lua_pushvalue(L, arg + 1); /* push function */ - lua.lua_pushstring(L, lua.lua_getlocal(L, null, nvar)); /* push local name */ + let ar = new lua_Debug(); + let nvar = luaL_checkinteger(L, arg + 2); /* local-variable index */ + if (lua_isfunction(L, arg + 1)) { + lua_pushvalue(L, arg + 1); /* push function */ + lua_pushstring(L, lua_getlocal(L, null, nvar)); /* push local name */ return 1; /* return only name (there is no value) */ } else { /* stack-level argument */ - let level = lauxlib.luaL_checkinteger(L, arg + 1); - if (!lua.lua_getstack(L1, level, ar)) /* out of range? */ - return lauxlib.luaL_argerror(L, arg+1, lua.to_luastring("level out of range", true)); + let level = luaL_checkinteger(L, arg + 1); + if (!lua_getstack(L1, level, ar)) /* out of range? */ + return luaL_argerror(L, arg+1, to_luastring("level out of range", true)); checkstack(L, L1, 1); - let name = lua.lua_getlocal(L1, ar, nvar); + let name = lua_getlocal(L1, ar, nvar); if (name) { - lua.lua_xmove(L1, L, 1); /* move local value */ - lua.lua_pushstring(L, name); /* push name */ - lua.lua_rotate(L, -2, 1); /* re-order */ + lua_xmove(L1, L, 1); /* move local value */ + lua_pushstring(L, name); /* push name */ + lua_rotate(L, -2, 1); /* re-order */ return 2; } else { - lua.lua_pushnil(L); /* no name (nor value) */ + lua_pushnil(L); /* no name (nor value) */ return 1; } } @@ -196,19 +273,19 @@ const db_setlocal = function(L) { let thread = getthread(L); let L1 = thread.thread; let arg = thread.arg; - let ar = new lua.lua_Debug(); - let level = lauxlib.luaL_checkinteger(L, arg + 1); - let nvar = lauxlib.luaL_checkinteger(L, arg + 2); - if (!lua.lua_getstack(L1, level, ar)) /* out of range? */ - return lauxlib.luaL_argerror(L, arg + 1, lua.to_luastring("level out of range", true)); - lauxlib.luaL_checkany(L, arg + 3); - lua.lua_settop(L, arg + 3); + let ar = new lua_Debug(); + let level = luaL_checkinteger(L, arg + 1); + let nvar = luaL_checkinteger(L, arg + 2); + if (!lua_getstack(L1, level, ar)) /* out of range? */ + return luaL_argerror(L, arg + 1, to_luastring("level out of range", true)); + luaL_checkany(L, arg + 3); + lua_settop(L, arg + 3); checkstack(L, L1, 1); - lua.lua_xmove(L, L1, 1); - let name = lua.lua_setlocal(L1, ar, nvar); + lua_xmove(L, L1, 1); + let name = lua_setlocal(L1, ar, nvar); if (name === null) - lua.lua_pop(L1, 1); /* pop value (if not popped by 'lua_setlocal') */ - lua.lua_pushstring(L, name); + lua_pop(L1, 1); /* pop value (if not popped by 'lua_setlocal') */ + lua_pushstring(L, name); return 1; }; @@ -216,12 +293,12 @@ const db_setlocal = function(L) { ** get (if 'get' is true) or set an upvalue from a closure */ const auxupvalue = function(L, get) { - let n = lauxlib.luaL_checkinteger(L, 2); /* upvalue index */ - lauxlib.luaL_checktype(L, 1, lua.LUA_TFUNCTION); /* closure */ - let name = get ? lua.lua_getupvalue(L, 1, n) : lua.lua_setupvalue(L, 1, n); + let n = luaL_checkinteger(L, 2); /* upvalue index */ + luaL_checktype(L, 1, LUA_TFUNCTION); /* closure */ + let name = get ? lua_getupvalue(L, 1, n) : lua_setupvalue(L, 1, n); if (name === null) return 0; - lua.lua_pushstring(L, name); - lua.lua_insert(L, -(get+1)); /* no-op if get is false */ + lua_pushstring(L, name); + lua_insert(L, -(get+1)); /* no-op if get is false */ return get + 1; }; @@ -231,7 +308,7 @@ const db_getupvalue = function(L) { }; const db_setupvalue = function(L) { - lauxlib.luaL_checkany(L, 3); + luaL_checkany(L, 3); return auxupvalue(L, 0); }; @@ -240,24 +317,24 @@ const db_setupvalue = function(L) { ** returns its index */ const checkupval = function(L, argf, argnup) { - let nup = lauxlib.luaL_checkinteger(L, argnup); /* upvalue index */ - lauxlib.luaL_checktype(L, argf, lua.LUA_TFUNCTION); /* closure */ - lauxlib.luaL_argcheck(L, (lua.lua_getupvalue(L, argf, nup) !== null), argnup, lua.to_luastring("invalid upvalue index", true)); + let nup = luaL_checkinteger(L, argnup); /* upvalue index */ + luaL_checktype(L, argf, LUA_TFUNCTION); /* closure */ + luaL_argcheck(L, (lua_getupvalue(L, argf, nup) !== null), argnup, to_luastring("invalid upvalue index", true)); return nup; }; const db_upvalueid = function(L) { let n = checkupval(L, 1, 2); - lua.lua_pushlightuserdata(L, lua.lua_upvalueid(L, 1, n)); + lua_pushlightuserdata(L, lua_upvalueid(L, 1, n)); return 1; }; const db_upvaluejoin = function(L) { let n1 = checkupval(L, 1, 2); let n2 = checkupval(L, 3, 4); - lauxlib.luaL_argcheck(L, !lua.lua_iscfunction(L, 1), 1, lua.to_luastring("Lua function expected", true)); - lauxlib.luaL_argcheck(L, !lua.lua_iscfunction(L, 3), 3, lua.to_luastring("Lua function expected", true)); - lua.lua_upvaluejoin(L, 1, n1, 3, n2); + luaL_argcheck(L, !lua_iscfunction(L, 1), 1, to_luastring("Lua function expected", true)); + luaL_argcheck(L, !lua_iscfunction(L, 3), 3, to_luastring("Lua function expected", true)); + lua_upvaluejoin(L, 1, n1, 3, n2); return 0; }; @@ -265,24 +342,24 @@ const db_upvaluejoin = function(L) { ** The hook table at registry[HOOKKEY] maps threads to their current ** hook function. (We only need the unique address of 'HOOKKEY'.) */ -const HOOKKEY = lua.to_luastring("__hooks__", true); +const HOOKKEY = to_luastring("__hooks__", true); -const hooknames = ["call", "return", "line", "count", "tail call"].map(e => lua.to_luastring(e)); +const hooknames = ["call", "return", "line", "count", "tail call"].map(e => to_luastring(e)); /* ** Call hook function registered at hook table for the current ** thread (if there is one) */ const hookf = function(L, ar) { - lua.lua_rawgetp(L, lua.LUA_REGISTRYINDEX, HOOKKEY); - lua.lua_pushthread(L); - if (lua.lua_rawget(L, -2) === lua.LUA_TFUNCTION) { /* is there a hook function? */ - lua.lua_pushstring(L, hooknames[ar.event]); /* push event name */ + lua_rawgetp(L, LUA_REGISTRYINDEX, HOOKKEY); + lua_pushthread(L); + if (lua_rawget(L, -2) === LUA_TFUNCTION) { /* is there a hook function? */ + lua_pushstring(L, hooknames[ar.event]); /* push event name */ if (ar.currentline >= 0) - lua.lua_pushinteger(L, ar.currentline); /* push current line */ - else lua.lua_pushnil(L); - assert(lua.lua_getinfo(L, lua.to_luastring("lS"), ar)); - lua.lua_call(L, 2, 0); /* call hook function */ + lua_pushinteger(L, ar.currentline); /* push current line */ + else lua_pushnil(L); + lualib.lua_assert(lua_getinfo(L, to_luastring("lS"), ar)); + lua_call(L, 2, 0); /* call hook function */ } }; @@ -291,10 +368,10 @@ const hookf = function(L, ar) { */ const makemask = function(smask, count) { let mask = 0; - if (smask.indexOf("c".charCodeAt(0)) > -1) mask |= lua.LUA_MASKCALL; - if (smask.indexOf("r".charCodeAt(0)) > -1) mask |= lua.LUA_MASKRET; - if (smask.indexOf("l".charCodeAt(0)) > -1) mask |= lua.LUA_MASKLINE; - if (count > 0) mask |= lua.LUA_MASKCOUNT; + if (luastring_indexOf(smask, 99 /* 'c'.charCodeAt(0) */) > -1) mask |= LUA_MASKCALL; + if (luastring_indexOf(smask, 114 /* 'r'.charCodeAt(0) */) > -1) mask |= LUA_MASKRET; + if (luastring_indexOf(smask, 108 /* 'l'.charCodeAt(0) */) > -1) mask |= LUA_MASKLINE; + if (count > 0) mask |= LUA_MASKCOUNT; return mask; }; @@ -303,9 +380,9 @@ const makemask = function(smask, count) { */ const unmakemask = function(mask, smask) { let i = 0; - if (mask & lua.LUA_MASKCALL) smask[i++] = "c".charCodeAt(0); - if (mask & lua.LUA_MASKRET) smask[i++] = "r".charCodeAt(0); - if (mask & lua.LUA_MASKLINE) smask[i++] = "l".charCodeAt(0); + if (mask & LUA_MASKCALL) smask[i++] = 99 /* 'c'.charCodeAt(0) */; + if (mask & LUA_MASKRET) smask[i++] = 114 /* 'r'.charCodeAt(0) */; + if (mask & LUA_MASKLINE) smask[i++] = 108 /* 'l'.charCodeAt(0) */; return smask.subarray(0, i); }; @@ -314,30 +391,30 @@ const db_sethook = function(L) { let thread = getthread(L); let L1 = thread.thread; let arg = thread.arg; - if (lua.lua_isnoneornil(L, arg+1)) { /* no hook? */ - lua.lua_settop(L, arg+1); + if (lua_isnoneornil(L, arg+1)) { /* no hook? */ + lua_settop(L, arg+1); func = null; mask = 0; count = 0; /* turn off hooks */ } else { - const smask = lauxlib.luaL_checkstring(L, arg + 2); - lauxlib.luaL_checktype(L, arg+1, lua.LUA_TFUNCTION); - count = lauxlib.luaL_optinteger(L, arg + 3, 0); + const smask = luaL_checkstring(L, arg + 2); + luaL_checktype(L, arg+1, LUA_TFUNCTION); + count = luaL_optinteger(L, arg + 3, 0); func = hookf; mask = makemask(smask, count); } - if (lua.lua_rawgetp(L, lua.LUA_REGISTRYINDEX, HOOKKEY) === lua.LUA_TNIL) { - lua.lua_createtable(L, 0, 2); /* create a hook table */ - lua.lua_pushvalue(L, -1); - lua.lua_rawsetp(L, lua.LUA_REGISTRYINDEX, HOOKKEY); /* set it in position */ - lua.lua_pushstring(L, lua.to_luastring("k")); - lua.lua_setfield(L, -2, lua.to_luastring("__mode", true)); /** hooktable.__mode = "k" */ - lua.lua_pushvalue(L, -1); - lua.lua_setmetatable(L, -2); /* setmetatable(hooktable) = hooktable */ + if (lua_rawgetp(L, LUA_REGISTRYINDEX, HOOKKEY) === LUA_TNIL) { + lua_createtable(L, 0, 2); /* create a hook table */ + lua_pushvalue(L, -1); + lua_rawsetp(L, LUA_REGISTRYINDEX, HOOKKEY); /* set it in position */ + lua_pushstring(L, to_luastring("k")); + lua_setfield(L, -2, to_luastring("__mode", true)); /** hooktable.__mode = "k" */ + lua_pushvalue(L, -1); + lua_setmetatable(L, -2); /* setmetatable(hooktable) = hooktable */ } checkstack(L, L1, 1); - lua.lua_pushthread(L1); lua.lua_xmove(L1, L, 1); /* key (thread) */ - lua.lua_pushvalue(L, arg + 1); /* value (hook function) */ - lua.lua_rawset(L, -3); /* hooktable[L1] = new Lua hook */ - lua.lua_sethook(L1, func, mask, count); + lua_pushthread(L1); lua_xmove(L1, L, 1); /* key (thread) */ + lua_pushvalue(L, arg + 1); /* value (hook function) */ + lua_rawset(L, -3); /* hooktable[L1] = new Lua hook */ + lua_sethook(L1, func, mask, count); return 0; }; @@ -345,21 +422,21 @@ const db_gethook = function(L) { let thread = getthread(L); let L1 = thread.thread; let buff = new Uint8Array(5); - let mask = lua.lua_gethookmask(L1); - let hook = lua.lua_gethook(L1); + let mask = lua_gethookmask(L1); + let hook = lua_gethook(L1); if (hook === null) /* no hook? */ - lua.lua_pushnil(L); + lua_pushnil(L); else if (hook !== hookf) /* external hook? */ - lua.lua_pushliteral(L, "external hook"); + lua_pushliteral(L, "external hook"); else { /* hook table must exist */ - lua.lua_rawgetp(L, lua.LUA_REGISTRYINDEX, HOOKKEY); + lua_rawgetp(L, LUA_REGISTRYINDEX, HOOKKEY); checkstack(L, L1, 1); - lua.lua_pushthread(L1); lua.lua_xmove(L1, L, 1); - lua.lua_rawget(L, -2); /* 1st result = hooktable[L1] */ - lua.lua_remove(L, -2); /* remove hook table */ + lua_pushthread(L1); lua_xmove(L1, L, 1); + lua_rawget(L, -2); /* 1st result = hooktable[L1] */ + lua_remove(L, -2); /* remove hook table */ } - lua.lua_pushstring(L, unmakemask(mask, buff)); /* 2nd result = mask */ - lua.lua_pushinteger(L, lua.lua_gethookcount(L1)); /* 3rd result = count */ + lua_pushstring(L, unmakemask(mask, buff)); /* 2nd result = mask */ + lua_pushinteger(L, lua_gethookcount(L1)); /* 3rd result = count */ return 3; }; @@ -367,12 +444,12 @@ const db_traceback = function(L) { let thread = getthread(L); let L1 = thread.thread; let arg = thread.arg; - let msg = lua.lua_tostring(L, arg + 1); - if (msg === null && !lua.lua_isnoneornil(L, arg + 1)) /* non-string 'msg'? */ - lua.lua_pushvalue(L, arg + 1); /* return it untouched */ + let msg = lua_tostring(L, arg + 1); + if (msg === null && !lua_isnoneornil(L, arg + 1)) /* non-string 'msg'? */ + lua_pushvalue(L, arg + 1); /* return it untouched */ else { - let level = lauxlib.luaL_optinteger(L, arg + 2, L === L1 ? 1 : 0); - lauxlib.luaL_traceback(L, L1, msg, level); + let level = luaL_optinteger(L, arg + 2, L === L1 ? 1 : 0); + luaL_traceback(L, L1, msg, level); } return 1; }; @@ -424,18 +501,18 @@ if (getinput) { if (input.length === 0) continue; - let buffer = lua.to_luastring(input); - if (lauxlib.luaL_loadbuffer(L, buffer, buffer.length, lua.to_luastring("=(debug command)", true)) - || lua.lua_pcall(L, 0, 0, 0)) { - lauxlib.lua_writestringerror(lua.lua_tojsstring(L, -1), "\n"); + let buffer = to_luastring(input); + if (luaL_loadbuffer(L, buffer, buffer.length, to_luastring("=(debug command)", true)) + || lua_pcall(L, 0, 0, 0)) { + lua_writestringerror(lua_tojsstring(L, -1), "\n"); } - lua.lua_settop(L, 0); /* remove eventual returns */ + lua_settop(L, 0); /* remove eventual returns */ } }; } const luaopen_debug = function(L) { - lauxlib.luaL_newlib(L, dblib); + luaL_newlib(L, dblib); return 1; }; diff --git a/src/ldebug.js b/src/ldebug.js index 1bb7a8a..a471c75 100644 --- a/src/ldebug.js +++ b/src/ldebug.js @@ -1,8 +1,30 @@ "use strict"; -const assert = require('assert'); - -const defs = require('./defs.js'); +const { + LUA_HOOKCOUNT, + LUA_HOOKLINE, + LUA_MASKCOUNT, + LUA_MASKLINE, + constant_types: { + LUA_TBOOLEAN, + LUA_TNIL, + LUA_TTABLE + }, + thread_status: { + LUA_ERRRUN, + LUA_YIELD + }, + from_userstring, + luastring_eq, + luastring_indexOf, + to_luastring +} = require('./defs.js'); +const { + api_check, + lua_assert +} = require('./llimits.js'); +const { LUA_IDSIZE } = require('./luaconf.js'); +const lapi = require('./lapi.js'); const ldo = require('./ldo.js'); const lfunc = require('./lfunc.js'); const llex = require('./llex.js'); @@ -11,14 +33,10 @@ const lopcodes = require('./lopcodes.js'); const lstate = require('./lstate.js'); const ltable = require('./ltable.js'); const ltm = require('./ltm.js'); -const luaconf = require('./luaconf.js'); const lvm = require('./lvm.js'); -const CT = defs.constant_types; -const TS = defs.thread_status; - const currentpc = function(ci) { - assert(ci.callstatus & lstate.CIST_LUA); + lua_assert(ci.callstatus & lstate.CIST_LUA); return ci.l_savedpc - 1; }; @@ -33,7 +51,7 @@ const currentline = function(ci) { ** after debugging, it also "re-restores" ** 'func' to its altered value. */ const swapextra = function(L) { - if (L.status === TS.LUA_YIELD) { + if (L.status === LUA_YIELD) { let ci = L.ci; /* get function that yielded */ let temp = ci.funcOff; /* exchange its 'func' and 'extra' values */ ci.func = L.stack[ci.extra]; @@ -84,9 +102,9 @@ const lua_getstack = function(L, level, ar) { }; const upvalname = function(p, uv) { - assert(uv < p.upvalues.length); + lua_assert(uv < p.upvalues.length); let s = p.upvalues[uv].name; - if (s === null) return defs.to_luastring("?", true); + if (s === null) return to_luastring("?", true); return s.getstr(); }; @@ -97,7 +115,7 @@ const findvararg = function(ci, n) { else { return { pos: ci.funcOff + nparams + n, - name: defs.to_luastring("(*vararg)", true) /* generic name for any vararg */ + name: to_luastring("(*vararg)", true) /* generic name for any vararg */ }; } }; @@ -118,7 +136,7 @@ const findlocal = function(L, ci, n) { if (name === null) { /* no 'standard' name? */ let limit = ci === L.ci ? L.top : ci.next.funcOff; if (limit - base >= n && n > 0) /* is 'n' inside 'ci' stack? */ - name = defs.to_luastring("(*temporary)", true); /* generic name for any valid slot */ + name = to_luastring("(*temporary)", true); /* generic name for any valid slot */ else return null; /* no name */ } @@ -141,7 +159,7 @@ const lua_getlocal = function(L, ar, n) { if (local) { name = local.name; lobject.pushobj2s(L, L.stack[local.pos]); - assert(L.top <= L.ci.top, "stack overflow"); + api_check(L, L.top <= L.ci.top, "stack overflow"); } else { name = null; } @@ -167,33 +185,31 @@ const lua_setlocal = function(L, ar, n) { const funcinfo = function(ar, cl) { if (cl === null || cl instanceof lobject.CClosure) { - ar.source = defs.to_luastring("=[JS]", true); + ar.source = to_luastring("=[JS]", true); ar.linedefined = -1; ar.lastlinedefined = -1; - ar.what = defs.to_luastring("J", true); + ar.what = to_luastring("J", true); } else { let p = cl.p; - ar.source = p.source ? p.source.getstr() : defs.to_luastring("=?", true); + ar.source = p.source ? p.source.getstr() : to_luastring("=?", true); ar.linedefined = p.linedefined; ar.lastlinedefined = p.lastlinedefined; - ar.what = ar.linedefined === 0 ? defs.to_luastring("main", true) : defs.to_luastring("Lua", true); + ar.what = ar.linedefined === 0 ? to_luastring("main", true) : to_luastring("Lua", true); } - ar.short_src = lobject.luaO_chunkid(ar.source, luaconf.LUA_IDSIZE); + ar.short_src = lobject.luaO_chunkid(ar.source, LUA_IDSIZE); }; const collectvalidlines = function(L, f) { if (f === null || f instanceof lobject.CClosure) { - L.stack[L.top] = new lobject.TValue(CT.LUA_TNIL, null); - L.top++; - assert(L.top <= L.ci.top, "stack overflow"); + L.stack[L.top] = new lobject.TValue(LUA_TNIL, null); + lapi.api_incr_top(L); } else { let lineinfo = f.p.lineinfo; let t = ltable.luaH_new(L); - L.stack[L.top] = new lobject.TValue(CT.LUA_TTABLE, t); - L.top++; - assert(L.top <= L.ci.top, "stack overflow"); - let v = new lobject.TValue(CT.LUA_TBOOLEAN, true); + L.stack[L.top] = new lobject.TValue(LUA_TTABLE, t); + lapi.api_incr_top(L); + let v = new lobject.TValue(LUA_TBOOLEAN, true); for (let i = 0; i < lineinfo.length; i++) ltable.luaH_setint(t, lineinfo[i], v); } @@ -207,8 +223,8 @@ const getfuncname = function(L, ci) { if (ci === null) return null; else if (ci.callstatus & lstate.CIST_FIN) { /* is this a finalizer? */ - r.name = defs.to_luastring("__gc", true); - r.funcname = defs.to_luastring("metamethod", true); /* report it as such */ + r.name = to_luastring("__gc", true); + r.funcname = to_luastring("metamethod", true); /* report it as such */ return r; } /* calling function is a known Lua function? */ @@ -219,17 +235,17 @@ const getfuncname = function(L, ci) { const auxgetinfo = function(L, what, ar, f, ci) { let status = 1; - for (; what.length > 0; what = what.slice(1)) { - switch (String.fromCharCode(what[0])) { - case 'S': { + for (; what.length > 0; what = what.subarray(1)) { + switch (what[0]) { + case 83 /* ('S').charCodeAt(0) */: { funcinfo(ar, f); break; } - case 'l': { + case 108 /* ('l').charCodeAt(0) */: { ar.currentline = ci && ci.callstatus & lstate.CIST_LUA ? currentline(ci) : -1; break; } - case 'u': { + case 117 /* ('u').charCodeAt(0) */: { ar.nups = f === null ? 0 : f.nupvalues; if (f === null || f instanceof lobject.CClosure) { ar.isvararg = true; @@ -240,14 +256,14 @@ const auxgetinfo = function(L, what, ar, f, ci) { } break; } - case 't': { + case 116 /* ('t').charCodeAt(0) */: { ar.istailcall = ci ? ci.callstatus & lstate.CIST_TAIL : 0; break; } - case 'n': { + case 110 /* ('n').charCodeAt(0) */: { let r = getfuncname(L, ci); if (r === null) { - ar.namewhat = defs.to_luastring("", true); + ar.namewhat = to_luastring("", true); ar.name = null; } else { ar.namewhat = r.funcname; @@ -255,8 +271,8 @@ const auxgetinfo = function(L, what, ar, f, ci) { } break; } - case 'L': - case 'f': /* handled by lua_getinfo */ + case 76 /* ('L').charCodeAt(0) */: + case 102 /* ('f').charCodeAt(0) */: /* handled by lua_getinfo */ break; default: status = 0; /* invalid option */ } @@ -266,30 +282,30 @@ const auxgetinfo = function(L, what, ar, f, ci) { }; const lua_getinfo = function(L, what, ar) { - what = defs.from_userstring(what); + what = from_userstring(what); let status, cl, ci, func; swapextra(L); - if (what[0] === '>'.charCodeAt(0)) { + if (what[0] === 62 /* ('>').charCodeAt(0) */) { ci = null; func = L.stack[L.top - 1]; - assert(L, func.ttisfunction(), "function expected"); - what = what.slice(1); /* skip the '>' */ + api_check(L, func.ttisfunction(), "function expected"); + what = what.subarray(1); /* skip the '>' */ L.top--; /* pop function */ } else { ci = ar.i_ci; func = ci.func; - assert(ci.func.ttisfunction()); + lua_assert(ci.func.ttisfunction()); } cl = func.ttisclosure() ? func.value : null; status = auxgetinfo(L, what, ar, cl, ci); - if (what.indexOf('f'.charCodeAt(0)) >= 0) { + if (luastring_indexOf(what, 102 /* ('f').charCodeAt(0) */) >= 0) { lobject.pushobj2s(L, func); - assert(L.top <= L.ci.top, "stack overflow"); + api_check(L, L.top <= L.ci.top, "stack overflow"); } swapextra(L); - if (what.indexOf('L'.charCodeAt(0)) >= 0) + if (luastring_indexOf(what, 76 /* ('L').charCodeAt(0) */) >= 0) collectvalidlines(L, cl); return status; @@ -310,12 +326,12 @@ const kname = function(p, pc, c) { /* else no reasonable name found */ } else { /* 'c' is a register */ let what = getobjname(p, pc, c); /* search for 'c' */ - if (what && what.funcname[0] === 'c'.charCodeAt(0)) { /* found a constant name? */ + if (what && what.funcname[0] === 99 /* ('c').charCodeAt(0) */) { /* found a constant name? */ return what; /* 'name' already filled */ } /* else no reasonable name found */ } - r.name = defs.to_luastring("?", true); + r.name = to_luastring("?", true); return r; /* no reasonable name found */ }; @@ -381,7 +397,7 @@ const getobjname = function(p, lastpc, reg) { }; if (r.name) { /* is a local? */ - r.funcname = defs.to_luastring("local", true); + r.funcname = to_luastring("local", true); return r; } @@ -403,12 +419,12 @@ const getobjname = function(p, lastpc, reg) { let t = i.B; /* table index */ let vn = i.opcode === OCi.OP_GETTABLE ? lfunc.luaF_getlocalname(p, t + 1, pc) : upvalname(p, t); r.name = kname(p, pc, k).name; - r.funcname = (vn && defs.luastring_cmp(vn, llex.LUA_ENV)) ? defs.to_luastring("global", true) : defs.to_luastring("field", true); + r.funcname = (vn && luastring_eq(vn, llex.LUA_ENV)) ? to_luastring("global", true) : to_luastring("field", true); return r; } case OCi.OP_GETUPVAL: { r.name = upvalname(p, i.B); - r.funcname = defs.to_luastring("upvalue", true); + r.funcname = to_luastring("upvalue", true); return r; } case OCi.OP_LOADK: @@ -416,7 +432,7 @@ const getobjname = function(p, lastpc, reg) { let b = i.opcode === OCi.OP_LOADK ? i.Bx : p.code[pc + 1].Ax; if (p.k[b].ttisstring()) { r.name = p.k[b].svalue(); - r.funcname = defs.to_luastring("constant", true); + r.funcname = to_luastring("constant", true); return r; } break; @@ -424,7 +440,7 @@ const getobjname = function(p, lastpc, reg) { case OCi.OP_SELF: { let k = i.C; r.name = kname(p, pc, k).name; - r.funcname = defs.to_luastring("method", true); + r.funcname = to_luastring("method", true); return r; } default: break; @@ -453,8 +469,8 @@ const funcnamefromcode = function(L, ci) { let OCi = lopcodes.OpCodesI; if (ci.callstatus & lstate.CIST_HOOKED) { - r.name = defs.to_luastring("?", true); - r.funcname = defs.to_luastring("hook", true); + r.name = to_luastring("?", true); + r.funcname = to_luastring("hook", true); return r; } @@ -463,8 +479,8 @@ const funcnamefromcode = function(L, ci) { case OCi.OP_TAILCALL: return getobjname(p, pc, i.A); /* get function name */ case OCi.OP_TFORCALL: - r.name = defs.to_luastring("for iterator", true); - r.funcname = defs.to_luastring("for iterator", true); + r.name = to_luastring("for iterator", true); + r.funcname = to_luastring("for iterator", true); return r; /* other instructions can do calls through metamethods */ case OCi.OP_SELF: @@ -500,7 +516,7 @@ const funcnamefromcode = function(L, ci) { } r.name = L.l_G.tmname[tm].getstr(); - r.funcname = defs.to_luastring("metamethod", true); + r.funcname = to_luastring("metamethod", true); return r; }; @@ -521,10 +537,10 @@ const isinstack = function(L, ci, o) { const getupvalname = function(L, ci, o) { let c = ci.func.value; for (let i = 0; i < c.nupvalues; i++) { - if (c.upvals[i].v === o) { + if (c.upvals[i] === o) { return { name: upvalname(c.p, i), - funcname: defs.to_luastring('upvalue', true) + funcname: to_luastring('upvalue', true) }; } } @@ -542,17 +558,17 @@ const varinfo = function(L, o) { kind = getobjname(ci.func.value.p, currentpc(ci), stkid - ci.l_base); } - return kind ? lobject.luaO_pushfstring(L, defs.to_luastring(" (%s '%s')", true), kind.funcname, kind.name) : defs.to_luastring("", true); + return kind ? lobject.luaO_pushfstring(L, to_luastring(" (%s '%s')", true), kind.funcname, kind.name) : to_luastring("", true); }; const luaG_typeerror = function(L, o, op) { let t = ltm.luaT_objtypename(L, o); - luaG_runerror(L, defs.to_luastring("attempt to %s a %s value%s", true), op, t, varinfo(L, o)); + luaG_runerror(L, to_luastring("attempt to %s a %s value%s", true), op, t, varinfo(L, o)); }; const luaG_concaterror = function(L, p1, p2) { if (p1.ttisstring() || lvm.cvt2str(p1)) p1 = p2; - luaG_typeerror(L, p1, defs.to_luastring('concatenate', true)); + luaG_typeerror(L, p1, to_luastring('concatenate', true)); }; /* @@ -567,21 +583,21 @@ 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 (defs.luastring_cmp(t1, t2)) - luaG_runerror(L, defs.to_luastring("attempt to compare two %s values", true), t1); + if (luastring_eq(t1, t2)) + luaG_runerror(L, to_luastring("attempt to compare two %s values", true), t1); else - luaG_runerror(L, defs.to_luastring("attempt to compare %s with %s", true), t1, t2); + luaG_runerror(L, to_luastring("attempt to compare %s with %s", true), t1, t2); }; /* add src:line information to 'msg' */ const luaG_addinfo = function(L, msg, src, line) { let buff; if (src) - buff = lobject.luaO_chunkid(src.getstr(), luaconf.LUA_IDSIZE); + buff = lobject.luaO_chunkid(src.getstr(), LUA_IDSIZE); else - buff = defs.to_luastring("?", true); + buff = to_luastring("?", true); - return lobject.luaO_pushfstring(L, defs.to_luastring("%s:%d: %s", true), buff, line, msg); + return lobject.luaO_pushfstring(L, to_luastring("%s:%d: %s", true), buff, line, msg); }; const luaG_runerror = function(L, fmt, ...argp) { @@ -600,7 +616,7 @@ const luaG_errormsg = function(L) { ldo.luaD_callnoyield(L, L.top - 2, 1); } - ldo.luaD_throw(L, TS.LUA_ERRRUN); + ldo.luaD_throw(L, LUA_ERRRUN); }; /* @@ -610,41 +626,41 @@ const luaG_tointerror = function(L, p1, p2) { let temp = lvm.tointeger(p1); if (temp === false) p2 = p1; - luaG_runerror(L, defs.to_luastring("number%s has no integer representation", true), varinfo(L, p2)); + luaG_runerror(L, to_luastring("number%s has no integer representation", true), varinfo(L, p2)); }; const luaG_traceexec = function(L) { let ci = L.ci; let mask = L.hookmask; - let counthook = (--L.hookcount === 0 && (mask & defs.LUA_MASKCOUNT)); + let counthook = (--L.hookcount === 0 && (mask & LUA_MASKCOUNT)); if (counthook) L.hookcount = L.basehookcount; /* reset count */ - else if (!(mask & defs.LUA_MASKLINE)) + else if (!(mask & LUA_MASKLINE)) return; /* no line hook and count != 0; nothing to be done */ if (ci.callstatus & lstate.CIST_HOOKYIELD) { /* called hook last time? */ ci.callstatus &= ~lstate.CIST_HOOKYIELD; /* erase mark */ return; /* do not call hook again (VM yielded, so it did not move) */ } if (counthook) - ldo.luaD_hook(L, defs.LUA_HOOKCOUNT, -1); /* call count hook */ - if (mask & defs.LUA_MASKLINE) { + ldo.luaD_hook(L, LUA_HOOKCOUNT, -1); /* call count hook */ + if (mask & LUA_MASKLINE) { let p = ci.func.value.p; let npc = ci.l_savedpc - 1; // pcRel(ci.u.l.savedpc, p); let newline = p.lineinfo.length !== 0 ? p.lineinfo[npc] : -1; if (npc === 0 || /* call linehook when enter a new function, */ ci.l_savedpc <= L.oldpc || /* when jump back (loop), or when */ newline !== (p.lineinfo.length !== 0 ? p.lineinfo[L.oldpc - 1] : -1)) /* enter a new line */ - ldo.luaD_hook(L, defs.LUA_HOOKLINE, newline); /* call line hook */ + ldo.luaD_hook(L, LUA_HOOKLINE, newline); /* call line hook */ } L.oldpc = ci.l_savedpc; - if (L.status === TS.LUA_YIELD) { /* did hook yield? */ + if (L.status === LUA_YIELD) { /* did hook yield? */ if (counthook) L.hookcount = 1; /* undo decrement to zero */ ci.l_savedpc--; /* undo increment (resume will increment it again) */ ci.callstatus |= lstate.CIST_HOOKYIELD; /* mark that it yielded */ ci.funcOff = L.top - 1; /* protect stack below results */ ci.func = L.stack[ci.funcOff]; - ldo.luaD_throw(L, TS.LUA_YIELD); + ldo.luaD_throw(L, LUA_YIELD); } }; @@ -1,30 +1,56 @@ "use strict"; -const assert = require('assert'); - -const defs = require('./defs.js'); +const { + LUA_HOOKCALL, + LUA_HOOKRET, + LUA_HOOKTAILCALL, + LUA_MASKCALL, + LUA_MASKLINE, + LUA_MASKRET, + LUA_MINSTACK, + LUA_MULTRET, + LUA_SIGNATURE, + constant_types: { + LUA_TCCL, + LUA_TLCF, + LUA_TLCL, + LUA_TNIL + }, + thread_status: { + LUA_ERRMEM, + LUA_ERRERR, + LUA_ERRRUN, + LUA_ERRSYNTAX, + LUA_OK, + LUA_YIELD + }, + lua_Debug, + luastring_indexOf, + to_luastring +} = require('./defs.js'); const lapi = require('./lapi.js'); const ldebug = require('./ldebug.js'); const lfunc = require('./lfunc.js'); -const llimits = require('./llimits.js'); +const { + api_check, + lua_assert, + LUAI_MAXCCALLS +} = require('./llimits.js'); const lobject = require('./lobject.js'); const lopcodes = require('./lopcodes.js'); const lparser = require('./lparser.js'); const lstate = require('./lstate.js'); -const lstring = require('./lstring.js'); +const { luaS_newliteral } = require('./lstring.js'); const ltm = require('./ltm.js'); -const luaconf = require('./luaconf.js'); +const { LUAI_MAXSTACK } = require('./luaconf.js'); const lundump = require('./lundump.js'); const lvm = require('./lvm.js'); -const lzio = require('./lzio.js'); - -const CT = defs.constant_types; -const TS = defs.thread_status; +const { MBuffer } = require('./lzio.js'); const adjust_top = function(L, newtop) { if (L.top < newtop) { while (L.top < newtop) - L.stack[L.top++] = new lobject.TValue(CT.LUA_TNIL, null); + L.stack[L.top++] = new lobject.TValue(LUA_TNIL, null); } else { while (L.top > newtop) delete L.stack[--L.top]; @@ -36,15 +62,15 @@ const seterrorobj = function(L, errcode, oldtop) { /* extend stack so that L.stack[oldtop] is sure to exist */ while (L.top < oldtop + 1) - L.stack[L.top++] = new lobject.TValue(CT.LUA_TNIL, null); + L.stack[L.top++] = new lobject.TValue(LUA_TNIL, null); switch (errcode) { - case TS.LUA_ERRMEM: { - lobject.setsvalue2s(L, oldtop, lstring.luaS_newliteral(L, "not enough memory")); + case LUA_ERRMEM: { + lobject.setsvalue2s(L, oldtop, luaS_newliteral(L, "not enough memory")); break; } - case TS.LUA_ERRERR: { - lobject.setsvalue2s(L, oldtop, lstring.luaS_newliteral(L, "error in error handling")); + case LUA_ERRERR: { + lobject.setsvalue2s(L, oldtop, luaS_newliteral(L, "error in error handling")); break; } default: { @@ -56,27 +82,27 @@ const seterrorobj = function(L, errcode, oldtop) { delete L.stack[--L.top]; }; -const ERRORSTACKSIZE = luaconf.LUAI_MAXSTACK + 200; +const ERRORSTACKSIZE = LUAI_MAXSTACK + 200; const luaD_reallocstack = function(L, newsize) { - assert(newsize <= luaconf.LUAI_MAXSTACK || newsize == ERRORSTACKSIZE); - assert(L.stack_last == L.stack.length - lstate.EXTRA_STACK); + lua_assert(newsize <= LUAI_MAXSTACK || newsize == ERRORSTACKSIZE); + lua_assert(L.stack_last == L.stack.length - lstate.EXTRA_STACK); L.stack.length = newsize; L.stack_last = newsize - lstate.EXTRA_STACK; }; const luaD_growstack = function(L, n) { let size = L.stack.length; - if (size > luaconf.LUAI_MAXSTACK) - luaD_throw(L, TS.LUA_ERRERR); + if (size > LUAI_MAXSTACK) + luaD_throw(L, LUA_ERRERR); else { let needed = L.top + n + lstate.EXTRA_STACK; let newsize = 2 * size; - if (newsize > luaconf.LUAI_MAXSTACK) newsize = luaconf.LUAI_MAXSTACK; + if (newsize > LUAI_MAXSTACK) newsize = LUAI_MAXSTACK; if (newsize < needed) newsize = needed; - if (newsize > luaconf.LUAI_MAXSTACK) { /* stack overflow? */ + if (newsize > LUAI_MAXSTACK) { /* stack overflow? */ luaD_reallocstack(L, ERRORSTACKSIZE); - ldebug.luaG_runerror(L, defs.to_luastring("stack overflow", true)); + ldebug.luaG_runerror(L, to_luastring("stack overflow", true)); } else luaD_reallocstack(L, newsize); @@ -93,26 +119,26 @@ const stackinuse = function(L) { for (let ci = L.ci; ci !== null; ci = ci.previous) { if (lim < ci.top) lim = ci.top; } - assert(lim <= L.stack_last); + lua_assert(lim <= L.stack_last); return lim + 1; /* part of stack in use */ }; const luaD_shrinkstack = function(L) { let inuse = stackinuse(L); let goodsize = inuse + Math.floor(inuse / 8) + 2*lstate.EXTRA_STACK; - if (goodsize > luaconf.LUAI_MAXSTACK) - goodsize = luaconf.LUAI_MAXSTACK; /* respect stack limit */ - if (L.stack.length > luaconf.LUAI_MAXSTACK) /* had been handling stack overflow? */ + if (goodsize > LUAI_MAXSTACK) + goodsize = LUAI_MAXSTACK; /* respect stack limit */ + if (L.stack.length > LUAI_MAXSTACK) /* had been handling stack overflow? */ lstate.luaE_freeCI(L); /* free all CIs (list grew because of an error) */ /* if thread is currently not handling a stack overflow and its good size is smaller than current size, shrink its stack */ - if (inuse <= (luaconf.LUAI_MAXSTACK - lstate.EXTRA_STACK) && goodsize < L.stack.length) + if (inuse <= (LUAI_MAXSTACK - lstate.EXTRA_STACK) && goodsize < L.stack.length) luaD_reallocstack(L, goodsize); }; const luaD_inctop = function(L) { luaD_checkstack(L, 1); - L.stack[L.top++] = new lobject.TValue(CT.LUA_TNIL, null); + L.stack[L.top++] = new lobject.TValue(LUA_TNIL, null); }; /* @@ -126,30 +152,30 @@ const luaD_precall = function(L, off, nresults) { let func = L.stack[off]; switch(func.type) { - case CT.LUA_TCCL: - case CT.LUA_TLCF: { - let f = func.type === CT.LUA_TCCL ? func.value.f : func.value; + case LUA_TCCL: + case LUA_TLCF: { + let f = func.type === LUA_TCCL ? func.value.f : func.value; - luaD_checkstack(L, defs.LUA_MINSTACK); + luaD_checkstack(L, LUA_MINSTACK); let ci = lstate.luaE_extendCI(L); ci.funcOff = off; ci.nresults = nresults; ci.func = func; - ci.top = L.top + defs.LUA_MINSTACK; - assert(ci.top <= L.stack_last); + ci.top = L.top + LUA_MINSTACK; + lua_assert(ci.top <= L.stack_last); ci.callstatus = 0; - if (L.hookmask & defs.LUA_MASKCALL) - luaD_hook(L, defs.LUA_HOOKCALL, -1); + if (L.hookmask & LUA_MASKCALL) + luaD_hook(L, LUA_HOOKCALL, -1); let n = f(L); /* do the actual call */ - - assert(typeof n == "number" && n >= 0 && (n|0) === n, "invalid return value from JS function (expected integer)"); - assert(n < L.top - L.ci.funcOff, "not enough elements in the stack"); + if (typeof n !== "number" || n < 0 || (n|0) !== n) + throw Error("invalid return value from JS function (expected integer)"); + lapi.api_checknelems(L, n); luaD_poscall(L, ci, L.top - n, n); return true; } - case CT.LUA_TLCL: { + case LUA_TLCL: { let base; let p = func.value.p; let n = L.top - off - 1; @@ -159,7 +185,7 @@ const luaD_precall = function(L, off, nresults) { base = adjust_varargs(L, p, n); } else { for (; n < p.numparams; n++) - L.stack[L.top++] = new lobject.TValue(CT.LUA_TNIL, null); // complete missing arguments + L.stack[L.top++] = new lobject.TValue(LUA_TNIL, null); // complete missing arguments base = off + 1; } @@ -173,7 +199,7 @@ const luaD_precall = function(L, off, nresults) { ci.l_code = p.code; ci.l_savedpc = 0; ci.callstatus = lstate.CIST_LUA; - if (L.hookmask & defs.LUA_MASKCALL) + if (L.hookmask & LUA_MASKCALL) callhook(L, ci); return false; } @@ -187,9 +213,9 @@ const luaD_precall = function(L, off, nresults) { const luaD_poscall = function(L, ci, firstResult, nres) { let wanted = ci.nresults; - if (L.hookmask & (defs.LUA_MASKRET | defs.LUA_MASKLINE)) { - if (L.hookmask & defs.LUA_MASKRET) - luaD_hook(L, defs.LUA_HOOKRET, -1); + if (L.hookmask & (LUA_MASKRET | LUA_MASKLINE)) { + if (L.hookmask & LUA_MASKRET) + luaD_hook(L, LUA_HOOKRET, -1); L.oldpc = ci.previous.l_savedpc; /* 'oldpc' for caller function */ } @@ -211,7 +237,7 @@ const moveresults = function(L, firstResult, res, nres, wanted) { } break; } - case defs.LUA_MULTRET: { + case LUA_MULTRET: { for (let i = 0; i < nres; i++) lobject.setobjs2s(L, res + i, firstResult + i); for (let i=L.top; i>=(res + nres); i--) @@ -229,7 +255,7 @@ const moveresults = function(L, firstResult, res, nres, wanted) { lobject.setobjs2s(L, res + i, firstResult + i); for (; i < wanted; i++) { if (res+i >= L.top) - L.stack[res + i] = new lobject.TValue(CT.LUAT_NIL, null); + L.stack[res + i] = new lobject.TValue(LUA_TNIL, null); else L.stack[res + i].setnilvalue(); } @@ -255,17 +281,17 @@ const luaD_hook = function(L, event, line) { let ci = L.ci; let top = L.top; let ci_top = ci.top; - let ar = new defs.lua_Debug(); + let ar = new lua_Debug(); ar.event = event; ar.currentline = line; ar.i_ci = ci; - luaD_checkstack(L, defs.LUA_MINSTACK); /* ensure minimum stack size */ - ci.top = L.top + defs.LUA_MINSTACK; - assert(ci.top <= L.stack_last); + luaD_checkstack(L, LUA_MINSTACK); /* ensure minimum stack size */ + ci.top = L.top + LUA_MINSTACK; + lua_assert(ci.top <= L.stack_last); L.allowhook = 0; /* cannot call hooks inside a hook */ ci.callstatus |= lstate.CIST_HOOKED; hook(L, ar); - assert(!L.allowhook); + lua_assert(!L.allowhook); L.allowhook = 1; ci.top = ci_top; adjust_top(L, top); @@ -274,12 +300,12 @@ const luaD_hook = function(L, event, line) { }; const callhook = function(L, ci) { - let hook = defs.LUA_HOOKCALL; + let hook = LUA_HOOKCALL; ci.l_savedpc++; /* hooks assume 'pc' is already incremented */ if ((ci.previous.callstatus & lstate.CIST_LUA) && ci.previous.l_code[ci.previous.l_savedpc - 1].opcode == lopcodes.OpCodesI.OP_TAILCALL) { ci.callstatus |= lstate.CIST_TAIL; - hook = defs.LUA_HOOKTAILCALL; + hook = LUA_HOOKTAILCALL; } luaD_hook(L, hook, -1); ci.l_savedpc--; /* correct 'pc' */ @@ -298,7 +324,7 @@ const adjust_varargs = function(L, p, actual) { } for (; i < nfixargs; i++) - L.stack[L.top++] = new lobject.TValue(CT.LUA_TNIL, null); + L.stack[L.top++] = new lobject.TValue(LUA_TNIL, null); return base; }; @@ -306,7 +332,7 @@ const adjust_varargs = function(L, p, actual) { const tryfuncTM = function(L, off, func) { let tm = ltm.luaT_gettmbyobj(L, func, ltm.TMS.TM_CALL); if (!tm.ttisfunction(tm)) - ldebug.luaG_typeerror(L, func, defs.to_luastring("call", true)); + ldebug.luaG_typeerror(L, func, to_luastring("call", true)); /* Open a hole inside the stack at 'func' */ lobject.pushobj2s(L, L.stack[L.top-1]); /* push top of stack again */ for (let p = L.top-2; p > off; p--) @@ -322,10 +348,10 @@ const tryfuncTM = function(L, off, func) { ** allow overflow handling to work) */ const stackerror = function(L) { - if (L.nCcalls === llimits.LUAI_MAXCCALLS) - ldebug.luaG_runerror(L, defs.to_luastring("JS stack overflow", true)); - else if (L.nCcalls >= llimits.LUAI_MAXCCALLS + (llimits.LUAI_MAXCCALLS >> 3)) - luaD_throw(L, TS.LUA_ERRERR); /* error while handing stack error */ + if (L.nCcalls === LUAI_MAXCCALLS) + ldebug.luaG_runerror(L, to_luastring("JS stack overflow", true)); + else if (L.nCcalls >= LUAI_MAXCCALLS + (LUAI_MAXCCALLS >> 3)) + luaD_throw(L, LUA_ERRERR); /* error while handing stack error */ }; /* @@ -335,7 +361,7 @@ const stackerror = function(L) { ** function position. */ const luaD_call = function(L, off, nResults) { - if (++L.nCcalls >= llimits.LUAI_MAXCCALLS) + if (++L.nCcalls >= LUAI_MAXCCALLS) stackerror(L); if (!luaD_precall(L, off, nResults)) lvm.luaV_execute(L); @@ -368,7 +394,7 @@ const luaD_throw = function(L, errcode) { const luaD_rawrunprotected = function(L, f, ud) { let oldnCcalls = L.nCcalls; let lj = { // TODO: necessary when using try/catch ? (ldo.c:47-52) - status: TS.LUA_OK, + status: LUA_OK, previous: L.errorJmp /* chain new error handler */ }; L.errorJmp = lj; @@ -376,13 +402,13 @@ const luaD_rawrunprotected = function(L, f, ud) { try { f(L, ud); } catch (e) { - if (lj.status === TS.LUA_OK) { + if (lj.status === LUA_OK) { /* error was not thrown via luaD_throw, i.e. it is a JS error */ /* run user error handler (if it exists) */ let atnativeerror = L.l_G.atnativeerror; if (atnativeerror) { try { - lj.status = TS.LUA_OK; + lj.status = LUA_OK; lapi.lua_pushcfunction(L, atnativeerror); lapi.lua_pushlightuserdata(L, e); @@ -397,9 +423,9 @@ const luaD_rawrunprotected = function(L, f, ud) { luaD_callnoyield(L, L.top - 2, 1); } - lj.status = TS.LUA_ERRRUN; + lj.status = LUA_ERRRUN; } catch(e2) { - if (lj.status === TS.LUA_OK) { + if (lj.status === LUA_OK) { /* also failed */ lj.status = -1; } @@ -425,21 +451,21 @@ const finishCcall = function(L, status) { let ci = L.ci; /* must have a continuation and must be able to call it */ - assert(ci.c_k !== null && L.nny === 0); + lua_assert(ci.c_k !== null && L.nny === 0); /* error status can only happen in a protected call */ - assert(ci.callstatus & lstate.CIST_YPCALL || status === TS.LUA_YIELD); + lua_assert(ci.callstatus & lstate.CIST_YPCALL || status === LUA_YIELD); - if (ci.callstatus & TS.CIST_YPCALL) { /* was inside a pcall? */ - ci.callstatus &= ~TS.CIST_YPCALL; /* continuation is also inside it */ + if (ci.callstatus & lstate.CIST_YPCALL) { /* was inside a pcall? */ + ci.callstatus &= ~lstate.CIST_YPCALL; /* continuation is also inside it */ L.errfunc = ci.c_old_errfunc; /* with the same error function */ } /* finish 'lua_callk'/'lua_pcall'; CIST_YPCALL and 'errfunc' already handled */ - if (ci.nresults === defs.LUA_MULTRET && L.ci.top < L.top) L.ci.top = L.top; + if (ci.nresults === LUA_MULTRET && L.ci.top < L.top) L.ci.top = L.top; let c_k = ci.c_k; /* don't want to call as method */ let n = c_k(L, status, ci.c_ctx); /* call continuation function */ - assert(n < (L.top - L.ci.funcOff), "not enough elements in the stack"); + lapi.api_checknelems(L, n); luaD_poscall(L, ci, L.top - n, n); /* finish 'luaD_precall' */ }; @@ -457,7 +483,7 @@ const unroll = function(L, ud) { while (L.ci !== L.base_ci) { /* something in the stack */ if (!(L.ci.callstatus & lstate.CIST_LUA)) /* C function? */ - finishCcall(L, TS.LUA_YIELD); /* complete its execution */ + finishCcall(L, LUA_YIELD); /* complete its execution */ else { /* Lua function */ lvm.luaV_finishOp(L); /* finish interrupted instruction */ lvm.luaV_execute(L); /* execute down to higher C 'boundary' */ @@ -504,17 +530,17 @@ const recover = function(L, status) { ** coroutine error handler and should not kill the coroutine.) */ const resume_error = function(L, msg, narg) { - let ts = lstring.luaS_newliteral(L, msg); + let ts = luaS_newliteral(L, msg); if (narg === 0) { lobject.pushsvalue2s(L, ts); - assert(L.top <= L.ci.top, "stack overflow"); + api_check(L, L.top <= L.ci.top, "stack overflow"); } else { /* remove args from the stack */ for (let i=1; i<narg; i++) delete L.stack[--L.top]; lobject.setsvalue2s(L, L.top-1, ts); /* push error message */ } - return TS.LUA_ERRRUN; + return LUA_ERRRUN; }; /* @@ -527,12 +553,12 @@ const resume_error = function(L, msg, narg) { const resume = function(L, n) { let firstArg = L.top - n; /* first argument */ let ci = L.ci; - if (L.status === TS.LUA_OK) { /* starting a coroutine? */ - if (!luaD_precall(L, firstArg - 1, defs.LUA_MULTRET)) /* Lua function? */ + if (L.status === LUA_OK) { /* starting a coroutine? */ + if (!luaD_precall(L, firstArg - 1, LUA_MULTRET)) /* Lua function? */ lvm.luaV_execute(L); /* call it */ } else { /* resuming from previous yield */ - assert(L.status === TS.LUA_YIELD); - L.status = TS.LUA_OK; /* mark that it is running (again) */ + lua_assert(L.status === LUA_YIELD); + L.status = LUA_OK; /* mark that it is running (again) */ ci.funcOff = ci.extra; ci.func = L.stack[ci.funcOff]; @@ -540,8 +566,8 @@ const resume = function(L, n) { lvm.luaV_execute(L); /* just continue running Lua code */ else { /* 'common' yield */ if (ci.c_k !== null) { /* does it have a continuation function? */ - n = ci.c_k(L, TS.LUA_YIELD, ci.c_ctx); /* call continuation */ - assert(n < (L.top - L.ci.funcOff), "not enough elements in the stack"); + n = ci.c_k(L, LUA_YIELD, ci.c_ctx); /* call continuation */ + lapi.api_checknelems(L, n); firstArg = L.top - n; /* yield results come from continuation */ } @@ -555,41 +581,40 @@ const resume = function(L, n) { const lua_resume = function(L, from, nargs) { let oldnny = L.nny; /* save "number of non-yieldable" calls */ - if (L.status === TS.LUA_OK) { /* may be starting a coroutine */ + if (L.status === LUA_OK) { /* may be starting a coroutine */ if (L.ci !== L.base_ci) /* not in base level? */ return resume_error(L, "cannot resume non-suspended coroutine", nargs); - } else if (L.status !== TS.LUA_YIELD) + } else if (L.status !== LUA_YIELD) return resume_error(L, "cannot resume dead coroutine", nargs); L.nCcalls = from ? from.nCcalls + 1 : 1; - if (L.nCcalls >= llimits.LUAI_MAXCCALLS) + if (L.nCcalls >= LUAI_MAXCCALLS) return resume_error(L, "JS stack overflow", nargs); L.nny = 0; /* allow yields */ - assert((L.status === TS.LUA_OK ? nargs + 1: nargs) < (L.top - L.ci.funcOff), - "not enough elements in the stack"); + lapi.api_checknelems(L, L.status === LUA_OK ? nargs + 1: nargs); let status = luaD_rawrunprotected(L, resume, nargs); if (status === -1) /* error calling 'lua_resume'? */ - status = TS.LUA_ERRRUN; + status = LUA_ERRRUN; else { /* continue running after recoverable errors */ - while (status > TS.LUA_YIELD && recover(L, status)) { + while (status > LUA_YIELD && recover(L, status)) { /* unroll continuation */ status = luaD_rawrunprotected(L, unroll, status); } - if (status > TS.LUA_YIELD) { /* unrecoverable error? */ + if (status > LUA_YIELD) { /* unrecoverable error? */ L.status = status; /* mark thread as 'dead' */ seterrorobj(L, status, L.top); /* push error message */ L.ci.top = L.top; } else - assert(status === L.status); /* normal end or yield */ + lua_assert(status === L.status); /* normal end or yield */ } L.nny = oldnny; /* restore 'nny' */ L.nCcalls--; - assert(L.nCcalls === (from ? from.nCcalls : 0)); + lua_assert(L.nCcalls === (from ? from.nCcalls : 0)); return status; }; @@ -599,29 +624,29 @@ const lua_isyieldable = function(L) { const lua_yieldk = function(L, nresults, ctx, k) { let ci = L.ci; - assert(nresults < (L.top - L.ci.funcOff), "not enough elements in the stack"); + lapi.api_checknelems(L, nresults); if (L.nny > 0) { if (L !== L.l_G.mainthread) - ldebug.luaG_runerror(L, defs.to_luastring("attempt to yield across a JS-call boundary", true)); + ldebug.luaG_runerror(L, to_luastring("attempt to yield across a JS-call boundary", true)); else - ldebug.luaG_runerror(L, defs.to_luastring("attempt to yield from outside a coroutine", true)); + ldebug.luaG_runerror(L, to_luastring("attempt to yield from outside a coroutine", true)); } - L.status = TS.LUA_YIELD; + L.status = LUA_YIELD; ci.extra = ci.funcOff; /* save current 'func' */ if (ci.callstatus & lstate.CIST_LUA) /* inside a hook? */ - assert(k === null, "hooks cannot continue after yielding"); + api_check(L, k === null, "hooks cannot continue after yielding"); else { ci.c_k = k; if (k !== null) /* is there a continuation? */ ci.c_ctx = ctx; /* save context */ ci.funcOff = L.top - nresults - 1; /* protect stack below results */ ci.func = L.stack[ci.funcOff]; - luaD_throw(L, TS.LUA_YIELD); + luaD_throw(L, LUA_YIELD); } - assert(ci.callstatus & lstate.CIST_HOOKED); /* must be inside a hook */ + lua_assert(ci.callstatus & lstate.CIST_HOOKED); /* must be inside a hook */ return 0; /* return to 'luaD_hook' */ }; @@ -638,7 +663,7 @@ const luaD_pcall = function(L, func, u, old_top, ef) { let status = luaD_rawrunprotected(L, func, u); - if (status !== TS.LUA_OK) { + if (status !== LUA_OK) { lfunc.luaF_close(L, old_top); seterrorobj(L, status, old_top); L.ci = old_ci; @@ -667,7 +692,7 @@ const luaD_callnoyield = function(L, off, nResults) { class SParser { constructor(z, name, mode) { /* data to 'f_parser' */ this.z = z; - this.buff = new lzio.MBuffer(); /* dynamic structure used by the scanner */ + this.buff = new MBuffer(); /* dynamic structure used by the scanner */ this.dyd = new lparser.Dyndata(); /* dynamic structures used by the parser */ this.mode = mode; this.name = name; @@ -675,25 +700,25 @@ class SParser { } const checkmode = function(L, mode, x) { - if (mode && mode.indexOf(x[0]) === -1) { + if (mode && luastring_indexOf(mode, x[0]) === -1) { lobject.luaO_pushfstring(L, - defs.to_luastring("attempt to load a %s chunk (mode is '%s')"), x, mode); - luaD_throw(L, TS.LUA_ERRSYNTAX); + to_luastring("attempt to load a %s chunk (mode is '%s')"), x, mode); + luaD_throw(L, LUA_ERRSYNTAX); } }; const f_parser = function(L, p) { let cl; let c = p.z.zgetc(); /* read first character */ - if (c === defs.LUA_SIGNATURE.charCodeAt(0)) { - checkmode(L, p.mode, defs.to_luastring("binary", true)); + if (c === LUA_SIGNATURE[0]) { + checkmode(L, p.mode, to_luastring("binary", true)); cl = lundump.luaU_undump(L, p.z, p.name); } else { - checkmode(L, p.mode, defs.to_luastring("text", true)); + checkmode(L, p.mode, to_luastring("text", true)); cl = lparser.luaY_parser(L, p.z, p.buff, p.dyd, p.name, c); } - assert(cl.nupvalues === cl.p.upvalues.length); + lua_assert(cl.nupvalues === cl.p.upvalues.length); lfunc.luaF_initupvals(L, cl); }; diff --git a/src/ldump.js b/src/ldump.js index 7e62da3..596a319 100644 --- a/src/ldump.js +++ b/src/ldump.js @@ -1,12 +1,24 @@ "use strict"; -const defs = require('./defs.js'); -const CT = defs.constant_types; - -const LUAC_DATA = defs.string_of(25, 147, 13, 10, 26, 10); +const { + LUA_SIGNATURE, + LUA_VERSION_MAJOR, + LUA_VERSION_MINOR, + constant_types: { + LUA_TBOOLEAN, + LUA_TLNGSTR, + LUA_TNIL, + LUA_TNUMFLT, + LUA_TNUMINT, + LUA_TSHRSTR + }, + luastring_of +} = require('./defs.js'); + +const LUAC_DATA = luastring_of(25, 147, 13, 10, 26, 10); const LUAC_INT = 0x5678; const LUAC_NUM = 370.5; -const LUAC_VERSION = Number.parseInt(defs.LUA_VERSION_MAJOR) * 16 + Number.parseInt(defs.LUA_VERSION_MINOR); +const LUAC_VERSION = Number(LUA_VERSION_MAJOR) * 16 + Number(LUA_VERSION_MINOR); const LUAC_FORMAT = 0; /* this is the official format */ class DumpState { @@ -24,13 +36,8 @@ const DumpBlock = function(b, size, D) { D.status = D.writer(D.L, b, size, D.data); }; -const DumpLiteral = function(s, D) { - s = defs.to_luastring(s); - DumpBlock(s, s.length, D); -}; - const DumpByte = function(y, D) { - DumpBlock(defs.string_of(y), 1, D); + DumpBlock(luastring_of(y), 1, D); }; const DumpInt = function(x, D) { @@ -88,19 +95,19 @@ const DumpConstants = function(f, D) { let o = f.k[i]; DumpByte(o.ttype(), D); switch (o.ttype()) { - case CT.LUA_TNIL: + case LUA_TNIL: break; - case CT.LUA_TBOOLEAN: + case LUA_TBOOLEAN: DumpByte(o.value ? 1 : 0, D); break; - case CT.LUA_TNUMFLT: + case LUA_TNUMFLT: DumpNumber(o.value, D); break; - case CT.LUA_TNUMINT: + case LUA_TNUMINT: DumpInteger(o.value, D); break; - case CT.LUA_TSHRSTR: - case CT.LUA_TLNGSTR: + case LUA_TSHRSTR: + case LUA_TLNGSTR: DumpString(o.tsvalue(), D); break; } @@ -159,7 +166,7 @@ const DumpFunction = function(f, psource, D) { }; const DumpHeader = function(D) { - DumpLiteral(defs.LUA_SIGNATURE, D); + DumpBlock(LUA_SIGNATURE, LUA_SIGNATURE.length, D); DumpByte(LUAC_VERSION, D); DumpByte(LUAC_FORMAT, D); DumpBlock(LUAC_DATA, LUAC_DATA.length, D); diff --git a/src/lfunc.js b/src/lfunc.js index b07b803..9290f4b 100644 --- a/src/lfunc.js +++ b/src/lfunc.js @@ -1,13 +1,9 @@ "use strict"; -const assert = require('assert'); - -const defs = require('./defs.js'); +const { constant_types: { LUA_TNIL } } = require('./defs.js'); const lobject = require('./lobject.js'); -const CT = defs.constant_types; class Proto { - constructor(L) { this.id = L.l_G.id_counter++; this.k = []; // constants used by the function @@ -24,81 +20,32 @@ class Proto { this.lastlinedefined = 0; // debug information this.source = null; // used for debug information } - -} - -class UpVal { - - constructor(L) { - this.id = L.l_G.id_counter++; - this.v = void 0; /* if open: reference to TValue on stack. if closed: TValue */ - this.vOff = void 0; /* if open: index on stack. if closed: undefined */ - this.refcount = 0; - this.open_next = null; /* linked list (when open) */ - } - - isopen() { - return this.vOff !== void 0; - } - } const luaF_newLclosure = function(L, n) { - let c = new lobject.LClosure(L, n); - return c; + return new lobject.LClosure(L, n); }; const luaF_findupval = function(L, level) { - let prevp; - let p = L.openupval; - while (p !== null && p.vOff >= level) { - assert(p.isopen()); - if (p.vOff === level) /* found a corresponding upvalue? */ - return p; /* return it */ - prevp = p; - p = p.open_next; - } - /* not found: create a new upvalue */ - let uv = new UpVal(L); - /* link it to list of open upvalues */ - uv.open_next = p; - if (prevp) - prevp.open_next = uv; - else - L.openupval = uv; - uv.v = L.stack[level]; /* current value lives in the stack */ - uv.vOff = level; - return uv; + return L.stack[level]; }; const luaF_close = function(L, level) { - while (L.openupval !== null && L.openupval.vOff >= level) { - let uv = L.openupval; - assert(uv.isopen()); - L.openupval = uv.open_next; /* remove from 'open' list */ - if (uv.refcount === 0) { /* no references? */ - /* free upvalue */ - uv.v = void 0; - uv.open_next = null; - } else { - let from = uv.v; - uv.v = new lobject.TValue(from.type, from.value); - } - uv.vOff = void 0; + /* Create new TValues on stack; + * any closures will keep referencing old TValues */ + for (let i=level; i<L.top; i++) { + let old = L.stack[i]; + L.stack[i] = new lobject.TValue(old.type, old.value); } }; /* -** fill a closure with new closed upvalues +** fill a closure with new upvalues */ const luaF_initupvals = function(L, cl) { - for (let i = 0; i < cl.nupvalues; i++) { - let uv = new UpVal(L); - uv.refcount = 1; - uv.v = new lobject.TValue(CT.LUA_TNIL, null); - cl.upvals[i] = uv; - } + for (let i = 0; i < cl.nupvalues; i++) + cl.upvals[i] = new lobject.TValue(LUA_TNIL, null); }; /* @@ -116,10 +63,8 @@ const luaF_getlocalname = function(f, local_number, pc) { return null; /* not found */ }; - module.exports.MAXUPVAL = 255; module.exports.Proto = Proto; -module.exports.UpVal = UpVal; module.exports.luaF_findupval = luaF_findupval; module.exports.luaF_close = luaF_close; module.exports.luaF_getlocalname = luaF_getlocalname; diff --git a/src/linit.js b/src/linit.js index 97cbfc9..a265045 100644 --- a/src/linit.js +++ b/src/linit.js @@ -1,38 +1,40 @@ "use strict"; -const lua = require('./lua.js'); -const lauxlib = require('./lauxlib.js'); -const lbaselib = require('./lbaselib.js'); -const lcorolib = require('./lcorolib.js'); -const lmathlib = require('./lmathlib.js'); -const lstrlib = require('./lstrlib.js'); -const ltablib = require('./ltablib.js'); -const lutf8lib = require('./lutf8lib.js'); -const ldblib = require('./ldblib.js'); -const loslib = require('./loslib.js'); -const loadlib = require('./loadlib.js'); -const lualib = require('./lualib.js'); +const { lua_pop } = require('./lua.js'); +const { luaL_requiref } = require('./lauxlib.js'); +const { to_luastring } = require("./fengaricore.js"); -const luaL_openlibs = function(L) { - const loadedlibs = { - [lualib.LUA_LOADLIBNAME]: loadlib.luaopen_package, - [lualib.LUA_COLIBNAME]: lcorolib.luaopen_coroutine, - [lualib.LUA_DBLIBNAME]: ldblib.luaopen_debug, - [lualib.LUA_MATHLIBNAME]: lmathlib.luaopen_math, - [lualib.LUA_OSLIBNAME]: loslib.luaopen_os, - [lualib.LUA_STRLIBNAME]: lstrlib.luaopen_string, - [lualib.LUA_TABLIBNAME]: ltablib.luaopen_table, - [lualib.LUA_UTF8LIBNAME]: lutf8lib.luaopen_utf8, - "_G": lbaselib.luaopen_base - }; - - if (typeof process !== "undefined") loadedlibs[lualib.LUA_IOLIBNAME] = require('./liolib.js').luaopen_io; +const loadedlibs = {}; +/* export before requiring lualib.js */ +const luaL_openlibs = function(L) { /* "require" functions from 'loadedlibs' and set results to global table */ for (let lib in loadedlibs) { - lauxlib.luaL_requiref(L, lua.to_luastring(lib), loadedlibs[lib], 1); - lua.lua_pop(L, 1); /* remove lib */ + luaL_requiref(L, to_luastring(lib), loadedlibs[lib], 1); + lua_pop(L, 1); /* remove lib */ } }; - module.exports.luaL_openlibs = luaL_openlibs; + +const lualib = require('./lualib.js'); +const { luaopen_base } = require('./lbaselib.js'); +const { luaopen_coroutine } = require('./lcorolib.js'); +const { luaopen_debug } = require('./ldblib.js'); +const { luaopen_math } = require('./lmathlib.js'); +const { luaopen_package } = require('./loadlib.js'); +const { luaopen_os } = require('./loslib.js'); +const { luaopen_string } = require('./lstrlib.js'); +const { luaopen_table } = require('./ltablib.js'); +const { luaopen_utf8 } = require('./lutf8lib.js'); + +loadedlibs["_G"] = luaopen_base, +loadedlibs[lualib.LUA_LOADLIBNAME] = luaopen_package; +loadedlibs[lualib.LUA_COLIBNAME] = luaopen_coroutine; +loadedlibs[lualib.LUA_TABLIBNAME] = luaopen_table; +loadedlibs[lualib.LUA_OSLIBNAME] = luaopen_os; +loadedlibs[lualib.LUA_STRLIBNAME] = luaopen_string; +loadedlibs[lualib.LUA_MATHLIBNAME] = luaopen_math; +loadedlibs[lualib.LUA_UTF8LIBNAME] = luaopen_utf8; +loadedlibs[lualib.LUA_DBLIBNAME] = luaopen_debug; +if (typeof process !== "undefined") + loadedlibs[lualib.LUA_IOLIBNAME] = require('./liolib.js').luaopen_io; diff --git a/src/liolib.js b/src/liolib.js index 3241011..bd78f87 100644 --- a/src/liolib.js +++ b/src/liolib.js @@ -1,18 +1,46 @@ "use strict"; -const assert = require('assert'); const fs = require('fs'); -const lua = require('./lua.js'); -const lauxlib = require('./lauxlib.js'); +const { + LUA_REGISTRYINDEX, + lua_getfield, + lua_gettop, + lua_isnone, + lua_isnoneornil, + lua_newuserdata, + lua_pop, + lua_pushliteral, + lua_pushnil, + lua_pushstring, + lua_pushvalue, + lua_setfield, + lua_tostring, + lua_touserdata +} = require('./lua.js'); +const { + LUA_FILEHANDLE, + luaL_checkany, + luaL_checklstring, + luaL_checkudata, + luaL_error, + luaL_fileresult, + luaL_newlib, + luaL_newmetatable, + luaL_setfuncs, + luaL_setmetatable, + luaL_testudata +} = require('./lauxlib.js'); +const lualib = require('./lualib.js'); +const { to_luastring } = require("./fengaricore.js"); const IO_PREFIX = "_IO_"; const IOPREF_LEN = IO_PREFIX.length; -const IO_INPUT = lua.to_luastring(IO_PREFIX + "input"); -const IO_OUTPUT = lua.to_luastring(IO_PREFIX + "output"); +const IO_INPUT = to_luastring(IO_PREFIX + "input"); +const IO_OUTPUT = to_luastring(IO_PREFIX + "output"); const tolstream = function(L) { - return lauxlib.luaL_checkudata(L, 1, lauxlib.LUA_FILEHANDLE); + return luaL_checkudata(L, 1, LUA_FILEHANDLE); }; const isclosed = function(p) { @@ -20,39 +48,39 @@ const isclosed = function(p) { }; const io_type = function(L) { - lauxlib.luaL_checkany(L, 1); - let p = lauxlib.luaL_testudata(L, 1, lauxlib.LUA_FILEHANDLE); + luaL_checkany(L, 1); + let p = luaL_testudata(L, 1, LUA_FILEHANDLE); if (p === null) - lua.lua_pushnil(L); /* not a file */ + lua_pushnil(L); /* not a file */ else if (isclosed(p)) - lua.lua_pushliteral(L, "closed file"); + lua_pushliteral(L, "closed file"); else - lua.lua_pushliteral(L, "file"); + lua_pushliteral(L, "file"); return 1; }; const f_tostring = function(L) { let p = tolstream(L); if (isclosed(p)) - lua.lua_pushliteral(L, "file (closed)"); + lua_pushliteral(L, "file (closed)"); else - lua.lua_pushstring(L, lua.to_luastring(`file (${p.f.toString()})`)); + lua_pushstring(L, to_luastring(`file (${p.f.toString()})`)); return 1; }; const tofile = function(L) { let p = tolstream(L); if (isclosed(p)) - lauxlib.luaL_error(L, lua.to_luastring("attempt to use a closed file")); - assert(p.f); + luaL_error(L, to_luastring("attempt to use a closed file")); + lualib.lua_assert(p.f); return p.f; }; const newprefile = function(L) { - let p = lua.lua_newuserdata(L); + let p = lua_newuserdata(L); p.f = null; p.closef = null; - lauxlib.luaL_setmetatable(L, lauxlib.LUA_FILEHANDLE); + luaL_setmetatable(L, LUA_FILEHANDLE); return p; }; @@ -64,33 +92,33 @@ const aux_close = function(L) { }; const io_close = function(L) { - if (lua.lua_isnone(L, 1)) /* no argument? */ - lua.lua_getfield(L, lua.LUA_REGISTRYINDEX, IO_OUTPUT); /* use standard output */ + if (lua_isnone(L, 1)) /* no argument? */ + lua_getfield(L, LUA_REGISTRYINDEX, IO_OUTPUT); /* use standard output */ tofile(L); /* make sure argument is an open stream */ return aux_close(L); }; const getiofile = function(L, findex) { - lua.lua_getfield(L, lua.LUA_REGISTRYINDEX, findex); - let p = lua.lua_touserdata(L, -1); + lua_getfield(L, LUA_REGISTRYINDEX, findex); + let p = lua_touserdata(L, -1); if (isclosed(p)) - lauxlib.luaL_error(L, lua.to_luastring("standard %s file is closed"), findex.slice(IOPREF_LEN)); + luaL_error(L, to_luastring("standard %s file is closed"), findex.subarray(IOPREF_LEN)); return p.f; }; const g_iofile = function(L, f, mode) { - if (!lua.lua_isnoneornil(L, 1)) { - let filename = lua.lua_tostring(L, 1); + if (!lua_isnoneornil(L, 1)) { + let filename = lua_tostring(L, 1); if (filename) - lauxlib.luaL_error(L, lua.to_luastring("opening files not yet implemented")); + luaL_error(L, to_luastring("opening files not yet implemented")); else { tofile(L); /* check that it's a valid file handle */ - lua.lua_pushvalue(L, 1); + lua_pushvalue(L, 1); } - lua.lua_setfield(L, lua.LUA_REGISTRYINDEX, f); + lua_setfield(L, LUA_REGISTRYINDEX, f); } /* return current value */ - lua.lua_getfield(L, lua.LUA_REGISTRYINDEX, f); + lua_getfield(L, LUA_REGISTRYINDEX, f); return 1; }; @@ -103,11 +131,11 @@ const io_output = function(L) { }; const g_write = function(L, f, arg) { - let nargs = lua.lua_gettop(L) - arg; + let nargs = lua_gettop(L) - arg; let status = true; let err; for (; nargs--; arg++) { - let s = lauxlib.luaL_checklstring(L, arg); + let s = luaL_checklstring(L, arg); try { status = status && (fs.writeSync(f.fd, Uint8Array.from(s)) === s.length); } catch (e) { @@ -116,7 +144,7 @@ const g_write = function(L, f, arg) { } } if (status) return 1; /* file handle already on stack top */ - else return lauxlib.luaL_fileresult(L, status, null, err); + else return luaL_fileresult(L, status, null, err); }; const io_write = function(L) { @@ -125,20 +153,20 @@ const io_write = function(L) { const f_write = function(L) { let f = tofile(L); - lua.lua_pushvalue(L, 1); /* push file at the stack top (to be returned) */ + lua_pushvalue(L, 1); /* push file at the stack top (to be returned) */ return g_write(L, f, 2); }; const io_flush = function (L) { /* stub, as node doesn't have synchronized buffered IO */ getiofile(L, IO_OUTPUT); - return lauxlib.luaL_fileresult(L, true, null, null); + return luaL_fileresult(L, true, null, null); }; const f_flush = function (L) { /* stub, as node doesn't have synchronized buffered IO */ tofile(L); - return lauxlib.luaL_fileresult(L, true, null, null); + return luaL_fileresult(L, true, null, null); }; const iolib = { @@ -158,18 +186,18 @@ const flib = { }; const createmeta = function(L) { - lauxlib.luaL_newmetatable(L, lauxlib.LUA_FILEHANDLE); /* create metatable for file handles */ - lua.lua_pushvalue(L, -1); /* push metatable */ - lua.lua_setfield(L, -2, lua.to_luastring("__index", true)); /* metatable.__index = metatable */ - lauxlib.luaL_setfuncs(L, flib, 0); /* add file methods to new metatable */ - lua.lua_pop(L, 1); /* pop new metatable */ + luaL_newmetatable(L, LUA_FILEHANDLE); /* create metatable for file handles */ + lua_pushvalue(L, -1); /* push metatable */ + lua_setfield(L, -2, to_luastring("__index", true)); /* metatable.__index = metatable */ + luaL_setfuncs(L, flib, 0); /* add file methods to new metatable */ + lua_pop(L, 1); /* pop new metatable */ }; const io_noclose = function(L) { let p = tolstream(L); p.closef = io_noclose; - lua.lua_pushnil(L); - lua.lua_pushliteral(L, "cannot close standard file"); + lua_pushnil(L); + lua_pushliteral(L, "cannot close standard file"); return 2; }; @@ -178,19 +206,19 @@ const createstdfile = function(L, f, k, fname) { p.f = f; p.closef = io_noclose; if (k !== null) { - lua.lua_pushvalue(L, -1); - lua.lua_setfield(L, lua.LUA_REGISTRYINDEX, k); /* add file to registry */ + lua_pushvalue(L, -1); + lua_setfield(L, LUA_REGISTRYINDEX, k); /* add file to registry */ } - lua.lua_setfield(L, -2, fname); /* add file to module */ + lua_setfield(L, -2, fname); /* add file to module */ }; const luaopen_io = function(L) { - lauxlib.luaL_newlib(L, iolib); + luaL_newlib(L, iolib); createmeta(L); /* create (and set) default files */ - createstdfile(L, process.stdin, IO_INPUT, lua.to_luastring("stdin")); - createstdfile(L, process.stdout, IO_OUTPUT, lua.to_luastring("stdout")); - createstdfile(L, process.stderr, null, lua.to_luastring("stderr")); + createstdfile(L, process.stdin, IO_INPUT, to_luastring("stdin")); + createstdfile(L, process.stdout, IO_OUTPUT, to_luastring("stdout")); + createstdfile(L, process.stderr, null, to_luastring("stderr")); return 1; }; diff --git a/src/llex.js b/src/llex.js index 438f288..360e3d7 100644 --- a/src/llex.js +++ b/src/llex.js @@ -1,67 +1,124 @@ "use strict"; -const assert = require('assert'); - -const defs = require('./defs.js'); +const { + constant_types: { LUA_TLNGSTR }, + thread_status: { LUA_ERRSYNTAX }, + to_luastring +} = require('./defs.js'); +const { + LUA_MINBUFFER, + MAX_INT, + lua_assert +} = require('./llimits.js'); const ldebug = require('./ldebug.js'); const ldo = require('./ldo.js'); -const ljstype = require('./ljstype.js'); +const { + lisdigit, + lislalnum, + lislalpha, + lisspace, + lisxdigit +} = require('./ljstype.js'); const lobject = require('./lobject.js'); -const lstring = require('./lstring.js'); +const { + luaS_bless, + luaS_hash, + luaS_hashlongstr, + luaS_new +} = require('./lstring.js'); const ltable = require('./ltable.js'); -const llimits = require('./llimits.js'); -const lzio = require('./lzio.js'); -const TS = defs.thread_status; -const char = defs.char; +const { + EOZ, + luaZ_buffer, + luaZ_buffremove, + luaZ_resetbuffer, + luaZ_resizebuffer +} = require('./lzio.js'); const FIRST_RESERVED = 257; -const LUA_ENV = defs.to_luastring("_ENV", true); +const LUA_ENV = to_luastring("_ENV", true); + +/* terminal symbols denoted by reserved words */ +const TK_AND = FIRST_RESERVED; +const TK_BREAK = FIRST_RESERVED + 1; +const TK_DO = FIRST_RESERVED + 2; +const TK_ELSE = FIRST_RESERVED + 3; +const TK_ELSEIF = FIRST_RESERVED + 4; +const TK_END = FIRST_RESERVED + 5; +const TK_FALSE = FIRST_RESERVED + 6; +const TK_FOR = FIRST_RESERVED + 7; +const TK_FUNCTION = FIRST_RESERVED + 8; +const TK_GOTO = FIRST_RESERVED + 9; +const TK_IF = FIRST_RESERVED + 10; +const TK_IN = FIRST_RESERVED + 11; +const TK_LOCAL = FIRST_RESERVED + 12; +const TK_NIL = FIRST_RESERVED + 13; +const TK_NOT = FIRST_RESERVED + 14; +const TK_OR = FIRST_RESERVED + 15; +const TK_REPEAT = FIRST_RESERVED + 16; +const TK_RETURN = FIRST_RESERVED + 17; +const TK_THEN = FIRST_RESERVED + 18; +const TK_TRUE = FIRST_RESERVED + 19; +const TK_UNTIL = FIRST_RESERVED + 20; +const TK_WHILE = FIRST_RESERVED + 21; +/* other terminal symbols */ +const TK_IDIV = FIRST_RESERVED + 22; +const TK_CONCAT = FIRST_RESERVED + 23; +const TK_DOTS = FIRST_RESERVED + 24; +const TK_EQ = FIRST_RESERVED + 25; +const TK_GE = FIRST_RESERVED + 26; +const TK_LE = FIRST_RESERVED + 27; +const TK_NE = FIRST_RESERVED + 28; +const TK_SHL = FIRST_RESERVED + 29; +const TK_SHR = FIRST_RESERVED + 30; +const TK_DBCOLON = FIRST_RESERVED + 31; +const TK_EOS = FIRST_RESERVED + 32; +const TK_FLT = FIRST_RESERVED + 33; +const TK_INT = FIRST_RESERVED + 34; +const TK_NAME = FIRST_RESERVED + 35; +const TK_STRING = FIRST_RESERVED + 36; const RESERVED = { - /* terminal symbols denoted by reserved words */ - TK_AND: FIRST_RESERVED, - TK_BREAK: FIRST_RESERVED + 1, - TK_DO: FIRST_RESERVED + 2, - TK_ELSE: FIRST_RESERVED + 3, - TK_ELSEIF: FIRST_RESERVED + 4, - TK_END: FIRST_RESERVED + 5, - TK_FALSE: FIRST_RESERVED + 6, - TK_FOR: FIRST_RESERVED + 7, - TK_FUNCTION: FIRST_RESERVED + 8, - TK_GOTO: FIRST_RESERVED + 9, - TK_IF: FIRST_RESERVED + 10, - TK_IN: FIRST_RESERVED + 11, - TK_LOCAL: FIRST_RESERVED + 12, - TK_NIL: FIRST_RESERVED + 13, - TK_NOT: FIRST_RESERVED + 14, - TK_OR: FIRST_RESERVED + 15, - TK_REPEAT: FIRST_RESERVED + 16, - TK_RETURN: FIRST_RESERVED + 17, - TK_THEN: FIRST_RESERVED + 18, - TK_TRUE: FIRST_RESERVED + 19, - TK_UNTIL: FIRST_RESERVED + 20, - TK_WHILE: FIRST_RESERVED + 21, - /* other terminal symbols */ - TK_IDIV: FIRST_RESERVED + 22, - TK_CONCAT: FIRST_RESERVED + 23, - TK_DOTS: FIRST_RESERVED + 24, - TK_EQ: FIRST_RESERVED + 25, - TK_GE: FIRST_RESERVED + 26, - TK_LE: FIRST_RESERVED + 27, - TK_NE: FIRST_RESERVED + 28, - TK_SHL: FIRST_RESERVED + 29, - TK_SHR: FIRST_RESERVED + 30, - TK_DBCOLON: FIRST_RESERVED + 31, - TK_EOS: FIRST_RESERVED + 32, - TK_FLT: FIRST_RESERVED + 33, - TK_INT: FIRST_RESERVED + 34, - TK_NAME: FIRST_RESERVED + 35, - TK_STRING: FIRST_RESERVED + 36 + "TK_AND": TK_AND, + "TK_BREAK": TK_BREAK, + "TK_DO": TK_DO, + "TK_ELSE": TK_ELSE, + "TK_ELSEIF": TK_ELSEIF, + "TK_END": TK_END, + "TK_FALSE": TK_FALSE, + "TK_FOR": TK_FOR, + "TK_FUNCTION": TK_FUNCTION, + "TK_GOTO": TK_GOTO, + "TK_IF": TK_IF, + "TK_IN": TK_IN, + "TK_LOCAL": TK_LOCAL, + "TK_NIL": TK_NIL, + "TK_NOT": TK_NOT, + "TK_OR": TK_OR, + "TK_REPEAT": TK_REPEAT, + "TK_RETURN": TK_RETURN, + "TK_THEN": TK_THEN, + "TK_TRUE": TK_TRUE, + "TK_UNTIL": TK_UNTIL, + "TK_WHILE": TK_WHILE, + "TK_IDIV": TK_IDIV, + "TK_CONCAT": TK_CONCAT, + "TK_DOTS": TK_DOTS, + "TK_EQ": TK_EQ, + "TK_GE": TK_GE, + "TK_LE": TK_LE, + "TK_NE": TK_NE, + "TK_SHL": TK_SHL, + "TK_SHR": TK_SHR, + "TK_DBCOLON": TK_DBCOLON, + "TK_EOS": TK_EOS, + "TK_FLT": TK_FLT, + "TK_INT": TK_INT, + "TK_NAME": TK_NAME, + "TK_STRING": TK_STRING }; -const R = RESERVED; - const luaX_tokens = [ "and", "break", "do", "else", "elseif", "end", "false", "for", "function", "goto", "if", @@ -70,7 +127,7 @@ const luaX_tokens = [ "//", "..", "...", "==", ">=", "<=", "~=", "<<", ">>", "::", "<eof>", "<number>", "<integer>", "<name>", "<string>" -]; +].map((e, i)=>to_luastring(e)); class SemInfo { constructor() { @@ -110,28 +167,28 @@ class LexState { const save = function(ls, c) { let b = ls.buff; if (b.n + 1 > b.buffer.length) { - if (b.buffer.length >= llimits.MAX_INT/2) - lexerror(ls, defs.to_luastring("lexical element too long", true), 0); + if (b.buffer.length >= MAX_INT/2) + lexerror(ls, to_luastring("lexical element too long", true), 0); let newsize = b.buffer.length*2; - lzio.luaZ_resizebuffer(ls.L, b, newsize); + luaZ_resizebuffer(ls.L, b, newsize); } b.buffer[b.n++] = c < 0 ? 255 + c + 1 : c; }; const luaX_token2str = function(ls, token) { if (token < FIRST_RESERVED) { /* single-byte symbols? */ - return lobject.luaO_pushfstring(ls.L, defs.to_luastring("'%c'", true), token); + return lobject.luaO_pushfstring(ls.L, to_luastring("'%c'", true), token); } else { let s = luaX_tokens[token - FIRST_RESERVED]; - if (token < R.TK_EOS) /* fixed format (symbols and reserved words)? */ - return lobject.luaO_pushfstring(ls.L, defs.to_luastring("'%s'", true), defs.to_luastring(s)); + if (token < TK_EOS) /* fixed format (symbols and reserved words)? */ + return lobject.luaO_pushfstring(ls.L, to_luastring("'%s'", true), s); else /* names, strings, and numerals */ - return defs.to_luastring(s); + return s; } }; const currIsNewline = function(ls) { - return ls.current === char['\n'] || ls.current === char['\r']; + return ls.current === 10 /* ('\n').charCodeAt(0) */ || ls.current === 13 /* ('\r').charCodeAt(0) */; }; const next = function(ls) { @@ -150,14 +207,14 @@ const save_and_next = function(ls) { */ const luaX_newstring = function(ls, str) { let L = ls.L; - let ts = lstring.luaS_new(L, str); - let o = ltable.luaH_set(L, ls.h, new lobject.TValue(defs.CT.LUA_TLNGSTR, ts)); + let ts = luaS_new(L, str); + let o = ltable.luaH_set(L, ls.h, new lobject.TValue(LUA_TLNGSTR, ts)); if (o.ttisnil()) { /* not in use yet? */ o.setbvalue(true); } else { /* string already present */ /* HACK: Workaround lack of ltable 'keyfromval' */ - let tpair = ls.h.strong.get(lstring.luaS_hashlongstr(ts)); - assert(tpair.value == o); + let tpair = ls.h.strong.get(luaS_hashlongstr(ts)); + lua_assert(tpair.value == o); /* fengari addition */ ts = tpair.key.tsvalue(); /* re-use value previously stored */ } return ts; @@ -169,12 +226,12 @@ const luaX_newstring = function(ls, str) { */ const inclinenumber = function(ls) { let old = ls.current; - assert(currIsNewline(ls)); + lua_assert(currIsNewline(ls)); next(ls); /* skip '\n' or '\r' */ if (currIsNewline(ls) && ls.current !== old) next(ls); /* skip '\n\r' or '\r\n' */ - if (++ls.linenumber >= llimits.MAX_INT) - lexerror(ls, defs.to_luastring("chunk has too many lines", true), 0); + if (++ls.linenumber >= MAX_INT) + lexerror(ls, to_luastring("chunk has too many lines", true), 0); }; const luaX_setinput = function(L, ls, z, source, firstchar) { @@ -185,7 +242,7 @@ const luaX_setinput = function(L, ls, z, source, firstchar) { ls.L = L; ls.current = firstchar; ls.lookahead = { - token: R.TK_EOS, + token: TK_EOS, seminfo: new SemInfo() }; ls.z = z; @@ -193,12 +250,12 @@ const luaX_setinput = function(L, ls, z, source, firstchar) { ls.linenumber = 1; ls.lastline = 1; ls.source = source; - ls.envn = lstring.luaS_bless(L, LUA_ENV); - lzio.luaZ_resizebuffer(L, ls.buff, llimits.LUA_MINBUFFER); /* initialize buffer */ + ls.envn = luaS_bless(L, LUA_ENV); + luaZ_resizebuffer(L, ls.buff, LUA_MINBUFFER); /* initialize buffer */ }; const check_next1 = function(ls, c) { - if (ls.current === c.charCodeAt(0)) { + if (ls.current === c) { next(ls); return true; } @@ -222,17 +279,17 @@ const check_next2 = function(ls, set) { const read_numeral = function(ls, seminfo) { let expo = "Ee"; let first = ls.current; - assert(ljstype.lisdigit(ls.current)); + lua_assert(lisdigit(ls.current)); save_and_next(ls); - if (first === char['0'] && check_next2(ls, "xX")) /* hexadecimal? */ + if (first === 48 /* ('0').charCodeAt(0) */ && check_next2(ls, "xX")) /* hexadecimal? */ expo = "Pp"; for (;;) { if (check_next2(ls, expo)) /* exponent part? */ check_next2(ls, "-+"); /* optional exponent sign */ - if (ljstype.lisxdigit(ls.current)) + if (lisxdigit(ls.current)) save_and_next(ls); - else if (ls.current === char['.']) + else if (ls.current === 46 /* ('.').charCodeAt(0) */) save_and_next(ls); else break; } @@ -240,24 +297,24 @@ const read_numeral = function(ls, seminfo) { // save(ls, 0); let obj = new lobject.TValue(); - if (lobject.luaO_str2num(lzio.luaZ_buffer(ls.buff), obj) === 0) /* format error? */ - lexerror(ls, defs.to_luastring("malformed number", true), R.TK_FLT); + if (lobject.luaO_str2num(luaZ_buffer(ls.buff), obj) === 0) /* format error? */ + lexerror(ls, to_luastring("malformed number", true), TK_FLT); if (obj.ttisinteger()) { seminfo.i = obj.value; - return R.TK_INT; + return TK_INT; } else { - assert(obj.ttisfloat()); + lua_assert(obj.ttisfloat()); seminfo.r = obj.value; - return R.TK_FLT; + return TK_FLT; } }; const txtToken = function(ls, token) { switch (token) { - case R.TK_NAME: case R.TK_STRING: - case R.TK_FLT: case R.TK_INT: + case TK_NAME: case TK_STRING: + case TK_FLT: case TK_INT: // save(ls, 0); - return lobject.luaO_pushfstring(ls.L, defs.to_luastring("'%s'", true), lzio.luaZ_buffer(ls.buff)); + return lobject.luaO_pushfstring(ls.L, to_luastring("'%s'", true), luaZ_buffer(ls.buff)); default: return luaX_token2str(ls, token); } @@ -266,8 +323,8 @@ const txtToken = function(ls, token) { const lexerror = function(ls, msg, token) { msg = ldebug.luaG_addinfo(ls.L, msg, ls.source, ls.linenumber); if (token) - lobject.luaO_pushfstring(ls.L, defs.to_luastring("%s near %s"), msg, txtToken(ls, token)); - ldo.luaD_throw(ls.L, TS.LUA_ERRSYNTAX); + lobject.luaO_pushfstring(ls.L, to_luastring("%s near %s"), msg, txtToken(ls, token)); + ldo.luaD_throw(ls.L, LUA_ERRSYNTAX); }; const luaX_syntaxerror = function(ls, msg) { @@ -282,9 +339,9 @@ const luaX_syntaxerror = function(ls, msg) { const skip_sep = function(ls) { let count = 0; let s = ls.current; - assert(s === char['['] || s === char[']']); + lua_assert(s === 91 /* ('[').charCodeAt(0) */ || s === 93 /* (']').charCodeAt(0) */); save_and_next(ls); - while (ls.current === char['=']) { + while (ls.current === 61 /* ('=').charCodeAt(0) */) { save_and_next(ls); count++; } @@ -301,23 +358,24 @@ const read_long_string = function(ls, seminfo, sep) { let skip = false; for (; !skip ;) { switch (ls.current) { - case lzio.EOZ: { /* error */ + case EOZ: { /* error */ let what = seminfo ? "string" : "comment"; let msg = `unfinished long ${what} (starting at line ${line})`; - lexerror(ls, defs.to_luastring(msg), R.TK_EOS); + lexerror(ls, to_luastring(msg), TK_EOS); break; } - case char[']']: { + case 93 /* (']').charCodeAt(0) */: { if (skip_sep(ls) === sep) { save_and_next(ls); /* skip 2nd ']' */ skip = true; } break; } - case char['\n']: case char['\r']: { - save(ls, char['\n']); + case 10 /* ('\n').charCodeAt(0) */: + case 13 /* ('\r').charCodeAt(0) */: { + save(ls, 10 /* ('\n').charCodeAt(0) */); inclinenumber(ls); - if (!seminfo) lzio.luaZ_resetbuffer(ls.buff); + if (!seminfo) luaZ_resetbuffer(ls.buff); break; } default: { @@ -333,41 +391,41 @@ const read_long_string = function(ls, seminfo, sep) { const esccheck = function(ls, c, msg) { if (!c) { - if (ls.current !== lzio.EOZ) + if (ls.current !== EOZ) save_and_next(ls); /* add current to buffer for error message */ - lexerror(ls, msg, R.TK_STRING); + lexerror(ls, msg, TK_STRING); } }; const gethexa = function(ls) { save_and_next(ls); - esccheck(ls, ljstype.lisxdigit(ls.current), defs.to_luastring("hexadecimal digit expected", true)); + esccheck(ls, lisxdigit(ls.current), to_luastring("hexadecimal digit expected", true)); return lobject.luaO_hexavalue(ls.current); }; const readhexaesc = function(ls) { let r = gethexa(ls); r = (r << 4) + gethexa(ls); - lzio.luaZ_buffremove(ls.buff, 2); /* remove saved chars from buffer */ + luaZ_buffremove(ls.buff, 2); /* remove saved chars from buffer */ return r; }; 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 === char['{'], defs.to_luastring("missing '{'", true)); + esccheck(ls, ls.current === 123 /* ('{').charCodeAt(0) */, to_luastring("missing '{'", true)); let r = gethexa(ls); /* must have at least one digit */ save_and_next(ls); - while (ljstype.lisxdigit(ls.current)) { + while (lisxdigit(ls.current)) { i++; r = (r << 4) + lobject.luaO_hexavalue(ls.current); - esccheck(ls, r <= 0x10FFFF, defs.to_luastring("UTF-8 value too large", true)); + esccheck(ls, r <= 0x10FFFF, to_luastring("UTF-8 value too large", true)); save_and_next(ls); } - esccheck(ls, ls.current === char['}'], defs.to_luastring("missing '}'", true)); + esccheck(ls, ls.current === 125 /* ('}').charCodeAt(0) */, to_luastring("missing '}'", true)); next(ls); /* skip '}' */ - lzio.luaZ_buffremove(ls.buff, i); /* remove saved chars from buffer */ + luaZ_buffremove(ls.buff, i); /* remove saved chars from buffer */ return r; }; @@ -381,12 +439,12 @@ const utf8esc = function(ls) { const readdecesc = function(ls) { let r = 0; /* result accumulator */ let i; - for (i = 0; i < 3 && ljstype.lisdigit(ls.current); i++) { /* read up to 3 digits */ - r = 10 * r + ls.current - char['0']; + for (i = 0; i < 3 && lisdigit(ls.current); i++) { /* read up to 3 digits */ + r = 10 * r + ls.current - 48 /* ('0').charCodeAt(0) */; save_and_next(ls); } - esccheck(ls, r <= 255, defs.to_luastring("decimal escape too large", true)); - lzio.luaZ_buffremove(ls.buff, i); /* remove read digits from buffer */ + esccheck(ls, r <= 255, to_luastring("decimal escape too large", true)); + luaZ_buffremove(ls.buff, i); /* remove read digits from buffer */ return r; }; @@ -395,43 +453,46 @@ const read_string = function(ls, del, seminfo) { while (ls.current !== del) { switch (ls.current) { - case lzio.EOZ: - lexerror(ls, defs.to_luastring("unfinished string", true), R.TK_EOS); + case EOZ: + lexerror(ls, to_luastring("unfinished string", true), TK_EOS); break; - case char['\n']: - case char['\r']: - lexerror(ls, defs.to_luastring("unfinished string", true), R.TK_STRING); + case 10 /* ('\n').charCodeAt(0) */: + case 13 /* ('\r').charCodeAt(0) */: + lexerror(ls, to_luastring("unfinished string", true), TK_STRING); break; - case char['\\']: { /* escape sequences */ + case 92 /* ('\\').charCodeAt(0) */: { /* escape sequences */ save_and_next(ls); /* keep '\\' for error messages */ let will; let c; switch(ls.current) { - case char['a']: c = 7 /* \a isn't valid JS */; 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['\'']: + case 97 /* ('a').charCodeAt(0) */: c = 7 /* \a isn't valid JS */; will = 'read_save'; break; + case 98 /* ('b').charCodeAt(0) */: c = 8 /* ('\b').charCodeAt(0) */; will = 'read_save'; break; + case 102 /* ('f').charCodeAt(0) */: c = 12 /* ('\f').charCodeAt(0) */; will = 'read_save'; break; + case 110 /* ('n').charCodeAt(0) */: c = 10 /* ('\n').charCodeAt(0) */; will = 'read_save'; break; + case 114 /* ('r').charCodeAt(0) */: c = 13 /* ('\r').charCodeAt(0) */; will = 'read_save'; break; + case 116 /* ('t').charCodeAt(0) */: c = 9 /* ('\t').charCodeAt(0) */; will = 'read_save'; break; + case 118 /* ('v').charCodeAt(0) */: c = 11 /* ('\v').charCodeAt(0) */; will = 'read_save'; break; + case 120 /* ('x').charCodeAt(0) */: c = readhexaesc(ls); will = 'read_save'; break; + case 117 /* ('u').charCodeAt(0) */: utf8esc(ls); will = 'no_save'; break; + case 10 /* ('\n').charCodeAt(0) */: + case 13 /* ('\r').charCodeAt(0) */: + inclinenumber(ls); c = 10 /* ('\n').charCodeAt(0) */; will = 'only_save'; break; + case 92 /* ('\\').charCodeAt(0) */: + case 34 /* ('"').charCodeAt(0) */: + case 39 /* ('\'').charCodeAt(0) */: c = ls.current; will = 'read_save'; break; - case lzio.EOZ: will = 'no_save'; break; /* will raise an error next loop */ - case char['z']: { /* zap following span of spaces */ - lzio.luaZ_buffremove(ls.buff, 1); /* remove '\\' */ + case EOZ: will = 'no_save'; break; /* will raise an error next loop */ + case 122 /* ('z').charCodeAt(0) */: { /* zap following span of spaces */ + luaZ_buffremove(ls.buff, 1); /* remove '\\' */ next(ls); /* skip the 'z' */ - while (ljstype.lisspace(ls.current)) { + while (lisspace(ls.current)) { if (currIsNewline(ls)) inclinenumber(ls); else next(ls); } will = 'no_save'; break; } default: { - esccheck(ls, ljstype.lisdigit(ls.current), defs.to_luastring("invalid escape sequence", true)); + esccheck(ls, lisdigit(ls.current), to_luastring("invalid escape sequence", true)); c = readdecesc(ls); /* digital escape '\ddd' */ will = 'only_save'; break; } @@ -441,7 +502,7 @@ const read_string = function(ls, del, seminfo) { next(ls); if (will === 'read_save' || will === 'only_save') { - lzio.luaZ_buffremove(ls.buff, 1); /* remove '\\' */ + luaZ_buffremove(ls.buff, 1); /* remove '\\' */ save(ls, c); } @@ -457,120 +518,125 @@ const read_string = function(ls, del, seminfo) { }; const token_to_index = Object.create(null); /* don't want to return true for e.g. 'hasOwnProperty' */ -luaX_tokens.forEach((e, i)=>token_to_index[lstring.luaS_hash(defs.to_luastring(e))] = i); +luaX_tokens.forEach((e, i)=>token_to_index[luaS_hash(e)] = i); const isreserved = function(w) { - let kidx = token_to_index[lstring.luaS_hashlongstr(w)]; + let kidx = token_to_index[luaS_hashlongstr(w)]; return kidx !== void 0 && kidx <= 22; }; const llex = function(ls, seminfo) { - lzio.luaZ_resetbuffer(ls.buff); + luaZ_resetbuffer(ls.buff); for (;;) { - assert(typeof ls.current == "number"); + lua_assert(typeof ls.current == "number"); /* fengari addition */ switch (ls.current) { - case char['\n']: case char['\r']: { /* line breaks */ + case 10 /* ('\n').charCodeAt(0) */: + case 13 /* ('\r').charCodeAt(0) */: { /* line breaks */ inclinenumber(ls); break; } - case char[' ']: case char['\f']: case char['\t']: case char['\v']: { /* spaces */ + case 32 /* (' ').charCodeAt(0) */: + case 12 /* ('\f').charCodeAt(0) */: + case 9 /* ('\t').charCodeAt(0) */: + case 11 /* ('\v').charCodeAt(0) */: { /* spaces */ next(ls); break; } - case char['-']: { /* '-' or '--' (comment) */ + case 45 /* ('-').charCodeAt(0) */: { /* '-' or '--' (comment) */ next(ls); - if (ls.current !== char['-']) return char['-']; + if (ls.current !== 45 /* ('-').charCodeAt(0) */) return 45 /* ('-').charCodeAt(0) */; /* else is a comment */ next(ls); - if (ls.current === char['[']) { /* long comment? */ + if (ls.current === 91 /* ('[').charCodeAt(0) */) { /* long comment? */ let sep = skip_sep(ls); - lzio.luaZ_resetbuffer(ls.buff); /* 'skip_sep' may dirty the buffer */ + luaZ_resetbuffer(ls.buff); /* 'skip_sep' may dirty the buffer */ if (sep >= 0) { read_long_string(ls, null, sep); /* skip long comment */ - lzio.luaZ_resetbuffer(ls.buff); /* previous call may dirty the buff. */ + luaZ_resetbuffer(ls.buff); /* previous call may dirty the buff. */ break; } } /* else short comment */ - while (!currIsNewline(ls) && ls.current !== lzio.EOZ) + while (!currIsNewline(ls) && ls.current !== EOZ) next(ls); /* skip until end of line (or end of file) */ break; } - case char['[']: { /* long string or simply '[' */ + case 91 /* ('[').charCodeAt(0) */: { /* long string or simply '[' */ let sep = skip_sep(ls); if (sep >= 0) { read_long_string(ls, seminfo, sep); - return R.TK_STRING; + return TK_STRING; } else if (sep !== -1) /* '[=...' missing second bracket */ - lexerror(ls, defs.to_luastring("invalid long string delimiter", true), R.TK_STRING); - return char['[']; + lexerror(ls, to_luastring("invalid long string delimiter", true), TK_STRING); + return 91 /* ('[').charCodeAt(0) */; } - case char['=']: { + case 61 /* ('=').charCodeAt(0) */: { next(ls); - if (check_next1(ls, '=')) return R.TK_EQ; - else return char['=']; + if (check_next1(ls, 61 /* ('=').charCodeAt(0) */)) return TK_EQ; + else return 61 /* ('=').charCodeAt(0) */; } - case char['<']: { + case 60 /* ('<').charCodeAt(0) */: { next(ls); - if (check_next1(ls, '=')) return R.TK_LE; - else if (check_next1(ls, '<')) return R.TK_SHL; - else return char['<']; + if (check_next1(ls, 61 /* ('=').charCodeAt(0) */)) return TK_LE; + else if (check_next1(ls, 60 /* ('<').charCodeAt(0) */)) return TK_SHL; + else return 60 /* ('<').charCodeAt(0) */; } - case char['>']: { + case 62 /* ('>').charCodeAt(0) */: { next(ls); - if (check_next1(ls, '=')) return R.TK_GE; - else if (check_next1(ls, '>')) return R.TK_SHR; - else return char['>']; + if (check_next1(ls, 61 /* ('=').charCodeAt(0) */)) return TK_GE; + else if (check_next1(ls, 62 /* ('>').charCodeAt(0) */)) return TK_SHR; + else return 62 /* ('>').charCodeAt(0) */; } - case char['/']: { + case 47 /* ('/').charCodeAt(0) */: { next(ls); - if (check_next1(ls, '/')) return R.TK_IDIV; - else return char['/']; + if (check_next1(ls, 47 /* ('/').charCodeAt(0) */)) return TK_IDIV; + else return 47 /* ('/').charCodeAt(0) */; } - case char['~']: { + case 126 /* ('~').charCodeAt(0) */: { next(ls); - if (check_next1(ls, '=')) return R.TK_NE; - else return char['~']; + if (check_next1(ls, 61 /* ('=').charCodeAt(0) */)) return TK_NE; + else return 126 /* ('~').charCodeAt(0) */; } - case char[':']: { + case 58 /* (':').charCodeAt(0) */: { next(ls); - if (check_next1(ls, ':')) return R.TK_DBCOLON; - else return char[':']; + if (check_next1(ls, 58 /* (':').charCodeAt(0) */)) return TK_DBCOLON; + else return 58 /* (':').charCodeAt(0) */; } - case char['"']: case char['\'']: { /* short literal strings */ + case 34 /* ('"').charCodeAt(0) */: + case 39 /* ('\'').charCodeAt(0) */: { /* short literal strings */ read_string(ls, ls.current, seminfo); - return R.TK_STRING; + return TK_STRING; } - case char['.']: { /* '.', '..', '...', or number */ + case 46 /* ('.').charCodeAt(0) */: { /* '.', '..', '...', or number */ save_and_next(ls); - if (check_next1(ls, '.')) { - if (check_next1(ls, '.')) - return R.TK_DOTS; /* '...' */ - else return R.TK_CONCAT; /* '..' */ + if (check_next1(ls, 46 /* ('.').charCodeAt(0) */)) { + if (check_next1(ls, 46 /* ('.').charCodeAt(0) */)) + return TK_DOTS; /* '...' */ + else return TK_CONCAT; /* '..' */ } - else if (!ljstype.lisdigit(ls.current)) return char['.']; + else if (!lisdigit(ls.current)) return 46 /* ('.').charCodeAt(0) */; else return read_numeral(ls, seminfo); } - 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']: { + case 48 /* ('0').charCodeAt(0) */: case 49 /* ('1').charCodeAt(0) */: case 50 /* ('2').charCodeAt(0) */: case 51 /* ('3').charCodeAt(0) */: case 52 /* ('4').charCodeAt(0) */: + case 53 /* ('5').charCodeAt(0) */: case 54 /* ('6').charCodeAt(0) */: case 55 /* ('7').charCodeAt(0) */: case 56 /* ('8').charCodeAt(0) */: case 57 /* ('9').charCodeAt(0) */: { return read_numeral(ls, seminfo); } - case lzio.EOZ: { - return R.TK_EOS; + case EOZ: { + return TK_EOS; } default: { - if (ljstype.lislalpha(ls.current)) { /* identifier or reserved word? */ + if (lislalpha(ls.current)) { /* identifier or reserved word? */ do { save_and_next(ls); - } while (ljstype.lislalnum(ls.current)); - let ts = luaX_newstring(ls, lzio.luaZ_buffer(ls.buff)); + } while (lislalnum(ls.current)); + let ts = luaX_newstring(ls, luaZ_buffer(ls.buff)); seminfo.ts = ts; - let kidx = token_to_index[lstring.luaS_hashlongstr(ts)]; + let kidx = token_to_index[luaS_hashlongstr(ts)]; if (kidx !== void 0 && kidx <= 22) /* reserved word? */ return kidx + FIRST_RESERVED; else - return R.TK_NAME; + return TK_NAME; } else { /* single-char tokens (+ - / ...) */ let c = ls.current; next(ls); @@ -583,18 +649,18 @@ const llex = function(ls, seminfo) { const luaX_next = function(ls) { ls.lastline = ls.linenumber; - if (ls.lookahead.token !== R.TK_EOS) { /* is there a look-ahead token? */ + if (ls.lookahead.token !== TK_EOS) { /* is there a look-ahead token? */ ls.t.token = ls.lookahead.token; /* use this one */ ls.t.seminfo.i = ls.lookahead.seminfo.i; ls.t.seminfo.r = ls.lookahead.seminfo.r; ls.t.seminfo.ts = ls.lookahead.seminfo.ts; // TODO ? - ls.lookahead.token = R.TK_EOS; /* and discharge it */ + ls.lookahead.token = TK_EOS; /* and discharge it */ } else ls.t.token = llex(ls, ls.t.seminfo); /* read next token */ }; const luaX_lookahead = function(ls) { - assert(ls.lookahead.token === R.TK_EOS); + lua_assert(ls.lookahead.token === TK_EOS); ls.lookahead.token = llex(ls, ls.lookahead.seminfo); return ls.lookahead.token; }; diff --git a/src/llimits.js b/src/llimits.js index 4a76bbe..2e7b892 100644 --- a/src/llimits.js +++ b/src/llimits.js @@ -1,5 +1,19 @@ "use strict"; +const { luai_apicheck } = require("./luaconf.js"); + +const lua_assert = function(c) { + if (!c) throw Error("assertion failed"); +}; +module.exports.lua_assert = lua_assert; + +module.exports.luai_apicheck = luai_apicheck || function(l, e) { return lua_assert(e); }; + +const api_check = function(l, e, msg) { + return luai_apicheck(l, e && msg); +}; +module.exports.api_check = api_check; + const LUAI_MAXCCALLS = 200; module.exports.LUAI_MAXCCALLS = LUAI_MAXCCALLS; diff --git a/src/lmathlib.js b/src/lmathlib.js index e056fd8..301aa02 100644 --- a/src/lmathlib.js +++ b/src/lmathlib.js @@ -1,138 +1,170 @@ "use strict"; -const lua = require('./lua.js'); -const lauxlib = require('./lauxlib.js'); -const luaconf = require('./luaconf.js'); +const { + LUA_OPLT, + LUA_TNUMBER, + lua_compare, + lua_gettop, + lua_isinteger, + lua_isnoneornil, + lua_pushboolean, + lua_pushinteger, + lua_pushliteral, + lua_pushnil, + lua_pushnumber, + lua_pushvalue, + lua_setfield, + lua_settop, + lua_tointeger, + lua_tointegerx, + lua_type +} = require('./lua.js'); +const { + luaL_argcheck, + luaL_argerror, + luaL_checkany, + luaL_checkinteger, + luaL_checknumber, + luaL_error, + luaL_newlib, + luaL_optnumber +} = require('./lauxlib.js'); +const { + LUA_MAXINTEGER, + LUA_MININTEGER, + lua_numbertointeger +} = require('./luaconf.js'); +const { to_luastring } = require("./fengaricore.js"); const math_random = function(L) { let low, up; let r = Math.random(); - switch (lua.lua_gettop(L)) { /* check number of arguments */ + switch (lua_gettop(L)) { /* check number of arguments */ case 0: - lua.lua_pushnumber(L, r); /* Number between 0 and 1 */ + lua_pushnumber(L, r); /* Number between 0 and 1 */ return 1; case 1: { low = 1; - up = lauxlib.luaL_checkinteger(L, 1); + up = luaL_checkinteger(L, 1); break; } case 2: { - low = lauxlib.luaL_checkinteger(L, 1); - up = lauxlib.luaL_checkinteger(L, 2); + low = luaL_checkinteger(L, 1); + up = luaL_checkinteger(L, 2); break; } - default: return lauxlib.luaL_error(L, lua.to_luastring("wrong number of arguments", true)); + default: return luaL_error(L, to_luastring("wrong number of arguments", true)); } /* random integer in the interval [low, up] */ - lauxlib.luaL_argcheck(L, low <= up, 1, lua.to_luastring("interval is empty", true)); - lauxlib.luaL_argcheck(L, low >= 0 || up <= luaconf.LUA_MAXINTEGER + low, 1, - lua.to_luastring("interval too large", true)); + luaL_argcheck(L, low <= up, 1, to_luastring("interval is empty", true)); + luaL_argcheck(L, low >= 0 || up <= LUA_MAXINTEGER + low, 1, + to_luastring("interval too large", true)); r *= (up - low) + 1; - lua.lua_pushinteger(L, Math.floor(r) + low); + lua_pushinteger(L, Math.floor(r) + low); return 1; }; const math_abs = function(L) { - if (lua.lua_isinteger(L, 1)) { - let n = lua.lua_tointeger(L, 1); + if (lua_isinteger(L, 1)) { + let n = lua_tointeger(L, 1); if (n < 0) n = (-n)|0; - lua.lua_pushinteger(L, n); + lua_pushinteger(L, n); } else - lua.lua_pushnumber(L, Math.abs(lauxlib.luaL_checknumber(L, 1))); + lua_pushnumber(L, Math.abs(luaL_checknumber(L, 1))); return 1; }; const math_sin = function(L) { - lua.lua_pushnumber(L, Math.sin(lauxlib.luaL_checknumber(L, 1))); + lua_pushnumber(L, Math.sin(luaL_checknumber(L, 1))); return 1; }; const math_cos = function(L) { - lua.lua_pushnumber(L, Math.cos(lauxlib.luaL_checknumber(L, 1))); + lua_pushnumber(L, Math.cos(luaL_checknumber(L, 1))); return 1; }; const math_tan = function(L) { - lua.lua_pushnumber(L, Math.tan(lauxlib.luaL_checknumber(L, 1))); + lua_pushnumber(L, Math.tan(luaL_checknumber(L, 1))); return 1; }; const math_asin = function(L) { - lua.lua_pushnumber(L, Math.asin(lauxlib.luaL_checknumber(L, 1))); + lua_pushnumber(L, Math.asin(luaL_checknumber(L, 1))); return 1; }; const math_acos = function(L) { - lua.lua_pushnumber(L, Math.acos(lauxlib.luaL_checknumber(L, 1))); + lua_pushnumber(L, Math.acos(luaL_checknumber(L, 1))); return 1; }; const math_atan = function(L) { - let y = lauxlib.luaL_checknumber(L, 1); - let x = lauxlib.luaL_optnumber(L, 2, 1); - lua.lua_pushnumber(L, Math.atan2(y, x)); + let y = luaL_checknumber(L, 1); + let x = luaL_optnumber(L, 2, 1); + lua_pushnumber(L, Math.atan2(y, x)); return 1; }; const math_toint = function(L) { - let n = lua.lua_tointegerx(L, 1); + let n = lua_tointegerx(L, 1); if (n !== false) - lua.lua_pushinteger(L, n); + lua_pushinteger(L, n); else { - lauxlib.luaL_checkany(L, 1); - lua.lua_pushnil(L); /* value is not convertible to integer */ + luaL_checkany(L, 1); + lua_pushnil(L); /* value is not convertible to integer */ } return 1; }; const pushnumint = function(L, d) { - let n = luaconf.lua_numbertointeger(d); + let n = lua_numbertointeger(d); if (n !== false) /* does 'd' fit in an integer? */ - lua.lua_pushinteger(L, n); /* result is integer */ + lua_pushinteger(L, n); /* result is integer */ else - lua.lua_pushnumber(L, d); /* result is float */ + lua_pushnumber(L, d); /* result is float */ }; const math_floor = function(L) { - if (lua.lua_isinteger(L, 1)) - lua.lua_settop(L, 1); + if (lua_isinteger(L, 1)) + lua_settop(L, 1); else - pushnumint(L, Math.floor(lauxlib.luaL_checknumber(L, 1))); + pushnumint(L, Math.floor(luaL_checknumber(L, 1))); return 1; }; const math_ceil = function(L) { - if (lua.lua_isinteger(L, 1)) - lua.lua_settop(L, 1); + if (lua_isinteger(L, 1)) + lua_settop(L, 1); else - pushnumint(L, Math.ceil(lauxlib.luaL_checknumber(L, 1))); + pushnumint(L, Math.ceil(luaL_checknumber(L, 1))); return 1; }; const math_sqrt = function(L) { - lua.lua_pushnumber(L, Math.sqrt(lauxlib.luaL_checknumber(L, 1))); + lua_pushnumber(L, Math.sqrt(luaL_checknumber(L, 1))); return 1; }; const math_ult = function(L) { - let a = lauxlib.luaL_checkinteger(L, 1); - let b = lauxlib.luaL_checkinteger(L, 2); - lua.lua_pushboolean(L, (a >= 0)?(b<0 || a<b):(b<0 && a<b)); + let a = luaL_checkinteger(L, 1); + let b = luaL_checkinteger(L, 2); + lua_pushboolean(L, (a >= 0)?(b<0 || a<b):(b<0 && a<b)); return 1; }; const math_log = function(L) { - let x = lauxlib.luaL_checknumber(L, 1); + let x = luaL_checknumber(L, 1); let res; - if (lua.lua_isnoneornil(L, 2)) + if (lua_isnoneornil(L, 2)) res = Math.log(x); else { - let base = lauxlib.luaL_checknumber(L, 2); + let base = luaL_checknumber(L, 2); if (base === 2) res = Math.log2(x); else if (base === 10) @@ -140,87 +172,87 @@ const math_log = function(L) { else res = Math.log(x)/Math.log(base); } - lua.lua_pushnumber(L, res); + lua_pushnumber(L, res); return 1; }; const math_exp = function(L) { - lua.lua_pushnumber(L, Math.exp(lauxlib.luaL_checknumber(L, 1))); + lua_pushnumber(L, Math.exp(luaL_checknumber(L, 1))); return 1; }; const math_deg = function(L) { - lua.lua_pushnumber(L, lauxlib.luaL_checknumber(L, 1) * (180 / Math.PI)); + lua_pushnumber(L, luaL_checknumber(L, 1) * (180 / Math.PI)); return 1; }; const math_rad = function(L) { - lua.lua_pushnumber(L, lauxlib.luaL_checknumber(L, 1) * (Math.PI / 180)); + lua_pushnumber(L, luaL_checknumber(L, 1) * (Math.PI / 180)); return 1; }; const math_min = function(L) { - let n = lua.lua_gettop(L); /* number of arguments */ + let n = lua_gettop(L); /* number of arguments */ let imin = 1; /* index of current minimum value */ - lauxlib.luaL_argcheck(L, n >= 1, 1, lua.to_luastring("value expected", true)); + luaL_argcheck(L, n >= 1, 1, to_luastring("value expected", true)); for (let i = 2; i <= n; i++){ - if (lua.lua_compare(L, i, imin, lua.LUA_OPLT)) + if (lua_compare(L, i, imin, LUA_OPLT)) imin = i; } - lua.lua_pushvalue(L, imin); + lua_pushvalue(L, imin); return 1; }; const math_max = function(L) { - let n = lua.lua_gettop(L); /* number of arguments */ + let n = lua_gettop(L); /* number of arguments */ let imax = 1; /* index of current minimum value */ - lauxlib.luaL_argcheck(L, n >= 1, 1, lua.to_luastring("value expected", true)); + luaL_argcheck(L, n >= 1, 1, to_luastring("value expected", true)); for (let i = 2; i <= n; i++){ - if (lua.lua_compare(L, imax, i, lua.LUA_OPLT)) + if (lua_compare(L, imax, i, LUA_OPLT)) imax = i; } - lua.lua_pushvalue(L, imax); + lua_pushvalue(L, imax); return 1; }; const math_type = function(L) { - if (lua.lua_type(L, 1) === lua.LUA_TNUMBER) { - if (lua.lua_isinteger(L, 1)) - lua.lua_pushliteral(L, "integer"); + if (lua_type(L, 1) === LUA_TNUMBER) { + if (lua_isinteger(L, 1)) + lua_pushliteral(L, "integer"); else - lua.lua_pushliteral(L, "float"); + lua_pushliteral(L, "float"); } else { - lauxlib.luaL_checkany(L, 1); - lua.lua_pushnil(L); + luaL_checkany(L, 1); + lua_pushnil(L); } return 1; }; const math_fmod = function(L) { - if (lua.lua_isinteger(L, 1) && lua.lua_isinteger(L, 2)) { - let d = lua.lua_tointeger(L, 2); + if (lua_isinteger(L, 1) && lua_isinteger(L, 2)) { + let d = lua_tointeger(L, 2); /* no special case needed for -1 in javascript */ if (d === 0) { - lauxlib.luaL_argerror(L, 2, lua.to_luastring("zero", true)); + luaL_argerror(L, 2, to_luastring("zero", true)); } else - lua.lua_pushinteger(L, (lua.lua_tointeger(L, 1) % d)|0); + lua_pushinteger(L, (lua_tointeger(L, 1) % d)|0); } else { - let a = lauxlib.luaL_checknumber(L, 1); - let b = lauxlib.luaL_checknumber(L, 2); - lua.lua_pushnumber(L, a%b); + let a = luaL_checknumber(L, 1); + let b = luaL_checknumber(L, 2); + lua_pushnumber(L, a%b); } return 1; }; const math_modf = function(L) { - if (lua.lua_isinteger(L, 1)) { - lua.lua_settop(L, 1); /* number is its own integer part */ - lua.lua_pushnumber(L, 0); /* no fractional part */ + if (lua_isinteger(L, 1)) { + lua_settop(L, 1); /* number is its own integer part */ + lua_pushnumber(L, 0); /* no fractional part */ } else { - let n = lauxlib.luaL_checknumber(L, 1); + let n = luaL_checknumber(L, 1); let ip = n < 0 ? Math.ceil(n) : Math.floor(n); pushnumint(L, ip); - lua.lua_pushnumber(L, n === ip ? 0 : n - ip); + lua_pushnumber(L, n === ip ? 0 : n - ip); } return 2; }; @@ -251,15 +283,15 @@ const mathlib = { }; const luaopen_math = function(L) { - lauxlib.luaL_newlib(L, mathlib); - lua.lua_pushnumber(L, Math.PI); - lua.lua_setfield(L, -2, lua.to_luastring("pi", true)); - lua.lua_pushnumber(L, Infinity); - lua.lua_setfield(L, -2, lua.to_luastring("huge", true)); - lua.lua_pushinteger(L, luaconf.LUA_MAXINTEGER); - lua.lua_setfield(L, -2, lua.to_luastring("maxinteger", true)); - lua.lua_pushinteger(L, luaconf.LUA_MININTEGER); - lua.lua_setfield(L, -2, lua.to_luastring("mininteger", true)); + luaL_newlib(L, mathlib); + lua_pushnumber(L, Math.PI); + lua_setfield(L, -2, to_luastring("pi", true)); + lua_pushnumber(L, Infinity); + lua_setfield(L, -2, to_luastring("huge", true)); + lua_pushinteger(L, LUA_MAXINTEGER); + lua_setfield(L, -2, to_luastring("maxinteger", true)); + lua_pushinteger(L, LUA_MININTEGER); + lua_setfield(L, -2, to_luastring("mininteger", true)); return 1; }; diff --git a/src/loadlib.js b/src/loadlib.js index 0be1742..99540e4 100644 --- a/src/loadlib.js +++ b/src/loadlib.js @@ -1,8 +1,74 @@ "use strict"; +const { + LUA_CPATH_DEFAULT, + LUA_DIRSEP, + LUA_EXEC_DIR, + LUA_OK, + LUA_PATH_DEFAULT, + LUA_PATH_MARK, + LUA_PATH_SEP, + LUA_REGISTRYINDEX, + LUA_TNIL, + LUA_TTABLE, + LUA_VERSUFFIX, + lua_callk, + lua_createtable, + lua_getfield, + lua_insert, + lua_isfunction, + lua_isnil, + lua_isstring, + lua_newtable, + lua_pop, + lua_pushboolean, + lua_pushcclosure, + lua_pushcfunction, + lua_pushfstring, + lua_pushglobaltable, + lua_pushlightuserdata, + lua_pushliteral, + lua_pushlstring, + lua_pushnil, + lua_pushstring, + lua_pushvalue, + lua_rawgeti, + lua_rawgetp, + lua_rawseti, + lua_rawsetp, + lua_remove, + lua_setfield, + lua_setmetatable, + lua_settop, + lua_toboolean, + lua_tostring, + lua_touserdata, + lua_upvalueindex +} = require('./lua.js'); +const { + LUA_LOADED_TABLE, + LUA_PRELOAD_TABLE, + luaL_Buffer, + luaL_addvalue, + luaL_buffinit, + luaL_checkstring, + luaL_error, + luaL_getsubtable, + luaL_gsub, + luaL_len, + luaL_loadfile, + luaL_newlib, + luaL_optstring, + luaL_pushresult, + luaL_setfuncs +} = require('./lauxlib.js'); +const { + luastring_indexOf, + to_jsstring, + to_luastring, + to_uristring +} = require("./fengaricore.js"); const fengari = require('./fengari.js'); -const lua = require('./lua.js'); -const lauxlib = require('./lauxlib.js'); const global_env = (function() { /* global WorkerGlobalScope */ /* see https://github.com/sindresorhus/globals/issues/127 */ @@ -21,7 +87,7 @@ const global_env = (function() { } })(); -const CLIBS = lua.to_luastring("__CLIBS__", true); +const CLIBS = to_luastring("__CLIBS__"); const LUA_PATH_VAR = "LUA_PATH"; const LUA_CPATH_VAR = "LUA_CPATH"; @@ -33,17 +99,17 @@ const LUA_IGMARK = "-"; ** LUA_LSUBSEP is the character that replaces dots in submodule names ** when searching for a Lua loader. */ -const LUA_CSUBSEP = lua.LUA_DIRSEP; -const LUA_LSUBSEP = lua.LUA_DIRSEP; +const LUA_CSUBSEP = LUA_DIRSEP; +const LUA_LSUBSEP = LUA_DIRSEP; /* prefix for open functions in C libraries */ -const LUA_POF = lua.to_luastring("luaopen_"); +const LUA_POF = to_luastring("luaopen_"); /* separator for open functions in C libraries */ -const LUA_OFSEP = lua.to_luastring("_"); +const LUA_OFSEP = to_luastring("_"); const LIB_FAIL = "open"; -const AUXMARK = lua.to_luastring("\x01"); +const AUXMARK = to_luastring("\x01"); /* @@ -55,13 +121,13 @@ const AUXMARK = lua.to_luastring("\x01"); let lsys_load; if (typeof process === "undefined") { lsys_load = function(L, path, seeglb) { - path = lua.to_uristring(path); + path = to_uristring(path); let xhr = new XMLHttpRequest(); xhr.open("GET", path, false); xhr.send(); if (xhr.status < 200 || xhr.status >= 300) { - lua.lua_pushstring(L, lua.to_luastring(`${xhr.status}: ${xhr.statusText}`)); + lua_pushstring(L, to_luastring(`${xhr.status}: ${xhr.statusText}`)); return null; } @@ -73,7 +139,7 @@ if (typeof process === "undefined") { try { func = Function("fengari", code); } catch (e) { - lua.lua_pushstring(L, lua.to_luastring(`${e.name}: ${e.message}`)); + lua_pushstring(L, to_luastring(`${e.name}: ${e.message}`)); return null; } let res = func(fengari); @@ -82,20 +148,20 @@ if (typeof process === "undefined") { } else if (res === void 0) { /* assume library added symbols to global environment */ return global_env; } else { - lua.lua_pushstring(L, lua.to_luastring(`library returned unexpected type (${typeof res})`)); + lua_pushstring(L, to_luastring(`library returned unexpected type (${typeof res})`)); return null; } }; } else { const pathlib = require('path'); lsys_load = function(L, path, seeglb) { - path = lua.to_jsstring(path); + path = to_jsstring(path); /* relative paths should be relative to cwd, not this js file */ path = pathlib.resolve(process.cwd(), path); try { return require(path); } catch (e) { - lua.lua_pushstring(L, lua.to_luastring(e.message)); + lua_pushstring(L, to_luastring(e.message)); return null; } }; @@ -107,12 +173,12 @@ if (typeof process === "undefined") { ** error string in the stack. */ const lsys_sym = function(L, lib, sym) { - let f = lib[lua.to_jsstring(sym)]; + let f = lib[to_jsstring(sym)]; if (f && typeof f === 'function') return f; else { - lua.lua_pushfstring(L, lua.to_luastring("undefined symbol: %s"), sym); + lua_pushfstring(L, to_luastring("undefined symbol: %s"), sym); return null; } }; @@ -121,9 +187,9 @@ const lsys_sym = function(L, lib, sym) { ** return registry.LUA_NOENV as a boolean */ const noenv = function(L) { - lua.lua_getfield(L, lua.LUA_REGISTRYINDEX, lua.to_luastring("LUA_NOENV")); - let b = lua.lua_toboolean(L, -1); - lua.lua_pop(L, 1); /* remove value */ + lua_getfield(L, LUA_REGISTRYINDEX, to_luastring("LUA_NOENV")); + let b = lua_toboolean(L, -1); + lua_pop(L, 1); /* remove value */ return b; }; @@ -143,7 +209,7 @@ if (typeof process !== "undefined") { // Only with Node } else { /* TODO: use async/await ? */ readable = function(path) { - path = lua.to_uristring(path); + path = to_uristring(path); let xhr = new XMLHttpRequest(); /* Following GET request done by searcher_Web will be cached */ xhr.open("GET", path, false); @@ -177,28 +243,28 @@ const lookforfunc = function(L, path, sym) { addtoclib(L, path, reg); } if (sym[0] === '*'.charCodeAt(0)) { /* loading only library (no function)? */ - lua.lua_pushboolean(L, 1); /* return 'true' */ + lua_pushboolean(L, 1); /* return 'true' */ return 0; /* no errors */ } else { let f = lsys_sym(L, reg, sym); if (f === null) return ERRFUNC; /* unable to find function */ - lua.lua_pushcfunction(L, f); /* else create new function */ + lua_pushcfunction(L, f); /* else create new function */ return 0; /* no errors */ } }; const ll_loadlib = function(L) { - let path = lauxlib.luaL_checkstring(L, 1); - let init = lauxlib.luaL_checkstring(L, 2); + let path = luaL_checkstring(L, 1); + let init = luaL_checkstring(L, 2); let stat = lookforfunc(L, path, init); if (stat === 0) /* no errors? */ return 1; /* return the loaded function */ else { /* error; error message is on stack top */ - lua.lua_pushnil(L); - lua.lua_insert(L, -2); - lua.lua_pushliteral(L, (stat === ERRLIB) ? LIB_FAIL : "init"); + lua_pushnil(L); + lua_insert(L, -2); + lua_pushliteral(L, (stat === ERRLIB) ? LIB_FAIL : "init"); return 3; /* return nil, error message, and where */ } }; @@ -216,36 +282,36 @@ const env = (function() { ** Set a path */ const setpath = function(L, fieldname, envname, dft) { - let nver = `${envname}${lua.LUA_VERSUFFIX}`; - lua.lua_pushstring(L, lua.to_luastring(nver)); + let nver = `${envname}${LUA_VERSUFFIX}`; + lua_pushstring(L, to_luastring(nver)); let path = env[nver]; /* use versioned name */ if (path === undefined) /* no environment variable? */ path = env[envname]; /* try unversioned name */ if (path === undefined || noenv(L)) /* no environment variable? */ - lua.lua_pushstring(L, lua.to_luastring(dft)); /* use default */ + lua_pushstring(L, dft); /* use default */ else { /* replace ";;" by ";AUXMARK;" and then AUXMARK by default path */ - path = lauxlib.luaL_gsub( + path = luaL_gsub( L, - lua.to_luastring(path), - lua.to_luastring(lua.LUA_PATH_SEP + lua.LUA_PATH_SEP, true), - lua.to_luastring(lua.LUA_PATH_SEP + lua.to_jsstring(AUXMARK) + lua.LUA_PATH_SEP, true) + to_luastring(path), + to_luastring(LUA_PATH_SEP + LUA_PATH_SEP, true), + to_luastring(LUA_PATH_SEP + to_jsstring(AUXMARK) + LUA_PATH_SEP, true) ); - lauxlib.luaL_gsub(L, path, AUXMARK, lua.to_luastring(dft)); - lua.lua_remove(L, -2); /* remove result from 1st 'gsub' */ + luaL_gsub(L, path, AUXMARK, dft); + lua_remove(L, -2); /* remove result from 1st 'gsub' */ } - lua.lua_setfield(L, -3, fieldname); /* package[fieldname] = path value */ - lua.lua_pop(L, 1); /* pop versioned variable name */ + lua_setfield(L, -3, fieldname); /* package[fieldname] = path value */ + lua_pop(L, 1); /* pop versioned variable name */ }; /* ** return registry.CLIBS[path] */ const checkclib = function(L, path) { - lua.lua_rawgetp(L, lua.LUA_REGISTRYINDEX, CLIBS); - lua.lua_getfield(L, -1, path); - let plib = lua.lua_touserdata(L, -1); /* plib = CLIBS[path] */ - lua.lua_pop(L, 2); /* pop CLIBS table and 'plib' */ + lua_rawgetp(L, LUA_REGISTRYINDEX, CLIBS); + lua_getfield(L, -1, path); + let plib = lua_touserdata(L, -1); /* plib = CLIBS[path] */ + lua_pop(L, 2); /* pop CLIBS table and 'plib' */ return plib; }; @@ -254,79 +320,79 @@ const checkclib = function(L, path) { ** registry.CLIBS[#CLIBS + 1] = plib -- also keep a list of all libraries */ const addtoclib = function(L, path, plib) { - lua.lua_rawgetp(L, lua.LUA_REGISTRYINDEX, CLIBS); - lua.lua_pushlightuserdata(L, plib); - lua.lua_pushvalue(L, -1); - lua.lua_setfield(L, -3, path); /* CLIBS[path] = plib */ - lua.lua_rawseti(L, -2, lauxlib.luaL_len(L, -2) + 1); /* CLIBS[#CLIBS + 1] = plib */ - lua.lua_pop(L, 1); /* pop CLIBS table */ + lua_rawgetp(L, LUA_REGISTRYINDEX, CLIBS); + lua_pushlightuserdata(L, plib); + lua_pushvalue(L, -1); + lua_setfield(L, -3, path); /* CLIBS[path] = plib */ + lua_rawseti(L, -2, luaL_len(L, -2) + 1); /* CLIBS[#CLIBS + 1] = plib */ + lua_pop(L, 1); /* pop CLIBS table */ }; const pushnexttemplate = function(L, path) { - while (path[0] === lua.LUA_PATH_SEP.charCodeAt(0)) path = path.slice(1); /* skip separators */ + while (path[0] === LUA_PATH_SEP.charCodeAt(0)) path = path.subarray(1); /* skip separators */ if (path.length === 0) return null; /* no more templates */ - let l = path.indexOf(lua.LUA_PATH_SEP.charCodeAt(0)); /* find next separator */ + let l = luastring_indexOf(path, LUA_PATH_SEP.charCodeAt(0)); /* find next separator */ if (l < 0) l = path.length; - lua.lua_pushlstring(L, path, l); /* template */ - return path.slice(l); + lua_pushlstring(L, path, l); /* template */ + return path.subarray(l); }; const searchpath = function(L, name, path, sep, dirsep) { - let msg = new lauxlib.luaL_Buffer(); /* to build error message */ - lauxlib.luaL_buffinit(L, msg); + let msg = new luaL_Buffer(); /* to build error message */ + luaL_buffinit(L, msg); if (sep[0] !== 0) /* non-empty separator? */ - name = lauxlib.luaL_gsub(L, name, sep, dirsep); /* replace it by 'dirsep' */ + name = luaL_gsub(L, name, sep, dirsep); /* replace it by 'dirsep' */ while ((path = pushnexttemplate(L, path)) !== null) { - let filename = lauxlib.luaL_gsub(L, lua.lua_tostring(L, -1), lua.to_luastring(lua.LUA_PATH_MARK, true), name); - lua.lua_remove(L, -2); /* remove path template */ + let filename = luaL_gsub(L, lua_tostring(L, -1), to_luastring(LUA_PATH_MARK, true), name); + lua_remove(L, -2); /* remove path template */ if (readable(filename)) /* does file exist and is readable? */ return filename; /* return that file name */ - lua.lua_pushfstring(L, lua.to_luastring("\n\tno file '%s'"), filename); - lua.lua_remove(L, -2); /* remove file name */ - lauxlib.luaL_addvalue(msg); + lua_pushfstring(L, to_luastring("\n\tno file '%s'"), filename); + lua_remove(L, -2); /* remove file name */ + luaL_addvalue(msg); } - lauxlib.luaL_pushresult(msg); /* create error message */ + luaL_pushresult(msg); /* create error message */ return null; /* not found */ }; const ll_searchpath = function(L) { let f = searchpath( L, - lauxlib.luaL_checkstring(L, 1), - lauxlib.luaL_checkstring(L, 2), - lauxlib.luaL_optstring(L, 3, lua.to_luastring(".")), - lauxlib.luaL_optstring(L, 4, lua.to_luastring(lua.LUA_DIRSEP)) + luaL_checkstring(L, 1), + luaL_checkstring(L, 2), + luaL_optstring(L, 3, to_luastring(".")), + luaL_optstring(L, 4, to_luastring(LUA_DIRSEP)) ); if (f !== null) return 1; else { /* error message is on top of the stack */ - lua.lua_pushnil(L); - lua.lua_insert(L, -2); + lua_pushnil(L); + lua_insert(L, -2); return 2; /* return nil + error message */ } }; const findfile = function(L, name, pname, dirsep) { - lua.lua_getfield(L, lua.lua_upvalueindex(1), pname); - let path = lua.lua_tostring(L, -1); + lua_getfield(L, lua_upvalueindex(1), pname); + let path = lua_tostring(L, -1); if (path === null) - lauxlib.luaL_error(L, lua.to_luastring("'package.%s' must be a string"), pname); - return searchpath(L, name, path, lua.to_luastring("."), dirsep); + luaL_error(L, to_luastring("'package.%s' must be a string"), pname); + return searchpath(L, name, path, to_luastring("."), dirsep); }; const checkload = function(L, stat, filename) { if (stat) { /* module loaded successfully? */ - lua.lua_pushstring(L, filename); /* will be 2nd argument to module */ + lua_pushstring(L, filename); /* will be 2nd argument to module */ return 2; /* return open function and file name */ } else - return lauxlib.luaL_error(L, lua.to_luastring("error loading module '%s' from file '%s':\n\t%s"), - lua.lua_tostring(L, 1), filename, lua.lua_tostring(L, -1)); + return luaL_error(L, to_luastring("error loading module '%s' from file '%s':\n\t%s"), + lua_tostring(L, 1), filename, lua_tostring(L, -1)); }; const searcher_Lua = function(L) { - let name = lauxlib.luaL_checkstring(L, 1); - let filename = findfile(L, name, lua.to_luastring("path", true), lua.to_luastring(LUA_LSUBSEP, true)); + let name = luaL_checkstring(L, 1); + let filename = findfile(L, name, to_luastring("path", true), to_luastring(LUA_LSUBSEP, true)); if (filename === null) return 1; /* module not found in this path */ - return checkload(L, lauxlib.luaL_loadfile(L, filename) === lua.LUA_OK, filename); + return checkload(L, luaL_loadfile(L, filename) === LUA_OK, filename); }; /* @@ -339,119 +405,119 @@ const searcher_Lua = function(L) { */ const loadfunc = function(L, filename, modname) { let openfunc; - modname = lauxlib.luaL_gsub(L, modname, lua.to_luastring("."), LUA_OFSEP); - let mark = modname.indexOf(LUA_IGMARK.charCodeAt(0)); + modname = luaL_gsub(L, modname, to_luastring("."), LUA_OFSEP); + let mark = luastring_indexOf(modname, LUA_IGMARK.charCodeAt(0)); if (mark >= 0) { - openfunc = lua.lua_pushlstring(L, modname, mark); - openfunc = lua.lua_pushfstring(L, lua.to_luastring("%s%s"), LUA_POF, openfunc); + openfunc = lua_pushlstring(L, modname, mark); + openfunc = lua_pushfstring(L, to_luastring("%s%s"), LUA_POF, openfunc); let stat = lookforfunc(L, filename, openfunc); if (stat !== ERRFUNC) return stat; modname = mark + 1; /* else go ahead and try old-style name */ } - openfunc = lua.lua_pushfstring(L, lua.to_luastring("%s%s"), LUA_POF, modname); + openfunc = lua_pushfstring(L, to_luastring("%s%s"), LUA_POF, modname); return lookforfunc(L, filename, openfunc); }; const searcher_C = function(L) { - let name = lauxlib.luaL_checkstring(L, 1); - let filename = findfile(L, name, lua.to_luastring("cpath", true), lua.to_luastring(LUA_CSUBSEP, true)); + let name = luaL_checkstring(L, 1); + let filename = findfile(L, name, to_luastring("cpath", true), to_luastring(LUA_CSUBSEP, true)); if (filename === null) return 1; /* module not found in this path */ return checkload(L, (loadfunc(L, filename, name) === 0), filename); }; const searcher_Croot = function(L) { - let name = lauxlib.luaL_checkstring(L, 1); - let p = name.indexOf('.'.charCodeAt(0)); + let name = luaL_checkstring(L, 1); + let p = luastring_indexOf(name, '.'.charCodeAt(0)); let stat; if (p < 0) return 0; /* is root */ - lua.lua_pushlstring(L, name, p); - let filename = findfile(L, lua.lua_tostring(L, -1), lua.to_luastring("cpath", true), lua.to_luastring(LUA_CSUBSEP, true)); + lua_pushlstring(L, name, p); + let filename = findfile(L, lua_tostring(L, -1), to_luastring("cpath", true), to_luastring(LUA_CSUBSEP, true)); if (filename === null) return 1; /* root not found */ if ((stat = loadfunc(L, filename, name)) !== 0) { if (stat != ERRFUNC) return checkload(L, 0, filename); /* real error */ else { /* open function not found */ - lua.lua_pushstring(L, lua.to_luastring("\n\tno module '%s' in file '%s'"), name, filename); + lua_pushstring(L, to_luastring("\n\tno module '%s' in file '%s'"), name, filename); return 1; } } - lua.lua_pushstring(L, filename); /* will be 2nd argument to module */ + lua_pushstring(L, filename); /* will be 2nd argument to module */ return 2; }; const searcher_preload = function(L) { - let name = lauxlib.luaL_checkstring(L, 1); - lua.lua_getfield(L, lua.LUA_REGISTRYINDEX, lauxlib.LUA_PRELOAD_TABLE); - if (lua.lua_getfield(L, -1, name) === lua.LUA_TNIL) /* not found? */ - lua.lua_pushfstring(L, lua.to_luastring("\n\tno field package.preload['%s']"), name); + let name = luaL_checkstring(L, 1); + lua_getfield(L, LUA_REGISTRYINDEX, LUA_PRELOAD_TABLE); + if (lua_getfield(L, -1, name) === LUA_TNIL) /* not found? */ + lua_pushfstring(L, to_luastring("\n\tno field package.preload['%s']"), name); return 1; }; const findloader = function(L, name, ctx, k) { - let msg = new lauxlib.luaL_Buffer(); /* to build error message */ - lauxlib.luaL_buffinit(L, msg); + let msg = new luaL_Buffer(); /* to build error message */ + luaL_buffinit(L, msg); /* push 'package.searchers' to index 3 in the stack */ - if (lua.lua_getfield(L, lua.lua_upvalueindex(1), lua.to_luastring("searchers", true)) !== lua.LUA_TTABLE) - lauxlib.luaL_error(L, lua.to_luastring("'package.searchers' must be a table")); + if (lua_getfield(L, lua_upvalueindex(1), to_luastring("searchers", true)) !== LUA_TTABLE) + luaL_error(L, to_luastring("'package.searchers' must be a table")); let ctx2 = {name: name, i: 1, msg: msg, ctx: ctx, k: k}; - return findloader_cont(L, lua.LUA_OK, ctx2); + return findloader_cont(L, LUA_OK, ctx2); }; const findloader_cont = function(L, status, ctx) { /* iterate over available searchers to find a loader */ for (; ; ctx.i++) { - if (status === lua.LUA_OK) { - if (lua.lua_rawgeti(L, 3, ctx.i) === lua.LUA_TNIL) { /* no more searchers? */ - lua.lua_pop(L, 1); /* remove nil */ - lauxlib.luaL_pushresult(ctx.msg); /* create error message */ - lauxlib.luaL_error(L, lua.to_luastring("module '%s' not found:%s"), ctx.name, lua.lua_tostring(L, -1)); + if (status === LUA_OK) { + if (lua_rawgeti(L, 3, ctx.i) === LUA_TNIL) { /* no more searchers? */ + lua_pop(L, 1); /* remove nil */ + luaL_pushresult(ctx.msg); /* create error message */ + luaL_error(L, to_luastring("module '%s' not found:%s"), ctx.name, lua_tostring(L, -1)); } - lua.lua_pushstring(L, ctx.name); - lua.lua_callk(L, 1, 2, ctx, findloader_cont); /* call it */ + lua_pushstring(L, ctx.name); + lua_callk(L, 1, 2, ctx, findloader_cont); /* call it */ } else { - status = lua.LUA_OK; + status = LUA_OK; } - if (lua.lua_isfunction(L, -2)) /* did it find a loader? */ + if (lua_isfunction(L, -2)) /* did it find a loader? */ break; /* module loader found */ - else if (lua.lua_isstring(L, -2)) { /* searcher returned error message? */ - lua.lua_pop(L, 1); /* remove extra return */ - lauxlib.luaL_addvalue(ctx.msg); /* concatenate error message */ + else if (lua_isstring(L, -2)) { /* searcher returned error message? */ + lua_pop(L, 1); /* remove extra return */ + luaL_addvalue(ctx.msg); /* concatenate error message */ } else - lua.lua_pop(L, 2); /* remove both returns */ + lua_pop(L, 2); /* remove both returns */ } - return ctx.k(L, lua.LUA_OK, ctx.ctx); + return ctx.k(L, LUA_OK, ctx.ctx); }; const ll_require = function(L) { - let name = lauxlib.luaL_checkstring(L, 1); - lua.lua_settop(L, 1); /* LOADED table will be at index 2 */ - lua.lua_getfield(L, lua.LUA_REGISTRYINDEX, lauxlib.LUA_LOADED_TABLE); - lua.lua_getfield(L, 2, name); /* LOADED[name] */ - if (lua.lua_toboolean(L, -1)) /* is it there? */ + let name = luaL_checkstring(L, 1); + lua_settop(L, 1); /* LOADED table will be at index 2 */ + lua_getfield(L, LUA_REGISTRYINDEX, LUA_LOADED_TABLE); + lua_getfield(L, 2, name); /* LOADED[name] */ + if (lua_toboolean(L, -1)) /* is it there? */ return 1; /* package is already loaded */ /* else must load package */ - lua.lua_pop(L, 1); /* remove 'getfield' result */ + lua_pop(L, 1); /* remove 'getfield' result */ let ctx = name; return findloader(L, name, ctx, ll_require_cont); }; const ll_require_cont = function(L, status, ctx) { let name = ctx; - lua.lua_pushstring(L, name); /* pass name as argument to module loader */ - lua.lua_insert(L, -2); /* name is 1st argument (before search data) */ - lua.lua_callk(L, 2, 1, ctx, ll_require_cont2); - return ll_require_cont2(L, lua.LUA_OK, ctx); /* run loader to load module */ + lua_pushstring(L, name); /* pass name as argument to module loader */ + lua_insert(L, -2); /* name is 1st argument (before search data) */ + lua_callk(L, 2, 1, ctx, ll_require_cont2); + return ll_require_cont2(L, LUA_OK, ctx); /* run loader to load module */ }; const ll_require_cont2 = function(L, status, ctx) { let name = ctx; - if (!lua.lua_isnil(L, -1)) /* non-nil return? */ - lua.lua_setfield(L, 2, name); /* LOADED[name] = returned value */ - if (lua.lua_getfield(L, 2, name) == lua.LUA_TNIL) { /* module set no value? */ - lua.lua_pushboolean(L, 1); /* use true as result */ - lua.lua_pushvalue(L, -1); /* extra copy to be returned */ - lua.lua_setfield(L, 2, name); /* LOADED[name] = true */ + if (!lua_isnil(L, -1)) /* non-nil return? */ + lua_setfield(L, 2, name); /* LOADED[name] = returned value */ + if (lua_getfield(L, 2, name) == LUA_TNIL) { /* module set no value? */ + lua_pushboolean(L, 1); /* use true as result */ + lua_pushvalue(L, -1); /* extra copy to be returned */ + lua_setfield(L, 2, name); /* LOADED[name] = true */ } return 1; }; @@ -468,14 +534,14 @@ const ll_funcs = { const createsearcherstable = function(L) { let searchers = [searcher_preload, searcher_Lua, searcher_C, searcher_Croot, null]; /* create 'searchers' table */ - lua.lua_createtable(L); + lua_createtable(L); /* fill it with predefined searchers */ for (let i = 0; searchers[i]; i++) { - lua.lua_pushvalue(L, -2); /* set 'package' as upvalue for all searchers */ - lua.lua_pushcclosure(L, searchers[i], 1); - lua.lua_rawseti(L, -2, i+1); + lua_pushvalue(L, -2); /* set 'package' as upvalue for all searchers */ + lua_pushcclosure(L, searchers[i], 1); + lua_rawseti(L, -2, i+1); } - lua.lua_setfield(L, -2, lua.to_luastring("searchers", true)); /* put it in field 'searchers' */ + lua_setfield(L, -2, to_luastring("searchers", true)); /* put it in field 'searchers' */ }; /* @@ -483,33 +549,33 @@ const createsearcherstable = function(L) { ** setting a finalizer to close all libraries when closing state. */ const createclibstable = function(L) { - lua.lua_newtable(L); /* create CLIBS table */ - lua.lua_createtable(L, 0, 1); /* create metatable for CLIBS */ - lua.lua_setmetatable(L, -2); - lua.lua_rawsetp(L, lua.LUA_REGISTRYINDEX, CLIBS); /* set CLIBS table in registry */ + lua_newtable(L); /* create CLIBS table */ + lua_createtable(L, 0, 1); /* create metatable for CLIBS */ + lua_setmetatable(L, -2); + lua_rawsetp(L, LUA_REGISTRYINDEX, CLIBS); /* set CLIBS table in registry */ }; const luaopen_package = function(L) { createclibstable(L); - lauxlib.luaL_newlib(L, pk_funcs); /* create 'package' table */ + luaL_newlib(L, pk_funcs); /* create 'package' table */ createsearcherstable(L); /* set paths */ - setpath(L, lua.to_luastring("path", true), LUA_PATH_VAR, lua.LUA_PATH_DEFAULT); - setpath(L, lua.to_luastring("cpath", true), LUA_CPATH_VAR, lua.LUA_CPATH_DEFAULT); + setpath(L, to_luastring("path", true), LUA_PATH_VAR, LUA_PATH_DEFAULT); + setpath(L, to_luastring("cpath", true), LUA_CPATH_VAR, LUA_CPATH_DEFAULT); /* store config information */ - lua.lua_pushliteral(L, lua.LUA_DIRSEP + "\n" + lua.LUA_PATH_SEP + "\n" + lua.LUA_PATH_MARK + "\n" + - lua.LUA_EXEC_DIR + "\n" + LUA_IGMARK + "\n"); - lua.lua_setfield(L, -2, lua.to_luastring("config", true)); + lua_pushliteral(L, LUA_DIRSEP + "\n" + LUA_PATH_SEP + "\n" + LUA_PATH_MARK + "\n" + + LUA_EXEC_DIR + "\n" + LUA_IGMARK + "\n"); + lua_setfield(L, -2, to_luastring("config", true)); /* set field 'loaded' */ - lauxlib.luaL_getsubtable(L, lua.LUA_REGISTRYINDEX, lauxlib.LUA_LOADED_TABLE); - lua.lua_setfield(L, -2, lua.to_luastring("loaded", true)); + luaL_getsubtable(L, LUA_REGISTRYINDEX, LUA_LOADED_TABLE); + lua_setfield(L, -2, to_luastring("loaded", true)); /* set field 'preload' */ - lauxlib.luaL_getsubtable(L, lua.LUA_REGISTRYINDEX, lauxlib.LUA_PRELOAD_TABLE); - lua.lua_setfield(L, -2, lua.to_luastring("preload", true)); - lua.lua_pushglobaltable(L); - lua.lua_pushvalue(L, -2); /* set 'package' as upvalue for next lib */ - lauxlib.luaL_setfuncs(L, ll_funcs, 1); /* open lib into global table */ - lua.lua_pop(L, 1); /* pop global table */ + luaL_getsubtable(L, LUA_REGISTRYINDEX, LUA_PRELOAD_TABLE); + lua_setfield(L, -2, to_luastring("preload", true)); + lua_pushglobaltable(L); + lua_pushvalue(L, -2); /* set 'package' as upvalue for next lib */ + luaL_setfuncs(L, ll_funcs, 1); /* open lib into global table */ + lua_pop(L, 1); /* pop global table */ return 1; /* return 'package' table */ }; diff --git a/src/lobject.js b/src/lobject.js index 37419a9..4b3d0aa 100644 --- a/src/lobject.js +++ b/src/lobject.js @@ -1,24 +1,75 @@ "use strict"; -const assert = require('assert'); - -const defs = require('./defs.js'); -const ljstype = require('./ljstype.js'); +const { + LUA_OPADD, + LUA_OPBAND, + LUA_OPBNOT, + LUA_OPBOR, + LUA_OPBXOR, + LUA_OPDIV, + LUA_OPIDIV, + LUA_OPMOD, + LUA_OPMUL, + LUA_OPPOW, + LUA_OPSHL, + LUA_OPSHR, + LUA_OPSUB, + LUA_OPUNM, + constant_types: { + LUA_NUMTAGS, + LUA_TBOOLEAN, + LUA_TCCL, + LUA_TFUNCTION, + LUA_TLCF, + LUA_TLCL, + LUA_TLIGHTUSERDATA, + LUA_TLNGSTR, + LUA_TNIL, + LUA_TNUMBER, + LUA_TNUMFLT, + LUA_TNUMINT, + LUA_TSHRSTR, + LUA_TSTRING, + LUA_TTABLE, + LUA_TTHREAD, + LUA_TUSERDATA + }, + from_userstring, + luastring_indexOf, + luastring_of, + to_jsstring, + to_luastring +} = require('./defs.js'); +const { + lisdigit, + lisprint, + lisspace, + lisxdigit +} = require('./ljstype.js'); const ldebug = require('./ldebug.js'); const ldo = require('./ldo.js'); -const lfunc = require('./lfunc.js'); const lstate = require('./lstate.js'); -const lstring = require('./lstring.js'); +const { + luaS_bless, + luaS_new +} = require('./lstring.js'); const ltable = require('./ltable.js'); -const luaconf = require('./luaconf.js'); +const { + ldexp, + lua_getlocaledecpoint, + lua_integer2str, + lua_number2str +} = require('./luaconf.js'); const lvm = require('./lvm.js'); -const llimits = require('./llimits.js'); +const { + MAX_INT, + luai_nummod, + lua_assert +} = require("./llimits.js"); const ltm = require('./ltm.js'); -const CT = defs.constant_types; -const char = defs.char; -const LUA_TPROTO = CT.LUA_NUMTAGS; -const LUA_TDEADKEY = CT.LUA_NUMTAGS+1; +const LUA_TPROTO = LUA_NUMTAGS; +const LUA_TDEADKEY = LUA_NUMTAGS+1; class TValue { @@ -46,71 +97,71 @@ class TValue { } ttisnumber() { - return this.checktype(CT.LUA_TNUMBER); + return this.checktype(LUA_TNUMBER); } ttisfloat() { - return this.checktag(CT.LUA_TNUMFLT); + return this.checktag(LUA_TNUMFLT); } ttisinteger() { - return this.checktag(CT.LUA_TNUMINT); + return this.checktag(LUA_TNUMINT); } ttisnil() { - return this.checktag(CT.LUA_TNIL); + return this.checktag(LUA_TNIL); } ttisboolean() { - return this.checktag(CT.LUA_TBOOLEAN); + return this.checktag(LUA_TBOOLEAN); } ttislightuserdata() { - return this.checktag(CT.LUA_TLIGHTUSERDATA); + return this.checktag(LUA_TLIGHTUSERDATA); } ttisstring() { - return this.checktype(CT.LUA_TSTRING); + return this.checktype(LUA_TSTRING); } ttisshrstring() { - return this.checktag(CT.LUA_TSHRSTR); + return this.checktag(LUA_TSHRSTR); } ttislngstring() { - return this.checktag(CT.LUA_TLNGSTR); + return this.checktag(LUA_TLNGSTR); } ttistable() { - return this.checktag(CT.LUA_TTABLE); + return this.checktag(LUA_TTABLE); } ttisfunction() { - return this.checktype(CT.LUA_TFUNCTION); + return this.checktype(LUA_TFUNCTION); } ttisclosure() { - return (this.type & 0x1F) === CT.LUA_TFUNCTION; + return (this.type & 0x1F) === LUA_TFUNCTION; } ttisCclosure() { - return this.checktag(CT.LUA_TCCL); + return this.checktag(LUA_TCCL); } ttisLclosure() { - return this.checktag(CT.LUA_TLCL); + return this.checktag(LUA_TLCL); } ttislcf() { - return this.checktag(CT.LUA_TLCF); + return this.checktag(LUA_TLCF); } ttisfulluserdata() { - return this.checktag(CT.LUA_TUSERDATA); + return this.checktag(LUA_TUSERDATA); } ttisthread() { - return this.checktag(CT.LUA_TTHREAD); + return this.checktag(LUA_TTHREAD); } ttisdeadkey() { @@ -122,72 +173,72 @@ class TValue { } setfltvalue(x) { - this.type = CT.LUA_TNUMFLT; + this.type = LUA_TNUMFLT; this.value = x; } chgfltvalue(x) { - assert(this.type == CT.LUA_TNUMFLT); + lua_assert(this.type == LUA_TNUMFLT); this.value = x; } setivalue(x) { - this.type = CT.LUA_TNUMINT; + this.type = LUA_TNUMINT; this.value = x; } chgivalue(x) { - assert(this.type == CT.LUA_TNUMINT); + lua_assert(this.type == LUA_TNUMINT); this.value = x; } setnilvalue() { - this.type = CT.LUA_TNIL; - this.value = void 0; + this.type = LUA_TNIL; + this.value = null; } setfvalue(x) { - this.type = CT.LUA_TLCF; + this.type = LUA_TLCF; this.value = x; } setpvalue(x) { - this.type = CT.LUA_TLIGHTUSERDATA; + this.type = LUA_TLIGHTUSERDATA; this.value = x; } setbvalue(x) { - this.type = CT.LUA_TBOOLEAN; + this.type = LUA_TBOOLEAN; this.value = x; } setsvalue(x) { - this.type = CT.LUA_TLNGSTR; /* LUA_TSHRSTR? */ + this.type = LUA_TLNGSTR; /* LUA_TSHRSTR? */ this.value = x; } setuvalue(x) { - this.type = CT.LUA_TUSERDATA; + this.type = LUA_TUSERDATA; this.value = x; } setthvalue(x) { - this.type = CT.LUA_TTHREAD; + this.type = LUA_TTHREAD; this.value = x; } setclLvalue(x) { - this.type = CT.LUA_TLCL; + this.type = LUA_TLCL; this.value = x; } setclCvalue(x) { - this.type = CT.LUA_TCCL; + this.type = LUA_TCCL; this.value = x; } sethvalue(x) { - this.type = CT.LUA_TTABLE; + this.type = LUA_TTABLE; this.value = x; } @@ -202,7 +253,7 @@ class TValue { } tsvalue() { - assert(this.ttisstring()); + lua_assert(this.ttisstring()); return this.value; } @@ -215,7 +266,7 @@ class TValue { } jsstring(from, to) { - return defs.to_jsstring(this.svalue(), from, to); + return to_jsstring(this.svalue(), from, to); } } @@ -224,7 +275,7 @@ const pushobj2s = function(L, tv) { L.stack[L.top++] = new TValue(tv.type, tv.value); }; const pushsvalue2s = function(L, ts) { - L.stack[L.top++] = new TValue(CT.LUA_TLNGSTR, ts); + L.stack[L.top++] = new TValue(LUA_TLNGSTR, ts); }; /* from stack to (same) stack */ const setobjs2s = function(L, newidx, oldidx) { @@ -238,7 +289,7 @@ const setsvalue2s = function(L, newidx, ts) { L.stack[newidx].setsvalue(ts); }; -const luaO_nilobject = new TValue(CT.LUA_TNIL, null); +const luaO_nilobject = new TValue(LUA_TNIL, null); Object.freeze(luaO_nilobject); module.exports.luaO_nilobject = luaO_nilobject; @@ -249,7 +300,7 @@ class LClosure { this.p = null; this.nupvalues = n; - this.upvals = new Array(n); /* list of upvalues as UpVals. initialised in luaF_initupvals */ + this.upvals = new Array(n); /* list of upvalues. initialised in luaF_initupvals */ } } @@ -263,7 +314,7 @@ class CClosure { this.nupvalues = n; this.upvalue = new Array(n); /* list of upvalues as TValues */ while (n--) { - this.upvalue[n] = new TValue(CT.LUA_TNIL, null); + this.upvalue[n] = new TValue(LUA_TNIL, null); } } @@ -275,7 +326,7 @@ class Udata { this.id = L.l_G.id_counter++; this.metatable = null; - this.uservalue = new TValue(CT.LUA_TNIL, null); + this.uservalue = new TValue(LUA_TNIL, null); this.len = size; this.data = Object.create(null); // ignores size argument } @@ -294,23 +345,26 @@ class LocVar { } } -const RETS = defs.to_luastring("..."); -const PRE = defs.to_luastring("[string \""); -const POS = defs.to_luastring("\"]"); +const RETS = to_luastring("..."); +const PRE = to_luastring("[string \""); +const POS = to_luastring("\"]"); const luaO_chunkid = function(source, bufflen) { let l = source.length; let out; - if (source[0] === char['=']) { /* 'literal' source */ - if (l < bufflen) /* small enough? */ - out = source.slice(1); - else { /* truncate it */ - out = source.slice(1, bufflen+1); + if (source[0] === 61 /* ('=').charCodeAt(0) */) { /* 'literal' source */ + if (l < bufflen) { /* small enough? */ + out = new Uint8Array(l-1); + out.set(source.subarray(1)); + } else { /* truncate it */ + out = new Uint8Array(bufflen); + out.set(source.subarray(1, bufflen+1)); } - } else if (source[0] === char['@']) { /* file name */ - if (l <= bufflen) /* small enough? */ - out = source.slice(1); - else { /* add '...' before rest of name */ + } else if (source[0] === 64 /* ('@').charCodeAt(0) */) { /* file name */ + if (l <= bufflen) { /* small enough? */ + out = new Uint8Array(l-1); + out.set(source.subarray(1)); + } else { /* add '...' before rest of name */ out = new Uint8Array(bufflen); out.set(RETS); bufflen -= RETS.length; @@ -318,7 +372,7 @@ const luaO_chunkid = function(source, bufflen) { } } else { /* string; format as [string "source"] */ out = new Uint8Array(bufflen); - let nli = source.indexOf(char['\n']); /* find first new line (if any) */ + let nli = luastring_indexOf(source, 10 /* ('\n').charCodeAt(0) */); /* find first new line (if any) */ out.set(PRE); /* add prefix */ let out_i = PRE.length; bufflen -= PRE.length + RETS.length + POS.length; /* save space for prefix+suffix */ @@ -341,15 +395,15 @@ const luaO_chunkid = function(source, bufflen) { }; const luaO_hexavalue = function(c) { - if (ljstype.lisdigit(c)) return c - char['0']; - else return (String.fromCharCode(c).toLowerCase().charCodeAt(0) - char['a']) + 10; + if (lisdigit(c)) return c - 48; + else return (c & 0xdf) - 55; }; const UTF8BUFFSZ = 8; const luaO_utf8esc = function(buff, x) { let n = 1; /* number of bytes put in buffer (backwards) */ - assert(x <= 0x10FFFF); + lua_assert(x <= 0x10FFFF); if (x < 0x80) /* ascii? */ buff[UTF8BUFFSZ - 1] = x; else { /* need continuation bytes */ @@ -374,24 +428,24 @@ const MAXSIGDIG = 30; */ const lua_strx2number = function(s) { let i = 0; - let dot = char[luaconf.lua_getlocaledecpoint()]; + let dot = lua_getlocaledecpoint(); let r = 0.0; /* result (accumulator) */ let sigdig = 0; /* number of significant digits */ let nosigdig = 0; /* number of non-significant digits */ let e = 0; /* exponent correction */ let neg; /* 1 if number is negative */ let hasdot = false; /* true after seen a dot */ - while (ljstype.lisspace(s[i])) i++; /* skip initial spaces */ - if ((neg = (s[i] === char['-']))) i++; /* check signal */ - else if (s[i] === char['+']) i++; - if (!(s[i] === char['0'] && (s[i+1] === char['x'] || s[i+1] === char['X']))) /* check '0x' */ + while (lisspace(s[i])) i++; /* skip initial spaces */ + if ((neg = (s[i] === 45 /* ('-').charCodeAt(0) */))) i++; /* check signal */ + else if (s[i] === 43 /* ('+').charCodeAt(0) */) i++; + if (!(s[i] === 48 /* ('0').charCodeAt(0) */ && (s[i+1] === 120 /* ('x').charCodeAt(0) */ || s[i+1] === 88 /* ('X').charCodeAt(0) */))) /* check '0x' */ return null; /* invalid format (no '0x') */ for (i += 2; ; i++) { /* skip '0x' and read numeral */ if (s[i] === dot) { if (hasdot) break; /* second dot? stop loop */ else hasdot = true; - } else if (ljstype.lisxdigit(s[i])) { - if (sigdig === 0 && s[i] === char['0']) /* non-significant digit (zero)? */ + } else if (lisxdigit(s[i])) { + if (sigdig === 0 && s[i] === 48 /* ('0').charCodeAt(0) */) /* non-significant digit (zero)? */ nosigdig++; else if (++sigdig <= MAXSIGDIG) /* can read it without overflow? */ r = (r * 16) + luaO_hexavalue(s[i]); @@ -403,29 +457,29 @@ const lua_strx2number = function(s) { if (nosigdig + sigdig === 0) /* no digits? */ return null; /* invalid format */ e *= 4; /* each digit multiplies/divides value by 2^4 */ - if (s[i] === char['p'] || s[i] === char['P']) { /* exponent part? */ + if (s[i] === 112 /* ('p').charCodeAt(0) */ || s[i] === 80 /* ('P').charCodeAt(0) */) { /* exponent part? */ let exp1 = 0; /* exponent value */ let neg1; /* exponent signal */ i++; /* skip 'p' */ - if ((neg1 = (s[i] === char['-']))) i++; /* signal */ - else if (s[i] === char['+']) i++; - if (!ljstype.lisdigit(s[i])) + if ((neg1 = (s[i] === 45 /* ('-').charCodeAt(0) */))) i++; /* signal */ + else if (s[i] === 43 /* ('+').charCodeAt(0) */) i++; + if (!lisdigit(s[i])) return null; /* invalid; must have at least one digit */ - while (ljstype.lisdigit(s[i])) /* read exponent */ - exp1 = exp1 * 10 + s[i++] - char['0']; + while (lisdigit(s[i])) /* read exponent */ + exp1 = exp1 * 10 + s[i++] - 48 /* ('0').charCodeAt(0) */; if (neg1) exp1 = -exp1; e += exp1; } if (neg) r = -r; return { - n: luaconf.ldexp(r, e), + n: ldexp(r, e), i: i }; }; const lua_str2number = function(s) { try { - s = defs.to_jsstring(s); + s = to_jsstring(s); } catch (e) { return null; } @@ -441,26 +495,46 @@ const lua_str2number = function(s) { const l_str2dloc = function(s, mode) { let result = mode === 'x' ? lua_strx2number(s) : lua_str2number(s); /* try to convert */ if (result === null) return null; - while (ljstype.lisspace(s[result.i])) result.i++; /* skip trailing spaces */ + while (lisspace(s[result.i])) result.i++; /* skip trailing spaces */ return (result.i === s.length || s[result.i] === 0) ? result : null; /* OK if no trailing characters */ }; +const SIGILS = [ + 46 /* (".").charCodeAt(0) */, + 120 /* ("x").charCodeAt(0) */, + 88 /* ("X").charCodeAt(0) */, + 110 /* ("n").charCodeAt(0) */, + 78 /* ("N").charCodeAt(0) */ +]; +const modes = { + [ 46]: ".", + [120]: "x", + [ 88]: "x", + [110]: "n", + [ 78]: "n" +}; const l_str2d = function(s) { - let pidx = /[.xXnN]/g.exec(String.fromCharCode(...s)); - pidx = pidx ? pidx.index : null; - let pmode = pidx ? s[pidx] : null; - let mode = pmode ? String.fromCharCode(pmode).toLowerCase() : 0; + let l = s.length; + let pmode = 0; + for (let i=0; i<l; i++) { + let v = s[i]; + if (SIGILS.indexOf(v) !== -1) { + pmode = v; + break; + } + } + let mode = modes[pmode]; if (mode === 'n') /* reject 'inf' and 'nan' */ return null; let end = l_str2dloc(s, mode); /* try to convert */ - if (end === null) { /* failed? may be a different locale */ - // throw new Error("Locale not available to handle number"); // TODO - } + // if (end === null) { /* failed? may be a different locale */ + // throw new Error("Locale not available to handle number"); // TODO + // } return end; }; -const MAXBY10 = Math.floor(llimits.MAX_INT / 10); -const MAXLASTD = llimits.MAX_INT % 10; +const MAXBY10 = Math.floor(MAX_INT / 10); +const MAXLASTD = MAX_INT % 10; const l_str2int = function(s) { let i = 0; @@ -468,26 +542,25 @@ const l_str2int = function(s) { let empty = true; let neg; - while (ljstype.lisspace(s[i])) i++; /* skip initial spaces */ - if ((neg = (s[i] === char['-']))) i++; - else if (s[i] === char['+']) i++; - if (s[i] === char['0'] && (s[i+1] === char['x'] || s[i+1] === char['X'])) { /* hex? */ + while (lisspace(s[i])) i++; /* skip initial spaces */ + if ((neg = (s[i] === 45 /* ('-').charCodeAt(0) */))) i++; + else if (s[i] === 43 /* ('+').charCodeAt(0) */) i++; + if (s[i] === 48 /* ('0').charCodeAt(0) */ && (s[i+1] === 120 /* ('x').charCodeAt(0) */ || s[i+1] === 88 /* ('X').charCodeAt(0) */)) { /* hex? */ i += 2; /* skip '0x' */ - - for (; i < s.length && ljstype.lisxdigit(s[i]); i++) { + for (; i < s.length && lisxdigit(s[i]); i++) { a = (a * 16 + luaO_hexavalue(s[i]))|0; empty = false; } } else { /* decimal */ - for (; i < s.length && ljstype.lisdigit(s[i]); i++) { - let d = s[i] - char['0']; + for (; i < s.length && lisdigit(s[i]); i++) { + let d = s[i] - 48 /* ('0').charCodeAt(0) */; if (a >= MAXBY10 && (a > MAXBY10 || d > MAXLASTD + neg)) /* overflow? */ return null; /* do not accept it (as integer) */ a = (a * 10 + d)|0; empty = false; } } - while (i < s.length && ljstype.lisspace(s[i])) i++; /* skip trailing spaces */ + while (i < s.length && lisspace(s[i])) i++; /* skip trailing spaces */ if (empty || (i !== s.length && s[i] !== 0)) return null; /* something wrong in the numeral */ else { return { @@ -516,21 +589,21 @@ const luaO_str2num = function(s, o) { const luaO_tostring = function(L, obj) { let buff; if (obj.ttisinteger()) - buff = defs.to_luastring(luaconf.lua_integer2str(obj.value)); + buff = to_luastring(lua_integer2str(obj.value)); else { - let str = luaconf.lua_number2str(obj.value); + let str = lua_number2str(obj.value); // Assume no LUA_COMPAT_FLOATSTRING if (/^[-0123456789]+$/.test(str)) { /* looks like an int? */ - str += luaconf.lua_getlocaledecpoint() + '0'; /* adds '.0' to result */ + str += String.fromCharCode(lua_getlocaledecpoint()) + '0'; /* adds '.0' to result */ } - buff = defs.to_luastring(str); + buff = to_luastring(str); } - obj.setsvalue(lstring.luaS_bless(L, buff)); + obj.setsvalue(luaS_bless(L, buff)); }; const pushstr = function(L, str) { ldo.luaD_inctop(L); - setsvalue2s(L, L.top-1, lstring.luaS_new(L, str)); + setsvalue2s(L, L.top-1, luaS_new(L, str)); }; const luaO_pushvfstring = function(L, fmt, argp) { @@ -539,82 +612,96 @@ const luaO_pushvfstring = function(L, fmt, argp) { let a = 0; let e; for (;;) { - e = fmt.indexOf(char['%'], i); + e = luastring_indexOf(fmt, 37 /* ('%').charCodeAt(0) */, i); if (e == -1) break; pushstr(L, fmt.subarray(i, e)); switch(fmt[e+1]) { - case char['s']: { + case 115 /* ('s').charCodeAt(0) */: { let s = argp[a++]; - if (s === null) s = defs.to_luastring("(null)", true); + if (s === null) s = to_luastring("(null)", true); else { - s = defs.from_userstring(s); + s = from_userstring(s); /* respect null terminator */ - let i = s.indexOf(0); + let i = luastring_indexOf(s, 0); if (i !== -1) s = s.subarray(0, i); } pushstr(L, s); break; } - case char['c']: { + case 99 /* ('c').charCodeAt(0) */: { let buff = argp[a++]; - if (ljstype.lisprint(buff)) - pushstr(L, defs.string_of(buff)); + if (lisprint(buff)) + pushstr(L, luastring_of(buff)); else - luaO_pushfstring(L, defs.to_luastring("<\\%d>", true), buff); + luaO_pushfstring(L, to_luastring("<\\%d>", true), buff); break; } - case char['d']: - case char['I']: + case 100 /* ('d').charCodeAt(0) */: + case 73 /* ('I').charCodeAt(0) */: ldo.luaD_inctop(L); L.stack[L.top-1].setivalue(argp[a++]); luaO_tostring(L, L.stack[L.top-1]); break; - case char['f']: + case 102 /* ('f').charCodeAt(0) */: ldo.luaD_inctop(L); L.stack[L.top-1].setfltvalue(argp[a++]); luaO_tostring(L, L.stack[L.top-1]); break; - case char['p']: { + case 112 /* ('p').charCodeAt(0) */: { let v = argp[a++]; if (v instanceof lstate.lua_State || v instanceof ltable.Table || v instanceof Udata || v instanceof LClosure || - v instanceof CClosure || - v instanceof lfunc.UpVal) { - pushstr(L, defs.to_luastring("0x"+v.id.toString(16))); - } else if (v === null) { /* handle null before checking for typeof == object */ - pushstr(L, defs.to_luastring("null")); - } else if (typeof v === "function" || typeof v === "object") { - let id = L.l_G.ids.get(v); - if (!id) { - id = L.l_G.id_counter++; - L.l_G.ids.set(v, id); + v instanceof CClosure) { + pushstr(L, to_luastring("0x"+v.id.toString(16))); + } + switch(typeof v) { + case "undefined": + pushstr(L, to_luastring("undefined")); + break; + case "number": /* before check object as null is an object */ + pushstr(L, to_luastring("Number("+v+")")); + break; + case "string": /* before check object as null is an object */ + pushstr(L, to_luastring("String("+JSON.stringify(v)+")")); + break; + case "boolean": /* before check object as null is an object */ + pushstr(L, to_luastring(v?"Boolean(true)":"Boolean(false)")); + break; + case "object": + if (v === null) { /* null is special */ + pushstr(L, to_luastring("null")); + break; + } + /* fall through */ + case "function": { + let id = L.l_G.ids.get(v); + if (!id) { + id = L.l_G.id_counter++; + L.l_G.ids.set(v, id); + } + pushstr(L, to_luastring("0x"+id.toString(16))); + break; } - pushstr(L, defs.to_luastring("0x"+id.toString(16))); - } else if (v === void 0) { - pushstr(L, defs.to_luastring("undefined")); - } else if (typeof v === "number") { /* before check object as null is an object */ - pushstr(L, defs.to_luastring("Number("+v+")")); - } else if (typeof v === "string") { /* before check object as null is an object */ - pushstr(L, defs.to_luastring("String("+JSON.stringify(v)+")")); - } else if (typeof v === "boolean") { /* before check object as null is an object */ - pushstr(L, defs.to_luastring(v?"Boolean(true)":"Boolean(false)")); - } else { - /* user provided object. no id available */ - pushstr(L, defs.to_luastring("<id NYI>")); + default: + /* user provided object. no id available */ + pushstr(L, to_luastring("<id NYI>")); } break; } - case char['U']: - pushstr(L, defs.to_luastring(String.fromCodePoint(argp[a++]))); + case 85 /* ('U').charCodeAt(0) */: { + let buff = new Uint8Array(UTF8BUFFSZ); + let l = luaO_utf8esc(buff, argp[a++]); + pushstr(L, buff.subarray(UTF8BUFFSZ - l)); break; - case char['%']: - pushstr(L, defs.to_luastring("%", true)); + } + case 37 /* ('%').charCodeAt(0) */: + pushstr(L, to_luastring("%", true)); break; default: - ldebug.luaG_runerror(L, defs.to_luastring("invalid option '%%%c' to 'lua_pushfstring'"), fmt[e + 1]); + ldebug.luaG_runerror(L, to_luastring("invalid option '%%%c' to 'lua_pushfstring'"), fmt[e + 1]); } n += 2; i = e + 2; @@ -651,34 +738,34 @@ const luaO_int2fb = function(x) { const intarith = function(L, op, v1, v2) { switch (op) { - case defs.LUA_OPADD: return (v1 + v2)|0; - case defs.LUA_OPSUB: return (v1 - v2)|0; - case defs.LUA_OPMUL: return Math.imul(v1, v2); - case defs.LUA_OPMOD: return lvm.luaV_mod(L, v1, v2); - case defs.LUA_OPIDIV: return lvm.luaV_div(L, v1, v2); - case defs.LUA_OPBAND: return (v1 & v2); - case defs.LUA_OPBOR: return (v1 | v2); - case defs.LUA_OPBXOR: return (v1 ^ v2); - case defs.LUA_OPSHL: return lvm.luaV_shiftl(v1, v2); - case defs.LUA_OPSHR: return lvm.luaV_shiftl(v1, -v2); - case defs.LUA_OPUNM: return (0 - v1)|0; - case defs.LUA_OPBNOT: return (~0 ^ v1); - default: assert(0); + case LUA_OPADD: return (v1 + v2)|0; + case LUA_OPSUB: return (v1 - v2)|0; + case LUA_OPMUL: return lvm.luaV_imul(v1, v2); + case LUA_OPMOD: return lvm.luaV_mod(L, v1, v2); + case LUA_OPIDIV: return lvm.luaV_div(L, v1, v2); + case LUA_OPBAND: return (v1 & v2); + case LUA_OPBOR: return (v1 | v2); + case LUA_OPBXOR: return (v1 ^ v2); + case LUA_OPSHL: return lvm.luaV_shiftl(v1, v2); + case LUA_OPSHR: return lvm.luaV_shiftl(v1, -v2); + case LUA_OPUNM: return (0 - v1)|0; + case LUA_OPBNOT: return (~0 ^ v1); + default: lua_assert(0); } }; const numarith = function(L, op, v1, v2) { switch (op) { - case defs.LUA_OPADD: return v1 + v2; - case defs.LUA_OPSUB: return v1 - v2; - case defs.LUA_OPMUL: return v1 * v2; - case defs.LUA_OPDIV: return v1 / v2; - case defs.LUA_OPPOW: return Math.pow(v1, v2); - case defs.LUA_OPIDIV: return Math.floor(v1 / v2); - case defs.LUA_OPUNM: return -v1; - case defs.LUA_OPMOD: return llimits.luai_nummod(L, v1, v2); - default: assert(0); + case LUA_OPADD: return v1 + v2; + case LUA_OPSUB: return v1 - v2; + case LUA_OPMUL: return v1 * v2; + case LUA_OPDIV: return v1 / v2; + case LUA_OPPOW: return Math.pow(v1, v2); + case LUA_OPIDIV: return Math.floor(v1 / v2); + case LUA_OPUNM: return -v1; + case LUA_OPMOD: return luai_nummod(L, v1, v2); + default: lua_assert(0); } }; @@ -686,9 +773,9 @@ const luaO_arith = function(L, op, p1, p2, p3) { let res = (typeof p3 === "number") ? L.stack[p3] : p3; /* FIXME */ switch (op) { - case defs.LUA_OPBAND: case defs.LUA_OPBOR: case defs.LUA_OPBXOR: - case defs.LUA_OPSHL: case defs.LUA_OPSHR: - case defs.LUA_OPBNOT: { /* operate only on integers */ + case LUA_OPBAND: case LUA_OPBOR: case LUA_OPBXOR: + case LUA_OPSHL: case LUA_OPSHR: + case LUA_OPBNOT: { /* operate only on integers */ let i1, i2; if ((i1 = lvm.tointeger(p1)) !== false && (i2 = lvm.tointeger(p2)) !== false) { res.setivalue(intarith(L, op, i1, i2)); @@ -696,7 +783,7 @@ const luaO_arith = function(L, op, p1, p2, p3) { } else break; /* go to the end */ } - case defs.LUA_OPDIV: case defs.LUA_OPPOW: { /* operate only on floats */ + case LUA_OPDIV: case LUA_OPPOW: { /* operate only on floats */ let n1, n2; if ((n1 = lvm.tonumber(p1)) !== false && (n2 = lvm.tonumber(p2)) !== false) { res.setfltvalue(numarith(L, op, n1, n2)); @@ -718,8 +805,8 @@ const luaO_arith = function(L, op, p1, p2, p3) { } } /* could not perform raw operation; try metamethod */ - assert(L !== null); /* should not fail when folding (compile time) */ - ltm.luaT_trybinTM(L, p1, p2, p3, (op - defs.LUA_OPADD) + ltm.TMS.TM_ADD); + lua_assert(L !== null); /* should not fail when folding (compile time) */ + ltm.luaT_trybinTM(L, p1, p2, p3, (op - LUA_OPADD) + ltm.TMS.TM_ADD); }; diff --git a/src/loslib.js b/src/loslib.js index ecd42f1..9a8a327 100644 --- a/src/loslib.js +++ b/src/loslib.js @@ -1,26 +1,70 @@ "use strict"; -const lua = require('./lua.js'); -const lauxlib = require('./lauxlib.js'); +const { + LUA_TNIL, + LUA_TTABLE, + lua_close, + lua_createtable, + lua_getfield, + lua_isboolean, + lua_isnoneornil, + lua_pop, + lua_pushboolean, + lua_pushfstring, + lua_pushinteger, + lua_pushliteral, + lua_pushnil, + lua_pushnumber, + lua_pushstring, + lua_setfield, + lua_settop, + lua_toboolean, + lua_tointegerx +} = require('./lua.js'); +const { + luaL_Buffer, + luaL_addchar, + luaL_addstring, + // luaL_argcheck, + luaL_argerror, + luaL_buffinit, + luaL_checkinteger, + luaL_checkstring, + luaL_checktype, + luaL_error, + luaL_execresult, + luaL_fileresult, + luaL_newlib, + luaL_opt, + luaL_optinteger, + luaL_optlstring, + luaL_optstring, + luaL_pushresult +} = require('./lauxlib.js'); +const { + luastring_indexOf, + to_jsstring, + to_luastring +} = require("./fengaricore.js"); const strftime = require('strftime'); /* options for ANSI C 89 (only 1-char options) */ -const L_STRFTIMEC89 = lua.to_luastring("aAbBcdHIjmMpSUwWxXyYZ%"); +const L_STRFTIMEC89 = to_luastring("aAbBcdHIjmMpSUwWxXyYZ%"); const LUA_STRFTIMEOPTIONS = L_STRFTIMEC89; /* options for ISO C 99 and POSIX */ -// const L_STRFTIMEC99 = lua.to_luastring("aAbBcCdDeFgGhHIjmMnprRStTuUVwWxXyYzZ%||EcECExEXEyEYOdOeOHOIOmOMOSOuOUOVOwOWOy"); /* two-char options */ +// const L_STRFTIMEC99 = to_luastring("aAbBcCdDeFgGhHIjmMnprRStTuUVwWxXyYzZ%||EcECExEXEyEYOdOeOHOIOmOMOSOuOUOVOwOWOy"); /* two-char options */ // const LUA_STRFTIMEOPTIONS = L_STRFTIMEC99; /* options for Windows */ -// const L_STRFTIMEWIN = lua.to_luastring("aAbBcdHIjmMpSUwWxXyYzZ%||#c#x#d#H#I#j#m#M#S#U#w#W#y#Y"); /* two-char options */ +// const L_STRFTIMEWIN = to_luastring("aAbBcdHIjmMpSUwWxXyYzZ%||#c#x#d#H#I#j#m#M#S#U#w#W#y#Y"); /* two-char options */ // const LUA_STRFTIMEOPTIONS = L_STRFTIMEWIN; const setfield = function(L, key, value) { - lua.lua_pushinteger(L, value); - lua.lua_setfield(L, -2, lua.to_luastring(key, true)); + lua_pushinteger(L, value); + lua_setfield(L, -2, to_luastring(key, true)); }; const setallfields = function(L, time, utc) { @@ -39,21 +83,21 @@ const setallfields = function(L, time, utc) { const L_MAXDATEFIELD = (Number.MAX_SAFE_INTEGER / 2); const getfield = function(L, key, d, delta) { - let t = lua.lua_getfield(L, -1, lua.to_luastring(key, true)); /* get field and its type */ - let res = lua.lua_tointegerx(L, -1); + let t = lua_getfield(L, -1, to_luastring(key, true)); /* get field and its type */ + let res = lua_tointegerx(L, -1); if (res === false) { /* field is not an integer? */ - if (t !== lua.LUA_TNIL) /* some other value? */ - return lauxlib.luaL_error(L, lua.to_luastring("field '%s' is not an integer"), key); + if (t !== LUA_TNIL) /* some other value? */ + return luaL_error(L, to_luastring("field '%s' is not an integer"), key); else if (d < 0) /* absent field; no default? */ - return lauxlib.luaL_error(L, lua.to_luastring("field '%s' missing in date table"), key); + return luaL_error(L, to_luastring("field '%s' missing in date table"), key); res = d; } else { if (!(-L_MAXDATEFIELD <= res && res <= L_MAXDATEFIELD)) - return lauxlib.luaL_error(L, lua.to_luastring("field '%s' is out-of-bound"), key); + return luaL_error(L, to_luastring("field '%s' is out-of-bound"), key); res -= delta; } - lua.lua_pop(L, 1); + lua_pop(L, 1); return res; }; @@ -73,12 +117,12 @@ const checkoption = function(L, conv, i, buff) { if (option[o] === '|'.charCodeAt(0)) /* next block? */ oplen++; /* will check options with next length (+1) */ else if (array_cmp(conv, i, option, o, oplen)) { /* match? */ - buff.set(conv.slice(i, i+oplen)); /* copy valid option to buffer */ + buff.set(conv.subarray(i, i+oplen)); /* copy valid option to buffer */ return i + oplen; /* return next item */ } } - lauxlib.luaL_argerror(L, 1, - lua.lua_pushfstring(L, lua.to_luastring("invalid conversion specifier '%%%s'"), conv)); + luaL_argerror(L, 1, + lua_pushfstring(L, to_luastring("invalid conversion specifier '%%%s'"), conv)); }; /* maximum size for an individual 'strftime' item */ @@ -86,8 +130,8 @@ const checkoption = function(L, conv, i, buff) { const os_date = function(L) { - let s = lauxlib.luaL_optlstring(L, 1, lua.to_luastring("%c")); - let t = lauxlib.luaL_opt(L, l_checktime, 2, new Date().getTime() / 1000) * 1000; + let s = luaL_optlstring(L, 1, to_luastring("%c")); + let t = luaL_opt(L, l_checktime, 2, new Date().getTime() / 1000) * 1000; let stm = new Date(t); let utc = false; let i = 0; @@ -97,38 +141,38 @@ const os_date = function(L) { } if (stm === null) /* invalid date? */ - lauxlib.luaL_error(L, lua.to_luastring("time result cannot be represented in this installation", true)); + luaL_error(L, to_luastring("time result cannot be represented in this installation", true)); if (s[i] === "*".charCodeAt(0) && s[i+1] === "t".charCodeAt(0)) { - lua.lua_createtable(L, 0, 9); /* 9 = number of fields */ + lua_createtable(L, 0, 9); /* 9 = number of fields */ setallfields(L, stm, utc); } else { let cc = new Uint8Array(4); cc[0] = "%".charCodeAt(0); - let b = new lauxlib.luaL_Buffer(); - lauxlib.luaL_buffinit(L, b); + let b = new luaL_Buffer(); + luaL_buffinit(L, b); while (i < s.length) { if (s[i] !== '%'.charCodeAt(0)) { /* not a conversion specifier? */ - lauxlib.luaL_addchar(b, s[i++]); + luaL_addchar(b, s[i++]); } else { i++; /* skip '%' */ i = checkoption(L, s, i, cc.subarray(1)); /* copy specifier to 'cc' */ - let len = cc.indexOf(0); + let len = luastring_indexOf(cc, 0); if (len !== -1) cc = cc.subarray(0, len); - let buff = strftime(lua.to_jsstring(cc), stm); - lauxlib.luaL_addstring(b, lua.to_luastring(buff)); + let buff = strftime(to_jsstring(cc), stm); + luaL_addstring(b, to_luastring(buff)); } } - lauxlib.luaL_pushresult(b); + luaL_pushresult(b); } return 1; }; const os_time = function(L) { let t = new Date(); - if (!lua.lua_isnoneornil(L, 1)) /* called with arg */{ - lauxlib.luaL_checktype(L, 1, lua.LUA_TTABLE); /* make sure table is at the top */ - lua.lua_settop(L, 1); + if (!lua_isnoneornil(L, 1)) /* called with arg */{ + luaL_checktype(L, 1, LUA_TTABLE); /* make sure table is at the top */ + lua_settop(L, 1); t.setSeconds(getfield(L, "sec", 0, 0)); t.setMinutes(getfield(L, "min", 0, 0)); t.setHours(getfield(L, "hour", 12, 0)); @@ -138,20 +182,20 @@ const os_time = function(L) { setallfields(L, t); } - lua.lua_pushinteger(L, Math.floor(t / 1000)); + lua_pushinteger(L, Math.floor(t / 1000)); return 1; }; const l_checktime = function(L, arg) { - let t = lauxlib.luaL_checkinteger(L, arg); - // lauxlib.luaL_argcheck(L, t, arg, lua.to_luastring("time out-of-bounds")); + let t = luaL_checkinteger(L, arg); + // luaL_argcheck(L, t, arg, to_luastring("time out-of-bounds")); return t; }; const os_difftime = function(L) { let t1 = l_checktime(L, 1); let t2 = l_checktime(L, 2); - lua.lua_pushnumber(L, new Date(t1) - new Date(t2)); + lua_pushnumber(L, new Date(t1) - new Date(t2)); return 1; }; @@ -163,7 +207,7 @@ const syslib = { if (typeof process === "undefined") { syslib.clock = function(L) { - lua.lua_pushnumber(L, performance.now()/1000); + lua_pushnumber(L, performance.now()/1000); return 1; }; } else { @@ -174,29 +218,29 @@ if (typeof process === "undefined") { syslib.exit = function(L) { let status; - if (lua.lua_isboolean(L, 1)) - status = (lua.lua_toboolean(L, 1) ? 0 : 1); + if (lua_isboolean(L, 1)) + status = (lua_toboolean(L, 1) ? 0 : 1); else - status = lauxlib.luaL_optinteger(L, 1, 0); - if (lua.lua_toboolean(L, 2)) - lua.lua_close(L); + status = luaL_optinteger(L, 1, 0); + if (lua_toboolean(L, 2)) + lua_close(L); if (L) process.exit(status); /* 'if' to avoid warnings for unreachable 'return' */ return 0; }; syslib.getenv = function(L) { - let key = lauxlib.luaL_checkstring(L, 1); - key = lua.to_jsstring(key); /* https://github.com/nodejs/node/issues/16961 */ + let key = luaL_checkstring(L, 1); + key = to_jsstring(key); /* https://github.com/nodejs/node/issues/16961 */ if (Object.prototype.hasOwnProperty.call(process.env, key)) { - lua.lua_pushliteral(L, process.env[key]); + lua_pushliteral(L, process.env[key]); } else { - lua.lua_pushnil(L); + lua_pushnil(L); } return 1; }; syslib.clock = function(L) { - lua.lua_pushnumber(L, process.uptime()); + lua_pushnumber(L, process.uptime()); return 1; }; @@ -206,7 +250,7 @@ if (typeof process === "undefined") { }; syslib.remove = function(L) { - let filename = lauxlib.luaL_checkstring(L, 1); + let filename = luaL_checkstring(L, 1); try { if (fs.lstatSync(filename).isDirectory()) { fs.rmdirSync(filename); @@ -214,32 +258,32 @@ if (typeof process === "undefined") { fs.unlinkSync(filename); } } catch (e) { - return lauxlib.luaL_fileresult(L, false, filename, e); + return luaL_fileresult(L, false, filename, e); } - return lauxlib.luaL_fileresult(L, true); + return luaL_fileresult(L, true); }; syslib.rename = function(L) { - let fromname = lauxlib.luaL_checkstring(L, 1); - let toname = lauxlib.luaL_checkstring(L, 2); + let fromname = luaL_checkstring(L, 1); + let toname = luaL_checkstring(L, 2); try { fs.renameSync(fromname, toname); } catch (e) { - return lauxlib.luaL_fileresult(L, false, false, e); + return luaL_fileresult(L, false, false, e); } - return lauxlib.luaL_fileresult(L, true); + return luaL_fileresult(L, true); }; syslib.tmpname = function(L) { let name = lua_tmpname(); if (!name) - return lauxlib.luaL_error(L, lua.to_luastring("unable to generate a unique filename")); - lua.lua_pushstring(L, lua.to_luastring(name)); + return luaL_error(L, to_luastring("unable to generate a unique filename")); + lua_pushstring(L, to_luastring(name)); return 1; }; syslib.execute = function(L) { - let cmd = lauxlib.luaL_optstring(L, 1, null); + let cmd = luaL_optstring(L, 1, null); if (cmd !== null) { try { child_process.execSync( @@ -249,23 +293,23 @@ if (typeof process === "undefined") { } ); } catch (e) { - return lauxlib.luaL_execresult(L, e); + return luaL_execresult(L, e); } - return lauxlib.luaL_execresult(L, null); + return luaL_execresult(L, null); } else { /* Assume a shell is available. If it's good enough for musl it's good enough for us. http://git.musl-libc.org/cgit/musl/tree/src/process/system.c?id=ac45692a53a1b8d2ede329d91652d43c1fb5dc8d#n22 */ - lua.lua_pushboolean(L, 1); + lua_pushboolean(L, 1); return 1; } }; } const luaopen_os = function(L) { - lauxlib.luaL_newlib(L, syslib); + luaL_newlib(L, syslib); return 1; }; diff --git a/src/lparser.js b/src/lparser.js index d183d25..a427424 100644 --- a/src/lparser.js +++ b/src/lparser.js @@ -1,23 +1,117 @@ "use strict"; -const assert = require('assert'); - -const defs = require('./defs.js'); -const lcode = require('./lcode.js'); +const { + LUA_MULTRET, + to_luastring +} = require('./defs.js'); +const { + BinOpr: { + OPR_ADD, + OPR_AND, + OPR_BAND, + OPR_BOR, + OPR_BXOR, + OPR_CONCAT, + OPR_DIV, + OPR_EQ, + OPR_GE, + OPR_GT, + OPR_IDIV, + OPR_LE, + OPR_LT, + OPR_MOD, + OPR_MUL, + OPR_NE, + OPR_NOBINOPR, + OPR_OR, + OPR_POW, + OPR_SHL, + OPR_SHR, + OPR_SUB + }, + UnOpr: { + OPR_BNOT, + OPR_LEN, + OPR_MINUS, + OPR_NOT, + OPR_NOUNOPR + }, + NO_JUMP, + getinstruction, + luaK_checkstack, + luaK_codeABC, + luaK_codeABx, + luaK_codeAsBx, + luaK_codek, + luaK_concat, + luaK_dischargevars, + luaK_exp2RK, + luaK_exp2anyreg, + luaK_exp2anyregup, + luaK_exp2nextreg, + luaK_exp2val, + luaK_fixline, + luaK_getlabel, + luaK_goiffalse, + luaK_goiftrue, + luaK_indexed, + luaK_infix, + luaK_intK, + luaK_jump, + luaK_jumpto, + luaK_nil, + luaK_patchclose, + luaK_patchlist, + luaK_patchtohere, + luaK_posfix, + luaK_prefix, + luaK_reserveregs, + luaK_ret, + luaK_self, + luaK_setlist, + luaK_setmultret, + luaK_setoneret, + luaK_setreturns, + luaK_storevar, + luaK_stringK +} = require('./lcode.js'); const ldo = require('./ldo.js'); const lfunc = require('./lfunc.js'); const llex = require('./llex.js'); -const llimits = require('./llimits.js'); +const { + LUAI_MAXCCALLS, + MAX_INT, + lua_assert +} = require('./llimits.js'); const lobject = require('./lobject.js'); -const lopcodes = require('./lopcodes.js'); -const lstring = require('./lstring.js'); +const { + OpCodesI: { + OP_CALL, + OP_CLOSURE, + OP_FORLOOP, + OP_FORPREP, + OP_GETUPVAL, + OP_MOVE, + OP_NEWTABLE, + OP_SETTABLE, + OP_TAILCALL, + OP_TFORCALL, + OP_TFORLOOP, + OP_VARARG + }, + LFIELDS_PER_FLUSH, + SETARG_B, + SETARG_C, + SET_OPCODE +} = require('./lopcodes.js'); +const { + luaS_eqlngstr, + luaS_new, + luaS_newliteral +} = require('./lstring.js'); const ltable = require('./ltable.js'); -const BinOpr = lcode.BinOpr; -const OpCodesI = lopcodes.OpCodesI; const Proto = lfunc.Proto; const R = llex.RESERVED; -const UnOpr = lcode.UnOpr; -const char = defs.char; const MAXVARS = 200; @@ -27,7 +121,7 @@ const hasmultret = function(k) { const eqstr = function(a, b) { /* TODO: use plain equality as strings are cached */ - return lstring.luaS_eqlngstr(a, b); + return luaS_eqlngstr(a, b); }; class BlockCnt { @@ -165,16 +259,16 @@ const semerror = function(ls, msg) { }; const error_expected = function(ls, token) { - llex.luaX_syntaxerror(ls, lobject.luaO_pushfstring(ls.L, defs.to_luastring("%s expected", true), llex.luaX_token2str(ls, token))); + llex.luaX_syntaxerror(ls, lobject.luaO_pushfstring(ls.L, to_luastring("%s expected", true), llex.luaX_token2str(ls, token))); }; const errorlimit = function(fs, limit, what) { let L = fs.ls.L; let line = fs.f.linedefined; let where = (line === 0) - ? defs.to_luastring("main function", true) - : lobject.luaO_pushfstring(L, defs.to_luastring("function at line %d", true), line); - let msg = lobject.luaO_pushfstring(L, defs.to_luastring("too many %s (limit is %d) in %s", true), + ? to_luastring("main function", true) + : lobject.luaO_pushfstring(L, to_luastring("function at line %d", true), line); + let msg = lobject.luaO_pushfstring(L, to_luastring("too many %s (limit is %d) in %s", true), what, limit, where); llex.luaX_syntaxerror(fs.ls, msg); }; @@ -213,7 +307,7 @@ const check_match = function(ls, what, who, where) { error_expected(ls, what); else llex.luaX_syntaxerror(ls, lobject.luaO_pushfstring(ls.L, - defs.to_luastring("%s expected (to close %s at line %d)"), + to_luastring("%s expected (to close %s at line %d)"), llex.luaX_token2str(ls, what), llex.luaX_token2str(ls, who), where)); } }; @@ -226,13 +320,13 @@ const str_checkname = function(ls) { }; const init_exp = function(e, k, i) { - e.f = e.t = lcode.NO_JUMP; + e.f = e.t = NO_JUMP; e.k = k; e.u.info = i; }; const codestring = function(ls, e, s) { - init_exp(e, expkind.VK, lcode.luaK_stringK(ls.fs, s)); + init_exp(e, expkind.VK, luaK_stringK(ls.fs, s)); }; const checkname = function(ls, e) { @@ -251,19 +345,19 @@ const new_localvar = function(ls, name) { let fs = ls.fs; let dyd = ls.dyd; let reg = registerlocalvar(ls, name); - checklimit(fs, dyd.actvar.n + 1 - fs.firstlocal, MAXVARS, defs.to_luastring("local variables", true)); + checklimit(fs, dyd.actvar.n + 1 - fs.firstlocal, MAXVARS, to_luastring("local variables", true)); dyd.actvar.arr[dyd.actvar.n] = new Vardesc(); dyd.actvar.arr[dyd.actvar.n].idx = reg; dyd.actvar.n++; }; const new_localvarliteral = function(ls, name) { - new_localvar(ls, llex.luaX_newstring(ls, defs.to_luastring(name, true))); + new_localvar(ls, llex.luaX_newstring(ls, to_luastring(name, true))); }; const getlocvar = function(fs, i) { let idx = fs.ls.dyd.actvar.arr[fs.firstlocal + i].idx; - assert(idx < fs.nlocvars); + lua_assert(idx < fs.nlocvars); return fs.f.locvars[idx]; }; @@ -291,7 +385,7 @@ const searchupvalue = function(fs, name) { const newupvalue = function(fs, name, v) { let f = fs.f; - checklimit(fs, fs.nups + 1, lfunc.MAXUPVAL, defs.to_luastring("upvalues", true)); + checklimit(fs, fs.nups + 1, lfunc.MAXUPVAL, to_luastring("upvalues", true)); f.upvalues[fs.nups] = { instack: v.k === expkind.VLOCAL, idx: v.u.info, @@ -354,9 +448,9 @@ const singlevar = function(ls, vr) { if (vr.k === expkind.VVOID) { /* is global name? */ let key = new expdesc(); singlevaraux(fs, ls.envn, vr, 1); /* get environment variable */ - assert(vr.k !== expkind.VVOID); /* this one must exist */ + lua_assert(vr.k !== expkind.VVOID); /* this one must exist */ codestring(ls, key, varname); /* key is variable name */ - lcode.luaK_indexed(fs, vr, key); /* env[varname] */ + luaK_indexed(fs, vr, key); /* env[varname] */ } }; @@ -366,14 +460,14 @@ const adjust_assign = function(ls, nvars, nexps, e) { if (hasmultret(e.k)) { extra++; /* includes call itself */ if (extra < 0) extra = 0; - lcode.luaK_setreturns(fs, e, extra); /* last exp. provides the difference */ - if (extra > 1) lcode.luaK_reserveregs(fs, extra - 1); + luaK_setreturns(fs, e, extra); /* last exp. provides the difference */ + if (extra > 1) luaK_reserveregs(fs, extra - 1); } else { - if (e.k !== expkind.VVOID) lcode.luaK_exp2nextreg(fs, e); /* close last expression */ + if (e.k !== expkind.VVOID) luaK_exp2nextreg(fs, e); /* close last expression */ if (extra > 0) { let reg = fs.freereg; - lcode.luaK_reserveregs(fs, extra); - lcode.luaK_nil(fs, reg, extra); + luaK_reserveregs(fs, extra); + luaK_nil(fs, reg, extra); } } if (nexps > nvars) @@ -383,7 +477,7 @@ const adjust_assign = function(ls, nvars, nexps, e) { const enterlevel = function(ls) { let L = ls.L; ++L.nCcalls; - checklimit(ls.fs, L.nCcalls, llimits.LUAI_MAXCCALLS, defs.to_luastring("JS levels", true)); + checklimit(ls.fs, L.nCcalls, LUAI_MAXCCALLS, to_luastring("JS levels", true)); }; const leavelevel = function(ls) { @@ -394,15 +488,15 @@ const closegoto = function(ls, g, label) { let fs = ls.fs; let gl = ls.dyd.gt; let gt = gl.arr[g]; - assert(eqstr(gt.name, label.name)); + lua_assert(eqstr(gt.name, label.name)); if (gt.nactvar < label.nactvar) { let vname = getlocvar(fs, gt.nactvar).varname; let msg = lobject.luaO_pushfstring(ls.L, - defs.to_luastring("<goto %s> at line %d jumps into the scope of local '%s'"), + to_luastring("<goto %s> at line %d jumps into the scope of local '%s'"), gt.name.getstr(), gt.line, vname.getstr()); semerror(ls, msg); } - lcode.luaK_patchlist(fs, gt.pc, label.pc); + luaK_patchlist(fs, gt.pc, label.pc); /* remove goto from pending list */ for (let i = g; i < gl.n - 1; i++) gl.arr[i] = gl.arr[i + 1]; @@ -421,7 +515,7 @@ const findlabel = function(ls, g) { let lb = dyd.label.arr[i]; if (eqstr(lb.name, gt.name)) { /* correct label? */ if (gt.nactvar > lb.nactvar && (bl.upval || dyd.label.n > bl.firstlabel)) - lcode.luaK_patchclose(ls.fs, gt.pc, lb.nactvar); + luaK_patchclose(ls.fs, gt.pc, lb.nactvar); closegoto(ls, g, lb); /* close it */ return true; } @@ -470,7 +564,7 @@ const movegotosout = function(fs, bl) { let gt = gl.arr[i]; if (gt.nactvar > bl.nactvar) { if (bl.upval) - lcode.luaK_patchclose(fs, gt.pc, bl.nactvar); + luaK_patchclose(fs, gt.pc, bl.nactvar); gt.nactvar = bl.nactvar; } if (!findlabel(fs.ls, i)) @@ -486,14 +580,14 @@ const enterblock = function(fs, bl, isloop) { bl.upval = 0; bl.previous = fs.bl; fs.bl = bl; - assert(fs.freereg === fs.nactvar); + lua_assert(fs.freereg === fs.nactvar); }; /* ** create a label named 'break' to resolve break statements */ const breaklabel = function(ls) { - let n = lstring.luaS_newliteral(ls.L, "break"); + let n = luaS_newliteral(ls.L, "break"); let l = newlabelentry(ls, ls.dyd.label, n, 0, ls.fs.pc); findgotos(ls, ls.dyd.label.arr[l]); }; @@ -506,7 +600,7 @@ const undefgoto = function(ls, gt) { let msg = llex.isreserved(gt.name) ? "<%s> at line %d not inside a loop" : "no visible label '%s' for <goto> at line %d"; - msg = lobject.luaO_pushfstring(ls.L, defs.to_luastring(msg), gt.name.getstr(), gt.line); + msg = lobject.luaO_pushfstring(ls.L, to_luastring(msg), gt.name.getstr(), gt.line); semerror(ls, msg); }; @@ -527,8 +621,8 @@ const addprototype = function(ls) { */ const codeclosure = function(ls, v) { let fs = ls.fs.prev; - init_exp(v, expkind.VRELOCABLE, lcode.luaK_codeABx(fs, OpCodesI.OP_CLOSURE, 0, fs.np -1)); - lcode.luaK_exp2nextreg(fs, v); /* fix it at the last register */ + init_exp(v, expkind.VRELOCABLE, luaK_codeABx(fs, OP_CLOSURE, 0, fs.np -1)); + luaK_exp2nextreg(fs, v); /* fix it at the last register */ }; const open_func = function(ls, fs, bl) { @@ -537,7 +631,7 @@ const open_func = function(ls, fs, bl) { ls.fs = fs; fs.pc = 0; fs.lasttarget = 0; - fs.jpc = lcode.NO_JUMP; + fs.jpc = NO_JUMP; fs.freereg = 0; fs.nk = 0; fs.np = 0; @@ -558,9 +652,9 @@ const leaveblock = function(fs) { let ls = fs.ls; if (bl.previous && bl.upval) { /* create a 'jump to here' to close upvalues */ - let j = lcode.luaK_jump(fs); - lcode.luaK_patchclose(fs, j , bl.nactvar); - lcode.luaK_patchtohere(fs, j); + let j = luaK_jump(fs); + luaK_patchclose(fs, j , bl.nactvar); + luaK_patchtohere(fs, j); } if (bl.isloop) @@ -568,7 +662,7 @@ const leaveblock = function(fs) { fs.bl = bl.previous; removevars(fs, bl.nactvar); - assert(bl.nactvar === fs.nactvar); + lua_assert(bl.nactvar === fs.nactvar); fs.freereg = fs.nactvar; /* free registers */ ls.dyd.label.n = bl.firstlabel; /* remove local labels */ if (bl.previous) /* inner block? */ @@ -579,9 +673,9 @@ const leaveblock = function(fs) { const close_func = function(ls) { let fs = ls.fs; - lcode.luaK_ret(fs, 0, 0); /* final return */ + luaK_ret(fs, 0, 0); /* final return */ leaveblock(fs); - assert(fs.bl === null); + lua_assert(fs.bl === null); ls.fs = fs.prev; }; @@ -614,18 +708,18 @@ const fieldsel = function(ls, v) { /* fieldsel -> ['.' | ':'] NAME */ let fs = ls.fs; let key = new expdesc(); - lcode.luaK_exp2anyregup(fs, v); + luaK_exp2anyregup(fs, v); llex.luaX_next(ls); /* skip the dot or colon */ checkname(ls, key); - lcode.luaK_indexed(fs, v, key); + luaK_indexed(fs, v, key); }; const yindex = function(ls, v) { /* index -> '[' expr ']' */ llex.luaX_next(ls); /* skip the '[' */ expr(ls, v); - lcode.luaK_exp2val(ls.fs, v); - checknext(ls, char[']']); + luaK_exp2val(ls.fs, v); + checknext(ls, 93 /* (']').charCodeAt(0) */); }; /* @@ -652,24 +746,24 @@ const recfield = function(ls, cc) { let val = new expdesc(); if (ls.t.token === R.TK_NAME) { - checklimit(fs, cc.nh, llimits.MAX_INT, defs.to_luastring("items in a constructor", true)); + checklimit(fs, cc.nh, MAX_INT, to_luastring("items in a constructor", true)); checkname(ls, key); } else /* ls->t.token === '[' */ yindex(ls, key); cc.nh++; - checknext(ls, char['=']); - let rkkey = lcode.luaK_exp2RK(fs, key); + checknext(ls, 61 /* ('=').charCodeAt(0) */); + let rkkey = luaK_exp2RK(fs, key); expr(ls, val); - lcode.luaK_codeABC(fs, OpCodesI.OP_SETTABLE, cc.t.u.info, rkkey, lcode.luaK_exp2RK(fs, val)); + luaK_codeABC(fs, OP_SETTABLE, cc.t.u.info, rkkey, luaK_exp2RK(fs, val)); fs.freereg = reg; /* free registers */ }; const closelistfield = function(fs, cc) { if (cc.v.k === expkind.VVOID) return; /* there is no list item */ - lcode.luaK_exp2nextreg(fs, cc.v); + luaK_exp2nextreg(fs, cc.v); cc.v.k = expkind.VVOID; - if (cc.tostore === lopcodes.LFIELDS_PER_FLUSH) { - lcode.luaK_setlist(fs, cc.t.u.info, cc.na, cc.tostore); /* flush */ + if (cc.tostore === LFIELDS_PER_FLUSH) { + luaK_setlist(fs, cc.t.u.info, cc.na, cc.tostore); /* flush */ cc.tostore = 0; /* no more items pending */ } }; @@ -677,20 +771,20 @@ const closelistfield = function(fs, cc) { const lastlistfield = function(fs, cc) { if (cc.tostore === 0) return; if (hasmultret(cc.v.k)) { - lcode.luaK_setmultret(fs, cc.v); - lcode.luaK_setlist(fs, cc.t.u.info, cc.na, defs.LUA_MULTRET); + luaK_setmultret(fs, cc.v); + luaK_setlist(fs, cc.t.u.info, cc.na, LUA_MULTRET); cc.na--; /* do not count last expression (unknown number of elements) */ } else { if (cc.v.k !== expkind.VVOID) - lcode.luaK_exp2nextreg(fs, cc.v); - lcode.luaK_setlist(fs, cc.t.u.info, cc.na, cc.tostore); + luaK_exp2nextreg(fs, cc.v); + luaK_setlist(fs, cc.t.u.info, cc.na, cc.tostore); } }; const listfield = function(ls, cc) { /* listfield -> exp */ expr(ls, cc.v); - checklimit(ls.fs, cc.na, llimits.MAX_INT, defs.to_luastring("items in a constructor", true)); + checklimit(ls.fs, cc.na, MAX_INT, to_luastring("items in a constructor", true)); cc.na++; cc.tostore++; }; @@ -699,13 +793,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) !== char['=']) /* expression? */ + if (llex.luaX_lookahead(ls) !== 61 /* ('=').charCodeAt(0) */) /* expression? */ listfield(ls, cc); else recfield(ls, cc); break; } - case char['[']: { + case 91 /* ('[').charCodeAt(0) */: { recfield(ls, cc); break; } @@ -721,24 +815,24 @@ const constructor = function(ls, t) { sep -> ',' | ';' */ let fs = ls.fs; let line = ls.linenumber; - let pc = lcode.luaK_codeABC(fs, OpCodesI.OP_NEWTABLE, 0, 0, 0); + let pc = luaK_codeABC(fs, OP_NEWTABLE, 0, 0, 0); let cc = new ConsControl(); cc.na = cc.nh = cc.tostore = 0; cc.t = 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, char['{']); + luaK_exp2nextreg(ls.fs, t); /* fix it at stack top */ + checknext(ls, 123 /* ('{').charCodeAt(0) */); do { - assert(cc.v.k === expkind.VVOID || cc.tostore > 0); - if (ls.t.token === char['}']) break; + lua_assert(cc.v.k === expkind.VVOID || cc.tostore > 0); + if (ls.t.token === 125 /* ('}').charCodeAt(0) */) break; closelistfield(fs, cc); field(ls, cc); - } while (testnext(ls, char[',']) || testnext(ls, char[';'])); - check_match(ls, char['}'], char['{'], line); + } while (testnext(ls, 44 /* (',').charCodeAt(0) */) || testnext(ls, 59 /* (';').charCodeAt(0) */)); + check_match(ls, 125 /* ('}').charCodeAt(0) */, 123 /* ('{').charCodeAt(0) */, line); lastlistfield(fs, cc); - lopcodes.SETARG_B(fs.f.code[pc], lobject.luaO_int2fb(cc.na)); /* set initial array size */ - lopcodes.SETARG_C(fs.f.code[pc], lobject.luaO_int2fb(cc.nh)); /* set initial table size */ + SETARG_B(fs.f.code[pc], lobject.luaO_int2fb(cc.na)); /* set initial array size */ + SETARG_C(fs.f.code[pc], lobject.luaO_int2fb(cc.nh)); /* set initial table size */ }; /* }====================================================================== */ @@ -749,7 +843,7 @@ const parlist = function(ls) { let f = fs.f; let nparams = 0; f.is_vararg = false; - if (ls.t.token !== char[')']) { /* is 'parlist' not empty? */ + if (ls.t.token !== 41 /* (')').charCodeAt(0) */) { /* is 'parlist' not empty? */ do { switch (ls.t.token) { case R.TK_NAME: { /* param -> NAME */ @@ -762,13 +856,13 @@ const parlist = function(ls) { f.is_vararg = true; /* declared vararg */ break; } - default: llex.luaX_syntaxerror(ls, defs.to_luastring("<name> or '...' expected", true)); + default: llex.luaX_syntaxerror(ls, to_luastring("<name> or '...' expected", true)); } - } while(!f.is_vararg && testnext(ls, char[','])); + } while(!f.is_vararg && testnext(ls, 44 /* (',').charCodeAt(0) */)); } adjustlocalvars(ls, nparams); f.numparams = fs.nactvar; - lcode.luaK_reserveregs(fs, fs.nactvar); /* reserve register for parameters */ + luaK_reserveregs(fs, fs.nactvar); /* reserve register for parameters */ }; const body = function(ls, e, ismethod, line) { @@ -778,13 +872,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, char['(']); + checknext(ls, 40 /* ('(').charCodeAt(0) */); if (ismethod) { new_localvarliteral(ls, "self"); /* create 'self' parameter */ adjustlocalvars(ls, 1); } parlist(ls); - checknext(ls, char[')']); + checknext(ls, 41 /* (')').charCodeAt(0) */); statlist(ls); new_fs.f.lastlinedefined = ls.linenumber; check_match(ls, R.TK_END, R.TK_FUNCTION, line); @@ -796,8 +890,8 @@ const explist = function(ls, v) { /* explist -> expr { ',' expr } */ let n = 1; /* at least one expression */ expr(ls, v); - while (testnext(ls, char[','])) { - lcode.luaK_exp2nextreg(ls.fs, v); + while (testnext(ls, 44 /* (',').charCodeAt(0) */)) { + luaK_exp2nextreg(ls.fs, v); expr(ls, v); n++; } @@ -808,18 +902,18 @@ const funcargs = function(ls, f, line) { let fs = ls.fs; let args = new expdesc(); switch (ls.t.token) { - case char['(']: { /* funcargs -> '(' [ explist ] ')' */ + case 40 /* ('(').charCodeAt(0) */: { /* funcargs -> '(' [ explist ] ')' */ llex.luaX_next(ls); - if (ls.t.token === char[')']) /* arg list is empty? */ + if (ls.t.token === 41 /* (')').charCodeAt(0) */) /* arg list is empty? */ args.k = expkind.VVOID; else { explist(ls, args); - lcode.luaK_setmultret(fs, args); + luaK_setmultret(fs, args); } - check_match(ls, char[')'], char['('], line); + check_match(ls, 41 /* (')').charCodeAt(0) */, 40 /* ('(').charCodeAt(0) */, line); break; } - case char['{']: { /* funcargs -> constructor */ + case 123 /* ('{').charCodeAt(0) */: { /* funcargs -> constructor */ constructor(ls, args); break; } @@ -829,21 +923,21 @@ const funcargs = function(ls, f, line) { break; } default: { - llex.luaX_syntaxerror(ls, defs.to_luastring("function arguments expected", true)); + llex.luaX_syntaxerror(ls, to_luastring("function arguments expected", true)); } } - assert(f.k === expkind.VNONRELOC); + lua_assert(f.k === expkind.VNONRELOC); let nparams; let base = f.u.info; /* base register for call */ if (hasmultret(args.k)) - nparams = defs.LUA_MULTRET; /* open call */ + nparams = LUA_MULTRET; /* open call */ else { if (args.k !== expkind.VVOID) - lcode.luaK_exp2nextreg(fs, args); /* close last argument */ + luaK_exp2nextreg(fs, args); /* close last argument */ nparams = fs.freereg - (base+1); } - init_exp(f, expkind.VCALL, lcode.luaK_codeABC(fs, OpCodesI.OP_CALL, base, nparams+1, 2)); - lcode.luaK_fixline(fs, line); + init_exp(f, expkind.VCALL, luaK_codeABC(fs, OP_CALL, base, nparams+1, 2)); + luaK_fixline(fs, line); fs.freereg = base + 1; /* call remove function and arguments and leaves (unless changed) one result */ }; @@ -856,12 +950,12 @@ const funcargs = function(ls, f, line) { const primaryexp = function(ls, v) { /* primaryexp -> NAME | '(' expr ')' */ switch (ls.t.token) { - case char['(']: { + case 40 /* ('(').charCodeAt(0) */: { let line = ls.linenumber; llex.luaX_next(ls); expr(ls, v); - check_match(ls, char[')'], char['('], line); - lcode.luaK_dischargevars(ls.fs, v); + check_match(ls, 41 /* (')').charCodeAt(0) */, 40 /* ('(').charCodeAt(0) */, line); + luaK_dischargevars(ls.fs, v); return; } case R.TK_NAME: { @@ -869,7 +963,7 @@ const primaryexp = function(ls, v) { return; } default: { - llex.luaX_syntaxerror(ls, defs.to_luastring("unexpected symbol", true)); + llex.luaX_syntaxerror(ls, to_luastring("unexpected symbol", true)); } } }; @@ -882,27 +976,27 @@ const suffixedexp = function(ls, v) { primaryexp(ls, v); for (;;) { switch (ls.t.token) { - case char['.']: { /* fieldsel */ + case 46 /* ('.').charCodeAt(0) */: { /* fieldsel */ fieldsel(ls, v); break; } - case char['[']: { /* '[' exp1 ']' */ + case 91 /* ('[').charCodeAt(0) */: { /* '[' exp1 ']' */ let key = new expdesc(); - lcode.luaK_exp2anyregup(fs, v); + luaK_exp2anyregup(fs, v); yindex(ls, key); - lcode.luaK_indexed(fs, v, key); + luaK_indexed(fs, v, key); break; } - case char[':']: { /* ':' NAME funcargs */ + case 58 /* (':').charCodeAt(0) */: { /* ':' NAME funcargs */ let key = new expdesc(); llex.luaX_next(ls); checkname(ls, key); - lcode.luaK_self(fs, v, key); + luaK_self(fs, v, key); funcargs(ls, v, line); break; } - case char['(']: case R.TK_STRING: case char['{']: { /* funcargs */ - lcode.luaK_exp2nextreg(fs, v); + case 40 /* ('(').charCodeAt(0) */: case R.TK_STRING: case 123 /* ('{').charCodeAt(0) */: { /* funcargs */ + luaK_exp2nextreg(fs, v); funcargs(ls, v, line); break; } @@ -943,11 +1037,11 @@ const simpleexp = function(ls, v) { } case R.TK_DOTS: { /* vararg */ let fs = ls.fs; - check_condition(ls, fs.f.is_vararg, defs.to_luastring("cannot use '...' outside a vararg function", true)); - init_exp(v, expkind.VVARARG, lcode.luaK_codeABC(fs, OpCodesI.OP_VARARG, 0, 1, 0)); + check_condition(ls, fs.f.is_vararg, to_luastring("cannot use '...' outside a vararg function", true)); + init_exp(v, expkind.VVARARG, luaK_codeABC(fs, OP_VARARG, 0, 1, 0)); break; } - case char['{']: { /* constructor */ + case 123 /* ('{').charCodeAt(0) */: { /* constructor */ constructor(ls, v); return; } @@ -966,38 +1060,38 @@ const simpleexp = function(ls, v) { const getunopr = function(op) { switch (op) { - 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; + case R.TK_NOT: return OPR_NOT; + case 45 /* ('-').charCodeAt(0) */: return OPR_MINUS; + case 126 /* ('~').charCodeAt(0) */: return OPR_BNOT; + case 35 /* ('#').charCodeAt(0) */: return OPR_LEN; + default: return OPR_NOUNOPR; } }; const getbinopr = function(op) { switch (op) { - 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 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 char['<']: return BinOpr.OPR_LT; - case R.TK_LE: return BinOpr.OPR_LE; - 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; - default: return BinOpr.OPR_NOBINOPR; + case 43 /* ('+').charCodeAt(0) */: return OPR_ADD; + case 45 /* ('-').charCodeAt(0) */: return OPR_SUB; + case 42 /* ('*').charCodeAt(0) */: return OPR_MUL; + case 37 /* ('%').charCodeAt(0) */: return OPR_MOD; + case 94 /* ('^').charCodeAt(0) */: return OPR_POW; + case 47 /* ('/').charCodeAt(0) */: return OPR_DIV; + case R.TK_IDIV: return OPR_IDIV; + case 38 /* ('&').charCodeAt(0) */: return OPR_BAND; + case 124 /* ('|').charCodeAt(0) */: return OPR_BOR; + case 126 /* ('~').charCodeAt(0) */: return OPR_BXOR; + case R.TK_SHL: return OPR_SHL; + case R.TK_SHR: return OPR_SHR; + case R.TK_CONCAT: return OPR_CONCAT; + case R.TK_NE: return OPR_NE; + case R.TK_EQ: return OPR_EQ; + case 60 /* ('<').charCodeAt(0) */: return OPR_LT; + case R.TK_LE: return OPR_LE; + case 62 /* ('>').charCodeAt(0) */: return OPR_GT; + case R.TK_GE: return OPR_GE; + case R.TK_AND: return OPR_AND; + case R.TK_OR: return OPR_OR; + default: return OPR_NOBINOPR; } }; @@ -1023,23 +1117,23 @@ const UNARY_PRIORITY = 12; const subexpr = function(ls, v, limit) { enterlevel(ls); let uop = getunopr(ls.t.token); - if (uop !== UnOpr.OPR_NOUNOPR) { + if (uop !== OPR_NOUNOPR) { let line = ls.linenumber; llex.luaX_next(ls); subexpr(ls, v, UNARY_PRIORITY); - lcode.luaK_prefix(ls.fs, uop, v, line); + luaK_prefix(ls.fs, uop, v, line); } else simpleexp(ls, v); /* expand while operators have priorities higher than 'limit' */ let op = getbinopr(ls.t.token); - while (op !== BinOpr.OPR_NOBINOPR && priority[op].left > limit) { + while (op !== OPR_NOBINOPR && priority[op].left > limit) { let v2 = new expdesc(); let line = ls.linenumber; llex.luaX_next(ls); - lcode.luaK_infix(ls.fs, op, v); + luaK_infix(ls.fs, op, v); /* read sub-expression with higher priority */ let nextop = subexpr(ls, v2, priority[op].right); - lcode.luaK_posfix(ls.fs, op, v, v2, line); + luaK_posfix(ls.fs, op, v, v2, line); op = nextop; } leavelevel(ls); @@ -1107,36 +1201,36 @@ const check_conflict = function(ls, lh, v) { } if (conflict) { /* copy upvalue/local value to a temporary (in position 'extra') */ - let op = v.k === expkind.VLOCAL ? OpCodesI.OP_MOVE : OpCodesI.OP_GETUPVAL; - lcode.luaK_codeABC(fs, op, extra, v.u.info, 0); - lcode.luaK_reserveregs(fs, 1); + let op = v.k === expkind.VLOCAL ? OP_MOVE : OP_GETUPVAL; + luaK_codeABC(fs, op, extra, v.u.info, 0); + luaK_reserveregs(fs, 1); } }; const assignment = function(ls, lh, nvars) { let e = new expdesc(); - check_condition(ls, vkisvar(lh.v.k), defs.to_luastring("syntax error", true)); - if (testnext(ls, char[','])) { /* assignment -> ',' suffixedexp assignment */ + check_condition(ls, vkisvar(lh.v.k), to_luastring("syntax error", true)); + if (testnext(ls, 44 /* (',').charCodeAt(0) */)) { /* assignment -> ',' suffixedexp assignment */ let nv = new LHS_assign(); nv.prev = lh; suffixedexp(ls, nv.v); if (nv.v.k !== expkind.VINDEXED) check_conflict(ls, lh, nv.v); - checklimit(ls.fs, nvars + ls.L.nCcalls, llimits.LUAI_MAXCCALLS, defs.to_luastring("JS levels", true)); + checklimit(ls.fs, nvars + ls.L.nCcalls, LUAI_MAXCCALLS, to_luastring("JS levels", true)); assignment(ls, nv, nvars + 1); } else { /* assignment -> '=' explist */ - checknext(ls, char['=']); + checknext(ls, 61 /* ('=').charCodeAt(0) */); let nexps = explist(ls, e); if (nexps !== nvars) adjust_assign(ls, nvars, nexps, e); else { - lcode.luaK_setoneret(ls.fs, e); /* close last expression */ - lcode.luaK_storevar(ls.fs, lh.v, e); + luaK_setoneret(ls.fs, e); /* close last expression */ + luaK_storevar(ls.fs, lh.v, e); return; /* avoid default */ } } init_exp(e, expkind.VNONRELOC, ls.fs.freereg-1); /* default assignment */ - lcode.luaK_storevar(ls.fs, lh.v, e); + luaK_storevar(ls.fs, lh.v, e); }; const cond = function(ls) { @@ -1144,7 +1238,7 @@ const cond = function(ls) { let v = new expdesc(); expr(ls, v); /* read condition */ if (v.k === expkind.VNIL) v.k = expkind.VFALSE; /* 'falses' are all equal here */ - lcode.luaK_goiftrue(ls.fs, v); + luaK_goiftrue(ls.fs, v); return v.f; }; @@ -1155,7 +1249,7 @@ const gotostat = function(ls, pc) { label = str_checkname(ls); else { llex.luaX_next(ls); /* skip break */ - label = lstring.luaS_newliteral(ls.L, "break"); + label = luaS_newliteral(ls.L, "break"); } let g = newlabelentry(ls, ls.dyd.gt, label, line, pc); findlabel(ls, g); /* close it if label already defined */ @@ -1166,7 +1260,7 @@ const checkrepeated = function(fs, ll, label) { for (let i = fs.bl.firstlabel; i < ll.n; i++) { if (eqstr(label, ll.arr[i].name)) { let msg = lobject.luaO_pushfstring(fs.ls.L, - defs.to_luastring("label '%s' already defined on line %d", true), + to_luastring("label '%s' already defined on line %d", true), label.getstr(), ll.arr[i].line); semerror(fs.ls, msg); } @@ -1175,7 +1269,7 @@ const checkrepeated = function(fs, ll, label) { /* skip no-op statements */ const skipnoopstat = function(ls) { - while (ls.t.token === char[';'] || ls.t.token === R.TK_DBCOLON) + while (ls.t.token === 59 /* (';').charCodeAt(0) */ || ls.t.token === R.TK_DBCOLON) statement(ls); }; @@ -1187,7 +1281,7 @@ const labelstat = function(ls, label, line) { checkrepeated(fs, ll, label); /* check for repeated labels */ checknext(ls, R.TK_DBCOLON); /* skip double colon */ /* create new entry for this label */ - l = newlabelentry(ls, ll, label, line, lcode.luaK_getlabel(fs)); + l = newlabelentry(ls, ll, label, line, luaK_getlabel(fs)); skipnoopstat(ls); /* skip other no-op statements */ if (block_follow(ls, 0)) { /* label is last no-op statement in the block? */ /* assume that locals are already out of scope */ @@ -1201,21 +1295,21 @@ const whilestat = function(ls, line) { let fs = ls.fs; let bl = new BlockCnt(); llex.luaX_next(ls); /* skip WHILE */ - let whileinit = lcode.luaK_getlabel(fs); + let whileinit = luaK_getlabel(fs); let condexit = cond(ls); enterblock(fs, bl, 1); checknext(ls, R.TK_DO); block(ls); - lcode.luaK_jumpto(fs, whileinit); + luaK_jumpto(fs, whileinit); check_match(ls, R.TK_END, R.TK_WHILE, line); leaveblock(fs); - lcode.luaK_patchtohere(fs, condexit); /* false conditions finish the loop */ + luaK_patchtohere(fs, condexit); /* false conditions finish the loop */ }; const repeatstat = function(ls, line) { /* repeatstat -> REPEAT block UNTIL cond */ let fs = ls.fs; - let repeat_init = lcode.luaK_getlabel(fs); + let repeat_init = luaK_getlabel(fs); let bl1 = new BlockCnt(); let bl2 = new BlockCnt(); enterblock(fs, bl1, 1); /* loop block */ @@ -1225,17 +1319,17 @@ const repeatstat = function(ls, line) { check_match(ls, R.TK_UNTIL, R.TK_REPEAT, line); let condexit = cond(ls); /* read condition (inside scope block) */ if (bl2.upval) /* upvalues? */ - lcode.luaK_patchclose(fs, condexit, bl2.nactvar); + luaK_patchclose(fs, condexit, bl2.nactvar); leaveblock(fs); /* finish scope */ - lcode.luaK_patchlist(fs, condexit, repeat_init); /* close the loop */ + luaK_patchlist(fs, condexit, repeat_init); /* close the loop */ leaveblock(fs); /* finish loop */ }; const exp1 = function(ls) { let e = new expdesc(); expr(ls, e); - lcode.luaK_exp2nextreg(ls.fs, e); - assert(e.k === expkind.VNONRELOC); + luaK_exp2nextreg(ls.fs, e); + lua_assert(e.k === expkind.VNONRELOC); let reg = e.u.info; return reg; }; @@ -1247,22 +1341,22 @@ const forbody = function(ls, base, line, nvars, isnum) { let endfor; adjustlocalvars(ls, 3); /* control variables */ checknext(ls, R.TK_DO); - let prep = isnum ? lcode.luaK_codeAsBx(fs, OpCodesI.OP_FORPREP, base, lcode.NO_JUMP) : lcode.luaK_jump(fs); + let prep = isnum ? luaK_codeAsBx(fs, OP_FORPREP, base, NO_JUMP) : luaK_jump(fs); enterblock(fs, bl, 0); /* scope for declared variables */ adjustlocalvars(ls, nvars); - lcode.luaK_reserveregs(fs, nvars); + luaK_reserveregs(fs, nvars); block(ls); leaveblock(fs); /* end of scope for declared variables */ - lcode.luaK_patchtohere(fs, prep); + luaK_patchtohere(fs, prep); if (isnum) /* end of scope for declared variables */ - endfor = lcode.luaK_codeAsBx(fs, OpCodesI.OP_FORLOOP, base, lcode.NO_JUMP); + endfor = luaK_codeAsBx(fs, OP_FORLOOP, base, NO_JUMP); else { /* generic for */ - lcode.luaK_codeABC(fs, OpCodesI.OP_TFORCALL, base, 0, nvars); - lcode.luaK_fixline(fs, line); - endfor = lcode.luaK_codeAsBx(fs, OpCodesI.OP_TFORLOOP, base + 2, lcode.NO_JUMP); + luaK_codeABC(fs, OP_TFORCALL, base, 0, nvars); + luaK_fixline(fs, line); + endfor = luaK_codeAsBx(fs, OP_TFORLOOP, base + 2, NO_JUMP); } - lcode.luaK_patchlist(fs, endfor, prep + 1); - lcode.luaK_fixline(fs, line); + luaK_patchlist(fs, endfor, prep + 1); + luaK_fixline(fs, line); }; const fornum = function(ls, varname, line) { @@ -1273,15 +1367,15 @@ const fornum = function(ls, varname, line) { new_localvarliteral(ls, "(for limit)"); new_localvarliteral(ls, "(for step)"); new_localvar(ls, varname); - checknext(ls, char['=']); + checknext(ls, 61 /* ('=').charCodeAt(0) */); exp1(ls); /* initial value */ - checknext(ls, char[',']); + checknext(ls, 44 /* (',').charCodeAt(0) */); exp1(ls); /* limit */ - if (testnext(ls, char[','])) + if (testnext(ls, 44 /* (',').charCodeAt(0) */)) exp1(ls); /* optional step */ else { /* default step = 1 */ - lcode.luaK_codek(fs, fs.freereg, lcode.luaK_intK(fs, 1)); - lcode.luaK_reserveregs(fs, 1); + luaK_codek(fs, fs.freereg, luaK_intK(fs, 1)); + luaK_reserveregs(fs, 1); } forbody(ls, base, line, 1, 1); }; @@ -1298,14 +1392,14 @@ const forlist = function(ls, indexname) { new_localvarliteral(ls, "(for control)"); /* create declared variables */ new_localvar(ls, indexname); - while (testnext(ls, char[','])) { + while (testnext(ls, 44 /* (',').charCodeAt(0) */)) { new_localvar(ls, str_checkname(ls)); nvars++; } checknext(ls, R.TK_IN); let line = ls.linenumber; adjust_assign(ls, 3, explist(ls, e), e); - lcode.luaK_checkstack(fs, 3); /* extra space to call generator */ + luaK_checkstack(fs, 3); /* extra space to call generator */ forbody(ls, base, line, nvars - 3, 0); }; @@ -1317,9 +1411,9 @@ const forstat = function(ls, line) { llex.luaX_next(ls); /* skip 'for' */ let varname = str_checkname(ls); /* first variable name */ switch (ls.t.token) { - case char['=']: fornum(ls, varname, line); break; - case char[',']: case R.TK_IN: forlist(ls, varname); break; - default: llex.luaX_syntaxerror(ls, defs.to_luastring("'=' or 'in' expected", true)); + case 61 /* ('=').charCodeAt(0) */: fornum(ls, varname, line); break; + case 44 /* (',').charCodeAt(0) */: case R.TK_IN: forlist(ls, varname); break; + default: llex.luaX_syntaxerror(ls, to_luastring("'=' or 'in' expected", true)); } check_match(ls, R.TK_END, R.TK_FOR, line); leaveblock(fs); /* loop scope ('break' jumps to this point) */ @@ -1337,17 +1431,17 @@ const test_then_block = function(ls, escapelist) { checknext(ls, R.TK_THEN); if (ls.t.token === R.TK_GOTO || ls.t.token === R.TK_BREAK) { - lcode.luaK_goiffalse(ls.fs, v); /* will jump to label if condition is true */ + luaK_goiffalse(ls.fs, v); /* will jump to label if condition is true */ enterblock(fs, bl, false); /* must enter block before 'goto' */ gotostat(ls, v.t); /* handle goto/break */ - while (testnext(ls, char[';'])); /* skip colons */ + while (testnext(ls, 59 /* (';').charCodeAt(0) */)); /* skip colons */ if (block_follow(ls, 0)) { /* 'goto' is the entire block? */ leaveblock(fs); return escapelist; /* and that is it */ } else /* must skip over 'then' part if condition is false */ - jf = lcode.luaK_jump(fs); + jf = luaK_jump(fs); } else { /* regular case (not goto/break) */ - lcode.luaK_goiftrue(ls.fs, v); /* skip over block if condition is false */ + luaK_goiftrue(ls.fs, v); /* skip over block if condition is false */ enterblock(fs, bl, false); jf = v.f; } @@ -1355,8 +1449,8 @@ const test_then_block = function(ls, escapelist) { statlist(ls); /* 'then' part */ leaveblock(fs); if (ls.t.token === R.TK_ELSE || ls.t.token === R.TK_ELSEIF) /* followed by 'else'/'elseif'? */ - escapelist = lcode.luaK_concat(fs, escapelist, lcode.luaK_jump(fs)); /* must jump over it */ - lcode.luaK_patchtohere(fs, jf); + escapelist = luaK_concat(fs, escapelist, luaK_jump(fs)); /* must jump over it */ + luaK_patchtohere(fs, jf); return escapelist; }; @@ -1364,14 +1458,14 @@ const test_then_block = function(ls, escapelist) { const ifstat = function(ls, line) { /* ifstat -> IF cond THEN block {ELSEIF cond THEN block} [ELSE block] END */ let fs = ls.fs; - let escapelist = lcode.NO_JUMP; /* exit list for finished parts */ + let escapelist = NO_JUMP; /* exit list for finished parts */ escapelist = test_then_block(ls, escapelist); /* IF cond THEN block */ while (ls.t.token === R.TK_ELSEIF) escapelist = test_then_block(ls, escapelist); /* ELSEIF cond THEN block */ if (testnext(ls, R.TK_ELSE)) block(ls); /* 'else' part */ check_match(ls, R.TK_END, R.TK_IF, line); - lcode.luaK_patchtohere(fs, escapelist); /* patch escape list to 'if' end */ + luaK_patchtohere(fs, escapelist); /* patch escape list to 'if' end */ }; const localfunc = function(ls) { @@ -1392,8 +1486,8 @@ const localstat = function(ls) { do { new_localvar(ls, str_checkname(ls)); nvars++; - } while (testnext(ls, char[','])); - if (testnext(ls, char['='])) + } while (testnext(ls, 44 /* (',').charCodeAt(0) */)); + if (testnext(ls, 61 /* ('=').charCodeAt(0) */)) nexps = explist(ls, e); else { e.k = expkind.VVOID; @@ -1407,9 +1501,9 @@ const funcname = function(ls, v) { /* funcname -> NAME {fieldsel} [':' NAME] */ let ismethod = 0; singlevar(ls, v); - while (ls.t.token === char['.']) + while (ls.t.token === 46 /* ('.').charCodeAt(0) */) fieldsel(ls, v); - if (ls.t.token === char[':']) { + if (ls.t.token === 58 /* (':').charCodeAt(0) */) { ismethod = 1; fieldsel(ls, v); } @@ -1423,8 +1517,8 @@ const funcstat = function(ls, line) { llex.luaX_next(ls); /* skip FUNCTION */ let ismethod = funcname(ls, v); body(ls, b, ismethod, line); - lcode.luaK_storevar(ls.fs, v, b); - lcode.luaK_fixline(ls.fs, line); /* definition "happens" in the first line */ + luaK_storevar(ls.fs, v, b); + luaK_fixline(ls.fs, line); /* definition "happens" in the first line */ }; const exprstat= function(ls) { @@ -1432,13 +1526,13 @@ const exprstat= function(ls) { let fs = ls.fs; let v = new LHS_assign(); suffixedexp(ls, v.v); - if (ls.t.token === char['='] || ls.t.token === char[',']) { /* stat . assignment ? */ + if (ls.t.token === 61 /* ('=').charCodeAt(0) */ || ls.t.token === 44 /* (',').charCodeAt(0) */) { /* stat . assignment ? */ v.prev = null; assignment(ls, v, 1); } else { /* stat -> func */ - check_condition(ls, v.v.k === expkind.VCALL, defs.to_luastring("syntax error", true)); - lopcodes.SETARG_C(lcode.getinstruction(fs, v.v), 1); /* call statement uses no results */ + check_condition(ls, v.v.k === expkind.VCALL, to_luastring("syntax error", true)); + SETARG_C(getinstruction(fs, v.v), 1); /* call statement uses no results */ } }; @@ -1447,37 +1541,37 @@ 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 === char[';']) + if (block_follow(ls, 1) || ls.t.token === 59 /* (';').charCodeAt(0) */) first = nret = 0; /* return no values */ else { nret = explist(ls, e); /* optional return values */ if (hasmultret(e.k)) { - lcode.luaK_setmultret(fs, e); + luaK_setmultret(fs, e); if (e.k === expkind.VCALL && nret === 1) { /* tail call? */ - lopcodes.SET_OPCODE(lcode.getinstruction(fs, e), OpCodesI.OP_TAILCALL); - assert(lcode.getinstruction(fs, e).A === fs.nactvar); + SET_OPCODE(getinstruction(fs, e), OP_TAILCALL); + lua_assert(getinstruction(fs, e).A === fs.nactvar); } first = fs.nactvar; - nret = defs.LUA_MULTRET; /* return all values */ + nret = LUA_MULTRET; /* return all values */ } else { if (nret === 1) /* only one single value? */ - first = lcode.luaK_exp2anyreg(fs, e); + first = luaK_exp2anyreg(fs, e); else { - lcode.luaK_exp2nextreg(fs, e); /* values must go to the stack */ + luaK_exp2nextreg(fs, e); /* values must go to the stack */ first = fs.nactvar; /* return all active values */ - assert(nret === fs.freereg - first); + lua_assert(nret === fs.freereg - first); } } } - lcode.luaK_ret(fs, first, nret); - testnext(ls, char[';']); /* skip optional semicolon */ + luaK_ret(fs, first, nret); + testnext(ls, 59 /* (';').charCodeAt(0) */); /* skip optional semicolon */ }; const statement = function(ls) { let line = ls.linenumber; /* may be needed for error messages */ enterlevel(ls); switch(ls.t.token) { - case char[';']: { /* stat -> ';' (empty statement) */ + case 59 /* (';').charCodeAt(0) */: { /* stat -> ';' (empty statement) */ llex.luaX_next(ls); /* skip ';' */ break; } @@ -1527,7 +1621,7 @@ const statement = function(ls) { } case R.TK_BREAK: /* stat -> breakstat */ case R.TK_GOTO: { /* stat -> 'goto' NAME */ - gotostat(ls, lcode.luaK_jump(ls.fs)); + gotostat(ls, luaK_jump(ls.fs)); break; } default: { /* stat -> func | assignment */ @@ -1535,8 +1629,7 @@ const statement = function(ls) { break; } } - - assert(ls.fs.f.maxstacksize >= ls.fs.freereg && ls.fs.freereg >= ls.fs.nactvar); + lua_assert(ls.fs.f.maxstacksize >= ls.fs.freereg && ls.fs.freereg >= ls.fs.nactvar); ls.fs.freereg = ls.fs.nactvar; /* free registers */ leavelevel(ls); }; @@ -1568,15 +1661,15 @@ const luaY_parser = function(L, z, buff, dyd, name, firstchar) { ldo.luaD_inctop(L); L.stack[L.top-1].sethvalue(lexstate.h); funcstate.f = cl.p = new Proto(L); - funcstate.f.source = lstring.luaS_new(L, name); + funcstate.f.source = luaS_new(L, name); lexstate.buff = buff; lexstate.dyd = dyd; dyd.actvar.n = dyd.gt.n = dyd.label.n = 0; llex.luaX_setinput(L, lexstate, z, funcstate.f.source, firstchar); mainfunc(lexstate, funcstate); - assert(!funcstate.prev && funcstate.nups === 1 && !lexstate.fs); + lua_assert(!funcstate.prev && funcstate.nups === 1 && !lexstate.fs); /* all scopes should be correctly finished */ - assert(dyd.actvar.n === 0 && dyd.gt.n === 0 && dyd.label.n === 0); + lua_assert(dyd.actvar.n === 0 && dyd.gt.n === 0 && dyd.label.n === 0); delete L.stack[--L.top]; /* remove scanner's table */ return cl; /* closure is on the stack, too */ }; diff --git a/src/lstate.js b/src/lstate.js index db046dc..0c44f3c 100644 --- a/src/lstate.js +++ b/src/lstate.js @@ -1,21 +1,28 @@ "use strict"; -const assert = require('assert'); - -const defs = require('./defs.js'); +const { + LUA_MINSTACK, + LUA_RIDX_GLOBALS, + LUA_RIDX_MAINTHREAD, + constant_types: { + LUA_NUMTAGS, + LUA_TNIL, + LUA_TTABLE, + LUA_TTHREAD + }, + thread_status: { + LUA_OK + } +} = require('./defs.js'); const lobject = require('./lobject.js'); const ldo = require('./ldo.js'); const lapi = require('./lapi.js'); const ltable = require('./ltable.js'); -const lfunc = require('./lfunc.js'); const ltm = require('./ltm.js'); -const CT = defs.constant_types; -const TS = defs.thread_status; -const LUA_NUMTAGS = CT.LUA_NUMTAGS; const EXTRA_STACK = 5; -const BASIC_STACK_SIZE = 2 * defs.LUA_MINSTACK; +const BASIC_STACK_SIZE = 2 * LUA_MINSTACK; class CallInfo { @@ -62,9 +69,8 @@ class lua_State { this.basehookcount = 0; this.allowhook = 1; this.hookcount = this.basehookcount; - this.openupval = null; this.nny = 1; - this.status = TS.LUA_OK; + this.status = LUA_OK; this.errfunc = 0; } @@ -77,7 +83,7 @@ class global_State { this.ids = new WeakMap(); this.mainthread = null; - this.l_registry = new lobject.TValue(CT.LUA_TNIL, null); + this.l_registry = new lobject.TValue(LUA_TNIL, null); this.panic = null; this.atnativeerror = null; this.version = null; @@ -111,8 +117,8 @@ const stack_init = function(L1, L) { ci.callstatus = 0; ci.funcOff = L1.top; ci.func = L1.stack[L1.top]; - L1.stack[L1.top++] = new lobject.TValue(CT.LUA_TNIL, null); - ci.top = L1.top + defs.LUA_MINSTACK; + L1.stack[L1.top++] = new lobject.TValue(LUA_TNIL, null); + ci.top = L1.top + LUA_MINSTACK; L1.ci = ci; }; @@ -128,8 +134,8 @@ const freestack = function(L) { const init_registry = function(L, g) { let registry = ltable.luaH_new(L); g.l_registry.sethvalue(registry); - ltable.luaH_setint(registry, defs.LUA_RIDX_MAINTHREAD, new lobject.TValue(CT.LUA_TTHREAD, L)); - ltable.luaH_setint(registry, defs.LUA_RIDX_GLOBALS, new lobject.TValue(CT.LUA_TTABLE, ltable.luaH_new(L))); + ltable.luaH_setint(registry, LUA_RIDX_MAINTHREAD, new lobject.TValue(LUA_TTHREAD, L)); + ltable.luaH_setint(registry, LUA_RIDX_GLOBALS, new lobject.TValue(LUA_TTABLE, ltable.luaH_new(L))); }; /* @@ -147,9 +153,8 @@ const f_luaopen = function(L) { const lua_newthread = function(L) { let g = L.l_G; let L1 = new lua_State(g); - L.stack[L.top] = new lobject.TValue(CT.LUA_TTHREAD, L1); - L.top++; - assert(L.top <= L.ci.top, "stack overflow"); + L.stack[L.top] = new lobject.TValue(LUA_TTHREAD, L1); + lapi.api_incr_top(L); L1.hookmask = L.hookmask; L1.basehookcount = L.basehookcount; L1.hook = L.hook; @@ -159,7 +164,6 @@ const lua_newthread = function(L) { }; const luaE_freethread = function(L, L1) { - lfunc.luaF_close(L1, L1.stack); freestack(L1); }; @@ -168,7 +172,7 @@ const lua_newstate = function() { let L = new lua_State(g); g.mainthread = L; - if (ldo.luaD_rawrunprotected(L, f_luaopen, null) !== TS.LUA_OK) { + if (ldo.luaD_rawrunprotected(L, f_luaopen, null) !== LUA_OK) { L = null; } @@ -176,7 +180,6 @@ const lua_newstate = function() { }; const close_state = function(L) { - lfunc.luaF_close(L, L.stack); /* close all upvalues for this thread */ freestack(L); }; diff --git a/src/lstring.js b/src/lstring.js index c8da56a..4769866 100644 --- a/src/lstring.js +++ b/src/lstring.js @@ -1,8 +1,12 @@ "use strict"; -const assert = require("assert"); - -const defs = require('./defs.js'); +const { + is_luastring, + luastring_eq, + luastring_from, + to_luastring +} = require('./defs.js'); +const { lua_assert } = require("./llimits.js"); class TString { @@ -22,20 +26,24 @@ class TString { } const luaS_eqlngstr = function(a, b) { - assert(a instanceof TString); - assert(b instanceof TString); - return a == b || defs.luastring_cmp(a.realstring, b.realstring); + lua_assert(a instanceof TString); + lua_assert(b instanceof TString); + return a == b || luastring_eq(a.realstring, b.realstring); }; /* converts strings (arrays) to a consistent map key make sure this doesn't conflict with any of the anti-collision strategies in ltable */ const luaS_hash = function(str) { - assert(defs.is_luastring(str)); - return '|'+str.join('|'); + lua_assert(is_luastring(str)); + let len = str.length; + let s = "|"; + for (let i=0; i<len; i++) + s += str[i].toString(16); + return s; }; const luaS_hashlongstr = function(ts) { - assert(ts instanceof TString); + lua_assert(ts instanceof TString); if(ts.hash === null) { ts.hash = luaS_hash(ts.getstr()); } @@ -44,18 +52,18 @@ const luaS_hashlongstr = function(ts) { /* variant that takes ownership of array */ const luaS_bless = function(L, str) { - assert(str instanceof Uint8Array); + lua_assert(str instanceof Uint8Array); return new TString(L, str); }; /* makes a copy */ const luaS_new = function(L, str) { - return luaS_bless(L, Uint8Array.from(str)); + return luaS_bless(L, luastring_from(str)); }; /* takes a js string */ const luaS_newliteral = function(L, str) { - return luaS_bless(L, defs.to_luastring(str)); + return luaS_bless(L, to_luastring(str)); }; module.exports.luaS_eqlngstr = luaS_eqlngstr; diff --git a/src/lstrlib.js b/src/lstrlib.js index 362942d..fcaea79 100644 --- a/src/lstrlib.js +++ b/src/lstrlib.js @@ -1,11 +1,84 @@ "use strict"; -const assert = require('assert'); -const sprintf = require('sprintf-js').sprintf; - -const lauxlib = require('./lauxlib.js'); -const lua = require('./lua.js'); -const luaconf = require('./luaconf.js'); +const { sprintf } = require('sprintf-js'); + +const { + LUA_INTEGER_FMT, + LUA_INTEGER_FRMLEN, + LUA_MININTEGER, + LUA_NUMBER_FMT, + LUA_NUMBER_FRMLEN, + frexp, + lua_getlocaledecpoint +} = require('./luaconf.js'); +const { + LUA_TBOOLEAN, + LUA_TFUNCTION, + LUA_TNIL, + LUA_TNUMBER, + LUA_TSTRING, + LUA_TTABLE, + lua_call, + lua_createtable, + lua_dump, + lua_gettable, + lua_gettop, + lua_isinteger, + lua_isstring, + lua_pop, + lua_pushcclosure, + lua_pushinteger, + lua_pushlightuserdata, + lua_pushliteral, + lua_pushlstring, + lua_pushnil, + lua_pushnumber, + lua_pushstring, + lua_pushvalue, + lua_remove, + lua_setfield, + lua_setmetatable, + lua_settop, + lua_toboolean, + lua_tointeger, + lua_tonumber, + lua_tostring, + lua_touserdata, + lua_type, + lua_upvalueindex +} = require('./lua.js'); +const { + luaL_Buffer, + luaL_addchar, + luaL_addlstring, + luaL_addsize, + luaL_addstring, + luaL_addvalue, + luaL_argcheck, + luaL_argerror, + luaL_buffinit, + luaL_buffinitsize, + luaL_checkinteger, + luaL_checknumber, + luaL_checkstack, + luaL_checkstring, + luaL_checktype, + luaL_error, + luaL_newlib, + luaL_optinteger, + luaL_optstring, + luaL_prepbuffsize, + luaL_pushresult, + luaL_pushresultsize, + luaL_tolstring, + luaL_typename +} = require('./lauxlib.js'); +const lualib = require('./lualib.js'); +const { + luastring_indexOf, + to_jsstring, + to_luastring +} = require("./fengaricore.js"); const sL_ESC = '%'; const L_ESC = sL_ESC.charCodeAt(0); @@ -22,7 +95,7 @@ const MAXSIZE = 2147483647; /* Give natural (i.e. strings end at the first \0) length of a string represented by an array of bytes */ const strlen = function(s) { - let len = s.indexOf(0); + let len = luastring_indexOf(s, 0); return len > -1 ? len : s.length; }; @@ -34,74 +107,74 @@ const posrelat = function(pos, len) { }; const str_sub = function(L) { - let s = lauxlib.luaL_checkstring(L, 1); + let s = luaL_checkstring(L, 1); let l = s.length; - let start = posrelat(lauxlib.luaL_checkinteger(L, 2), l); - let end = posrelat(lauxlib.luaL_optinteger(L, 3, -1), l); + let start = posrelat(luaL_checkinteger(L, 2), l); + let end = posrelat(luaL_optinteger(L, 3, -1), l); if (start < 1) start = 1; if (end > l) end = l; if (start <= end) - lua.lua_pushstring(L, s.slice(start - 1, (start - 1) + (end - start + 1))); - else lua.lua_pushliteral(L, ""); + lua_pushstring(L, s.subarray(start - 1, (start - 1) + (end - start + 1))); + else lua_pushliteral(L, ""); return 1; }; const str_len = function(L) { - lua.lua_pushinteger(L, lauxlib.luaL_checkstring(L, 1).length); + lua_pushinteger(L, luaL_checkstring(L, 1).length); return 1; }; const str_char = function(L) { - let n = lua.lua_gettop(L); /* number of arguments */ - let b = new lauxlib.luaL_Buffer(); - let p = lauxlib.luaL_buffinitsize(L, b, n); + let n = lua_gettop(L); /* number of arguments */ + let b = new luaL_Buffer(); + let p = luaL_buffinitsize(L, b, n); for (let i = 1; i <= n; i++) { - let c = lauxlib.luaL_checkinteger(L, i); - lauxlib.luaL_argcheck(L, c >= 0 && c <= 255, "value out of range"); // Strings are 8-bit clean + let c = luaL_checkinteger(L, i); + luaL_argcheck(L, c >= 0 && c <= 255, "value out of range"); // Strings are 8-bit clean p[i-1] = c; } - lauxlib.luaL_pushresultsize(b, n); + luaL_pushresultsize(b, n); return 1; }; const writer = function(L, b, size, B) { - lauxlib.luaL_addlstring(B, b, size); + luaL_addlstring(B, b, size); return 0; }; const str_dump = function(L) { - let b = new lauxlib.luaL_Buffer(); - let strip = lua.lua_toboolean(L, 2); - lauxlib.luaL_checktype(L, 1, lua.LUA_TFUNCTION); - lua.lua_settop(L, 1); - lauxlib.luaL_buffinit(L, b); - if (lua.lua_dump(L, writer, b, strip) !== 0) - return lauxlib.luaL_error(L, lua.to_luastring("unable to dump given function")); - lauxlib.luaL_pushresult(b); + let b = new luaL_Buffer(); + let strip = lua_toboolean(L, 2); + luaL_checktype(L, 1, LUA_TFUNCTION); + lua_settop(L, 1); + luaL_buffinit(L, b); + if (lua_dump(L, writer, b, strip) !== 0) + return luaL_error(L, to_luastring("unable to dump given function")); + luaL_pushresult(b); return 1; }; -const SIZELENMOD = luaconf.LUA_NUMBER_FRMLEN.length + 1; +const SIZELENMOD = LUA_NUMBER_FRMLEN.length + 1; const L_NBFD = 1; const num2straux = function(x) { /* if 'inf' or 'NaN', format it like '%g' */ if (Object.is(x, Infinity)) - return lua.to_luastring('inf', true).slice(0); + return to_luastring('inf'); else if (Object.is(x, -Infinity)) - return lua.to_luastring('-inf', true).slice(0); + return to_luastring('-inf'); else if (Number.isNaN(x)) - return lua.to_luastring('nan', true).slice(0); + return to_luastring('nan'); else if (x === 0) { /* can be -0... */ /* create "0" or "-0" followed by exponent */ - let zero = sprintf(luaconf.LUA_NUMBER_FMT + "x0p+0", x); + let zero = sprintf(LUA_NUMBER_FMT + "x0p+0", x); if (Object.is(x, -0)) zero = "-" + zero; - return lua.to_luastring(zero); + return to_luastring(zero); } else { let buff = ""; - let fe = luaconf.frexp(x); /* 'x' fraction and exponent */ + let fe = frexp(x); /* 'x' fraction and exponent */ let m = fe[0]; let e = fe[1]; if (m < 0) { /* is number negative? */ @@ -112,17 +185,20 @@ const num2straux = function(x) { buff += (m * (1<<L_NBFD)).toString(16); e -= L_NBFD; /* this digit goes before the radix point */ buff += sprintf("p%+d", e); /* add exponent */ - return lua.to_luastring(buff); + return to_luastring(buff); } }; const lua_number2strx = function(L, fmt, x) { let buff = num2straux(x); - if (fmt[SIZELENMOD] === 'A'.charCodeAt(0)) { - for (let i = 0; i < buff.length; i++) - buff[i] = String.fromCharCode(buff[i]).toUpperCase().charCodeAt(0); - } else if (fmt[SIZELENMOD] !== 'a'.charCodeAt(0)) - lauxlib.luaL_error(L, lua.to_luastring("modifiers for format '%%a'/'%%A' not implemented")); + if (fmt[SIZELENMOD] === 65 /* 'A'.charCodeAt(0) */) { + for (let i = 0; i < buff.length; i++) { + let c = buff[i]; + if (c >= 97) /* toupper */ + buff[i] = c & 0xdf; + } + } else if (fmt[SIZELENMOD] !== 97 /* 'a'.charCodeAt(0) */) + luaL_error(L, to_luastring("modifiers for format '%%a'/'%%A' not implemented")); return buff; }; @@ -137,106 +213,105 @@ const lua_number2strx = function(L, fmt, x) { /* valid flags in a format specification */ -const FLAGS = ["-".charCodeAt(0), "+".charCodeAt(0), " ".charCodeAt(0), "#".charCodeAt(0), "0".charCodeAt(0)]; +const FLAGS = to_luastring("-+ #0"); /* ** maximum size of each format specification (such as "%-099.99d") */ // const MAX_FORMAT = 32; -// TODO: locale ? and do it better -const isalpha = e => ('a'.charCodeAt(0) <= e && e <= 'z'.charCodeAt(0)) || (e >= 'A'.charCodeAt(0) && e <= 'Z'.charCodeAt(0)); -const isdigit = e => '0'.charCodeAt(0) <= e && e <= '9'.charCodeAt(0); +const isalpha = e => (97 <= e && e <= 122) || (65 <= e && e <= 90); +const isdigit = e => 48 <= e && e <= 57; const iscntrl = e => (0x00 <= e && e <= 0x1f) || e === 0x7f; -const isgraph = e => e > 32 && e < 127; // TODO: Will only work for ASCII -const islower = e => /^[a-z]$/.test(String.fromCharCode(e)); -const isupper = e => /^[A-Z]$/.test(String.fromCharCode(e)); -const isalnum = e => /^[a-zA-Z0-9]$/.test(String.fromCharCode(e)); +const isgraph = e => 33 <= e && e <= 126; +const islower = e => 97 <= e && e <= 122; +const isupper = e => 65 <= e && e <= 90; +const isalnum = e => (97 <= e && e <= 122) || (65 <= e && e <= 90) || (48 <= e && e <= 57); const ispunct = e => isgraph(e) && !isalnum(e); -const isspace = e => /^\s$/.test(String.fromCharCode(e)); -const isxdigit = e => /^[0-9A-Fa-f]$/.test(String.fromCharCode(e)); +const isspace = e => e === 32 || (e >= 9 && e <= 13); +const isxdigit = e => (48 <= e && e <= 57) || (65 <= e && e <= 70) || (97 <= e && e <= 102); const addquoted = function(b, s, len) { - lauxlib.luaL_addchar(b, '"'.charCodeAt(0)); + luaL_addchar(b, 34 /* '"'.charCodeAt(0) */); let i = 0; while (len--) { - if (s[i] === '"'.charCodeAt(0) || s[i] === '\\'.charCodeAt(0) || s[i] === '\n'.charCodeAt(0)) { - lauxlib.luaL_addchar(b, '\\'.charCodeAt(0)); - lauxlib.luaL_addchar(b, s[i]); + if (s[i] === 34 /* '"'.charCodeAt(0) */ || + s[i] === 92 /* '\\'.charCodeAt(0) */ || + s[i] === 10 /* '\n'.charCodeAt(0) */) { + luaL_addchar(b, 92 /* '\\'.charCodeAt(0) */); + luaL_addchar(b, s[i]); } else if (iscntrl(s[i])) { - let buff; - if (!isdigit(s[i+1])) - buff = lua.to_luastring(sprintf("\\%d", s[i])); - else - buff = lua.to_luastring(sprintf("\\%03d", s[i])); - lauxlib.luaL_addstring(b, buff); + let buff = ''+s[i]; + if (isdigit(s[i+1])) + buff = '0'.repeat(3-buff.length) + buff; /* pad to 3 '0's */ + luaL_addstring(b, to_luastring("\\" + buff)); } else - lauxlib.luaL_addchar(b, s[i]); + luaL_addchar(b, s[i]); i++; } - lauxlib.luaL_addchar(b, '"'.charCodeAt(0)); + luaL_addchar(b, 34 /* '"'.charCodeAt(0) */); }; /* ** Ensures the 'buff' string uses a dot as the radix character. */ const checkdp = function(buff) { - if (buff.indexOf('.'.charCodeAt(0)) < 0) { /* no dot? */ - let point = luaconf.lua_getlocaledecpoint().charCodeAt(0); /* try locale point */ - let ppoint = buff.indexOf(point); - if (ppoint) buff[ppoint] = '.'; /* change it to a dot */ + if (luastring_indexOf(buff, 46 /* ('.').charCodeAt(0) */) < 0) { /* no dot? */ + let point = lua_getlocaledecpoint(); /* try locale point */ + let ppoint = luastring_indexOf(buff, point); + if (ppoint) buff[ppoint] = 46 /* ('.').charCodeAt(0) */; /* change it to a dot */ } }; const addliteral = function(L, b, arg) { - switch(lua.lua_type(L, arg)) { - case lua.LUA_TSTRING: { - let s = lua.lua_tostring(L, arg); + switch(lua_type(L, arg)) { + case LUA_TSTRING: { + let s = lua_tostring(L, arg); addquoted(b, s, s.length); break; } - case lua.LUA_TNUMBER: { + case LUA_TNUMBER: { let buff; - if (!lua.lua_isinteger(L, arg)) { /* float? */ - let n = lua.lua_tonumber(L, arg); /* write as hexa ('%a') */ - buff = lua_number2strx(L, lua.to_luastring(`%${luaconf.LUA_INTEGER_FRMLEN}a`), n); + if (!lua_isinteger(L, arg)) { /* float? */ + let n = lua_tonumber(L, arg); /* write as hexa ('%a') */ + buff = lua_number2strx(L, to_luastring(`%${LUA_INTEGER_FRMLEN}a`), n); checkdp(buff); /* ensure it uses a dot */ } else { /* integers */ - let n = lua.lua_tointeger(L, arg); - let format = (n === luaconf.LUA_MININTEGER) /* corner case? */ - ? "0x%" + luaconf.LUA_INTEGER_FRMLEN + "x" /* use hexa */ - : luaconf.LUA_INTEGER_FMT; /* else use default format */ - buff = lua.to_luastring(sprintf(format, n)); + let n = lua_tointeger(L, arg); + let format = (n === LUA_MININTEGER) /* corner case? */ + ? "0x%" + LUA_INTEGER_FRMLEN + "x" /* use hexa */ + : LUA_INTEGER_FMT; /* else use default format */ + buff = to_luastring(sprintf(format, n)); } - lauxlib.luaL_addstring(b, buff); + luaL_addstring(b, buff); break; } - case lua.LUA_TNIL: case lua.LUA_TBOOLEAN: { - lauxlib.luaL_tolstring(L, arg); - lauxlib.luaL_addvalue(b); + case LUA_TNIL: case LUA_TBOOLEAN: { + luaL_tolstring(L, arg); + luaL_addvalue(b); break; } default: { - lauxlib.luaL_argerror(L, arg, lua.to_luastring("value has no literal form", true)); + luaL_argerror(L, arg, to_luastring("value has no literal form", true)); } } }; const scanformat = function(L, strfrmt, i, form) { let p = i; - while (strfrmt[p] !== 0 && FLAGS.indexOf(strfrmt[p]) >= 0) p++; /* skip flags */ + while (strfrmt[p] !== 0 && luastring_indexOf(FLAGS, strfrmt[p]) >= 0) p++; /* skip flags */ if (p - i >= FLAGS.length) - lauxlib.luaL_error(L, lua.to_luastring("invalid format (repeated flags)", true)); + luaL_error(L, to_luastring("invalid format (repeated flags)", true)); if (isdigit(strfrmt[p])) p++; /* skip width */ if (isdigit(strfrmt[p])) p++; /* (2 digits at most) */ - if (strfrmt[p] === '.'.charCodeAt(0)) { + if (strfrmt[p] === 46 /* '.'.charCodeAt(0) */) { p++; if (isdigit(strfrmt[p])) p++; /* skip precision */ if (isdigit(strfrmt[p])) p++; /* (2 digits at most) */ } if (isdigit(strfrmt[p])) - lauxlib.luaL_error(L, lua.to_luastring("invalid format (width or precision too long)", true)); - form[0] = "%".charCodeAt(0); + luaL_error(L, to_luastring("invalid format (width or precision too long)", true)); + form[0] = 37 /* "%".charCodeAt(0) */; for (let j = 0; j < p - i + 1; j++) form[j+1] = strfrmt[i+j]; return p; @@ -249,52 +324,52 @@ const addlenmod = function(form, lenmod) { let l = form.length; let lm = lenmod.length; let spec = form[l - 1]; - for (let i = 0; i < lenmod.length; i++) + for (let i = 0; i < lm; i++) form[i + l - 1] = lenmod[i]; form[l + lm - 1] = spec; // form[l + lm] = 0; }; const str_format = function(L) { - let top = lua.lua_gettop(L); + let top = lua_gettop(L); let arg = 1; - let strfrmt = lauxlib.luaL_checkstring(L, arg); + let strfrmt = luaL_checkstring(L, arg); let i = 0; - let b = new lauxlib.luaL_Buffer(); - lauxlib.luaL_buffinit(L, b); + let b = new luaL_Buffer(); + luaL_buffinit(L, b); while (i < strfrmt.length) { if (strfrmt[i] !== L_ESC) { - lauxlib.luaL_addchar(b, strfrmt[i++]); + luaL_addchar(b, strfrmt[i++]); } else if (strfrmt[++i] === L_ESC) { - lauxlib.luaL_addchar(b, strfrmt[i++]); /* %% */ + luaL_addchar(b, strfrmt[i++]); /* %% */ } else { /* format item */ let form = []; /* to store the format ('%...') */ if (++arg > top) - lauxlib.luaL_argerror(L, arg, lua.to_luastring("no value", true)); + luaL_argerror(L, arg, to_luastring("no value", true)); i = scanformat(L, strfrmt, i, form); switch (String.fromCharCode(strfrmt[i++])) { case 'c': { - // sprintf(String.fromCharCode(...form), lauxlib.luaL_checkinteger(L, arg)); - lauxlib.luaL_addchar(b, lauxlib.luaL_checkinteger(L, arg)); + // sprintf(String.fromCharCode(...form), luaL_checkinteger(L, arg)); + luaL_addchar(b, luaL_checkinteger(L, arg)); break; } case 'd': case 'i': case 'o': case 'u': case 'x': case 'X': { - let n = lauxlib.luaL_checkinteger(L, arg); - addlenmod(form, luaconf.LUA_INTEGER_FRMLEN.split('').map(e => e.charCodeAt(0))); - lauxlib.luaL_addstring(b, lua.to_luastring(sprintf(String.fromCharCode(...form), n))); + let n = luaL_checkinteger(L, arg); + addlenmod(form, to_luastring(LUA_INTEGER_FRMLEN, true)); + luaL_addstring(b, to_luastring(sprintf(String.fromCharCode(...form), n))); break; } case 'a': case 'A': { - addlenmod(form, luaconf.LUA_INTEGER_FRMLEN.split('').map(e => e.charCodeAt(0))); - lauxlib.luaL_addstring(b, lua_number2strx(L, form, lauxlib.luaL_checknumber(L, arg))); + addlenmod(form, to_luastring(LUA_INTEGER_FRMLEN, true)); + luaL_addstring(b, lua_number2strx(L, form, luaL_checknumber(L, arg))); break; } case 'e': case 'E': case 'f': case 'g': case 'G': { - let n = lauxlib.luaL_checknumber(L, arg); - addlenmod(form, luaconf.LUA_INTEGER_FRMLEN.split('').map(e => e.charCodeAt(0))); - lauxlib.luaL_addstring(b, lua.to_luastring(sprintf(String.fromCharCode(...form), n))); + let n = luaL_checknumber(L, arg); + addlenmod(form, to_luastring(LUA_INTEGER_FRMLEN, true)); + luaL_addstring(b, to_luastring(sprintf(String.fromCharCode(...form), n))); break; } case 'q': { @@ -302,29 +377,29 @@ const str_format = function(L) { break; } case 's': { - let s = lauxlib.luaL_tolstring(L, arg); + let s = luaL_tolstring(L, arg); if (form.length <= 2 || form[2] === 0) { /* no modifiers? */ - lauxlib.luaL_addvalue(b); /* keep entire string */ + luaL_addvalue(b); /* keep entire string */ } else { - lauxlib.luaL_argcheck(L, s.length === strlen(s), arg, lua.to_luastring("string contains zeros", true)); - if (form.indexOf('.'.charCodeAt(0)) < 0 && s.length >= 100) { + luaL_argcheck(L, s.length === strlen(s), arg, to_luastring("string contains zeros", true)); + if (luastring_indexOf(form, 46 /* '.'.charCodeAt(0) */) < 0 && s.length >= 100) { /* no precision and string is too long to be formatted */ - lauxlib.luaL_addvalue(b); /* keep entire string */ + luaL_addvalue(b); /* keep entire string */ } else { /* format the string into 'buff' */ // TODO: will fail if s is not valid UTF-8 - lauxlib.luaL_addstring(b, lua.to_luastring(sprintf(String.fromCharCode(...form), lua.to_jsstring(s)))); - lua.lua_pop(L, 1); /* remove result from 'luaL_tolstring' */ + luaL_addstring(b, to_luastring(sprintf(String.fromCharCode(...form), to_jsstring(s)))); + lua_pop(L, 1); /* remove result from 'luaL_tolstring' */ } } break; } default: { /* also treat cases 'pnLlh' */ - return lauxlib.luaL_error(L, lua.to_luastring("invalid option '%%%c' to 'format'"), strfrmt[i-1]); + return luaL_error(L, to_luastring("invalid option '%%%c' to 'format'"), strfrmt[i-1]); } } } } - lauxlib.luaL_pushresult(b); + luaL_pushresult(b); return 1; }; @@ -358,21 +433,17 @@ class Header { /* ** options for pack/unpack */ -const KOption = { - Kint: 0, /* signed integers */ - Kuint: 1, /* unsigned integers */ - Kfloat: 2, /* floating-point numbers */ - Kchar: 3, /* fixed-length strings */ - Kstring: 4, /* strings with prefixed length */ - Kzstr: 5, /* zero-terminated strings */ - Kpadding: 6, /* padding */ - Kpaddalign: 7, /* padding for alignment */ - Knop: 8 /* no-op (configuration or spaces) */ -}; - -const digit = function(c) { - return '0'.charCodeAt(0) <= c && c <= '9'.charCodeAt(0); -}; +const Kint = 0; /* signed integers */ +const Kuint = 1; /* unsigned integers */ +const Kfloat = 2; /* floating-point numbers */ +const Kchar = 3; /* fixed-length strings */ +const Kstring = 4; /* strings with prefixed length */ +const Kzstr = 5; /* zero-terminated strings */ +const Kpadding = 6; /* padding */ +const Kpaddalign = 7; /* padding for alignment */ +const Knop = 8; /* no-op (configuration or spaces) */ + +const digit = isdigit; const getnum = function(fmt, df) { if (fmt.off >= fmt.s.length || !digit(fmt.s[fmt.off])) /* no number? */ @@ -380,7 +451,7 @@ const getnum = function(fmt, df) { else { let a = 0; do { - a = a * 10 + (fmt.s[fmt.off++] - '0'.charCodeAt(0)); + a = a * 10 + (fmt.s[fmt.off++] - 48 /* '0'.charCodeAt(0) */); } while (fmt.off < fmt.s.length && digit(fmt.s[fmt.off]) && a <= (MAXSIZE - 9)/10); return a; } @@ -393,7 +464,7 @@ const getnum = function(fmt, df) { const getnumlimit = function(h, fmt, df) { let sz = getnum(fmt, df); if (sz > MAXINTSIZE || sz <= 0) - lauxlib.luaL_error(h.L, lua.to_luastring("integral size (%d) out of limits [1,%d]"), sz, MAXINTSIZE); + luaL_error(h.L, to_luastring("integral size (%d) out of limits [1,%d]"), sz, MAXINTSIZE); return sz; }; @@ -402,47 +473,43 @@ const getnumlimit = function(h, fmt, df) { */ const getoption = function(h, fmt) { let r = { - opt: NaN, - size: NaN + opt: fmt.s[fmt.off++], + size: 0 /* default */ }; - - r.opt = fmt.s[fmt.off++]; - r.size = 0; /* default */ switch (r.opt) { - case 'b'.charCodeAt(0): r.size = 1; r.opt = KOption.Kint; return r; // sizeof(char): 1 - case 'B'.charCodeAt(0): r.size = 1; r.opt = KOption.Kuint; return r; - case 'h'.charCodeAt(0): r.size = 2; r.opt = KOption.Kint; return r; // sizeof(short): 2 - case 'H'.charCodeAt(0): r.size = 2; r.opt = KOption.Kuint; return r; - case 'l'.charCodeAt(0): r.size = 4; r.opt = KOption.Kint; return r; // sizeof(long): 4 - case 'L'.charCodeAt(0): r.size = 4; r.opt = KOption.Kuint; return r; - case 'j'.charCodeAt(0): r.size = 4; r.opt = KOption.Kint; return r; // sizeof(lua_Integer): 4 - case 'J'.charCodeAt(0): r.size = 4; r.opt = KOption.Kuint; return r; - case 'T'.charCodeAt(0): r.size = 4; r.opt = KOption.Kuint; return r; // sizeof(size_t): 4 - case 'f'.charCodeAt(0): r.size = 4; r.opt = KOption.Kfloat; return r; // sizeof(float): 4 - case 'd'.charCodeAt(0): r.size = 8; r.opt = KOption.Kfloat; return r; // sizeof(double): 8 - case 'n'.charCodeAt(0): r.size = 8; r.opt = KOption.Kfloat; return r; // sizeof(lua_Number): 8 - case 'i'.charCodeAt(0): r.size = getnumlimit(h, fmt, 4); r.opt = KOption.Kint; return r; // sizeof(int): 4 - case 'I'.charCodeAt(0): r.size = getnumlimit(h, fmt, 4); r.opt = KOption.Kuint; return r; - case 's'.charCodeAt(0): r.size = getnumlimit(h, fmt, 4); r.opt = KOption.Kstring; return r; - case 'c'.charCodeAt(0): { + case 98 /*'b'*/: r.size = 1; r.opt = Kint; return r; // sizeof(char): 1 + case 66 /*'B'*/: r.size = 1; r.opt = Kuint; return r; + case 104 /*'h'*/: r.size = 2; r.opt = Kint; return r; // sizeof(short): 2 + case 72 /*'H'*/: r.size = 2; r.opt = Kuint; return r; + case 108 /*'l'*/: r.size = 4; r.opt = Kint; return r; // sizeof(long): 4 + case 76 /*'L'*/: r.size = 4; r.opt = Kuint; return r; + case 106 /*'j'*/: r.size = 4; r.opt = Kint; return r; // sizeof(lua_Integer): 4 + case 74 /*'J'*/: r.size = 4; r.opt = Kuint; return r; + case 84 /*'T'*/: r.size = 4; r.opt = Kuint; return r; // sizeof(size_t): 4 + case 102 /*'f'*/: r.size = 4; r.opt = Kfloat; return r; // sizeof(float): 4 + case 100 /*'d'*/: r.size = 8; r.opt = Kfloat; return r; // sizeof(double): 8 + case 110 /*'n'*/: r.size = 8; r.opt = Kfloat; return r; // sizeof(lua_Number): 8 + case 105 /*'i'*/: r.size = getnumlimit(h, fmt, 4); r.opt = Kint; return r; // sizeof(int): 4 + case 73 /*'I'*/: r.size = getnumlimit(h, fmt, 4); r.opt = Kuint; return r; + case 115 /*'s'*/: r.size = getnumlimit(h, fmt, 4); r.opt = Kstring; return r; + case 99 /*'c'*/: { r.size = getnum(fmt, -1); if (r.size === -1) - lauxlib.luaL_error(h.L, lua.to_luastring("missing size for format option 'c'")); - r.opt = KOption.Kchar; + luaL_error(h.L, to_luastring("missing size for format option 'c'")); + r.opt = Kchar; return r; } - case 'z'.charCodeAt(0): r.opt = KOption.Kzstr; return r; - case 'x'.charCodeAt(0): r.size = 1; r.opt = KOption.Kpadding; return r; - case 'X'.charCodeAt(0): r.opt = KOption.Kpaddalign; return r; - case ' '.charCodeAt(0): break; - case '<'.charCodeAt(0): h.islittle = true; break; - case '>'.charCodeAt(0): h.islittle = false; break; - case '='.charCodeAt(0): h.islittle = true; break; - case '!'.charCodeAt(0): h.maxalign = getnumlimit(h, fmt, MAXALIGN); break; - default: lauxlib.luaL_error(h.L, lua.to_luastring("invalid format option '%c'"), r.opt); + case 122 /*'z'*/: r.opt = Kzstr; return r; + case 120 /*'x'*/: r.size = 1; r.opt = Kpadding; return r; + case 88 /*'X'*/: r.opt = Kpaddalign; return r; + case 32 /*' '*/: break; + case 60 /*'<'*/: h.islittle = true; break; + case 62 /*'>'*/: h.islittle = false; break; + case 61 /*'='*/: h.islittle = true; break; + case 33 /*'!'*/: h.maxalign = getnumlimit(h, fmt, MAXALIGN); break; + default: luaL_error(h.L, to_luastring("invalid format option '%c'"), r.opt); } - - r.opt = KOption.Knop; + r.opt = Knop; return r; }; @@ -466,24 +533,24 @@ const getdetails = function(h, totalsize, fmt) { r.size = opt.size; r.opt = opt.opt; let align = r.size; /* usually, alignment follows size */ - if (r.opt === KOption.Kpaddalign) { /* 'X' gets alignment from following option */ + if (r.opt === Kpaddalign) { /* 'X' gets alignment from following option */ if (fmt.off >= fmt.s.length || fmt.s[fmt.off] === 0) - lauxlib.luaL_argerror(h.L, 1, lua.to_luastring("invalid next option for option 'X'", true)); + luaL_argerror(h.L, 1, to_luastring("invalid next option for option 'X'", true)); else { let o = getoption(h, fmt); align = o.size; o = o.opt; - if (o === KOption.Kchar || align === 0) - lauxlib.luaL_argerror(h.L, 1, lua.to_luastring("invalid next option for option 'X'", true)); + if (o === Kchar || align === 0) + luaL_argerror(h.L, 1, to_luastring("invalid next option for option 'X'", true)); } } - if (align <= 1 || r.opt === KOption.Kchar) /* need no alignment? */ + if (align <= 1 || r.opt === Kchar) /* need no alignment? */ r.ntoalign = 0; else { if (align > h.maxalign) /* enforce maximum alignment */ align = h.maxalign; if ((align & (align -1)) !== 0) /* is 'align' not a power of 2? */ - lauxlib.luaL_argerror(h.L, 1, lua.to_luastring("format asks for alignment not power of 2", true)); + luaL_argerror(h.L, 1, to_luastring("format asks for alignment not power of 2", true)); r.ntoalign = (align - (totalsize & (align - 1))) & (align - 1); } return r; @@ -496,7 +563,7 @@ const getdetails = function(h, totalsize, fmt) { ** bytes if necessary (by default they would be zeros). */ const packint = function(b, n, islittle, size, neg) { - let buff = lauxlib.luaL_prepbuffsize(b, size); + let buff = luaL_prepbuffsize(b, size); buff[islittle ? 0 : size - 1] = n & MC; /* first byte */ for (let i = 1; i < size; i++) { n >>= NB; @@ -506,20 +573,20 @@ const packint = function(b, n, islittle, size, neg) { for (let i = SZINT; i < size; i++) /* correct extra bytes */ buff[islittle ? i : size - 1 - i] = MC; } - lauxlib.luaL_addsize(b, size); /* add result to buffer */ + luaL_addsize(b, size); /* add result to buffer */ }; const str_pack = function(L) { - let b = new lauxlib.luaL_Buffer(); + let b = new luaL_Buffer(); let h = new Header(L); let fmt = { - s: lauxlib.luaL_checkstring(L, 1), /* format string */ + s: luaL_checkstring(L, 1), /* format string */ off: 0 }; let arg = 1; /* current argument to pack */ let totalsize = 0; /* accumulate total size of result */ - lua.lua_pushnil(L); /* mark to separate arguments from string buffer */ - lauxlib.luaL_buffinit(L, b); + lua_pushnil(L); /* mark to separate arguments from string buffer */ + luaL_buffinit(L, b); while (fmt.off < fmt.s.length) { let details = getdetails(h, totalsize, fmt); let opt = details.opt; @@ -527,105 +594,124 @@ const str_pack = function(L) { let ntoalign = details.ntoalign; totalsize += ntoalign + size; while (ntoalign-- > 0) - lauxlib.luaL_addchar(b, LUAL_PACKPADBYTE); /* fill alignment */ + luaL_addchar(b, LUAL_PACKPADBYTE); /* fill alignment */ arg++; switch (opt) { - case KOption.Kint: { /* signed integers */ - let n = lauxlib.luaL_checkinteger(L, arg); + case Kint: { /* signed integers */ + let n = luaL_checkinteger(L, arg); if (size < SZINT) { /* need overflow check? */ let lim = 1 << (size * 8) - 1; - lauxlib.luaL_argcheck(L, -lim <= n && n < lim, arg, lua.to_luastring("integer overflow", true)); + luaL_argcheck(L, -lim <= n && n < lim, arg, to_luastring("integer overflow", true)); } packint(b, n, h.islittle, size, n < 0); break; } - case KOption.Kuint: { /* unsigned integers */ - let n = lauxlib.luaL_checkinteger(L, arg); + case Kuint: { /* unsigned integers */ + let n = luaL_checkinteger(L, arg); if (size < SZINT) - lauxlib.luaL_argcheck(L, (n>>>0) < (1 << (size * NB)), arg, lua.to_luastring("unsigned overflow", true)); + luaL_argcheck(L, (n>>>0) < (1 << (size * NB)), arg, to_luastring("unsigned overflow", true)); packint(b, n>>>0, h.islittle, size, false); break; } - case KOption.Kfloat: { /* floating-point options */ - let buff = lauxlib.luaL_prepbuffsize(b, size); - let n = lauxlib.luaL_checknumber(L, arg); /* get argument */ - let dv = new DataView(buff.buffer); + case Kfloat: { /* floating-point options */ + let buff = luaL_prepbuffsize(b, size); + let n = luaL_checknumber(L, arg); /* get argument */ + let dv = new DataView(buff.buffer, buff.byteOffset, buff.byteLength); if (size === 4) dv.setFloat32(0, n, h.islittle); else dv.setFloat64(0, n, h.islittle); - lauxlib.luaL_addsize(b, size); + luaL_addsize(b, size); break; } - case KOption.Kchar: { /* fixed-size string */ - let s = lauxlib.luaL_checkstring(L, arg); + case Kchar: { /* fixed-size string */ + let s = luaL_checkstring(L, arg); let len = s.length; - lauxlib.luaL_argcheck(L, len <= size, arg, lua.to_luastring("string longer than given size", true)); - lauxlib.luaL_addlstring(b, s, len); /* add string */ + luaL_argcheck(L, len <= size, arg, to_luastring("string longer than given size", true)); + luaL_addlstring(b, s, len); /* add string */ while (len++ < size) /* pad extra space */ - lauxlib.luaL_addchar(b, LUAL_PACKPADBYTE); + luaL_addchar(b, LUAL_PACKPADBYTE); break; } - case KOption.Kstring: { /* strings with length count */ - let s = lauxlib.luaL_checkstring(L, arg); + case Kstring: { /* strings with length count */ + let s = luaL_checkstring(L, arg); let len = s.length; - lauxlib.luaL_argcheck(L, + luaL_argcheck(L, size >= 4 /* sizeof(size_t) */ || len < (1 << (size * NB)), - arg, lua.to_luastring("string length does not fit in given size", true)); + arg, to_luastring("string length does not fit in given size", true)); packint(b, len, h.islittle, size, 0); /* pack length */ - lauxlib.luaL_addlstring(b, s, len); + luaL_addlstring(b, s, len); totalsize += len; break; } - case KOption.Kzstr: { /* zero-terminated string */ - let s = lauxlib.luaL_checkstring(L, arg); + case Kzstr: { /* zero-terminated string */ + let s = luaL_checkstring(L, arg); let len = s.length; - lauxlib.luaL_argcheck(L, s.indexOf(0) < 0, arg, lua.to_luastring("strings contains zeros", true)); - lauxlib.luaL_addlstring(b, s, len); - lauxlib.luaL_addchar(b, 0); /* add zero at the end */ + luaL_argcheck(L, luastring_indexOf(s, 0) < 0, arg, to_luastring("strings contains zeros", true)); + luaL_addlstring(b, s, len); + luaL_addchar(b, 0); /* add zero at the end */ totalsize += len + 1; break; } - case KOption.Kpadding: lauxlib.luaL_addchar(b, LUAL_PACKPADBYTE); /* fall through */ - case KOption.Kpaddalign: case KOption.Knop: + case Kpadding: luaL_addchar(b, LUAL_PACKPADBYTE); /* fall through */ + case Kpaddalign: case Knop: arg--; /* undo increment */ break; } } - lauxlib.luaL_pushresult(b); + luaL_pushresult(b); return 1; }; const str_reverse = function(L) { - lua.lua_pushstring(L, lauxlib.luaL_checkstring(L, 1).slice(0).reverse()); + let s = luaL_checkstring(L, 1); + let l = s.length; + let r = new Uint8Array(l); + for (let i=0; i<l; i++) + r[i] = s[l-1-i]; + lua_pushstring(L, r); return 1; }; const str_lower = function(L) { - let s = lauxlib.luaL_checkstring(L, 1); - // TODO: will fail on invalid UTF-8 - lua.lua_pushstring(L, lua.to_luastring(lua.to_jsstring(s).toLowerCase())); + let s = luaL_checkstring(L, 1); + let l = s.length; + let r = new Uint8Array(l); + for (let i=0; i<l; i++) { + let c = s[i]; + if (isupper(c)) + c = c | 0x20; + r[i] = c; + } + lua_pushstring(L, r); return 1; }; const str_upper = function(L) { - let s = lauxlib.luaL_checkstring(L, 1); - // TODO: will fail on invalid UTF-8 - lua.lua_pushstring(L, lua.to_luastring(lua.to_jsstring(s).toUpperCase())); + let s = luaL_checkstring(L, 1); + let l = s.length; + let r = new Uint8Array(l); + for (let i=0; i<l; i++) { + let c = s[i]; + if (islower(c)) + c = c & 0xdf; + r[i] = c; + } + lua_pushstring(L, r); return 1; }; const str_rep = function(L) { - let s = lauxlib.luaL_checkstring(L, 1); + let s = luaL_checkstring(L, 1); let l = s.length; - let n = lauxlib.luaL_checkinteger(L, 2); - let sep = lauxlib.luaL_optstring(L, 3, lua.to_luastring("")); + let n = luaL_checkinteger(L, 2); + let sep = luaL_optstring(L, 3, to_luastring("")); let lsep = sep.length; - if (n <= 0) lua.lua_pushliteral(L, ""); + if (n <= 0) lua_pushliteral(L, ""); else if (l + lsep < l || l + lsep > MAXSIZE / n) /* may overflow? */ - return lauxlib.luaL_error(L, lua.to_luastring("resulting string too large")); + return luaL_error(L, to_luastring("resulting string too large")); else { let totallen = n * l + (n - 1) * lsep; - let b = new lauxlib.luaL_Buffer(); - let p = lauxlib.luaL_buffinitsize(L, b, totallen); + let b = new luaL_Buffer(); + let p = luaL_buffinitsize(L, b, totallen); let pi = 0; while (n-- > 1) { /* first n-1 copies (followed by separator) */ p.set(s, pi); @@ -636,34 +722,34 @@ const str_rep = function(L) { } } p.set(s, pi); /* last copy (not followed by separator) */ - lauxlib.luaL_pushresultsize(b, totallen); + luaL_pushresultsize(b, totallen); } return 1; }; const str_byte = function(L) { - let s = lauxlib.luaL_checkstring(L, 1); + let s = luaL_checkstring(L, 1); let l = s.length; - let posi = posrelat(lauxlib.luaL_optinteger(L, 2, 1), l); - let pose = posrelat(lauxlib.luaL_optinteger(L, 3, posi), l); + let posi = posrelat(luaL_optinteger(L, 2, 1), l); + let pose = posrelat(luaL_optinteger(L, 3, posi), l); if (posi < 1) posi = 1; if (pose > l) pose = l; if (posi > pose) return 0; /* empty interval; return no values */ if (pose - posi >= Number.MAX_SAFE_INTEGER) /* arithmetic overflow? */ - return lauxlib.luaL_error(L, lua.to_luastring("string slice too long", true)); + return luaL_error(L, to_luastring("string slice too long", true)); let n = (pose - posi) + 1; - lauxlib.luaL_checkstack(L, n, lua.to_luastring("string slice too long", true)); + luaL_checkstack(L, n, to_luastring("string slice too long", true)); for (let i = 0; i < n; i++) - lua.lua_pushinteger(L, s[posi + i - 1]); + lua_pushinteger(L, s[posi + i - 1]); return n; }; const str_packsize = function(L) { let h = new Header(L); let fmt = { - s: lauxlib.luaL_checkstring(L, 1), + s: luaL_checkstring(L, 1), off: 0 }; let totalsize = 0; /* accumulate total size of result */ @@ -673,17 +759,17 @@ const str_packsize = function(L) { let size = details.size; let ntoalign = details.ntoalign; size += ntoalign; /* total space used by option */ - lauxlib.luaL_argcheck(L, totalsize <= MAXSIZE - size, 1, lua.to_luastring("format result too large", true)); + luaL_argcheck(L, totalsize <= MAXSIZE - size, 1, to_luastring("format result too large", true)); totalsize += size; switch (opt) { - case KOption.Kstring: /* strings with length count */ - case KOption.Kzstr: /* zero-terminated string */ - lauxlib.luaL_argerror(L, 1, lua.to_luastring("variable-length format", true)); + case Kstring: /* strings with length count */ + case Kzstr: /* zero-terminated string */ + luaL_argerror(L, 1, to_luastring("variable-length format", true)); /* call never return, but to avoid warnings: *//* fall through */ default: break; } } - lua.lua_pushinteger(L, totalsize); + lua_pushinteger(L, totalsize); return 1; }; @@ -711,14 +797,14 @@ const unpackint = function(L, str, islittle, size, issigned) { let mask = !issigned || res >= 0 ? 0 : MC; for (let i = limit; i < size; i++) { if (str[islittle ? i : size - 1 - i] !== mask) - lauxlib.luaL_error(L, lua.to_luastring("%d-byte integer does not fit into Lua Integer"), size); + luaL_error(L, to_luastring("%d-byte integer does not fit into Lua Integer"), size); } } return res; }; const unpacknum = function(L, b, islittle, size) { - assert(b.length >= size); + lualib.lua_assert(b.length >= size); let dv = new DataView(new ArrayBuffer(size)); for (let i = 0; i < size; i++) @@ -731,68 +817,69 @@ const unpacknum = function(L, b, islittle, size) { const str_unpack = function(L) { let h = new Header(L); let fmt = { - s: lauxlib.luaL_checkstring(L, 1), + s: luaL_checkstring(L, 1), off: 0 }; - let data = lauxlib.luaL_checkstring(L, 2); + let data = luaL_checkstring(L, 2); let ld = data.length; - let pos = posrelat(lauxlib.luaL_optinteger(L, 3, 1), ld) - 1; + let pos = posrelat(luaL_optinteger(L, 3, 1), ld) - 1; let n = 0; /* number of results */ - lauxlib.luaL_argcheck(L, pos <= ld && pos >= 0, 3, lua.to_luastring("initial position out of string", true)); + luaL_argcheck(L, pos <= ld && pos >= 0, 3, to_luastring("initial position out of string", true)); while (fmt.off < fmt.s.length) { let details = getdetails(h, pos, fmt); let opt = details.opt; let size = details.size; let ntoalign = details.ntoalign; if (/*ntoalign + size > ~pos ||*/ pos + ntoalign + size > ld) - lauxlib.luaL_argerror(L, 2, lua.to_luastring("data string too short", true)); + luaL_argerror(L, 2, to_luastring("data string too short", true)); pos += ntoalign; /* skip alignment */ /* stack space for item + next position */ - lauxlib.luaL_checkstack(L, 2, lua.to_luastring("too many results", true)); + luaL_checkstack(L, 2, to_luastring("too many results", true)); n++; switch (opt) { - case KOption.Kint: - case KOption.Kuint: { - let res = unpackint(L, data.slice(pos), h.islittle, size, opt === KOption.Kint); - lua.lua_pushinteger(L, res); + case Kint: + case Kuint: { + let res = unpackint(L, data.subarray(pos), h.islittle, size, opt === Kint); + lua_pushinteger(L, res); break; } - case KOption.Kfloat: { - let res = unpacknum(L, data.slice(pos), h.islittle, size); - lua.lua_pushnumber(L, res); + case Kfloat: { + let res = unpacknum(L, data.subarray(pos), h.islittle, size); + lua_pushnumber(L, res); break; } - case KOption.Kchar: { - lua.lua_pushstring(L, data.slice(pos, pos + size)); + case Kchar: { + lua_pushstring(L, data.subarray(pos, pos + size)); break; } - case KOption.Kstring: { - let len = unpackint(L, data.slice(pos), h.islittle, size, 0); - lauxlib.luaL_argcheck(L, pos + len + size <= ld, 2, lua.to_luastring("data string too short", true)); - lua.lua_pushstring(L, data.slice(pos + size, pos + size + len)); + case Kstring: { + let len = unpackint(L, data.subarray(pos), h.islittle, size, 0); + luaL_argcheck(L, pos + len + size <= ld, 2, to_luastring("data string too short", true)); + lua_pushstring(L, data.subarray(pos + size, pos + size + len)); pos += len; /* skip string */ break; } - case KOption.Kzstr: { - let len = data.slice(pos).indexOf(0); - lua.lua_pushstring(L, data.slice(pos, pos + len)); - pos += len + 1; /* skip string plus final '\0' */ + case Kzstr: { + let e = luastring_indexOf(data, 0, pos); + if (e === -1) e = data.length - pos; + lua_pushstring(L, data.subarray(pos, e)); + pos = e + 1; /* skip string plus final '\0' */ break; } - case KOption.Kpaddalign: case KOption.Kpadding: case KOption.Knop: + case Kpaddalign: case Kpadding: case Knop: n--; /* undo increment */ break; } pos += size; } - lua.lua_pushinteger(L, pos + 1); /* next position */ + lua_pushinteger(L, pos + 1); /* next position */ return n + 1; }; const CAP_UNFINISHED = -1; const CAP_POSITION = -2; const MAXCCALLS = 200; -const SPECIALS = ["^".charCodeAt(0), "$".charCodeAt(0), "*".charCodeAt(0), "+".charCodeAt(0), "?".charCodeAt(0), ".".charCodeAt(0), "(".charCodeAt(0), "[".charCodeAt(0), "%".charCodeAt(0), "-".charCodeAt(0)]; +const SPECIALS = to_luastring("^$*+?.([%-"); class MatchState { constructor(L) { @@ -809,9 +896,9 @@ class MatchState { } const check_capture = function(ms, l) { - l = l - '1'.charCodeAt(0); + l = l - 49 /* '1'.charCodeAt(0) */; if (l < 0 || l >= ms.level || ms.capture[l].len === CAP_UNFINISHED) - return lauxlib.luaL_error(ms.L, lua.to_luastring("invalid capture index %%%d"), l + 1); + return luaL_error(ms.L, to_luastring("invalid capture index %%%d"), l + 1); return l; }; @@ -819,24 +906,24 @@ const capture_to_close = function(ms) { let level = ms.level; for (level--; level >= 0; level--) if (ms.capture[level].len === CAP_UNFINISHED) return level; - return lauxlib.luaL_error(ms.L, lua.to_luastring("invalid pattern capture")); + return luaL_error(ms.L, to_luastring("invalid pattern capture")); }; const classend = function(ms, p) { switch(ms.p[p++]) { case L_ESC: { if (p === ms.p_end) - lauxlib.luaL_error(ms.L, lua.to_luastring("malformed pattern (ends with '%%')")); + luaL_error(ms.L, to_luastring("malformed pattern (ends with '%%')")); return p + 1; } - case '['.charCodeAt(0): { - if (ms.p[p] === '^'.charCodeAt(0)) p++; + case 91 /* '['.charCodeAt(0) */: { + if (ms.p[p] === 94 /* '^'.charCodeAt(0) */) p++; do { /* look for a ']' */ if (p === ms.p_end) - lauxlib.luaL_error(ms.L, lua.to_luastring("malformed pattern (missing ']')")); + luaL_error(ms.L, to_luastring("malformed pattern (missing ']')")); if (ms.p[p++] === L_ESC && p < ms.p_end) p++; /* skip escapes (e.g. '%]') */ - } while (ms.p[p] !== ']'.charCodeAt(0)); + } while (ms.p[p] !== 93 /* ']'.charCodeAt(0) */); return p + 1; } default: { @@ -846,27 +933,36 @@ const classend = function(ms, p) { }; const match_class = function(c, cl) { - let res; - switch (String.fromCharCode(cl).toLowerCase().charCodeAt(0)) { - case 'a'.charCodeAt(0) : res = isalpha(c); break; - case 'c'.charCodeAt(0) : res = iscntrl(c); break; - case 'd'.charCodeAt(0) : res = isdigit(c); break; - case 'g'.charCodeAt(0) : res = isgraph(c); break; - case 'l'.charCodeAt(0) : res = islower(c); break; - case 'p'.charCodeAt(0) : res = ispunct(c); break; - case 's'.charCodeAt(0) : res = isspace(c); break; - case 'u'.charCodeAt(0) : res = isupper(c); break; - case 'w'.charCodeAt(0) : res = isalnum(c); break; - case 'x'.charCodeAt(0) : res = isxdigit(c); break; - case 'z'.charCodeAt(0) : res = (c === 0); break; /* deprecated option */ + switch (cl) { + case 97 /* 'a'.charCodeAt(0) */: return isalpha(c); + case 65 /* 'A'.charCodeAt(0) */: return !isalpha(c); + case 99 /* 'c'.charCodeAt(0) */: return iscntrl(c); + case 67 /* 'C'.charCodeAt(0) */: return !iscntrl(c); + case 100 /* 'd'.charCodeAt(0) */: return isdigit(c); + case 68 /* 'D'.charCodeAt(0) */: return !isdigit(c); + case 103 /* 'g'.charCodeAt(0) */: return isgraph(c); + case 71 /* 'G'.charCodeAt(0) */: return !isgraph(c); + case 108 /* 'l'.charCodeAt(0) */: return islower(c); + case 76 /* 'L'.charCodeAt(0) */: return !islower(c); + case 112 /* 'p'.charCodeAt(0) */: return ispunct(c); + case 80 /* 'P'.charCodeAt(0) */: return !ispunct(c); + case 115 /* 's'.charCodeAt(0) */: return isspace(c); + case 83 /* 'S'.charCodeAt(0) */: return !isspace(c); + case 117 /* 'u'.charCodeAt(0) */: return isupper(c); + case 85 /* 'U'.charCodeAt(0) */: return !isupper(c); + case 119 /* 'w'.charCodeAt(0) */: return isalnum(c); + case 87 /* 'W'.charCodeAt(0) */: return !isalnum(c); + case 120 /* 'x'.charCodeAt(0) */: return isxdigit(c); + case 88 /* 'X'.charCodeAt(0) */: return !isxdigit(c); + case 122 /* 'z'.charCodeAt(0) */: return (c === 0); /* deprecated option */ + case 90 /* 'z'.charCodeAt(0) */: return (c !== 0); /* deprecated option */ default: return (cl === c); } - return (islower(cl) ? res : !res); }; const matchbracketclass = function(ms, c, p, ec) { let sig = true; - if (ms.p[p + 1] === '^'.charCodeAt(0)) { + if (ms.p[p + 1] === 94 /* '^'.charCodeAt(0) */) { sig = false; p++; /* skip the '^' */ } @@ -875,7 +971,7 @@ const matchbracketclass = function(ms, c, p, ec) { p++; if (match_class(c, ms.p[p])) return sig; - } else if (ms.p[p + 1] === '-'.charCodeAt(0) && p + 2 < ec) { + } else if (ms.p[p + 1] === 45 /* '-'.charCodeAt(0) */ && p + 2 < ec) { p += 2; if (ms.p[p - 2] <= c && c <= ms.p[p]) return sig; @@ -890,9 +986,9 @@ const singlematch = function(ms, s, p, ep) { else { let c = ms.src[s]; switch (ms.p[p]) { - case '.'.charCodeAt(0): return true; /* matches any char */ + case 46 /* '.'.charCodeAt(0) */: return true; /* matches any char */ case L_ESC: return match_class(c, ms.p[p + 1]); - case '['.charCodeAt(0): return matchbracketclass(ms, c, p, ep - 1); + case 91 /* '['.charCodeAt(0) */: return matchbracketclass(ms, c, p, ep - 1); default: return ms.p[p] === c; } } @@ -900,7 +996,7 @@ const singlematch = function(ms, s, p, ep) { const matchbalance = function(ms, s, p) { if (p >= ms.p_end - 1) - lauxlib.luaL_error(ms.L, lua.to_luastring("malformed pattern (missing arguments to '%%b'")); + luaL_error(ms.L, to_luastring("malformed pattern (missing arguments to '%%b'")); if (ms.src[s] !== ms.p[p]) return null; else { @@ -943,7 +1039,7 @@ const min_expand = function(ms, s, p, ep) { const start_capture = function(ms, s, p, what) { let level = ms.level; - if (level >= LUA_MAXCAPTURES) lauxlib.luaL_error(ms.L, lua.to_luastring("too many captures", true)); + if (level >= LUA_MAXCAPTURES) luaL_error(ms.L, to_luastring("too many captures", true)); ms.capture[level] = ms.capture[level] ? ms.capture[level] : {}; ms.capture[level].init = s; ms.capture[level].len = what; @@ -969,7 +1065,7 @@ const array_cmp = function(a, ai, b, bi, len) { return true; let aj = ai+len; loop: for (;;) { - ai = a.indexOf(b[bi], ai); + ai = luastring_indexOf(a, b[bi], ai); if (ai === -1 || ai >= aj) return false; for (let j = 1; j < len; j++) { @@ -995,24 +1091,24 @@ const match = function(ms, s, p) { let gotoinit = true; if (ms.matchdepth-- === 0) - lauxlib.luaL_error(ms.L, lua.to_luastring("pattern too complex", true)); + luaL_error(ms.L, to_luastring("pattern too complex", true)); while (gotoinit || gotodefault) { gotoinit = false; if (p !== ms.p_end) { /* end of pattern? */ - switch (gotodefault ? 'x'.charCodeAt(0) : ms.p[p]) { - case '('.charCodeAt(0): { /* start capture */ - if (ms.p[p + 1] === ')'.charCodeAt(0)) /* position capture? */ + switch (gotodefault ? void 0 : ms.p[p]) { + case 40 /* '('.charCodeAt(0) */: { /* start capture */ + if (ms.p[p + 1] === 41 /* ')'.charCodeAt(0) */) /* position capture? */ s = start_capture(ms, s, p + 2, CAP_POSITION); else s = start_capture(ms, s, p + 1, CAP_UNFINISHED); break; } - case ')'.charCodeAt(0): { /* end capture */ + case 41 /* ')'.charCodeAt(0) */: { /* end capture */ s = end_capture(ms, s, p + 1); break; } - case '$'.charCodeAt(0): { + case 36 /* '$'.charCodeAt(0) */: { if (p + 1 !== ms.p_end) { /* is the '$' the last char in pattern? */ gotodefault = true; /* no; go to default */ break; @@ -1022,7 +1118,7 @@ const match = function(ms, s, p) { } case L_ESC: { /* escaped sequences not in the format class[*+?-]? */ switch (ms.p[p + 1]) { - case 'b'.charCodeAt(0): { /* balanced string? */ + case 98 /* 'b'.charCodeAt(0) */: { /* balanced string? */ s = matchbalance(ms, s, p + 2); if (s !== null) { p += 4; @@ -1030,10 +1126,10 @@ const match = function(ms, s, p) { } break; } - case 'f'.charCodeAt(0): { /* frontier? */ + case 102 /* 'f'.charCodeAt(0) */: { /* frontier? */ p += 2; - if (ms.p[p] !== '['.charCodeAt(0)) - lauxlib.luaL_error(ms.L, lua.to_luastring("missing '[' after '%%f' in pattern")); + if (ms.p[p] !== 91 /* '['.charCodeAt(0) */) + luaL_error(ms.L, to_luastring("missing '[' after '%%f' in pattern")); let ep = classend(ms, p); /* points to what is next */ let previous = s === ms.src_init ? 0 : ms.src[s-1]; if (!matchbracketclass(ms, previous, p, ep - 1) && matchbracketclass(ms, (s===ms.src_end)?0:ms.src[s], p, ep - 1)) { @@ -1042,9 +1138,8 @@ const match = function(ms, s, p) { s = null; /* match failed */ break; } - case '0'.charCodeAt(0): case '1'.charCodeAt(0): case '2'.charCodeAt(0): case '3'.charCodeAt(0): - case '4'.charCodeAt(0): case '5'.charCodeAt(0): case '6'.charCodeAt(0): case '7'.charCodeAt(0): - case '8'.charCodeAt(0): case '9'.charCodeAt(0): { /* capture results (%0-%9)? */ + case 48: case 49: case 50: case 51: case 52: + case 53: case 54: case 55: case 56: case 57: { /* capture results (%0-%9)? */ s = match_capture(ms, s, ms.p[p + 1]); if (s !== null) { p += 2; gotoinit = true; @@ -1060,13 +1155,16 @@ const match = function(ms, s, p) { let ep = classend(ms, p); /* points to optional suffix */ /* does not match at least once? */ if (!singlematch(ms, s, p, ep)) { - if (ms.p[ep] === '*'.charCodeAt(0) || ms.p[ep] === '?'.charCodeAt(0) || ms.p[ep] === '-'.charCodeAt(0)) { /* accept empty? */ + if (ms.p[ep] === 42 /* '*'.charCodeAt(0) */ || + ms.p[ep] === 63 /* '?'.charCodeAt(0) */ || + ms.p[ep] === 45 /* '-'.charCodeAt(0) */ + ) { /* accept empty? */ p = ep + 1; gotoinit = true; break; } else /* '+' or no suffix */ s = null; /* fail */ } else { /* matched once */ switch (ms.p[ep]) { /* handle optional suffix */ - case '?'.charCodeAt(0): { /* optional */ + case 63 /* '?'.charCodeAt(0) */: { /* optional */ let res; if ((res = match(ms, s + 1, ep + 1)) !== null) s = res; @@ -1075,13 +1173,13 @@ const match = function(ms, s, p) { } break; } - case '+'.charCodeAt(0): /* 1 or more repetitions */ + case 43 /* '+'.charCodeAt(0) */: /* 1 or more repetitions */ s++; /* 1 match already done */ /* fall through */ - case '*'.charCodeAt(0): /* 0 or more repetitions */ + case 42 /* '*'.charCodeAt(0) */: /* 0 or more repetitions */ s = max_expand(ms, s, p, ep); break; - case '-'.charCodeAt(0): /* 0 or more repetitions (minimum) */ + case 45 /* '-'.charCodeAt(0) */: /* 0 or more repetitions (minimum) */ s = min_expand(ms, s, p, ep); break; default: /* no suffix */ @@ -1100,22 +1198,22 @@ const match = function(ms, s, p) { const push_onecapture = function(ms, i, s, e) { if (i >= ms.level) { if (i === 0) - lua.lua_pushlstring(ms.L, ms.src.slice(s, e), e - s); /* add whole match */ + lua_pushlstring(ms.L, ms.src.subarray(s, e), e - s); /* add whole match */ else - lauxlib.luaL_error(ms.L, lua.to_luastring("invalid capture index %%%d"), i + 1); + luaL_error(ms.L, to_luastring("invalid capture index %%%d"), i + 1); } else { let l = ms.capture[i].len; - if (l === CAP_UNFINISHED) lauxlib.luaL_error(ms.L, lua.to_luastring("unfinished capture", true)); + if (l === CAP_UNFINISHED) luaL_error(ms.L, to_luastring("unfinished capture", true)); if (l === CAP_POSITION) - lua.lua_pushinteger(ms.L, ms.capture[i].init - ms.src_init + 1); + lua_pushinteger(ms.L, ms.capture[i].init - ms.src_init + 1); else - lua.lua_pushlstring(ms.L, ms.src.slice(ms.capture[i].init), l); + lua_pushlstring(ms.L, ms.src.subarray(ms.capture[i].init), l); } }; const push_captures = function(ms, s, e) { - let nlevels = ms.level === 0 && ms.src.slice(s) ? 1 : ms.level; - lauxlib.luaL_checkstack(ms.L, nlevels, lua.to_luastring("too many catpures", true)); + let nlevels = ms.level === 0 && ms.src.subarray(s) ? 1 : ms.level; + luaL_checkstack(ms.L, nlevels, to_luastring("too many catpures", true)); for (let i = 0; i < nlevels; i++) push_onecapture(ms, i, s, e); return nlevels; /* number of strings pushed */ @@ -1123,7 +1221,7 @@ const push_captures = function(ms, s, e) { const nospecials = function(p, l) { for (let i=0; i<l; i++) { - if (SPECIALS.indexOf(p[i]) !== -1) + if (luastring_indexOf(SPECIALS, p[i]) !== -1) return false; } return true; @@ -1141,7 +1239,7 @@ const prepstate = function(ms, L, s, ls, p, lp) { const reprepstate = function(ms) { ms.level = 0; - assert(ms.matchdepth === MAXCCALLS); + lualib.lua_assert(ms.matchdepth === MAXCCALLS); }; const find_subarray = function(arr, subarr, from_index) { @@ -1166,31 +1264,31 @@ const find_subarray = function(arr, subarr, from_index) { }; const str_find_aux = function(L, find) { - let s = lauxlib.luaL_checkstring(L, 1); - let p = lauxlib.luaL_checkstring(L, 2); + let s = luaL_checkstring(L, 1); + let p = luaL_checkstring(L, 2); let ls = s.length; let lp = p.length; - let init = posrelat(lauxlib.luaL_optinteger(L, 3, 1), ls); + let init = posrelat(luaL_optinteger(L, 3, 1), ls); if (init < 1) init = 1; else if (init > ls + 1) { /* start after string's end? */ - lua.lua_pushnil(L); /* cannot find anything */ + lua_pushnil(L); /* cannot find anything */ return 1; } /* explicit request or no special characters? */ - if (find && (lua.lua_toboolean(L, 4) || nospecials(p, lp))) { + if (find && (lua_toboolean(L, 4) || nospecials(p, lp))) { /* do a plain search */ - let f = find_subarray(s.slice(init - 1), p, 0); + let f = find_subarray(s.subarray(init - 1), p, 0); if (f > -1) { - lua.lua_pushinteger(L, init + f); - lua.lua_pushinteger(L, init + f + lp - 1); + lua_pushinteger(L, init + f); + lua_pushinteger(L, init + f + lp - 1); return 2; } } else { let ms = new MatchState(L); let s1 = init - 1; - let anchor = p[0] === '^'.charCodeAt(0); + let anchor = p[0] === 94 /* '^'.charCodeAt(0) */; if (anchor) { - p = p.slice(1); lp--; /* skip anchor character */ + p = p.subarray(1); lp--; /* skip anchor character */ } prepstate(ms, L, s, ls, p, lp); do { @@ -1198,15 +1296,15 @@ const str_find_aux = function(L, find) { reprepstate(ms); if ((res = match(ms, s1, 0)) !== null) { if (find) { - lua.lua_pushinteger(L, s1 + 1); /* start */ - lua.lua_pushinteger(L, res); /* end */ + lua_pushinteger(L, s1 + 1); /* start */ + lua_pushinteger(L, res); /* end */ return push_captures(ms, null, 0) + 2; } else return push_captures(ms, s1, res); } } while (s1++ < ms.src_end && !anchor); } - lua.lua_pushnil(L); /* not found */ + lua_pushnil(L); /* not found */ return 1; }; @@ -1229,7 +1327,7 @@ class GMatchState { } const gmatch_aux = function(L) { - let gm = lua.lua_touserdata(L, lua.lua_upvalueindex(3)); + let gm = lua_touserdata(L, lua_upvalueindex(3)); gm.ms.L = L; for (let src = gm.src; src <= gm.ms.src_end; src++) { reprepstate(gm.ms); @@ -1243,41 +1341,41 @@ const gmatch_aux = function(L) { }; const str_gmatch = function(L) { - let s = lauxlib.luaL_checkstring(L, 1); - let p = lauxlib.luaL_checkstring(L, 2); + let s = luaL_checkstring(L, 1); + let p = luaL_checkstring(L, 2); let ls = s.length; let lp = p.length; - lua.lua_settop(L, 2); /* keep them on closure to avoid being collected */ + lua_settop(L, 2); /* keep them on closure to avoid being collected */ let gm = new GMatchState(); - lua.lua_pushlightuserdata(L, gm); + lua_pushlightuserdata(L, gm); prepstate(gm.ms, L, s, ls, p, lp); gm.src = 0; gm.p = 0; gm.lastmatch = null; - lua.lua_pushcclosure(L, gmatch_aux, 3); + lua_pushcclosure(L, gmatch_aux, 3); return 1; }; const add_s = function(ms, b, s, e) { let L = ms.L; - let news = lua.lua_tostring(L, 3); + let news = lua_tostring(L, 3); let l = news.length; for (let i = 0; i < l; i++) { if (news[i] !== L_ESC) - lauxlib.luaL_addchar(b, news[i]); + luaL_addchar(b, news[i]); else { i++; /* skip ESC */ if (!isdigit(news[i])) { if (news[i] !== L_ESC) - lauxlib.luaL_error(L, lua.to_luastring("invalid use of '%c' in replacement string"), L_ESC); - lauxlib.luaL_addchar(b, news[i]); - } else if (news[i] === '0'.charCodeAt(0)) - lauxlib.luaL_addlstring(b, ms.src.slice(s), e - s); + luaL_error(L, to_luastring("invalid use of '%c' in replacement string"), L_ESC); + luaL_addchar(b, news[i]); + } else if (news[i] === 48 /* '0'.charCodeAt(0) */) + luaL_addlstring(b, ms.src.subarray(s, e), e - s); else { - push_onecapture(ms, news[i] - '1'.charCodeAt(0), s, e); - lauxlib.luaL_tolstring(L, -1); - lua.lua_remove(L, -2); /* remove original value */ - lauxlib.luaL_addvalue(b); /* add capture to accumulated result */ + push_onecapture(ms, news[i] - 49 /* '1'.charCodeAt(0) */, s, e); + luaL_tolstring(L, -1); + lua_remove(L, -2); /* remove original value */ + luaL_addvalue(b); /* add capture to accumulated result */ } } } @@ -1286,15 +1384,15 @@ const add_s = function(ms, b, s, e) { const add_value = function(ms, b, s, e, tr) { let L = ms.L; switch (tr) { - case lua.LUA_TFUNCTION: { - lua.lua_pushvalue(L, 3); + case LUA_TFUNCTION: { + lua_pushvalue(L, 3); let n = push_captures(ms, s, e); - lua.lua_call(L, n, 1); + lua_call(L, n, 1); break; } - case lua.LUA_TTABLE: { + case LUA_TTABLE: { push_onecapture(ms, 0, s, e); - lua.lua_gettable(L, 3); + lua_gettable(L, 3); break; } default: { /* LUA_TNUMBER or LUA_TSTRING */ @@ -1302,31 +1400,31 @@ const add_value = function(ms, b, s, e, tr) { return; } } - if (!lua.lua_toboolean(L, -1)) { /* nil or false? */ - lua.lua_pop(L, 1); - lua.lua_pushlstring(L, ms.src.slice(s, e), e - s); /* keep original text */ - } else if (!lua.lua_isstring(L, -1)) - lauxlib.luaL_error(L, lua.to_luastring("invalid replacement value (a %s)"), lauxlib.luaL_typename(L, -1)); - lauxlib.luaL_addvalue(b); /* add result to accumulator */ + if (!lua_toboolean(L, -1)) { /* nil or false? */ + lua_pop(L, 1); + lua_pushlstring(L, ms.src.subarray(s, e), e - s); /* keep original text */ + } else if (!lua_isstring(L, -1)) + luaL_error(L, to_luastring("invalid replacement value (a %s)"), luaL_typename(L, -1)); + luaL_addvalue(b); /* add result to accumulator */ }; const str_gsub = function(L) { - let src = lauxlib.luaL_checkstring(L, 1); /* subject */ + let src = luaL_checkstring(L, 1); /* subject */ let srcl = src.length; - let p = lauxlib.luaL_checkstring(L, 2); /* pattern */ + let p = luaL_checkstring(L, 2); /* pattern */ let lp = p.length; let lastmatch = null; /* end of last match */ - let tr = lua.lua_type(L, 3); /* replacement type */ - let max_s = lauxlib.luaL_optinteger(L, 4, srcl + 1); /* max replacements */ - let anchor = p[0] === '^'.charCodeAt(0); + let tr = lua_type(L, 3); /* replacement type */ + let max_s = luaL_optinteger(L, 4, srcl + 1); /* max replacements */ + let anchor = p[0] === 94 /* '^'.charCodeAt(0) */; let n = 0; /* replacement count */ let ms = new MatchState(L); - let b = new lauxlib.luaL_Buffer(); - lauxlib.luaL_argcheck(L, tr === lua.LUA_TNUMBER || tr === lua.LUA_TSTRING || tr === lua.LUA_TFUNCTION || tr === lua.LUA_TTABLE, 3, - lua.to_luastring("string/function/table expected", true)); - lauxlib.luaL_buffinit(L, b); + let b = new luaL_Buffer(); + luaL_argcheck(L, tr === LUA_TNUMBER || tr === LUA_TSTRING || tr === LUA_TFUNCTION || tr === LUA_TTABLE, 3, + to_luastring("string/function/table expected", true)); + luaL_buffinit(L, b); if (anchor) { - p = p.slice(1); lp--; /* skip anchor character */ + p = p.subarray(1); lp--; /* skip anchor character */ } prepstate(ms, L, src, srcl, p, lp); src = 0; p = 0; @@ -1338,13 +1436,13 @@ const str_gsub = function(L) { add_value(ms, b, src, e, tr); /* add replacement to buffer */ src = lastmatch = e; } else if (src < ms.src_end) /* otherwise, skip one character */ - lauxlib.luaL_addchar(b, ms.src[src++]); + luaL_addchar(b, ms.src[src++]); else break; /* end of subject */ if (anchor) break; } - lauxlib.luaL_addlstring(b, ms.src.slice(src), ms.src_end - src); - lauxlib.luaL_pushresult(b); - lua.lua_pushinteger(L, n); /* number of substitutions */ + luaL_addlstring(b, ms.src.subarray(src, ms.src_end), ms.src_end - src); + luaL_pushresult(b); + lua_pushinteger(L, n); /* number of substitutions */ return 2; }; @@ -1369,18 +1467,18 @@ const strlib = { }; const createmetatable = function(L) { - lua.lua_createtable(L, 0, 1); /* table to be metatable for strings */ - lua.lua_pushliteral(L, ""); /* dummy string */ - lua.lua_pushvalue(L, -2); /* copy table */ - lua.lua_setmetatable(L, -2); /* set table as metatable for strings */ - lua.lua_pop(L, 1); /* pop dummy string */ - lua.lua_pushvalue(L, -2); /* get string library */ - lua.lua_setfield(L, -2, lua.to_luastring("__index", true)); /* metatable.__index = string */ - lua.lua_pop(L, 1); /* pop metatable */ + lua_createtable(L, 0, 1); /* table to be metatable for strings */ + lua_pushliteral(L, ""); /* dummy string */ + lua_pushvalue(L, -2); /* copy table */ + lua_setmetatable(L, -2); /* set table as metatable for strings */ + lua_pop(L, 1); /* pop dummy string */ + lua_pushvalue(L, -2); /* get string library */ + lua_setfield(L, -2, to_luastring("__index", true)); /* metatable.__index = string */ + lua_pop(L, 1); /* pop metatable */ }; const luaopen_string = function(L) { - lauxlib.luaL_newlib(L, strlib); + luaL_newlib(L, strlib); createmetatable(L); return 1; }; diff --git a/src/ltable.js b/src/ltable.js index cf8b1da..d5ae6e6 100644 --- a/src/ltable.js +++ b/src/ltable.js @@ -1,13 +1,31 @@ "use strict"; -const assert = require('assert'); - -const defs = require('./defs.js'); +const { + constant_types: { + LUA_TBOOLEAN, + LUA_TCCL, + LUA_TLCF, + LUA_TLCL, + LUA_TLIGHTUSERDATA, + LUA_TLNGSTR, + LUA_TNIL, + LUA_TNUMFLT, + LUA_TNUMINT, + LUA_TSHRSTR, + LUA_TTABLE, + LUA_TTHREAD, + LUA_TUSERDATA + }, + to_luastring +} = require('./defs.js'); +const { lua_assert } = require('./llimits.js'); const ldebug = require('./ldebug.js'); const lobject = require('./lobject.js'); -const lstring = require('./lstring.js'); +const { + luaS_hashlongstr, + TString +} = require('./lstring.js'); const lstate = require('./lstate.js'); -const CT = defs.constant_types; /* used to prevent conflicts with lightuserdata keys */ let lightuserdata_hashes = new WeakMap(); @@ -24,25 +42,25 @@ const get_lightuserdata_hash = function(v) { const table_hash = function(L, key) { switch(key.type) { - case CT.LUA_TNIL: - return ldebug.luaG_runerror(L, defs.to_luastring("table index is nil", true)); - case CT.LUA_TNUMFLT: + case LUA_TNIL: + return ldebug.luaG_runerror(L, to_luastring("table index is nil", true)); + case LUA_TNUMFLT: if (isNaN(key.value)) - return ldebug.luaG_runerror(L, defs.to_luastring("table index is NaN", true)); + return ldebug.luaG_runerror(L, to_luastring("table index is NaN", true)); /* fall through */ - case CT.LUA_TNUMINT: /* takes advantage of floats and integers being same in JS */ - case CT.LUA_TBOOLEAN: - case CT.LUA_TTABLE: - case CT.LUA_TLCL: - case CT.LUA_TLCF: - case CT.LUA_TCCL: - case CT.LUA_TUSERDATA: - case CT.LUA_TTHREAD: + case LUA_TNUMINT: /* takes advantage of floats and integers being same in JS */ + case LUA_TBOOLEAN: + case LUA_TTABLE: + case LUA_TLCL: + case LUA_TLCF: + case LUA_TCCL: + case LUA_TUSERDATA: + case LUA_TTHREAD: return key.value; - case CT.LUA_TSHRSTR: - case CT.LUA_TLNGSTR: - return lstring.luaS_hashlongstr(key.tsvalue()); - case CT.LUA_TLIGHTUSERDATA: { + case LUA_TSHRSTR: + case LUA_TLNGSTR: + return luaS_hashlongstr(key.tsvalue()); + case LUA_TLIGHTUSERDATA: { let v = key.value; switch(typeof v) { case "string": @@ -151,17 +169,17 @@ const getgeneric = function(t, hash) { }; const luaH_getint = function(t, key) { - assert(typeof key == "number" && (key|0) === key); + lua_assert(typeof key == "number" && (key|0) === key); return getgeneric(t, key); }; const luaH_getstr = function(t, key) { - assert(key instanceof lstring.TString); - return getgeneric(t, lstring.luaS_hashlongstr(key)); + lua_assert(key instanceof TString); + return getgeneric(t, luaS_hashlongstr(key)); }; const luaH_get = function(L, t, key) { - assert(key instanceof lobject.TValue); + lua_assert(key instanceof lobject.TValue); if (key.ttisnil() || (key.ttisfloat() && isNaN(key.value))) return lobject.luaO_nilobject; return getgeneric(t, table_hash(L, key)); @@ -175,17 +193,17 @@ const setgeneric = function(t, hash, key) { let kv = key.value; if ((key.ttisfloat() && (kv|0) === kv)) { /* does index fit in an integer? */ /* insert it as an integer */ - key = new lobject.TValue(CT.LUA_TNUMINT, kv); + key = new lobject.TValue(LUA_TNUMINT, kv); } else { key = new lobject.TValue(key.type, kv); } - let tv = new lobject.TValue(CT.LUA_TNIL, null); + let tv = new lobject.TValue(LUA_TNIL, null); add(t, hash, key, tv); return tv; }; const luaH_setint = function(t, key, value) { - assert(typeof key == "number" && (key|0) === key && value instanceof lobject.TValue); + lua_assert(typeof key == "number" && (key|0) === key && value instanceof lobject.TValue); let hash = key; /* table_hash known result */ if (value.ttisnil()) { mark_dead(t, hash); @@ -196,20 +214,20 @@ const luaH_setint = function(t, key, value) { let tv = v.value; tv.setfrom(value); } else { - let k = new lobject.TValue(CT.LUA_TNUMINT, key); + let k = new lobject.TValue(LUA_TNUMINT, key); let v = new lobject.TValue(value.type, value.value); add(t, hash, k, v); } }; const luaH_set = function(L, t, key) { - assert(key instanceof lobject.TValue); + lua_assert(key instanceof lobject.TValue); let hash = table_hash(L, key); return setgeneric(t, hash, key); }; const luaH_delete = function(L, t, key) { - assert(key instanceof lobject.TValue); + lua_assert(key instanceof lobject.TValue); let hash = table_hash(L, key); return mark_dead(t, hash); }; @@ -234,7 +252,7 @@ const luaH_next = function(L, table, keyI) { let keyO = L.stack[keyI]; let entry; - if (keyO.type === CT.LUA_TNIL) { + if (keyO.type === LUA_TNIL) { entry = table.f; if (!entry) return false; @@ -252,7 +270,7 @@ const luaH_next = function(L, table, keyI) { entry = (table.dead_weak && table.dead_weak.get(hash)) || table.dead_strong.get(hash); if (!entry) /* item not in table */ - return ldebug.luaG_runerror(L, defs.to_luastring("invalid key to 'next'")); + return ldebug.luaG_runerror(L, to_luastring("invalid key to 'next'")); /* Iterate until either out of keys, or until finding a non-dead key */ do { entry = entry.n; diff --git a/src/ltablib.js b/src/ltablib.js index 70ff595..6f408da 100644 --- a/src/ltablib.js +++ b/src/ltablib.js @@ -1,11 +1,54 @@ "use strict"; -const assert = require('assert'); - -const lua = require('./lua.js'); -const lauxlib = require('./lauxlib.js'); -const luaconf = require('./luaconf.js'); - +const { LUA_MAXINTEGER } = require('./luaconf.js'); +const { + LUA_OPEQ, + LUA_OPLT, + LUA_TFUNCTION, + LUA_TNIL, + LUA_TTABLE, + lua_call, + lua_checkstack, + lua_compare, + lua_createtable, + lua_geti, + lua_getmetatable, + lua_gettop, + lua_insert, + lua_isnil, + lua_isnoneornil, + lua_isstring, + lua_pop, + lua_pushinteger, + lua_pushnil, + lua_pushstring, + lua_pushvalue, + lua_rawget, + lua_setfield, + lua_seti, + lua_settop, + lua_toboolean, + lua_type +} = require('./lua.js'); +const { + luaL_Buffer, + luaL_addlstring, + luaL_addvalue, + luaL_argcheck, + luaL_buffinit, + luaL_checkinteger, + luaL_checktype, + luaL_error, + luaL_len, + luaL_newlib, + luaL_opt, + luaL_optinteger, + luaL_optlstring, + luaL_pushresult, + luaL_typename +} = require('./lauxlib.js'); +const lualib = require('./lualib.js'); +const { to_luastring } = require("./fengaricore.js"); /* ** Operations that an object must define to mimic a table @@ -17,8 +60,8 @@ const TAB_L = 4; /* length */ const TAB_RW = (TAB_R | TAB_W); /* read/write */ const checkfield = function(L, key, n) { - lua.lua_pushstring(L, key); - return lua.lua_rawget(L, -n) !== lua.LUA_TNIL; + lua_pushstring(L, key); + return lua_rawget(L, -n) !== LUA_TNIL; }; /* @@ -26,70 +69,70 @@ const checkfield = function(L, key, n) { ** has a metatable with the required metamethods) */ const checktab = function(L, arg, what) { - if (lua.lua_type(L, arg) !== lua.LUA_TTABLE) { /* is it not a table? */ + if (lua_type(L, arg) !== LUA_TTABLE) { /* is it not a table? */ let n = 1; - if (lua.lua_getmetatable(L, arg) && /* must have metatable */ - (!(what & TAB_R) || checkfield(L, lua.to_luastring("__index", true), ++n)) && - (!(what & TAB_W) || checkfield(L, lua.to_luastring("__newindex", true), ++n)) && - (!(what & TAB_L) || checkfield(L, lua.to_luastring("__len", true), ++n))) { - lua.lua_pop(L, n); /* pop metatable and tested metamethods */ + if (lua_getmetatable(L, arg) && /* must have metatable */ + (!(what & TAB_R) || checkfield(L, to_luastring("__index", true), ++n)) && + (!(what & TAB_W) || checkfield(L, to_luastring("__newindex", true), ++n)) && + (!(what & TAB_L) || checkfield(L, to_luastring("__len", true), ++n))) { + lua_pop(L, n); /* pop metatable and tested metamethods */ } else - lauxlib.luaL_checktype(L, arg, lua.LUA_TTABLE); /* force an error */ + luaL_checktype(L, arg, LUA_TTABLE); /* force an error */ } }; const aux_getn = function(L, n, w) { checktab(L, n, w | TAB_L); - return lauxlib.luaL_len(L, n); + return luaL_len(L, n); }; const addfield = function(L, b, i) { - lua.lua_geti(L, 1, i); - if (!lua.lua_isstring(L, -1)) - lauxlib.luaL_error(L, lua.to_luastring("invalid value (%s) at index %d in table for 'concat'"), - lauxlib.luaL_typename(L, -1), i); + lua_geti(L, 1, i); + if (!lua_isstring(L, -1)) + luaL_error(L, to_luastring("invalid value (%s) at index %d in table for 'concat'"), + luaL_typename(L, -1), i); - lauxlib.luaL_addvalue(b); + luaL_addvalue(b); }; const tinsert = function(L) { let e = aux_getn(L, 1, TAB_RW) + 1; /* first empty element */ let pos; - switch (lua.lua_gettop(L)) { + switch (lua_gettop(L)) { case 2: pos = e; break; case 3: { - pos = lauxlib.luaL_checkinteger(L, 2); /* 2nd argument is the position */ - lauxlib.luaL_argcheck(L, 1 <= pos && pos <= e, 2, lua.to_luastring("position out of bounds", true)); + pos = luaL_checkinteger(L, 2); /* 2nd argument is the position */ + luaL_argcheck(L, 1 <= pos && pos <= e, 2, to_luastring("position out of bounds", true)); for (let i = e; i > pos; i--) { /* move up elements */ - lua.lua_geti(L, 1, i - 1); - lua.lua_seti(L, 1, i); /* t[i] = t[i - 1] */ + lua_geti(L, 1, i - 1); + lua_seti(L, 1, i); /* t[i] = t[i - 1] */ } break; } default: { - return lauxlib.luaL_error(L, lua.to_luastring("wrong number of arguments to 'insert'", true)); + return luaL_error(L, to_luastring("wrong number of arguments to 'insert'", true)); } } - lua.lua_seti(L, 1, pos); /* t[pos] = v */ + lua_seti(L, 1, pos); /* t[pos] = v */ return 0; }; const tremove = function(L) { let size = aux_getn(L, 1, TAB_RW); - let pos = lauxlib.luaL_optinteger(L, 2, size); + let pos = luaL_optinteger(L, 2, size); if (pos !== size) /* validate 'pos' if given */ - lauxlib.luaL_argcheck(L, 1 <= pos && pos <= size + 1, 1, lua.to_luastring("position out of bounds", true)); - lua.lua_geti(L, 1, pos); /* result = t[pos] */ + luaL_argcheck(L, 1 <= pos && pos <= size + 1, 1, to_luastring("position out of bounds", true)); + lua_geti(L, 1, pos); /* result = t[pos] */ for (; pos < size; pos++) { - lua.lua_geti(L, 1, pos + 1); - lua.lua_seti(L, 1, pos); /* t[pos] = t[pos + 1] */ + lua_geti(L, 1, pos + 1); + lua_seti(L, 1, pos); /* t[pos] = t[pos + 1] */ } - lua.lua_pushnil(L); - lua.lua_seti(L, 1, pos); /* t[pos] = nil */ + lua_pushnil(L); + lua_seti(L, 1, pos); /* t[pos] = nil */ return 1; }; @@ -100,77 +143,78 @@ const tremove = function(L) { ** than origin, or copying to another table. */ const tmove = function(L) { - let f = lauxlib.luaL_checkinteger(L, 2); - let e = lauxlib.luaL_checkinteger(L, 3); - let t = lauxlib.luaL_checkinteger(L, 4); - let tt = !lua.lua_isnoneornil(L, 5) ? 5 : 1; /* destination table */ + let f = luaL_checkinteger(L, 2); + let e = luaL_checkinteger(L, 3); + let t = luaL_checkinteger(L, 4); + let tt = !lua_isnoneornil(L, 5) ? 5 : 1; /* destination table */ checktab(L, 1, TAB_R); checktab(L, tt, TAB_W); if (e >= f) { /* otherwise, nothing to move */ - lauxlib.luaL_argcheck(L, f > 0 || e < luaconf.LUA_MAXINTEGER + f, 3, lua.to_luastring("too many elements to move", true)); + luaL_argcheck(L, f > 0 || e < LUA_MAXINTEGER + f, 3, to_luastring("too many elements to move", true)); let n = e - f + 1; /* number of elements to move */ - lauxlib.luaL_argcheck(L, t <= luaconf.LUA_MAXINTEGER - n + 1, 4, lua.to_luastring("destination wrap around", true)); + luaL_argcheck(L, t <= LUA_MAXINTEGER - n + 1, 4, to_luastring("destination wrap around", true)); - if (t > e || t <= f || (tt !== 1 && lua.lua_compare(L, 1, tt, lua.LUA_OPEQ) !== 1)) { + if (t > e || t <= f || (tt !== 1 && lua_compare(L, 1, tt, LUA_OPEQ) !== 1)) { for (let i = 0; i < n; i++) { - lua.lua_geti(L, 1, f + i); - lua.lua_seti(L, tt, t + i); + lua_geti(L, 1, f + i); + lua_seti(L, tt, t + i); } } else { for (let i = n - 1; i >= 0; i--) { - lua.lua_geti(L, 1, f + i); - lua.lua_seti(L, tt, t + i); + lua_geti(L, 1, f + i); + lua_seti(L, tt, t + i); } } } - lua.lua_pushvalue(L, tt); /* return destination table */ + lua_pushvalue(L, tt); /* return destination table */ return 1; }; const tconcat = function(L) { let last = aux_getn(L, 1, TAB_R); - let sep = lauxlib.luaL_optlstring(L, 2, lua.to_luastring("")); - let i = lauxlib.luaL_optinteger(L, 3, 1); - last = lauxlib.luaL_optinteger(L, 4, last); + let sep = luaL_optlstring(L, 2, to_luastring("")); + let lsep = sep.length; + let i = luaL_optinteger(L, 3, 1); + last = luaL_optinteger(L, 4, last); - let b = new lauxlib.luaL_Buffer(); - lauxlib.luaL_buffinit(L, b); + let b = new luaL_Buffer(); + luaL_buffinit(L, b); for (; i < last; i++) { addfield(L, b, i); - lauxlib.luaL_addlstring(b, sep); + luaL_addlstring(b, sep, lsep); } if (i === last) addfield(L, b, i); - lauxlib.luaL_pushresult(b); + luaL_pushresult(b); return 1; }; const pack = function(L) { - let n = lua.lua_gettop(L); /* number of elements to pack */ - lua.lua_createtable(L, n, 1); /* create result table */ - lua.lua_insert(L, 1); /* put it at index 1 */ + let n = lua_gettop(L); /* number of elements to pack */ + lua_createtable(L, n, 1); /* create result table */ + lua_insert(L, 1); /* put it at index 1 */ for (let i = n; i >= 1; i--) /* assign elements */ - lua.lua_seti(L, 1, i); - lua.lua_pushinteger(L, n); - lua.lua_setfield(L, 1, lua.to_luastring("n")); /* t.n = number of elements */ + lua_seti(L, 1, i); + lua_pushinteger(L, n); + lua_setfield(L, 1, to_luastring("n")); /* t.n = number of elements */ return 1; /* return table */ }; const unpack = function(L) { - let i = lauxlib.luaL_optinteger(L, 2, 1); - let e = lauxlib.luaL_opt(L, lauxlib.luaL_checkinteger, 3, lauxlib.luaL_len(L, 1)); + let i = luaL_optinteger(L, 2, 1); + let e = luaL_opt(L, luaL_checkinteger, 3, luaL_len(L, 1)); if (i > e) return 0; /* empty range */ let n = e - i; /* number of elements minus 1 (avoid overflows) */ - if (n >= Number.MAX_SAFE_INTEGER || !lua.lua_checkstack(L, ++n)) - return lauxlib.luaL_error(L, lua.to_luastring("too many results to unpack", true)); + if (n >= Number.MAX_SAFE_INTEGER || !lua_checkstack(L, ++n)) + return luaL_error(L, to_luastring("too many results to unpack", true)); for (; i < e; i++) /* push arg[i..e - 1] (to avoid overflows) */ - lua.lua_geti(L, 1, i); - lua.lua_geti(L, 1, e); /* push last element */ + lua_geti(L, 1, i); + lua_geti(L, 1, e); /* push last element */ return n; }; @@ -181,20 +225,20 @@ const l_randomizePivot = function() { const RANLIMIT = 100; const set2 = function(L, i, j) { - lua.lua_seti(L, 1, i); - lua.lua_seti(L, 1, j); + lua_seti(L, 1, i); + lua_seti(L, 1, j); }; const sort_comp = function(L, a, b) { - if (lua.lua_isnil(L, 2)) /* no function? */ - return lua.lua_compare(L, a, b, lua.LUA_OPLT); /* a < b */ + if (lua_isnil(L, 2)) /* no function? */ + return lua_compare(L, a, b, LUA_OPLT); /* a < b */ else { /* function */ - lua.lua_pushvalue(L, 2); /* push function */ - lua.lua_pushvalue(L, a-1); /* -1 to compensate function */ - lua.lua_pushvalue(L, b-2); /* -2 to compensate function and 'a' */ - lua.lua_call(L, 2, 1); /* call function */ - let res = lua.lua_toboolean(L, -1); /* get result */ - lua.lua_pop(L, 1); /* pop result */ + lua_pushvalue(L, 2); /* push function */ + lua_pushvalue(L, a-1); /* -1 to compensate function */ + lua_pushvalue(L, b-2); /* -2 to compensate function and 'a' */ + lua_call(L, 2, 1); /* call function */ + let res = lua_toboolean(L, -1); /* get result */ + lua_pop(L, 1); /* pop result */ return res; } }; @@ -205,22 +249,22 @@ const partition = function(L, lo, up) { /* loop invariant: a[lo .. i] <= P <= a[j .. up] */ for (;;) { /* next loop: repeat ++i while a[i] < P */ - while (lua.lua_geti(L, 1, ++i), sort_comp(L, -1, -2)) { + while (lua_geti(L, 1, ++i), sort_comp(L, -1, -2)) { if (i == up - 1) /* a[i] < P but a[up - 1] == P ?? */ - lauxlib.luaL_error(L, lua.to_luastring("invalid order function for sorting")); - lua.lua_pop(L, 1); /* remove a[i] */ + luaL_error(L, to_luastring("invalid order function for sorting")); + lua_pop(L, 1); /* remove a[i] */ } /* after the loop, a[i] >= P and a[lo .. i - 1] < P */ /* next loop: repeat --j while P < a[j] */ - while (lua.lua_geti(L, 1, --j), sort_comp(L, -3, -1)) { + while (lua_geti(L, 1, --j), sort_comp(L, -3, -1)) { if (j < i) /* j < i but a[j] > P ?? */ - lauxlib.luaL_error(L, lua.to_luastring("invalid order function for sorting")); - lua.lua_pop(L, 1); /* remove a[j] */ + luaL_error(L, to_luastring("invalid order function for sorting")); + lua_pop(L, 1); /* remove a[j] */ } /* after the loop, a[j] <= P and a[j + 1 .. up] >= P */ if (j < i) { /* no elements out of place? */ /* a[lo .. i - 1] <= P <= a[j + 1 .. i .. up] */ - lua.lua_pop(L, 1); /* pop a[j] */ + lua_pop(L, 1); /* pop a[j] */ /* swap pivot (a[up - 1]) with a[i] to satisfy pos-condition */ set2(L, up - 1, i); return i; @@ -233,19 +277,19 @@ const partition = function(L, lo, up) { const choosePivot = function(lo, up, rnd) { let r4 = Math.floor((up - lo) / 4); /* range/4 */ let p = rnd % (r4 * 2) + (lo + r4); - assert(lo + r4 <= p && p <= up - r4); + lualib.lua_assert(lo + r4 <= p && p <= up - r4); return p; }; const auxsort = function(L, lo, up, rnd) { while (lo < up) { /* loop for tail recursion */ /* sort elements 'lo', 'p', and 'up' */ - lua.lua_geti(L, 1, lo); - lua.lua_geti(L, 1, up); + lua_geti(L, 1, lo); + lua_geti(L, 1, up); if (sort_comp(L, -1, -2)) /* a[up] < a[lo]? */ set2(L, lo, up); /* swap a[lo] - a[up] */ else - lua.lua_pop(L, 2); /* remove both values */ + lua_pop(L, 2); /* remove both values */ if (up - lo == 1) /* only 2 elements? */ return; /* already sorted */ let p; /* Pivot index */ @@ -253,23 +297,23 @@ const auxsort = function(L, lo, up, rnd) { p = Math.floor((lo + up)/2); /* middle element is a good pivot */ else /* for larger intervals, it is worth a random pivot */ p = choosePivot(lo, up, rnd); - lua.lua_geti(L, 1, p); - lua.lua_geti(L, 1, lo); + lua_geti(L, 1, p); + lua_geti(L, 1, lo); if (sort_comp(L, -2, -1)) /* a[p] < a[lo]? */ set2(L, p, lo); /* swap a[p] - a[lo] */ else { - lua.lua_pop(L, 1); /* remove a[lo] */ - lua.lua_geti(L, 1, up); + lua_pop(L, 1); /* remove a[lo] */ + lua_geti(L, 1, up); if (sort_comp(L, -1, -2)) /* a[up] < a[p]? */ set2(L, p, up); /* swap a[up] - a[p] */ else - lua.lua_pop(L, 2); + lua_pop(L, 2); } if (up - lo == 2) /* only 3 elements? */ return; /* already sorted */ - lua.lua_geti(L, 1, p); /* get middle element (Pivot) */ - lua.lua_pushvalue(L, -1); /* push Pivot */ - lua.lua_geti(L, 1, up - 1); /* push a[up - 1] */ + lua_geti(L, 1, p); /* get middle element (Pivot) */ + lua_pushvalue(L, -1); /* push Pivot */ + lua_geti(L, 1, up - 1); /* push a[up - 1] */ set2(L, p, up - 1); /* swap Pivot (a[p]) with a[up - 1] */ p = partition(L, lo, up); let n; @@ -291,10 +335,10 @@ const auxsort = function(L, lo, up, rnd) { const sort = function(L) { let n = aux_getn(L, 1, TAB_RW); if (n > 1) { /* non-trivial interval? */ - lauxlib.luaL_argcheck(L, n < luaconf.LUA_MAXINTEGER, 1, lua.to_luastring("array too big", true)); - if (!lua.lua_isnoneornil(L, 2)) /* is there a 2nd argument? */ - lauxlib.luaL_checktype(L, 2, lua.LUA_TFUNCTION); /* must be a function */ - lua.lua_settop(L, 2); /* make sure there are two arguments */ + luaL_argcheck(L, n < LUA_MAXINTEGER, 1, to_luastring("array too big", true)); + if (!lua_isnoneornil(L, 2)) /* is there a 2nd argument? */ + luaL_checktype(L, 2, LUA_TFUNCTION); /* must be a function */ + lua_settop(L, 2); /* make sure there are two arguments */ auxsort(L, 1, n, 0); } return 0; @@ -311,7 +355,7 @@ const tab_funcs = { }; const luaopen_table = function(L) { - lauxlib.luaL_newlib(L, tab_funcs); + luaL_newlib(L, tab_funcs); return 1; }; @@ -1,16 +1,23 @@ "use strict"; -const assert = require('assert'); - -const defs = require('./defs.js'); +const { + constant_types: { + LUA_TTABLE, + LUA_TUSERDATA + }, + to_luastring +} = require('./defs.js'); +const { lua_assert } = require('./llimits.js'); const lobject = require('./lobject.js'); const ldo = require('./ldo.js'); const lstate = require('./lstate.js'); -const lstring = require('./lstring.js'); +const { + luaS_bless, + luaS_new +} = require('./lstring.js'); const ltable = require('./ltable.js'); const ldebug = require('./ldebug.js'); const lvm = require('./lvm.js'); -const CT = defs.constant_types; const luaT_typenames_ = [ "no value", @@ -24,7 +31,7 @@ const luaT_typenames_ = [ "userdata", "thread", "proto" /* this last case is used for tests only */ -].map(e => defs.to_luastring(e)); +].map(e => to_luastring(e)); const ttypename = function(t) { return luaT_typenames_[t + 1]; @@ -64,42 +71,42 @@ const TMS = { }; const luaT_init = function(L) { - L.l_G.tmname[TMS.TM_INDEX] = new lstring.luaS_new(L, defs.to_luastring("__index", true)); - L.l_G.tmname[TMS.TM_NEWINDEX] = new lstring.luaS_new(L, defs.to_luastring("__newindex", true)); - L.l_G.tmname[TMS.TM_GC] = new lstring.luaS_new(L, defs.to_luastring("__gc", true)); - L.l_G.tmname[TMS.TM_MODE] = new lstring.luaS_new(L, defs.to_luastring("__mode", true)); - L.l_G.tmname[TMS.TM_LEN] = new lstring.luaS_new(L, defs.to_luastring("__len", true)); - L.l_G.tmname[TMS.TM_EQ] = new lstring.luaS_new(L, defs.to_luastring("__eq", true)); - L.l_G.tmname[TMS.TM_ADD] = new lstring.luaS_new(L, defs.to_luastring("__add", true)); - L.l_G.tmname[TMS.TM_SUB] = new lstring.luaS_new(L, defs.to_luastring("__sub", true)); - L.l_G.tmname[TMS.TM_MUL] = new lstring.luaS_new(L, defs.to_luastring("__mul", true)); - L.l_G.tmname[TMS.TM_MOD] = new lstring.luaS_new(L, defs.to_luastring("__mod", true)); - L.l_G.tmname[TMS.TM_POW] = new lstring.luaS_new(L, defs.to_luastring("__pow", true)); - L.l_G.tmname[TMS.TM_DIV] = new lstring.luaS_new(L, defs.to_luastring("__div", true)); - L.l_G.tmname[TMS.TM_IDIV] = new lstring.luaS_new(L, defs.to_luastring("__idiv", true)); - L.l_G.tmname[TMS.TM_BAND] = new lstring.luaS_new(L, defs.to_luastring("__band", true)); - L.l_G.tmname[TMS.TM_BOR] = new lstring.luaS_new(L, defs.to_luastring("__bor", true)); - L.l_G.tmname[TMS.TM_BXOR] = new lstring.luaS_new(L, defs.to_luastring("__bxor", true)); - L.l_G.tmname[TMS.TM_SHL] = new lstring.luaS_new(L, defs.to_luastring("__shl", true)); - L.l_G.tmname[TMS.TM_SHR] = new lstring.luaS_new(L, defs.to_luastring("__shr", true)); - L.l_G.tmname[TMS.TM_UNM] = new lstring.luaS_new(L, defs.to_luastring("__unm", true)); - L.l_G.tmname[TMS.TM_BNOT] = new lstring.luaS_new(L, defs.to_luastring("__bnot", true)); - L.l_G.tmname[TMS.TM_LT] = new lstring.luaS_new(L, defs.to_luastring("__lt", true)); - L.l_G.tmname[TMS.TM_LE] = new lstring.luaS_new(L, defs.to_luastring("__le", true)); - L.l_G.tmname[TMS.TM_CONCAT] = new lstring.luaS_new(L, defs.to_luastring("__concat", true)); - L.l_G.tmname[TMS.TM_CALL] = new lstring.luaS_new(L, defs.to_luastring("__call", true)); + L.l_G.tmname[TMS.TM_INDEX] = new luaS_new(L, to_luastring("__index", true)); + L.l_G.tmname[TMS.TM_NEWINDEX] = new luaS_new(L, to_luastring("__newindex", true)); + L.l_G.tmname[TMS.TM_GC] = new luaS_new(L, to_luastring("__gc", true)); + L.l_G.tmname[TMS.TM_MODE] = new luaS_new(L, to_luastring("__mode", true)); + L.l_G.tmname[TMS.TM_LEN] = new luaS_new(L, to_luastring("__len", true)); + L.l_G.tmname[TMS.TM_EQ] = new luaS_new(L, to_luastring("__eq", true)); + L.l_G.tmname[TMS.TM_ADD] = new luaS_new(L, to_luastring("__add", true)); + L.l_G.tmname[TMS.TM_SUB] = new luaS_new(L, to_luastring("__sub", true)); + L.l_G.tmname[TMS.TM_MUL] = new luaS_new(L, to_luastring("__mul", true)); + L.l_G.tmname[TMS.TM_MOD] = new luaS_new(L, to_luastring("__mod", true)); + L.l_G.tmname[TMS.TM_POW] = new luaS_new(L, to_luastring("__pow", true)); + L.l_G.tmname[TMS.TM_DIV] = new luaS_new(L, to_luastring("__div", true)); + L.l_G.tmname[TMS.TM_IDIV] = new luaS_new(L, to_luastring("__idiv", true)); + L.l_G.tmname[TMS.TM_BAND] = new luaS_new(L, to_luastring("__band", true)); + L.l_G.tmname[TMS.TM_BOR] = new luaS_new(L, to_luastring("__bor", true)); + L.l_G.tmname[TMS.TM_BXOR] = new luaS_new(L, to_luastring("__bxor", true)); + L.l_G.tmname[TMS.TM_SHL] = new luaS_new(L, to_luastring("__shl", true)); + L.l_G.tmname[TMS.TM_SHR] = new luaS_new(L, to_luastring("__shr", true)); + L.l_G.tmname[TMS.TM_UNM] = new luaS_new(L, to_luastring("__unm", true)); + L.l_G.tmname[TMS.TM_BNOT] = new luaS_new(L, to_luastring("__bnot", true)); + L.l_G.tmname[TMS.TM_LT] = new luaS_new(L, to_luastring("__lt", true)); + L.l_G.tmname[TMS.TM_LE] = new luaS_new(L, to_luastring("__le", true)); + L.l_G.tmname[TMS.TM_CONCAT] = new luaS_new(L, to_luastring("__concat", true)); + L.l_G.tmname[TMS.TM_CALL] = new luaS_new(L, to_luastring("__call", true)); }; /* ** Return the name of the type of an object. For tables and userdata ** with metatable, use their '__name' metafield, if present. */ -const __name = defs.to_luastring('__name', true); +const __name = to_luastring('__name', true); const luaT_objtypename = function(L, o) { let mt; if ((o.ttistable() && (mt = o.value.metatable) !== null) || (o.ttisfulluserdata() && (mt = o.value.metatable) !== null)) { - let name = ltable.luaH_getstr(mt, lstring.luaS_bless(L, __name)); + let name = ltable.luaH_getstr(mt, luaS_bless(L, __name)); if (name.ttisstring()) return name.svalue(); } @@ -149,10 +156,10 @@ const luaT_trybinTM = function(L, p1, p2, res, event) { if (n1 !== false && n2 !== false) return ldebug.luaG_tointerror(L, p1, p2); else - return ldebug.luaG_opinterror(L, p1, p2, defs.to_luastring("perform bitwise operation on", true)); + return ldebug.luaG_opinterror(L, p1, p2, to_luastring("perform bitwise operation on", true)); } default: - return ldebug.luaG_opinterror(L, p1, p2, defs.to_luastring("perform arithmetic on", true)); + return ldebug.luaG_opinterror(L, p1, p2, to_luastring("perform arithmetic on", true)); } } }; @@ -172,7 +179,7 @@ const fasttm = function(l, et, e) { const luaT_gettm = function(events, event, ename) { const tm = ltable.luaH_getstr(events, ename); - assert(event <= TMS.TM_EQ); + lua_assert(event <= TMS.TM_EQ); if (tm.ttisnil()) { /* no tag method? */ events.flags |= 1<<event; /* cache this fact */ return null; @@ -183,8 +190,8 @@ const luaT_gettm = function(events, event, ename) { const luaT_gettmbyobj = function(L, o, event) { let mt; switch(o.ttnov()) { - case CT.LUA_TTABLE: - case CT.LUA_TUSERDATA: + case LUA_TTABLE: + case LUA_TUSERDATA: mt = o.value.metatable; break; default: @@ -6,14 +6,6 @@ const ldebug = require("./ldebug.js"); const ldo = require("./ldo.js"); const lstate = require("./lstate.js"); -module.exports.FENGARI_AUTHORS = defs.FENGARI_AUTHORS; -module.exports.FENGARI_COPYRIGHT = defs.FENGARI_COPYRIGHT; -module.exports.FENGARI_RELEASE = defs.FENGARI_RELEASE; -module.exports.FENGARI_VERSION = defs.FENGARI_VERSION; -module.exports.FENGARI_VERSION_MAJOR = defs.FENGARI_VERSION_MAJOR; -module.exports.FENGARI_VERSION_MINOR = defs.FENGARI_VERSION_MINOR; -module.exports.FENGARI_VERSION_NUM = defs.FENGARI_VERSION_NUM; -module.exports.FENGARI_VERSION_RELEASE = defs.FENGARI_VERSION_RELEASE; module.exports.LUA_AUTHORS = defs.LUA_AUTHORS; module.exports.LUA_COPYRIGHT = defs.LUA_COPYRIGHT; module.exports.LUA_ERRERR = defs.thread_status.LUA_ERRERR; @@ -34,7 +26,7 @@ module.exports.LUA_MASKLINE = defs.LUA_MASKLINE; module.exports.LUA_MASKRET = defs.LUA_MASKRET; module.exports.LUA_MINSTACK = defs.LUA_MINSTACK; module.exports.LUA_MULTRET = defs.LUA_MULTRET; -module.exports.LUA_NUMTAGS = defs.LUA_NUMTAGS; +module.exports.LUA_NUMTAGS = defs.constant_types.LUA_NUMTAGS; module.exports.LUA_OK = defs.thread_status.LUA_OK; module.exports.LUA_OPADD = defs.LUA_OPADD; module.exports.LUA_OPBAND = defs.LUA_OPBAND; @@ -59,16 +51,16 @@ module.exports.LUA_RIDX_GLOBALS = defs.LUA_RIDX_GLOBALS; module.exports.LUA_RIDX_LAST = defs.LUA_RIDX_LAST; module.exports.LUA_RIDX_MAINTHREAD = defs.LUA_RIDX_MAINTHREAD; module.exports.LUA_SIGNATURE = defs.LUA_SIGNATURE; -module.exports.LUA_TNONE = defs.CT.LUA_TNONE; -module.exports.LUA_TNIL = defs.CT.LUA_TNIL; -module.exports.LUA_TBOOLEAN = defs.CT.LUA_TBOOLEAN; -module.exports.LUA_TLIGHTUSERDATA = defs.CT.LUA_TLIGHTUSERDATA; -module.exports.LUA_TNUMBER = defs.CT.LUA_TNUMBER; -module.exports.LUA_TSTRING = defs.CT.LUA_TSTRING; -module.exports.LUA_TTABLE = defs.CT.LUA_TTABLE; -module.exports.LUA_TFUNCTION = defs.CT.LUA_TFUNCTION; -module.exports.LUA_TUSERDATA = defs.CT.LUA_TUSERDATA; -module.exports.LUA_TTHREAD = defs.CT.LUA_TTHREAD; +module.exports.LUA_TNONE = defs.constant_types.LUA_TNONE; +module.exports.LUA_TNIL = defs.constant_types.LUA_TNIL; +module.exports.LUA_TBOOLEAN = defs.constant_types.LUA_TBOOLEAN; +module.exports.LUA_TLIGHTUSERDATA = defs.constant_types.LUA_TLIGHTUSERDATA; +module.exports.LUA_TNUMBER = defs.constant_types.LUA_TNUMBER; +module.exports.LUA_TSTRING = defs.constant_types.LUA_TSTRING; +module.exports.LUA_TTABLE = defs.constant_types.LUA_TTABLE; +module.exports.LUA_TFUNCTION = defs.constant_types.LUA_TFUNCTION; +module.exports.LUA_TUSERDATA = defs.constant_types.LUA_TUSERDATA; +module.exports.LUA_TTHREAD = defs.constant_types.LUA_TTHREAD; module.exports.LUA_VERSION = defs.LUA_VERSION; module.exports.LUA_VERSION_MAJOR = defs.LUA_VERSION_MAJOR; module.exports.LUA_VERSION_MINOR = defs.LUA_VERSION_MINOR; @@ -78,9 +70,6 @@ module.exports.LUA_VERSUFFIX = defs.LUA_VERSUFFIX; module.exports.LUA_YIELD = defs.thread_status.LUA_YIELD; module.exports.lua_Debug = defs.lua_Debug; module.exports.lua_upvalueindex = defs.lua_upvalueindex; -module.exports.to_jsstring = defs.to_jsstring; -module.exports.to_luastring = defs.to_luastring; -module.exports.to_uristring = defs.to_uristring; module.exports.LUA_CDIR = defs.LUA_CDIR; module.exports.LUA_CPATH_DEFAULT = defs.LUA_CPATH_DEFAULT; module.exports.LUA_EXEC_DIR = defs.LUA_EXEC_DIR; diff --git a/src/luaconf.js b/src/luaconf.js index 4bf8583..533e316 100644 --- a/src/luaconf.js +++ b/src/luaconf.js @@ -38,7 +38,11 @@ const LUA_INTEGER_FMT = `%${LUA_INTEGER_FRMLEN}d`; const LUA_NUMBER_FMT = "%.14g"; const lua_getlocaledecpoint = function() { - return (1.1).toLocaleString().substring(1, 2); + return (1.1).toLocaleString().charCodeAt(1); +}; + +const luai_apicheck = function(l, e) { + if (!e) throw Error(e); }; // See: http://croquetweak.blogspot.fr/2014/08/deconstructing-floats-frexp-and-ldexp.html @@ -78,3 +82,4 @@ module.exports.lua_getlocaledecpoint = lua_getlocaledecpoint; module.exports.lua_integer2str = lua_integer2str; module.exports.lua_number2str = lua_number2str; module.exports.lua_numbertointeger = lua_numbertointeger; +module.exports.luai_apicheck = luai_apicheck; diff --git a/src/lualib.js b/src/lualib.js index 4fbae44..78f441f 100644 --- a/src/lualib.js +++ b/src/lualib.js @@ -1,11 +1,15 @@ "use strict"; -const lua = require("./lua.js"); -const linit = require('./linit.js'); +const { + LUA_VERSION_MAJOR, + LUA_VERSION_MINOR +} = require("./lua.js"); -const LUA_VERSUFFIX = "_" + lua.LUA_VERSION_MAJOR + "_" + lua.LUA_VERSION_MINOR; +const LUA_VERSUFFIX = "_" + LUA_VERSION_MAJOR + "_" + LUA_VERSION_MINOR; module.exports.LUA_VERSUFFIX = LUA_VERSUFFIX; +module.exports.lua_assert = function(c) {}; + const LUA_COLIBNAME = "coroutine"; module.exports.LUA_COLIBNAME = LUA_COLIBNAME; module.exports.luaopen_coroutine = require("./lcorolib.js").luaopen_coroutine; @@ -48,4 +52,5 @@ const LUA_LOADLIBNAME = "package"; module.exports.LUA_LOADLIBNAME = LUA_LOADLIBNAME; module.exports.luaopen_package = require("./loadlib.js").luaopen_package; +const linit = require('./linit.js'); module.exports.luaL_openlibs = linit.luaL_openlibs; diff --git a/src/lundump.js b/src/lundump.js index e49c376..cf3fafa 100644 --- a/src/lundump.js +++ b/src/lundump.js @@ -1,16 +1,46 @@ "use strict"; -const assert = require('assert'); - -const defs = require('./defs.js'); +const { + LUA_SIGNATURE, + constant_types: { + LUA_TBOOLEAN, + LUA_TLNGSTR, + LUA_TNIL, + LUA_TNUMFLT, + LUA_TNUMINT, + LUA_TSHRSTR + }, + thread_status: { LUA_ERRSYNTAX }, + is_luastring, + luastring_eq, + to_luastring +} = require('./defs.js'); const ldo = require('./ldo.js'); const lfunc = require('./lfunc.js'); const lobject = require('./lobject.js'); -const lopcodes = require('./lopcodes.js'); -const lstring = require('./lstring.js'); -const lzio = require('./lzio.js'); - -let LUAC_DATA = [0x19, 0x93, defs.char["\r"], defs.char["\n"], 0x1a, defs.char["\n"]]; +const { + MAXARG_sBx, + POS_A, + POS_Ax, + POS_B, + POS_Bx, + POS_C, + POS_OP, + SIZE_A, + SIZE_Ax, + SIZE_B, + SIZE_Bx, + SIZE_C, + SIZE_OP +} = require('./lopcodes.js'); +const { lua_assert } = require("./llimits.js"); +const { luaS_bless } = require('./lstring.js'); +const { + luaZ_read, + ZIO +} = require('./lzio.js'); + +let LUAC_DATA = [0x19, 0x93, 13, 10, 0x1a, 10]; class BytecodeParser { @@ -21,13 +51,13 @@ class BytecodeParser { this.integerSize = 4; this.numberSize = 8; - assert(Z instanceof lzio.ZIO, "BytecodeParser only operates on a ZIO"); - assert(defs.is_luastring(name)); + lua_assert(Z instanceof ZIO, "BytecodeParser only operates on a ZIO"); + lua_assert(is_luastring(name)); - if (name[0] == defs.char["@"] || name[0] == defs.char["="]) + if (name[0] === 64 /* ('@').charCodeAt(0) */ || name[0] === 61 /* ('=').charCodeAt(0) */) this.name = name.subarray(1); - else if (name[0] == defs.LUA_SIGNATURE.charCodeAt(0)) - this.name = defs.to_luastring("binary string", true); + else if (name[0] == LUA_SIGNATURE[0]) + this.name = to_luastring("binary string", true); else this.name = name; @@ -44,19 +74,19 @@ class BytecodeParser { read(size) { let u8 = new Uint8Array(size); - if(lzio.luaZ_read(this.Z, u8, 0, size) !== 0) + if(luaZ_read(this.Z, u8, 0, size) !== 0) this.error("truncated"); return u8; } readByte() { - if (lzio.luaZ_read(this.Z, this.u8, 0, 1) !== 0) + if (luaZ_read(this.Z, this.u8, 0, 1) !== 0) this.error("truncated"); return this.u8[0]; } readInteger() { - if (lzio.luaZ_read(this.Z, this.u8, 0, this.integerSize) !== 0) + if (luaZ_read(this.Z, this.u8, 0, this.integerSize) !== 0) this.error("truncated"); return this.dv.getInt32(0, true); } @@ -66,13 +96,13 @@ class BytecodeParser { } readInt() { - if (lzio.luaZ_read(this.Z, this.u8, 0, this.intSize) !== 0) + if (luaZ_read(this.Z, this.u8, 0, this.intSize) !== 0) this.error("truncated"); return this.dv.getInt32(0, true); } readNumber() { - if (lzio.luaZ_read(this.Z, this.u8, 0, this.numberSize) !== 0) + if (luaZ_read(this.Z, this.u8, 0, this.numberSize) !== 0) this.error("truncated"); return this.dv.getFloat64(0, true); } @@ -87,7 +117,7 @@ class BytecodeParser { return null; } - return lstring.luaS_bless(this.L, this.read(size)); + return luaS_bless(this.L, this.read(size)); } /* creates a mask with 'n' 1 bits at position 'p' */ @@ -101,27 +131,26 @@ class BytecodeParser { } readInstruction() { - if (lzio.luaZ_read(this.Z, this.u8, 0, this.instructionSize) !== 0) + if (luaZ_read(this.Z, this.u8, 0, this.instructionSize) !== 0) this.error("truncated"); return this.dv.getUint32(0, true); } readCode(f) { let n = this.readInt(); - let o = lopcodes; let p = BytecodeParser; for (let i = 0; i < n; i++) { let ins = this.readInstruction(); f.code[i] = { code: ins, - opcode: (ins >> o.POS_OP) & p.MASK1(o.SIZE_OP, 0), - A: (ins >> o.POS_A) & p.MASK1(o.SIZE_A, 0), - B: (ins >> o.POS_B) & p.MASK1(o.SIZE_B, 0), - C: (ins >> o.POS_C) & p.MASK1(o.SIZE_C, 0), - Bx: (ins >> o.POS_Bx) & p.MASK1(o.SIZE_Bx, 0), - Ax: (ins >> o.POS_Ax) & p.MASK1(o.SIZE_Ax, 0), - sBx: ((ins >> o.POS_Bx) & p.MASK1(o.SIZE_Bx, 0)) - o.MAXARG_sBx + opcode: (ins >> POS_OP) & p.MASK1(SIZE_OP, 0), + A: (ins >> POS_A) & p.MASK1(SIZE_A, 0), + B: (ins >> POS_B) & p.MASK1(SIZE_B, 0), + C: (ins >> POS_C) & p.MASK1(SIZE_C, 0), + Bx: (ins >> POS_Bx) & p.MASK1(SIZE_Bx, 0), + Ax: (ins >> POS_Ax) & p.MASK1(SIZE_Ax, 0), + sBx: ((ins >> POS_Bx) & p.MASK1(SIZE_Bx, 0)) - MAXARG_sBx }; } } @@ -145,21 +174,21 @@ class BytecodeParser { let t = this.readByte(); switch (t) { - case defs.CT.LUA_TNIL: - f.k.push(new lobject.TValue(defs.CT.LUA_TNIL, null)); + case LUA_TNIL: + f.k.push(new lobject.TValue(LUA_TNIL, null)); break; - case defs.CT.LUA_TBOOLEAN: - f.k.push(new lobject.TValue(defs.CT.LUA_TBOOLEAN, this.readByte() !== 0)); + case LUA_TBOOLEAN: + f.k.push(new lobject.TValue(LUA_TBOOLEAN, this.readByte() !== 0)); break; - case defs.CT.LUA_TNUMFLT: - f.k.push(new lobject.TValue(defs.CT.LUA_TNUMFLT, this.readNumber())); + case LUA_TNUMFLT: + f.k.push(new lobject.TValue(LUA_TNUMFLT, this.readNumber())); break; - case defs.CT.LUA_TNUMINT: - f.k.push(new lobject.TValue(defs.CT.LUA_TNUMINT, this.readInteger())); + case LUA_TNUMINT: + f.k.push(new lobject.TValue(LUA_TNUMINT, this.readInteger())); break; - case defs.CT.LUA_TSHRSTR: - case defs.CT.LUA_TLNGSTR: - f.k.push(new lobject.TValue(defs.CT.LUA_TLNGSTR, this.readString())); + case LUA_TSHRSTR: + case LUA_TLNGSTR: + f.k.push(new lobject.TValue(LUA_TLNGSTR, this.readString())); break; default: this.error(`unrecognized constant '${t}'`); @@ -214,12 +243,12 @@ class BytecodeParser { checkliteral(s, msg) { let buff = this.read(s.length); - if (!defs.luastring_cmp(buff, s)) + if (!luastring_eq(buff, s)) this.error(msg); } checkHeader() { - this.checkliteral(defs.to_luastring(defs.LUA_SIGNATURE.substring(1)), "not a"); /* 1st char already checked */ + this.checkliteral(LUA_SIGNATURE.subarray(1), "not a"); /* 1st char already checked */ if (this.readByte() !== 0x53) this.error("version mismatch in"); @@ -250,8 +279,8 @@ class BytecodeParser { } error(why) { - lobject.luaO_pushfstring(this.L, defs.to_luastring("%s: %s precompiled chunk"), this.name, defs.to_luastring(why)); - ldo.luaD_throw(this.L, defs.thread_status.LUA_ERRSYNTAX); + lobject.luaO_pushfstring(this.L, to_luastring("%s: %s precompiled chunk"), this.name, to_luastring(why)); + ldo.luaD_throw(this.L, LUA_ERRSYNTAX); } checksize(byte, size, tname) { @@ -268,7 +297,7 @@ const luaU_undump = function(L, Z, name) { L.stack[L.top-1].setclLvalue(cl); cl.p = new lfunc.Proto(L); S.readFunction(cl.p, null); - assert(cl.nupvalues === cl.p.upvalues.length); + lua_assert(cl.nupvalues === cl.p.upvalues.length); /* luai_verifycode */ return cl; }; diff --git a/src/lutf8lib.js b/src/lutf8lib.js index f581a9e..3e3e194 100644 --- a/src/lutf8lib.js +++ b/src/lutf8lib.js @@ -1,7 +1,33 @@ "use strict"; -const lua = require('./lua.js'); -const lauxlib = require('./lauxlib.js'); +const { + lua_gettop, + lua_pushcfunction, + lua_pushfstring, + lua_pushinteger, + lua_pushnil, + lua_pushstring, + lua_pushvalue, + lua_setfield, + lua_tointeger +} = require('./lua.js'); +const { + luaL_Buffer, + luaL_addvalue, + luaL_argcheck, + luaL_buffinit, + luaL_checkinteger, + luaL_checkstack, + luaL_checkstring, + luaL_error, + luaL_newlib, + luaL_optinteger, + luaL_pushresult +} = require('./lauxlib.js'); +const { + luastring_of, + to_luastring +} = require("./fengaricore.js"); const MAXUNICODE = 0x10FFFF; @@ -54,49 +80,50 @@ const utf8_decode = function(s, pos) { */ const utflen = function(L) { let n = 0; - let s = lauxlib.luaL_checkstring(L, 1); + let s = luaL_checkstring(L, 1); 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); + let posi = u_posrelat(luaL_optinteger(L, 2, 1), len); + let posj = u_posrelat(luaL_optinteger(L, 3, -1), len); - lauxlib.luaL_argcheck(L, 1 <= posi && --posi <= len, 2, lua.to_luastring("initial position out of string")); - lauxlib.luaL_argcheck(L, --posj < len, 3, lua.to_luastring("final position out of string")); + luaL_argcheck(L, 1 <= posi && --posi <= len, 2, to_luastring("initial position out of string")); + luaL_argcheck(L, --posj < len, 3, to_luastring("final position out of string")); while (posi <= posj) { let dec = utf8_decode(s, posi); if (dec === null) { /* conversion error? */ - lua.lua_pushnil(L); /* return nil ... */ - lua.lua_pushinteger(L, posi + 1); /* ... and current position */ + lua_pushnil(L); /* return nil ... */ + lua_pushinteger(L, posi + 1); /* ... and current position */ return 2; } posi = dec.pos; n++; } - lua.lua_pushinteger(L, n); + lua_pushinteger(L, n); return 1; }; +const p_U = to_luastring("%U"); 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", true)); - lua.lua_pushstring(L, lua.to_luastring(String.fromCodePoint(code))); + let code = luaL_checkinteger(L, arg); + luaL_argcheck(L, 0 <= code && code <= MAXUNICODE, arg, to_luastring("value out of range", true)); + lua_pushfstring(L, p_U, code); }; /* ** utfchar(n1, n2, ...) -> char(n1)..char(n2)... */ const utfchar = function(L) { - let n = lua.lua_gettop(L); /* number of arguments */ + let n = lua_gettop(L); /* number of arguments */ if (n === 1) /* optimize common case of single char */ pushutfchar(L, 1); else { - let b = new lauxlib.luaL_Buffer(); - lauxlib.luaL_buffinit(L, b); + let b = new luaL_Buffer(); + luaL_buffinit(L, b); for (let i = 1; i <= n; i++) { pushutfchar(L, i); - lauxlib.luaL_addvalue(b); + luaL_addvalue(b); } - lauxlib.luaL_pushresult(b); + luaL_pushresult(b); } return 1; }; @@ -106,19 +133,19 @@ const utfchar = function(L) { ** position 'i' starts; 0 means character at 'i'. */ const byteoffset = function(L) { - let s = lauxlib.luaL_checkstring(L, 1); - let n = lauxlib.luaL_checkinteger(L, 2); + let s = luaL_checkstring(L, 1); + let n = luaL_checkinteger(L, 2); let posi = n >= 0 ? 1 : s.length + 1; - posi = u_posrelat(lauxlib.luaL_optinteger(L, 3, posi), s.length); + posi = u_posrelat(luaL_optinteger(L, 3, posi), s.length); - lauxlib.luaL_argcheck(L, 1 <= posi && --posi <= s.length, 3, lua.to_luastring("position out of range", true)); + luaL_argcheck(L, 1 <= posi && --posi <= s.length, 3, to_luastring("position out of range", true)); if (n === 0) { /* find beginning of current byte sequence */ while (posi > 0 && iscont(s[posi])) posi--; } else { if (iscont(s[posi])) - lauxlib.luaL_error(L, lua.to_luastring("initial position is a continuation byte", true)); + luaL_error(L, to_luastring("initial position is a continuation byte", true)); if (n < 0) { while (n < 0 && posi > 0) { /* move back */ @@ -139,9 +166,9 @@ const byteoffset = function(L) { } if (n === 0) /* did it find given character? */ - lua.lua_pushinteger(L, posi + 1); + lua_pushinteger(L, posi + 1); else /* no such character */ - lua.lua_pushnil(L); + lua_pushnil(L); return 1; }; @@ -151,24 +178,24 @@ const byteoffset = function(L) { ** that start in the range [i,j] */ const codepoint = function(L) { - let s = lauxlib.luaL_checkstring(L, 1); - let posi = u_posrelat(lauxlib.luaL_optinteger(L, 2, 1), s.length); - let pose = u_posrelat(lauxlib.luaL_optinteger(L, 3, posi), s.length); + let s = luaL_checkstring(L, 1); + let posi = u_posrelat(luaL_optinteger(L, 2, 1), s.length); + let pose = u_posrelat(luaL_optinteger(L, 3, posi), s.length); - lauxlib.luaL_argcheck(L, posi >= 1, 2, lua.to_luastring("out of range", true)); - lauxlib.luaL_argcheck(L, pose <= s.length, 3, lua.to_luastring("out of range", true)); + luaL_argcheck(L, posi >= 1, 2, to_luastring("out of range", true)); + luaL_argcheck(L, pose <= s.length, 3, to_luastring("out of range", true)); if (posi > pose) return 0; /* empty interval; return no values */ if (pose - posi >= Number.MAX_SAFE_INTEGER) - return lauxlib.luaL_error(L, lua.to_luastring("string slice too long", true)); + return luaL_error(L, to_luastring("string slice too long", true)); let n = (pose - posi) + 1; - lauxlib.luaL_checkstack(L, n, lua.to_luastring("string slice too long", true)); + luaL_checkstack(L, n, to_luastring("string slice too long", true)); n = 0; for (posi -= 1; posi < pose;) { let dec = utf8_decode(s, posi); if (dec === null) - return lauxlib.luaL_error(L, lua.to_luastring("invalid UTF-8 code", true)); - lua.lua_pushinteger(L, dec.code); + return luaL_error(L, to_luastring("invalid UTF-8 code", true)); + lua_pushinteger(L, dec.code); posi = dec.pos; n++; } @@ -176,9 +203,9 @@ const codepoint = function(L) { }; const iter_aux = function(L) { - let s = lauxlib.luaL_checkstring(L, 1); + let s = luaL_checkstring(L, 1); let len = s.length; - let n = lua.lua_tointeger(L, 2) - 1; + let n = lua_tointeger(L, 2) - 1; if (n < 0) /* first iteration? */ n = 0; /* start from here */ @@ -192,18 +219,18 @@ const iter_aux = function(L) { else { let dec = utf8_decode(s, n); if (dec === null || iscont(s[dec.pos])) - return lauxlib.luaL_error(L, lua.to_luastring("invalid UTF-8 code", true)); - lua.lua_pushinteger(L, n + 1); - lua.lua_pushinteger(L, dec.code); + return luaL_error(L, to_luastring("invalid UTF-8 code", true)); + lua_pushinteger(L, n + 1); + lua_pushinteger(L, dec.code); return 2; } }; const iter_codes = function(L) { - lauxlib.luaL_checkstring(L, 1); - lua.lua_pushcfunction(L, iter_aux); - lua.lua_pushvalue(L, 1); - lua.lua_pushinteger(L, 0); + luaL_checkstring(L, 1); + lua_pushcfunction(L, iter_aux); + lua_pushvalue(L, 1); + lua_pushinteger(L, 0); return 3; }; @@ -216,12 +243,12 @@ const funcs = { }; /* pattern to match a single UTF-8 character */ -const UTF8PATT = Uint8Array.of(91, 0, 45, 127, 194, 45, 244, 93, 91, 128, 45, 191, 93, 42); +const UTF8PATT = luastring_of(91, 0, 45, 127, 194, 45, 244, 93, 91, 128, 45, 191, 93, 42); const luaopen_utf8 = function(L) { - lauxlib.luaL_newlib(L, funcs); - lua.lua_pushstring(L, UTF8PATT); - lua.lua_setfield(L, -2, lua.to_luastring("charpattern", true)); + luaL_newlib(L, funcs); + lua_pushstring(L, UTF8PATT); + lua_setfield(L, -2, to_luastring("charpattern", true)); return 1; }; @@ -1,56 +1,133 @@ "use strict"; -const assert = require('assert'); - -const defs = require('./defs.js'); -const lopcodes = require('./lopcodes.js'); -const luaconf = require('./luaconf.js'); -const lobject = require('./lobject.js'); -const lfunc = require('./lfunc.js'); -const lstate = require('./lstate.js'); -const lstring = require('./lstring.js'); -const llimits = require('./llimits.js'); -const ldo = require('./ldo.js'); -const ltm = require('./ltm.js'); -const ltable = require('./ltable.js'); -const ldebug = require('./ldebug.js'); -const CT = defs.constant_types; -const LUA_MULTRET = defs.LUA_MULTRET; +const { + LUA_MASKLINE, + LUA_MASKCOUNT, + LUA_MULTRET, + constant_types: { + LUA_TBOOLEAN, + LUA_TLCF, + LUA_TLIGHTUSERDATA, + LUA_TLNGSTR, + LUA_TNIL, + LUA_TNUMBER, + LUA_TNUMFLT, + LUA_TNUMINT, + LUA_TSHRSTR, + LUA_TTABLE, + LUA_TUSERDATA + }, + to_luastring +} = require('./defs.js'); +const { + INDEXK, + ISK, + LFIELDS_PER_FLUSH, + OpCodesI: { + OP_ADD, + OP_BAND, + OP_BNOT, + OP_BOR, + OP_BXOR, + OP_CALL, + OP_CLOSURE, + OP_CONCAT, + OP_DIV, + OP_EQ, + OP_EXTRAARG, + OP_FORLOOP, + OP_FORPREP, + OP_GETTABLE, + OP_GETTABUP, + OP_GETUPVAL, + OP_IDIV, + OP_JMP, + OP_LE, + OP_LEN, + OP_LOADBOOL, + OP_LOADK, + OP_LOADKX, + OP_LOADNIL, + OP_LT, + OP_MOD, + OP_MOVE, + OP_MUL, + OP_NEWTABLE, + OP_NOT, + OP_POW, + OP_RETURN, + OP_SELF, + OP_SETLIST, + OP_SETTABLE, + OP_SETTABUP, + OP_SETUPVAL, + OP_SHL, + OP_SHR, + OP_SUB, + OP_TAILCALL, + OP_TEST, + OP_TESTSET, + OP_TFORCALL, + OP_TFORLOOP, + OP_UNM, + OP_VARARG + } +} = require('./lopcodes.js'); +const { + LUA_MAXINTEGER, + LUA_MININTEGER, + lua_numbertointeger +} = require('./luaconf.js'); +const { + lua_assert, + luai_nummod +} = require('./llimits.js'); +const lobject = require('./lobject.js'); +const lfunc = require('./lfunc.js'); +const lstate = require('./lstate.js'); +const { + luaS_bless, + luaS_eqlngstr, + luaS_hashlongstr +} = require('./lstring.js'); +const ldo = require('./ldo.js'); +const ltm = require('./ltm.js'); +const ltable = require('./ltable.js'); +const ldebug = require('./ldebug.js'); /* ** finish execution of an opcode interrupted by an yield */ const luaV_finishOp = function(L) { let ci = L.ci; - let OCi = lopcodes.OpCodesI; let base = ci.l_base; let inst = ci.l_code[ci.l_savedpc - 1]; /* interrupted instruction */ let op = inst.opcode; switch (op) { /* finish its execution */ - case OCi.OP_ADD: case OCi.OP_SUB: case OCi.OP_MUL: case OCi.OP_DIV: case OCi.OP_IDIV: - case OCi.OP_BAND: case OCi.OP_BOR: case OCi.OP_BXOR: case OCi.OP_SHL: case OCi.OP_SHR: - case OCi.OP_MOD: case OCi.OP_POW: - case OCi.OP_UNM: case OCi.OP_BNOT: case OCi.OP_LEN: - case OCi.OP_GETTABUP: case OCi.OP_GETTABLE: case OCi.OP_SELF: { + case OP_ADD: case OP_SUB: case OP_MUL: case OP_DIV: case OP_IDIV: + case OP_BAND: case OP_BOR: case OP_BXOR: case OP_SHL: case OP_SHR: + case OP_MOD: case OP_POW: + case OP_UNM: case OP_BNOT: case OP_LEN: + case OP_GETTABUP: case OP_GETTABLE: case OP_SELF: { lobject.setobjs2s(L, base + inst.A, L.top-1); delete L.stack[--L.top]; break; } - case OCi.OP_LE: case OCi.OP_LT: case OCi.OP_EQ: { + case OP_LE: case OP_LT: case OP_EQ: { let res = !L.stack[L.top - 1].l_isfalse(); delete L.stack[--L.top]; if (ci.callstatus & lstate.CIST_LEQ) { /* "<=" using "<" instead? */ - assert(op === OCi.OP_LE); + lua_assert(op === OP_LE); ci.callstatus ^= lstate.CIST_LEQ; /* clear mark */ res = !res; /* negate result */ } - assert(ci.l_code[ci.l_savedpc].opcode === OCi.OP_JMP); + lua_assert(ci.l_code[ci.l_savedpc].opcode === OP_JMP); if (res !== (inst.A ? true : false)) /* condition failed? */ ci.l_savedpc++; /* skip jump instruction */ break; } - case OCi.OP_CONCAT: { + case OP_CONCAT: { let top = L.top - 1; /* top when 'luaT_trybinTM' was called */ let b = inst.B; /* first element to concatenate */ let total = top - 1 - (base + b); /* yet to concatenate */ @@ -64,12 +141,12 @@ const luaV_finishOp = function(L) { ldo.adjust_top(L, ci.top); /* restore top */ break; } - case OCi.OP_TFORCALL: { - assert(ci.l_code[ci.l_savedpc].opcode === OCi.OP_TFORLOOP); + case OP_TFORCALL: { + lua_assert(ci.l_code[ci.l_savedpc].opcode === OP_TFORLOOP); ldo.adjust_top(L, ci.top); /* correct top */ break; } - case OCi.OP_CALL: { + case OP_CALL: { if (inst.C - 1 >= 0) /* nresults >= 0? */ ldo.adjust_top(L, ci.top); /* adjust results */ break; @@ -90,28 +167,27 @@ const RB = function(L, base, i) { // }; const RKB = function(L, base, k, i) { - return lopcodes.ISK(i.B) ? k[lopcodes.INDEXK(i.B)] : L.stack[base + i.B]; + return ISK(i.B) ? k[INDEXK(i.B)] : L.stack[base + i.B]; }; const RKC = function(L, base, k, i) { - return lopcodes.ISK(i.C) ? k[lopcodes.INDEXK(i.C)] : L.stack[base + i.C]; + return ISK(i.C) ? k[INDEXK(i.C)] : L.stack[base + i.C]; }; const luaV_execute = function(L) { - const OCi = lopcodes.OpCodesI; let ci = L.ci; ci.callstatus |= lstate.CIST_FRESH; newframe: for (;;) { - assert(ci === L.ci); + lua_assert(ci === L.ci); let cl = ci.func.value; let k = cl.p.k; let base = ci.l_base; let i = ci.l_code[ci.l_savedpc++]; - if (L.hookmask & (defs.LUA_MASKLINE | defs.LUA_MASKCOUNT)) { + if (L.hookmask & (LUA_MASKLINE | LUA_MASKCOUNT)) { ldebug.luaG_traceexec(L); } @@ -119,22 +195,22 @@ const luaV_execute = function(L) { let opcode = i.opcode; switch (opcode) { - case OCi.OP_MOVE: { + case OP_MOVE: { lobject.setobjs2s(L, ra, RB(L, base, i)); break; } - case OCi.OP_LOADK: { + case OP_LOADK: { let konst = k[i.Bx]; lobject.setobj2s(L, ra, konst); break; } - case OCi.OP_LOADKX: { - assert(ci.l_code[ci.l_savedpc].opcode === OCi.OP_EXTRAARG); + case OP_LOADKX: { + lua_assert(ci.l_code[ci.l_savedpc].opcode === OP_EXTRAARG); let konst = k[ci.l_code[ci.l_savedpc++].Ax]; lobject.setobj2s(L, ra, konst); break; } - case OCi.OP_LOADBOOL: { + case OP_LOADBOOL: { L.stack[ra].setbvalue(i.B !== 0); if (i.C !== 0) @@ -142,41 +218,41 @@ const luaV_execute = function(L) { break; } - case OCi.OP_LOADNIL: { + case OP_LOADNIL: { for (let j = 0; j <= i.B; j++) L.stack[ra + j].setnilvalue(); break; } - case OCi.OP_GETUPVAL: { + case OP_GETUPVAL: { let b = i.B; - lobject.setobj2s(L, ra, cl.upvals[b].v); + lobject.setobj2s(L, ra, cl.upvals[b]); break; } - case OCi.OP_GETTABUP: { - let upval = cl.upvals[i.B].v; + case OP_GETTABUP: { + let upval = cl.upvals[i.B]; let rc = RKC(L, base, k, i); luaV_gettable(L, upval, rc, ra); break; } - case OCi.OP_GETTABLE: { + case OP_GETTABLE: { let rb = L.stack[RB(L, base, i)]; let rc = RKC(L, base, k, i); luaV_gettable(L, rb, rc, ra); break; } - case OCi.OP_SETTABUP: { - let upval = cl.upvals[i.A].v; + case OP_SETTABUP: { + let upval = cl.upvals[i.A]; let rb = RKB(L, base, k, i); let rc = RKC(L, base, k, i); settable(L, upval, rb, rc); break; } - case OCi.OP_SETUPVAL: { + case OP_SETUPVAL: { let uv = cl.upvals[i.B]; - uv.v.setfrom(L.stack[ra]); + uv.setfrom(L.stack[ra]); break; } - case OCi.OP_SETTABLE: { + case OP_SETTABLE: { let table = L.stack[ra]; let key = RKB(L, base, k, i); let v = RKC(L, base, k, i); @@ -184,18 +260,18 @@ const luaV_execute = function(L) { settable(L, table, key, v); break; } - case OCi.OP_NEWTABLE: { + case OP_NEWTABLE: { L.stack[ra].sethvalue(ltable.luaH_new(L)); break; } - case OCi.OP_SELF: { + case OP_SELF: { let rb = RB(L, base, i); let rc = RKC(L, base, k, i); lobject.setobjs2s(L, ra + 1, rb); luaV_gettable(L, L.stack[rb], rc, ra); break; } - case OCi.OP_ADD: { + case OP_ADD: { let op1 = RKB(L, base, k, i); let op2 = RKC(L, base, k, i); let numberop1, numberop2; @@ -209,7 +285,7 @@ const luaV_execute = function(L) { } break; } - case OCi.OP_SUB: { + case OP_SUB: { let op1 = RKB(L, base, k, i); let op2 = RKC(L, base, k, i); let numberop1, numberop2; @@ -223,13 +299,13 @@ const luaV_execute = function(L) { } break; } - case OCi.OP_MUL: { + case OP_MUL: { let op1 = RKB(L, base, k, i); let op2 = RKC(L, base, k, i); let numberop1, numberop2; if (op1.ttisinteger() && op2.ttisinteger()) { - L.stack[ra].setivalue(Math.imul(op1.value, op2.value)); + L.stack[ra].setivalue(luaV_imul(op1.value, op2.value)); } else if ((numberop1 = tonumber(op1)) !== false && (numberop2 = tonumber(op2)) !== false) { L.stack[ra].setfltvalue(numberop1 * numberop2); } else { @@ -237,7 +313,7 @@ const luaV_execute = function(L) { } break; } - case OCi.OP_MOD: { + case OP_MOD: { let op1 = RKB(L, base, k, i); let op2 = RKC(L, base, k, i); let numberop1, numberop2; @@ -245,13 +321,13 @@ const luaV_execute = function(L) { if (op1.ttisinteger() && op2.ttisinteger()) { L.stack[ra].setivalue(luaV_mod(L, op1.value, op2.value)); } else if ((numberop1 = tonumber(op1)) !== false && (numberop2 = tonumber(op2)) !== false) { - L.stack[ra].setfltvalue(llimits.luai_nummod(L, numberop1, numberop2)); + L.stack[ra].setfltvalue(luai_nummod(L, numberop1, numberop2)); } else { ltm.luaT_trybinTM(L, op1, op2, L.stack[ra], ltm.TMS.TM_MOD); } break; } - case OCi.OP_POW: { + case OP_POW: { let op1 = RKB(L, base, k, i); let op2 = RKC(L, base, k, i); let numberop1, numberop2; @@ -263,7 +339,7 @@ const luaV_execute = function(L) { } break; } - case OCi.OP_DIV: { + case OP_DIV: { let op1 = RKB(L, base, k, i); let op2 = RKC(L, base, k, i); let numberop1, numberop2; @@ -275,7 +351,7 @@ const luaV_execute = function(L) { } break; } - case OCi.OP_IDIV: { + case OP_IDIV: { let op1 = RKB(L, base, k, i); let op2 = RKC(L, base, k, i); let numberop1, numberop2; @@ -289,7 +365,7 @@ const luaV_execute = function(L) { } break; } - case OCi.OP_BAND: { + case OP_BAND: { let op1 = RKB(L, base, k, i); let op2 = RKC(L, base, k, i); let numberop1, numberop2; @@ -301,7 +377,7 @@ const luaV_execute = function(L) { } break; } - case OCi.OP_BOR: { + case OP_BOR: { let op1 = RKB(L, base, k, i); let op2 = RKC(L, base, k, i); let numberop1, numberop2; @@ -313,7 +389,7 @@ const luaV_execute = function(L) { } break; } - case OCi.OP_BXOR: { + case OP_BXOR: { let op1 = RKB(L, base, k, i); let op2 = RKC(L, base, k, i); let numberop1, numberop2; @@ -325,7 +401,7 @@ const luaV_execute = function(L) { } break; } - case OCi.OP_SHL: { + case OP_SHL: { let op1 = RKB(L, base, k, i); let op2 = RKC(L, base, k, i); let numberop1, numberop2; @@ -337,7 +413,7 @@ const luaV_execute = function(L) { } break; } - case OCi.OP_SHR: { + case OP_SHR: { let op1 = RKB(L, base, k, i); let op2 = RKC(L, base, k, i); let numberop1, numberop2; @@ -349,7 +425,7 @@ const luaV_execute = function(L) { } break; } - case OCi.OP_UNM: { + case OP_UNM: { let op = L.stack[RB(L, base, i)]; let numberop; @@ -362,7 +438,7 @@ const luaV_execute = function(L) { } break; } - case OCi.OP_BNOT: { + case OP_BNOT: { let op = L.stack[RB(L, base, i)]; if (op.ttisinteger()) { @@ -372,16 +448,16 @@ const luaV_execute = function(L) { } break; } - case OCi.OP_NOT: { + case OP_NOT: { let op = L.stack[RB(L, base, i)]; L.stack[ra].setbvalue(op.l_isfalse()); break; } - case OCi.OP_LEN: { + case OP_LEN: { luaV_objlen(L, L.stack[ra], L.stack[RB(L, base, i)]); break; } - case OCi.OP_CONCAT: { + case OP_CONCAT: { let b = i.B; let c = i.C; L.top = base + c + 1; /* mark the end of concat operands */ @@ -391,39 +467,39 @@ const luaV_execute = function(L) { ldo.adjust_top(L, ci.top); /* restore top */ break; } - case OCi.OP_JMP: { + case OP_JMP: { dojump(L, ci, i, 0); break; } - case OCi.OP_EQ: { + case OP_EQ: { if (luaV_equalobj(L, RKB(L, base, k, i), RKC(L, base, k, i)) !== i.A) ci.l_savedpc++; else donextjump(L, ci); break; } - case OCi.OP_LT: { + case OP_LT: { if (luaV_lessthan(L, RKB(L, base, k, i), RKC(L, base, k, i)) !== i.A) ci.l_savedpc++; else donextjump(L, ci); break; } - case OCi.OP_LE: { + case OP_LE: { if (luaV_lessequal(L, RKB(L, base, k, i), RKC(L, base, k, i)) !== i.A) ci.l_savedpc++; else donextjump(L, ci); break; } - case OCi.OP_TEST: { + case OP_TEST: { if (i.C ? L.stack[ra].l_isfalse() : !L.stack[ra].l_isfalse()) ci.l_savedpc++; else donextjump(L, ci); break; } - case OCi.OP_TESTSET: { + case OP_TESTSET: { let rbIdx = RB(L, base, i); let rb = L.stack[rbIdx]; if (i.C ? rb.l_isfalse() : !rb.l_isfalse()) @@ -434,7 +510,7 @@ const luaV_execute = function(L) { } break; } - case OCi.OP_CALL: { + case OP_CALL: { let b = i.B; let nresults = i.C - 1; if (b !== 0) ldo.adjust_top(L, ra+b); /* else previous instruction set top */ @@ -448,7 +524,7 @@ const luaV_execute = function(L) { break; } - case OCi.OP_TAILCALL: { + case OP_TAILCALL: { let b = i.B; if (b !== 0) ldo.adjust_top(L, ra+b); /* else previous instruction set top */ if (ldo.luaD_precall(L, ra, LUA_MULTRET)) { // JS function @@ -472,13 +548,13 @@ const luaV_execute = function(L) { oci.next = null; ci = L.ci = oci; - assert(L.top === oci.l_base + L.stack[ofuncOff].value.p.maxstacksize); + lua_assert(L.top === oci.l_base + L.stack[ofuncOff].value.p.maxstacksize); continue newframe; } break; } - case OCi.OP_RETURN: { + case OP_RETURN: { if (cl.p.p.length > 0) lfunc.luaF_close(L, base); let b = ldo.luaD_poscall(L, ci, ra, (i.B !== 0 ? i.B - 1 : L.top - ra)); @@ -487,11 +563,11 @@ const luaV_execute = function(L) { /* invocation via reentry: continue execution */ ci = L.ci; if (b) ldo.adjust_top(L, ci.top); - assert(ci.callstatus & lstate.CIST_LUA); - assert(ci.l_code[ci.l_savedpc - 1].opcode === OCi.OP_CALL); + lua_assert(ci.callstatus & lstate.CIST_LUA); + lua_assert(ci.l_code[ci.l_savedpc - 1].opcode === OP_CALL); continue newframe; } - case OCi.OP_FORLOOP: { + case OP_FORLOOP: { if (L.stack[ra].ttisinteger()) { /* integer loop? */ let step = L.stack[ra + 2].value; let idx = (L.stack[ra].value + step)|0; @@ -515,7 +591,7 @@ const luaV_execute = function(L) { } break; } - case OCi.OP_FORPREP: { + case OP_FORPREP: { let init = L.stack[ra]; let plimit = L.stack[ra + 1]; let pstep = L.stack[ra + 2]; @@ -529,20 +605,20 @@ const luaV_execute = function(L) { } else { /* try making all values floats */ let nlimit, nstep, ninit; if ((nlimit = tonumber(plimit)) === false) - ldebug.luaG_runerror(L, defs.to_luastring("'for' limit must be a number", true)); + ldebug.luaG_runerror(L, to_luastring("'for' limit must be a number", true)); L.stack[ra + 1].setfltvalue(nlimit); if ((nstep = tonumber(pstep)) === false) - ldebug.luaG_runerror(L, defs.to_luastring("'for' step must be a number", true)); + ldebug.luaG_runerror(L, to_luastring("'for' step must be a number", true)); L.stack[ra + 2].setfltvalue(nstep); if ((ninit = tonumber(init)) === false) - ldebug.luaG_runerror(L, defs.to_luastring("'for' initial value must be a number", true)); + ldebug.luaG_runerror(L, to_luastring("'for' initial value must be a number", true)); L.stack[ra].setfltvalue(ninit - nstep); } ci.l_savedpc += i.sBx; break; } - case OCi.OP_TFORCALL: { + case OP_TFORCALL: { let cb = ra + 3; /* call base */ lobject.setobjs2s(L, cb+2, ra+2); lobject.setobjs2s(L, cb+1, ra+1); @@ -553,29 +629,29 @@ const luaV_execute = function(L) { /* go straight to OP_TFORLOOP */ i = ci.l_code[ci.l_savedpc++]; ra = RA(L, base, i); - assert(i.opcode === OCi.OP_TFORLOOP); + lua_assert(i.opcode === OP_TFORLOOP); } /* fall through */ - case OCi.OP_TFORLOOP: { + case OP_TFORLOOP: { if (!L.stack[ra + 1].ttisnil()) { /* continue loop? */ lobject.setobjs2s(L, ra, ra + 1); /* save control variable */ ci.l_savedpc += i.sBx; /* jump back */ } break; } - case OCi.OP_SETLIST: { + case OP_SETLIST: { let n = i.B; let c = i.C; if (n === 0) n = L.top - ra - 1; if (c === 0) { - assert(ci.l_code[ci.l_savedpc].opcode === OCi.OP_EXTRAARG); + lua_assert(ci.l_code[ci.l_savedpc].opcode === OP_EXTRAARG); c = ci.l_code[ci.l_savedpc++].Ax; } let h = L.stack[ra].value; - let last = ((c - 1) * lopcodes.LFIELDS_PER_FLUSH) + n; + let last = ((c - 1) * LFIELDS_PER_FLUSH) + n; for (; n > 0; n--) { ltable.luaH_setint(h, last--, L.stack[ra + n]); @@ -583,7 +659,7 @@ const luaV_execute = function(L) { ldo.adjust_top(L, ci.top); /* correct top (in case of previous open call) */ break; } - case OCi.OP_CLOSURE: { + case OP_CLOSURE: { let p = cl.p.p[i.Bx]; let ncl = getcached(p, cl.upvals, L.stack, base); /* cached closure */ if (ncl === null) /* no match? */ @@ -592,7 +668,7 @@ const luaV_execute = function(L) { L.stack[ra].setclLvalue(ncl); break; } - case OCi.OP_VARARG: { + case OP_VARARG: { let b = i.B - 1; let n = base - ci.funcOff - cl.p.numparams - 1; let j; @@ -613,7 +689,7 @@ const luaV_execute = function(L) { L.stack[ra + j].setnilvalue(); break; } - case OCi.OP_EXTRAARG: { + case OP_EXTRAARG: { throw Error("invalid opcode"); } } @@ -667,7 +743,7 @@ const luaV_lessequal = function(L, l, r) { const luaV_equalobj = function(L, t1, t2) { if (t1.ttype() !== t2.ttype()) { /* not the same variant? */ - if (t1.ttnov() !== t2.ttnov() || t1.ttnov() !== CT.LUA_TNUMBER) + if (t1.ttnov() !== t2.ttnov() || t1.ttnov() !== LUA_TNUMBER) return 0; /* only numbers can be equal with different variants */ else { /* two numbers with different variants */ /* OPTIMIZATION: instead of calling luaV_tointeger we can just let JS do the comparison */ @@ -679,21 +755,21 @@ const luaV_equalobj = function(L, t1, t2) { /* values have same type and same variant */ switch(t1.ttype()) { - case CT.LUA_TNIL: + case LUA_TNIL: return 1; - case CT.LUA_TBOOLEAN: + case LUA_TBOOLEAN: return t1.value == t2.value ? 1 : 0; // Might be 1 or true - case CT.LUA_TLIGHTUSERDATA: - case CT.LUA_TNUMINT: - case CT.LUA_TNUMFLT: - case CT.LUA_TLCF: + case LUA_TLIGHTUSERDATA: + case LUA_TNUMINT: + case LUA_TNUMFLT: + case LUA_TLCF: return t1.value === t2.value ? 1 : 0; - case CT.LUA_TSHRSTR: - case CT.LUA_TLNGSTR: { - return lstring.luaS_eqlngstr(t1.tsvalue(), t2.tsvalue()) ? 1 : 0; + case LUA_TSHRSTR: + case LUA_TLNGSTR: { + return luaS_eqlngstr(t1.tsvalue(), t2.tsvalue()) ? 1 : 0; } - case CT.LUA_TUSERDATA: - case CT.LUA_TTABLE: + case LUA_TUSERDATA: + case LUA_TTABLE: if (t1.value === t2.value) return 1; else if (L === null) return 0; @@ -726,10 +802,10 @@ const forlimit = function(obj, step) { return false; if (0 < n) { - ilimit = luaconf.LUA_MAXINTEGER; + ilimit = LUA_MAXINTEGER; if (step < 0) stopnow = true; } else { - ilimit = luaconf.LUA_MININTEGER; + ilimit = LUA_MININTEGER; if (step >= 0) stopnow = true; } } @@ -758,7 +834,7 @@ const luaV_tointeger = function(obj, mode) { f += 1; /* convert floor to ceil (remember: n !== f) */ } - return luaconf.lua_numbertointeger(f); + return lua_numbertointeger(f); } else if (obj.ttisinteger()) { return obj.value; } else if (cvt2num(obj)) { @@ -775,7 +851,7 @@ const tointeger = function(o) { }; const tonumber = function(o) { - if (o.ttnov() === CT.LUA_TNUMBER) + if (o.ttnov() === LUA_TNUMBER) return o.value; if (cvt2num(o)) { /* string convertible to number? */ @@ -808,8 +884,8 @@ const LEnum = function(l, r) { ** -larger than zero if 'ls' is smaller-equal-larger than 'rs'. */ const l_strcmp = function(ls, rs) { - let l = lstring.luaS_hashlongstr(ls); - let r = lstring.luaS_hashlongstr(rs); + let l = luaS_hashlongstr(ls); + let r = luaS_hashlongstr(rs); /* In fengari we assume string hash has same collation as byte values */ if (l === r) return 0; @@ -825,21 +901,21 @@ const l_strcmp = function(ls, rs) { const luaV_objlen = function(L, ra, rb) { let tm; switch(rb.ttype()) { - case CT.LUA_TTABLE: { + case LUA_TTABLE: { let h = rb.value; tm = ltm.fasttm(L, h.metatable, ltm.TMS.TM_LEN); if (tm !== null) break; /* metamethod? break switch to call it */ ra.setivalue(ltable.luaH_getn(h)); /* else primitive len */ return; } - case CT.LUA_TSHRSTR: - case CT.LUA_TLNGSTR: + case LUA_TSHRSTR: + case LUA_TLNGSTR: ra.setivalue(rb.vslen()); return; default: { tm = ltm.luaT_gettmbyobj(L, rb, ltm.TMS.TM_LEN); if (tm.ttisnil()) - ldebug.luaG_typeerror(L, rb, defs.to_luastring("get length of", true)); + ldebug.luaG_typeerror(L, rb, to_luastring("get length of", true)); break; } } @@ -847,16 +923,29 @@ const luaV_objlen = function(L, ra, rb) { ltm.luaT_callTM(L, tm, rb, rb, ra, 1); }; +/* Shim taken from https://developer.mozilla.org/en-US/docs/Web/JavaScript/Reference/Global_Objects/Math/imul */ +const luaV_imul = Math.imul || function(a, b) { + let aHi = (a >>> 16) & 0xffff; + let aLo = a & 0xffff; + let bHi = (b >>> 16) & 0xffff; + let bLo = b & 0xffff; + /* + ** the shift by 0 fixes the sign on the high part + ** the final |0 converts the unsigned value into a signed value + */ + return ((aLo * bLo) + (((aHi * bLo + aLo * bHi) << 16) >>> 0) | 0); +}; + const luaV_div = function(L, m, n) { if (n === 0) - ldebug.luaG_runerror(L, defs.to_luastring("attempt to divide by zero")); + ldebug.luaG_runerror(L, to_luastring("attempt to divide by zero")); return Math.floor(m / n)|0; }; // % semantic on negative numbers is different in js const luaV_mod = function(L, m, n) { if (n === 0) - ldebug.luaG_runerror(L, defs.to_luastring("attempt to perform 'n%%0'")); + ldebug.luaG_runerror(L, to_luastring("attempt to perform 'n%%0'")); return (m - Math.floor(m / n) * n)|0; }; @@ -884,8 +973,8 @@ const getcached = function(p, encup, stack, base) { let uv = p.upvalues; let nup = uv.length; for (let i = 0; i < nup; i++) { /* check whether it has right upvalues */ - let v = uv[i].instack ? stack[base + uv[i].idx] : encup[uv[i].idx].v; - if (c.upvals[i].v !== v) + let v = uv[i].instack ? stack[base + uv[i].idx] : encup[uv[i].idx]; + if (c.upvals[i] !== v) return null; /* wrong upvalue; cannot reuse closure */ } } @@ -907,7 +996,6 @@ const pushclosure = function(L, p, encup, base, ra) { ncl.upvals[i] = lfunc.luaF_findupval(L, base + uv[i].idx); else ncl.upvals[i] = encup[uv[i].idx]; - ncl.upvals[i].refcount++; } p.cache = ncl; /* save it on cache for reuse */ }; @@ -954,7 +1042,7 @@ const copy2buff = function(L, top, n, buff) { ** from 'L->top - total' up to 'L->top - 1'. */ const luaV_concat = function(L, total) { - assert(total >= 2); + lua_assert(total >= 2); do { let top = L.top; let n = 2; /* number of elements handled in this pass (at least 2) */ @@ -975,7 +1063,7 @@ const luaV_concat = function(L, total) { } let buff = new Uint8Array(tl); copy2buff(L, top, n, buff); - let ts = lstring.luaS_bless(L, buff); + let ts = luaS_bless(L, buff); lobject.setsvalue2s(L, top - n, ts); } total -= n - 1; /* got 'n' strings to create 1 new */ @@ -994,7 +1082,7 @@ const luaV_gettable = function(L, t, key, ra) { if (!t.ttistable()) { tm = ltm.luaT_gettmbyobj(L, t, ltm.TMS.TM_INDEX); if (tm.ttisnil()) - ldebug.luaG_typeerror(L, t, defs.to_luastring('index', true)); /* no metamethod */ + ldebug.luaG_typeerror(L, t, to_luastring('index', true)); /* no metamethod */ /* else will try the metamethod */ } else { let slot = ltable.luaH_get(L, t.value, key); @@ -1017,7 +1105,7 @@ const luaV_gettable = function(L, t, key, ra) { t = tm; /* else try to access 'tm[key]' */ } - ldebug.luaG_runerror(L, defs.to_luastring("'__index' chain too long; possible loop", true)); + ldebug.luaG_runerror(L, to_luastring("'__index' chain too long; possible loop", true)); }; const settable = function(L, t, key, val) { @@ -1037,7 +1125,7 @@ const settable = function(L, t, key, val) { /* else will try the metamethod */ } else { /* not a table; check metamethod */ if ((tm = ltm.luaT_gettmbyobj(L, t, ltm.TMS.TM_NEWINDEX)).ttisnil()) - ldebug.luaG_typeerror(L, t, defs.to_luastring('index', true)); + ldebug.luaG_typeerror(L, t, to_luastring('index', true)); } /* try the metamethod */ if (tm.ttisfunction()) { @@ -1047,7 +1135,7 @@ const settable = function(L, t, key, val) { t = tm; /* else repeat assignment over 'tm' */ } - ldebug.luaG_runerror(L, defs.to_luastring("'__newindex' chain too long; possible loop", true)); + ldebug.luaG_runerror(L, to_luastring("'__newindex' chain too long; possible loop", true)); }; @@ -1059,6 +1147,7 @@ module.exports.luaV_div = luaV_div; module.exports.luaV_equalobj = luaV_equalobj; module.exports.luaV_execute = luaV_execute; module.exports.luaV_finishOp = luaV_finishOp; +module.exports.luaV_imul = luaV_imul; module.exports.luaV_lessequal = luaV_lessequal; module.exports.luaV_lessthan = luaV_lessthan; module.exports.luaV_mod = luaV_mod; diff --git a/src/lzio.js b/src/lzio.js index a00a24b..b9081a7 100644 --- a/src/lzio.js +++ b/src/lzio.js @@ -1,7 +1,6 @@ "use strict"; -const assert = require('assert'); - +const { lua_assert } = require("./llimits.js"); class MBuffer { constructor() { @@ -32,7 +31,7 @@ const luaZ_resizebuffer = function(L, buff, size) { class ZIO { constructor(L, reader, data) { this.L = L; /* Lua state (for reader) */ - assert(typeof reader == "function", "ZIO requires a reader"); + lua_assert(typeof reader == "function", "ZIO requires a reader"); this.reader = reader; /* reader function */ this.data = data; /* additional data */ this.n = 0; /* bytes still unread */ @@ -51,7 +50,7 @@ const luaZ_fill = function(z) { let buff = z.reader(z.L, z.data); if (buff === null) return EOZ; - assert(buff instanceof Uint8Array, "Should only load binary of array of bytes"); + lua_assert(buff instanceof Uint8Array, "Should only load binary of array of bytes"); let size = buff.length; if (size === 0) return EOZ; |