add another algo

This commit is contained in:
tour 2024-09-13 15:05:53 +02:00
parent 09e8eec932
commit 23f01fe6da
2 changed files with 117 additions and 1 deletions

113
algtour.lua Normal file
View File

@ -0,0 +1,113 @@
local nested_tables = {}
-- strings might contain characters that are part of the table syntax.
-- We need to mask them, otherwise they might break our parser
-- based on https://www.lua.org/pil/20.4.html
local function code(s)
-- mask all escaped characters
return s:gsub("\\(.)", function (c)
return string.format("\\%03d", string.byte(c))
end):gsub("([\"'])(.-)%1", function (_, match) -- detect all strings
return "'" .. match:gsub("([,;{}%[%]=])", function (c)
return string.format("\\%03d", string.byte(c))
end) .. "'"
end)
end
local function decode(s)
return s:gsub("\\(%d%d%d)", function (d)
return string.char(d)
end)
end
local function parse_value(str)
if str == "nil" then
return true, nil
elseif str == "true" then
return true, true
elseif str == "false" then
return true, false
elseif str:find("^([\"']).-%1$") then
return true, decode(str:sub(2, -2))
elseif tonumber(str) then
return true, tonumber(str)
elseif nested_tables[str] then
return true, nested_tables[str]
end
return false, string.format("unable to parse '%s'", str)
end
local function parse_key(str)
if str:find("^%[.*%]$") then
-- if in brackets, we can threat it like a value
local success, key = parse_value(str:sub(2, -2))
if not success then
return false, key
end
if key == nil then
return false, "nil cannot be a key"
end
return true, key
end
-- make sure the key is a valid identifier
if str:find("^[%a_][%a%d_]*$") then
return true, str
end
return false, string.format("'%s' is not a valid key", str)
end
local function parse_flat_table(str)
if str:find("{%s*}") then return true, {} end
str = str:gsub("^{(.-)[,;]?%s*}$", "%1,")
local next_index = 1
local res = {}
for pair in str:gmatch("(.-)[,;]") do
local key, value, success
if pair:find("=") then
key, value = pair:match("^(.-)=(.*)$")
key = key:gsub("^%s*(.-)%s*$", "%1")
success, key = parse_key(key)
if not success then return false, key end
else
while res[next_index] ~= nil do
next_index = next_index + 1
end
key = next_index
next_index = next_index + 1
value = pair
end
value = value:gsub("^%s*(.-)%s*$", "%1")
success, value = parse_value(value)
if not success then return false, value end
res[key] = value
end
return true, res
end
local function stringToTable(str)
str = code(str)
nested_tables = {}
local success = true
local tbl
local replacements = 0
local table_count = 0
repeat
str, replacements = str:gsub("({[^{}]*})", function (match)
table_count = table_count + 1
success, tbl = parse_flat_table(match)
nested_tables["\\t" .. tostring(table_count)] = tbl
return "\\t" .. tostring(table_count)
end)
until replacements == 0 or success == false
return success and (nested_tables[str] or "not a table") or tbl
end
function test_string_to_table.s2ttour(str)
return stringToTable(str)
end

View File

@ -5,6 +5,7 @@ test_string_to_table.modpath = minetest.get_modpath("test_string_to_table") .. D
dofile(test_string_to_table.modpath .. "alg1.lua")
dofile(test_string_to_table.modpath .. "alg2.lua")
dofile(test_string_to_table.modpath .. "alg3.lua")
dofile(test_string_to_table.modpath .. "algtour.lua")
local tests = {
'{1, 2, 3}',
@ -26,6 +27,7 @@ local function test(alg)
for _, case in ipairs(tests) do
local ret = {case, test_string_to_table[alg](case)}
table.insert(outcome, ret)
minetest.log(dump(ret))
end
local t2 = minetest.get_us_time()
minetest.log("action",alg .. " = " .. (t2-t1))
@ -33,4 +35,5 @@ end
-- test("s2t1")
-- test("s2t2")
test("s2t3")
-- test("s2t3")
test("s2ttour")