fix alg2
This commit is contained in:
parent
c0aaedae59
commit
e9d96b20d9
91
alg2.lua
91
alg2.lua
@ -1,4 +1,26 @@
|
|||||||
local function stringToTable(str)
|
-- 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 codedStringToTable(str)
|
||||||
|
-- special case: hadle empty tables (our parser would break here)
|
||||||
|
if str:find("^{%s*}$") then return {} end
|
||||||
|
|
||||||
local function parseValue(s)
|
local function parseValue(s)
|
||||||
s = s:match("^%s*(.-)%s*$") -- trim whitespace
|
s = s:match("^%s*(.-)%s*$") -- trim whitespace
|
||||||
|
|
||||||
@ -11,20 +33,41 @@ local function stringToTable(str)
|
|||||||
elseif tonumber(s) then
|
elseif tonumber(s) then
|
||||||
return tonumber(s)
|
return tonumber(s)
|
||||||
elseif s:match("^\".*\"$") or s:match("^'.*'$") then
|
elseif s:match("^\".*\"$") or s:match("^'.*'$") then
|
||||||
return s:sub(2, -2):gsub("\\(.)", "%1") -- handle escape sequences
|
return decode(s:sub(2, -2))
|
||||||
elseif s:match("^%b{}$") then
|
elseif s:match("^{.*}$") then
|
||||||
return stringToTable(s)
|
return codedStringToTable(s)
|
||||||
else
|
else
|
||||||
error("Unrecognized value: " .. s)
|
error("Unrecognized value: " .. s)
|
||||||
end
|
end
|
||||||
end
|
end
|
||||||
|
|
||||||
|
local function parseKey(s)
|
||||||
|
s = s:match("^%s*(.-)%s*$") -- trim whitespace
|
||||||
|
if s:match("^%[(.*)%]$") then
|
||||||
|
return parseValue(s:match("^%[(.*)%]$"))
|
||||||
|
elseif s:find("^[%a_][%a%d_]*$") then -- make sure the string is a valid lua identifier
|
||||||
|
return s
|
||||||
|
else
|
||||||
|
error("Unrecognized key: " .. s)
|
||||||
|
end
|
||||||
|
end
|
||||||
|
|
||||||
local tbl = {}
|
local tbl = {}
|
||||||
local key, value
|
local key, value
|
||||||
|
local next_key = 1
|
||||||
local inKey = true
|
local inKey = true
|
||||||
local depth = 0
|
local depth = 0
|
||||||
local buffer = ""
|
local buffer = ""
|
||||||
|
|
||||||
|
local function getNextKey()
|
||||||
|
while tbl[next_key] ~= nil do
|
||||||
|
next_key = next_key + 1
|
||||||
|
end
|
||||||
|
key = next_key
|
||||||
|
next_key = next_key + 1
|
||||||
|
return key
|
||||||
|
end
|
||||||
|
|
||||||
for i = 1, #str do
|
for i = 1, #str do
|
||||||
local char = str:sub(i, i)
|
local char = str:sub(i, i)
|
||||||
|
|
||||||
@ -33,44 +76,44 @@ local function stringToTable(str)
|
|||||||
buffer = buffer .. char
|
buffer = buffer .. char
|
||||||
end
|
end
|
||||||
depth = depth + 1
|
depth = depth + 1
|
||||||
|
|
||||||
elseif char == '}' then
|
elseif char == '}' then
|
||||||
depth = depth - 1
|
depth = depth - 1
|
||||||
if depth > 0 then
|
if depth > 0 then
|
||||||
buffer = buffer .. char
|
buffer = buffer .. char
|
||||||
elseif depth == 0 and buffer ~= "" then
|
elseif depth == 0 and not buffer:find("^%s*$") then
|
||||||
value = buffer
|
|
||||||
buffer = ""
|
|
||||||
end
|
|
||||||
|
|
||||||
elseif char == ',' and depth == 1 then
|
|
||||||
if inKey then
|
|
||||||
key = parseValue(buffer)
|
|
||||||
else
|
|
||||||
value = parseValue(buffer)
|
value = parseValue(buffer)
|
||||||
tbl[key] = value
|
buffer = ""
|
||||||
|
end
|
||||||
|
elseif (char == ',' or char == ";") and depth == 1 then
|
||||||
|
value = parseValue(buffer)
|
||||||
|
if key == nil then
|
||||||
|
key = getNextKey()
|
||||||
end
|
end
|
||||||
buffer = ""
|
|
||||||
inKey = not inKey
|
|
||||||
|
|
||||||
|
tbl[key] = value
|
||||||
|
key, value = nil, nil
|
||||||
|
buffer = ""
|
||||||
elseif char == '=' and depth == 1 then
|
elseif char == '=' and depth == 1 then
|
||||||
key = parseValue(buffer)
|
key = parseKey(buffer)
|
||||||
buffer = ""
|
buffer = ""
|
||||||
inKey = false
|
|
||||||
|
|
||||||
else
|
else
|
||||||
buffer = buffer .. char
|
buffer = buffer .. char
|
||||||
end
|
end
|
||||||
|
end
|
||||||
|
|
||||||
if depth == 1 and i == #str and buffer ~= "" then
|
if key == nil then
|
||||||
value = parseValue(buffer)
|
key = getNextKey()
|
||||||
|
end
|
||||||
tbl[key] = value
|
tbl[key] = value
|
||||||
end
|
|
||||||
end
|
|
||||||
|
|
||||||
return tbl
|
return tbl
|
||||||
end
|
end
|
||||||
|
|
||||||
|
local function stringToTable(str)
|
||||||
|
str = code(str)
|
||||||
|
return codedStringToTable(str)
|
||||||
|
end
|
||||||
|
|
||||||
function test_string_to_table.s2t2(str)
|
function test_string_to_table.s2t2(str)
|
||||||
return stringToTable(str)
|
return stringToTable(str)
|
||||||
end
|
end
|
4
init.lua
4
init.lua
@ -22,7 +22,7 @@ local tests = {
|
|||||||
'{[-42.42e42] = 42.42E-42}',
|
'{[-42.42e42] = 42.42E-42}',
|
||||||
'{1, 2, 3, }',
|
'{1, 2, 3, }',
|
||||||
-- invalid tables, the code should return an error
|
-- invalid tables, the code should return an error
|
||||||
-- --[[
|
--[[
|
||||||
"{a = 1",
|
"{a = 1",
|
||||||
"{'unclosed string\\'}",
|
"{'unclosed string\\'}",
|
||||||
"{invalid key = 3}",
|
"{invalid key = 3}",
|
||||||
@ -48,6 +48,6 @@ local function test(alg)
|
|||||||
end
|
end
|
||||||
|
|
||||||
-- test("s2t1")
|
-- test("s2t1")
|
||||||
-- test("s2t2")
|
test("s2t2")
|
||||||
-- test("s2t3")
|
-- test("s2t3")
|
||||||
test("s2ttour")
|
test("s2ttour")
|
Loading…
Reference in New Issue
Block a user