From cfc53ea643156a9993d37e85b0be6611a614704a Mon Sep 17 00:00:00 2001 From: Bruce Hill Date: Fri, 24 Sep 2021 22:55:39 -0700 Subject: Overhaul of lua API to use tables --- Lua/lbp.c | 153 +++++++++++++++++++++++++++++------------------------------ Lua/test.lua | 28 +++++++---- 2 files changed, 94 insertions(+), 87 deletions(-) diff --git a/Lua/lbp.c b/Lua/lbp.c index e45e8f3..9e5176e 100644 --- a/Lua/lbp.c +++ b/Lua/lbp.c @@ -51,78 +51,84 @@ static void push_matchstring(lua_State *L, match_t *m) fclose(out); } -static int Ltostring(lua_State *L) -{ - match_t **m = (match_t**)lua_touserdata(L, 1); - push_matchstring(L, *m); - return 1; -} +static void push_match(lua_State *L, match_t *m); -static int Lgc(lua_State *L) +static void set_capture_fields(lua_State *L, match_t *m, int *n) { - match_t **m = (match_t**)lua_touserdata(L, 1); - recycle_if_unused(m); - return 0; + if (m->pat->type == BP_CAPTURE) { + if (m->pat->args.capture.namelen > 0) { + lua_pushlstring(L, m->pat->args.capture.name, m->pat->args.capture.namelen); + push_match(L, m->children[0]); + lua_settable(L, -3); + } else { + push_match(L, m->children[0]); + lua_seti(L, -2, *(n++)); + } + } else if (m->children) { + for (int i = 0; m->children[i]; i++) + set_capture_fields(L, m->children[i], n); + } } -static int Llen(lua_State *L) +void push_match(lua_State *L, match_t *m) { - match_t **m = (match_t**)lua_touserdata(L, 1); - lua_pushinteger(L, (int)((*m)->end - (*m)->start)); - return 1; + lua_createtable(L, 1, 0); + lua_pushlightuserdata(L, (void*)&MATCH_METATABLE); + lua_gettable(L, LUA_REGISTRYINDEX); + lua_setmetatable(L, -2); + push_matchstring(L, m); + lua_seti(L, -2, 0); + int capture_num = 1; + for (int i = 0; m->children && m->children[i]; i++) + set_capture_fields(L, m->children[i], &capture_num); } -static int Lindex(lua_State *L) +static int Ltostring(lua_State *L) { - match_t **m = (match_t**)lua_touserdata(L, 1); - int type = lua_type(L, 2); - match_t *ret = NULL; - if (type == LUA_TNUMBER) { - int n = luaL_checkinteger(L, 2); - if (n == 0) { - push_matchstring(L, *m); - return 1; - } else if (n > 0) { - ret = get_numbered_capture(*m, n); - } - } else if (type == LUA_TSTRING) { - size_t len; - const char *name = luaL_checklstring(L, 2, &len); - ret = get_named_capture(*m, name, len); - } - - if (ret) { - match_t **userdata = (match_t**)lua_newuserdatauv(L, sizeof(match_t*), 0); - *userdata = ret; - lua_pushlightuserdata(L, (void*)&MATCH_METATABLE); - lua_gettable(L, LUA_REGISTRYINDEX); - lua_setmetatable(L, -2); - return 1; - } - return 0; + lua_geti(L, 1, 0); + return 1; } static const luaL_Reg Rinstance_metamethods[] = { - {"__len", Llen}, {"__tostring", Ltostring}, - {"__index", Lindex}, - {"__gc", Lgc}, {NULL, NULL} }; -// static void push_match(lua_State *L, match_t *m) -// { -// lua_createtable(L, 0, 1); -// lua_pushlightuserdata(L, (void*)&MATCH_METATABLE); -// lua_gettable(L, LUA_REGISTRYINDEX); -// lua_setmetatable(L, -2); - -// push_matchstring(L, m); -// lua_rawseti(L, -2, 0); -// int n = 1; -// assign_captures(L, m, &n); -// } +static void recursive_free_pat(pat_t *pat) +{ + // Do a depth-first traversal, freeing everyting along the way: + if (!pat) return; + switch (pat->type) { + case BP_DEFINITION: + recursive_free_pat(pat->args.def.def); + recursive_free_pat(pat->args.def.pat); + break; + case BP_REPEAT: + recursive_free_pat(pat->args.repetitions.sep); + recursive_free_pat(pat->args.repetitions.repeat_pat); + break; + case BP_CHAIN: case BP_UPTO: case BP_UPTO_STRICT: + case BP_OTHERWISE: case BP_NOT_MATCH: case BP_MATCH: + recursive_free_pat(pat->args.multiple.first); + recursive_free_pat(pat->args.multiple.second); + break; + case BP_REPLACE: + recursive_free_pat(pat->args.replace.pat); + break; + case BP_CAPTURE: + recursive_free_pat(pat->args.capture.capture_pat); + break; + case BP_NOT: case BP_AFTER: case BP_BEFORE: + recursive_free_pat(pat->args.pat); + break; + case BP_LEFTRECURSION: + recursive_free_pat(pat->args.leftrec.fallback); + break; + default: break; + } + free_pat(pat); +} static int Lmatch(lua_State *L) { @@ -141,27 +147,16 @@ static int Lmatch(lua_State *L) match_t *m = NULL; int ret = 0; - if (next_match(&m, builtins, text, &text[textlen], maybe_pat.value.pat, NULL, false)) { - - // lua_createtable(L, 0, 1); - - match_t **userdata = (match_t**)lua_newuserdatauv(L, sizeof(match_t*), 0); - *userdata = m; - lua_pushlightuserdata(L, (void*)&MATCH_METATABLE); - lua_gettable(L, LUA_REGISTRYINDEX); - lua_setmetatable(L, -2); - // push_matchstring(L, text_file, m); - // lua_rawseti(L, -2, 0); - // int n = 1; - // assign_captures(L, text_file, m, &n); - - lua_pushinteger(L, (int)(m->start - text) + index); + if (next_match(&m, builtins, text+index-1, &text[textlen], maybe_pat.value.pat, NULL, false)) { + push_match(L, m); + lua_pushinteger(L, (int)(m->start - text) + 1); lua_pushinteger(L, (int)(m->end - m->start)); - - // stop_matching(&m); + stop_matching(&m); ret = 3; } + recursive_free_pat(maybe_pat.value.pat); + return ret; } @@ -180,9 +175,10 @@ static int Lreplace(lua_State *L) raise_parse_error(L, maybe_pat); return 0; } - maybe_pat = bp_replacement(maybe_pat.value.pat, rep_text, rep_text + replen); - if (!maybe_pat.success) { - raise_parse_error(L, maybe_pat); + maybe_pat_t maybe_replacement = bp_replacement(maybe_pat.value.pat, rep_text, rep_text + replen); + if (!maybe_replacement.success) { + recursive_free_pat(maybe_pat.value.pat); + raise_parse_error(L, maybe_replacement); return 0; } @@ -191,7 +187,7 @@ static int Lreplace(lua_State *L) FILE *out = open_memstream(&buf, &size); int replacements = 0; const char *prev = text; - for (match_t *m = NULL; next_match(&m, builtins, text, &text[textlen], maybe_pat.value.pat, NULL, false); ) { + for (match_t *m = NULL; next_match(&m, builtins, text, &text[textlen], maybe_replacement.value.pat, NULL, false); ) { fwrite(prev, sizeof(char), (size_t)(m->start - prev), out); fprint_match(out, text, m, NULL); prev = m->end; @@ -203,6 +199,9 @@ static int Lreplace(lua_State *L) lua_pushinteger(L, replacements); fclose(out); + // maybe_pat will get freed by this: + recursive_free_pat(maybe_replacement.value.pat); + return 2; } diff --git a/Lua/test.lua b/Lua/test.lua index df7a63d..c2fbb3c 100644 --- a/Lua/test.lua +++ b/Lua/test.lua @@ -10,24 +10,32 @@ bp.each = function(s, pat, index) return iter, {s, pat, index}, index end +local function repr(obj) + if type(obj) == 'table' then + local ret = {} + for k,v in pairs(obj) do table.insert(ret, ("%s=%s"):format(k, repr(v))) end + return ("{%s}"):format(table.concat(ret,",")) + elseif type(obj) == 'string' then + return string.format("%q", obj) + else + return tostring(obj) + end +end + print("Matching:") for m, i,j in bp.each("one two three", "(*`a-z) => '(@0)'") do - print(("%q @%d len=%d"):format(tostring(m),i,j)) + print(("%s @%d len=%d"):format(repr(m),i,j)) end print(("Replacing: %q (%d replacements)"):format(bp.replace("one two three", "+`a-z", "(@0)"))) print("Captures:") -local m = bp.match("one two three four", "_:` ;@first=+`a-z _ @second=(+`a-z => 'XX@0XX') _ @+`a-z _ @last=+`a-z") -local function quote(x) return ("%q"):format(tostring(x)) end -print("0", quote(m[0])) -print("first", quote(m.first)) -print("second", m.second) -print("1", m[1]) -print("last", m.last) - -print("Len:", #m, #tostring(m)) +local m = bp.match("one two three four", "@first=+`a-z _ @second=(+`a-z => 'XX@0XX') _ @+`a-z _ @last=+`a-z") +print(repr(m)) + +local m = bp.match("one two three four", "@dup=+`a-z _ @dup=+`a-z _ @two=(@a=+`a-z _ @b=+`a-z)") +print(repr(m)) print("Testing parse errors:") -- cgit v1.2.3