summaryrefslogtreecommitdiff
diff options
context:
space:
mode:
authorBenoit Giannangeli <benoit.giannangeli@boursorama.fr>2017-03-20 16:15:36 +0100
committerBenoit Giannangeli <benoit.giannangeli@boursorama.fr>2017-03-20 16:15:36 +0100
commit5f5ba74ace8a956ae48a9f0b182a157052c2546e (patch)
tree93381379f3711fd5ad67015d686dbfd518c0eef5
parent645437b8e0846635f886520bb679a79ec1849c09 (diff)
downloadfengari-5f5ba74ace8a956ae48a9f0b182a157052c2546e.tar.gz
fengari-5f5ba74ace8a956ae48a9f0b182a157052c2546e.tar.bz2
fengari-5f5ba74ace8a956ae48a9f0b182a157052c2546e.zip
string.gsub
-rw-r--r--README.md14
-rw-r--r--src/lapi.js20
-rw-r--r--src/lstrlib.js40
-rw-r--r--tests/lstrlib.js56
4 files changed, 122 insertions, 8 deletions
diff --git a/README.md b/README.md
index 6de8cab..2d1e35a 100644
--- a/README.md
+++ b/README.md
@@ -43,7 +43,6 @@
- [ ] lua_islightuserdata
- [ ] lua_isthread
- [ ] lua_isuserdata
- - [ ] lua_newuserdata
- [ ] lua_pcallk
- [ ] lua_pushfstring
- [ ] lua_pushlightuserdata
@@ -57,7 +56,6 @@
- [ ] lua_setlocal
- [ ] lua_setuservalue
- [ ] lua_tocfunction
- - [ ] lua_touserdata
- [ ] lua_upvalueid
- [ ] lua_upvaluejoin
- [ ] Auxiliary library
@@ -99,20 +97,20 @@
- [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.find
- [ ] string.gmatch
- - [ ] string.gsub
- - [ ] string.match
- - [ ] string.pack
- - [ ] string.packsize
- - [ ] string.unpack
- [ ] Package
- [ ] os
- [ ] io
diff --git a/src/lapi.js b/src/lapi.js
index a884a97..6840ef9 100644
--- a/src/lapi.js
+++ b/src/lapi.js
@@ -428,6 +428,14 @@ const lua_createtable = function(L, narray, nrec) {
assert(L.top <= L.ci.top, "stack overflow");
};
+const lua_newuserdata = function(L, u) {
+ L.stack[L.top++] = new lobject.TValue(CT.LUA_TUSERDATA, u);
+
+ assert(L.top <= L.ci.top, "stack overflow");
+
+ return L.stack[L.top - 1].value;
+};
+
const aux_upvalue = function(fi, n) {
switch(fi.ttype()) {
case CT.LUAT_TCCL: { /* C closure */
@@ -578,6 +586,16 @@ const lua_tonumber = function(L, idx) {
return lvm.tonumber(index2addr(L, idx));
};
+const lua_touserdata = function(L, idx) {
+ let o = index2addr(L, idx);
+ switch (o.ttnov()) {
+ case CT.LUA_TUSERDATA:
+ case CT.LUA_TLIGHTUSERDATA:
+ return o.value;
+ default: return null;
+ }
+};
+
const lua_tothread = function(L, idx) {
let o = index2addr(L, idx);
return o.ttisthread() ? o.value : null;
@@ -879,6 +897,7 @@ module.exports.lua_istable = lua_istable;
module.exports.lua_len = lua_len;
module.exports.lua_load = lua_load;
module.exports.lua_newtable = lua_newtable;
+module.exports.lua_newuserdata = lua_newuserdata;
module.exports.lua_next = lua_next;
module.exports.lua_pcall = lua_pcall;
module.exports.lua_pcallk = lua_pcallk;
@@ -924,6 +943,7 @@ module.exports.lua_tonumber = lua_tonumber;
module.exports.lua_topointer = lua_topointer;
module.exports.lua_tostring = lua_tostring;
module.exports.lua_tothread = lua_tothread;
+module.exports.lua_touserdata = lua_touserdata;
module.exports.lua_type = lua_type;
module.exports.lua_typename = lua_typename;
module.exports.lua_version = lua_version;
diff --git a/src/lstrlib.js b/src/lstrlib.js
index cedb403..9caa3cc 100644
--- a/src/lstrlib.js
+++ b/src/lstrlib.js
@@ -1221,12 +1221,52 @@ const str_match = function(L) {
return str_find_aux(L, 0);
};
+/* state for 'gmatch' */
+class GMatchState {
+ constructor() {
+ this.src = NaN; /* current position */
+ this.p = NaN; /* pattern */
+ this.lastmatch = NaN; /* end of last match */
+ this.ms = new MatchState(); /* match state */
+ }
+}
+
+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++) {
+ reprepstate(gm.ms);
+ let e;
+ if ((e = match(gm.ms, src, gm.p)) !== null && e !== gm.lastmatch) {
+ gm.src = gm.lastmatch = e;
+ return push_captures(gm.ms, src, e);
+ }
+ }
+ return 0; /* not found */
+};
+
+const str_gmatch = function(L) {
+ let s = lauxlib.luaL_checkstring(L, 1);
+ let p = lauxlib.luaL_checkstring(L, 2);
+ let ls = s.length;
+ let lp = p.length;
+ 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.lastmatch = null;
+ lapi.lua_pushcclosure(L, gmatch_aux, 3);
+ return 1;
+};
+
const strlib = {
"byte": str_byte,
"char": str_char,
"dump": str_dump,
"find": str_find,
"format": str_format,
+ "gmatch": str_gmatch,
"len": str_len,
"lower": str_lower,
"match": str_match,
diff --git a/tests/lstrlib.js b/tests/lstrlib.js
index aac3851..ce77bdc 100644
--- a/tests/lstrlib.js
+++ b/tests/lstrlib.js
@@ -621,4 +621,60 @@ test('string.find', function (t) {
"123",
"Correct element(s) on the stack"
);
+});
+
+
+test('string.gmatch', function (t) {
+ let luaCode = `
+ local s = "hello world from Lua"
+ local t = {}
+
+ for w in string.gmatch(s, "%a+") do
+ table.insert(t, w)
+ end
+
+ return table.unpack(t)
+ `, L;
+
+ t.plan(6);
+
+ t.doesNotThrow(function () {
+
+ L = lauxlib.luaL_newstate();
+
+ linit.luaL_openlibs(L);
+
+ lauxlib.luaL_loadstring(L, luaCode);
+
+ }, "Lua program loaded without error");
+
+ t.doesNotThrow(function () {
+
+ lapi.lua_call(L, 0, -1);
+
+ }, "Lua program ran without error");
+
+ t.strictEqual(
+ lapi.lua_tostring(L, -4),
+ "hello",
+ "Correct element(s) on the stack"
+ );
+
+ t.strictEqual(
+ lapi.lua_tostring(L, -3),
+ "world",
+ "Correct element(s) on the stack"
+ );
+
+ t.strictEqual(
+ lapi.lua_tostring(L, -2),
+ "from",
+ "Correct element(s) on the stack"
+ );
+
+ t.strictEqual(
+ lapi.lua_tostring(L, -1),
+ "Lua",
+ "Correct element(s) on the stack"
+ );
}); \ No newline at end of file