aboutsummaryrefslogtreecommitdiff
diff options
context:
space:
mode:
authorBenoit Giannangeli <benoit.giannangeli@boursorama.fr>2017-03-21 07:33:40 +0100
committerBenoit Giannangeli <benoit.giannangeli@boursorama.fr>2017-03-21 08:17:14 +0100
commit2cc93b924a21030fcd6f5dc96f287bbf13f987f4 (patch)
treea831301ac901f51e75e2e9f71d822b8ad49a3212
parent5f5ba74ace8a956ae48a9f0b182a157052c2546e (diff)
downloadfengari-2cc93b924a21030fcd6f5dc96f287bbf13f987f4.tar.gz
fengari-2cc93b924a21030fcd6f5dc96f287bbf13f987f4.tar.bz2
fengari-2cc93b924a21030fcd6f5dc96f287bbf13f987f4.zip
string.gmatch
-rw-r--r--README.md19
-rw-r--r--src/lauxlib.js4
-rw-r--r--src/ldo.js2
-rw-r--r--src/lstrlib.js101
-rw-r--r--src/ltablib.js2
5 files changed, 101 insertions, 27 deletions
diff --git a/README.md b/README.md
index 2d1e35a..791a885 100644
--- a/README.md
+++ b/README.md
@@ -93,24 +93,7 @@
- [x] Table
- [x] Math
- [x] utf8
- - [ ] String
- - [x] string.byte
- - [x] string.char
- - [x] string.dump
- - [x] string.find
- - [x] string.format
- - [x] string.gsub
- - [x] string.len
- - [x] string.lower
- - [x] string.match
- - [x] string.pack
- - [x] string.packsize
- - [x] string.rep
- - [x] string.reverse
- - [x] string.sub
- - [x] string.unpack
- - [x] string.upper
- - [ ] string.gmatch
+ - [x] String
- [ ] Package
- [ ] os
- [ ] io
diff --git a/src/lauxlib.js b/src/lauxlib.js
index 3ee04a4..879d081 100644
--- a/src/lauxlib.js
+++ b/src/lauxlib.js
@@ -215,8 +215,8 @@ const luaL_buffinitsize = function(L, B, sz) {
return B;
};
-const luaL_addlstring = function(B, s) {
- B.b += s;
+const luaL_addlstring = function(B, s, l) {
+ B.b += s.slice(0, l);
};
const luaL_addstring = luaL_addlstring;
diff --git a/src/ldo.js b/src/ldo.js
index 7df4c62..a9f442a 100644
--- a/src/ldo.js
+++ b/src/ldo.js
@@ -143,7 +143,7 @@ const moveresults = function(L, firstResult, res, nres, wanted) {
break;
case 1: {
if (nres === 0)
- firstResult = nil;
+ L.stack[firstResult] = nil;
L.stack[res] = L.stack[firstResult];
break;
}
diff --git a/src/lstrlib.js b/src/lstrlib.js
index 9caa3cc..dc3845b 100644
--- a/src/lstrlib.js
+++ b/src/lstrlib.js
@@ -1113,7 +1113,7 @@ const match = function(ms, s, p) {
const push_onecapture = function(ms, i, s, e) {
if (i >= ms.level) {
if (i === 0)
- lapi.lua_pushlstring(ms.L, s, e); /* add whole match */
+ 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}`);
} else {
@@ -1127,7 +1127,7 @@ const push_onecapture = function(ms, i, s, e) {
};
const push_captures = function(ms, s, e) {
- let nlevels = ms.level === 0 && s ? 1 : ms.level;
+ let nlevels = ms.level === 0 && ms.src.slice(s) ? 1 : ms.level;
lauxlib.luaL_checkstack(ms.L, nlevels, "too many catpures");
for (let i = 0; i < nlevels; i++)
push_onecapture(ms, i, s, e);
@@ -1234,7 +1234,7 @@ class GMatchState {
const gmatch_aux = function(L) {
let gm = lapi.lua_touserdata(L, lua.lua_upvalueindex(3));
gm.ms.L = L;
- for (let src = 0; src < gm.ms.src_end; src++) {
+ for (let src = gm.src; src < gm.ms.src_end; src++) {
reprepstate(gm.ms);
let e;
if ((e = match(gm.ms, src, gm.p)) !== null && e !== gm.lastmatch) {
@@ -1253,13 +1253,103 @@ const str_gmatch = function(L) {
lapi.lua_settop(L, 2); /* keep them on closure to avoid being collected */
let gm = lapi.lua_newuserdata(L, new GMatchState());
prepstate(gm.ms, L, s, ls, p, lp);
- gm.src = s;
- gm.p = p;
+ gm.src = 0;
+ gm.p = 0;
gm.lastmatch = null;
lapi.lua_pushcclosure(L, gmatch_aux, 3);
return 1;
};
+const add_s = function(ms, b, s, e) {
+ let L = ms.L;
+ 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));
+ else {
+ i++; /* skip ESC */
+ if (!isdigit(news.charAt(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')
+ lauxlib.luaL_addlstring(b, ms.src.slice(s), e - s);
+ else {
+ push_onecapture(ms, news.charCodeAt(i) - '1'.charCodeAt(0), s, e);
+ lauxlib.luaL_tostring(L, -1);
+ lapi.lua_remove(L, -2); /* remove original value */
+ lauxlib.luaL_addvalue(b); /* add capture to accumulated result */
+ }
+ }
+ }
+};
+
+const add_value = function(ms, b, s, e, tr) {
+ let L = ms.L;
+ switch (tr) {
+ case CT.LUA_TFUNCTION: {
+ lapi.lua_pushvalue(L, 3);
+ let n = push_captures(ms, s, e);
+ lapi.lua_call(L, n, 1);
+ break;
+ }
+ case CT.LUA_TTABLE: {
+ push_onecapture(ms, 0, s, e);
+ lapi.lua_gettable(L, 3);
+ break;
+ }
+ default: { /* LUA_TNUMBER or LUA_TSTRING */
+ add_s(ms, b, s, e);
+ return;
+ }
+ }
+ if (!lapi.lua_toboolean(L, -1)) { /* nil or false? */
+ 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_addvalue(b); /* add result to accumulator */
+};
+
+const str_gsub = function(L) {
+ let src = lauxlib.luaL_checkstring(L, 1); /* subject */
+ let srcl = src.length;
+ let p = lauxlib.luaL_checkstring(L, 2); /* pattern */
+ let lp = p.length;
+ 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 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");
+ lauxlib.luaL_buffinit(L, b);
+ if (anchor) {
+ p = p.slice(1); lp--; /* skip anchor character */
+ }
+ prepstate(ms, L, src, srcl, p, lp);
+ src = 0; p = 0;
+ while (n < max_s) {
+ let e;
+ reprepstate(ms);
+ if ((e = match(ms, src, p)) !== null && e !== lastmatch) { /* match? */
+ n++;
+ 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++));
+ else break; /* end of subject */
+ if (anchor) break;
+ }
+ lauxlib.luaL_addlstring(b, ms.src.slice(src), ms.src_end - src);
+ lauxlib.luaL_pushresult(b);
+ lapi.lua_pushinteger(L, n); /* number of substitutions */
+ return 2;
+};
+
const strlib = {
"byte": str_byte,
"char": str_char,
@@ -1267,6 +1357,7 @@ const strlib = {
"find": str_find,
"format": str_format,
"gmatch": str_gmatch,
+ "gsub": str_gsub,
"len": str_len,
"lower": str_lower,
"match": str_match,
diff --git a/src/ltablib.js b/src/ltablib.js
index 10d66eb..20fdf95 100644
--- a/src/ltablib.js
+++ b/src/ltablib.js
@@ -168,7 +168,7 @@ const pack = function(L) {
const unpack = function(L) {
let i = lauxlib.luaL_optinteger(L, 2, 1);
- let e = lauxlib.luaL_opt(L, lauxlib.luaL_checkinteger, 3, lapi.lua_len(L, 1));
+ let e = lauxlib.luaL_opt(L, lauxlib.luaL_checkinteger, 3, lauxlib.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 || !lapi.lua_checkstack(L, ++n))