aboutsummaryrefslogtreecommitdiff
diff options
context:
space:
mode:
authorAlexander Pickering <alexandermpickering@gmail.com>2016-11-26 09:44:09 -0500
committerAlexander Pickering <alexandermpickering@gmail.com>2016-11-26 09:44:09 -0500
commitf96040eb138efdc8f13521bade5bf8bd299bb9fb (patch)
tree3e294ca3dd504028960a72cb44b17450d6f61266
parent81fb5ea551c3dd8cfcb8e30c0dfed32a9000eea1 (diff)
downloadglum-f96040eb138efdc8f13521bade5bf8bd299bb9fb.tar.gz
glum-f96040eb138efdc8f13521bade5bf8bd299bb9fb.tar.bz2
glum-f96040eb138efdc8f13521bade5bf8bd299bb9fb.zip
Started to remove extraneous spaces
-rw-r--r--src/compile.lua31
-rw-r--r--src/glum.lua387
-rw-r--r--src/parser_min.lua554
-rw-r--r--src/uglify.lua81
-rw-r--r--test/glum_test.lua918
-rw-r--r--test/test_output.lua293
6 files changed, 2013 insertions, 251 deletions
diff --git a/src/compile.lua b/src/compile.lua
deleted file mode 100644
index 13f652e..0000000
--- a/src/compile.lua
+++ /dev/null
@@ -1,31 +0,0 @@
---[[
- 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 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
diff --git a/src/parser_min.lua b/src/parser_min.lua
new file mode 100644
index 0000000..a627cc4
--- /dev/null
+++ b/src/parser_min.lua
@@ -0,0 +1,554 @@
+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")
+ 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
+
+ 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
+
+ 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
+ }
+
+ for ya, za in ipairs(xa) do
+ table.insert(T, za)
+ end
+
+ return T
+ else
+ return {
+ ["tag"] = "Index",
+ ["pos"] = wa.pos,
+ [1] = wa,
+ [2] = xa[1]
+ }
+ end
+ 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
+
+ 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
+
+ return wa
+ end,
+ ["ParList"] = k("NameList") * (fa(",") * fa("...") * ha("Dots", s())) ^ (-1) / function(T, ya)
+ if ya then
+ table.insert(T, ya)
+ 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
+
+ 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
+
+ za.tag = "VarList"
+ za.pos = za[1].pos
+
+ 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
+
+ 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]
+
+ for R = h, 0, -1 do
+ if Ea[R].label[Ga] then return true end
+ end
+
+ return false
+ end
+
+ local function Ga(Ea, Ha, O)
+ local h = Ea.scope
+ local Ia = Ea[h].label[Ha]
+
+ if not Ia then
+ Ea[h].label[Ha] = {
+ ["name"] = Ha,
+ ["pos"] = O
+ }
+
+ 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)
+
+ return nil, M(Ea.errorinfo, O, P)
+ end
+ end
+
+ local function Ia(Ea, Fa)
+ local h = Ea.scope
+ table.insert(Ea[h].goto, Fa)
+
+ return true
+ 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 nil, M(Ea.errorinfo, ya.pos, P)
+ end
+ 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
+
+ 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()
+ 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
+ end
+
+ 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)
+
+ 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, wb(xb, N), assert(type(xb) == "table"), assert(type(N) == "table"), 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
+
+ return wb(xb, N)
+ end
diff --git a/src/uglify.lua b/src/uglify.lua
new file mode 100644
index 0000000..143f67f
--- /dev/null
+++ b/src/uglify.lua
@@ -0,0 +1,81 @@
+local u = {}
+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"}
+
+u.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 not skipchars[k] then
+ if string.find(str, string.char(k)) then
+ avalchars[k] = false
+ else
+ avalchars[k] = true
+ end
+ end
+ end
+
+ for k, v in pairs(skipchars) do
+ avalchars[k] = false
+ end
+
+ local counts = {}
+ for k, v in ipairs(nonames) do
+ counts[v] = 0
+ end
+ for k,_ in pairs(counts) do
+ for i,j in string.gmatch(str,k) do
+ counts[k] = counts[k] + 1
+ end
+ 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 --Start at 1 because 0 is the null character
+
+ for k, v in ipairs(nonames) do
+ if counts[v] ~= 0 then
+ while not avalchars[cursor] do
+ cursor = cursor + 1
+ end
+
+ replacementtbl[v] = cursor
+ avalchars[cursor] = false
+ end
+ 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 = 1
+
+ local uglified = table.concat({pcd, "\n", "return assert(loadstring(p([", string.rep("=", numdeepcom), "[", str, "]", string.rep("=", numdeepcom), "])))()"})
+
+ if #uglified > #str then
+ print("WARNING: Uglification hurt rather than helped! Put more code in one file!")
+ end
+
+ return uglified
+end
+
+--prettifycode = string.format(prettifycode,)
+return u
diff --git a/test/glum_test.lua b/test/glum_test.lua
index 9f538ad..e9447dd 100644
--- a/test/glum_test.lua
+++ b/test/glum_test.lua
@@ -1,150 +1,888 @@
--local glum = dofile("../src/test.lua")
local glum = dofile("../src/glum.lua")
+local ugly = dofile("../src/uglify.lua")
local f5 = io.open("../src/glum.lua", "r")
local str5 = f5:read("*a")
f5:close()
-local str = [[
+local str = [==[
+--[[
+This module implements a parser for Lua 5.2 with LPeg,
+and generates an Abstract Syntax Tree in the Metalua format.
+For more information about Metalua, please, visit:
+https://github.com/fab13n/metalua-parser
+
+block: { stat* }
+
+stat:
+ `Do{ stat* }
+ | `Set{ {lhs+} {expr+} } -- lhs1, lhs2... = e1, e2...
+ | `While{ expr block } -- while e do b end
+ | `Repeat{ block expr } -- repeat b until e
+ | `If{ (expr block)+ block? } -- if e1 then b1 [elseif e2 then b2] ... [else bn] end
+ | `Fornum{ ident expr expr expr? block } -- for ident = e, e[, e] do b end
+ | `Forin{ {ident+} {expr+} block } -- for i1, i2... in e1, e2... do b end
+ | `Local{ {ident+} {expr+}? } -- local i1, i2... = e1, e2...
+ | `Localrec{ ident expr } -- only used for 'local function'
+ | `Goto{ <string> } -- goto str
+ | `Label{ <string> } -- ::str::
+ | `Return{ <expr*> } -- return e1, e2...
+ | `Break -- break
+ | apply
+
+expr:
+ `Nil
+ | `Dots
+ | `True
+ | `False
+ | `Number{ <number> }
+ | `String{ <string> }
+ | `Function{ { `Id{ <string> }* `Dots? } block }
+ | `Table{ ( `Pair{ expr expr } | expr )* }
+ | `Op{ opid expr expr? }
+ | `Paren{ expr } -- significant to cut multiple values returns
+ | apply
+ | lhs
+
+apply:
+ `Call{ expr expr* }
+ | `Invoke{ expr `String{ <string> } expr* }
+
+lhs: `Id{ <string> } | `Index{ expr expr }
+
+opid: 'add' | 'sub' | 'mul' | 'div' | 'idiv' | 'mod' | 'pow' | 'concat'
+ | 'band' | 'bor' | 'bxor' | 'shl' | 'shr' | 'eq' | 'lt' | 'le'
+ | 'and' | 'or' | 'not' | 'unm' | 'len' | 'bnot'
+]]
+local parser = {}
+local lpeg = require("lpeg")
+local scope
+if include ~= nil then
+ scope = include("./scope.lua")
+else
+ scope = dofile("../src/scope.lua")
+end
-AddCSLuaFile()
+lpeg.locale(lpeg)
+
+local P, S, V = lpeg.P, lpeg.S, lpeg.V
+local C, Carg, Cb, Cc = lpeg.C, lpeg.Carg, lpeg.Cb, lpeg.Cc
+local Cf, Cg, Cmt, Cp, Ct = lpeg.Cf, lpeg.Cg, lpeg.Cmt, lpeg.Cp, lpeg.Ct
+local alpha, digit, alnum = lpeg.alpha, lpeg.digit, lpeg.alnum
+local xdigit = lpeg.xdigit
+local space = lpeg.space
+
+local lineno = scope.lineno
+local new_scope, end_scope = scope.new_scope, scope.end_scope
+local new_function, end_function = scope.new_function, scope.end_function
+local begin_loop, end_loop = scope.begin_loop, scope.end_loop
+local insideloop = scope.insideloop
+
+--some stuff for getting glua comments
+local BEGIN_COMMENT = lpeg.P("/*")
+local END_COMMENT = lpeg.P("*/")
+local NOT_BEGIN = (1 - BEGIN_COMMENT)^0
+local NOT_END = (1 - END_COMMENT)^0
+local FULL_COMMENT_CONTENTS = BEGIN_COMMENT * NOT_END * END_COMMENT
+
+-- error message auxiliary functions
+
+-- creates an error message for the input string
+local function syntaxerror (errorinfo, pos, msg)
+ local l, c = lineno(errorinfo.subject, pos)
+ local error_msg = "%s:%d:%d: syntax error, %s"
+ return string.format(error_msg, errorinfo.filename, l, c, msg)
+end
-ENT.Type = "point"
-ENT.DisableDuplicator = true
+-- gets the farthest failure position
+local function getffp (s, i, t)
+ return t.ffp or i, t
+end
---
--- Make this entity always networked
---
-function ENT:UpdateTransmitState() return TRANSMIT_ALWAYS end
+-- gets the table that contains the error information
+local function geterrorinfo ()
+ return Cmt(Carg(1), getffp) * (C(V"OneWord") + Cc("EOF")) /
+ function (t, u)
+ t.unexpected = u
+ return t
+ end
+end
---
--- Networked / Saved Data
---
-function ENT:SetupDataTables()
+-- creates an errror message using the farthest failure position
+local function errormsg ()
+ return geterrorinfo() /
+ function (t)
+ local p = t.ffp or 1
+ local msg = "unexpected '%s', expecting %s"
+ msg = string.format(msg, t.unexpected, t.expected)
+ return nil, syntaxerror(t, p, msg)
+ end
+end
- self:NetworkVar( "Vector", 0, "TopColor", { KeyName = "topcolor", Edit = { type = "VectorColor", category = "Main", order = 1 } } )
- self:NetworkVar( "Vector", 1, "BottomColor", { KeyName = "bottomcolor", Edit = { type = "VectorColor", category = "Main", title = "Color Bottom", order = 2 } } )
- self:NetworkVar( "Float", 0, "FadeBias", { KeyName = "fadebias", Edit = { type = "Float", category = "Main", min = 0, max = 1, order = 3 } } )
+-- reports a syntactic error
+local function report_error ()
+ return errormsg()
+end
- self:NetworkVar( "Float", 4, "SunSize", { KeyName = "sunsize", Edit = { type = "Float", min = 0, max = 10, category = "Sun" } } )
- self:NetworkVar( "Vector", 2, "SunNormal", { KeyName = "sunnormal" } ) -- No editing this - it's for coders only
- self:NetworkVar( "Vector", 3, "SunColor", { KeyName = "suncolor", Edit = { type = "VectorColor", category = "Sun" } } )
+-- sets the farthest failure position and the expected tokens
+local function setffp (s, i, t, n)
+ if not t.ffp or i > t.ffp then
+ t.ffp = i
+ t.list = {} ; t.list[n] = n
+ t.expected = "'" .. n .. "'"
+ elseif i == t.ffp then
+ if not t.list[n] then
+ t.list[n] = n
+ t.expected = "'" .. n .. "', " .. t.expected
+ end
+ end
+ return false
+end
- self:NetworkVar( "Float", 2, "DuskScale", { KeyName = "duskscale", Edit = { type = "Float", min = 0, max = 1, category = "Dusk" } } )
- self:NetworkVar( "Float", 3, "DuskIntensity", { KeyName = "duskintensity", Edit = { type = "Float", min = 0, max = 10, category = "Dusk" } } )
- self:NetworkVar( "Vector", 4, "DuskColor", { KeyName = "duskcolor", Edit = { type = "VectorColor", category = "Dusk" } } )
+local function updateffp (name)
+ return Cmt(Carg(1) * Cc(name), setffp)
+end
- self:NetworkVar( "Bool", 0, "DrawStars", { KeyName = "drawstars", Edit = { type = "Boolean", category = "Stars", order = 10 } } )
- self:NetworkVar( "String", 0, "StarTexture", { KeyName = "startexture", Edit = { type = "Texture", group = "Stars", category = "Stars", order = 11 } } )
+--Fixes strings
+local function fix_str (str)
+ str = string.gsub(str, "\\a", "\a")
+ str = string.gsub(str, "\\b", "\b")
+ str = string.gsub(str, "\\f", "\f")
+ str = string.gsub(str, "\\n", "\n")
+ str = string.gsub(str, "\\r", "\r")
+ str = string.gsub(str, "\\t", "\t")
+ str = string.gsub(str, "\\v", "\v")
+ str = string.gsub(str, "\\\n", "\n")
+ str = string.gsub(str, "\\\r", "\n")
+ str = string.gsub(str, "\\'", "'")
+ str = string.gsub(str, '\\"', '"')
+ str = string.gsub(str, '\\\\', '\\')
+ return str
+end
- self:NetworkVarElement( "Angle", 0, 'p', "StarScale", { KeyName = "starscale", Edit = { type = "Float", min = 0, max = 5, category = "Stars", order = 12 } } )
- self:NetworkVarElement( "Angle", 0, 'y', "StarFade", { KeyName = "starfade", Edit = { type = "Float", min = 0, max = 5, category = "Stars", order = 13 } } )
- self:NetworkVarElement( "Angle", 0, 'r', "StarSpeed", { KeyName = "starspeed", Edit = { type = "Float", min = 0, max = 5, category = "Stars", order = 14 } } )
+-- regular combinators and auxiliary functions
- self:NetworkVar( "Float", 1, "HDRScale", { KeyName = "hdrscale", Edit = { type = "Float", category = "Main", min = 0, max = 1, order = 4 } } )
+local function token (pat, name)
+ return pat * V"Skip" + updateffp(name) * P(false)
+end
- --
- -- Entity defaults
- --
- if ( SERVER ) then
+local function symb (str)
+ return token (P(str), str)
+end
- self:SetTopColor( Vector( 0.2, 0.5, 1.0 ) )
- self:SetBottomColor( Vector( 0.8, 1.0, 1.0 ) )
- self:SetFadeBias( 1 )
+local function kw (str)
+ return token (P(str) * -V"idRest", str)
+end
+local function taggedCap (tag, pat)
+ return Ct(Cg(Cp(), "pos") * Cg(Cc(tag), "tag") * pat)
+end
- self:SetSunNormal( Vector( 0.4, 0.0, 0.01 ) )
- self:SetSunColor( Vector( 0.2, 0.1, 0.0 ) )
- self:SetSunSize( 2.0 )
+local function unaryop (op, e)
+ return { tag = "Op", pos = e.pos, [1] = op, [2] = e }
+end
- self:SetDuskColor( Vector( 1.0, 0.2, 0.0 ) )
- self:SetDuskScale( 1 )
- self:SetDuskIntensity( 1 )
+local function binaryop (e1, op, e2)
+ if not op then
+ return e1
+ elseif op == "add" or
+ op == "sub" or
+ op == "mul" or
+ op == "div" or
+ op == "idiv" or
+ op == "mod" or
+ op == "pow" or
+ op == "concat" or
+ op == "band" or
+ op == "bor" or
+ op == "bxor" or
+ op == "shl" or
+ op == "shr" or
+ op == "eq" or
+ op == "lt" or
+ op == "le" or
+ op == "and" or
+ op == "or" then
+ return { tag = "Op", pos = e1.pos, [1] = op, [2] = e1, [3] = e2 }
+ elseif op == "ne" then
+ return unaryop ("not", { tag = "Op", pos = e1.pos, [1] = "eq", [2] = e1, [3] = e2 })
+ elseif op == "gt" then
+ return { tag = "Op", pos = e1.pos, [1] = "lt", [2] = e2, [3] = e1 }
+ elseif op == "ge" then
+ return { tag = "Op", pos = e1.pos, [1] = "le", [2] = e2, [3] = e1 }
+ end
+end
- self:SetDrawStars( true )
- self:SetStarSpeed( 0.01 )
- self:SetStarScale( 0.5 )
- self:SetStarFade( 1.5 )
- self:SetStarTexture( "skybox/starfield" )
+local function chainl (pat, sep, a)
+ return Cf(pat * Cg(sep * pat)^0, binaryop) + a
+end
- self:SetHDRScale( 0.66 )
+local function chainl1 (pat, sep)
+ return Cf(pat * Cg(sep * pat)^0, binaryop)
+end
- end
+local function sepby (pat, sep, tag)
+ return taggedCap(tag, (pat * (sep * pat)^0)^(-1))
+end
+local function sepby1 (pat, sep, tag)
+ return taggedCap(tag, pat * (sep * pat)^0)
end
-function ENT:Initialize()
+-- grammar
+
+local G = { V"Lua",
+ Lua = V"Shebang"^(-1) * V"Skip" * V"Chunk" * -1 + report_error();
+ -- parser
+ Chunk = V"Block";
+ StatList = (symb(";") + V"Stat")^0;
+ Var = V"Id";
+ Id = taggedCap("Id", token(V"Name", "Name"));
+ FunctionDef = kw("function") * V"FuncBody";
+ FieldSep = symb(",") + symb(";");
+ Field = taggedCap("Pair", (symb("[") * V"Expr" * symb("]") * symb("=") * V"Expr") +
+ (taggedCap("String", token(V"Name", "Name")) * symb("=") * V"Expr")) +
+ V"Expr";
+ FieldList = (V"Field" * (V"FieldSep" * V"Field")^0 * V"FieldSep"^(-1))^(-1);
+ Constructor = taggedCap("Table", symb("{") * V"FieldList" * symb("}"));
+ NameList = sepby1(V"Id", symb(","), "NameList");
+ ExpList = sepby1(V"Expr", symb(","), "ExpList");
+ FuncArgs = symb("(") * (V"Expr" * (symb(",") * V"Expr")^0)^(-1) * symb(")") +
+ V"Constructor" +
+ taggedCap("String", token(V"String", "String"));
+ Expr = V"SubExpr_1";
+ SubExpr_1 = chainl1(V"SubExpr_2", V"OrOp");
+ SubExpr_2 = chainl1(V"SubExpr_3", V"AndOp");
+ SubExpr_3 = chainl1(V"SubExpr_4", V"RelOp");
+ SubExpr_4 = chainl1(V"SubExpr_5", V"BOrOp");
+ SubExpr_5 = chainl1(V"SubExpr_6", V"BXorOp");
+ SubExpr_6 = chainl1(V"SubExpr_7", V"BAndOp");
+ SubExpr_7 = chainl1(V"SubExpr_8", V"ShiftOp");
+ SubExpr_8 = V"SubExpr_9" * V"ConOp" * V"SubExpr_8" / binaryop +
+ V"SubExpr_9";
+ SubExpr_9 = chainl1(V"SubExpr_10", V"AddOp");
+ SubExpr_10 = chainl1(V"SubExpr_11", V"MulOp");
+ SubExpr_11 = V"UnOp" * V"SubExpr_11" / unaryop +
+ V"SubExpr_12";
+ SubExpr_12 = V"SimpleExp" * (V"PowOp" * V"SubExpr_11")^(-1) / binaryop;
+ SimpleExp = taggedCap("Number", token(V"Number", "Number")) +
+ taggedCap("String", token(V"String", "String")) +
+ taggedCap("Nil", kw("nil")) +
+ taggedCap("False", kw("false")) +
+ taggedCap("True", kw("true")) +
+ taggedCap("Dots", symb("...")) +
+ V"FunctionDef" +
+ V"Constructor" +
+ V"SuffixedExp";
+ SuffixedExp = Cf(V"PrimaryExp" * (
+ taggedCap("DotIndex", symb(".") * taggedCap("String", token(V"Name", "Name"))) +
+ taggedCap("ArrayIndex", symb("[") * V"Expr" * symb("]")) +
+ taggedCap("Invoke", Cg(symb(":") * taggedCap("String", token(V"Name", "Name")) * V"FuncArgs")) +
+ taggedCap("Call", V"FuncArgs")
+ )^0, function (t1, t2)
+ if t2 then
+ if t2.tag == "Call" or t2.tag == "Invoke" then
+ local t = {tag = t2.tag, pos = t1.pos, [1] = t1}
+ for k, v in ipairs(t2) do
+ table.insert(t, v)
+ end
+ return t
+ else
+ return {tag = "Index", pos = t1.pos, [1] = t1, [2] = t2[1]}
+ end
+ end
+ return t1
+ end);
+ PrimaryExp = V"Var" +
+ taggedCap("Paren", symb("(") * V"Expr" * symb(")"));
+ Block = taggedCap("Block", V"StatList" * V"RetStat"^(-1));
+ IfStat = taggedCap("If",
+ kw("if") * V"Expr" * kw("then") * V"Block" *
+ (kw("elseif") * V"Expr" * kw("then") * V"Block")^0 *
+ (kw("else") * V"Block")^(-1) *
+ kw("end"));
+ WhileStat = taggedCap("While", kw("while") * V"Expr" *
+ kw("do") * V"Block" * kw("end"));
+ DoStat = kw("do") * V"Block" * kw("end") /
+ function (t)
+ t.tag = "Do"
+ return t
+ end;
+ ForBody = kw("do") * V"Block";
+ ForNum = taggedCap("Fornum",
+ V"Id" * symb("=") * V"Expr" * symb(",") *
+ V"Expr" * (symb(",") * V"Expr")^(-1) *
+ V"ForBody");
+ ForGen = taggedCap("Forin", V"NameList" * kw("in") * V"ExpList" * V"ForBody");
+ ForStat = kw("for") * (V"ForNum" + V"ForGen") * kw("end");
+ RepeatStat = taggedCap("Repeat", kw("repeat") * V"Block" *
+ kw("until") * V"Expr");
+ FuncName = Cf(V"Id" * (symb(".") * taggedCap("String", token(V"Name", "Name")))^0,
+ function (t1, t2)
+ if t2 then
+ return {tag = "Index", pos = t1.pos, [1] = t1, [2] = t2}
+ end
+ return t1
+ end) * (symb(":") * taggedCap("String", token(V"Name", "Name")))^(-1) /
+ function (t1, t2)
+ if t2 then
+ return {tag = "Index", pos = t1.pos, is_method = true, [1] = t1, [2] = t2}
+ end
+ return t1
+ end;
+ ParList = V"NameList" * (symb(",") * symb("...") * taggedCap("Dots", Cp()))^(-1) /
+ function (t, v)
+ if v then table.insert(t, v) end
+ return t
+ end +
+ symb("...") * taggedCap("Dots", Cp()) /
+ function (v)
+ return {v}
+ end +
+ P(true) / function () return {} end;
+ -- Cc({}) generates a strange bug when parsing [[function t:a() end ; function t.a() end]]
+ -- the bug is to add the parameter self to the second function definition
+ --FuncBody = taggedCap("Function", symb("(") * (V"ParList" + Cc({})) * symb(")") * V"Block" * kw("end"));
+ FuncBody = taggedCap("Function", symb("(") * V"ParList" * symb(")") * V"Block" * kw("end"));
+ FuncStat = taggedCap("Set", kw("function") * V"FuncName" * V"FuncBody") /
+ function (t)
+ if t[1].is_method then table.insert(t[2][1], 1, {tag = "Id", [1] = "self"}) end
+ t[1] = {t[1]}
+ t[2] = {t[2]}
+ return t
+ end;
+ LocalFunc = taggedCap("Localrec", kw("function") * V"Id" * V"FuncBody") /
+ function (t)
+ t[1] = {t[1]}
+ t[2] = {t[2]}
+ return t
+ end;
+ LocalAssign = taggedCap("Local", V"NameList" * ((symb("=") * V"ExpList") + Ct(Cc())));
+ LocalStat = kw("local") * (V"LocalFunc" + V"LocalAssign");
+ LabelStat = taggedCap("Label", symb("::") * token(V"Name", "Name") * symb("::"));
+ BreakStat = taggedCap("Break", kw("break"));
+ ContinueStat = taggedCap("Continue", kw("continue"));
+ GoToStat = taggedCap("Goto", kw("goto") * token(V"Name", "Name"));
+ RetStat = taggedCap("Return", kw("return") * (V"Expr" * (symb(",") * V"Expr")^0)^(-1) * symb(";")^(-1));
+ ExprStat = Cmt(
+ (V"SuffixedExp" *
+ (Cc(function (...)
+ local vl = {...}
+ local el = vl[#vl]
+ table.remove(vl)
+ for k, v in ipairs(vl) do
+ if v.tag == "Id" or v.tag == "Index" then
+ vl[k] = v
+ else
+ -- invalid assignment
+ return false
+ end
+ end
+ vl.tag = "VarList"
+ vl.pos = vl[1].pos
+ return true, {tag = "Set", pos = vl.pos, [1] = vl, [2] = el}
+ end) * V"Assignment"))
+ +
+ (V"SuffixedExp" *
+ (Cc(function (s)
+ if s.tag == "Call" or
+ s.tag == "Invoke" then
+ return true, s
+ end
+ -- invalid statement
+ return false
+ end)))
+ , function (s, i, s1, f, ...) return f(s1, ...) end);
+ Assignment = ((symb(",") * V"SuffixedExp")^1)^(-1) * symb("=") * V"ExpList";
+ Stat = V"IfStat" + V"WhileStat" + V"DoStat" + V"ForStat" +
+ V"RepeatStat" + V"FuncStat" + V"LocalStat" + V"LabelStat" +
+ V"BreakStat" + V"GoToStat" + V"ExprStat" + V"ContinueStat";
+ -- lexer
+ Space = space^1;
+ Equals = P"="^0;
+ Open = "[" * Cg(V"Equals", "init") * "[" * P"\n"^(-1);
+ Close = "]" * C(V"Equals") * "]";
+ CloseEQ = Cmt(V"Close" * Cb("init"),
+ function (s, i, a, b) return a == b end);
+ LongString = V"Open" * C((P(1) - V"CloseEQ")^0) * V"Close" /
+ function (s, o) return s end;
+ Comment = P"--" * V"LongString" / function () return end +
+ P"--" * (P(1) - P"\n")^0 +
+ P"//" * (P(1) - P"\n")^0 +
+ C(FULL_COMMENT_CONTENTS) / function() return end;
+ Skip = (V"Space" + V"Comment")^0;
+ idStart = alpha + P("_");
+ idRest = alnum + P("_");
+ Keywords = P("and") + "break" + "do" + "elseif" + "else" + "end" +
+ "false" + "for" + "function" + "goto" + "if" + "in" +
+ "local" + "nil" + "not" + "or" + "repeat" + "return" +
+ "then" + "true" + "until" + "while" + "continue";
+ Reserved = V"Keywords" * -V"idRest";
+ Identifier = V"idStart" * V"idRest"^0;
+ Name = -V"Reserved" * C(V"Identifier") * -V"idRest";
+ Hex = (P("0x") + P("0X")) * xdigit^1;
+ Expo = S("eE") * S("+-")^(-1) * digit^1;
+ Float = (((digit^1 * P(".") * digit^0) +
+ (P(".") * digit^1)) * V"Expo"^(-1)) +
+ (digit^1 * V"Expo");
+ Int = digit^1;
+ Number = C(V"Hex" + V"Float" + V"Int") /
+ 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)
+ --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" +
+ symb("&&") / "and";
+ RelOp = symb("~=") / "ne" +
+ symb("==") / "eq" +
+ symb("<=") / "le" +
+ symb(">=") / "ge" +
+ symb("<") / "lt" +
+ symb(">") / "gt" +
+ symb("!=") / "ne";
+ BOrOp = symb("|") / "bor";
+ BXorOp = symb("~") / "bxor";
+ BAndOp = symb("&") / "band";
+ ShiftOp = symb("<<") / "shl" +
+ symb(">>") / "shr";
+ ConOp = symb("..") / "concat";
+ AddOp = symb("+") / "add" +
+ symb("-") / "sub";
+ MulOp = symb("*") / "mul" +
+ --symb("//") / "idiv" +
+ symb("/") / "div" +
+ symb("%") / "mod";
+ UnOp = kw("not") / "not" +
+ symb("-") / "unm" +
+ symb("#") / "len" +
+ symb("~") / "bnot" +
+ symb("!") / "not";
+ PowOp = symb("^") / "pow";
+ Shebang = P"#" * (P(1) - P"\n")^0 * P"\n";
+ -- for error reporting
+ OneWord = V"Name" + V"Number" + V"String" + V"Reserved" + P("...") + P(1);
+}
+
+local function exist_label (env, scope, stm)
+ local l = stm[1]
+ for s=scope, 0, -1 do
+ if env[s]["label"][l] then return true end
+ end
+ return false
end
-function ENT:KeyValue( key, value )
+local function set_label (env, label, pos)
+ local scope = env.scope
+ local l = env[scope]["label"][label]
+ if not l then
+ env[scope]["label"][label] = { name = label, pos = pos }
+ return true
+ else
+ local msg = "label '%s' already defined at line %d"
+ local line = lineno(env.errorinfo.subject, l.pos)
+ msg = string.format(msg, label, line)
+ return nil, syntaxerror(env.errorinfo, pos, msg)
+ end
+end
- if ( self:SetNetworkKeyValue( key, value ) ) then
- return
- end
+local function set_pending_goto (env, stm)
+ local scope = env.scope
+ table.insert(env[scope]["goto"], stm)
+ return true
+end
- -- TODO: sunposmethod
- -- 0 : "Custom - Use the Sun Normal to position the sun"
- -- 1 : "Automatic - Find a env_sun entity and use that"
+local function verify_pending_gotos (env)
+ for s=env.maxscope, 0, -1 do
+ for k, v in ipairs(env[s]["goto"]) do
+ if not exist_label(env, s, v) then
+ local msg = "no visible label '%s' for <goto>"
+ msg = string.format(msg, v[1])
+ return nil, syntaxerror(env.errorinfo, v.pos, msg)
+ end
+ end
+ end
+ return true
+end
+local function set_vararg (env, is_vararg)
+ env["function"][env.fscope].is_vararg = is_vararg
end
-function ENT:Think()
+local traverse_stm, traverse_exp, traverse_var
+local traverse_block, traverse_explist, traverse_varlist, traverse_parlist
+
+function traverse_parlist (env, parlist)
+ local len = #parlist
+ local is_vararg = false
+ if len > 0 and parlist[len].tag == "Dots" then
+ is_vararg = true
+ end
+ set_vararg(env, is_vararg)
+ return true
+end
- --
- -- Find an env_sun - if we don't already have one.
- --
- if ( SERVER && self.EnvSun == nil ) then
+local function traverse_function (env, exp)
+ new_function(env)
+ new_scope(env)
+ local status, msg = traverse_parlist(env, exp[1])
+ if not status then return status, msg end
+ status, msg = traverse_block(env, exp[2])
+ if not status then return status, msg end
+ end_scope(env)
+ end_function(env)
+ return true
+end
- -- so this closure only gets called once - even if it fails
- self.EnvSun = false
+local function traverse_op (env, exp)
+ local status, msg = traverse_exp(env, exp[2])
+ if not status then return status, msg end
+ if exp[3] then
+ status, msg = traverse_exp(env, exp[3])
+ if not status then return status, msg end
+ end
+ return true
+end
- local list = ents.FindByClass( "env_sun" )
- if ( #list > 0 ) then
- self.EnvSun = list[1]
- end
+local function traverse_paren (env, exp)
+ local status, msg = traverse_exp(env, exp[1])
+ if not status then return status, msg end
+ return true
+end
- end
+local function traverse_table (env, fieldlist)
+ for k, v in ipairs(fieldlist) do
+ local tag = v.tag
+ if tag == "Pair" then
+ local status, msg = traverse_exp(env, v[1])
+ if not status then return status, msg end
+ status, msg = traverse_exp(env, v[2])
+ if not status then return status, msg end
+ else
+ local status, msg = traverse_exp(env, v)
+ if not status then return status, msg end
+ end
+ end
+ return true
+end
- --
- -- If we have a sun - force our sun normal to its value
- --
- if ( SERVER && IsValid( self.EnvSun ) ) then
+local function traverse_vararg (env, exp)
+ if not env["function"][env.fscope].is_vararg then
+ local msg = "cannot use '...' outside a vararg function"
+ return nil, syntaxerror(env.errorinfo, exp.pos, msg)
+ end
+ return true
+end
- local vec = self.EnvSun:GetInternalVariable( "m_vDirection" )
+local function traverse_call (env, call)
+ local status, msg = traverse_exp(env, call[1])
+ if not status then return status, msg end
+ for i=2, #call do
+ status, msg = traverse_exp(env, call[i])
+ if not status then return status, msg end
+ end
+ return true
+end
- if ( isvector( vec ) ) then
- self:SetSunNormal( vec )
- end
+local function traverse_invoke (env, invoke)
+ local status, msg = traverse_exp(env, invoke[1])
+ if not status then return status, msg end
+ for i=3, #invoke do
+ status, msg = traverse_exp(env, invoke[i])
+ if not status then return status, msg end
+ end
+ return true
+end
- end
+local function traverse_assignment (env, stm)
+ local status, msg = traverse_varlist(env, stm[1])
+ if not status then return status, msg end
+ status, msg = traverse_explist(env, stm[2])
+ if not status then return status, msg end
+ return true
+end
- --
- -- Become the active sky again if we're not already
- --
- if ( CLIENT && g_SkyPaint != self ) then
+local function traverse_break (env, stm)
+ if not insideloop(env) then
+ local msg = "<break> not inside a loop"
+ return nil, syntaxerror(env.errorinfo, stm.pos, msg)
+ end
+ return true
+end
- if ( !IsValid( g_SkyPaint ) ) then
- g_SkyPaint = self
- end
+local function traverse_continue (env, stm)
+ if not insideloop(env) then
+ local msg = "<continue> not inside a loop"
+ return nil, syntaxerror(env.errorinfo, stm.pos, msg)
+ end
+ return true
+end
+
+local function traverse_forin (env, stm)
+ begin_loop(env)
+ new_scope(env)
+ local status, msg = traverse_explist(env, stm[2])
+ if not status then return status, msg end
+ status, msg = traverse_block(env, stm[3])
+ if not status then return status, msg end
+ end_scope(env)
+ end_loop(env)
+ return true
+end
+
+local function traverse_fornum (env, stm)
+ local status, msg
+ begin_loop(env)
+ new_scope(env)
+ status, msg = traverse_exp(env, stm[2])
+ if not status then return status, msg end
+ status, msg = traverse_exp(env, stm[3])
+ if not status then return status, msg end
+ if stm[5] then
+ status, msg = traverse_exp(env, stm[4])
+ if not status then return status, msg end
+ status, msg = traverse_block(env, stm[5])
+ if not status then return status, msg end
+ else
+ status, msg = traverse_block(env, stm[4])
+ if not status then return status, msg end
+ end
+ end_scope(env)
+ end_loop(env)
+ return true
+end
+
+local function traverse_goto (env, stm)
+ local status, msg = set_pending_goto(env, stm)
+ if not status then return status, msg end
+ return true
+end
+
+local function traverse_if (env, stm)
+ local len = #stm
+ if len % 2 == 0 then
+ for i=1, len, 2 do
+ local status, msg = traverse_exp(env, stm[i])
+ if not status then return status, msg end
+ status, msg = traverse_block(env, stm[i+1])
+ if not status then return status, msg end
+ end
+ else
+ for i=1, len-1, 2 do
+ local status, msg = traverse_exp(env, stm[i])
+ if not status then return status, msg end
+ status, msg = traverse_block(env, stm[i+1])
+ if not status then return status, msg end
+ end
+ local status, msg = traverse_block(env, stm[len])
+ if not status then return status, msg end
+ end
+ return true
+end
+
+local function traverse_label (env, stm)
+ local status, msg = set_label(env, stm[1], stm.pos)
+ if not status then return status, msg end
+ return true
+end
+
+local function traverse_let (env, stm)
+ local status, msg = traverse_explist(env, stm[2])
+ if not status then return status, msg end
+ return true
+end
+
+local function traverse_letrec (env, stm)
+ local status, msg = traverse_exp(env, stm[2][1])
+ if not status then return status, msg end
+ return true
+end
+
+local function traverse_repeat (env, stm)
+ begin_loop(env)
+ local status, msg = traverse_block(env, stm[1])
+ if not status then return status, msg end
+ status, msg = traverse_exp(env, stm[2])
+ if not status then return status, msg end
+ end_loop(env)
+ return true
+end
- end
+local function traverse_return (env, stm)
+ local status, msg = traverse_explist(env, stm)
+ if not status then return status, msg end
+ return true
+end
+local function traverse_while (env, stm)
+ begin_loop(env)
+ local status, msg = traverse_exp(env, stm[1])
+ if not status then return status, msg end
+ status, msg = traverse_block(env, stm[2])
+ if not status then return status, msg end
+ end_loop(env)
+ return true
end
---
--- To prevent server insanity - only let admins edit the sky.
---
-function ENT:CanEditVariables( ply )
+function traverse_var (env, var)
+ local tag = var.tag
+ if tag == "Id" then -- `Id{ <string> }
+ return true
+ elseif tag == "Index" then -- `Index{ expr expr }
+ local status, msg = traverse_exp(env, var[1])
+ if not status then return status, msg end
+ status, msg = traverse_exp(env, var[2])
+ if not status then return status, msg end
+ return true
+ else
+ error("expecting a variable, but got a " .. tag)
+ end
+end
- return ply:IsAdmin()
+function traverse_varlist (env, varlist)
+ for k, v in ipairs(varlist) do
+ local status, msg = traverse_var(env, v)
+ if not status then return status, msg end
+ end
+ return true
+end
+
+function traverse_exp (env, exp)
+ local tag = exp.tag
+ if tag == "Nil" or
+ tag == "True" or
+ tag == "False" or
+ tag == "Number" or -- `Number{ <number> }
+ tag == "String" then -- `String{ <string> }
+ return true
+ elseif tag == "Dots" then
+ return traverse_vararg(env, exp)
+ elseif tag == "Function" then -- `Function{ { `Id{ <string> }* `Dots? } block }
+ return traverse_function(env, exp)
+ elseif tag == "Table" then -- `Table{ ( `Pair{ expr expr } | expr )* }
+ return traverse_table(env, exp)
+ elseif tag == "Op" then -- `Op{ opid expr expr? }
+ return traverse_op(env, exp)
+ elseif tag == "Paren" then -- `Paren{ expr }
+ return traverse_paren(env, exp)
+ elseif tag == "Call" then -- `Call{ expr expr* }
+ return traverse_call(env, exp)
+ elseif tag == "Invoke" then -- `Invoke{ expr `String{ <string> expr* }
+ return traverse_invoke(env, exp)
+ elseif tag == "Id" or -- `Id{ <string> }
+ tag == "Index" then -- `Index{ expr expr }
+ return traverse_var(env, exp)
+ else
+ error("expecting an expression, but got a " .. tag)
+ end
+end
+
+function traverse_explist (env, explist)
+ for k, v in ipairs(explist) do
+ local status, msg = traverse_exp(env, v)
+ if not status then return status, msg end
+ end
+ return true
+end
+
+function traverse_stm (env, stm)
+ local tag = stm.tag
+ if tag == "Do" then -- `Do{ stat* }
+ return traverse_block(env, stm)
+ elseif tag == "Set" then -- `Set{ {lhs+} {expr+} }
+ return traverse_assignment(env, stm)
+ elseif tag == "While" then -- `While{ expr block }
+ return traverse_while(env, stm)
+ elseif tag == "Repeat" then -- `Repeat{ block expr }
+ return traverse_repeat(env, stm)
+ elseif tag == "If" then -- `If{ (expr block)+ block? }
+ return traverse_if(env, stm)
+ elseif tag == "Fornum" then -- `Fornum{ ident expr expr expr? block }
+ return traverse_fornum(env, stm)
+ elseif tag == "Forin" then -- `Forin{ {ident+} {expr+} block }
+ return traverse_forin(env, stm)
+ elseif tag == "Local" then -- `Local{ {ident+} {expr+}? }
+ return traverse_let(env, stm)
+ elseif tag == "Localrec" then -- `Localrec{ ident expr }
+ return traverse_letrec(env, stm)
+ elseif tag == "Goto" then -- `Goto{ <string> }
+ return traverse_goto(env, stm)
+ elseif tag == "Label" then -- `Label{ <string> }
+ return traverse_label(env, stm)
+ elseif tag == "Return" then -- `Return{ <expr>* }
+ return traverse_return(env, stm)
+ elseif tag == "Break" then
+ return traverse_break(env, stm)
+ elseif tag == "Continue" then
+ return traverse_continue(env,stm)
+ elseif tag == "Call" then -- `Call{ expr expr* }
+ return traverse_call(env, stm)
+ elseif tag == "Invoke" then -- `Invoke{ expr `String{ <string> } expr* }
+ return traverse_invoke(env, stm)
+ else
+ error("expecting a statement, but got a " .. tag)
+ end
+end
+function traverse_block (env, block)
+ local l = {}
+ new_scope(env)
+ for k, v in ipairs(block) do
+ local status, msg = traverse_stm(env, v)
+ if not status then return status, msg end
+ end
+ end_scope(env)
+ return true
end
+
+local function traverse (ast, errorinfo)
+ assert(type(ast) == "table")
+ assert(type(errorinfo) == "table")
+ local env = { errorinfo = errorinfo, ["function"] = {} }
+ new_function(env)
+ set_vararg(env, true)
+ local status, msg = traverse_block(env, ast)
+ if not status then return status, msg end
+ end_function(env)
+ status, msg = verify_pending_gotos(env)
+ if not status then return status, msg end
+ return ast
+end
+
+function parser.parse (subject, filename)
+ local errorinfo = { subject = subject, filename = filename }
+ lpeg.setmaxstack(1000)
+ --debug.getregistry()["lpeg-maxstack"] = 1000
+ local ast, error_msg = lpeg.match(G, subject, nil, errorinfo)
+ if not ast then return ast, error_msg end
+ return traverse(ast, errorinfo)
+end
+
+return parser
+]==]
+
+local str2 = [=[
+--[[/////////////////
+
]]
+local foo = 1
+if foo then print("bar") end
+local function something(foo, bar)
+ print("foobar")
+end
+something(foo,4)
+]=]
local min = glum.minify(str)
---local comp = glum.uglify(min)
+--local comp = ugly.uglify(min)
print(min)
+print(string.format("Old size:%d\nNew size:%d",#str,#min))
--[[
local fuzzel = loadstring(f)()
diff --git a/test/test_output.lua b/test/test_output.lua
new file mode 100644
index 0000000..44eb5f6
--- /dev/null
+++ b/test/test_output.lua
@@ -0,0 +1,293 @@
+Finding string reps
+ 1:
+ 1:NetworkVar
+ 2:96
+ 2:
+ 1:category
+ 2:84
+ 3:
+ 1:KeyName
+ 2:75
+ 4:
+ 1:NetworkVarElement
+ 2:45
+ 5:
+ 1:Float
+ 2:39
+ 6:
+ 1:VectorColor
+ 2:36
+ 7:
+ 1:Edit
+ 2:28
+ 8:
+ 1:type
+ 2:28
+ 9:
+ 1:order
+ 2:27
+ 10:
+ 1:EnvSun
+ 2:20
+ 11:
+ 1:SetSunNormal
+ 2:20
+ 12:
+ 1:Vector
+ 2:20
+ 13:
+ 1:Stars
+ 2:18
+ 14:
+ 1:UpdateTransmitState
+ 2:17
+ 15:
+ 1:GetInternalVariable
+ 2:17
+ 16:
+ 1:SetNetworkKeyValue
+ 2:16
+ 17:
+ 1:DisableDuplicator
+ 2:15
+ 18:
+ 1:skybox/starfield
+ 2:14
+ 19:
+ 1:CanEditVariables
+ 2:14
+ 20:
+ 1:SetDuskIntensity
+ 2:14
+ 21:
+ 1:SetupDataTables
+ 2:13
+ 22:
+ 1:SetStarTexture
+ 2:12
+ 23:
+ 1:SetBottomColor
+ 2:12
+ 24:
+ 1:duskintensity
+ 2:11
+ 25:
+ 1:DuskIntensity
+ 2:11
+ 26:
+ 1:m_vDirection
+ 2:10
+ 27:
+ 1:SetDrawStars
+ 2:10
+ 28:
+ 1:SetDuskColor
+ 2:10
+ 29:
+ 1:SetDuskScale
+ 2:10
+ 30:
+ 1:SetStarSpeed
+ 2:10
+ 31:
+ 1:Color Bottom
+ 2:10
+ 32:
+ 1:SetStarScale
+ 2:10
+ 33:
+ 1:StarTexture
+ 2:9
+ 34:
+ 1:SetFadeBias
+ 2:9
+ 35:
+ 1:SetStarFade
+ 2:9
+ 36:
+ 1:SetHDRScale
+ 2:9
+ 37:
+ 1:Angle
+ 2:9
+ 38:
+ 1:startexture
+ 2:9
+ 39:
+ 1:BottomColor
+ 2:9
+ 40:
+ 1:FindByClass
+ 2:9
+ 41:
+ 1:SetTopColor
+ 2:9
+ 42:
+ 1:SetSunColor
+ 2:9
+ 43:
+ 1:bottomcolor
+ 2:9
+ 44:
+ 1:min
+ 2:8
+ 45:
+ 1:SetSunSize
+ 2:8
+ 46:
+ 1:Main
+ 2:8
+ 47:
+ 1:Initialize
+ 2:8
+ 48:
+ 1:max
+ 2:8
+ 49:
+ 1:drawstars
+ 2:7
+ 50:
+ 1:duskscale
+ 2:7
+ 51:
+ 1:DuskColor
+ 2:7
+ 52:
+ 1:sunnormal
+ 2:7
+ 53:
+ 1:starspeed
+ 2:7
+ 54:
+ 1:DuskScale
+ 2:7
+ 55:
+ 1:SunNormal
+ 2:7
+ 56:
+ 1:DrawStars
+ 2:7
+ 57:
+ 1:duskcolor
+ 2:7
+ 58:
+ 1:StarSpeed
+ 2:7
+ 59:
+ 1:starscale
+ 2:7
+ 60:
+ 1:StarScale
+ 2:7
+ 61:
+ 1:topcolor
+ 2:6
+ 62:
+ 1:hdrscale
+ 2:6
+ 63:
+ 1:fadebias
+ 2:6
+ 64:
+ 1:suncolor
+ 2:6
+ 65:
+ 1:SunColor
+ 2:6
+ 66:
+ 1:StarFade
+ 2:6
+ 67:
+ 1:FadeBias
+ 2:6
+ 68:
+ 1:TopColor
+ 2:6
+ 69:
+ 1:HDRScale
+ 2:6
+ 70:
+ 1:KeyValue
+ 2:6
+ 71:
+ 1:starfade
+ 2:6
+ 72:
+ 1:Dusk
+ 2:6
+ 73:
+ 1:Texture
+ 2:5
+ 74:
+ 1:SunSize
+ 2:5
+ 75:
+ 1:IsAdmin
+ 2:5
+ 76:
+ 1:env_sun
+ 2:5
+ 77:
+ 1:Boolean
+ 2:5
+ 78:
+ 1:sunsize
+ 2:5
+ 79:
+ 1:String
+ 2:4
+ 80:
+ 1:group
+ 2:3
+ 81:
+ 1:point
+ 2:3
+ 82:
+ 1:Think
+ 2:3
+ 83:
+ 1:title
+ 2:3
+ 84:
+ 1:Bool
+ 2:2
+ 85:
+ 1:Type
+ 2:2
+ 86:
+ 1:Sun
+ 2:2
+ 87:
+ 1:r
+ 2:-1
+ 88:
+ 1:y
+ 2:-1
+ 89:
+ 1:p
+ 2:-1
+Found 1 locals as Local
+Found 1 locals as Local
+lhss is
+ 1:e
+ 2:a
+ 3:b
+ 4:c
+ 5:f
+ 6:d
+Before doing stringfor for the second time, olocalvar is
+ strings:
+ Float:e
+ NetworkVar:a
+ category:b
+ KeyName:c
+ VectorColor:f
+ NetworkVarElement:d
+ numlocals:2
+ lname:f
+ block:true
+ nids:
+ ids:
+Found 1 locals as Local
+Found 1 locals as Local
+ local e,a,b,c,f,d="Float","NetworkVar","category","KeyName","VectorColor","NetworkVarElement";AddCSLuaFile()ENT.Type="point";ENT.DisableDuplicator= true ;ENT.UpdateTransmitState= function() return TRANSMIT_ALWAYS end ;ENT.SetupDataTables= function()self[a]("Vector",0,"TopColor",{[c]="topcolor",["Edit"]={["type"]=f,[b]="Main",["order"]=1}})self[a]("Vector",1,"BottomColor",{[c]="bottomcolor",["Edit"]={["type"]=f,[b]="Main",["title"]="Color Bottom",["order"]=2}})self[a](e,0,"FadeBias",{[c]="fadebias",["Edit"]={["type"]=e,[b]="Main",["min"]=0,["max"]=1,["order"]=3}})self[a](e,4,"SunSize",{[c]="sunsize",["Edit"]={["type"]=e,["min"]=0,["max"]=10,[b]="Sun"}})self[a]("Vector",2,"SunNormal",{[c]="sunnormal"})self[a]("Vector",3,"SunColor",{[c]="suncolor",["Edit"]={["type"]=f,[b]="Sun"}})self[a](e,2,"DuskScale",{[c]="duskscale",["Edit"]={["type"]=e,["min"]=0,["max"]=1,[b]="Dusk"}})self[a](e,3,"DuskIntensity",{[c]="duskintensity",["Edit"]={["type"]=e,["min"]=0,["max"]=10,[b]="Dusk"}})self[a]("Vector",4,"DuskColor",{[c]="duskcolor",["Edit"]={["type"]=f,[b]="Dusk"}})self[a]("Bool",0,"DrawStars",{[c]="drawstars",["Edit"]={["type"]="Boolean",[b]="Stars",["order"]=10}})self[a]("String",0,"StarTexture",{[c]="startexture",["Edit"]={["type"]="Texture",["group"]="Stars",[b]="Stars",["order"]=11}})self[d]("Angle",0,"p","StarScale",{[c]="starscale",["Edit"]={["type"]=e,["min"]=0,["max"]=5,[b]="Stars",["order"]=12}})self[d]("Angle",0,"y","StarFade",{[c]="starfade",["Edit"]={["type"]=e,["min"]=0,["max"]=5,[b]="Stars",["order"]=13}})self[d]("Angle",0,"r","StarSpeed",{[c]="starspeed",["Edit"]={["type"]=e,["min"]=0,["max"]=5,[b]="Stars",["order"]=14}})self[a](e,1,"HDRScale",{[c]="hdrscale",["Edit"]={["type"]=e,[b]="Main",["min"]=0,["max"]=1,["order"]=4}}) if (SERVER) then self:SetTopColor(Vector(0.2,0.5,1))self:SetBottomColor(Vector(0.8,1,1))self:SetFadeBias(1)self:SetSunNormal(Vector(0.4,0,0.01))self:SetSunColor(Vector(0.2,0.1,0))self:SetSunSize(2)self:SetDuskColor(Vector(1,0.2,0))self:SetDuskScale(1)self:SetDuskIntensity(1)self:SetDrawStars( true )self:SetStarSpeed(0.01)self:SetStarScale(0.5)self:SetStarFade(1.5)self:SetStarTexture("skybox/starfield")self:SetHDRScale(0.66) end end ;ENT.Initialize= function() end ;ENT.KeyValue= function(g,h,i) if (g:SetNetworkKeyValue(h,i)) then return end end ;ENT.Think= function() if (SERVER and g.EnvSun== nil ) then g.EnvSun= false ;local j=ents.FindByClass("env_sun"); if (0<#j) then g.EnvSun=j[1]; end end if (SERVER and IsValid(g.EnvSun)) then local j=g.EnvSun:GetInternalVariable("m_vDirection"); if (isvector(j)) then g:SetSunNormal(j) end end if (CLIENT and not g_SkyPaint~=g) then if ( not IsValid(g_SkyPaint)) then g_SkyPaint=g; end end end ;ENT.CanEditVariables= function(g,j) return j:IsAdmin() end ;