2024-07-18 04:29:47 +00:00
|
|
|
local function _parse(str, init)
|
|
|
|
local pos = init
|
|
|
|
if string.find(str, "^%(", pos) then
|
|
|
|
pos = pos + 1
|
|
|
|
local list = {};
|
|
|
|
while true do
|
|
|
|
if string.find(str, "^%)", pos) then
|
|
|
|
pos = pos + 1
|
|
|
|
return list, pos
|
|
|
|
end
|
|
|
|
local child, new_pos = _parse(str, pos)
|
|
|
|
if not child then
|
|
|
|
error(string.format("expected ')', '(', or atom at index %d", pos))
|
|
|
|
end
|
|
|
|
table.insert(list, child)
|
|
|
|
pos = new_pos
|
|
|
|
end
|
|
|
|
else
|
|
|
|
local pos = init
|
2024-07-18 06:46:06 +00:00
|
|
|
local len_str = string.match(str, "^%d+", pos)
|
2024-07-18 04:29:47 +00:00
|
|
|
if not len_str then
|
|
|
|
error(string.format("expected '(' or atom at index %d", pos))
|
|
|
|
end
|
|
|
|
local len = tonumber(len_str)
|
|
|
|
pos = pos+#len_str
|
|
|
|
|
|
|
|
if not string.find(str, "^:", pos) then error(string.format("expected ':' at index %d", pos)) end
|
|
|
|
pos = pos + 1
|
|
|
|
local value = string.sub(str, pos, pos + len - 1)
|
|
|
|
if #value < len then error(string.format("unexpected end of string at index %d", pos)) end
|
|
|
|
pos = pos + len
|
|
|
|
|
|
|
|
return value, pos
|
|
|
|
end
|
|
|
|
end
|
|
|
|
|
|
|
|
local function parse(str)
|
|
|
|
local value, pos = _parse(str, 1)
|
|
|
|
if pos <= #str then
|
|
|
|
error(string.format("extra characters at index %d", pos))
|
|
|
|
end
|
|
|
|
return value
|
|
|
|
end
|
|
|
|
|
|
|
|
local function _serialize(tokens, obj)
|
|
|
|
if type(obj) == "table" then
|
|
|
|
table.insert(tokens, "(")
|
|
|
|
for _, item in ipairs(obj) do
|
|
|
|
_serialize(tokens, item)
|
|
|
|
end
|
|
|
|
table.insert(tokens, ")")
|
|
|
|
else
|
|
|
|
local s = tostring(obj)
|
|
|
|
table.insert(tokens, tostring(#s))
|
|
|
|
table.insert(tokens, ":")
|
|
|
|
table.insert(tokens, s)
|
|
|
|
end
|
|
|
|
end
|
|
|
|
|
|
|
|
local function serialize(obj)
|
|
|
|
local tokens = {}
|
|
|
|
_serialize(tokens, obj)
|
|
|
|
return table.concat(tokens)
|
|
|
|
end
|
|
|
|
|
|
|
|
return {parse = parse, serialize = serialize}
|