diff options
| -rw-r--r-- | AUTHORS | 2 | ||||
| -rw-r--r-- | src/ast_opts.lua | 100 | ||||
| -rw-r--r-- | src/glum.lua | 136 | ||||
| -rw-r--r-- | src/parser_min.lua | 1216 | ||||
| -rw-r--r-- | test/glum_spec.lua | 71 | ||||
| -rw-r--r-- | test/glum_test.lua | 21 | ||||
| -rw-r--r-- | test/tests/call.lua | 4 | ||||
| -rw-r--r-- | test/tests/valid_snippits/call.lua | 22 | ||||
| -rw-r--r-- | test/tests/valid_snippits/forinloop.lua | 10 | ||||
| -rw-r--r-- | test/tests/valid_snippits/fornumloop.lua | 10 | ||||
| -rw-r--r-- | test/tests/valid_snippits/invoke.lua | 12 | ||||
| -rw-r--r-- | test/tests/valid_snippits/string.lua | 8 |
12 files changed, 1048 insertions, 564 deletions
@@ -0,0 +1,2 @@ +Alex Pickering - Most of GLUM +MeepDarknessM - Inspiration for some optimizations diff --git a/src/ast_opts.lua b/src/ast_opts.lua new file mode 100644 index 0000000..de49932 --- /dev/null +++ b/src/ast_opts.lua @@ -0,0 +1,100 @@ +--[[ + Optimizatoins for abstract syntax trees +]] +local msg = io.write +--A debugging function, a replacement for glua PrintTable +local function printtable(tbl, tabset) + tabset = tabset or 0 + for k,v in pairs(tbl) do + for i = 0,tabset do msg("\t") end + msg(k .. ":") + if type(v) == "table" then + msg("\n") + printtable(v, tabset + 1) + else + msg(tostring(v) .. "\n") + end + end +end + +--A function to see if two ast's are equal-ish (does not compare position) +local function deepcompare(tbl1, tbl2) + if type(tbl1) ~= type(tbl2) then return false end + for k,v in pairs(tbl1) do + print("Checking ", k, " from tbl1") + if k == "pos" then goto cont end + if type(v) == "table" then + print("It is a table! going deeper") + if not deepcompare(v,tbl2[k]) then + return false + end + else + print("Checking ", v , " against ", tbl2[k]) + if v ~= tbl2[k] then + return false + end + end + ::cont:: + end + return true +end + +local opts = {} + +--Optimization 1 +--Folds things with an operator when the fold results in a smaller string +local foldables = { + ["add"] = function(a,b) return a + b end, + ["mul"] = function(a,b) return a * b end, + ["mod"] = function(a,b) return a % b end, + ["sub"] = function(a,b) return a - b end, + --["div"] = function(a,b) return a / b end, division has the chance to give us really long strings! +} +opts[1] = function(ast) + if ast.tag ~= "Op" then return false end + local opname = ast[1] + local func = foldables[opname] + if ast[3] ~= nil and func ~= nil and ast[2].tag == "Number" and ast[3].tag == "Number" then + ast.tag = "Number" + ast[1] = func(ast[2][1],ast[3][1]) + for i = 2,#ast do + ast[i] = nil + end + return true + end + return false +end + +--Optimization 2 +--Find places where we can replace calls with invokes. +opts[2] = function(ast) + if ast.tag == "Call" and ast.pos == 160 then + print("Ast:") + printtable(ast) + print("ast[1][1]") + printtable(ast[1][1]) + print("ast[2]") + printtable(ast[2]) + local dcr = deepcompare(ast[1][1],ast[2]) + print("Deepcompare:",dcr) + --error("stopping") + end + if ast.tag == "Call" and deepcompare(ast[1][1][1], ast[2][1]) then + print("Before correcting for invoke, ast is") + printtable(ast) + for i = 2,#ast[2] do + ast[i] = ast[i+1] + end + ast.tag = "Invoke" + ast[2] = ast[1][2] + ast[1] = ast[1][1] + print("After correcting for invoke, ast is") + printtable(ast) + + --error("Call that should be invoke detected") + return true + end + +end + +return opts diff --git a/src/glum.lua b/src/glum.lua index f4385c0..bcdd5e6 100644 --- a/src/glum.lua +++ b/src/glum.lua @@ -21,18 +21,37 @@ This moudle allows you to minify gLua code local parser local msg +local optimi if include ~= nil then parser = include("./parser.lua") msg = Msg + optimi = include("./ast_opts.lua") else parser = dofile("../src/parser.lua") msg = io.write + optimi = dofile("../src/ast_opts.lua") + print("Just did optimi, it is",type(optimi)) end local lpeg = require("lpeg") lpeg.locale(lpeg) local glum = {} +--Checks if two tables are the same +local function deepcompare(tbl1, tbl2) + for k,v in pairs(tbl1) do + if type(v) == "table" then + if not deepcompare(v,tbl2[k]) then + return false + end + else + if v ~= tbl2[k] then + return false + end + end + end +end + --Creates a deep copy of a table local function deepcopy(orig) local orig_type = type(orig) @@ -125,6 +144,22 @@ local getstringreps = function(ast) return sstbl end +local function astwalker(ast) + for i,j in pairs(optimi) do + local new = j(ast) + changed = changed or new + end + for k,v in pairs(ast) do + if type(v) == "table" then + astwalker(v) + end + end + for i,j in pairs(optimi) do + local new = j(ast) + changed = changed or new + end +end + local syntax = {} local function stringfor(ast,tbl) @@ -142,10 +177,7 @@ end syntax = { ["Call"] = function(ast,tbl) - print("ast for call is") - printtable(ast) local exprname = stringfor(ast[1],tbl) - print("String for expname is",exprname) last = false local argnames = {} local cursor = 2 @@ -213,7 +245,6 @@ syntax = { ["Id"] = function(ast,tbl) local ret if last then ret = " " else ret = "" end - if ast[1] == "pairs" then print("in id, ast1 is pairs") printtable(tbl.ids) end if tbl.ids[ast[1]] == nil then ret = ret .. ast[1] last = true @@ -225,7 +256,7 @@ syntax = { end, ["Index"] = function(ast,tbl) local globalvar = stringfor(ast[1],tbl) - if ast[2].tag == "String" then + if ast[2].tag == "String" and tbl.strings[ast[2][1]] == nil then last = true return table.concat({globalvar, ".", ast[2][1]}) end @@ -243,8 +274,6 @@ syntax = { return "..." end, ["Forin"] = function(ast,tbl) - print("At forin, ast is") - printtable(ast) local codetbl = {} if last then codetbl[1] = " for" else codetbl[1] = "for" end last = true @@ -275,17 +304,20 @@ syntax = { outputtbl[#outputtbl + 1] = stringfor(ast[k]) else if tbl.ids[ast[k][1]] ~= nil then + print("Found id in id table") outputtbl[#outputtbl + 1] = tbl.ids[ast[k][1]] else local newvar = getnextvarname(tbl.lname) tbl.lname = newvar tbl.ids[ast[k][1]] = newvar outputtbl[#outputtbl + 1] = newvar + print("Not found, output is ", newvar) end last = false end end local output = bef .. table.concat(outputtbl, ",") + print("Output from namelist is ", output) last = true return output end, @@ -307,14 +339,12 @@ syntax = { return ret end, ["True"] = function(ast,tbl) - local ret - if last then ret = " true" else ret = "true" end + local ret = "!!1" last = true return ret end, ["False"] = function(ast,tbl) - local ret - if last then ret = " false" else ret = "false" end + local ret = "!1" last = true return ret end, @@ -393,8 +423,8 @@ syntax = { end, ["Fornum"] = function(ast,tbl) local spargs = {} - if last then spargs[1] = " for " else spargs[1] = "for " end - last = false + if last then spargs[1] = " for" else spargs[1] = "for" end + last = true local var assert(ast[1].tag == "Id","Oh no, I was expecting an ID!") if ast[1].tag == "Id" then @@ -424,9 +454,12 @@ syntax = { local code = "" spargs[7] = "" if ast[4].tag ~= "Block" then -- incrementer + last = false incrementer = stringfor(ast[4],tbl) if incrementer ~= 1 then spargs[7] = "," .. incrementer + else + last = true end if last then spargs[8] = " do" else spargs[8] = "do" end last = true @@ -470,14 +503,14 @@ syntax = { if uniop[opname] ~= nil then --Some special case where the parser messes up, fix it here. --It translates ~= into not ==, but the order of operations makes it so == is evaluated first, and not second. + local bef if opname == "not" and ast[2]["tag"] == "Op" and ast[2][1] == "eq" then ast[2][1] = "ne" local ret = stringfor(ast[2],tbl) return ret end - local rhs = stringfor(ast[2],tbl) - local bef if last then bef = " " else bef = "" end + local rhs = stringfor(ast[2],tbl) return bef .. uniop[opname] .. rhs end local sargs = {} @@ -578,6 +611,12 @@ syntax = { return (last and " " or "") .. "goto " .. tbl.nids[ast[1]] end, ["Function"] = function(ast,tbl) + --Sometimes the parser fucks up, correct it here + if ast[1][1] ~= nil and ast[1][1].tag == nil then + ast[1] = ast[1][1] + error("Detected parser fuckup") + end + --end of parser-fuckup-fix code local funcstr if last then funcstr = " function(" else funcstr = "function(" end last = false @@ -590,7 +629,39 @@ syntax = { return table.concat({funcstr,funcargs,")",code,endstr}) end, ["Localrec"] = function(ast,tbl) - local ident + local ident = ast[1][1] + local args = ast[2][1][1] + local func = ast[2][1][2] + local bf = {} + if last then bf[1] = " local" else bf[1] = "local" end + bf[2] = stringfor(ident,tbl) --ident + bf[3] = " function" + bf[4] = "(" + last = false + bf[5] = stringfor(args,tbl) --args + bf[6] = ")" + last = false + bf[7] = stringfor(func,tbl) -- function + if last then bf[8] = " end" else bf[8] = "end" end + last = true + return table.concat(bf) + + --[==[ + --Sometimes the parser fucks up, correct it here + print("in localrec, ast is") + printtable(ast) + if ast[1][1] ~= nil and ast[1].tag == nil then + ast[1] = ast[1][1] + --error("Detected parser fuckup") + print("after fixing fuckup, ast was") + printtable(ast) + else + print("ast[1][1] is",ast[1][1]) + printtable(ast[1][1]) + end + --end of parser-fuckup-fix code + local ident = stringfor(ast[1],tbl) + --[=[ if tbl.ids[ast[1][1]] ~= nil then ident = tbl.ids[ast[1][1]] else @@ -599,6 +670,7 @@ syntax = { tbl.ids[ast[1][1][1]] = newvar ident = newvar end + ]=] local locfuncstr if last then locfuncstr = " local function " else locfuncstr = "local function " end last = false @@ -612,6 +684,7 @@ syntax = { print(string.format("At localrec, locfuncstr:%q ident:%q argstr:%q expr:%q endstr:%q last:%q",locfuncstr,ident,argstr,expr,endstr,tostring(last))) --print("Found 1 local as Localrec") return table.concat({locfuncstr,ident,"(",argstr,")",expr,endstr}) + ]==] end, ["Continue"] = function(ast,tbl) local ret @@ -653,34 +726,6 @@ syntax = { end, } - - ---Removes extra spaces and duplicated ; from a string ---[[ -local function removespaces(str) - local removables = { - {"%s*%)%s*","%)"}, --Spaces before or after ) - {"%s*%(%s*","%("}, --Spaces before or after ( - {"%s*;%s*",";"}, --Spaces before or after ; - {"%s*,%s*",","}, --Spaces before or after , - {";+",";"}, --Multiple ; in a row - {"^%s*",""}, --Spaces at the beginning of the file - {"%s*$",""}, --Spaces at the end of the file - {"%s+"," "}, --Multiple spaces in a row - } - --Order is important - for k,v in ipairs(removables) do - str = string.gsub(str,v[1],v[2]) - end - return str -end -]] - ---Compress the string, and adds a little decompression code at the top. ---local function compress(str) --- ---end - glum.minify = function(str, name) name = name or "anonymous" local ast, error_msg = parser.parse(str, name) @@ -688,7 +733,8 @@ glum.minify = function(str, name) error(error_msg) return nil end - print("in glum.minify, ast is ") + astwalker(ast) + print("After astwalker, ast is") printtable(ast) print("Finding string reps") local strreps = getstringreps(ast) diff --git a/src/parser_min.lua b/src/parser_min.lua index a627cc4..8750cfd 100644 --- a/src/parser_min.lua +++ b/src/parser_min.lua @@ -1,554 +1,804 @@ local a, b, d, e, c = "String", "errorinfo", "function", "cannot use '...' outside a vararg function", "SuffixedExp" - local f = {} - local g = require("lpeg") - local h - - if include ~= nil then - h = include("./scope.lua") - else - h = dofile("../src/scope.lua") +local f = {} +local g = require("lpeg") +local h + +if include ~= nil then + h = include("./scope.lua") +else + h = dofile("../src/scope.lua") +end + +g.locale(g) +local i, j, k = g.P, g.S, g.V +local l, m, n, o = g.C, g.Carg, g.Cb, g.Cc +local p, q, r, s, t = g.Cf, g.Cg, g.Cmt, g.Cp, g.Ct +local u, v, w = g.alpha, g.digit, g.alnum +local x = g.xdigit +local y = g.space +local z = h.lineno +local A, B = h.new_scope, h.end_scope +local C, D = h.new_function, h.end_function +local E, F = h.begin_loop, h.end_loop +local G = h.insideloop +local H = g.P("/*") +local I = g.P("*/") +local J = (1 - H) ^ 0 +local K = (1 - I) ^ 0 +local L = H * K * I + +local function M(N, O, P) + local Q, R = z(N.subject, O) + local S = "%s:%d:%d: syntax error, %s" + + return string.format(S, N.filename, Q, R, P) +end + +local function Q(R, S, T) + return T.ffp or S, T +end + +local function U() + return r(m(1), Q) * (l(k("OneWord")) + o("EOF")) / function(T, V) + T.unexpected = V + + return T end +end - g.locale(g) - local i, j, k = g.P, g.S, g.V - local l, m, n, o = g.C, g.Carg, g.Cb, g.Cc - local p, q, r, s, t = g.Cf, g.Cg, g.Cmt, g.Cp, g.Ct - local u, v, w = g.alpha, g.digit, g.alnum - local x = g.xdigit - local y = g.space - local z = h.lineno - local A, B = h.new_scope, h.end_scope - local C, D = h.new_function, h.end_function - local E, F = h.begin_loop, h.end_loop - local G = h.insideloop - local H = g.P("/*") - local I = g.P("*/") - local J = (1 - H) ^ 0 - local K = (1 - I) ^ 0 - local L = H * K * I - - local function M(N, O, P) - local Q, R = z(N.subject, O) - local S = "%s:%d:%d: syntax error, %s" - - return string.format(S, N.filename, Q, R, P) +local function V() + return U() / function(T) + local W = T.ffp or 1 + local P = "unexpected '%s', expecting %s" + P = string.format(P, T.unexpected, T.expected) + + return nil, M(T, W, P) + end +end + +local function W() + return V() +end + +local function X(R, S, T, Y) + if not T.ffp or T.ffp < S then + T.ffp = S + T.list = {} + T.list[Y] = Y + T.expected = "'" .. Y .. "'" + elseif S == T.ffp then end - local function Q(R, S, T) - return T.ffp or S, T + return false +end + +local function Z(aa) + return r(m(1) * o(aa), X) +end + +local function ba(ca) + ca = string.gsub(ca, "\\a", "\a") + ca = string.gsub(ca, "\\b", "\b") + ca = string.gsub(ca, "\\f", "\f") + ca = string.gsub(ca, "\\n", "\n") + ca = string.gsub(ca, "\\r", "\r") + ca = string.gsub(ca, "\\t", "\t") + ca = string.gsub(ca, "\\v", "\v") + ca = string.gsub(ca, "\\\n", "\n") + ca = string.gsub(ca, "\\\r", "\n") + ca = string.gsub(ca, "\\'", "'") + ca = string.gsub(ca, [[\\"]], [["]]) + ca = string.gsub(ca, "\\\\", "\\") + + return ca +end + +local function da(ea, aa) + return ea * k("Skip") + Z(aa) * i(false) +end + +local function fa(ca) + return da(i(ca), ca) +end + +local function ga(ca) + return da(i(ca) * -k("idRest"), ca) +end + +local function ha(ia, ea) + return t(q(s(), "pos") * q(o(ia), "tag") * ea) +end + +local function ja(ka, la) + return { + ["tag"] = "Op", + ["pos"] = la.pos, + [1] = ka, + [2] = la + } +end + +local function ma(na, ka, oa) + if not ka then + return na + elseif ka == "add" then + orka"sub" + orka"mul" + orka"div" + orka"idiv" + orka"mod" + orka"pow" + orka"concat" + orka"band" + orka"bor" + orka"bxor" + orka"shl" + orka"shr" + orka"eq" + orka"lt" + orka"le" + orka"and" + orka"or" + elseif ka == "ne" then + elseif ka == "gt" then + elseif ka == "ge" then end +end + +local function pa(ea, qa, ra) + return p(ea * q(qa * ea) ^ 0, ma) + ra +end + +local function sa(ea, qa) + return p(ea * q(qa * ea) ^ 0, ma) +end + +local function ta(ea, qa, ia) + return ha(ia, (ea * (qa * ea) ^ 0) ^ (-1)) +end + +local function ua(ea, qa, ia) + return ha(ia, ea * (qa * ea) ^ 0) +end + +local va = { + k("Lua"), + ["Lua"] = k("Shebang") ^ (-1) * k("Skip") * k("Chunk") * -1 + W(), + ["Chunk"] = k("Block"), + ["StatList"] = (fa(";") + k("Stat")) ^ 0, + ["Var"] = k("Id"), + ["Id"] = ha("Id", da(k("Name"), "Name")), + ["FunctionDef"] = ga(d) * k("FuncBody"), + ["FieldSep"] = fa(",") + fa(";"), + ["Field"] = ha("Pair", (fa("[") * k("Expr") * fa("]") * fa("=") * k("Expr")) + (ha(a, da(k("Name"), "Name")) * fa("=") * k("Expr"))) + k("Expr"), + ["FieldList"] = (k("Field") * (k("FieldSep") * k("Field")) ^ 0 * k("FieldSep") ^ (-1)) ^ (-1), + ["Constructor"] = ha("Table", fa("{") * k("FieldList") * fa("}")), + ["NameList"] = ua(k("Id"), fa(","), "NameList"), + ["ExpList"] = ua(k("Expr"), fa(","), "ExpList"), + ["FuncArgs"] = fa("(") * (k("Expr") * (fa(",") * k("Expr")) ^ 0) ^ (-1) * fa(")") + k("Constructor") + ha(a, da(k(a), a)), + ["Expr"] = k("SubExpr_1"), + ["SubExpr_1"] = sa(k("SubExpr_2"), k("OrOp")), + ["SubExpr_2"] = sa(k("SubExpr_3"), k("AndOp")), + ["SubExpr_3"] = sa(k("SubExpr_4"), k("RelOp")), + ["SubExpr_4"] = sa(k("SubExpr_5"), k("BOrOp")), + ["SubExpr_5"] = sa(k("SubExpr_6"), k("BXorOp")), + ["SubExpr_6"] = sa(k("SubExpr_7"), k("BAndOp")), + ["SubExpr_7"] = sa(k("SubExpr_8"), k("ShiftOp")), + ["SubExpr_8"] = k("SubExpr_9") * k("ConOp") * k("SubExpr_8") / ma + k("SubExpr_9"), + ["SubExpr_9"] = sa(k("SubExpr_10"), k("AddOp")), + ["SubExpr_10"] = sa(k("SubExpr_11"), k("MulOp")), + ["SubExpr_11"] = k("UnOp") * k("SubExpr_11") / ja + k("SubExpr_12"), + ["SubExpr_12"] = k("SimpleExp") * (k("PowOp") * k("SubExpr_11")) ^ (-1) / ma, + ["SimpleExp"] = ha("Number", da(k("Number"), "Number")) + ha(a, da(k(a), a)) + ha("Nil", ga("nil")) + ha("False", ga("false")) + ha("True", ga("true")) + ha("Dots", fa("...")) + k("FunctionDef") + k("Constructor") + k(c), + [c] = p(k("PrimaryExp") * (ha("DotIndex", fa(".") * ha(a, da(k("Name"), "Name"))) + ha("ArrayIndex", fa("[") * k("Expr") * fa("]")) + ha("Invoke", q(fa(":") * ha(a, da(k("Name"), "Name")) * k("FuncArgs"))) + ha("Call", k("FuncArgs"))) ^ 0, function(wa, xa) + if xa then + if xa.tag == "Call" then + orxa.tag"Invoke" + + local T = { + ["tag"] = xa.tag, + ["pos"] = wa.pos, + [1] = wa + } - local function U() - return r(m(1), Q) * (l(k("OneWord")) + o("EOF")) / function(T, V) - T.unexpected = V + for ya, za in ipairs(xa) do + table.insert(T, za) + end - return T + return T + else + return { + ["tag"] = "Index", + ["pos"] = wa.pos, + [1] = wa, + [2] = xa[1] + } + end end - end - local function V() - return U() / function(T) - local W = T.ffp or 1 - local P = "unexpected '%s', expecting %s" - P = string.format(P, T.unexpected, T.expected) + return wa + end), + ["PrimaryExp"] = k("Var") + ha("Paren", fa("(") * k("Expr") * fa(")")), + ["Block"] = ha("Block", k("StatList") * k("RetStat") ^ (-1)), + ["IfStat"] = ha("If", ga("if") * k("Expr") * ga("then") * k("Block") * (ga("elseif") * k("Expr") * ga("then") * k("Block")) ^ 0 * (ga("else") * k("Block")) ^ (-1) * ga("end")), + ["WhileStat"] = ha("While", ga("while") * k("Expr") * ga("do") * k("Block") * ga("end")), + ["DoStat"] = ga("do") * k("Block") * ga("end") / function(T) + T.tag = "Do" + + return T + end, + ["ForBody"] = ga("do") * k("Block"), + ["ForNum"] = ha("Fornum", k("Id") * fa("=") * k("Expr") * fa(",") * k("Expr") * (fa(",") * k("Expr")) ^ (-1) * k("ForBody")), + ["ForGen"] = ha("Forin", k("NameList") * ga("in") * k("ExpList") * k("ForBody")), + ["ForStat"] = ga("for") * (k("ForNum") + k("ForGen")) * ga("end"), + ["RepeatStat"] = ha("Repeat", ga("repeat") * k("Block") * ga("until") * k("Expr")), + ["FuncName"] = p(k("Id") * (fa(".") * ha(a, da(k("Name"), "Name"))) ^ 0, function(wa, xa) + if xa then + return { + ["tag"] = "Index", + ["pos"] = wa.pos, + [1] = wa, + [2] = xa + } + end - return nil, M(T, W, P) - end - end + return wa + end) * (fa(":") * ha(a, da(k("Name"), "Name"))) ^ (-1) / function(wa, xa) + if xa then + return { + ["tag"] = "Index", + ["pos"] = wa.pos, + ["is_method"] = true, + [1] = wa, + [2] = xa + } + end - local function W() - return V() - end + return wa + end, + ["ParList"] = k("NameList") * (fa(",") * fa("...") * ha("Dots", s())) ^ (-1) / function(T, ya) + if ya then + table.insert(T, ya) + end - local function X(R, S, T, Y) - if not T.ffp or T.ffp < S then - T.ffp = S - T.list = {} - T.list[Y] = Y - T.expected = "'" .. Y .. "'" - elseif S == T.ffp then - end + return T + end + fa("...") * ha("Dots", s()) / function(ya) return {ya} end + i(true) / function() return {} end, + ["FuncBody"] = ha("Function", fa("(") * k("ParList") * fa(")") * k("Block") * ga("end")), + ["FuncStat"] = ha("Set", ga(d) * k("FuncName") * k("FuncBody")) / function(T) + if T[1].is_method then + table.insert(T[2][1], 1, { + ["tag"] = "Id", + [1] = "self" + }) + end - return false - end + T[1] = {T[1]} + T[2] = {T[2]} + + return T + end, + ["LocalFunc"] = ha("Localrec", ga(d) * k("Id") * k("FuncBody")) / function(T) + T[1] = {T[1]} + T[2] = {T[2]} + + return T + end, + ["LocalAssign"] = ha("Local", k("NameList") * ((fa("=") * k("ExpList")) + t(o()))), + ["LocalStat"] = ga("local") * (k("LocalFunc") + k("LocalAssign")), + ["LabelStat"] = ha("Label", fa("::") * da(k("Name"), "Name") * fa("::")), + ["BreakStat"] = ha("Break", ga("break")), + ["ContinueStat"] = ha("Continue", ga("continue")), + ["GoToStat"] = ha("Goto", ga("goto") * da(k("Name"), "Name")), + ["RetStat"] = ha("Return", ga("return") * (k("Expr") * (fa(",") * k("Expr")) ^ 0) ^ (-1) * fa(";") ^ (-1)), + ["ExprStat"] = r((k(c) * (o(function() + local za = {...} + local Aa = za[#za] + table.remove(za) + + for Ba, ya in ipairs(za) do + if ya.tag == "Id" then + orya.tag"Index" + else + za[Ba] = ya - local function Z(aa) - return r(m(1) * o(aa), X) - end + return false + end + end - local function ba(ca) - ca = string.gsub(ca, "\\a", "\a") - ca = string.gsub(ca, "\\b", "\b") - ca = string.gsub(ca, "\\f", "\f") - ca = string.gsub(ca, "\\n", "\n") - ca = string.gsub(ca, "\\r", "\r") - ca = string.gsub(ca, "\\t", "\t") - ca = string.gsub(ca, "\\v", "\v") - ca = string.gsub(ca, "\\\n", "\n") - ca = string.gsub(ca, "\\\r", "\n") - ca = string.gsub(ca, "\\'", "'") - ca = string.gsub(ca, [[\\"]], [["]]) - ca = string.gsub(ca, "\\\\", "\\") - - return ca - end + za.tag = "VarList" + za.pos = za[1].pos - local function da(ea, aa) - return ea * k("Skip") + Z(aa) * i(false) - end + return true, { + ["tag"] = "Set", + ["pos"] = za.pos, + [1] = za, + [2] = Aa + } + end) * k("Assignment"))) + (k(c) * (o(function(R) + if R.tag == "Call" then + orR.tag"Invoke" + else + return true, R + end - local function fa(ca) - return da(i(ca), ca) - end + return false + end))), function(R, S, za, Aa, ...) return Aa(za, ...) end), + ["Assignment"] = ((fa(",") * k(c)) ^ 1) ^ (-1) * fa("=") * k("ExpList"), + ["Stat"] = k("IfStat") + k("WhileStat") + k("DoStat") + k("ForStat") + k("RepeatStat") + k("FuncStat") + k("LocalStat") + k("LabelStat") + k("BreakStat") + k("GoToStat") + k("ExprStat") + k("ContinueStat"), + ["Space"] = y ^ 1, + ["Equals"] = i("=") ^ 0, + ["Open"] = "[" * q(k("Equals"), "init") * "[" * i("\n") ^ (-1), + ["Close"] = "]" * l(k("Equals")) * "]", + ["CloseEQ"] = r(k("Close") * n("init"), function(R, S, ra, Ba) return ra == Ba end), + ["LongString"] = k("Open") * l((i(1) - k("CloseEQ")) ^ 0) * k("Close") / function(R, Ca) return R end, + ["Comment"] = i("--") * k("LongString") / function() return end + i("--") * (i(1) - i("\n")) ^ 0 + i("//") * (i(1) - i("\n")) ^ 0 + l(L) / function() return end, + ["Skip"] = (k("Space") + k("Comment")) ^ 0, + ["idStart"] = u + i("_"), + ["idRest"] = w + i("_"), + ["Keywords"] = i("and") + "break" + "do" + "elseif" + "else" + "end" + "false" + "for" + d + "goto" + "if" + "in" + "local" + "nil" + "not" + "or" + "repeat" + "return" + "then" + "true" + "until" + "while" + "continue", + ["Reserved"] = k("Keywords") * -k("idRest"), + ["Identifier"] = k("idStart") * k("idRest") ^ 0, + ["Name"] = -k("Reserved") * l(k("Identifier")) * -k("idRest"), + ["Hex"] = (i("0x") + i("0X")) * x ^ 1, + ["Expo"] = j("eE") * j("+-") ^ (-1) * v ^ 1, + ["Float"] = (((v ^ 1 * i(".") * v ^ 0) + (i(".") * v ^ 1)) * k("Expo") ^ (-1)) + (v ^ 1 * k("Expo")), + ["Int"] = v ^ 1, + ["Number"] = l(k("Hex") + k("Float") + k("Int")) / function(Y) return tonumber(Y) end, + ["ShortString"] = i([["]]) * l(((i("\\") * i(1)) + (i(1) - i([["]]))) ^ 0) * i([["]]) + i("'") * l(((i("\\") * i(1)) + (i(1) - i("'"))) ^ 0) * i("'"), + [a] = k("LongString") + (k("ShortString") / function(R) return R end), + ["OrOp"] = ga("or") / "or" + fa("||") / "or", + ["AndOp"] = ga("and") / "and" + fa("&&") / "and", + ["RelOp"] = fa("~=") / "ne" + fa("==") / "eq" + fa("<=") / "le" + fa(">=") / "ge" + fa("<") / "lt" + fa(">") / "gt" + fa("!=") / "ne", + ["BOrOp"] = fa("|") / "bor", + ["BXorOp"] = fa("~") / "bxor", + ["BAndOp"] = fa("&") / "band", + ["ShiftOp"] = fa("<<") / "shl" + fa(">>") / "shr", + ["ConOp"] = fa("..") / "concat", + ["AddOp"] = fa("+") / "add" + fa("-") / "sub", + ["MulOp"] = fa("*") / "mul" + fa("/") / "div" + fa("%") / "mod", + ["UnOp"] = ga("not") / "not" + fa("-") / "unm" + fa("#") / "len" + fa("~") / "bnot" + fa("!") / "not", + ["PowOp"] = fa("^") / "pow", + ["Shebang"] = i("#") * (i(1) - i("\n")) ^ 0 * i("\n"), + ["OneWord"] = k("Name") + k("Number") + k(a) + k("Reserved") + i("...") + i(1) + } + + local function Da(Ea, h, Fa) + local Ga = Fa[1] + forR = h + + do + if Ea[R].label[Ga] then return true end + end - local function ga(ca) - return da(i(ca) * -k("idRest"), ca) - end + return false + end - local function ha(ia, ea) - return t(q(s(), "pos") * q(o(ia), "tag") * ea) - end + local function Ga(Ea, Ha, O) + local h = Ea.scope + local Ia = Ea[h].label[Ha] - local function ja(ka, la) - return { - ["tag"] = "Op", - ["pos"] = la.pos, - [1] = ka, - [2] = la - } - end + if not Ia then + Ea[h].label[Ha] = { + ["name"] = Ha, + ["pos"] = O + } - local function ma(na, ka, oa) - if not ka then - return na - elseif ka == "add" then - orka"sub" - orka"mul" - orka"div" - orka"idiv" - orka"mod" - orka"pow" - orka"concat" - orka"band" - orka"bor" - orka"bxor" - orka"shl" - orka"shr" - orka"eq" - orka"lt" - orka"le" - orka"and" - orka"or" - elseif ka == "ne" then - elseif ka == "gt" then - elseif ka == "ge" then - end - end + return true + else + local P = "label '%s' already defined at line %d" + local Ja = z(Ea.errorinfo.subject, Ia.pos) + P = string.format(P, Ha, Ja) - local function pa(ea, qa, ra) - return p(ea * q(qa * ea) ^ 0, ma) + ra - end + return nil, M(Ea.errorinfo, O, P) + end + end - local function sa(ea, qa) - return p(ea * q(qa * ea) ^ 0, ma) - end + local function Ia(Ea, Fa) + local h = Ea.scope + table.insert(Ea[h].goto, Fa) - local function ta(ea, qa, ia) - return ha(ia, (ea * (qa * ea) ^ 0) ^ (-1)) - end + return true + end - local function ua(ea, qa, ia) - return ha(ia, ea * (qa * ea) ^ 0) - end + local function Ja(Ea) + forR = Ea.maxscope - local va = { - k("Lua"), - ["Lua"] = k("Shebang") ^ (-1) * k("Skip") * k("Chunk") * -1 + W(), - ["Chunk"] = k("Block"), - ["StatList"] = (fa(";") + k("Stat")) ^ 0, - ["Var"] = k("Id"), - ["Id"] = ha("Id", da(k("Name"), "Name")), - ["FunctionDef"] = ga(d) * k("FuncBody"), - ["FieldSep"] = fa(",") + fa(";"), - ["Field"] = ha("Pair", (fa("[") * k("Expr") * fa("]") * fa("=") * k("Expr")) + (ha(a, da(k("Name"), "Name")) * fa("=") * k("Expr"))) + k("Expr"), - ["FieldList"] = (k("Field") * (k("FieldSep") * k("Field")) ^ 0 * k("FieldSep") ^ (-1)) ^ (-1), - ["Constructor"] = ha("Table", fa("{") * k("FieldList") * fa("}")), - ["NameList"] = ua(k("Id"), fa(","), "NameList"), - ["ExpList"] = ua(k("Expr"), fa(","), "ExpList"), - ["FuncArgs"] = fa("(") * (k("Expr") * (fa(",") * k("Expr")) ^ 0) ^ (-1) * fa(")") + k("Constructor") + ha(a, da(k(a), a)), - ["Expr"] = k("SubExpr_1"), - ["SubExpr_1"] = sa(k("SubExpr_2"), k("OrOp")), - ["SubExpr_2"] = sa(k("SubExpr_3"), k("AndOp")), - ["SubExpr_3"] = sa(k("SubExpr_4"), k("RelOp")), - ["SubExpr_4"] = sa(k("SubExpr_5"), k("BOrOp")), - ["SubExpr_5"] = sa(k("SubExpr_6"), k("BXorOp")), - ["SubExpr_6"] = sa(k("SubExpr_7"), k("BAndOp")), - ["SubExpr_7"] = sa(k("SubExpr_8"), k("ShiftOp")), - ["SubExpr_8"] = k("SubExpr_9") * k("ConOp") * k("SubExpr_8") / ma + k("SubExpr_9"), - ["SubExpr_9"] = sa(k("SubExpr_10"), k("AddOp")), - ["SubExpr_10"] = sa(k("SubExpr_11"), k("MulOp")), - ["SubExpr_11"] = k("UnOp") * k("SubExpr_11") / ja + k("SubExpr_12"), - ["SubExpr_12"] = k("SimpleExp") * (k("PowOp") * k("SubExpr_11")) ^ (-1) / ma, - ["SimpleExp"] = ha("Number", da(k("Number"), "Number")) + ha(a, da(k(a), a)) + ha("Nil", ga("nil")) + ha("False", ga("false")) + ha("True", ga("true")) + ha("Dots", fa("...")) + k("FunctionDef") + k("Constructor") + k(c), - [c] = p(k("PrimaryExp") * (ha("DotIndex", fa(".") * ha(a, da(k("Name"), "Name"))) + ha("ArrayIndex", fa("[") * k("Expr") * fa("]")) + ha("Invoke", q(fa(":") * ha(a, da(k("Name"), "Name")) * k("FuncArgs"))) + ha("Call", k("FuncArgs"))) ^ 0, function(wa, xa) - if xa then - if xa.tag == "Call" then - orxa.tag"Invoke" - - local T = { - ["tag"] = xa.tag, - ["pos"] = wa.pos, - [1] = wa - } + do + for Ka, ya in ipairs(Ea[R].goto) do + if not Da(Ea, R, ya) then + local P = "no visible label '%s' for <goto>" + P = string.format(P, ya[1]) - for ya, za in ipairs(xa) do - table.insert(T, za) + return nil, M(Ea.errorinfo, ya.pos, P) + end end + end - return T - else - return { - ["tag"] = "Index", - ["pos"] = wa.pos, - [1] = wa, - [2] = xa[1] - } + return true + end + + local function Ka(Ea, La) + Ea.Ea.fscope.is_vararg = La + end + + local Ma, Na, Oa + local Pa, Qa, Ra, Sa + + Sa = function(Ea, Ta) + local Ua = #Ta + local La = false + + if 0 < Ua and Ta[Ua].tag == "Dots" then + La = true end + + Ka(Ea, La) + + return true end - return wa - end), - ["PrimaryExp"] = k("Var") + ha("Paren", fa("(") * k("Expr") * fa(")")), - ["Block"] = ha("Block", k("StatList") * k("RetStat") ^ (-1)), - ["IfStat"] = ha("If", ga("if") * k("Expr") * ga("then") * k("Block") * (ga("elseif") * k("Expr") * ga("then") * k("Block")) ^ 0 * (ga("else") * k("Block")) ^ (-1) * ga("end")), - ["WhileStat"] = ha("While", ga("while") * k("Expr") * ga("do") * k("Block") * ga("end")), - ["DoStat"] = ga("do") * k("Block") * ga("end") / function(T) - T.tag = "Do" - - return T - end, - ["ForBody"] = ga("do") * k("Block"), - ["ForNum"] = ha("Fornum", k("Id") * fa("=") * k("Expr") * fa(",") * k("Expr") * (fa(",") * k("Expr")) ^ (-1) * k("ForBody")), - ["ForGen"] = ha("Forin", k("NameList") * ga("in") * k("ExpList") * k("ForBody")), - ["ForStat"] = ga("for") * (k("ForNum") + k("ForGen")) * ga("end"), - ["RepeatStat"] = ha("Repeat", ga("repeat") * k("Block") * ga("until") * k("Expr")), - ["FuncName"] = p(k("Id") * (fa(".") * ha(a, da(k("Name"), "Name"))) ^ 0, function(wa, xa) - if xa then - return { - ["tag"] = "Index", - ["pos"] = wa.pos, - [1] = wa, - [2] = xa - } - end + local function Ua(Ea, Va) + C(Ea) + A(Ea) + local Wa, P = Sa(Ea, Va[1]) + if not Wa then return Wa, P end + Wa, P, Wa, P = Pa(Ea, Va[2]) + if not Wa then return Wa, P end + B(Ea) + D(Ea) + + return true + end - return wa - end) * (fa(":") * ha(a, da(k("Name"), "Name"))) ^ (-1) / function(wa, xa) - if xa then - return { - ["tag"] = "Index", - ["pos"] = wa.pos, - ["is_method"] = true, - [1] = wa, - [2] = xa - } - end + local function Wa(Ea, Va) + local Xa, P = Na(Ea, Va[2]) + if not Xa then return Xa, P end - return wa - end, - ["ParList"] = k("NameList") * (fa(",") * fa("...") * ha("Dots", s())) ^ (-1) / function(T, ya) - if ya then - table.insert(T, ya) - end + if Va[3] then + Xa, P, Xa, P = Na(Ea, Va[3]) + if not Xa then return Xa, P end + end - return T - end + fa("...") * ha("Dots", s()) / function(ya) return {ya} end + i(true) / function() return {} end, - ["FuncBody"] = ha("Function", fa("(") * k("ParList") * fa(")") * k("Block") * ga("end")), - ["FuncStat"] = ha("Set", ga(d) * k("FuncName") * k("FuncBody")) / function(T) - if T[1].is_method then - table.insert(T[2][1], 1, { - ["tag"] = "Id", - [1] = "self" - }) - end + return true + end - T[1] = {T[1]} - T[2] = {T[2]} - - return T - end, - ["LocalFunc"] = ha("Localrec", ga(d) * k("Id") * k("FuncBody")) / function(T) - T[1] = {T[1]} - T[2] = {T[2]} - - return T - end, - ["LocalAssign"] = ha("Local", k("NameList") * ((fa("=") * k("ExpList")) + t(o()))), - ["LocalStat"] = ga("local") * (k("LocalFunc") + k("LocalAssign")), - ["LabelStat"] = ha("Label", fa("::") * da(k("Name"), "Name") * fa("::")), - ["BreakStat"] = ha("Break", ga("break")), - ["ContinueStat"] = ha("Continue", ga("continue")), - ["GoToStat"] = ha("Goto", ga("goto") * da(k("Name"), "Name")), - ["RetStat"] = ha("Return", ga("return") * (k("Expr") * (fa(",") * k("Expr")) ^ 0) ^ (-1) * fa(";") ^ (-1)), - ["ExprStat"] = r((k(c) * (o(function() - local za = {...} - local Aa = za[#za] - table.remove(za) - - for Ba, ya in ipairs(za) do - if ya.tag == "Id" then - orya.tag"Index" - else - za[Ba] = ya - - return false - end - end + local function Xa(Ea, Va) + local Ya, P = Na(Ea, Va[1]) + if not Ya then return Ya, P end - za.tag = "VarList" - za.pos = za[1].pos + return true + end - return true, { - ["tag"] = "Set", - ["pos"] = za.pos, - [1] = za, - [2] = Aa - } - end) * k("Assignment"))) + (k(c) * (o(function(R) - if R.tag == "Call" then - orR.tag"Invoke" + local function Ya(Ea, Za) + for ab, ya in ipairs(Za) do + local ia = ya.tag + + if ia == "Pair" then + local bb, P = Na(Ea, ya[1]) + if not bb then return bb, P end + bb, P, bb, P = Na(Ea, ya[2]) + if not bb then return bb, P end else - return true, R + local bb, P = Na(Ea, ya) + if not bb then return bb, P end end + end - return false - end))), function(R, S, za, Aa, ...) return Aa(za, ...) end), - ["Assignment"] = ((fa(",") * k(c)) ^ 1) ^ (-1) * fa("=") * k("ExpList"), - ["Stat"] = k("IfStat") + k("WhileStat") + k("DoStat") + k("ForStat") + k("RepeatStat") + k("FuncStat") + k("LocalStat") + k("LabelStat") + k("BreakStat") + k("GoToStat") + k("ExprStat") + k("ContinueStat"), - ["Space"] = y ^ 1, - ["Equals"] = i("=") ^ 0, - ["Open"] = "[" * q(k("Equals"), "init") * "[" * i("\n") ^ (-1), - ["Close"] = "]" * l(k("Equals")) * "]", - ["CloseEQ"] = r(k("Close") * n("init"), function(R, S, ra, Ba) return ra == Ba end), - ["LongString"] = k("Open") * l((i(1) - k("CloseEQ")) ^ 0) * k("Close") / function(R, Ca) return R end, - ["Comment"] = i("--") * k("LongString") / function() return end + i("--") * (i(1) - i("\n")) ^ 0 + i("//") * (i(1) - i("\n")) ^ 0 + l(L) / function() return end, - ["Skip"] = (k("Space") + k("Comment")) ^ 0, - ["idStart"] = u + i("_"), - ["idRest"] = w + i("_"), - ["Keywords"] = i("and") + "break" + "do" + "elseif" + "else" + "end" + "false" + "for" + d + "goto" + "if" + "in" + "local" + "nil" + "not" + "or" + "repeat" + "return" + "then" + "true" + "until" + "while" + "continue", - ["Reserved"] = k("Keywords") * -k("idRest"), - ["Identifier"] = k("idStart") * k("idRest") ^ 0, - ["Name"] = -k("Reserved") * l(k("Identifier")) * -k("idRest"), - ["Hex"] = (i("0x") + i("0X")) * x ^ 1, - ["Expo"] = j("eE") * j("+-") ^ (-1) * v ^ 1, - ["Float"] = (((v ^ 1 * i(".") * v ^ 0) + (i(".") * v ^ 1)) * k("Expo") ^ (-1)) + (v ^ 1 * k("Expo")), - ["Int"] = v ^ 1, - ["Number"] = l(k("Hex") + k("Float") + k("Int")) / function(Y) return tonumber(Y) end, - ["ShortString"] = i([["]]) * l(((i("\\") * i(1)) + (i(1) - i([["]]))) ^ 0) * i([["]]) + i("'") * l(((i("\\") * i(1)) + (i(1) - i("'"))) ^ 0) * i("'"), - [a] = k("LongString") + (k("ShortString") / function(R) return R end), - ["OrOp"] = ga("or") / "or" + fa("||") / "or", - ["AndOp"] = ga("and") / "and" + fa("&&") / "and", - ["RelOp"] = fa("~=") / "ne" + fa("==") / "eq" + fa("<=") / "le" + fa(">=") / "ge" + fa("<") / "lt" + fa(">") / "gt" + fa("!=") / "ne", - ["BOrOp"] = fa("|") / "bor", - ["BXorOp"] = fa("~") / "bxor", - ["BAndOp"] = fa("&") / "band", - ["ShiftOp"] = fa("<<") / "shl" + fa(">>") / "shr", - ["ConOp"] = fa("..") / "concat", - ["AddOp"] = fa("+") / "add" + fa("-") / "sub", - ["MulOp"] = fa("*") / "mul" + fa("/") / "div" + fa("%") / "mod", - ["UnOp"] = ga("not") / "not" + fa("-") / "unm" + fa("#") / "len" + fa("~") / "bnot" + fa("!") / "not", - ["PowOp"] = fa("^") / "pow", - ["Shebang"] = i("#") * (i(1) - i("\n")) ^ 0 * i("\n"), - ["OneWord"] = k("Name") + k("Number") + k(a) + k("Reserved") + i("...") + i(1) - } + return true + end - local function Da(Ea, h, Fa) - local Ga = Fa[1] + local function ab(Ea, Va) + if not Ea.Ea.fscope.is_vararg then + local P = e - for R = h, 0, -1 do - if Ea[R].label[Ga] then return true end - end + return nil, M(Ea.errorinfo, Va.pos, P) + end + + return true + end - return false + local function bb(Ea, cb) + local db, P = Na(Ea, cb[1]) + if not db then return db, P end + forS = 2 + + do + db, P, db, P = Na(Ea, cb[S]) + if not db then return db, P end end - local function Ga(Ea, Ha, O) - local h = Ea.scope - local Ia = Ea[h].label[Ha] + return true + end - if not Ia then - Ea[h].label[Ha] = { - ["name"] = Ha, - ["pos"] = O - } + local function db(Ea, eb) + local fb, P = Na(Ea, eb[1]) + if not fb then return fb, P end + forS = 3 - return true - else - local P = "label '%s' already defined at line %d" - local Ja = z(Ea.errorinfo.subject, Ia.pos) - P = string.format(P, Ha, Ja) + do + fb, P, fb, P = Na(Ea, eb[S]) + if not fb then return fb, P end + end - return nil, M(Ea.errorinfo, O, P) - end + return true + end + + local function fb(Ea, Fa) + local gb, P = Ra(Ea, Fa[1]) + if not gb then return gb, P end + gb, P, gb, P = Qa(Ea, Fa[2]) + if not gb then return gb, P end + + return true + end + + local function gb(Ea, Fa) + if not G(Ea) then + local P = "<break> not inside a loop" + + return nil, M(Ea.errorinfo, Fa.pos, P) end - local function Ia(Ea, Fa) - local h = Ea.scope - table.insert(Ea[h].goto, Fa) + return true + end + + local function hb(Ea, Fa) + if not G(Ea) then + local P = "<continue> not inside a loop" - return true + return nil, M(Ea.errorinfo, Fa.pos, P) end - local function Ja(Ea) - for R = Ea.maxscope, 0, -1 do - for Ka, ya in ipairs(Ea[R].goto) do - ifnot"someString" - Da(Ea, R, ya) - local P = "no visible label '%s' for <goto>" - P = string.format(P, ya[1]) + return true + end - return nil, M(Ea.errorinfo, ya.pos, P) - end - end + local function ib(Ea, Fa) + E(Ea) + A(Ea) + local jb, P = Qa(Ea, Fa[2]) + if not jb then return jb, P end + jb, P, jb, P = Pa(Ea, Fa[3]) + if not jb then return jb, P end + B(Ea) + F(Ea) + + return true + end + + local function jb(Ea, Fa) + local kb, P + E(Ea) + A(Ea) + kb, P, kb, P = Na(Ea, Fa[2]) + if not kb then return kb, P end + kb, P, kb, P = Na(Ea, Fa[3]) + if not kb then return kb, P end + + if Fa[5] then + kb, P, kb, P = Na(Ea, Fa[4]) + if not kb then return kb, P end + kb, P, kb, P = Pa(Ea, Fa[5]) + if not kb then return kb, P end + else + kb, P, kb, P = Pa(Ea, Fa[4]) + if not kb then return kb, P end end - return true, Ka(Ea, La), Ea.Ea.fscope.is_vararg{ - someVariable = La, - Na, - Oa or Pa, - Qa, - Ra, - Sa{ - Sa = function(Ea, Ta) - local Ua = #Ta - local La = false - - if 0 < Ua and Ta[Ua].tag == "Dots" then - La = true - end - - Ka(Ea, La) - - return true - end, - Ua(Ea, Va) - }(Ea) - }(Ea), P, Sa(Ea, Va[1]), not Wa, P, P, Wa, P, Pa(Ea, Va[2]), not Wa, P, (Ea), (Ea), true, Wa(Ea, Va), P, Na(Ea, Va[2]), not Xa, Xa, P, Va[3], P, Xa, P, Na(Ea, Va[3]), not Xa, Xa, P, true, Xa(Ea, Va), P, Na(Ea, Va[1]), not Ya, Ya, P, true, Ya(Ea, Za), ya, (Za){ - ia = ya.tag, - ia == "Pair", - P = Na(Ea, ya[1]), - not bb, - P or bb, - P, - bb, - P = Na(Ea, ya[2]), - not bb, - bb, - P or bb, - P = Na(Ea, ya), - not bb, bb, P or true, ab(Ea, Va) - }, not Ea.Ea.fscope.is_vararg{ - P = e - }, M(Ea.errorinfo, Va.pos, P), true, bb(Ea, cb), P, Na(Ea, cb[1]), not db, db, P{ - S = 2, - #cb - }, P, db, P, Na(Ea, cb[S]), not db, db, P, true, db(Ea, eb), P, Na(Ea, eb[1]), not fb, fb, P{ - S = 3, - #eb - }, P, fb, P, Na(Ea, eb[S]), not fb, fb, P, true, fb(Ea, Fa), P, Ra(Ea, Fa[1]), not gb, P, P, gb, P, Qa(Ea, Fa[2]), not gb, gb, P, true, gb(Ea, Fa), ifnot, (Ea), P"<break> not inside a loop", M(Ea.errorinfo, Fa.pos, P), true, hb(Ea, Fa), ifnot, (Ea), P"<continue> not inside a loop", M(Ea.errorinfo, Fa.pos, P), true, ib(Ea, Fa), (Ea), (Ea), P, Qa(Ea, Fa[2]), not jb, P, P, jb, P, Pa(Ea, Fa[3]), not jb, P, (Ea), (Ea), true, jb(Ea, Fa), P, (Ea), (Ea), P, kb, P, Na(Ea, Fa[2]), not kb, P, P, kb, P, Na(Ea, Fa[3]), not kb, kb, P, Fa[5], P, kb, P, Na(Ea, Fa[4]), not kb, P, P, kb, P, Pa(Ea, Fa[5]), not kb, kb, P, P, kb, P, Pa(Ea, Fa[4]), not kb, kb, P, (Ea), (Ea), true, kb(Ea, Fa), P, Ia(Ea, Fa), not lb, lb, P, true, lb(Ea, Fa){ - mb = #Fa - } % 2 == 0, mb, 2, P, Na(Ea, Fa[S]), not nb, P, P, nb, P, Pa(Ea, Fa[S + 1]), not nb, nb, P, mb - 1, 2, P, Na(Ea, Fa[S]), not nb, P, P, nb, P, Pa(Ea, Fa[S + 1]), not nb, nb, P, P, Pa(Ea, Fa[mb]), not nb, nb, P, true, mb(Ea, Fa), P, Ga(Ea, Fa[1], Fa.pos), not nb, nb, P, true, nb(Ea, Fa), P, Qa(Ea, Fa[2]), not ob, ob, P, true, ob(Ea, Fa), P, Na(Ea, Fa[2][1]), not pb, pb, P, true, pb(Ea, Fa), (Ea), P, Pa(Ea, Fa[1]), not qb, P, P, qb, P, Na(Ea, Fa[2]), not qb, P, (Ea), true, qb(Ea, Fa), P, Qa(Ea, Fa), not rb, rb, P, true, rb(Ea, Fa), (Ea), P, Na(Ea, Fa[1]), not sb, P, P, sb, P, Pa(Ea, Fa[2]), not sb, P, (Ea), true, function(Ea, sb) - local ia = sb.tag - - if ia == "Id" then - return true - elseif ia == "Index" then - thenelse"expecting a variable, but got a " - ia() - end - end, function(Ea, tb) - for ub, ya in ipairs(tb) do - local vb, P = Oa(Ea, ya) - if not vb then return vb, P end - end + B(Ea) + F(Ea) - return true - end, function(Ea, Va) - local ia = Va.tag - - if ia == "Nil" then - oria"True" - oria"False" - oria"Number" - oria"someString" - - return true - elseif ia == "Dots" then - elseif ia == "Function" then - elseif ia == "Table" then - elseif ia == "Op" then - elseif ia == "Paren" then - elseif ia == "Call" then - elseif ia == "Invoke" then - elseif ia == "Id" then - oria"Index" - thenelse"expecting an expression, but got a " - ia() + return true + end + + local function kb(Ea, Fa) + local lb, P = Ia(Ea, Fa) + if not lb then return lb, P end + + return true + end + + local function lb(Ea, Fa) + local mb = #Fa + + if mb % 2 == 0 then + forS = 1 + + do + local nb, P = Na(Ea, Fa[S]) + if not nb then return nb, P end + nb, P, nb, P = Pa(Ea, Fa[S + 1]) + if not nb then return nb, P end end - end, function(Ea, ub) - for vb, ya in ipairs(ub) do - local wb, P = Na(Ea, ya) - if not wb then return wb, P end + else + forS = 1 + + do + local nb, P = Na(Ea, Fa[S]) + if not nb then return nb, P end + nb, P, nb, P = Pa(Ea, Fa[S + 1]) + if not nb then return nb, P end end + local nb, P = Pa(Ea, Fa[mb]) + if not nb then return nb, P end + end + + return true + end + + local function mb(Ea, Fa) + local nb, P = Ga(Ea, Fa[1], Fa.pos) + if not nb then return nb, P end + + return true + end + + local function nb(Ea, Fa) + local ob, P = Qa(Ea, Fa[2]) + if not ob then return ob, P end + + return true + end + + local function ob(Ea, Fa) + local pb, P = Na(Ea, Fa[2][1]) + if not pb then return pb, P end + + return true + end + + local function pb(Ea, Fa) + E(Ea) + local qb, P = Pa(Ea, Fa[1]) + if not qb then return qb, P end + qb, P, qb, P = Na(Ea, Fa[2]) + if not qb then return qb, P end + F(Ea) + + return true + end + + local function qb(Ea, Fa) + local rb, P = Qa(Ea, Fa) + if not rb then return rb, P end + + return true + end + + local function rb(Ea, Fa) + E(Ea) + local sb, P = Na(Ea, Fa[1]) + if not sb then return sb, P end + sb, P, sb, P = Pa(Ea, Fa[2]) + if not sb then return sb, P end + F(Ea) + + return true + end + + Oa = function(Ea, sb) + local ia = sb.tag + + if ia == "Id" then return true - end, function(Ea, Fa) - local ia = Fa.tag - - if ia == "Do" then - return Pa(Ea, Fa) - elseif ia == "Set" then - elseif ia == "While" then - elseif ia == "Repeat" then - elseif ia == "If" then - elseif ia == "Fornum" then - elseif ia == "Forin" then - elseif ia == "Local" then - elseif ia == "Localrec" then - elseif ia == "Goto" then - elseif ia == "Label" then - elseif ia == "Return" then - elseif ia == "Break" then - elseif ia == "Continue" then - elseif ia == "Call" then - elseif ia == "Invoke" then - thenelse"expecting a statement, but got a " - ia() - end - end, function(Ea, vb) - local wb = {} - A(Ea) + elseif ia == "Index" then + thenelse"expecting a variable, but got a " + ia() + end + end - for xb, ya in ipairs(vb) do - local yb, P = Ma(Ea, ya) - if not yb then return yb, P end - end + Ra = function(Ea, tb) + for ub, ya in ipairs(tb) do + local vb, P = Oa(Ea, ya) + if not vb then return vb, P end + end + + return true + end - B(Ea) + Na = function(Ea, Va) + local ia = Va.tag + + if ia == "Nil" then + oria"True" + oria"False" + oria"Number" + oria"someString" return true - end, wb(xb, N), assert(type(xb) == "table"), assert(type(N) == "table"), Ea, { + elseif ia == "Dots" then + elseif ia == "Function" then + elseif ia == "Table" then + elseif ia == "Op" then + elseif ia == "Paren" then + elseif ia == "Call" then + elseif ia == "Invoke" then + elseif ia == "Id" then + oria"Index" + thenelse"expecting an expression, but got a " + ia() + end + end + + Qa = function(Ea, ub) + for vb, ya in ipairs(ub) do + local wb, P = Na(Ea, ya) + if not wb then return wb, P end + end + + return true + end + + Ma = function(Ea, Fa) + local ia = Fa.tag + + if ia == "Do" then + return Pa(Ea, Fa) + elseif ia == "Set" then + elseif ia == "While" then + elseif ia == "Repeat" then + elseif ia == "If" then + elseif ia == "Fornum" then + elseif ia == "Forin" then + elseif ia == "Local" then + elseif ia == "Localrec" then + elseif ia == "Goto" then + elseif ia == "Label" then + elseif ia == "Return" then + elseif ia == "Break" then + elseif ia == "Continue" then + elseif ia == "Call" then + elseif ia == "Invoke" then + thenelse"expecting a statement, but got a " + ia() + end + end + + Pa = function(Ea, vb) + local wb = {} + A(Ea) + + for xb, ya in ipairs(vb) do + local yb, P = Ma(Ea, ya) + if not yb then return yb, P end + end + + B(Ea) + + return true + end + + local function wb(xb, N) + assert(type(xb) == "table") + assert(type(N) == "table") + + local Ea = { [b] = N, [d] = {} - }, (Ea), Ka(Ea, true), P, Pa(Ea, xb), not yb, P, (Ea), P, yb, P, (Ea), not yb, yb, P, f.parse, function(yb, zb) - local N = { - ["subject"] = yb, - ["filename"] = zb - } + } - g.setmaxstack(1000) - local xb, Ab = g.match(va, yb, nil, N) - if not xb then return xb, Ab end + C(Ea) + Ka(Ea, true) + local yb, P = Pa(Ea, xb) + if not yb then return yb, P end + D(Ea) + yb, P, yb, P = Ja(Ea) + if not yb then return yb, P end - return wb(xb, N) - end + return xb + end + + f.parse = function(yb, zb) + local N = { + ["subject"] = yb, + ["filename"] = zb + } + + g.setmaxstack(1000) + local xb, Ab = g.match(va, yb, nil, N) + if not xb then return xb, Ab end + + return wb(xb, N) + end + + return f diff --git a/test/glum_spec.lua b/test/glum_spec.lua index e4c5749..3cee0ab 100644 --- a/test/glum_spec.lua +++ b/test/glum_spec.lua @@ -1,31 +1,50 @@ +--Tests glum to make sure it works correctly! + +--Come config stuff, you can edit this to your likeing +local config = { + lscmd = "ls -a \"%s\"", -- List directory contents command + ignoredirs = {".",".."} -- List of directories that appear in the above command that we should ignore +} + local tests = {} +describe("Finding tests",function() + --A function that looks for files in a directory, you might need to rewrite this for windows + local function scan_paths(path,tbl) + local pfile = io.popen(string.format(config.lscmd,path)) + local pdata = pfile:read("*all") + for filename in string.gmatch(pdata,"[^\n]+") do + if filename:find("%.lua$") then --It's a file, include it on the path + tbl[path .. "/" .. filename] = true + else + local shouldignore = false + + for k,v in pairs(config.ignoredirs) do + if filename == v then + shouldignore = true + break + end + end + + if not shouldignore then + scan_paths(path .. "/" .. filename,tbl) + end + end + end + end + + local t = {} + scan_paths("./tests",t) + tests = t +end) -describe("Initializeing tests",function() - local testnames = { - {"forinloop.lua", "forin loops"}, - {"fornumloop.lua","fornum loops"}, - {"invoke.lua","invokes"}, - {"call.lua","calls"}, - {"string.lua","strings"}, - } - for k,v in pairs(testnames) do - local file = io.open("./tests/"..v[1],"r") - tests[v[2]] = file:read("*a") - end +local glum +describe("Finding GLuM",function() + glum = dofile("../src/glum.lua") end) -describe("GLuM should", function() - local glum - it("initialize without error",function() - glum = dofile("../src/glum.lua") - end) - describe("output non-erroring minified code for",function() - for k,v in pairs(tests) do - it(k,function() - local miniftxt = glum.minify(v) - local minified = loadstring(miniftxt) - assert.has_no.errors(minified) - end) - end - end) +describe("GLuM", function() + for k,v in pairs(tests) do + local testcode = loadstring(v) + testcode() + end end) diff --git a/test/glum_test.lua b/test/glum_test.lua index e9447dd..2fdceb9 100644 --- a/test/glum_test.lua +++ b/test/glum_test.lua @@ -871,18 +871,21 @@ local str2 = [=[ --[[///////////////// ]] -local foo = 1 -if foo then print("bar") end -local function something(foo, bar) - print("foobar") -end -something(foo,4) +local obj = {} +obj.subobj = {} +obj.bar = 1 +obj.subobj.foo = function(foo,fizz) + foo.bar = foo.bar + 1 + print(fizz,foo.bar) +end +obj.subobj.foo(obj.subobj,"something") ]=] -local min = glum.minify(str) +--local min = glum.minify(str2) --local comp = ugly.uglify(min) -print(min) -print(string.format("Old size:%d\nNew size:%d",#str,#min)) +--print(min) +--print(string.format("Old size:%d\nNew size:%d",#str,#min)) +print(string.dump(CompileString(str2)())) --[[ local fuzzel = loadstring(f)() diff --git a/test/tests/call.lua b/test/tests/call.lua index 8549b7f..db79cf9 100644 --- a/test/tests/call.lua +++ b/test/tests/call.lua @@ -1,4 +1,6 @@ - +describe("Should minify calls to other functions correctly",function() + local minitxt = glum. +end) function afunction() print("You called a function!") end diff --git a/test/tests/valid_snippits/call.lua b/test/tests/valid_snippits/call.lua new file mode 100644 index 0000000..8549b7f --- /dev/null +++ b/test/tests/valid_snippits/call.lua @@ -0,0 +1,22 @@ + +function afunction() + print("You called a function!") +end + +function anotherfunction(num) + print("Thanks, I love " .. num .. "!") + return num == 0 and 1 or anotherfunction(num-1) +end + +local function yetanotherfunction(num) + print("Ew, I don't like " .. num .. ".") + return num <= 0 and 1 or yetanotherfunction(num/2) +end + +afunction() + +for k = 100,1000,100 do + anotherfunction(k) +end + +yetanotherfunction(2000) diff --git a/test/tests/valid_snippits/forinloop.lua b/test/tests/valid_snippits/forinloop.lua new file mode 100644 index 0000000..b9ee57b --- /dev/null +++ b/test/tests/valid_snippits/forinloop.lua @@ -0,0 +1,10 @@ + +local tbl = { + "Alpha", + "Beta", + "Charlie", +} + +for k,v in pairs(tbl) do + print(v) +end diff --git a/test/tests/valid_snippits/fornumloop.lua b/test/tests/valid_snippits/fornumloop.lua new file mode 100644 index 0000000..19ee201 --- /dev/null +++ b/test/tests/valid_snippits/fornumloop.lua @@ -0,0 +1,10 @@ + +local tbl = { + "Alpha", + "Beta", + "Charlie", +} + +for k = 1,#tbl do + print(v) +end diff --git a/test/tests/valid_snippits/invoke.lua b/test/tests/valid_snippits/invoke.lua new file mode 100644 index 0000000..568bc2d --- /dev/null +++ b/test/tests/valid_snippits/invoke.lua @@ -0,0 +1,12 @@ +local something = {} + +something.givenumber = function(self,num) + print("Thanks, I love " .. num .. "! It's much better than " .. self.lastnum) + self.lastnum = num +end + +something.lastnum = 0 + +something:givenumber(1) +something:givenumber(2) +something:givenumber(10) diff --git a/test/tests/valid_snippits/string.lua b/test/tests/valid_snippits/string.lua new file mode 100644 index 0000000..769d528 --- /dev/null +++ b/test/tests/valid_snippits/string.lua @@ -0,0 +1,8 @@ +local string = "what" + +local tbl = {} +local tbl2 = {} + +tbl[string] = 10 +tbl2.what = 10 +assert(tbl.what == tbl2[string],"Not equal") |
