mirror of
https://github.com/emptyynes/LIVM.git
synced 2025-01-02 14:42:24 +03:00
250 lines
No EOL
7.3 KiB
Lua
250 lines
No EOL
7.3 KiB
Lua
local date = {
|
|
__def_val = {
|
|
boolean = true,
|
|
string = true,
|
|
number = true
|
|
},
|
|
__shorten_val = {
|
|
["function"] = true,
|
|
thread = true,
|
|
userdata = true,
|
|
["nil"] = true
|
|
},
|
|
__spec_val = {
|
|
table = true
|
|
}
|
|
}
|
|
|
|
--[==[ UNIT TEST FUNCTION
|
|
local function test(t)
|
|
for i, v in ipairs(t) do
|
|
local passed
|
|
if type(v[2]) == "table" then
|
|
passed = v[2][v[1]]
|
|
elseif type(v[2]) == "function" then
|
|
passed = v[2](v[1])
|
|
else
|
|
passed = v[1] == v[2]
|
|
end
|
|
if not passed then
|
|
print("Test " .. i .. " failed!")
|
|
print(v[1], v[2])
|
|
return false
|
|
end
|
|
end
|
|
return true
|
|
end
|
|
]==]
|
|
|
|
local function trim(s)
|
|
local n = s:find"%S"
|
|
return n and s:match(".*%S", n) or ""
|
|
end
|
|
|
|
function date.encode(t, st)
|
|
if date.__shorten_val[type(t)] then
|
|
return type(t)
|
|
elseif date.__def_val[type(t)] then
|
|
return trim(tostring(t):gsub("\\", "\\\\"):gsub(":", "\\:")
|
|
:gsub("%-", "\\-"):gsub("%^", "\\^"):gsub("{", "\\{"):gsub("}", "\\}"))
|
|
elseif st then
|
|
if st[1][t] then
|
|
return "{^" .. st[2][t] .. "}"
|
|
end
|
|
end
|
|
st = st or {{}, {}, 0}
|
|
if not st[1][t] then
|
|
st[3] = st[3] + 1
|
|
st[1][t] = true
|
|
st[2][t] = st[3]
|
|
end
|
|
local result = {}
|
|
local c = 1
|
|
local ordered = true
|
|
for k, v in pairs(t) do
|
|
ordered = ordered and c == k
|
|
local append = ""
|
|
if not ordered then
|
|
append = date.encode(k, st) .. "-"
|
|
end
|
|
if date.__spec_val[type(v)] then
|
|
if st[1][v] then append = append .. "{^" .. st[2][v] .. "}"
|
|
else
|
|
append = append .. "{" .. date.encode(v, st) .. "}"
|
|
if not st[1][t] then
|
|
st[3] = st[3] + 1
|
|
st[1][t] = true
|
|
st[2][t] = st[3]
|
|
end
|
|
end
|
|
elseif date.__shorten_val[type(v)] then
|
|
append = append .. type(v)
|
|
elseif date.__def_val[type(v)] then
|
|
append = append .. trim(tostring(v):gsub("\\", "\\\\"):gsub(":", "\\:")
|
|
:gsub("%-", "\\-"):gsub("%^", "\\^"):gsub("{", "\\{"):gsub("}", "\\}"))
|
|
end
|
|
result[#result + 1] = append
|
|
c = c + 1
|
|
end
|
|
return table.concat(result, ":")
|
|
end
|
|
|
|
function date.decode(s, st)
|
|
if type(s) ~= "string" then return error("date.decode arg #1 must be string") end
|
|
s = trim(s)
|
|
if #s:gsub("\\?%-?%d+%.?$d*", "") == 0 then return tonumber(({s:gsub("\\", "")})[1])
|
|
elseif s == "true" then return true
|
|
elseif s == "false" then return false
|
|
elseif s == "function" then return function() end
|
|
elseif s == "thread" then return coroutine.create(function() end)
|
|
elseif s == "userdata" then return "userdata"
|
|
elseif s == "nil" then return nil end
|
|
local result = {}
|
|
if st == nil then
|
|
st = { result }
|
|
else
|
|
st[#st + 1] = result
|
|
end
|
|
local sv = {}
|
|
local key, last
|
|
|
|
local function parseValue(x)
|
|
if type(x) ~= "string" then return error("date.decode.parseValue arg #1 must be string") end
|
|
x = trim(x)
|
|
if x == "false" then return false
|
|
elseif #x:gsub("%{%^%d+%}", "") == 0 then return st[tonumber(x:gmatch"%d+"())]
|
|
elseif x == "true" then return true
|
|
elseif x == "nil" then return nil
|
|
elseif #x:gsub("\\?%-?%d+%.?%d*", "") == 0 then return tonumber(({x:gsub("\\", "")})[1])
|
|
elseif x == "function" then return function() end
|
|
elseif x == "thread" then return coroutine.create(function() end)
|
|
elseif x == "userdata" then return "userdata"
|
|
elseif x:sub(1, 1) == "{" then return date.decode(x:sub(2, #x - 1), st)
|
|
else return x:gsub("\\%-", "-"):gsub("\\:", ":"):gsub("\\{", "{"):gsub("\\%^", "^") end
|
|
end
|
|
|
|
local d = 0
|
|
for c in s:gmatch"." do
|
|
if c == '{' and last ~= '\\' then
|
|
d = d + 1
|
|
sv[#sv + 1] = c
|
|
elseif c == '}' and last ~= '\\' then
|
|
d = d - 1
|
|
sv[#sv + 1] = c
|
|
elseif c == '-' and last ~= '\\' and d == 0 then
|
|
key = sv
|
|
sv = {}
|
|
elseif c == ':' and last ~= '\\' and d == 0 then
|
|
if key then
|
|
result[parseValue(table.concat(key, ""))] = parseValue(table.concat(sv, ""))
|
|
key = nil
|
|
sv = {}
|
|
else
|
|
result[#result + 1] = parseValue(table.concat(sv, ""))
|
|
sv = {}
|
|
end
|
|
else sv[#sv + 1] = c end
|
|
last = c
|
|
end
|
|
if #sv > 0 then
|
|
if key then
|
|
result[parseValue(table.concat(key, ""))] = parseValue(table.concat(sv, ""))
|
|
else
|
|
result[#result + 1] = parseValue(table.concat(sv, ""))
|
|
end
|
|
end
|
|
|
|
return result
|
|
end
|
|
|
|
--[==[ UNIT TEST
|
|
local self_ref = {}
|
|
self_ref[1] = self_ref
|
|
|
|
local self_ref2 = {}
|
|
self_ref2[self_ref2] = self_ref2
|
|
|
|
for i = 1, 0x40 do
|
|
local s = test{
|
|
-- 0-7
|
|
{date.encode{1, 2}, "1:2"},
|
|
{date.encode{1, 3, 2}, "1:3:2"},
|
|
{date.encode{"str", 3, "ing"}, "str:3:ing"},
|
|
{date.encode{"str", {"table"} ,"ing"}, "str:{table}:ing"},
|
|
{date.encode{"str", {{"table"}} ,"ing"}, "str:{{table}}:ing"},
|
|
{date.encode{"str", {{"table", 2}, 1} ,"ing"}, "str:{{table:2}:1}:ing"},
|
|
{date.encode{ function()end, coroutine.create(function()end) }, "function:thread"},
|
|
{date.encode{ true, false, nil, 1, -1, "-:" }, "true:false:4-1:5-\\-1:6-\\-\\:"},
|
|
-- 10-17
|
|
{date.encode"q+u:e-i", "q+u\\:e\\-i"},
|
|
{date.encode(-5), "\\-5"},
|
|
{date.encode(true), "true"},
|
|
{date.encode(false), "false"},
|
|
{date.encode(nil), "nil"},
|
|
{date.encode{}, ""},
|
|
{date.encode{nil}, ""},
|
|
{date.encode{nil, nil}, ""},
|
|
-- 20-27
|
|
{date.encode{a = 1}, "a-1"},
|
|
{date.encode{a = {b = {c = 1}}}, "a-{b-{c-1}}"},
|
|
{date.encode{x = [[big
|
|
python]]}, [[x-big
|
|
python]]},
|
|
{date.encode{["-"] = "-", [":"] = ":"}, {["\\:-\\::\\--\\-"] = true, ["\\--\\-:\\:-\\:"] = true}},
|
|
{date.encode{self_ref}, "{{^2}}"},
|
|
{date.encode(self_ref), "{^1}"},
|
|
{date.encode(self_ref2), "{^1}-{^1}"},
|
|
{date.encode(date.decode("1")), "1"},
|
|
-- 30-37
|
|
{date.encode(date.decode("\\-1")), "\\-1"},
|
|
{date.encode(date.decode("str+ing")), "str+ing"},
|
|
{date.encode(date.decode("st\\:ri\\-ng")), "st\\:ri\\-ng"},
|
|
{date.decode("true"), true},
|
|
{date.decode("false"), false},
|
|
{date.decode("nil"), nil},
|
|
{date.encode(date.decode("function")), "function"},
|
|
{date.encode(date.decode("thread")), "thread"},
|
|
-- 40-47
|
|
{date.encode(date.decode("userdata")), "userdata"},
|
|
{date.encode(date.decode("1:2")), "1:2"},
|
|
{date.decode"1:2"[1], 1},
|
|
{date.decode"1:2"[2], 2},
|
|
{date.encode(date.decode"str:3:ing"), "str:3:ing"},
|
|
{date.decode"str:3:ing"[1], "str"},
|
|
{date.decode"str:3:ing"[2], 3},
|
|
{date.decode"str:3:ing"[3], "ing"},
|
|
-- 50-57
|
|
{date.decode"str:{table}:ing"[1], "str"},
|
|
{date.decode"str:{table}:ing"[2][1], "table"},
|
|
{date.decode"str:{table}:ing"[3], "ing"},
|
|
{date.decode(date.encode{"str", {{"table", 2}, 1} ,"ing"})[1], "str"},
|
|
{date.decode(date.encode{"str", {{"table", 2}, 1} ,"ing"})[2][1][1], "table"},
|
|
{date.decode(date.encode{"str", {{"table", 2}, 1} ,"ing"})[2][1][2], 2},
|
|
{date.decode(date.encode{"str", {{"table", 2}, 1} ,"ing"})[2][2], 1},
|
|
{date.decode(date.encode{"str", {{"table", 2}, 1} ,"ing"})[3], "ing"},
|
|
-- 60-67
|
|
{date.decode"q+u\\:e\\-i"[1], "q+u:e-i"},
|
|
{date.decode"true:false:4-1:5-\\-1:6-\\-\\:"[1], true},
|
|
{date.decode"true:false:4-1:5-\\-1:6-\\-\\:"[2], false},
|
|
{date.decode"true:false:4-1:5-\\-1:6-\\-\\:"[3], nil},
|
|
{date.decode"true:false:4-1:5-\\-1:6-\\-\\:"[4], 1},
|
|
{date.decode"true:false:4-1:5-\\-1:6-\\-\\:"[5], -1},
|
|
{date.decode"true:false:4-1:5-\\-1:6-\\-\\:"[6], "-:"},
|
|
{date.decode"a-1"["a"], 1},
|
|
-- 70-77
|
|
{date.decode"a-1".a, 1},
|
|
{date.decode"a-{b-{c-1}}".a.b.c, 1},
|
|
{date.decode[[x-big
|
|
python]].x, [[big
|
|
python]]},
|
|
{date.decode"\\:-\\::\\--\\-"[":"], ":"},
|
|
{date.decode"\\:-\\::\\--\\-"["-"], "-"},
|
|
{date.decode"{{^2}}", function(x) return x[1][1] == x[1] end},
|
|
{date.decode"{^1}", function(x) return x[1] == x end},
|
|
{date.decode"{^1}-{^1}", function(x) return x[x] == x end}
|
|
}
|
|
if not s then print("(iteration [" .. i .. "])") break end
|
|
end
|
|
]==]
|
|
|
|
return date |