aboutsummaryrefslogtreecommitdiff
path: root/src
diff options
context:
space:
mode:
authorBenoit Giannangeli <giann008@gmail.com>2017-03-30 11:58:09 +0200
committerBenoit Giannangeli <giann008@gmail.com>2017-03-30 14:39:19 +0200
commit3813f2d43054708bab7221a5ca74a0183a2ebcaf (patch)
tree2e27bc81114099cbf94b18e2c139843e66db6b53 /src
parent456ab7b69f88859683c60cc2261e70d6dbadd8e8 (diff)
downloadfengari-3813f2d43054708bab7221a5ca74a0183a2ebcaf.tar.gz
fengari-3813f2d43054708bab7221a5ca74a0183a2ebcaf.tar.bz2
fengari-3813f2d43054708bab7221a5ca74a0183a2ebcaf.zip
8-bit only in lstrlib
Diffstat (limited to 'src')
-rw-r--r--src/lapi.js4
-rw-r--r--src/lauxlib.js2
-rw-r--r--src/ldebug.js6
-rw-r--r--src/llex.js14
-rw-r--r--src/lobject.js39
-rw-r--r--src/lparser.js3
-rw-r--r--src/lstrlib.js427
-rw-r--r--src/lua.js6
8 files changed, 257 insertions, 244 deletions
diff --git a/src/lapi.js b/src/lapi.js
index e7fbf4f..a7d7033 100644
--- a/src/lapi.js
+++ b/src/lapi.js
@@ -748,8 +748,10 @@ const lua_rawequal = function(L, index1, index2) {
*/
const lua_load = function(L, reader, data, chunckname, mode) {
+ assert(Array.isArray(chunckname), "lua_load expect an array of byte as chunckname");
+ assert(mode ? Array.isArray(mode) : true, "lua_load expect an array of byte as mode");
let z = new llex.MBuffer(L, data, reader);
- if (!chunckname) chunckname = "?";
+ if (!chunckname) chunckname = [lua.char["?"]];
let status = ldo.luaD_protectedparser(L, z, chunckname, mode);
if (status === TS.LUA_OK) { /* no errors? */
let f = L.stack[L.top - 1]; /* get newly created function */
diff --git a/src/lauxlib.js b/src/lauxlib.js
index 9813095..90cff5c 100644
--- a/src/lauxlib.js
+++ b/src/lauxlib.js
@@ -89,7 +89,7 @@ const luaL_argerror = function(L, arg, extramsg) {
}
if (ar.name === null)
- ar.name = pushglobalfuncname(L, ar) ? lapi.lua_tostring(L, -1) : "?";
+ ar.name = pushglobalfuncname(L, ar) ? lapi.lua_tostring(L, -1) : [lua.char["?"]];
return luaL_error(L, lua.to_luastring(`bad argument #${arg} to '${lobject.jsstring(ar.name)}' (${lobject.jsstring(extramsg)})`));
};
diff --git a/src/ldebug.js b/src/ldebug.js
index 0fba4cb..3d66d85 100644
--- a/src/ldebug.js
+++ b/src/ldebug.js
@@ -205,7 +205,7 @@ const kname = function(p, pc, c) {
}
/* else no reasonable name found */
}
- r.name = "?";
+ r.name = [lua.char["?"]];
return r; /* no reasonable name found */
};
@@ -342,7 +342,7 @@ const funcnamefromcode = function(L, ci) {
let i = p.code[pc]; /* calling instruction */
if (ci.callstatus & lstate.CIST_HOOKED) {
- r.name = "?";
+ r.name = [lua.char["?"]];
r.funcname = lua.to_luastring("hook");
return r;
}
@@ -388,7 +388,7 @@ const funcnamefromcode = function(L, ci) {
return null; /* cannot find a reasonable name */
}
- r.name = L.l_G.tmname[tm].jsstring();
+ r.name = L.l_G.tmname[tm];
r.funcname = lua.to_luastring("metamethod");
return r;
};
diff --git a/src/llex.js b/src/llex.js
index e043c17..3ed0e56 100644
--- a/src/llex.js
+++ b/src/llex.js
@@ -12,15 +12,10 @@ const lua = require('./lua.js');
const TValue = lobject.TValue;
const CT = lua.constant_types;
const TS = lua.thread_status;
+const char = lua.char;
const FIRST_RESERVED = 257;
-// To avoid charCodeAt everywhere
-const char = [];
-for (let i = 0; i < 127; i++)
- char[String.fromCharCode(i)] = i;
-module.exports.char = char;
-
const RESERVED = {
/* terminal symbols denoted by reserved words */
TK_AND: FIRST_RESERVED,
@@ -87,7 +82,8 @@ class MBuffer {
this.reader = reader ? reader : null;
if (!this.reader) {
- this.buffer = typeof data === "string" ? lua.to_luastring(data) : (data ? data : []);
+ assert(typeof data !== "string", "Should only load binary of array of bytes");
+ this.buffer = data ? data : [];
this.n = this.buffer instanceof DataView ? this.buffer.byteLength : this.buffer.length;
this.off = 0;
}
@@ -103,7 +99,7 @@ class MBuffer {
fill() {
if (this.reader) {
this.buffer = this.reader(this.L, this.data);
- this.buffer = typeof this.buffer === "string" ? lua.to_luastring(this.buffer) : this.buffer;
+ assert(typeof this.buffer !== "string", "Should only load binary of array of bytes");
if (this.buffer === null)
return -1;
this.n = this.buffer instanceof DataView ? this.buffer.byteLength - 1 : this.buffer.length - 1;
@@ -418,7 +414,7 @@ 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 + parseInt(ls.current);
+ r = 10 * r + ls.current - char['0'];
save_and_next(ls);
}
esccheck(ls, r <= 255, lua.to_luastring("decimal escape too large"));
diff --git a/src/lobject.js b/src/lobject.js
index e958975..b2cffe3 100644
--- a/src/lobject.js
+++ b/src/lobject.js
@@ -8,6 +8,7 @@ const lua = require('./lua.js');
const luaconf = require('./luaconf.js');
const CT = lua.constant_types;
const UpVal = require('./lfunc.js').UpVal;
+const char = lua.char;
let tvalueCount = 0;
@@ -291,13 +292,13 @@ const luaO_chunkid = function(source, bufflen) {
bufflen = bufflen instanceof TValue ? bufflen.value : bufflen;
let l = source.length;
let out = [];
- if (source[0] === '='.charCodeAt(0)) { /* 'literal' source */
+ if (source[0] === char['=']) { /* 'literal' source */
if (l < bufflen) /* small enough? */
out = source.slice(1);
else { /* truncate it */
out = out.concat(source.slice(1, bufflen));
}
- } else if (source[0] === '@'.charCodeAt(0)) { /* file name */
+ } else if (source[0] === char['@']) { /* file name */
if (l <= bufflen) /* small enough? */
out = source.slice(1);
else { /* add '...' before rest of name */
@@ -323,8 +324,8 @@ const luaO_chunkid = function(source, bufflen) {
};
const luaO_hexavalue = function(c) {
- if (ljstype.lisdigit(c)) return c - '0'.charCodeAt(0);
- else return (String.fromCharCode(c).toLowerCase().charCodeAt(0) - 'a'.charCodeAt(0)) + 10;
+ if (ljstype.lisdigit(c)) return c - char['0'];
+ else return (String.fromCharCode(c).toLowerCase().charCodeAt(0) - char['a']) + 10;
};
const UTF8BUFFSZ = 8;
@@ -379,7 +380,7 @@ const ldexp = function(mantissa, exponent) {
** C99 specification for 'strtod'
*/
const lua_strx2number = function(s) {
- let dot = luaconf.lua_getlocaledecpoint();
+ let dot = char[luaconf.lua_getlocaledecpoint()];
let r = 0.0; /* result (accumulator) */
let sigdig = 0; /* number of significant digits */
let nosigdig = 0; /* number of non-significant digits */
@@ -387,11 +388,11 @@ const lua_strx2number = function(s) {
let neg; /* 1 if number is negative */
let hasdot = false; /* true after seen a dot */
- while (ljstype.lisspace(s)) s = s.slice(1); /* skip initial spaces */
+ while (ljstype.lisspace(s[0])) s = s.slice(1); /* skip initial spaces */
- neg = s[0] === '-'.charCodeAt(0); /* check signal */
- s = neg || s[0] === '+'.charCodeAt(0) ? s.slice(1) : s; /* skip sign if one */
- if (!(s[0] === '0' && (s[1] === 'x'.charCodeAt(0) || s[1] === 'X'.charCodeAt(0)))) /* check '0x' */
+ neg = s[0] === char['-']; /* check signal */
+ s = neg || s[0] === char['+'] ? s.slice(1) : s; /* skip sign if one */
+ if (!(s[0] === char['0'] && (s[1] === char['x'] || s[1] === char['X']))) /* check '0x' */
return 0.0; /* invalid format (no '0x') */
for (s = s.slice(2); ; s = s.slice(1)) { /* skip '0x' and read numeral */
@@ -399,10 +400,10 @@ const lua_strx2number = function(s) {
if (hasdot) break; /* second dot? stop loop */
else hasdot = true;
} else if (ljstype.lisxdigit(s[0])) {
- if (sigdig === 0 && s[0] === '0'.charCodeAt(0)) /* non-significant digit (zero)? */
+ if (sigdig === 0 && s[0] === char['0']) /* non-significant digit (zero)? */
nosigdig++;
else if (++sigdig <= MAXSIGDIG) /* can read it without overflow? */
- r = (r * 16) + luaO_hexavalue(s);
+ r = (r * 16) + luaO_hexavalue(s[0]);
else e++; /* too many digits; ignore, but still count for exponent */
if (hasdot) e--; /* decimal digit? correct exponent */
} else break; /* neither a dot nor a digit */
@@ -411,16 +412,16 @@ const lua_strx2number = function(s) {
if (nosigdig + sigdig === 0) /* no digits? */
return 0.0; /* invalid format */
e *= 4; /* each digit multiplies/divides value by 2^4 */
- if (s[0] === 'p'.charCodeAt(0) || s[0] === 'P'.charCodeAt(0)) { /* exponent part? */
+ if (s[0] === char['p'] || s[0] === char['P']) { /* exponent part? */
let exp1 = 0; /* exponent value */
let neg1; /* exponent signal */
s = s.slice(1); /* skip 'p' */
- neg1 = s[0] === '-'.charCodeAt(0); /* check signal */
- s = neg1 || s[0] === '+'.charCodeAt(0) ? s.slice(1) : s; /* skip sign if one */
+ neg1 = s[0] === char['-']; /* check signal */
+ s = neg1 || s[0] === char['+'] ? s.slice(1) : s; /* skip sign if one */
if (!ljstype.lisdigit(s[0]))
return 0.0; /* invalid; must have at least one digit */
while (ljstype.lisdigit(s[0])) { /* read exponent */
- exp1 = exp1 * 10 + s - '0'.charCodeAt(0);
+ exp1 = exp1 * 10 + s[0] - char['0'];
s = s.slice(1);
}
if (neg1) exp1 = -exp1;
@@ -458,12 +459,12 @@ const l_str2int = function(s) {
let neg;
while (ljstype.lisspace(s[0])) s = s.slice(1); /* skip initial spaces */
- neg = s[0] === '-'.charCodeAt(0);
+ neg = s[0] === char['-'];
- if (neg || s[0] === '+'.charCodeAt(0))
+ if (neg || s[0] === char['+'])
s = s.slice(1);
- if (s[0] === '0'.charCodeAt(0) && (s[1] === 'x'.charCodeAt(0) || s[1] === 'X'.charCodeAt(0))) { /* hex? */
+ if (s[0] === char['0'] && (s[1] === char['x'] || s[1] === char['X'])) { /* hex? */
s = s.slice(2); /* skip '0x' */
for (; ljstype.lisxdigit(s[0]); s = s.slice(1)) {
@@ -472,7 +473,7 @@ const l_str2int = function(s) {
}
} else { /* decimal */
for (; ljstype.lisdigit(s[0]); s = s.slice(1)) {
- let d = s[0] - '0'.charCodeAt(0);
+ let d = s[0] - char['0'];
if (a >= MAXBY10 && (a > MAXBY10 || d > MAXLASTD + neg)) /* overflow? */
return null; /* do not accept it (as integer) */
a = a * 10 + d;
diff --git a/src/lparser.js b/src/lparser.js
index 249d51f..73caf70 100644
--- a/src/lparser.js
+++ b/src/lparser.js
@@ -17,8 +17,7 @@ const TValue = lobject.TValue;
const Table = lobject.Table;
const UnOpr = lcode.UnOpr;
const UpVal = lfunc.UpVal;
-
-const char = llex.char;
+const char = lua.char;
const MAXVARS = 200;
diff --git a/src/lstrlib.js b/src/lstrlib.js
index e163485..c132e02 100644
--- a/src/lstrlib.js
+++ b/src/lstrlib.js
@@ -9,9 +9,10 @@ const lobject = require('./lobject.js');
const lua = require('./lua.js');
const luaconf = require('./luaconf.js');
const CT = lua.constant_types;
+const char = lua.char;
const sL_ESC = '%';
-const L_ESC = sL_ESC.charCodeAt(0);
+const L_ESC = char[sL_ESC];
/*
** maximum number of captures that a pattern can do during
@@ -41,7 +42,7 @@ const str_sub = function(L) {
if (start < 1) start = 1;
if (end > l) end = l;
if (start <= end)
- lapi.lua_pushstring(L, ts.jsstring(start - 1, (start - 1) + (end - start + 1)));
+ lapi.lua_pushstring(L, ts.value.slice(start - 1, (start - 1) + (end - start + 1)));
else lapi.lua_pushliteral(L, "");
return 1;
};
@@ -59,8 +60,7 @@ const str_char = function(L) {
lauxlib.luaL_argcheck(L, c >= 0 && c <= 255, "value out of range"); // Strings are 8-bit clean
p.push(c);
}
- lapi.lua_pushstring(L, "");
- L.stack[L.top - 1].value = p; // Since value are already capped, avoid conversion
+ lapi.lua_pushstring(L, p);
return 1;
};
@@ -77,7 +77,7 @@ const str_dump = function(L) {
lapi.lua_settop(L, 1);
if (lapi.lua_dump(L, writer, b, strip) !== 0)
return lauxlib.luaL_error(L, "unable to dump given function");
- L.stack[L.top++] = new lobject.TValue(CT.LUA_TLNGSTR, b); // We don't want lua > js > lua string conversion here
+ lapi.lua_pushstring(L, b);
return 1;
};
@@ -90,7 +90,7 @@ const L_NBFD = 1;
*/
const adddigit = function(buff, n, x) {
let d = Math.floor(x); /* get integer part from 'x' */
- buff[n] = d < 10 ? d + '0'.charCodeAt(0) : d - 10 + 'a'.charCodeAt(0); /* add to buffer */
+ buff[n] = d < 10 ? d + char['0'] : d - 10 + char['a']; /* add to buffer */
return x - d; /* return what is left */
};
@@ -108,11 +108,11 @@ const num2straux = function(x) {
let e = fe[1];
let n = 0; /* character count */
if (m < 0) { /* is number negative? */
- buff[n++] = '-'.charCodeAt(0); /* add signal */
+ buff[n++] = char['-']; /* add signal */
m = -m; /* make it positive */
}
- buff[n++] = '0'.charCodeAt(0);
- buff[n++] = 'x'.charCodeAt(0); /* add "0x" */
+ buff[n++] = char['0'];
+ buff[n++] = char['x']; /* add "0x" */
m = adddigit(buff, n++, m * (1 << L_NBFD)); /* add first digit */
e -= L_NBFD; /* this digit goes before the radix point */
if (m > 0) { /* more digits? */
@@ -128,11 +128,11 @@ const num2straux = function(x) {
const lua_number2strx = function(L, fmt, x) {
let buff = num2straux(x);
- if (fmt.charAt(SIZELENMOD) === 'A') {
+ if (fmt[SIZELENMOD] === char['A']) {
for (let i = 0; i < buff.length; i++)
- buff[i] = String.fromCharCode(buff[i]).toUpperCase().charCodeAt(0);
- } else if (fmt.charAt(SIZELENMOD) !== 'a')
- lauxlib.luaL_error(L, "modifiers for format '%a'/'%A' not implemented");
+ buff[i] = char[String.fromCharCode(buff[i]).toUpperCase()];
+ } else if (fmt[SIZELENMOD] !== char['a'])
+ lauxlib.luaL_error(L, lua.to_luastring("modifiers for format '%a'/'%A' not implemented"));
return buff;
};
@@ -147,24 +147,24 @@ const MAX_ITEM = 120;// TODO: + l_mathlim(MAX_10_EXP);
/* valid flags in a format specification */
-const FLAGS = ["-", "+", " ", "#", "0"].map(e => e.charCodeAt(0));
+const FLAGS = [char["-"], char["+"], char[" "], char["#"], char["0"]];
/*
** maximum size of each format specification (such as "%-099.99d")
*/
const MAX_FORMAT = 32;
-// TODO: locale ?
-const isalpha = e => /^[a-zA-Z]$/.test(e.charAt(0));
-const isdigit = e => "0".charCodeAt(0) <= e && e <= "9".charCodeAt(0);
+// TODO: locale ? and do it better
+const isalpha = e => (char['a'] <= e && e <= char['z']) || (e >= char['A'] && e <= char['Z']);
+const isdigit = e => char['0'] <= e && e <= char['9'];
const iscntrl = e => (0x00 <= e && e <= 0x1f) || e === 0x7f;
-const isgraph = e => e.charCodeAt(0) > 32 && e.charCodeAt(0) < 127; // TODO: Will only work for ASCII
-const islower = e => /^(?![A-Z]).*$/.test(e.charAt(0));
-const isupper = e => /^(?![a-z]).*$/.test(e.charAt(0));
-const isalnum = e => /^[a-zA-Z0-9]$/.test(e.charAt(0));
+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 ispunct = e => isgraph(e) && !isalnum(e);
-const isspace = e => /^\s$/.test(e.charAt(0));
-const isxdigit = e => /^[0-9A-Fa-f]$/.test(e.charAt(0));
+const isspace = e => /^\s$/.test(String.fromCharCode(e));
+const isxdigit = e => /^[0-9A-Fa-f]$/.test(String.fromCharCode(e));
// Concat 2 arrays by modifying the first one
const concat = function (a1, a2) {
@@ -173,11 +173,11 @@ const concat = function (a1, a2) {
};
const addquoted = function(b, s) {
- b.push('"'.charCodeAt(0));
+ b.push(char['"']);
let len = s.length;
while (len--) {
- if (s[0] === '"'.charCodeAt(0) || s[0] === '\\'.charCodeAt(0) || s[0] === '\n'.charCodeAt(0)) {
- b.push('\\'.charCodeAt(0));
+ if (s[0] === char['"'] || s[0] === char['\\'] || s[0] === char['\n']) {
+ b.push(char['\\']);
b.push(s[0]);
} else if (iscntrl(s[0])) {
let buff = [];
@@ -190,15 +190,15 @@ const addquoted = function(b, s) {
b.push(s[0]);
s = s.slice(1);
}
- b.push('"'.charCodeAt(0));
+ b.push(char['"']);
};
/*
** 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 */
+ if (buff.indexOf(char['.']) < 0) { /* no dot? */
+ let point = char[luaconf.lua_getlocaledecpoint()]; /* try locale point */
let ppoint = buff.indexOf(point);
if (ppoint) buff[ppoint] = '.'; /* change it to a dot */
}
@@ -207,14 +207,14 @@ const checkdp = function(buff) {
const addliteral = function(L, b, arg) {
switch(lapi.lua_type(L, arg)) {
case CT.LUA_TSTRING: {
- let s = L.stack[lapi.index2addr_(L, arg)].value;
+ let s = lapi.lua_tostring(L, arg);
addquoted(b, s, s.length);
break;
}
case CT.LUA_TNUMBER: {
if (!lapi.lua_isinteger(L, arg)) { /* float? */
let n = lapi.lua_tonumber(L, arg); /* write as hexa ('%a') */
- concat(b, lua_number2strx(L, `%${luaconf.LUA_INTEGER_FRMLEN}a`, n));
+ concat(b, lua_number2strx(L, lua.to_luastring(`%${luaconf.LUA_INTEGER_FRMLEN}a`), n));
checkdp(b); /* ensure it uses a dot */
} else { /* integers */
let n = lapi.lua_tointeger(L, arg);
@@ -223,13 +223,11 @@ const addliteral = function(L, b, arg) {
break;
}
case CT.LUA_TNIL: case CT.LUA_TBOOLEAN: {
- lauxlib.luaL_tolstring(L, arg);
- concat(b, lapi.index2addr(L, -1).value);
- lapi.lua_remove(L, -1);
+ concat(b, lauxlib.luaL_tolstring(L, arg));
break;
}
default: {
- lauxlib.luaL_argerror(L, arg, "value has no literal form");
+ lauxlib.luaL_argerror(L, arg, lua.to_luastring("value has no literal form"));
}
}
};
@@ -238,17 +236,17 @@ const scanformat = function(L, strfrmt, form) {
let p = strfrmt;
while (p[0] !== 0 && FLAGS.indexOf(p[0]) >= 0) p = p.slice(1); /* skip flags */
if (strfrmt.length - p.length >= FLAGS.length)
- lauxlib.luaL_error(L, "invalid format (repeated flags)");
+ lauxlib.luaL_error(L, lua.to_luastring("invalid format (repeated flags)"));
if (isdigit(p[0])) p = p.slice(1); /* skip width */
if (isdigit(p[0])) p = p.slice(1); /* (2 digits at most) */
- if (p[0] === '.'.charCodeAt(0)) {
+ if (p[0] === char['.']) {
p = p.slice(1);
if (isdigit(p[0])) p = p.slice(1); /* skip precision */
if (isdigit(p[0])) p = p.slice(1); /* (2 digits at most) */
}
if (isdigit(p[0]))
- lauxlib.luaL_error(L, "invalid format (width or precision too long)");
- form[0] = "%".charCodeAt(0);
+ lauxlib.luaL_error(L, lua.to_luastring("invalid format (width or precision too long)"));
+ form[0] = char["%"];
for (let i = 0; i < strfrmt.length - p.length + 1; i++)
form[i + 1] = strfrmt[i];
// form[strfrmt.length - p.length + 2] = 0;
@@ -276,7 +274,6 @@ const str_format = function(L) {
let top = lapi.lua_gettop(L);
let arg = 1;
let strfrmt = lauxlib.luaL_checkstring(L, arg);
- strfrmt = L.stack[lapi.index2addr_(L, 1)].value;
let b = [];
while (strfrmt.length > 0) {
@@ -289,7 +286,7 @@ const str_format = function(L) {
} else { /* format item */
let form = []; /* to store the format ('%...') */
if (++arg > top)
- lauxlib.luaL_argerror(L, arg, "no value");
+ lauxlib.luaL_argerror(L, arg, lua.to_luastring("no value"));
let f = scanformat(L, strfrmt, form);
strfrmt = f.p;
form = f.form;
@@ -329,34 +326,33 @@ const str_format = function(L) {
}
case 's': {
strfrmt = strfrmt.slice(1);
- lauxlib.luaL_tolstring(L, arg); // Convert parameter to string
- let str = lapi.index2addr(L, -1);
- let s = str.value;
- if (form[2] === '\0') { /* no modifiers? */
+ let s = lauxlib.luaL_tolstring(L, arg);
+ if (form[2] === char['\0']) { /* no modifiers? */
concat(b, s); /* keep entire string */
lapi.lua_pop(L, 1); /* remove result from 'luaL_tolstring' */
} else {
let zero = s.indexOf(0);
- lauxlib.luaL_argcheck(L, zero < 0 || zero === s.length - 1, arg, "string contains zeros");
- if (form.indexOf('.'.charCodeAt(0)) < 0 && s.length >= 100) {
+ lauxlib.luaL_argcheck(L, zero < 0 || zero === s.length - 1, arg, lua.to_luastring("string contains zeros"));
+ if (form.indexOf(char['.']) < 0 && s.length >= 100) {
/* no precision and string is too long to be formatted */
concat(b, s); /* keep entire string */
lapi.lua_pop(L, 1); /* remove result from 'luaL_tolstring' */
} else { /* format the string into 'buff' */
- concat(b, lua.to_luastring(sprintf(String.fromCharCode(...form), str.jsstring())));
+ // TODO: will failt if s is not valid UTF-8
+ concat(b, lua.to_luastring(sprintf(String.fromCharCode(...form), lobject.jsstring(s))));
lapi.lua_pop(L, 1); /* remove result from 'luaL_tolstring' */
}
}
break;
}
default: { /* also treat cases 'pnLlh' */
- return lauxlib.luaL_error(L, `invalid option '%${strfrmt[0]}'`);
+ return lauxlib.luaL_error(L, lua.to_luastring(`invalid option '%${String.fromCharCode(strfrmt[0])}'`));
}
}
}
}
- L.stack[L.top++] = new lobject.TValue(CT.LUA_TLNGSTR, b);
+ lapi.lua_pushstring(L, b);
return 1;
};
@@ -403,7 +399,7 @@ const KOption = {
};
const digit = function(c) {
- return '0'.charCodeAt(0) <= c.charCodeAt(0) && c.charCodeAt(0) <= '9'.charCodeAt(0);
+ return char['0'] <= c && c <= char['9'];
};
const getnum = function(fmt, df) {
@@ -412,7 +408,7 @@ const getnum = function(fmt, df) {
else {
let a = 0;
do {
- a = a * 10 + (fmt.s[0].charCodeAt(0) - '0'.charCodeAt(0));
+ a = a * 10 + (fmt.s[0] - char['0']);
fmt.s = fmt.s.slice(1);
} while (digit(fmt.s[0]) && a <= (MAXSIZE - 9)/10);
return a;
@@ -426,7 +422,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, `integral size (${sz}) out of limits [1,${MAXINTSIZE}]`);
+ lauxlib.luaL_error(h.L, lua.to_luastring(`integral size (${sz}) out of limits [1,${MAXINTSIZE}]`));
return sz;
};
@@ -443,37 +439,37 @@ const getoption = function(h, fmt) {
fmt.s = fmt.s.slice(1);
r.size = 0; /* default */
switch (r.opt) {
- case 'b': r.size = 1; r.opt = KOption.Kint; return r; // sizeof(char): 1
- case 'B': r.size = 1; r.opt = KOption.Kuint; return r;
- case 'h': r.size = 2; r.opt = KOption.Kint; return r; // sizeof(short): 2
- case 'H': r.size = 2; r.opt = KOption.Kuint; return r;
- case 'l': r.size = 8; r.opt = KOption.Kint; return r; // sizeof(long): 8
- case 'L': r.size = 8; r.opt = KOption.Kuint; return r;
- case 'j': r.size = 8; r.opt = KOption.Kint; return r; // sizeof(lua_Integer): 8
- case 'J': r.size = 8; r.opt = KOption.Kuint; return r;
- case 'T': r.size = 8; r.opt = KOption.Kuint; return r; // sizeof(size_t): 8
- case 'f': r.size = 4; r.opt = KOption.Kfloat; return r; // sizeof(float): 4
- case 'd': r.size = 8; r.opt = KOption.Kfloat; return r; // sizeof(double): 8
- case 'n': r.size = 8; r.opt = KOption.Kfloat; return r; // sizeof(lua_Number): 8
- case 'i': r.size = getnumlimit(h, fmt, 4); r.opt = KOption.Kint; return r; // sizeof(int): 4
- case 'I': r.size = getnumlimit(h, fmt, 4); r.opt = KOption.Kuint; return r;
- case 's': r.size = getnumlimit(h, fmt, 8); r.opt = KOption.Kstring; return r;
- case 'c': {
+ case char['b']: r.size = 1; r.opt = KOption.Kint; return r; // sizeof(char): 1
+ case char['B']: r.size = 1; r.opt = KOption.Kuint; return r;
+ case char['h']: r.size = 2; r.opt = KOption.Kint; return r; // sizeof(short): 2
+ case char['H']: r.size = 2; r.opt = KOption.Kuint; return r;
+ case char['l']: r.size = 8; r.opt = KOption.Kint; return r; // sizeof(long): 8
+ case char['L']: r.size = 8; r.opt = KOption.Kuint; return r;
+ case char['j']: r.size = 8; r.opt = KOption.Kint; return r; // sizeof(lua_Integer): 8
+ case char['J']: r.size = 8; r.opt = KOption.Kuint; return r;
+ case char['T']: r.size = 8; r.opt = KOption.Kuint; return r; // sizeof(size_t): 8
+ case char['f']: r.size = 4; r.opt = KOption.Kfloat; return r; // sizeof(float): 4
+ case char['d']: r.size = 8; r.opt = KOption.Kfloat; return r; // sizeof(double): 8
+ case char['n']: r.size = 8; r.opt = KOption.Kfloat; return r; // sizeof(lua_Number): 8
+ case char['i']: r.size = getnumlimit(h, fmt, 4); r.opt = KOption.Kint; return r; // sizeof(int): 4
+ case char['I']: r.size = getnumlimit(h, fmt, 4); r.opt = KOption.Kuint; return r;
+ case char['s']: r.size = getnumlimit(h, fmt, 8); r.opt = KOption.Kstring; return r;
+ case char['c']: {
r.size = getnum(fmt, -1);
if (r.size === -1)
- lauxlib.luaL_error(h.L, "missing size for format option 'c'");
+ lauxlib.luaL_error(h.L, lua.to_luastring("missing size for format option 'c'"));
r.opt = KOption.Kchar;
return r;
}
- case 'z': r.opt = KOption.Kzstr; return r;
- case 'x': r.size = 1; r.opt = KOption.Kpadding; return r;
- case 'X': r.opt = KOption.Kpaddalign; return r;
- case ' ': break;
- case '<': h.islittle = true; break;
- case '>': h.islittle = false; break;
- case '=': h.islittle = true; break;
- case '!': h.maxalign = getnumlimit(h, fmt, MAXALIGN); break;
- default: lauxlib.luaL_error(h.L, `invalid format option '${r.opt}'`);
+ case char['z']: r.opt = KOption.Kzstr; return r;
+ case char['x']: r.size = 1; r.opt = KOption.Kpadding; return r;
+ case char['X']: r.opt = KOption.Kpaddalign; return r;
+ case char[' ']: break;
+ case char['<']: h.islittle = true; break;
+ case char['>']: h.islittle = false; break;
+ case char['=']: h.islittle = true; break;
+ case char['!']: h.maxalign = getnumlimit(h, fmt, MAXALIGN); break;
+ default: lauxlib.luaL_error(h.L, lua.to_luastring(`invalid format option '${String.fromCharCode(r.opt)}'`));
}
r.opt = KOption.Knop;
@@ -502,13 +498,13 @@ const getdetails = function(h, totalsize, fmt) {
let align = r.size; /* usually, alignment follows size */
if (r.opt === KOption.Kpaddalign) { /* 'X' gets alignment from following option */
if (fmt.s[0] === 0)
- lauxlib.luaL_argerror(h.L, 1, "invalid next option for option 'X'");
+ lauxlib.luaL_argerror(h.L, 1, lua.to_luastring("invalid next option for option 'X'"));
else {
let o = getoption(h, fmt);
align = o.size;
o = o.opt;
if (o === KOption.Kchar || align === 0)
- lauxlib.luaL_argerror(h.L, 1, "invalid next option for option 'X'");
+ lauxlib.luaL_argerror(h.L, 1, lua.to_luastring("invalid next option for option 'X'"));
}
}
if (align <= 1 || r.opt === KOption.Kchar) /* need no alignment? */
@@ -517,7 +513,7 @@ const getdetails = function(h, totalsize, fmt) {
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, "format asks for alignment not power of 2");
+ lauxlib.luaL_argerror(h.L, 1, lua.to_luastring("format asks for alignment not power of 2"));
r.ntoalign = (align - (totalsize & (align - 1))) & (align - 1);
}
return r;
@@ -555,8 +551,8 @@ const packnum = function(b, n, islittle, size) {
const str_pack = function(L) {
let b = [];
let h = new Header(L);
- let fmt = lauxlib.luaL_checkstring(L, 1).split(''); /* format string */
- fmt.push('\0'); // Add \0 to avoid overflow
+ let fmt = lauxlib.luaL_checkstring(L, 1); /* format string */
+ fmt.push(0); // Add \0 to avoid overflow
fmt = {
s: fmt,
off: 0
@@ -578,7 +574,7 @@ const str_pack = function(L) {
let n = lauxlib.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, "integer overflow");
+ lauxlib.luaL_argcheck(L, -lim <= n && n < lim, arg, lua.to_luastring("integer overflow"));
}
packint(b, n, h.islittle, size, n < 0);
break;
@@ -586,7 +582,7 @@ const str_pack = function(L) {
case KOption.Kuint: { /* unsigned integers */
let n = lauxlib.luaL_checkinteger(L, arg);
if (size < SZINT)
- lauxlib.luaL_argcheck(L, n < (1 << (size * NB)), arg, "unsigned overflow");
+ lauxlib.luaL_argcheck(L, n < (1 << (size * NB)), arg, lua.to_luastring("unsigned overflow"));
packint(b, n, h.islittle, size, false);
break;
}
@@ -597,30 +593,27 @@ const str_pack = function(L) {
}
case KOption.Kchar: { /* fixed-size string */
let s = lauxlib.luaL_checkstring(L, arg);
- s = L.stack[lapi.index2addr_(L, arg)];
- let len = s.value.length;
- lauxlib.luaL_argcheck(L, len <= size, arg, "string long than given size");
- b.push(...s.value); /* add string */
+ let len = s.length;
+ lauxlib.luaL_argcheck(L, len <= size, arg, lua.to_luastring("string long than given size"));
+ b.push(...s); /* add string */
while (len++ < size) /* pad extra space */
b.push(LUAL_PACKPADBYTE);
break;
}
case KOption.Kstring: { /* strings with length count */
let s = lauxlib.luaL_checkstring(L, arg);
- s = L.stack[lapi.index2addr_(L, arg)].value;
- let len = s.value.length;
- lauxlib.luaL_argcheck(L, size >= NB || len < (1 << size * NB), arg, "string length does not fit in given size");
+ let len = s.length;
+ lauxlib.luaL_argcheck(L, size >= NB || len < (1 << size * NB), arg, lua.to_luastring("string length does not fit in given size"));
packint(b, len, h.islittle, size, 0); /* pack length */
- b.push(...s.value);
+ b.push(...s);
totalsize += len;
break;
}
case KOption.Kzstr: { /* zero-terminated string */
let s = lauxlib.luaL_checkstring(L, arg);
- s = L.stack[lapi.index2addr_(L, arg)].value;
- let len = s.value.length;
- lauxlib.luaL_argcheck(L, s.value.length === String.fromCharCode(...s.value).length, arg, "strings contains zeros");
- b.push(...s.value);
+ let len = s.length;
+ lauxlib.luaL_argcheck(L, s.length === String.fromCharCode(...s).length, arg, lua.to_luastring("strings contains zeros"));
+ b.push(...s);
b.push(0); /* add zero at the end */
totalsize += len + 1;
break;
@@ -631,40 +624,46 @@ const str_pack = function(L) {
break;
}
}
- L.stack[L.top++] = new lobject.TValue(CT.LUA_TLNGSTR, b); // We don't want lua > js > lua string conversion here
+ lapi.lua_pushstring(L, b);
return 1;
};
const str_reverse = function(L) {
- lapi.lua_pushstring(L, lauxlib.luaL_checkstring(L, 1).split("").reverse().join(""));
+ lapi.lua_pushstring(L, lauxlib.luaL_checkstring(L, 1).reverse());
return 1;
};
const str_lower = function(L) {
- lapi.lua_pushstring(L, lauxlib.luaL_checkstring(L, 1).toLowerCase());
+ // TODO: will fail on invalid UTF-8
+ lapi.lua_pushstring(L, lua.to_luastring(lobject.jsstring(lauxlib.luaL_checkstring(L, 1)).toLowerCase()));
return 1;
};
const str_upper = function(L) {
- lapi.lua_pushstring(L, lauxlib.luaL_checkstring(L, 1).toUpperCase());
+ // TODO: will fail on invalid UTF-8
+ lapi.lua_pushstring(L, lua.to_luastring(lobject.jsstring(lauxlib.luaL_checkstring(L, 1)).toUpperCase()));
return 1;
};
const str_rep = function(L) {
let s = lauxlib.luaL_checkstring(L, 1);
let n = lauxlib.luaL_checkinteger(L, 2);
- let sep = lauxlib.luaL_optstring(L, 3, "");
+ let sep = lauxlib.luaL_optstring(L, 3, []);
if (s.length + sep.length < s.length || s.length + sep.length > MAXSIZE / n) /* may overflow? */
- return lauxlib.luaL_error(L, "resulting string too large");
+ return lauxlib.luaL_error(L, lua.to_luastring("resulting string too large"));
- lapi.lua_pushstring(L, n > 0 ? (s + sep).repeat(n - 1) + s : "");
+ let r = [];
+ for (let i = 0; i < n - 1; i++)
+ r = r.concat(s.concat(sep));
+ r = r.concat(s);
+
+ lapi.lua_pushstring(L, n > 0 ? r : []);
return 1;
};
const str_byte = function(L) {
let s = lauxlib.luaL_checkstring(L, 1);
- s = L.stack[lapi.index2addr_(L, 1)].value;
let l = s.length;
let posi = posrelat(lauxlib.luaL_optinteger(L, 2, 1), l);
let pose = posrelat(lauxlib.luaL_optinteger(L, 3, posi), l);
@@ -673,10 +672,10 @@ const str_byte = function(L) {
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, "string slice too long");
+ return lauxlib.luaL_error(L, lua.to_luastring("string slice too long"));
let n = (pose - posi) + 1;
- lauxlib.luaL_checkstack(L, n, "string slice too long");
+ lauxlib.luaL_checkstack(L, n, lua.to_luastring("string slice too long"));
for (let i = 0; i < n; i++)
lapi.lua_pushinteger(L, s[posi + i - 1]);
return n;
@@ -684,8 +683,8 @@ const str_byte = function(L) {
const str_packsize = function(L) {
let h = new Header(L);
- let fmt = lauxlib.luaL_checkstring(L, 1).split('');
- fmt.push('\0'); // Add \0 to avoid overflow
+ let fmt = lauxlib.luaL_checkstring(L, 1);
+ fmt.push(0); // Add \0 to avoid overflow
fmt = {
s: fmt,
off: 0
@@ -697,12 +696,12 @@ 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, "format result too large");
+ lauxlib.luaL_argcheck(L, totalsize <= MAXSIZE - size - 1, lua.to_luastring("format result too large"));
totalsize += size;
switch (opt) {
case KOption.Kstring: /* strings with length count */
case KOption.Kzstr: /* zero-terminated string */
- lauxlib.luaL_argerror(L, 1, "variable-length format");
+ lauxlib.luaL_argerror(L, 1, lua.to_luastring("variable-length format"));
default: break;
}
}
@@ -734,7 +733,7 @@ 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, `${size}-byte integer does not fit into Lua Integer`);
+ lauxlib.luaL_error(L, lua.to_luastring(`${size}-byte integer does not fit into Lua Integer`));
}
}
return res;
@@ -751,28 +750,27 @@ const unpacknum = function(L, b, islittle, size) {
const str_unpack = function(L) {
let h = new Header(L);
- let fmt = lauxlib.luaL_checkstring(L, 1).split('');
- fmt.push('\0'); // Add \0 to avoid overflow
+ let fmt = lauxlib.luaL_checkstring(L, 1);
+ fmt.push(0); // Add \0 to avoid overflow
fmt = {
s: fmt,
off: 0
};
let data = lauxlib.luaL_checkstring(L, 2);
- data = L.stack[lapi.index2addr_(L, 2)].value;
let ld = data.length;
let pos = posrelat(lauxlib.luaL_optinteger(L, 3, 1), ld) - 1;
let n = 0; /* number of results */
- lauxlib.luaL_argcheck(L, pos <= ld, 3, "initial position out of string");
+ lauxlib.luaL_argcheck(L, pos <= ld, 3, lua.to_luastring("initial position out of string"));
while (fmt.s.length - 1 > 0) {
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, "data string too short");
+ lauxlib.luaL_argerror(L, 2, lua.to_luastring("data string too short"));
pos += ntoalign; /* skip alignment */
/* stack space for item + next position */
- lauxlib.luaL_checkstack(L, 2, "too many results");
+ lauxlib.luaL_checkstack(L, 2, lua.to_luastring("too many results"));
n++;
switch (opt) {
case KOption.Kint:
@@ -787,22 +785,19 @@ const str_unpack = function(L) {
break;
}
case KOption.Kchar: {
- // lapi.lua_pushstring(L, data.slice(pos, pos + size));
- L.stack[L.top++] = new lobject.TValue(CT.LUA_TLNGSTR, data.slice(pos, pos + size));
+ lapi.lua_pushstring(L, data.slice(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, "data string too short");
- // lapi.lua_pushstring(L, data.slice(pos + size, pos + size + len));
- L.stack[L.top++] = new lobject.TValue(CT.LUA_TLNGSTR, data.slice(pos + size, pos + size + len));
+ lauxlib.luaL_argcheck(L, pos + len + size <= ld, 2, lua.to_luastring("data string too short"));
+ lapi.lua_pushstring(L, data.slice(pos + size, pos + size + len));
pos += len; /* skip string */
break;
}
case KOption.Kzstr: {
let len = data.slice(pos).indexOf(0);
- // lapi.lua_pushstring(L, data.slice(pos, pos + len));
- L.stack[L.top++] = new lobject.TValue(CT.LUA_TLNGSTR, data.slice(pos, pos + len));
+ lapi.lua_pushstring(L, data.slice(pos, pos + len));
pos += len + 1; /* skip string plus final '\0' */
break;
}
@@ -819,7 +814,7 @@ const str_unpack = function(L) {
const CAP_UNFINISHED = -1;
const CAP_POSITION = -2;
const MAXCCALLS = 200;
-const SPECIALS = ["^", "$", "*", "+", "?", ".", "(", "[", "%", "-"];
+const SPECIALS = [char["^"], char["$"], char["*"], char["+"], char["?"], char["."], char["("], char["["], char["%"], char["-"]];
class MatchState {
constructor(L) {
@@ -836,9 +831,9 @@ class MatchState {
}
const check_capture = function(ms, l) {
- l = String.fromCharCode(l - '1'.charCodeAt(0));
+ l = l - char['1'];
if (l < 0 || l >= ms.level || ms.capture[l].len === CAP_UNFINISHED)
- return lauxlib.luaL_error(ms.L, `invalid capture index %${l + 1}`);
+ return lauxlib.luaL_error(ms.L, lua.to_luastring(`invalid capture index %${l + 1}`));
return l;
};
@@ -846,24 +841,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, "invalid pattern capture");
+ return lauxlib.luaL_error(ms.L, lua.to_luastring("invalid pattern capture"));
};
const classend = function(ms, p) {
- switch(ms.p.charAt(p++)) {
- case sL_ESC: {
+ switch(ms.p[p++]) {
+ case L_ESC: {
if (p === ms.p_end)
- lauxlib.luaL_error(ms.L, "malformed pattern (ends with '%')");
+ lauxlib.luaL_error(ms.L, lua.to_luastring("malformed pattern (ends with '%')"));
return p + 1;
}
- case '[': {
- if (ms.p.charAt(p) === '^') p++;
+ case char['[']: {
+ if (ms.p[p] === char['^']) p++;
do { /* look for a ']' */
if (p === ms.p_end)
- lauxlib.luaL_error(ms.L, "malformed pattern (missing ']')");
- if (ms.p.charAt(p++) === L_ESC && p < ms.p_end)
+ lauxlib.luaL_error(ms.L, lua.to_luastring("malformed pattern (missing ']')"));
+ if (ms.p[p++] === L_ESC && p < ms.p_end)
p++; /* skip escapes (e.g. '%]') */
- } while (ms.p.charAt(p) !== ']');
+ } while (ms.p[p] !== char[']']);
return p + 1;
}
default: {
@@ -874,18 +869,18 @@ const classend = function(ms, p) {
const match_class = function(c, cl) {
let res;
- switch (cl.toLowerCase()) {
- case 'a' : res = isalpha(c); break;
- case 'c' : res = iscntrl(c); break;
- case 'd' : res = isdigit(c.charCodeAt(0)); break;
- case 'g' : res = isgraph(c); break;
- case 'l' : res = islower(c); break;
- case 'p' : res = ispunct(c); break;
- case 's' : res = isspace(c); break;
- case 'u' : res = isupper(c); break;
- case 'w' : res = isalnum(c); break;
- case 'x' : res = isxdigit(c); break;
- case 'z' : res = (c.charCodeAt(0) === 0); break; /* deprecated option */
+ switch (String.fromCharCode(cl).toLowerCase().charCodeAt(0)) {
+ case char['a'] : res = isalpha(c); break;
+ case char['c'] : res = iscntrl(c); break;
+ case char['d'] : res = isdigit(c); break;
+ case char['g'] : res = isgraph(c); break;
+ case char['l'] : res = islower(c); break;
+ case char['p'] : res = ispunct(c); break;
+ case char['s'] : res = isspace(c); break;
+ case char['u'] : res = isupper(c); break;
+ case char['w'] : res = isalnum(c); break;
+ case char['x'] : res = isxdigit(c); break;
+ case char['z'] : res = (c === 0); break; /* deprecated option */
default: return (cl === c);
}
return (islower(cl) ? res : !res);
@@ -893,20 +888,20 @@ const match_class = function(c, cl) {
const matchbracketclass = function(ms, c, p, ec) {
let sig = true;
- if (ms.p.charAt(p + 1) === '^') {
+ if (ms.p[p + 1] === char['^']) {
sig = false;
p++; /* skip the '^' */
}
while (++p < ec) {
- if (ms.p.charAt(p) === L_ESC) {
+ if (ms.p[p] === L_ESC) {
p++;
- if (match_class(c, ms.p.charAt(p)))
+ if (match_class(c, ms.p[p]))
return sig;
- } else if (ms.p.charAt(p + 1) === '-' && p + 2 < ec) {
+ } else if (ms.p[p + 1] === char['-'] && p + 2 < ec) {
p += 2;
- if (ms.p.charAt(p - 2) <= c.charCodeAt(0) && c.charCodeAt(0) <= ms.p.charAt(p))
+ if (ms.p[p - 2] <= c && c <= ms.p[p])
return sig;
- } else if (ms.p.charAt(p) === c) return sig;
+ } else if (ms.p[p] === c) return sig;
}
return !sig;
};
@@ -915,27 +910,27 @@ const singlematch = function(ms, s, p, ep) {
if (s >= ms.src_end)
return false;
else {
- let c = ms.src.charAt(s);
- switch (ms.p.charAt(p)) {
- case '.': return true; /* matches any char */
- case sL_ESC: return match_class(c, ms.p.charAt(p + 1));
- case '[': return matchbracketclass(ms, c, p, ep - 1);
- default: return ms.p.charAt(p) === c;
+ let c = ms.src[s];
+ switch (ms.p[p]) {
+ case char['.']: return true; /* matches any char */
+ case L_ESC: return match_class(c, ms.p[p + 1]);
+ case char['[']: return matchbracketclass(ms, c, p, ep - 1);
+ default: return ms.p[p] === c;
}
}
};
const matchbalance = function(ms, s, p) {
if (p >= ms.p_end - 1)
- lauxlib.luaL_error(ms.L, "malformed pattern (missing arguments to '%b'");
- if (ms.src.charAt(s) !== ms.p.charAt(p))
+ lauxlib.luaL_error(ms.L, lua.to_luastring("malformed pattern (missing arguments to '%b'"));
+ if (ms.src[s] !== ms.p[p])
return null;
else {
- let b = ms.p.charAt(p);
- let e = ms.p.charAt(p + 1);
+ let b = ms.p[p];
+ let e = ms.p[p + 1];
let cont = 1;
while (++s < ms.src_end) {
- if (ms.src.charAt(s) === e) {
+ if (ms.src[s] === e) {
if (--cont === 0) return s + 1;
}
else if (s === b) cont++;
@@ -970,7 +965,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, "too many captures");
+ if (level >= LUA_MAXCAPTURES) lauxlib.luaL_error(ms.L, lua.to_luastring("too many captures"));
ms.capture[level] = ms.capture[level] ? ms.capture[level] : {};
ms.capture[level].init = s;
ms.capture[level].len = what;
@@ -1003,24 +998,24 @@ const match = function(ms, s, p) {
let gotoinit = true;
if (ms.matchdepth-- === 0)
- lauxlib.luaL_error(ms.L, "pattern too complex");
+ lauxlib.luaL_error(ms.L, lua.to_luastring("pattern too complex"));
while (gotoinit || gotodefault) {
gotoinit = false;
if (p !== ms.p_end) { /* end of pattern? */
- switch (gotodefault ? 'x' : ms.p.charAt(p)) {
- case '(': { /* start capture */
- if (ms.p.charAt(p + 1) === ')') /* position capture? */
+ switch (gotodefault ? char['x'] : ms.p[p]) {
+ case char['(']: { /* start capture */
+ if (ms.p[p + 1] === char[')']) /* position capture? */
s = start_capture(ms, s, p + 2, CAP_POSITION);
else
s = start_capture(ms, s, p + 1, CAP_UNFINISHED);
break;
}
- case ')': { /* end capture */
+ case char[')']: { /* end capture */
s = end_capture(ms, s, p + 1);
break;
}
- case '$': {
+ case char['$']: {
if (p + 1 !== ms.p_end) { /* is the '$' the last char in pattern? */
gotodefault = true; /* no; go to default */
break;
@@ -1028,9 +1023,9 @@ const match = function(ms, s, p) {
s = ms.src.slice(s).length === 0 ? s : null; /* check end of string */
break;
}
- case sL_ESC: { /* escaped sequences not in the format class[*+?-]? */
- switch (ms.p.charAt(p + 1)) {
- case 'b': { /* balanced string? */
+ case L_ESC: { /* escaped sequences not in the format class[*+?-]? */
+ switch (ms.p[p + 1]) {
+ case char['b']: { /* balanced string? */
s = matchbalance(ms, s, p + 2);
if (s !== null) {
p = p.slice(4);
@@ -1038,22 +1033,22 @@ const match = function(ms, s, p) {
}
break;
}
- case 'f': {
+ case char['f']: {
p += 2;
- if (ms.p.charAt(p) !== '[')
- lauxlib.luaL_error(ms.L, `missing '[' after '%f' in pattern`);
+ if (ms.p[p] !== '[')
+ lauxlib.luaL_error(ms.L, lua.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.s.charAt(s - 1);
- if (!matchbracketclass(ms, previous, p, ep - 1) && matchbracketclass(ms, ms.src.charAt(s), p, ep - 1)) {
+ let previous = s === ms.src_init ? 0 : ms.s[s-1];
+ if (!matchbracketclass(ms, previous, p, ep - 1) && matchbracketclass(ms, ms.src[s], p, ep - 1)) {
p = ep; gotoinit = true; break;
}
s = null; /* match failed */
break;
}
- case '0': case '1': case '2': case '3':
- case '4': case '5': case '6': case '7':
- case '8': case '9': { /* capture results (%0-%9)? */
- s = match_capture(ms, s, ms.p.charAt(p + 1));
+ 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']: { /* capture results (%0-%9)? */
+ s = match_capture(ms, s, ms.p[p + 1]);
if (s !== null) {
p += 2; gotoinit = true;
}
@@ -1068,13 +1063,13 @@ 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.charAt(ep) === '*' || ms.p.charAt(ep) === '?' || ms.p.charAt(ep) === '-') { /* accept empty? */
+ if (ms.p[ep] === char['*'] || ms.p[ep] === char['?'] || ms.p[ep] === char['-']) { /* accept empty? */
p = ep + 1; gotoinit = true; break;
} else /* '+' or no suffix */
s = null; /* fail */
} else { /* matched once */
- switch (ms.p.charAt(ep)) { /* handle optional suffix */
- case '?': { /* optional */
+ switch (ms.p[ep]) { /* handle optional suffix */
+ case char['?']: { /* optional */
let res;
if ((res = match(ms, s + 1, ep + 1)) !== null)
s = res;
@@ -1083,12 +1078,12 @@ const match = function(ms, s, p) {
}
break;
}
- case '+': /* 1 or more repetitions */
+ case char['+']: /* 1 or more repetitions */
s++; /* 1 match already done */
- case '*': /* 0 or more repetitions */
+ case char['*']: /* 0 or more repetitions */
s = max_expand(ms, s, p, ep);
break;
- case '-': /* 0 or more repetitions (minimum) */
+ case char['-']: /* 0 or more repetitions (minimum) */
s = min_expand(ms, s, p, ep);
break;
default: /* no suffix */
@@ -1109,10 +1104,10 @@ const push_onecapture = function(ms, i, s, e) {
if (i === 0)
lapi.lua_pushlstring(ms.L, ms.src.slice(s), e - s); /* add whole match */
else
- lauxlib.luaL_error(ms.L, `invalid capture index %${i + 1}`);
+ lauxlib.luaL_error(ms.L, lua.to_luastring(`invalid capture index %${i + 1}`));
} else {
let l = ms.capture[i].len;
- if (l === CAP_UNFINISHED) lauxlib.luaL_error(ms.L, "unfinished capture");
+ if (l === CAP_UNFINISHED) lauxlib.luaL_error(ms.L, lua.to_luastring("unfinished capture"));
if (l === CAP_POSITION)
lapi.lua_pushinteger(ms.L, ms.src_init + 1);
else
@@ -1122,7 +1117,7 @@ const push_onecapture = function(ms, i, s, e) {
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, "too many catpures");
+ lauxlib.luaL_checkstack(ms.L, nlevels, lua.to_luastring("too many catpures"));
for (let i = 0; i < nlevels; i++)
push_onecapture(ms, i, s, e);
return nlevels; /* number of strings pushed */
@@ -1162,6 +1157,20 @@ const reprepstate = function(ms) {
assert(ms.matchdepth === MAXCCALLS);
};
+const find_subarray = function(arr, subarr, from_index) {
+ var i = from_index >>> 0,
+ sl = subarr.length,
+ l = arr.length + 1 - sl;
+
+ loop: for (; i < l; i++) {
+ for (let j = 0; j < sl; j++)
+ if (arr[i+j] !== subarr[j])
+ continue loop;
+ return i;
+ }
+ return -1;
+};
+
const str_find_aux = function(L, find) {
let s = lauxlib.luaL_checkstring(L, 1);
let p = lauxlib.luaL_checkstring(L, 2);
@@ -1176,7 +1185,7 @@ const str_find_aux = function(L, find) {
/* explicit request or no special characters? */
if (find && (lapi.lua_toboolean(L, 4) || nospecials(p, lp))) {
/* do a plain search */
- let f = s.slice(init - 1).indexOf(p);
+ let f = find_subarray(s.slice(init - 1), p, 0);
if (f > -1) {
lapi.lua_pushinteger(L, init + f);
lapi.lua_pushinteger(L, init + f + lp - 1);
@@ -1185,7 +1194,7 @@ const str_find_aux = function(L, find) {
} else {
let ms = new MatchState(L);
let s1 = init - 1;
- let anchor = s.charAt(0) === '^';
+ let anchor = s[0] === char['^'];
if (anchor) {
p = p.slice(1); lp--; /* skip anchor character */
}
@@ -1260,18 +1269,18 @@ const add_s = function(ms, b, s, e) {
let news = lapi.lua_tostring(L, 3);
let l = news.length;
for (let i = 0; i < l; i++) {
- if (news.charAt(i) !== sL_ESC)
- lauxlib.luaL_addchar(b, news.charAt(i));
+ if (news[i] !== L_ESC)
+ lauxlib.luaL_addchar(b, news[i]);
else {
i++; /* skip ESC */
- if (!isdigit(news.charCodeAt(i))) {
- if (news.charAt(i) !== sL_ESC)
- lauxlib.luaL_error(L, `invalid use of '${sL_ESC}' in replacement string`);
- lauxlib.luaL_addchar(b, news.charAt(i));
- } else if (news.charAt(i) === '0')
+ if (!isdigit(news[i])) {
+ if (news[i] !== L_ESC)
+ lauxlib.luaL_error(L, lua.to_luastring(`invalid use of '${sL_ESC}' in replacement string`));
+ lauxlib.luaL_addchar(b, news[i]);
+ } else if (news[i] === char['0'])
lauxlib.luaL_addlstring(b, ms.src.slice(s), e - s);
else {
- push_onecapture(ms, news.charCodeAt(i) - '1'.charCodeAt(0), s, e);
+ push_onecapture(ms, news[i] - char['1'], s, e);
lauxlib.luaL_tolstring(L, -1);
lapi.lua_remove(L, -2); /* remove original value */
lauxlib.luaL_addvalue(b); /* add capture to accumulated result */
@@ -1303,7 +1312,7 @@ const add_value = function(ms, b, s, e, tr) {
lapi.lua_pop(L, 1);
lapi.lua_pushlstring(L, s, e - s); /* keep original text */
} else if (!lapi.lua_isstring(L, -1))
- lauxlib.luaL_error(L, `invalid replacement value (a ${lauxlib.luaL_typename(L, -1)})`);
+ lauxlib.luaL_error(L, lua.to_luastring(`invalid replacement value (a ${lobject.jsstring(lauxlib.luaL_typename(L, -1))})`));
lauxlib.luaL_addvalue(b); /* add result to accumulator */
};
@@ -1315,12 +1324,12 @@ const str_gsub = function(L) {
let lastmatch = null; /* end of last match */
let tr = lapi.lua_type(L, 3); /* replacement type */
let max_s = lauxlib.luaL_optinteger(L, 4, srcl + 1); /* max replacements */
- let anchor = p.charAt(0) === '^';
+ let anchor = p[0] === char['^'];
let n = 0; /* replacement count */
let ms = new MatchState(L);
let b = new lauxlib.luaL_Buffer(L);
lauxlib.luaL_argcheck(L, tr === CT.LUA_TNUMBER || tr === CT.LUA_TSTRING || tr === CT.LUA_TFUNCTION || tr === CT.LUA_TTABLE, 3,
- "string/function/table expected");
+ lua.to_luastring("string/function/table expected"));
lauxlib.luaL_buffinit(L, b);
if (anchor) {
p = p.slice(1); lp--; /* skip anchor character */
@@ -1335,7 +1344,7 @@ 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.charAt(src++));
+ lauxlib.luaL_addchar(b, ms.src[src++]);
else break; /* end of subject */
if (anchor) break;
}
diff --git a/src/lua.js b/src/lua.js
index 85d4b64..d4f620b 100644
--- a/src/lua.js
+++ b/src/lua.js
@@ -4,6 +4,12 @@
const assert = require('assert');
const luaconf = 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;
+
/* mark for precompiled code ('<esc>Lua') */
const LUA_SIGNATURE = "\x1bLua";