Advertisement
Not a member of Pastebin yet?
Sign Up,
it unlocks many cool features!
- local function trim(str, chars)
- if chars == nil then
- chars = "%s*"
- end
- return string.match(str, "^"..chars.."(.-)"..chars.."$")
- end
- local function split(str, delim)
- if delim == nil then
- delim = "\n"
- end
- local t = {}
- for s in string.gmatch(str, "([^"..delim.."]+)") do
- table.insert(t, trim(s))
- end
- return t
- end
- local function find_multiple(str, patterns, offset)
- local ws = string.len(str)
- local we = we
- local wpattern = nil
- for i, pattern in pairs(patterns) do
- s, e = string.find(str, pattern, offset)
- if s ~= nil then
- if s < ws then
- ws = s
- we = e
- wpattern = pattern
- end
- end
- end
- return ws, we, wpattern
- end
- local function balanced_end(str, word, offset)
- if offset == nil then
- offset = 1
- end
- local i = offset
- while true do
- local s, e, p
- if word == "then" then
- s, e, p = find_multiple(str, {"%smatch%s", "%sfunction%s", "%sthen%s", "%sdo%s", "%send%s", "%selseif%s"}, i)
- else
- s, e, p = find_multiple(str, {"%smatch%s", "%sfunction%s", "%sthen%s", "%sdo%s", "%send%s"}, i)
- end
- if p == "%send%s" then
- return e
- elseif p == "%selseif%s" then
- return e
- elseif p == nil then
- return "UNBAL"
- end
- i = balanced_end(str, string.sub(p, 3, -3), e)
- if i == "UNBAL" then
- return i
- end
- end
- end
- local function get_decls(str)
- -- gather data declarations from source & remove
- local datas = {}
- local i = 0
- local strout = ""
- while true do
- local n, a = string.find(str, "%sdata [%w]+", i+1)
- if n == nil then
- strout = strout .. string.sub(str, i+1)
- break
- end
- strout = strout .. string.sub(str, i+1, n)
- local e, d = string.find(str, "end", i+1)
- local cont = string.sub(str, a+1, e-1)
- local data = {}
- for i, case in ipairs(split(cont)) do
- local c = {}
- local b, p = string.find(case, "%(")
- if b == nil then
- c.name = case
- c.args = 0
- else
- c.name = string.sub(case, 1, p-1)
- c.args = #split(case, ",")
- end
- table.insert(data, c)
- end
- i = d
- table.insert(datas, data)
- end
- return datas, strout
- end
- function parseexpr(str)
- local n, o, name, body = string.find(str, "(%w+)(%b())")
- if n == nil then
- local b = string.find(str, ",")
- if b == nil then
- return {type="var",name=str}, ""
- else
- return {type="var", name=string.sub(str, 0, b-1)}, string.sub(str,b+1)
- end
- end
- body = string.sub(body, 2, -2)
- local obj = {type="data", name=name, body=parseexprs(body)}
- local rem = string.sub(str, o+1)
- local b = string.find(rem, ",")
- if b == nil then
- return obj, ""
- else
- return obj, string.sub(rem,b+1)
- end
- end
- function parseexprs(str)
- local t = {}
- while str ~= "" do
- local obj
- obj, str = parseexpr(str)
- table.insert(t, obj)
- end
- return t
- end
- local function getCase(datas, data)
- for i, x in ipairs(datas) do
- for i, case in ipairs(x) do
- if case.name == data then
- return i
- end
- end
- end
- end
- local function comparison(datas, var, pattern)
- if pattern.type == "data" then
- local out = var .. ".case == " .. getCase(datas, pattern.name)
- for i, x in ipairs(pattern.body) do
- if x.type == "data" then
- out = out .. " and " .. comparison(datas, var .. "[" .. i .. "]", x)
- end
- end
- return out
- else
- return "true"
- end
- end
- local function destructure(datas, var, pattern)
- if pattern.type == "var" then
- return "local " .. pattern.name .. " = " .. var
- else
- local out = ""
- for i, x in ipairs(pattern.body) do
- out = out .. "\n" .. destructure(datas, var .. "[" .. i .. "]", x)
- end
- return out
- end
- end
- function replace_match(datas, str)
- while true do
- local m, b, var = string.find(str, "%smatch (%w+)%s")
- if m == nil then
- return str
- end
- local e = balanced_end(str, "match", b)
- local cont = string.sub(str, b, e-4)
- str = string.sub(str, 1, m) .. replace_case(datas, cont, var) .. string.sub(str, e, -1)
- end
- end
- function replace_case(datas, out, var)
- local str = out
- local count = 0
- while true do
- local m
- local b
- local p
- m, b, p = string.find(str, "%scase ([^%s]+) do%s")
- if m == nil then
- for i=1,count do
- str = str .. "\nend"
- end
- return str
- end
- count = count + 1
- local e = balanced_end(str, "do", b)
- local cont = string.sub(str, b, e-5)
- local pattern = parseexpr(p)
- local bool = comparison(datas, var, pattern)
- local body = destructure(datas, var, pattern)
- str = string.sub(str, 1, m) .. "\nif " .. bool .. " then\n" .. body .. cont .. "\nelse\n" .. string.sub(str, e, -1)
- end
- end
- function printpattern(pattern)
- if pattern.type == "data" then
- io.write(pattern.name)
- io.write("(")
- for i, v in ipairs(pattern.body) do
- printpattern(v)
- io.write(",")
- end
- io.write(")")
- else
- io.write(pattern.name)
- end
- end
- local function writeheaders(datas)
- local out = ""
- for i, x in ipairs(datas) do
- for i, case in ipairs(x) do
- out = out .. "\nlocal function " .. case.name .. "(...) return {case=" .. i .. ",...} end"
- end
- end
- return out
- end
- local function preprocess(str)
- local decls, str0 = get_decls(str)
- local b = replace_match(decls, str0)
- local h = writeheaders(decls)
- return h .. b
- end
- args = {...}
- inp = io.open(args[1], "r")
- str = inp:read("*a")
- io.close(inp)
- out = io.open(args[2], "w")
- out:write(preprocess(str))
- io.close(out)
Advertisement
Add Comment
Please, Sign In to add comment
Advertisement