test_string_to_table/alg1.lua

151 lines
4.6 KiB
Lua

local function stringToTable(str)
local parseTable -- defined later, but we need it in parseValue
local function parseValue(s, idx)
s = s:match("^%s*(.-)%s*$", idx) -- Trim leading/trailing spaces
if s:sub(1, 1) == "{" then
return parseTable(s)
elseif s:sub(1, 4) == "true" then
return true, 4
elseif s:sub(1, 5) == "false" then
return false, 5
elseif s:sub(1, 3) == "nil" then
return nil, 3
elseif s:sub(1, 1) == '"' or s:sub(1, 1) == "'" then
local quote = s:sub(1, 1)
local value = ""
for i = 2, #s do
if s:sub(i, i) == quote then
local j = i - 1
local escaped = false
while (s:sub(j,j)) == "\\" do
escaped = not escaped
j = j - 1
end
if not escaped then
value = value:gsub("\\(.)", "%1")
return value, i
end
end
value = value .. s:sub(i, i)
end
error("Unclosed string")
end
local _, next_i = s:find("^[+-]?%d+%.?%d*[eE][+-]?%d+%s*")
if not next_i then
_, next_i = s:find("^[+-]?%d+%.?%d*%s*")
end
if next_i then
return tonumber(s:match("^[+-]?%d+%.?%d*[eE][+-]?%d+") or s:match("^([+-]?%d+%.?%d*)")), next_i
else
print(s)
error("Invalid value")
end
end
local lua_keywords = {
["and"] = true,
["break"] = true,
["do"] = true,
["else"] = true,
["elseif"] = true,
["end"] = true,
["false"] = true,
["for"] = true,
["function"] = true,
["goto"] = true,
["if"] = true,
["in"] = true,
["local"] = true,
["nil"] = true,
["not"] = true,
["or"] = true,
["repeat"] = true,
["return"] = true,
["then"] = true,
["true"] = true,
["until"] = true,
["while"] = true,
}
local function parseKey(s, i)
s = s:match("^%s*(.-)%s*$", i) -- Trim leading/trailing spaces
if s:find("^[%a_]") then
local key = s:match("^[%a%d_]*")
if not lua_keywords[key] then
return key, #key
end
end
end
function parseTable(s)
local tbl = {}
local i = 2 -- Start after the opening '{'
local key, value
local value_found -- we cannot check for value, bc {nil} is valid
local next_key = 1
local next_i
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
while i <= #s do
local char = s:sub(i, i)
if char == "}" then
return tbl, i
elseif char == " " then
i = i + 1
elseif char == "," or char == ";" then
if key ~= nil or (not value_found) then
error("value expected")
end
value_found = false
i = i + 1
elseif char == "[" then
if key ~= nil then
error("Expected value, not a key")
end
key, next_i = parseValue(s:sub(i + 1))
i = i + next_i + 1
if s:sub(i, i) ~= "]" then
error("Expected closing bracket")
end
i = i + 1
elseif key == nil then
key, next_i = parseKey(s:sub(i))
if not key then -- not a valid key
value, next_i = parseValue(s:sub(i))
key = getNextKey()
tbl[key] = value
value_found = true
key = nil
end
i = i + next_i
elseif char == "=" then
i = i + 1
value, next_i = parseValue(s:sub(i))
tbl[key] = value
value_found = true
key = nil
i = i + next_i + 1
else
error("Unexpected character: " .. s:sub(i, i))
end
end
error("Unclosed table")
end
local result, _ = parseValue(str)
return result
end
function test_string_to_table.s2t1(str)
return stringToTable(str)
end