aboutsummaryrefslogtreecommitdiff
path: root/src/glum.lua
diff options
context:
space:
mode:
Diffstat (limited to 'src/glum.lua')
-rw-r--r--src/glum.lua387
1 files changed, 257 insertions, 130 deletions
diff --git a/src/glum.lua b/src/glum.lua
index 969dc27..f4385c0 100644
--- a/src/glum.lua
+++ b/src/glum.lua
@@ -14,6 +14,11 @@ This moudle allows you to minify gLua code
lpeg
]]
+--Abandon all hope, ye who enter here
+--Refer to the comments at the top of parser.lua for what each function should do.
+--If anyone ever decides to add new language features, they need to be added to BOTH parser.lua and here.
+--Someone should rewrite this much cleaner.
+
local parser
local msg
if include ~= nil then
@@ -44,6 +49,10 @@ local function deepcopy(orig)
return copy
end
+--Is the last character in the built-so-far string a character?
+--Used to know if we should insert a space after it
+local last = false
+
--A list of reserved words that cannot be used as variable names
local nonames = {"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 reservednames = {}
@@ -130,49 +139,64 @@ local function stringfor(ast,tbl)
error("Attempted to use unknown tag type:" .. ast.tag)
end
end
---Abandon all hope, ye who enter here
---Refer to the comments at the top of parser.lua for what each function should do.
---If anyone ever decides to add new language features, they need to be added to BOTH parser.lua and here.
+
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
while ast[cursor] ~= nil do
argnames[cursor-1] = stringfor(ast[cursor],tbl)
cursor = cursor + 1
+ last = false
end
local argstring = table.concat(argnames,",")
local ostring = table.concat({exprname,"(",argstring,")"})
+ last = false
return ostring
end,
["Invoke"] = function(ast,tbl)
- local func = stringfor(ast[1],tbl)
- local invargs = {}
- for k = 3,#ast do
- invargs[#invargs + 1] = stringfor(ast[k],tbl)
- end
- local output = func
- local inv
- --A short hand if it's a simple thing
+ local ret = {}
+ ret[1] = stringfor(ast[1],tbl) -- The table
+ last = false
+ --If it's a . then use oo notation
if ast[2].tag == "String" and ast[2][1]:find(" ") == nil and tbl.strings[ast[2][1]] == nil then
- inv = ast[2][1]
- output = table.concat({output, ":", inv, "("})
+ ret[2] = ":"
+ ret[3] = ast[2][1]
+ ret[4] = "("
elseif tbl.strings[ast[2][1]] ~= nil then
- output = table.concat({output,"[", tbl.strings[ast[2][1]], "]","("})
+ ret[2] = "["
+ ret[3] = tbl.strings[ast[2][1]]
+ ret[4] = "]("
else
- inv = stringfor(ast[2],tbl)
- output = table.concat({output, "[", inv, "](", func, ","})
+ last = false
+ ret[2] = "["
+ ret[3] = stringfor(ast[2],tbl)
+ ret[4] = "]("
+ ret[5] = ast[1]
+ ret[6] = ","
+ end
+ last = false
+ local args = {}
+ for k = 3,#ast do
+ args[#args + 1] = stringfor(ast[k],tbl)
+ last = false
end
- output = output .. table.concat(invargs,",") .. ")"
- return output
+ ret[#ret+1] = table.concat(args,",")
+ ret[#ret+1] = ")"
+ last = false
+ return table.concat(ret)
end,
["String"] = function(ast,tbl)
local sop,eop = "\"","\""
- print("looking for",ast[1],"in")
- printtable(tbl.strings)
+ --print("looking for",ast[1],"in")
+ --printtable(tbl.strings)
if tbl.strings[ast[1]] then
- print("Found it, it is", tbl.strings[ast[1]])
+ --print("Found it, it is", tbl.strings[ast[1]])
return tbl.strings[ast[1]]
end
if tbl.strings[ast[1]] == nil then
@@ -182,41 +206,70 @@ syntax = {
end
return table.concat({sop,ast[1],eop})
end
- print("Returning non-catated string")
+ --print("Returning non-catated string")
+ last = false
return tbl.strings[ast[1]]
end,
["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
- return ast[1]
+ ret = ret .. ast[1]
+ last = true
+ return ret
end
- return tbl.ids[ast[1]]
+ ret = ret .. tbl.ids[ast[1]]
+ last = true
+ return ret
end,
["Index"] = function(ast,tbl)
local globalvar = stringfor(ast[1],tbl)
if ast[2].tag == "String" then
- return table.concat({globalvar, ".", ast[2][1]})
+ last = true
+ return table.concat({globalvar, ".", ast[2][1]})
end
- return table.concat({globalvar, "[", stringfor(ast[2],tbl), "]"})
+ last = false
+ local ret = table.concat({globalvar, "[", stringfor(ast[2],tbl), "]"})
+ last = false
+ return ret
end,
["Paren"] = function(ast,tbl)
+ last = false
return table.concat({"(",stringfor(ast[1],tbl),")"})
end,
["Dots"] = function(ast,tbl)
+ last = false
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
local nadd = deepcopy(tbl)
local nl = stringfor(ast[1],nadd)
+ codetbl[2] = nl
+ if last then codetbl[3] = " in" else codetbl[3] = "in" end
+ last = true
nadd.numlocals = nadd.numlocals + #ast[1]
- print("Found",#ast[1],"locals as Forin")
local el = stringfor(ast[2],nadd)
+ codetbl[4] = el
+ if last then codetbl[5] = " do" else codetbl[5] = "do" end
+ last = true
local code = stringfor(ast[3],nadd)
- local output = table.concat({" for ", nl, " in ", el, " do ", code, " end "})
+ codetbl[6] = code
+ if last then codetbl[7] = " end" else codetbl[7] = "end" end
+ last = true
+ local output = table.concat(codetbl)
tbl.numlocals = nadd.numlocals
return output
end,
["NameList"] = function(ast,tbl)
local outputtbl = {}
+ local bef
+ if last then bef = " " else bef = "" end
for k = 1,#ast do
if ast[k].tag ~= "Id" then
outputtbl[#outputtbl + 1] = stringfor(ast[k])
@@ -229,68 +282,121 @@ syntax = {
tbl.ids[ast[k][1]] = newvar
outputtbl[#outputtbl + 1] = newvar
end
+ last = false
end
end
- local output = table.concat(outputtbl, ",")
+ local output = bef .. table.concat(outputtbl, ",")
+ last = true
return output
end,
["ExpList"] = function(ast,tbl)
local exprs = {}
+ local bef
+ if last then bef = " " else bef = "" end
for k = 1,#ast do
exprs[k] = stringfor(ast[k],tbl)
+ last = false
end
+ last = true
return table.concat(exprs,",")
end,
["Nil"] = function(ast,tbl)
- return " nil "
+ local ret
+ if last then ret = " nil" else ret = "nil" end
+ last = true
+ return ret
end,
["True"] = function(ast,tbl)
- return " true "
+ local ret
+ if last then ret = " true" else ret = "true" end
+ last = true
+ return ret
end,
["False"] = function(ast,tbl)
- return " false "
+ local ret
+ if last then ret = " false" else ret = "false" end
+ last = true
+ return ret
end,
["Return"] = function(ast,tbl)
local retargs = {}
+ local ccat
+ if last then
+ ccat = " return"
+ else
+ ccat = "return"
+ end
+ last = true
for k,v in ipairs(ast) do
retargs[k] = stringfor(v,tbl)
+ last = false
end
- return " return " .. table.concat(retargs,",")
+ last = true
+ return ccat .. table.concat(retargs,",")
end,
["Do"] = function(ast,tbl)
local ntbl = deepcopy(tbl)
+ local argparts = {}
+ if last then argparts[1] = " do" else argparts[1] = "do" end
+ last = true
local allst = {}
for k = 1,#ast do
allst[k] = stringfor(ast[k],ntbl)
end
local code = table.concat(allst,";")
+ argparts[2] = code
tbl.numlocals = ntbl.numlocals
- return table.concat({" do ", code," end "})
+ if last then argparts[3] = " end" else argparts[3] = "end" end
+ last = true
+ return table.concat(argparts)
end,
["If"] = function(ast,tbl)
-
+ local exparts = {}
+ if last then exparts[1] = " if" else exparts[1] = "if" end
+ last = true
local expr1 = stringfor(ast[1],tbl)
+ exparts[2] = expr1
+ if last then exparts[3] = " then" else exparts[3] = "then" end
+ last = true
local block1 = stringfor(ast[2],tbl)
+ exparts[4] = block1
local codeblocks = {}
- codeblocks[#codeblocks + 1] = table.concat({" if ",expr1," then ",block1})
+ codeblocks[#codeblocks + 1] = table.concat(exparts)
for k = 3,#ast-1,2 do
+ local efargs = {}
+ if last then efargs[1] = " elseif" else efargs[1] = "elseif" end
+ last = true
local expr = stringfor(ast[k],tbl)
+ efargs[2] = expr
+ if last then efargs[3] = " then" else efargs[3] = "then" end
+ last = true
local block = stringfor(ast[k + 1],tbl)
- codeblocks[#codeblocks + 1] = table.concat({" elseif " , expr , " then " , block})
+ codeblocks[#codeblocks + 1] = table.concat(efargs)
end
if #ast % 2 == 1 then
local block = stringfor(ast[#ast],tbl)
if block ~= "" then --If for some reason there's an empty else block, forget about it.
- codeblocks[#codeblocks + 1] = " else " .. block
+ if last then
+ codeblocks[#codeblocks + 1] = " else" .. block
+ else
+ codeblocks[#codeblocks + 1] = "else" .. block
+ end
end
end
- codeblocks[#codeblocks + 1] = " end "
+ local estr
+ if last then estr = " end" else estr = "end" end
+ codeblocks[#codeblocks + 1] = estr
+ last = true
return table.concat(codeblocks)
end,
["Fornum"] = function(ast,tbl)
+ local spargs = {}
+ if last then spargs[1] = " for " else spargs[1] = "for " end
+ last = false
local var
+ assert(ast[1].tag == "Id","Oh no, I was expecting an ID!")
if ast[1].tag == "Id" then
if tbl.ids[ast[1][1]] ~= nil then
var = tbl.ids[ast[1][1]]
@@ -300,28 +406,52 @@ syntax = {
tbl.ids[ast[1][1]] = newvar
var = newvar
end
+ --[[
else
var = stringfor(ast[1],tbl)
+ ]]
end
+ spargs[2] = var
+ spargs[3] = "="
+ last = false
local start = stringfor(ast[2],tbl)
+ spargs[4] = start
+ spargs[5] = ","
+ last = false
local endnum = stringfor(ast[3],tbl)
+ spargs[6] = endnum
local incrementer = 1
local code = ""
+ spargs[7] = ""
if ast[4].tag ~= "Block" then -- incrementer
incrementer = stringfor(ast[4],tbl)
+ if incrementer ~= 1 then
+ spargs[7] = "," .. incrementer
+ end
+ if last then spargs[8] = " do" else spargs[8] = "do" end
+ last = true
code = stringfor(ast[5],tbl)
+ spargs[9] = code
+ if last then spargs[10] = " end" else spargs[10] = "end" end
+ last = true
else
+ if last then spargs[8] = " do" else spargs[8] = "do" end
+ last = true
code = stringfor(ast[4],tbl)
+ spargs[9] = code
+ if last then spargs[10] = " end" else spargs[10] = "end" end
+ last = true
end
local incstr = incrementer ~= 1 and ("," .. incrementer) or ""
tbl[var] = nil
tbl.numlocals = tbl.numlocals + 1
- print("Found 1 locals as Fornum")
- return table.concat({" for ",var,"=",start,",",endnum,incstr," do ",code," end "})
+ --print("Found 1 locals as Fornum")
+ return table.concat(spargs)
end,
["Op"] = function(ast,tbl)
+ --NOTE: Bitwise operators << and >> are not supported in LuaJIT (lua 5.1) and were introduced in lua 5.3, if the operators are ever supported, stuff should just work.
local binop = {
- ["or"] = " or ", ["and"] = " and ",
+ ["or"] = "or", ["and"] = "and",
["ne"] = "~=", ["eq"] = "==",
["le"] = "<=", ["ge"] = ">=",
["lt"] = "<", ["gt"] = ">",
@@ -333,7 +463,7 @@ syntax = {
["mod"] = "%", ["pow"] = "^",
}
local uniop = {
- ["len"] = "#", ["not"] = " not ",
+ ["len"] = "#", ["not"] = "not",
["unm"] = "-", ["bnot"] = "~",
}
local opname = ast[1]
@@ -342,14 +472,28 @@ syntax = {
--It translates ~= into not ==, but the order of operations makes it so == is evaluated first, and not second.
if opname == "not" and ast[2]["tag"] == "Op" and ast[2][1] == "eq" then
ast[2][1] = "ne"
- return stringfor(ast[2],tbl)
+ local ret = stringfor(ast[2],tbl)
+ return ret
end
local rhs = stringfor(ast[2],tbl)
- return uniop[opname] .. rhs
+ local bef
+ if last then bef = " " else bef = "" end
+ return bef .. uniop[opname] .. rhs
end
+ local sargs = {}
local lhs = stringfor(ast[2],tbl)
+ sargs[1] = lhs
+ if last and (opname == "or" or opname == "and") then
+ sargs[2] = " "
+ last = true
+ else
+ sargs[2] = ""
+ last = false
+ end
+ sargs[3] = binop[opname]
local rhs = stringfor(ast[3],tbl)
- local output = table.concat({lhs,binop[opname],rhs})
+ sargs[4] = rhs
+ local output = table.concat(sargs)
return output
end,
["Pair"] = function(ast,tbl)
@@ -359,25 +503,33 @@ syntax = {
end,
["Table"] = function(ast,tbl)
local fields = {}
+ last = false
for k = 1, #ast do
fields[#fields + 1] = stringfor(ast[k],tbl)
+ last = false
end
local fieldstr = table.concat(fields,",")
+ last = false
return table.concat({"{",fieldstr,"}"})
end,
["Number"] = function(ast,tbl)
- return ast[1]
+ local ret
+ if last then ret = " " .. ast[1] else ret = ast[1] end
+ last = true
+ return ret
end,
["Local"] = function(ast,tbl)
+ local bef
+ if last then bef = " " else bef = "" end
+ last = true
local lhs,rhs = stringfor(ast[1],tbl),nil
tbl.numlocals = tbl.numlocals + #ast[1]
- print("Found",#ast[1],"locals as Local")
+ --print("Found",#ast[1],"locals as Local")
+ local output = bef .. "local" .. lhs
if ast[2].tag ~= nil then
+ last = false
rhs = stringfor(ast[2],tbl)
- end
- local output = "local " .. lhs
- if ast[2].tag ~= nil then
- output = output .. "=" .. rhs .. ";"
+ output = output .. "=" .. rhs
end
return output
end,
@@ -385,7 +537,9 @@ syntax = {
local vars = {}
for k = 1,#ast do
vars[#vars + 1] = stringfor(ast[k],tbl)
+ last = false
end
+ last = true
return table.concat(vars,",")
end,
["Set"] = function(ast,tbl)
@@ -393,15 +547,17 @@ syntax = {
local a1 = ast[1].tag ~= nil and ast[1] or ast[1][1]
for k = 1,#ast[1] do
lhs[#lhs + 1] = stringfor(a1,tbl)
+ last = false
end
local rhs = {}
local a2 = ast[2].tag ~= nil and ast[2] or ast[2][1]
for k = 1,#ast[2] do
+ last = false
rhs[#rhs + 1] = stringfor(a2,tbl)
end
local ostring = table.concat(lhs,",")
ostring = ostring .. "=" .. table.concat(rhs,",")
- return ostring .. ";"
+ return ostring
end,
["Label"] = function(ast,tbl)
if tbl.nids[ast[1]] == nil then
@@ -409,6 +565,7 @@ syntax = {
tbl.lname = nextvar
tbl.nids[ast[1]] = nextvar
end
+ last = false
return "::" .. tbl.nids[ast[1]] .. "::"
end,
["Goto"] = function(ast,tbl)
@@ -417,12 +574,20 @@ syntax = {
tbl.lname = nextvar
tbl.nids[ast[1]] = nextvar
end
- return " goto " .. tbl.nids[ast[1]]
+ last = true
+ return (last and " " or "") .. "goto " .. tbl.nids[ast[1]]
end,
["Function"] = function(ast,tbl)
+ local funcstr
+ if last then funcstr = " function(" else funcstr = "function(" end
+ last = false
local funcargs = ast[1].tag ~= nil and stringfor(ast[1],tbl) or ""
+ last = false
local code = stringfor(ast[2],tbl)
- return table.concat({" function(",funcargs,")",code," end "})
+ local endstr
+ if last then endstr = " end" else endstr = "end" end
+ last = true
+ return table.concat({funcstr,funcargs,")",code,endstr})
end,
["Localrec"] = function(ast,tbl)
local ident
@@ -434,23 +599,46 @@ 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
local argstr = ast[2][1][1].tag ~= nil and stringfor(ast[2][1][1],tbl) or ""
+ last = false
local expr = stringfor(ast[2][1][2],tbl)
+ local endstr
+ if last then endstr = " end" else endstr = "end" end
+ last = true
tbl.numlocals = tbl.numlocals + 1
- print("Found 1 local as Localrec")
- return table.concat({" local function ",ident,"(",argstr,")",expr," end "})
+ 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)
- return " continue "
+ local ret
+ if last then ret = " continue" else ret = "continue" end
+ last = true
+ return ret
end,
["While"] = function(ast,tbl)
+ local whilestr
+ if last then whilestr = " while" else whilestr = "while" end
+ last = true
local expr = stringfor(ast[1],tbl)
+ local dostr
+ if last then dostr = " do" else dostr = "do" end
+ last = true
local block = stringfor(ast[2],tbl)
- local output = table.concat({" while " , expr , " do " , block , " end "})
+ local endstr
+ if last then endstr = " end" else endstr = "end" end
+ last = true
+ local output = table.concat({whilestr, expr , dostr, block , endstr})
return output
end,
["Break"] = function(ast,tbl)
- return " break "
+ local ret
+ if last then ret = " break" else ret = "break" end
+ last = true
+ return ret
end,
["Block"] = function(ast,oldtbl)
local tbl = deepcopy(oldtbl)
@@ -468,6 +656,7 @@ syntax = {
--Removes extra spaces and duplicated ; from a string
+--[[
local function removespaces(str)
local removables = {
{"%s*%)%s*","%)"}, --Spaces before or after )
@@ -485,6 +674,7 @@ local function removespaces(str)
end
return str
end
+]]
--Compress the string, and adds a little decompression code at the top.
--local function compress(str)
@@ -498,6 +688,8 @@ glum.minify = function(str, name)
error(error_msg)
return nil
end
+ print("in glum.minify, ast is ")
+ printtable(ast)
print("Finding string reps")
local strreps = getstringreps(ast)
printtable(strreps)
@@ -512,13 +704,12 @@ glum.minify = function(str, name)
--printtable(ast)
local lvt = deepcopy(olocalvar)
- local ret = stringfor(ast,olocalvar)
local numstrreplaced = 0
local maxlocals = lvt.numlocals
while
(numstrreplaced + maxlocals < 200) and --We have some locals left
(numstrreplaced < #strreps) and --We have more strings to replace
- (strreps[numstrreplaced+1][2] > 5) do --Replaceing this string will at least cover the cost of "local "
+ ((strreps[numstrreplaced + 1][2] * #strreps[numstrreplaced + 1][1]) > (strreps[numstrreplaced + 1][2] * 4 + 6)) do --Replaceing this string will at least cover the cost of "local " and []
numstrreplaced = numstrreplaced + 1
local nvar = getnextvarname(olocalvar.lname)
olocalvar.strings[strreps[numstrreplaced][1]] = nvar
@@ -531,82 +722,18 @@ glum.minify = function(str, name)
rhss[#rhss + 1] = string.format("%q",k)
end
local inits = ""
- print("lhss is")
- printtable(lhss)
+ --print("lhss is")
+ --printtable(lhss)
local lhs = " local " .. table.concat(lhss,",")
local rhs = table.concat(rhss,",")
if string.len(rhs) > 0 then
inits = table.concat({lhs, "=", rhs, ";"})
end
- print("Before doing stringfor for the second time, olocalvar is")
- printtable(olocalvar)
+ --print("Before doing stringfor for the second time, olocalvar is")
+ --printtable(olocalvar)
return inits .. stringfor(ast,olocalvar)
end
-glum.uglify = function(str)
- assert(str ~= nil, "Cannot uglify a nil string")
- local avalchars = {}
- local capture_chars = {"%","(","[","\13"}
- local skipchars = {}
- for k,v in pairs(capture_chars) do skipchars[string.byte(v,1)] = true end
- for k = 1, 128 do
- if skipchars[k] then goto skip_loop end --Skip the % character
- if string.find(str,string.char(k)) then
- avalchars[k] = false
- else
- avalchars[k] = true
- end
- ::skip_loop::
- end
- for k,v in pairs(skipchars) do
- avalchars[k] = false
- end
- local prettifycode = [[
-local function p(s)
- local r = {
- %s
- }
- for k,v in pairs(r) do
- s = s:gsub(v[2],v[1])
- end
- return s
-end
-]]
- local replacementtbl = {}
- local cursor = 1
- for k,v in pairs(nonames) do
- while not avalchars[cursor] do
- cursor = cursor + 1
- end
- replacementtbl[v] = cursor
- avalchars[cursor] = false
- end
- assert(cursor < 128, "Unable to uglify file, not enough unused characters!")
- local replacementstr = {}
- for k,v in pairs(replacementtbl) do
- local trs = string.format("{%q,%q}",k,string.char(v))
- replacementstr[#replacementstr + 1] = trs
- end
- local frepstr = table.concat(replacementstr,",")
- local pcd = string.format(prettifycode,frepstr)
- for k,v in pairs(replacementtbl) do
- str = str:gsub(k,string.char(v))
- end
- local numdeepcom = math.random(5) + 5
- return table.concat({
- pcd,
- "\n",
- "return assert(loadstring(p([",
- string.rep("=",numdeepcom),
- "[",
- str,
- "]",
- string.rep("=",numdeepcom),
- "])))()"
- })
- --prettifycode = string.format(prettifycode,)
-end
-
return glum