From 25af93b5d1281e7a0f8d8869c5bff0a2ce8cf1bf Mon Sep 17 00:00:00 2001 From: Alexander Pickering Date: Mon, 22 Aug 2016 14:32:38 -0400 Subject: Completed minifier, created+completed uglifier --- src/compile.lua | 31 +++++++++++ src/glum.lua | 162 +++++++++++++++++++++++++++++++++----------------------- src/parser.lua | 8 +-- src/test.lua | 32 ----------- 4 files changed, 130 insertions(+), 103 deletions(-) create mode 100644 src/compile.lua delete mode 100644 src/test.lua (limited to 'src') diff --git a/src/compile.lua b/src/compile.lua new file mode 100644 index 0000000..13f652e --- /dev/null +++ b/src/compile.lua @@ -0,0 +1,31 @@ +--[[ + Interprets a .pill file to minify a file structure +]] + +local lfs = require("lfs") + +--Create some common functions +local function getfile(filename) + if file ~= nil then --glua environment + return file.Read(filename) + elseif io.open ~= nil then --Lua environment + return io.open(filename,"r"):read("*a") + else + error("Could not find a way to read from files!") + end +end + +local function putfile(filename,data) + if file ~= nil then --gLua environment + file.Write(filename,data) + elseif io.open ~= nil then --Lua environment + io.open(filename):write(data) + end +end + +local function getdirs(filepath) + local files, directories = file.Find( filepath .. "/*", "LUA" ) +end + +local filepath = arg[1] +local pillfile = io.open(filepath) diff --git a/src/glum.lua b/src/glum.lua index a50382a..7ee37b6 100644 --- a/src/glum.lua +++ b/src/glum.lua @@ -11,34 +11,9 @@ This moudle allows you to minify gLua code print(x.minify(str)) Dependencies: lua-parser + lpeg ]] -local strreps = { - ["\\"] = "\\\\", - ["\a"] = "\\a", - ["\b"] = "\\b", - ["\f"] = "\\f", - ["\n"] = "\\n", - ["\r"] = "\\r", - ["\t"] = "\\t", - ["\v"] = "\\v", - ["\""] = "\\\"" -} -local function safe_str (str) - local tep = {} - --print("--------------Safeing str:" .. str) - for c in str:gmatch(".") do - if strreps[c] ~= nil then - --print(string.format("safeing %s:%s",c,strreps[c])) - end - tep[#tep + 1] = strreps[c] or c - end - local output = table.concat(tep) - --print("-------------Returning string:" .. output) - return output -end - - local parser = dofile("../src/parser.lua") local lpeg = require("lpeg") lpeg.locale(lpeg) @@ -109,12 +84,16 @@ local function stringfor(ast,tbl) if syntax[ast.tag] ~= nil then return syntax[ast.tag](ast,tbl) else + print("Valid tags are:") + for k,v in pairs(syntax) do + print(k) + end 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 willox ever decides to add new language features, they need to be added to BOTH parser.lua and here. +--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) local exprname = stringfor(ast[1],tbl) @@ -139,45 +118,24 @@ syntax = { --A short hand if it's a simple thing if ast[2].tag == "String" and #ast[2][1] < (#func + 2) then inv = ast[2][1] - output = output .. ":" .. inv .. "(" + output = table.concat({output, ":", inv, "("}) else inv = stringfor(ast[2],tbl) - output = output .. "[" .. inv .. "](" .. func .. "," + output = table.concat({output, "[", inv, "](", func, ","}) end - output = output .. table.concat(invargs,",") - output = output .. ")" + output = output .. table.concat(invargs,",") .. ")" return output end, ["String"] = function(ast,tbl) + local sop,eop = "\"","\"" if tbl.strings[ast[1]] == nil then - local fsstr = safe_str(ast[1]) - local fstr = string.format("\"%s\"",fsstr) - --fstr = safe_str(fstr) - --local lstr = string.format("return %q",ast[1]) - print("Loading string:" .. fstr) - local rstring = loadstring("return " .. fstr) - --print("Returning string:") - --print(ast[1]) - --print("fsstr") - --print(fsstr) - --print("formated:") - --print(string.format("%q",ast[1])) - local rstrs = rstring() - --assert(rstrs == ast[1],string.format("%q is not equal to %q",rstrs,ast[1])) - --print(string.format("%q is equal to %s:%s", rstrs, ast[1],fsstr)) - --print("Returning " .. fstr .. " from " .. ast[1] .. " out of " .. fsstr) - return fstr - --return string.format("%q",ast[1]) - --return safe_str(string.format("%q",ast[1])) - --return string.format("%q",safe_str(ast[1])) - --[[ - if #ast[1] < 4 then return "\""..ast[1].."\"" end - local nextvar = getnextvarname(tbl.lname) - tbl.lname = nextvar - tbl.strings[ast[1] ] = nextvar - return nextvar - ]] + if string.find(ast[1],"\"") then + sop = "[[" + eop = "]]" + end + return table.concat({sop,ast[1],eop}) end + print("Returning non-catated string") return tbl.strings[ast[1]] end, ["Id"] = function(ast,tbl) @@ -194,7 +152,7 @@ syntax = { return table.concat({globalvar, "[", stringfor(ast[2],tbl), "]"}) end, ["Paren"] = function(ast,tbl) - return table.concat({"(" .. stringfor(ast[1],tbl) .. ")"}) + return table.concat({"(",stringfor(ast[1],tbl),")"}) end, ["Dots"] = function(ast,tbl) return "..." @@ -229,18 +187,18 @@ syntax = { ["ExpList"] = function(ast,tbl) local exprs = {} for k = 1,#ast do - exprs[#exprs + 1] = stringfor(ast[k],tbl) + exprs[k] = stringfor(ast[k],tbl) end return table.concat(exprs,",") end, ["Nil"] = function(ast,tbl) - return "nil" + return " nil " end, ["True"] = function(ast,tbl) - return "true" + return " true " end, ["False"] = function(ast,tbl) - return "false" + return " false " end, ["Return"] = function(ast,tbl) local retargs = {} @@ -316,6 +274,12 @@ syntax = { } local opname = ast[1] 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. + if opname == "not" and ast[2]["tag"] == "Op" and ast[2][1] == "eq" then + ast[2][1] = "ne" + return stringfor(ast[2],tbl) + end local rhs = stringfor(ast[2],tbl) return uniop[opname] .. rhs end @@ -468,9 +432,9 @@ local function removespaces(str) end --Compress the string, and adds a little decompression code at the top. -local function compress(str) - -end +--local function compress(str) +-- +--end glum.minify = function(str, name) name = name or "anonymous" @@ -479,13 +443,77 @@ glum.minify = function(str, name) error(error_msg) end local localvar = { + ["numlocals"] = 0, ["strings"] = {}, ["ids"] = {}, ["lname"] = "", ["nids"] = {}, } --printtable(ast) - return --[[removespaces(]]stringfor(ast,localvar)--) + return stringfor(ast,localvar) +end + +glum.uglify = function(str) + 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 diff --git a/src/parser.lua b/src/parser.lua index ffcca71..0770bf7 100644 --- a/src/parser.lua +++ b/src/parser.lua @@ -132,8 +132,6 @@ end --Fixes strings local function fix_str (str) - --print("I need to fix string:" .. str) - --print("attempt:" .. string.format("%q",str)) str = string.gsub(str, "\\a", "\a") str = string.gsub(str, "\\b", "\b") str = string.gsub(str, "\\f", "\f") @@ -146,7 +144,6 @@ local function fix_str (str) str = string.gsub(str, "\\'", "'") str = string.gsub(str, '\\"', '"') str = string.gsub(str, '\\\\', '\\') - --print("actual:" .. str) return str end @@ -420,7 +417,10 @@ local G = { V"Lua", function (n) return tonumber(n) end; ShortString = P'"' * C(((P'\\' * P(1)) + (P(1) - P'"'))^0) * P'"' + P"'" * C(((P"\\" * P(1)) + (P(1) - P"'"))^0) * P"'"; - String = V"LongString" + (V"ShortString" / function (s) return fix_str(s) end); + String = V"LongString" + (V"ShortString" / function (s) + --print("instead of " .. s .. " i return " .. fix_str(s)) + return s end); + --return fix_str(s) end); OrOp = kw("or") / "or" + symb("||") / "or"; AndOp = kw("and") / "and" + diff --git a/src/test.lua b/src/test.lua deleted file mode 100644 index 68de568..0000000 --- a/src/test.lua +++ /dev/null @@ -1,32 +0,0 @@ - local function a(b) - b=string.gsub(b,"\\","\\\\"); - b=string.gsub(b,"\a","\\\a"); - b=string.gsub(b,"\b","\\\b"); - b=string.gsub(b,"\f","\\\f"); - b=string.gsub(b,"\n","\n"); - b=string.gsub(b,"\r","\n"); - b=string.gsub(b,"\t","\\\t"); - b=string.gsub(b,"\v","\\\v"); - b=string.gsub(b,"\'","\\\'"); - b=string.gsub(b,"\"","\\\""); - return b -end -local function c(b) - b=string.gsub(b,"\\\a","\a"); - b=string.gsub(b,"\\\b","\b"); - b=string.gsub(b,"\\\f","\f"); - b=string.gsub(b,"\n","\n"); - b=string.gsub(b,"\n","\r"); - b=string.gsub(b,"\\\t","\t"); - b=string.gsub(b,"\\\v","\v"); - b=string.gsub(b,"\\\n","\n"); - b=string.gsub(b,"\\\n","\n"); - b=string.gsub(b,"\\\'","\'"); - b=string.gsub(b,"\\\"","\""); - b=string.gsub(b,"\\\\","\\"); - return b -end -local d= function() - local d={}; - local e=require("lpeg"); - local f= function()local f={};f.lineno= function(g,h) if h==1 then return 1,1 end local i,j=0,"";g=g["sub"](g,1,h).."\n"; for k in g["gmatch"](g,"[^\n]*[\n]") do i=i+1;j=k; end local k=j["len"](j,)-1; return i, not k==0 and k or 1 end ;f.new_scope= function(i) if not i.scope then i.scope=0; else i.scope=i.scope+1; end local f=i.scope;i.maxscope=f;i[f]={};i[f].label={};i[f].local={};i[f].goto={}; end ;f.begin_scope= function(i)i.scope=i.scope+1; end ;f.end_scope= function(i)i.scope=i.scope-1; end ;f.new_function= function(i) if not i.fscope then i.fscope=0; else i.fscope=i.fscope+1; end local j=i.fscope;i.function[j]={}; end ;f.begin_function= function(i)i.fscope=i.fscope+1; end ;f.end_function= function(i)i.fscope=i.fscope-1; end ;f.begin_loop= function(i) if not i.loop then i.loop=1; else i.loop=i.loop+1; end end ;f.end_loop= function(i)i.loop=i.loop-1; end ;f.insideloop= function(i) return i.loop and 0=")/"ge"+ba("<")/"lt"+ba(">")/"gt"+ba("!=")/"ne",["BOrOp"]=ba("|")/"bor",["BXorOp"]=ba("~")/"bxor",["BAndOp"]=ba("&")/"band",["ShiftOp"]=ba("<<")/"shl"+ba(">>")/"shr",["ConOp"]=ba("..")/"concat",["AddOp"]=ba("+")/"add"+ba("-")/"sub",["MulOp"]=ba("*")/"mul"+ba("/")/"div"+ba("%")/"mod",["UnOp"]=ca("not")/"not"+ba("-")/"unm"+ba("#")/"len"+ba("~")/"bnot"+ba("!")/"not",["PowOp"]=ba("^")/"pow",["Shebang"]=g("#")*(g(1)-g("\n"))^0*g("\n"),["OneWord"]=i("Name")+i("Number")+i("String")+i("Reserved")+g("...")+g(1)}; local function za(Aa,f,Ba)local Ca=Ba[1]; for P=f,0,-1 do if Aa[P].label[Ca] then return true end end return false end local function Ca(Aa,Da,M)local f=Aa.scope;local Ea=Aa[f].label[Da]; if not Ea then Aa[f].label[Da]={["name"]=Da,["pos"]=M}; return true else local N="label \'%s\' already defined at line %d";local Fa=x(Aa.errorinfo.subject,Ea.pos);N=string.format(N,Da,Fa); return nil,K(Aa.errorinfo,M,N) end end local function Ea(Aa,Ba)local f=Aa.scope;table.insert(Aa[f].goto,Ba) return true end local function Fa(Aa) for P=Aa.maxscope,0,-1 do for Ga,ua in ipairs(Aa[P].goto) do if not za(Aa,P,ua) then local N="no visible label \'%s\' for ";N=string.format(N,ua[1]); return nil,K(Aa.errorinfo,ua.pos,N) end end end return true end local function Ga(Aa,Ha)Aa.function[Aa.fscope].is_vararg=Ha; end local Ia,Ja,Kalocal La,Ma,Na,OaOa= function(Aa,Pa)local Qa=#Pa;local Ha=false; if 0