View difference between Paste ID: LuPYZaNe and PeEePR7Y
SHOW: | | - or go back to the newest paste.
1
local function trim(str, chars)
2
    if chars == nil then
3
        chars = "%s*"
4
    end
5
    return string.match(str, "^"..chars.."(.-)"..chars.."$")
6
end
7
8
local function split(str, delim)
9
    if delim == nil then
10
        delim = "\n"
11
    end
12
    local t = {}
13
    for s in string.gmatch(str, "([^"..delim.."]+)") do
14
        table.insert(t, trim(s))
15
    end
16
    return t
17
end
18
19
local function find_multiple(str, patterns, offset)
20
    local ws = string.len(str)
21
    local we = we
22
    local wpattern = nil
23
    for i, pattern in pairs(patterns) do
24
        s, e = string.find(str, pattern, offset)
25
        if s ~= nil then
26
            if s < ws then
27
                ws = s
28
                we = e
29
                wpattern = pattern
30
            end
31
        end
32
    end
33
    return ws, we, wpattern
34
end
35
36
local function balanced_end(str, word, offset)
37
    if offset == nil then
38
        offset = 1
39
    end
40
    local i = offset
41
    while true do
42
        local s, e, p
43
        if word == "then" then
44
            s, e, p = find_multiple(str, {"%smatch%s", "%sfunction%s", "%sthen%s", "%sdo%s", "%send%s", "%selseif%s"}, i)
45
        else
46
            s, e, p = find_multiple(str, {"%smatch%s", "%sfunction%s", "%sthen%s", "%sdo%s", "%send%s"}, i)
47
        end
48
        if p == "%send%s" then
49
            return e
50
        elseif p == "%selseif%s" then
51
            return e
52
        elseif p == nil then
53
            return "UNBAL"
54
        end
55
        i = balanced_end(str, string.sub(p, 3, -3), e)
56
        if i == "UNBAL" then
57
            return i
58
        end
59
    end
60
end
61
62
local function get_decls(str)
63
    -- gather data declarations from source & remove
64
    local datas = {}
65
    local i = 0
66
    local strout = ""
67
    while true do
68
        local n, a = string.find(str, "%sdata [%w]+", i+1)
69
        if n == nil then
70
            strout = strout .. string.sub(str, i+1)
71
            break
72
        end
73
        strout = strout .. string.sub(str, i+1, n)
74
        local e, d = string.find(str, "end", i+1)
75
        local cont = string.sub(str, a+1, e-1)
76
        local data = {}
77
        for i, case in ipairs(split(cont)) do
78
            local c = {}
79
            local b, p = string.find(case, "%(")
80
            if b == nil then
81
                c.name = case
82
                c.args = 0   
83
            else
84
                c.name = string.sub(case, 1, p-1)
85
                c.args = #split(case, ",")
86
            end
87
            table.insert(data, c)
88
        end
89
        i = d
90
        table.insert(datas, data)
91
    end
92
    return datas, strout
93
end
94
95-
function parseexpr(str)
95+
local parseexprs, replace_case, replace_match
96
local function parseexpr(str)
97
    local n, o, name, body = string.find(str, "(%w+)(%b())")
98
    if n == nil then
99
        local b = string.find(str, ",")
100
        if b == nil then
101
            return {type="var",name=str}, ""
102
        else
103
            return {type="var", name=string.sub(str, 0, b-1)}, string.sub(str,b+1)
104
        end
105
    end
106
    body = string.sub(body, 2, -2)
107
    local obj = {type="data", name=name, body=parseexprs(body)}
108
    local rem = string.sub(str, o+1)
109
    local b = string.find(rem, ",")
110
    if b == nil then
111
        return obj, ""
112
    else
113
        return obj, string.sub(rem,b+1)
114
    end
115
end
116-
function parseexprs(str)
116+
117
parseexprs = function(str)
118
    local t = {}
119
    while str ~= "" do
120
        local obj
121
        obj, str = parseexpr(str)
122
        table.insert(t, obj)
123
    end
124
    return t
125
end
126
127
local function getCase(datas, data)
128
    for i, x in ipairs(datas) do
129
        for i, case in ipairs(x) do
130
            if case.name == data then
131
                return i
132
            end
133
        end
134
    end
135
end
136
137
local function comparison(datas, var, pattern)
138
    if pattern.type == "data" then
139
        local out = var .. ".case == " .. getCase(datas, pattern.name)
140
        for i, x in ipairs(pattern.body) do
141
            if x.type == "data" then
142
                out = out .. " and " .. comparison(datas, var .. "[" .. i .. "]", x)
143
            end
144
        end
145
        return out
146
    else
147
        return "true"
148
    end
149
end
150
151
local function destructure(datas, var, pattern)
152
    if pattern.type == "var" then
153
        return "local " .. pattern.name .. " = " .. var
154
    else
155
        local out = ""
156
        for i, x in ipairs(pattern.body) do
157
            out = out .. "\n" .. destructure(datas, var .. "[" .. i .. "]", x)
158
        end
159
        return out
160
    end
161
end
162-
function replace_match(datas, str)
162+
163
replace_match = function(datas, str)
164
    while true do
165
        local m, b, var = string.find(str, "%smatch (%w+)%s")
166
        if m == nil then
167
            return str
168
        end
169
        local e = balanced_end(str, "match", b)
170
        local cont = string.sub(str, b, e-4)
171
        str = string.sub(str, 1, m) .. replace_case(datas, cont, var) .. string.sub(str, e, -1)
172
    end
173
end
174-
function replace_case(datas, out, var)
174+
175
replace_case = function(datas, out, var)
176
    local str = out
177
    local count = 0
178
    while true do
179
        local m
180
        local b
181
        local p
182
        m, b, p = string.find(str, "%scase ([^%s]+) do%s")
183
        if m == nil then
184
            for i=1,count do
185
                str = str .. "\nend"
186
            end
187
            return str
188
        end
189
        count = count + 1
190
        local e = balanced_end(str, "do", b)
191
        local cont = string.sub(str, b, e-5)
192
        local pattern = parseexpr(p)
193
        local bool = comparison(datas, var, pattern)
194
        local body = destructure(datas, var, pattern)
195
        str = string.sub(str, 1, m) .. "\nif " .. bool .. " then\n" .. body .. cont .. "\nelse\n" .. string.sub(str, e, -1)
196
    end
197
end
198-
function printpattern(pattern)
198+
199
local function printpattern(pattern)
200
    if pattern.type == "data" then
201
        io.write(pattern.name)
202
        io.write("(")
203
        for i, v in ipairs(pattern.body) do
204
            printpattern(v)
205
            io.write(",")
206
        end
207
        io.write(")")
208
    else
209
        io.write(pattern.name)
210
    end
211
end
212
213
local function writeheaders(datas)
214
    local out = ""
215
    for i, x in ipairs(datas) do
216
        for i, case in ipairs(x) do
217
            out = out .. "\nlocal function " .. case.name .. "(...) return {case=" .. i .. ",...} end"
218
        end
219
    end
220
    return out
221
end
222-
local function preprocess(str)
222+
223
function preprocess(str)
224
    local decls, str0 = get_decls(str)
225
    local b = replace_match(decls, str0)
226
    local h = writeheaders(decls)
227
    return h .. b
228
end