From aa0cc1ab537c9e6efb19633b88b6e568971b88f5 Mon Sep 17 00:00:00 2001 From: rubenwardy Date: Wed, 28 Aug 2019 18:57:11 +0100 Subject: [PATCH] Update Lib ChatCmdBuilder --- .luacheckrc | 2 +- mods/other/lib_chatcmdbuilder/init.lua | 155 ++++++++++++++++++------- 2 files changed, 116 insertions(+), 41 deletions(-) diff --git a/.luacheckrc b/.luacheckrc index e884902..fbc2d8a 100644 --- a/.luacheckrc +++ b/.luacheckrc @@ -19,7 +19,7 @@ globals = { } read_globals = { - string = {fields = {"split"}}, + string = {fields = {"split", "trim"}}, table = {fields = {"copy", "getn"}}, "dump", "DIR_DELIM", diff --git a/mods/other/lib_chatcmdbuilder/init.lua b/mods/other/lib_chatcmdbuilder/init.lua index 400d250..8177da3 100644 --- a/mods/other/lib_chatcmdbuilder/init.lua +++ b/mods/other/lib_chatcmdbuilder/init.lua @@ -32,14 +32,28 @@ local function escape(char) end end -function ChatCmdBuilder.build(func) +local dprint = function() end + +ChatCmdBuilder.types = { + pos = "%(? *(%-?[%d.]+) *, *(%-?[%d.]+) *, *(%-?[%d.]+) *%)?", + text = "(.+)", + number = "(%-?[%d.]+)", + int = "(%-?[%d]+)", + word = "([^ ]+)", + alpha = "([A-Za-z]+)", + modname = "([a-z0-9_]+)", + alphascore = "([A-Za-z_]+)", + alphanumeric = "([A-Za-z0-9]+)", + username = "([A-Za-z0-9-_]+)", +} + +function ChatCmdBuilder.build(rfunc) local cmd = { _subs = {} } - function cmd:sub(route, func, def) - print("Parsing " .. route) + function cmd:sub(route, func, _) + dprint("Parsing " .. route) - def = def or {} if string.trim then route = string.trim(route) end @@ -56,25 +70,15 @@ function ChatCmdBuilder.build(func) local should_be_eos = false local function finishParam() if param ~= "" and param_type ~= "" then - print(" - Found param " .. param .. " type " .. param_type) + dprint(" - Found param " .. param .. " type " .. param_type) - if param_type == "pos" then - sub.pattern = sub.pattern .. "%(? *(%-?[%d.]+) *, *(%-?[%d.]+) *, *(%-?[%d.]+) *%)?" - elseif param_type == "text" then - sub.pattern = sub.pattern .. "(*+)" - should_be_eos = true - elseif param_type == "number" then - sub.pattern = sub.pattern .. "([%d.]+)" - elseif param_type == "int" then - sub.pattern = sub.pattern .. "([%d]+)" - else - if param_type ~= "word" then - print("Unrecognised param_type=" .. param_type .. ", using 'word' type instead") - param_type = "word" - end - sub.pattern = sub.pattern .. "([^ ]+)" + local pattern = ChatCmdBuilder.types[param_type] + if not pattern then + error("Unrecognised param_type=" .. param_type) end + sub.pattern = sub.pattern .. pattern + table.insert(sub.params, param_type) param = "" @@ -84,6 +88,9 @@ function ChatCmdBuilder.build(func) -- Iterate through the route to find params local state = STATE_READY + local catching_space = false + local match_space = " " -- change to "%s" to also catch tabs and newlines + local catch_space = match_space.."+" for i = 1, #route do local c = route:sub(i, i) if should_be_eos then @@ -92,19 +99,33 @@ function ChatCmdBuilder.build(func) if state == STATE_READY then if c == ":" then - print(" - Found :, entering param") + dprint(" - Found :, entering param") state = STATE_PARAM param_type = "word" + catching_space = false + elseif c:match(match_space) then + print(" - Found space") + if not catching_space then + catching_space = true + sub.pattern = sub.pattern .. catch_space + end else + catching_space = false sub.pattern = sub.pattern .. escape(c) end elseif state == STATE_PARAM then if c == ":" then - print(" - Found :, entering param type") + dprint(" - Found :, entering param type") state = STATE_PARAM_TYPE param_type = "" + elseif c:match(match_space) then + print(" - Found whitespace, leaving param") + state = STATE_READY + finishParam() + catching_space = true + sub.pattern = sub.pattern .. catch_space elseif c:match("%W") then - print(" - Found nonalphanum, leaving param") + dprint(" - Found nonalphanum, leaving param") state = STATE_READY finishParam() sub.pattern = sub.pattern .. escape(c) @@ -112,8 +133,14 @@ function ChatCmdBuilder.build(func) param = param .. c end elseif state == STATE_PARAM_TYPE then - if c:match("%W") then - print(" - Found nonalphanum, leaving param type") + if c:match(match_space) then + print(" - Found space, leaving param type") + state = STATE_READY + finishParam() + catching_space = true + sub.pattern = sub.pattern .. catch_space + elseif c:match("%W") then + dprint(" - Found nonalphanum, leaving param type") state = STATE_READY finishParam() sub.pattern = sub.pattern .. escape(c) @@ -122,22 +149,22 @@ function ChatCmdBuilder.build(func) end end end - print(" - End of route") + dprint(" - End of route") finishParam() sub.pattern = sub.pattern .. "$" - print("Pattern: " .. sub.pattern) + dprint("Pattern: " .. sub.pattern) table.insert(self._subs, sub) end - if func then - func(cmd) + if rfunc then + rfunc(cmd) end - cmd.run = function(name, param) + cmd.run = function(name, message) for i = 1, #cmd._subs do local sub = cmd._subs[i] - local res = { string.match(param, sub.pattern) } + local res = { string.match(message, sub.pattern) } if #res > 0 then local pointer = 1 local params = { name } @@ -159,10 +186,16 @@ function ChatCmdBuilder.build(func) pointer = pointer + 1 end end - return sub.func(unpack(params)) + if table.unpack then + -- lua 5.2 or later + return sub.func(table.unpack(params)) + else + -- lua 5.1 or earlier + return sub.func(unpack(params)) + end end end - print("No matches") + return false, "Invalid command" end return cmd @@ -175,7 +208,7 @@ local function run_tests() return true end end) - end))("singleplayer", "bar abc and def") then + end)).run("singleplayer", "bar abc and def") then error("Test 1 failed") end @@ -186,7 +219,7 @@ local function run_tests() return true end end) - end) + end).run if not move("singleplayer", "move player1 to 0,1,2") then error("Test 2 failed") end @@ -206,13 +239,13 @@ local function run_tests() error("Test 7 failed") end if not move("singleplayer", "move player1 to ( 0 ,1 ,2)") then - error("Test 7 failed") + error("Test 8 failed") end if move("singleplayer", "move player1 to abc,def,sdosd") then - error("Test 8 failed") + error("Test 9 failed") end if move("singleplayer", "move player1 to abc def sdosd") then - error("Test 8 failed") + error("Test 10 failed") end if not (ChatCmdBuilder.build(function(cmd) @@ -221,9 +254,51 @@ local function run_tests() return true end end) - end))("singleplayer", "does 1 plus 2 equal 3") then - error("Test 9 failed") + end)).run("singleplayer", "does 1 plus 2 equal 3") then + error("Test 11 failed") end + + local checknegint = ChatCmdBuilder.build(function(cmd) + cmd:sub("checknegint :x:int", function(name, x) + return x + end) + end).run + if checknegint("checker","checknegint -2") ~= -2 then + error("Test 12 failed") + end + + local checknegnumber = ChatCmdBuilder.build(function(cmd) + cmd:sub("checknegnumber :x:number", function(name, x) + return x + end) + end).run + if checknegnumber("checker","checknegnumber -3.3") ~= -3.3 then + error("Test 13 failed") + end + + local checknegpos = ChatCmdBuilder.build(function(cmd) + cmd:sub("checknegpos :pos:pos", function(name, pos) + return pos + end) + end).run + local negpos = checknegpos("checker","checknegpos (-13.3,-4.6,-1234.5)") + if negpos.x ~= -13.3 or negpos.y ~= -4.6 or negpos.z ~= -1234.5 then + error("Test 14 failed") + end + + local checktypes = ChatCmdBuilder.build(function(cmd) + cmd:sub("checktypes :int:int :number:number :pos:pos :word:word :text:text", function(name, int, number, pos, word, text) + return int, number, pos.x, pos.y, pos.z, word, text + end) + end).run + local int, number, posx, posy, posz, word, text + int, number, posx, posy, posz, word, text = checktypes("checker","checktypes -1 -2.4 (-3,-5.3,6.12) some text to finish off with") + --dprint(int, number, posx, posy, posz, word, text) + if int ~= -1 or number ~= -2.4 or posx ~= -3 or posy ~= -5.3 or posz ~= 6.12 or word ~= "some" or text ~= "text to finish off with" then + error("Test 15 failed") + end + dprint("All tests passed") + end if not minetest then run_tests()