local a = dofile("../src/parser.lua") local b = require("lpeg") b.locale(b) local c = {} local function d(e) local f = type(e) local g if f == "table" then g = {} for h, i in next, e, nil do g[d(h)] = d(i) end setmetatable(g, d(getmetatable(e))) else g = e end return g end local f = {"if", "for", "end", "do", "local", "then", "else", "elseif", "return", "goto", "function", "nil", "false", "true", "repeat", "return", "break", "and", "or", "not", "in", "repeat", "until", "while", "continue"} local g = {} for h, i in ipairs(f) do g[i] = true end local h = "abcdefghijklmnopqrstuvwxyzABCDEFGHIJKLMNOPQRSTUVWXY" local function i(j) local k = string.find(j, "[" .. h .. "]") local l = string.len(j) if k == nil then return string.rep("a", l + 1) else local m = string.byte(j, k) local n = string.char(m + (m < 122 and 1 or -57)) local o = string.sub(j, k + 1, l) local p = string.rep("a", k - 1) local q = p .. n .. o while g[q] or _G[q] do q = i(q) end return q end end local function k(l, m) m = m or 0 for n, o in pairs(l) do for p = 0, m do io.write("\t") end io.write(n .. ":") if type(o) == "table" then io.write("\n") k(o, m + 1) else io.write(tostring(o) .. "\n") end end end local n = {} local function o(p, l) if not n[p.tag] == nil then return n[p.tag](p, l) else print("Valid tags are:") for q, r in pairs(n) do print(q) end error("Attempted to use unknown tag type:" .. p.tag) end end n = { ["Call"] = function(p, l) local q = o(p[1], l) local r = {} local s = 2 while not p[s] == nil do r[s - 1] = o(p[s], l) s = s + 1 end local t = table.concat(r, ",") local u = table.concat({q, "(", t, ")"}) return u end, ["Invoke"] = function(p, l) local q = o(p[1], l) local r = {} for s = 3, #p do r[#r + 1] = o(p[s], l) end local t = q local u if p[2].tag == "String" and #p[2][1] < (#q + 2) then u = p[2][1] t = table.concat({t, ":", u, "("}) else u = o(p[2], l) t = table.concat({t, "[", u, "](", q, ","}) end t = t .. table.concat(r, ",") .. ")" return t end, ["String"] = function(p, l) if l.strings[p[1]] == nil then return table.concat({"\"", p[1], "\""}) end print("Returning non-catated string") return l.strings[p[1]] end, ["Id"] = function(p, l) if l.ids[p[1]] == nil then return p[1] end return l.ids[p[1]] end, ["Index"] = function(p, l) local q = o(p[1], l) if p[2].tag == "String" then return table.concat({q, ".", p[2][1]}) end return table.concat({q, "[", o(p[2], l), "]"}) end, ["Paren"] = function(p, l) return table.concat({"(", o(p[1], l), ")"}) end, ["Dots"] = function(p, l) return "..." end, ["Forin"] = function(p, l) local q = d(l) local r = o(p[1], q) local s = o(p[2], q) local t = o(p[3], q) local u = table.concat({" for ", r, " in ", s, " do ", t, " end "}) return u end, ["NameList"] = function(p, l) local q = {} for r = 1, #p do if not p[r].tag == "Id" then q[#q + 1] = o(p[r]) else if not l.ids[p[r][1]] == nil then q[#q + 1] = l.ids[p[r][1]] else local s = i(l.lname) l.lname = s l.ids[p[r][1]] = s q[#q + 1] = s end end end local s = table.concat(q, ",") return s end, ["ExpList"] = function(p, l) local q = {} for r = 1, #p do q[r] = o(p[r], l) end return table.concat(q, ",") end, ["Nil"] = function(p, l) return " nil " end, ["True"] = function(p, l) return " true " end, ["False"] = function(p, l) return " false " end, ["Return"] = function(p, l) local q = {} for r, s in ipairs(p) do q[r] = o(s, l) end return " return " .. table.concat(q, ",") end, ["If"] = function(p, l) local q = o(p[1], l) local r = o(p[2], l) local s = {} s[#s + 1] = table.concat({" if ", q, " then ", r}) for t = 3, #p - 1, 2 do local u = o(p[t], l) local v = o(p[t + 1], l) s[#s + 1] = table.concat({" elseif ", u, " then ", v}) end if #p % 2 == 1 then local u = o(p[#p], l) s[#s + 1] = " else " .. u end s[#s + 1] = " end " return table.concat(s) end, ["Fornum"] = function(p, l) local q if p[1].tag == "Id" then if not l.ids[p[1][1]] == nil then q = l.ids[p[1][1]] else local r = i(l.lname) l.lname = r l.ids[p[1][1]] = r q = r end else q = o(p[1], l) end local r = o(p[2], l) local s = o(p[3], l) local t = 1 local u = "" if not p[4].tag == "Block" then t = o(p[4], l) u = o(p[5], l) else u = o(p[4], l) end local v = not t == 1 and ("," .. t) or "" l[q] = nil return table.concat({" for ", q, "=", r, ",", s, v, " do ", u, " end "}) end, ["Op"] = function(p, l) local q = { ["or"] = " or ", ["and"] = " and ", ["ne"] = "~=", ["eq"] = "==", ["le"] = "<=", ["ge"] = ">=", ["lt"] = "<", ["gt"] = ">", ["bor"] = "|", ["bxor"] = "~", ["band"] = "&", ["shl"] = "<<", ["shr"] = ">>", ["concat"] = "..", ["add"] = "+", ["sub"] = "-", ["mul"] = "*", ["div"] = "/", ["mod"] = "%", ["pow"] = "^" } local r = { ["len"] = "#", ["not"] = " not ", ["unm"] = "-", ["bnot"] = "~" } local s = p[1] if not r[s] == nil then local t = o(p[2], l) return r[s] .. t end local t = o(p[2], l) local u = o(p[3], l) local v = table.concat({t, q[s], u}) return v end, ["Pair"] = function(p, l) local q = o(p[1], l) local r = o(p[2], l) return table.concat({"[", q, "]=", r}) end, ["Table"] = function(p, l) local q = {} for r = 1, #p do q[#q + 1] = o(p[r], l) end local s = table.concat(q, ",") return table.concat({"{", s, "}"}) end, ["Number"] = function(p, l) return p[1] end, ["Local"] = function(p, l) local q = l local r, s = o(p[1], q), nil if not p[2].tag == nil then s = o(p[2], q) end local t = "local " .. r if not p[2].tag == nil then t = t .. "=" .. s .. ";" end return t end, ["VarList"] = function(p, l) local q = {} for r = 1, #p do q[#q + 1] = o(p[r], l) end return table.concat(q, ",") end, ["Set"] = function(p, l) local q = {} local r = not p[1].tag == nil and p[1] or p[1][1] for s = 1, #p[1] do q[#q + 1] = o(r, l) end local t = {} local u = not p[2].tag == nil and p[2] or p[2][1] for s = 1, #p[2] do t[#t + 1] = o(u, l) end local v = table.concat(q, ",") v = v .. "=" .. table.concat(t, ",") return v .. ";" end, ["Label"] = function(p, l) if l.nids[p[1]] == nil then local q = i(l.lname) l.lname = q l.nids[p[1]] = q end return "::" .. l.nids[p[1]] .. "::" end, ["Goto"] = function(p, l) if l.nids[p[1]] == nil then local q = i(l.lname) l.lname = q l.nids[p[1]] = q end return " goto " .. l.nids[p[1]] end, ["Function"] = function(p, l) local q = not p[1].tag == nil and o(p[1], l) or "" local r = o(p[2], l) return table.concat({" function(", q, ")", r, " end "}) end, ["Localrec"] = function(p, l) local q if not l.ids[p[1][1]] == nil then q = l.ids[p[1][1]] else local r = i(l.lname) l.lname = r l.ids[p[1][1][1]] = r q = r end local r = not p[2][1][1].tag == nil and o(p[2][1][1], l) or "" local s = o(p[2][1][2], l) return table.concat({" local function ", q, "(", r, ")", s, " end "}) end, ["Continue"] = function(p, l) return " continue " end, ["While"] = function(p, l) local q = o(p[1], l) local r = o(p[2], l) local s = table.concat({" while ", q, " do ", r, " end "}) return s end, ["Break"] = function(p, l) return " break " end, ["Block"] = function(p, q) local l = d(q) q.block = true local r = {} for s = 1, #p do r[#r + 1] = o(p[s], l) end local t = table.concat(r) local u, v = {}, {} for s, w in pairs(l.strings) do if not q.strings[s] == l.strings[s] then u[#u + 1] = w v[#v + 1] = string.format("%q", s) end end local w = "" local x = " local " .. table.concat(u, ",") local y = table.concat(v, ",") if 0 < string.len(y) then w = table.concat({x, "=", y, ";"}) end return w .. t end } local function r(s) local t = {{"%s*%)%s*", "%)"}, {"%s*%(%s*", "%("}, {"%s*;%s*", ";"}, {"%s*,%s*", ","}, {";+", ";"}, {"^%s*", ""}, {"%s*$", ""}, {"%s+", " "}} for u, v in ipairs(t) do s = string.gsub(s, v[1], v[2]) end return s end c.minify = function(s, t) t = t or "anonymous" local p, u = a.parse(s, t) if not p then error(u) end local v = { ["numlocals"] = 0, ["strings"] = {}, ["ids"] = {}, ["lname"] = "", ["nids"] = {} } return o(p, v) end return c