diff options
Diffstat (limited to 'src/defs.js')
-rw-r--r-- | src/defs.js | 382 |
1 files changed, 215 insertions, 167 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; |