Thu, 06 Sep 2018 19:13:42 +0100
stanzacmp + tests: Advance through matching stanza on successful match
#!/usr/bin/env lua5.2 package.preload['optlex']=(function(...) local _ENV=_ENV; local function a(t,...) local e=package.loaded[t]or _ENV[t]or{_NAME=t}; package.loaded[t]=e; for t=1,select("#",...)do (select(t,...))(e); end _ENV=e; _M=e; return e; end local h=_G local m=require"string" a"optlex" local i=m.match local e=m.sub local r=m.find local l=m.rep local c error=h.error warn={} local n,o,d local k={ TK_KEYWORD=true, TK_NAME=true, TK_NUMBER=true, TK_STRING=true, TK_LSTRING=true, TK_OP=true, TK_EOS=true, } local v={ TK_COMMENT=true, TK_LCOMMENT=true, TK_EOL=true, TK_SPACE=true, } local s local function q(e) local t=n[e-1] if e<=1 or t=="TK_EOL"then return true elseif t==""then return q(e-1) end return false end local function j(t) local e=n[t+1] if t>=#n or e=="TK_EOL"or e=="TK_EOS"then return true elseif e==""then return j(t+1) end return false end local function T(t) local a=#i(t,"^%-%-%[=*%[") local a=e(t,a+1,-(a-1)) local e,t=1,0 while true do local o,n,i,a=r(a,"([\r\n])([\r\n]?)",e) if not o then break end e=o+1 t=t+1 if#a>0 and i~=a then e=e+1 end end return t end local function b(s,h) local a=i local t,e=n[s],n[h] if t=="TK_STRING"or t=="TK_LSTRING"or e=="TK_STRING"or e=="TK_LSTRING"then return"" elseif t=="TK_OP"or e=="TK_OP"then if(t=="TK_OP"and(e=="TK_KEYWORD"or e=="TK_NAME"))or (e=="TK_OP"and(t=="TK_KEYWORD"or t=="TK_NAME"))then return"" end if t=="TK_OP"and e=="TK_OP"then local t,e=o[s],o[h] if(a(t,"^%.%.?$")and a(e,"^%."))or (a(t,"^[~=<>]$")and e=="=")or (t=="["and(e=="["or e=="="))then return" " end return"" end local t=o[s] if e=="TK_OP"then t=o[h]end if a(t,"^%.%.?%.?$")then return" " end return"" else return" " end end local function g() local a,i,s={},{},{} local e=1 for t=1,#n do local n=n[t] if n~=""then a[e],i[e],s[e]=n,o[t],d[t] e=e+1 end end n,o,d=a,i,s end local function A(r) local t=o[r] local t=t local n if i(t,"^0[xX]")then local e=h.tostring(h.tonumber(t)) if#e<=#t then t=e else return end end if i(t,"^%d+%.?0*$")then t=i(t,"^(%d+)%.?0*$") if t+0>0 then t=i(t,"^0*([1-9]%d*)$") local a=#i(t,"0*$") local o=h.tostring(a) if a>#o+1 then t=e(t,1,#t-a).."e"..o end n=t else n="0" end elseif not i(t,"[eE]")then local a,t=i(t,"^(%d*)%.(%d+)$") if a==""then a=0 end if t+0==0 and a==0 then n="0" else local o=#i(t,"0*$") if o>0 then t=e(t,1,#t-o) end if a+0>0 then n=a.."."..t else n="."..t local a=#i(t,"^0*") local o=#t-a local a=h.tostring(#t) if o+2+#a<1+#t then n=e(t,-o).."e-"..a end end end else local t,a=i(t,"^([^eE]+)[eE]([%+%-]?%d+)$") a=h.tonumber(a) local s,o=i(t,"^(%d*)%.(%d*)$") if s then a=a-#o t=s..o end if t+0==0 then n="0" else local o=#i(t,"^0*") t=e(t,o+1) o=#i(t,"0*$") if o>0 then t=e(t,1,#t-o) a=a+o end local i=h.tostring(a) if a==0 then n=t elseif a>0 and(a<=1+#i)then n=t..l("0",a) elseif a<0 and(a>=-#t)then o=#t+a n=e(t,1,o).."."..e(t,o+1) elseif a<0 and(#i>=-a-#t)then o=-a-#t n="."..l("0",o)..t else n=t.."e"..a end end end if n and n~=o[r]then if s then c("<number> (line "..d[r]..") "..o[r].." -> "..n) s=s+1 end o[r]=n end end local function I(u) local t=o[u] local n=e(t,1,1) local f=(n=="'")and'"'or"'" local t=e(t,2,-2) local a=1 local l,h=0,0 while a<=#t do local u=e(t,a,a) if u=="\\"then local o=a+1 local d=e(t,o,o) local s=r("abfnrtv\\\n\r\"\'0123456789",d,1,true) if not s then t=e(t,1,a-1)..e(t,o) a=a+1 elseif s<=8 then a=a+2 elseif s<=10 then local i=e(t,o,o+1) if i=="\r\n"or i=="\n\r"then t=e(t,1,a).."\n"..e(t,o+2) elseif s==10 then t=e(t,1,a).."\n"..e(t,o+1) end a=a+2 elseif s<=12 then if d==n then l=l+1 a=a+2 else h=h+1 t=e(t,1,a-1)..e(t,o) a=a+1 end else local i=i(t,"^(%d%d?%d?)",o) o=a+1+#i local d=i+0 local s=m.char(d) local r=r("\a\b\f\n\r\t\v",s,1,true) if r then i="\\"..e("abfnrtv",r,r) elseif d<32 then i="\\"..d elseif s==n then i="\\"..s l=l+1 elseif s=="\\"then i="\\\\" else i=s if s==f then h=h+1 end end t=e(t,1,a-1)..i..e(t,o) a=a+#i end else a=a+1 if u==f then h=h+1 end end end if l>h then a=1 while a<=#t do local o,s,i=r(t,"([\'\"])",a) if not o then break end if i==n then t=e(t,1,o-2)..e(t,o) a=o else t=e(t,1,o-1).."\\"..e(t,o) a=o+2 end end n=f end t=n..t..n if t~=o[u]then if s then c("<string> (line "..d[u]..") "..o[u].." -> "..t) s=s+1 end o[u]=t end end local function O(h) local t=o[h] local u=i(t,"^%[=*%[") local a=#u local c=e(t,-a,-1) local s=e(t,a+1,-(a+1)) local n="" local t=1 while true do local a,o,l,r=r(s,"([\r\n])([\r\n]?)",t) local o if not a then o=e(s,t) elseif a>=t then o=e(s,t,a-1) end if o~=""then if i(o,"%s+$")then warn.lstring="trailing whitespace in long string near line "..d[h] end n=n..o end if not a then break end t=a+1 if a then if#r>0 and l~=r then t=t+1 end if not(t==1 and t==a)then n=n.."\n" end end end if a>=3 then local e,t=a-1 while e>=2 do local a="%]"..l("=",e-2).."%]" if not i(n,a)then t=e end e=e-1 end if t then a=l("=",t-2) u,c="["..a.."[","]"..a.."]" end end o[h]=u..n..c end local function w(d) local a=o[d] local h=i(a,"^%-%-%[=*%[") local t=#h local u=e(a,-t,-1) local s=e(a,t+1,-(t-1)) local n="" local a=1 while true do local o,t,r,h=r(s,"([\r\n])([\r\n]?)",a) local t if not o then t=e(s,a) elseif o>=a then t=e(s,a,o-1) end if t~=""then local a=i(t,"%s*$") if#a>0 then t=e(t,1,-(a+1))end n=n..t end if not o then break end a=o+1 if o then if#h>0 and r~=h then a=a+1 end n=n.."\n" end end t=t-2 if t>=3 then local e,a=t-1 while e>=2 do local t="%]"..l("=",e-2).."%]" if not i(n,t)then a=e end e=e-1 end if a then t=l("=",a-2) h,u="--["..t.."[","]"..t.."]" end end o[d]=h..n..u end local function p(n) local t=o[n] local a=i(t,"%s*$") if#a>0 then t=e(t,1,-(a+1)) end o[n]=t end local function x(o,a) if not o then return false end local t=i(a,"^%-%-%[=*%[") local t=#t local i=e(a,-t,-1) local e=e(a,t+1,-(t-1)) if r(e,o,1,true)then return true end end function optimize(t,r,a,i) local m=t["opt-comments"] local u=t["opt-whitespace"] local f=t["opt-emptylines"] local y=t["opt-eols"] local z=t["opt-strings"] local E=t["opt-numbers"] local _=t.KEEP s=t.DETAILS and 0 c=c or h.print if y then m=true u=true f=true end n,o,d =r,a,i local t=1 local a,r local h local function i(a,i,e) e=e or t n[e]=a or"" o[e]=i or"" end while true do a,r=n[t],o[t] local s=q(t) if s then h=nil end if a=="TK_EOS"then break elseif a=="TK_KEYWORD"or a=="TK_NAME"or a=="TK_OP"then h=t elseif a=="TK_NUMBER"then if E then A(t) end h=t elseif a=="TK_STRING"or a=="TK_LSTRING"then if z then if a=="TK_STRING"then I(t) else O(t) end end h=t elseif a=="TK_COMMENT"then if m then if t==1 and e(r,1,1)=="#"then p(t) else i() end elseif u then p(t) end elseif a=="TK_LCOMMENT"then if x(_,r)then if u then w(t) end h=t elseif m then local e=T(r) if v[n[t+1]]then i() a="" else i("TK_SPACE"," ") end if not f and e>0 then i("TK_EOL",l("\n",e)) end if u and a~=""then t=t-1 end else if u then w(t) end h=t end elseif a=="TK_EOL"then if s and f then i() elseif r=="\r\n"or r=="\n\r"then i("TK_EOL","\n") end elseif a=="TK_SPACE"then if u then if s or j(t)then i() else local a=n[h] if a=="TK_LCOMMENT"then i() else local e=n[t+1] if v[e]then if(e=="TK_COMMENT"or e=="TK_LCOMMENT")and a=="TK_OP"and o[h]=="-"then else i() end else local e=b(h,t+1) if e==""then i() else i("TK_SPACE"," ") end end end end end else error("unidentified token encountered") end t=t+1 end g() if y then t=1 if n[1]=="TK_COMMENT"then t=3 end while true do a,r=n[t],o[t] if a=="TK_EOS"then break elseif a=="TK_EOL"then local e,a=n[t-1],n[t+1] if k[e]and k[a]then local e=b(t-1,t+1) if e==""then i() end end end t=t+1 end g() end if s and s>0 then c()end return n,o,d end return _M; end) package.preload['optparser']=(function(...) local _ENV=_ENV; local function o(t,...) local e=package.loaded[t]or _ENV[t]or{_NAME=t}; package.loaded[t]=e; for t=1,select("#",...)do (select(t,...))(e); end _ENV=e; _M=e; return e; end local e=_G local a=require"string" local l=require"table" o"optparser" local n="etaoinshrdlucmfwypvbgkqjxz_ETAOINSHRDLUCMFWYPVBGKQJXZ" local d="etaoinshrdlucmfwypvbgkqjxz_0123456789ETAOINSHRDLUCMFWYPVBGKQJXZ" local w={} for e in a.gmatch([[ and break do else elseif end false for function if in local nil not or repeat return then true until while self _ENV]],"%S+")do w[e]=true end local r,u, c,o, m,v, h, s local function f(e) local i={} for n=1,#e do local e=e[n] local o=e.name if not i[o]then i[o]={ decl=0,token=0,size=0, } end local t=i[o] t.decl=t.decl+1 local i=e.xref local a=#i t.token=t.token+a t.size=t.size+a*#o if e.decl then e.id=n e.xcount=a if a>1 then e.first=i[2] e.last=i[a] end else t.id=n end end return i end local function p(e) local i=a.byte local s=a.char local a={ TK_KEYWORD=true,TK_NAME=true,TK_NUMBER=true, TK_STRING=true,TK_LSTRING=true, } if not e["opt-comments"]then a.TK_COMMENT=true a.TK_LCOMMENT=true end local t={} for e=1,#r do t[e]=u[e] end for e=1,#o do local e=o[e] local a=e.xref for e=1,e.xcount do local e=a[e] t[e]="" end end local e={} for t=0,255 do e[t]=0 end for o=1,#r do local o,t=r[o],t[o] if a[o]then for a=1,#t do local t=i(t,a) e[t]=e[t]+1 end end end local function a(o) local t={} for a=1,#o do local o=i(o,a) t[a]={c=o,freq=e[o],} end l.sort(t, function(t,e) return t.freq>e.freq end ) local e={} for a=1,#t do e[a]=s(t[a].c) end return l.concat(e) end n=a(n) d=a(d) end local function y() local t local s,r=#n,#d local e=h if e<s then e=e+1 t=a.sub(n,e,e) else local o,i=s,1 repeat e=e-o o=o*r i=i+1 until o>e local o=e%s e=(e-o)/s o=o+1 t=a.sub(n,o,o) while i>1 do local o=e%r e=(e-o)/r o=o+1 t=t..a.sub(d,o,o) i=i-1 end end h=h+1 return t,m[t]~=nil end function optimize(e,i,n,a,t) r,u,c,o =i,n,a,t h=0 s={} m=f(c) v=f(o) if e["opt-entropy"]then p(e) end local e={} for t=1,#o do e[t]=o[t] end l.sort(e, function(e,t) return e.xcount>t.xcount end ) local a,t,r={},1,false for o=1,#e do local e=e[o] if not e.preserve then a[t]=e t=t+1 elseif e.name=="self"then r=true end end e=a local h=#e while h>0 do local n,a repeat n,a=y() until not w[n] s[#s+1]=n local t=h if a then local i=c[m[n].id].xref local n=#i for a=1,h do local a=e[a] local s,e=a.act,a.rem while e<0 do e=o[-e].rem end local o for t=1,n do local t=i[t] if t>=s and t<=e then o=true end end if o then a.skip=true t=t-1 end end end while t>0 do local a=1 while e[a].skip do a=a+1 end t=t-1 local i=e[a] a=a+1 i.newname=n i.skip=true i.done=true local s,r=i.first,i.last local h=i.xref if s and t>0 then local n=t while n>0 do while e[a].skip do a=a+1 end n=n-1 local e=e[a] a=a+1 local n,a=e.act,e.rem while a<0 do a=o[-a].rem end if not(r<n or s>a)then if n>=i.act then for o=1,i.xcount do local o=h[o] if o>=n and o<=a then t=t-1 e.skip=true break end end else if e.last and e.last>=i.act then t=t-1 e.skip=true end end end if t==0 then break end end end end local a,t={},1 for o=1,h do local e=e[o] if not e.done then e.skip=false a[t]=e t=t+1 end end e=a h=#e end for e=1,#o do local e=o[e] local t=e.xref if e.newname then for a=1,e.xcount do local t=t[a] u[t]=e.newname end e.name,e.oldname =e.newname,e.name else e.oldname=e.name end end if r then s[#s+1]="self" end local e=f(o) end return _M; end) package.preload['llex']=(function(...) local _ENV=_ENV; local function a(t,...) local e=package.loaded[t]or _ENV[t]or{_NAME=t}; package.loaded[t]=e; for t=1,select("#",...)do (select(t,...))(e); end _ENV=e; _M=e; return e; end local d=_G local h=require"string" a"llex" local u=h.find local c=h.match local i=h.sub local f={} for e in h.gmatch([[ and break do else elseif end false for function if in local nil not or repeat return then true until while]],"%S+")do f[e]=true end local e, r, a, n, s local function o(a,t) local e=#tok+1 tok[e]=a seminfo[e]=t tokln[e]=s end local function l(t,h) local n=i local i=n(e,t,t) t=t+1 local e=n(e,t,t) if(e=="\n"or e=="\r")and(e~=i)then t=t+1 i=i..e end if h then o("TK_EOL",i)end s=s+1 a=t return t end function init(i,t) e=i r=t a=1 s=1 tok={} seminfo={} tokln={} local i,n,e,t=u(e,"^(#[^\r\n]*)(\r?\n?)") if i then a=a+#e o("TK_COMMENT",e) if#t>0 then l(a,true)end end end function chunkid() if r and c(r,"^[=@]")then return i(r,2) end return"[string]" end function errorline(a,t) local e=error or d.error e(h.format("%s:%d: %s",chunkid(),t or s,a)) end local r=errorline local function m(t) local i=i local n=i(e,t,t) t=t+1 local o=#c(e,"=*",t) t=t+o a=t return(i(e,t,t)==n)and o or(-o)-1 end local function w(d,h) local t=a+1 local i=i local o=i(e,t,t) if o=="\r"or o=="\n"then t=l(t) end local o=t while true do local o,u,s=u(e,"([\r\n%]])",t) if not o then r(d and"unfinished long string"or "unfinished long comment") end t=o if s=="]"then if m(t)==h then n=i(e,n,a) a=a+1 return n end t=a else n=n.."\n" t=l(t) end end end local function y(d) local t=a local s=u local h=i while true do local i,u,o=s(e,"([\n\r\\\"\'])",t) if i then if o=="\n"or o=="\r"then r("unfinished string") end t=i if o=="\\"then t=t+1 o=h(e,t,t) if o==""then break end i=s("abfnrtv\n\r",o,1,true) if i then if i>7 then t=l(t) else t=t+1 end elseif s(o,"%D")then t=t+1 else local o,a,e=s(e,"^(%d%d?%d?)",t) t=a+1 if e+1>256 then r("escape sequence too large") end end else t=t+1 if o==d then a=t return h(e,n,t-1) end end else break end end r("unfinished string") end function llex() local s=u local u=c while true do local t=a while true do local c,p,h=s(e,"^([_%a][_%w]*)",t) if c then a=t+#h if f[h]then o("TK_KEYWORD",h) else o("TK_NAME",h) end break end local h,f,c=s(e,"^(%.?)%d",t) if h then if c=="."then t=t+1 end local c,l,n=s(e,"^%d*[%.%d]*([eE]?)",t) t=l+1 if#n==1 then if u(e,"^[%+%-]",t)then t=t+1 end end local n,t=s(e,"^[_%w]*",t) a=t+1 local e=i(e,h,t) if not d.tonumber(e)then r("malformed number") end o("TK_NUMBER",e) break end local d,c,f,h=s(e,"^((%s)[ \t\v\f]*)",t) if d then if h=="\n"or h=="\r"then l(t,true) else a=c+1 o("TK_SPACE",f) end break end local h=u(e,"^%p",t) if h then n=t local d=s("-[\"\'.=<>~",h,1,true) if d then if d<=2 then if d==1 then local r=u(e,"^%-%-(%[?)",t) if r then t=t+2 local h=-1 if r=="["then h=m(t) end if h>=0 then o("TK_LCOMMENT",w(false,h)) else a=s(e,"[\n\r]",t)or(#e+1) o("TK_COMMENT",i(e,n,a-1)) end break end else local e=m(t) if e>=0 then o("TK_LSTRING",w(true,e)) elseif e==-1 then o("TK_OP","[") else r("invalid long string delimiter") end break end elseif d<=5 then if d<5 then a=t+1 o("TK_STRING",y(h)) break end h=u(e,"^%.%.?%.?",t) else h=u(e,"^%p=?",t) end end a=t+#h o("TK_OP",h) break end local e=i(e,t,t) if e~=""then a=t+1 o("TK_OP",e) break end o("TK_EOS","") return end end end d.print(_M) d.assert(d.type(_M)=="table") return _M end) package.preload['lparser']=(function(...) local _ENV=_ENV; local function a(t,...) local e=package.loaded[t]or _ENV[t]or{_NAME=t}; package.loaded[t]=e; for t=1,select("#",...)do (select(t,...))(e); end _ENV=e; _M=e; return e; end local R=_G local v=require"string" a"lparser" local E, j, T, S, r, d, B, t,x,s,m, p, a, K, q, N, l, b, A local w,u,y,_,z,g local e=v.gmatch local O={} for e in e("else elseif end until <eof>","%S+")do O[e]=true end local G={} for e in e("if while do for repeat function local return break","%S+")do G[e]=e.."_stat" end local I={} local Q={} for e,a,t in e([[ {+ 6 6}{- 6 6}{* 7 7}{/ 7 7}{% 7 7} {^ 10 9}{.. 5 4} {~= 3 3}{== 3 3} {< 3 3}{<= 3 3}{> 3 3}{>= 3 3} {and 2 2}{or 1 1} ]],"{(%S+)%s(%d+)%s(%d+)}")do I[e]=a+0 Q[e]=t+0 end local X={["not"]=true,["-"]=true, ["#"]=true,} local Z=8 local function o(e,a) local t=error or R.error t(v.format("(source):%d: %s",a or s,e)) end local function e() B=T[r] t,x,s,m =E[r],j[r],T[r],S[r] r=r+1 end local function J() return E[r] end local function h(a) local e=t if e~="<number>"and e~="<string>"then if e=="<name>"then e=x end e="'"..e.."'" end o(a.." near "..e) end local function c(e) h("'"..e.."' expected") end local function i(a) if t==a then e();return true end end local function D(e) if t~=e then c(e)end end local function o(t) D(t);e() end local function V(e,t) if not e then h(t)end end local function n(e,a,t) if not i(e)then if t==s then c(e) else h("'"..e.."' expected (to close '"..a.."' at line "..t..")") end end end local function f() D("<name>") local t=x p=m e() return t end local function U(e,t) e.k="VK" end local function L(e) U(e,f()) end local function c(o,i) local t=a.bl local e if t then e=t.locallist else e=a.locallist end local t=#l+1 l[t]={ name=o, xref={p}, decl=p, } if i or o=="_ENV"then l[t].preserve=true end local a=#b+1 b[a]=t A[a]=e end local function k(e) local t=#b while e>0 do e=e-1 local e=t-e local a=b[e] local t=l[a] local o=t.name t.act=m b[e]=nil local i=A[e] A[e]=nil local e=i[o] if e then t=l[e] t.rem=-a end i[o]=a end end local function H() local t=a.bl local e if t then e=t.locallist else e=a.locallist end for t,e in R.pairs(e)do local e=l[e] e.rem=m end end local function m(e,t) if v.sub(e,1,1)=="("then return end c(e,t) end local function R(o,a) local t=o.bl local e if t then e=t.locallist while e do if e[a]then return e[a]end t=t.prev e=t and t.locallist end end e=o.locallist return e[a]or-1 end local function v(t,o,e) if t==nil then e.k="VGLOBAL" return"VGLOBAL" else local a=R(t,o) if a>=0 then e.k="VLOCAL" e.id=a return"VLOCAL" else if v(t.prev,o,e)=="VGLOBAL"then return"VGLOBAL" end e.k="VUPVAL" return"VUPVAL" end end end local function P(o) local t=f() v(a,t,o) if o.k=="VGLOBAL"then local e=N[t] if not e then e=#q+1 q[e]={ name=t, xref={p}, } N[t]=e else local e=q[e].xref e[#e+1]=p end else local e=o.id local e=l[e].xref e[#e+1]=p end end local function p(t) local e={} e.isbreakable=t e.prev=a.bl e.locallist={} a.bl=e end local function v() local e=a.bl H() a.bl=e.prev end local function Y() local e if not a then e=K else e={} end e.prev=a e.bl=nil e.locallist={} a=e end local function F() H() a=a.prev end local function H(a) local t={} e() L(t) a.k="VINDEXED" end local function M(t) e() u(t) o("]") end local function R(e) local e,a={},{} if t=="<name>"then L(e) else M(e) end o("=") u(a) end local function C(e) if e.v.k=="VVOID"then return end e.v.k="VVOID" end local function C(e) u(e.v) end local function W(a) local s=s local e={} e.v={} e.t=a a.k="VRELOCABLE" e.v.k="VVOID" o("{") repeat if t=="}"then break end local t=t if t=="<name>"then if J()~="="then C(e) else R(e) end elseif t=="["then R(e) else C(e) end until not i(",")and not i(";") n("}","{",s) end local function J() local o=0 if t~=")"then repeat local t=t if t=="<name>"then c(f()) o=o+1 elseif t=="..."then e() a.is_vararg=true else h("<name> or '...' expected") end until a.is_vararg or not i(",") end k(o) end local function C(r) local a={} local i=s local o=t if o=="("then if i~=B then h("ambiguous syntax (function call x new statement)") end e() if t==")"then a.k="VVOID" else w(a) end n(")","(",i) elseif o=="{"then W(a) elseif o=="<string>"then U(a,x) e() else h("function arguments expected") return end r.k="VCALL" end local function B(a) local t=t if t=="("then local t=s e() u(a) n(")","(",t) elseif t=="<name>"then P(a) else h("unexpected symbol") end end local function R(a) B(a) while true do local t=t if t=="."then H(a) elseif t=="["then local e={} M(e) elseif t==":"then local t={} e() L(t) C(a) elseif t=="("or t=="<string>"or t=="{"then C(a) else return end end end local function L(o) local t=t if t=="<number>"then o.k="VKNUM" elseif t=="<string>"then U(o,x) elseif t=="nil"then o.k="VNIL" elseif t=="true"then o.k="VTRUE" elseif t=="false"then o.k="VFALSE" elseif t=="..."then V(a.is_vararg==true, "cannot use '...' outside a vararg function"); o.k="VVARARG" elseif t=="{"then W(o) return elseif t=="function"then e() z(o,false,s) return else R(o) return end e() end local function x(o,n) local a=t local i=X[a] if i then e() x(o,Z) else L(o) end a=t local t=I[a] while t and t>n do local o={} e() local e=x(o,Q[a]) a=e t=I[a] end return a end function u(e) x(e,0) end local function I(e) local t={} local e=e.v.k V(e=="VLOCAL"or e=="VUPVAL"or e=="VGLOBAL" or e=="VINDEXED","syntax error") if i(",")then local e={} e.v={} R(e.v) I(e) else o("=") w(t) return end t.k="VNONRELOC" end local function x(e,t) o("do") p(false) k(e) y() v() end local function U(e) local t=d m("(for index)") m("(for limit)") m("(for step)") c(e) o("=") _() o(",") _() if i(",")then _() else end x(1,true) end local function M(e) local t={} m("(for generator)") m("(for state)") m("(for control)") c(e) local e=1 while i(",")do c(f()) e=e+1 end o("in") local a=d w(t) x(e,false) end local function L(e) local a=false P(e) while t=="."do H(e) end if t==":"then a=true H(e) end return a end function _() local e={} u(e) end local function x() local e={} u(e) end local function _() e() x() o("then") y() end local function C() local t,e={} c(f()) t.k="VLOCAL" k(1) z(e,false,s) end local function H() local e=0 local t={} repeat c(f()) e=e+1 until not i(",") if i("=")then w(t) else t.k="VVOID" end k(e) end function w(e) u(e) while i(",")do u(e) end end function z(a,t,e) Y() o("(") if t then m("self",true) k(1) end J() o(")") g() n("end","function",e) F() end function y() p(false) g() v() end function for_stat() local o=d p(true) e() local a=f() local e=t if e=="="then U(a) elseif e==","or e=="in"then M(a) else h("'=' or 'in' expected") end n("end","for",o) v() end function while_stat() local t=d e() x() p(true) o("do") y() n("end","while",t) v() end function repeat_stat() local t=d p(true) p(false) e() g() n("until","repeat",t) x() v() v() end function if_stat() local a=d local o={} _() while t=="elseif"do _() end if t=="else"then e() y() end n("end","if",a) end function return_stat() local a={} e() local e=t if O[e]or e==";"then else w(a) end end function break_stat() local t=a.bl e() while t and not t.isbreakable do t=t.prev end if not t then h("no loop to break") end end function expr_stat() local e={} e.v={} R(e.v) if e.v.k=="VCALL"then else e.prev=nil I(e) end end function function_stat() local t=d local o,a={},{} e() local e=L(o) z(a,e,t) end function do_stat() local t=d e() y() n("end","do",t) end function local_stat() e() if i("function")then C() else H() end end local function o() d=s local e=t local t=G[e] if t then _M[t]() if e=="return"or e=="break"then return true end else expr_stat() end return false end function g() local e=false while not e and not O[t]do e=o() i(";") end end function parser() Y() a.is_vararg=true e() g() D("<eof>") F() return q,l end function init(e,o,n) r=1 K={} local t=1 E,j,T,S={},{},{},{} for a=1,#e do local e=e[a] local i=true if e=="TK_KEYWORD"or e=="TK_OP"then e=o[a] elseif e=="TK_NAME"then e="<name>" j[t]=o[a] elseif e=="TK_NUMBER"then e="<number>" j[t]=0 elseif e=="TK_STRING"or e=="TK_LSTRING"then e="<string>" j[t]="" elseif e=="TK_EOS"then e="<eof>" else i=false end if i then E[t]=e T[t]=n[a] S[t]=a t=t+1 end end q,N,l={},{},{} b,A={},{} end return _M end) package.preload['minichunkspy']=(function(...) local _ENV=_ENV; local function e(t,...) local e=package.loaded[t]or _ENV[t]or{_NAME=t}; package.loaded[t]=e; for t=1,select("#",...)do (select(t,...))(e); end _ENV=e; _M=e; return e; end local c,t,u=string,table,math local a,w,n,e=ipairs,setmetatable,type,assert local a=__END_OF_GLOBALS__ local l,i,f=c.char,c.byte,c.sub local E,d,_=u.frexp,u.ldexp,u.abs local y=t.concat local a=u.huge local x=a-a local o=false local h=4 local s=4 local r=8 local t={} local function v() t[#t+1] ={o,h,s,r} end local function p() o,h,s,r =unpack(t[#t]) t[#t]=nil end local function t(e,t) return e.new(e,t) end local m={} local t=t{ new= function(e,a) local a=a or{} local t=m[e]or{ __index=e, __call=t } m[e]=t return w(a,t) end, } local q=t{ unpack=function(t,t,e)return nil,e end, pack=function(e,e)return""end } local m={} local function b(e) local t=m[e]or t{ unpack=function(o,a,t) return f(a,t,t+e-1),t+e end, pack=function(a,t)return f(t,1,e)end } m[e]=t return t end local w=t{ unpack=function(a,t,e) return i(t,e,e),e+1 end, pack=function(t,e)return l(e)end } local i=t{ unpack= function(t,e,a) local e,t,n,i=i(e,a,a+3) if o then e,t,n,i=i,n,t,e end return e+t*256+n*256^2+i*256^3,a+4 end, pack= function(t,s) e(n(s)=="number", "unexpected value type to pack as an uint32") local t,a,i,e e=s%2^32 t=e%256;e=(e-t)/256 a=e%256;e=(e-a)/256 i=e%256;e=(e-i)/256 if o then t,a,i,e=e,i,a,t end return l(t,a,i,e) end } local j=t{ unpack= function(a,e,t) local a=i:unpack(e,t) local e=i:unpack(e,t+4) if o then a,e=e,a end return a+e*2^32,t+8 end, pack= function(a,t) e(n(t)=="number", "unexpected value type to pack as an uint64") local e=t%2^32 local t=(t-e)/2^32 if o then e,t=t,e end return i:pack(e)..i:pack(t) end } local function z(a,e) local t=i:unpack(a,e) local e=i:unpack(a,e+4) if o then t,e=e,t end local a=e%2^20 local t=t local o=t+a*2^32 e=(e-a)/2^20 local t=e%2^11 local e=e<=t and 1 or-1 return e,t,o end local function l(a,n,t) local e=t%2^32 local s=(t-e)/2^32 local t=e local e=((a<0 and 2^11 or 0)+n)*2^20+s if o then t,e=e,t end return i.pack(nil,t)..i.pack(nil,e) end local function k(e) if e~=e then return e end if e==0 then e=1/e end return e>0 and 1 or-1 end local m=d(1,-1022-52) local f=m*2^52 local g=d(2^52-1,-1022-52) local f=d(2^53-1,1023-52) e(m~=0 and m/2==0) e(f~=a) e(f*2==a) local l=t{ unpack= function(t,e,i) local n,o,t=z(e,i) local e if o==0 then e=d(t,-1022-52) elseif o==2047 then e=t==0 and a or x else e=d(2^52+t,o-1023-52) end e=n*e return e,i+8 end, pack= function(t,e) if e~=e then return l(1,2047,2^52-1) end local o=k(e) e=_(e) if e==a then return l(o,2047,0)end if e==0 then return l(o,0,0)end local a,t if e<=g then a=0 t=e/m else local e,o=E(e) t=(2*e-1)*2^52 a=o+1022 end return l(o,a,t) end } local a=w local d={ [4]=i, [8]=j } local w={ [4]=float, [8]=l } local m=t{ unpack=function(a,t,e) return d[h]:unpack(t,e) end, pack=function(t,e) return d[h]:pack(e) end, } local i=t{ unpack=function(a,t,e) return d[s]:unpack(t,e) end, pack=function(t,e) return d[s]:pack(e) end, } local j=t{ unpack=function(a,t,e) return w[r]:unpack(t,e) end, pack=function(t,e) return w[r]:pack(e) end, } local g=b(4) local f=t{ unpack= function(o,s,t) local i={} local e,a=1,1 while o[e]do local n=o[e] local o=n.name if not o then o,a=a,a+1 end i[o],t=n:unpack(s,t) e=e+1 end return i,t end, pack= function(t,n) local i={} local e,a=1,1 while t[e]do local o=t[e] local t=o.name if not t then t,a=a,a+1 end i[e]=o:pack(n[t]) e=e+1 end return y(i) end } local l=t{ unpack= function(n,a,e) local o,e=i:unpack(a,e) local t={} local i=n.type for o=1,o do t[o],e=i:unpack(a,e) end return t,e end, pack= function(o,a) local t=#a local e={i:pack(t)} local o=o.type for t=1,t do e[#e+1]=o:pack(a[t]) end return y(e) end } local k=t{ unpack= function(o,a,t) local t,a=i:unpack(a,t) e(t==0 or t==1, "unpacked an unexpected value "..t.." for a Boolean") return t==1,a end, pack= function(a,t) e(n(t)=="boolean", "unexpected value type to pack as a Boolean") return i:pack(t and 1 or 0) end } local m=t{ unpack= function(t,o,e) local t,e=m:unpack(o,e) local a=nil if t>0 then local t=t-1 a=o:sub(e,e+t-1) end return a,e+t end, pack= function(a,t) e(n(t)=="nil"or n(t)=="string", "unexpected value type to pack as a String") if t==nil then return m:pack(0) end return m:pack(#t+1)..t.."\000" end } local y=f{ b(4){name="signature"}, a{name="version"}, a{name="format"}, a{name="endianness"}, a{name="sizeof_int"}, a{name="sizeof_size_t"}, a{name="sizeof_insn"}, a{name="sizeof_Number"}, a{name="integral_flag"}, } local b={ [0]=q, [1]=k, [3]=j, [4]=m, } local b=t{ unpack= function(i,o,t) local t,i=a:unpack(o,t) local a=b[t] e(a,"unknown constant type "..t.." to unpack") local a,o=a:unpack(o,i) if t==3 then e(n(a)=="number") end return{ type=t, value=a },o end, pack= function(t,e) local e,t=e.type,e.value return a:pack(e)..b[e]:pack(t) end } local k=f{ m{name="name"}, i{name="startpc"}, i{name="endpc"} } local a=f{ m{name="name"}, i{name="line"}, i{name="last_line"}, a{name="num_upvalues"}, a{name="num_parameters"}, a{name="is_vararg"}, a{name="max_stack_size"}, l{name="insns",type=g}, l{name="constants",type=b}, l{name="prototypes",type=nil}, l{name="source_lines",type=i}, l{name="locals",type=k}, l{name="upvalues",type=m}, } e(a[10].name=="prototypes", "missed the function prototype list") a[10].type=a local a=t{ unpack= function(i,l,t) local i={} local t,n=y:unpack(l,t) e(t.signature=="\027Lua","signature check failed") e(t.version==81,"version mismatch") e(t.format==0,"format mismatch") e(t.endianness==0 or t.endianness==1,"endianness mismatch") e(d[t.sizeof_int],"int size unsupported") e(d[t.sizeof_size_t],"size_t size unsupported") e(t.sizeof_insn==4,"insn size unsupported") e(w[t.sizeof_Number],"number size unsupported") e(t.integral_flag==0,"integral flag mismatch; only floats supported") v() o=t.endianness==0 h=t.sizeof_size_t s=t.sizeof_int r=t.sizeof_Number i.header=t i.body,n=a:unpack(l,n) p() return i,n end, pack= function(e,t) local i v() local e=t.header o=e.endianness==0 h=e.sizeof_size_t s=e.sizeof_int r=e.sizeof_Number i=y:pack(t.header)..a:pack(t.body) p() return i end } local function o(e) if n(e)=="function"then return o(c.dump(e)) end local t=a:unpack(e,1) local a=a:pack(t) if e==a then return true end local t local t=u.min(#e,#a) for t=1,t do local a=e:sub(t,t) local e=e:sub(t,t) if a~=e then return false,("chunk roundtripping failed: ".. "first byte difference at index %d"):format(t) end end return false,("chunk round tripping failed: ".. "original length %d vs. %d"):format(#e,#a) end return{ disassemble=function(e)return a:unpack(e,1)end, assemble=function(e)return a:pack(e)end, validate=o } end) do local e={}; e["vio"]="local vio = {};\ vio.__index = vio; \ \9\ function vio.open(string)\ \9return setmetatable({ pos = 1, data = string }, vio);\ end\ \ function vio:read(format, ...)\ \9if self.pos >= #self.data then return; end\ \9if format == \"*a\" then\ \9\9local oldpos = self.pos;\ \9\9self.pos = #self.data;\ \9\9return self.data:sub(oldpos, self.pos);\ \9elseif format == \"*l\" then\ \9\9local data;\ \9\9data, self.pos = self.data:match(\"([^\\r\\n]*)\\r?\\n?()\", self.pos)\ \9\9return data;\ \9elseif format == \"*n\" then\ \9\9local data;\ \9\9data, self.pos = self.data:match(\"(%d+)()\", self.pos)\ \9\9return tonumber(data);\9\ \9elseif type(format) == \"number\" then\ \9\9local oldpos = self.pos;\ \9\9self.pos = self.pos + format;\ \9\9return self.data:sub(oldpos, self.pos-1);\ \9end\ end\ \ function vio:seek(whence, offset)\ \9if type(whence) == \"number\" then\ \9\9whence, offset = \"cur\", whence;\ \9end\ \9offset = offset or 0;\ \9\ \9if whence == \"cur\" then\ \9\9self.pos = self.pos + offset;\ \9elseif whence == \"set\" then\ \9\9self.pos = offset + 1;\ \9elseif whence == \"end\" then\ \9\9self.pos = #self.data - offset;\ \9end\ \9\ \9return self.pos;\ end\ \ local function _readline(f) return f:read(\"*l\"); end\ function vio:lines()\ \9return _readline, self;\ end\ \ function vio:write(...)\ \9for i=1,select('#', ...) do\ \9\9local dat = tostring(select(i, ...));\ \9\9self.data = self.data:sub(1, self.pos-1)..dat..self.data:sub(self.pos+#dat, -1);\ \9end\ end\ \ function vio:close()\ \9self.pos, self.data = nil, nil;\ end\ \ "e["gunzip.lua"]="local base_char,keywords=128,{\"and\",\"break\",\"do\",\"else\",\"elseif\",\"end\",\"false\",\"for\",\"function\",\"if\",\"in\",\"local\",\"nil\",\"not\",\"or\",\"repeat\",\"return\",\"then\",\"true\",\"until\",\"while\",\"read\",\"nbits\",\"nbits_left_in_byte\",\"wnd_pos\",\"output\",\"val\",\"input\",}; function prettify(code) return code:gsub(\"[\"..string.char(base_char)..\"-\"..string.char(base_char+#keywords)..\"]\", \ \9function (c) return keywords[c:byte()-base_char]; end) end return setfenv(assert(loadstring(prettify[===[ i,h,b,m,l,d,e,y,r,w,u,v,l,l=assert,error,ipairs,pairs,tostring,type,setmetatable,io,math,table.sort,math.max,string.char,io.open,_G; p(n) l={}; e=e({},l) l:__index(l) n=n(l);e[l]=n\ n\ \ e\ \ l(n,l)l=l 1\ h({n},l+1)\ _(n) l={}l.outbs=n\ l.wnd={}l.=1\ l\ \ t(l,e) n=l.\ l.outbs(e)l.wnd[n]=e\ l.=n%32768+1\ \ n(l) i(l,'unexpected end of file')\ o(n,l) n%(l+l)>=l\ \ a=p((l) 2^l ) c=e({},{__mode='k'}) g(o) l=1\ e={} e:() n\ l<=#o \ n=o:byte(l)l=l+1\ \ n\ \ e\ \ l\ s(d) n,l,o=0,0,{}; o:() l\ \ o:(e)e=e 1\ l<e \ e=d:() e \ n=n+a[l]*e\ l=l+8\ \ o=a[e] a=n%o\ n=(n-a)/o\ l=l-e\ a\ \ c[o]=\ o\ \ f(l) c[l] l s(g(l))\ s(l) n\ y.type(l)=='file'\ n=(n)l:write(v(n))\ d(l)=='function'\ n=l\ \ n\ \ d(e,o) l={} o \ e,n m(e)\ n~=0 \ l[#l+1]={=e,=n}\ \ \ n=1,#e-2,2 \ o,n,e=e[n],e[n+1],e[n+2] n~=0 \ e=o,e-1 \ l[#l+1]={=e,=n}\ \ \ \ w(l,(n,l) n.==l. n.<l. n.<l.\ ) e=1\ o=0\ n,l b(l)\ l.~=o \ e=e*a[l.-o]o=l.\ \ l.code=e\ e=e+1\ \ e=r.huge\ c={} n,l b(l)\ e=r.min(e,l.)c[l.code]=l.\ \ o(n,e) l=0\ e=1,e \ e=n%2\ n=(n-e)/2\ l=l*2+e\ \ l\ \ d=p((l) a[e]+o(l,e)) l:(a) o,l=1,0\ 1 \ l==0 \ o=d[n(a:(e))]l=l+e\ \ n=n(a:())l=l+1\ o=o*2+n\ \ l=c[o] l \ l\ \ \ \ l\ \ b(l) a=2^1\ e=2^2\ c=2^3\ d=2^4\ n=l:(8) n=l:(8) n=l:(8) n=l:(8) t=l:(32) t=l:(8) t=l:(8) o(n,e)\ n=l:(16) e=0\ n=1,n \ e=l:(8)\ \ o(n,c)\ l:(8)~=0 \ \ o(n,d)\ l:(8)~=0 \ \ o(n,a)\ l:(16)\ \ p(l) f=l:(5) i=l:(5) e=n(l:(4)) a=e+4\ e={} o={16,17,18,0,8,7,9,6,10,5,11,4,12,3,13,2,14,1,15} n=1,a \ l=l:(3) n=o[n]e[n]=l\ \ e=d(e,) r(o) t={} a\ c=0\ c<o \ o=e:(l) e\ o<=15 \ e=1\ a=o\ o==16 \ e=3+n(l:(2)) o==17 \ e=3+n(l:(3))a=0\ o==18 \ e=11+n(l:(7))a=0\ \ h'ASSERT'\ l=1,e \ t[c]=a\ c=c+1\ \ \ l=d(t,) l\ \ n=f+257\ l=i+1\ n=r(n) l=r(l) n,l\ \ a\ o\ c\ r\ h(e,n,l,d) l=l:(e) l<256 \ t(n,l) l==256 \ \ \ a \ l={[257]=3} e=1\ n=258,285,4 \ n=n,n+3 l[n]=l[n-1]+e \ n~=258 e=e*2 \ \ l[285]=258\ a=l\ \ o \ l={} e=257,285 \ n=u(e-261,0)l[e]=(n-(n%4))/4\ \ l[285]=0\ o=l\ \ a=a[l] l=o[l] l=e:(l) o=a+l\ c \ e={[0]=1} l=1\ n=1,29,2 \ n=n,n+1 e[n]=e[n-1]+l \ n~=1 l=l*2 \ \ c=e\ \ r \ n={} e=0,29 \ l=u(e-2,0)n[e]=(l-(l%2))/2\ \ r=n\ \ l=d:(e) a=c[l] l=r[l] l=e:(l) l=a+l\ e=1,o \ l=(n.-1-l)%32768+1\ t(n,i(n.wnd[l],'invalid distance'))\ \ \ \ u(l,a) i=l:(1) e=l:(2) r=0\ o=1\ c=2\ f=3\ e==r \ l:(l:()) e=l:(16) o=n(l:(16)) e=1,e \ l=n(l:(8))t(a,l)\ e==o e==c \ n,o\ e==c \ n,o=p(l)\ n=d{0,8,144,9,256,7,280,8,288,}o=d{0,5,32,}\ h(l,a,n,o);\ i~=0\ \ e(l) n,l=f(l.),_(s(l.)) u(n,l)\ (n) l=f(n.) n=s(n.)b(l)e{=l,=n}l:(l:())l:()\ ]===], '@gunzip.lua')), getfenv())()"e["squish.debug"]="package.preload['minichunkspy']=(function(...)local _ENV=_ENV;local function module(name,...)local t=package.loaded[name]or _ENV[name]or{_NAME=name};package.loaded[name]=t;for i=1,select(\"#\",...)do(select(i,...))(t);end\ _ENV=t;_M=t;return t;end\ local string,table,math=string,table,math\ local ipairs,setmetatable,type,assert=ipairs,setmetatable,type,assert\ local _=__END_OF_GLOBALS__\ local string_char,string_byte,string_sub=string.char,string.byte,string.sub\ local table_concat=table.concat\ local math_abs,math_ldexp,math_frexp=math.abs,math.ldexp,math.frexp\ local Inf=math.huge\ local Nan=Inf-Inf\ local BIG_ENDIAN=false\ local function construct(class,...)return class.new(class,...)end\ local mt_memo={}local Field=construct{new=function(class,self)local self=self or{}local mt=mt_memo[class]or{__index=class,__call=construct}mt_memo[class]=mt\ return setmetatable(self,mt)end,}local None=Field{unpack=function(self,bytes,ix)return nil,ix end,pack=function(self,val)return\"\"end}local char_memo={}local function char(n)local field=char_memo[n]or Field{unpack=function(self,bytes,ix)return string_sub(bytes,ix,ix+n-1),ix+n\ end,pack=function(self,val)return string_sub(val,1,n)end}char_memo[n]=field\ return field\ end\ local uint8=Field{unpack=function(self,bytes,ix)return string_byte(bytes,ix,ix),ix+1\ end,pack=function(self,val)return string_char(val)end}local uint32=Field{unpack=function(self,bytes,ix)local a,b,c,d=string_byte(bytes,ix,ix+3)if BIG_ENDIAN then a,b,c,d=d,c,b,a end\ return a+b*256+c*256^2+d*256^3,ix+4\ end,pack=function(self,val)assert(type(val)==\"number\",\"unexpected value type to pack as an uint32\")local a,b,c,d\ d=val%2^32\ a=d%256;d=(d-a)/256\ b=d%256;d=(d-b)/256\ c=d%256;d=(d-c)/256\ if BIG_ENDIAN then a,b,c,d=d,c,b,a end\ return string_char(a,b,c,d)end}local int32=uint32{unpack=function(self,bytes,ix)local val,ix=uint32:unpack(bytes,ix)return val<2^32 and val or(val-2^31),ix\ end}local Byte=uint8\ local Size_t=uint32\ local Integer=int32\ local Number=char(8)local Insn=char(4)local Struct=Field{unpack=function(self,bytes,ix)local val={}local i,j=1,1\ while self[i]do\ local field=self[i]local key=field.name\ if not key then key,j=j,j+1 end\ val[key],ix=field:unpack(bytes,ix)i=i+1\ end\ return val,ix\ end,pack=function(self,val)local data={}local i,j=1,1\ while self[i]do\ local field=self[i]local key=field.name\ if not key then key,j=j,j+1 end\ data[i]=field:pack(val[key])i=i+1\ end\ return table_concat(data)end}local List=Field{unpack=function(self,bytes,ix)local len,ix=Integer:unpack(bytes,ix)local vals={}local field=self.type\ for i=1,len do\ vals[i],ix=field:unpack(bytes,ix)end\ return vals,ix\ end,pack=function(self,vals)local len=#vals\ local data={Integer:pack(len)}local field=self.type\ for i=1,len do\ data[#data+1]=field:pack(vals[i])end\ return table_concat(data)end}local Boolean=Field{unpack=function(self,bytes,ix)local val,ix=Integer:unpack(bytes,ix)assert(val==0 or val==1,\"unpacked an unexpected value \"..val..\" for a Boolean\")return val==1,ix\ end,pack=function(self,val)assert(type(val)==\"boolean\",\"unexpected value type to pack as a Boolean\")return Integer:pack(val and 1 or 0)end}local String=Field{unpack=function(self,bytes,ix)local len,ix=Integer:unpack(bytes,ix)local val=nil\ if len>0 then\ local string_len=len-1\ val=bytes:sub(ix,ix+string_len-1)end\ return val,ix+len\ end,pack=function(self,val)assert(type(val)==\"nil\"or type(val)==\"string\",\"unexpected value type to pack as a String\")if val==nil then\ return Integer:pack(0)end\ return Integer:pack(#val+1)..val..\"\\0\"end}local ChunkHeader=Struct{char(4){name=\"signature\"},Byte{name=\"version\"},Byte{name=\"format\"},Byte{name=\"endianness\"},Byte{name=\"sizeof_int\"},Byte{name=\"sizeof_size_t\"},Byte{name=\"sizeof_insn\"},Byte{name=\"sizeof_Number\"},Byte{name=\"integral_flag\"},}local ConstantTypes={[0]=None,[1]=Boolean,[3]=Number,[4]=String,}local Constant=Field{unpack=function(self,bytes,ix)local t,ix=Byte:unpack(bytes,ix)local field=ConstantTypes[t]assert(field,\"unknown constant type \"..t..\" to unpack\")local v,ix=field:unpack(bytes,ix)return{type=t,value=v},ix\ end,pack=function(self,val)local t,v=val.type,val.value\ return Byte:pack(t)..ConstantTypes[t]:pack(v)end}local Local=Struct{String{name=\"name\"},Integer{name=\"startpc\"},Integer{name=\"endpc\"}}local Function=Struct{String{name=\"name\"},Integer{name=\"line\"},Integer{name=\"last_line\"},Byte{name=\"num_upvalues\"},Byte{name=\"num_parameters\"},Byte{name=\"is_vararg\"},Byte{name=\"max_stack_size\"},List{name=\"insns\",type=Insn},List{name=\"constants\",type=Constant},List{name=\"prototypes\",type=nil},List{name=\"source_lines\",type=Integer},List{name=\"locals\",type=Local},List{name=\"upvalues\",type=String},}assert(Function[10].name==\"prototypes\",\"missed the function prototype list\")Function[10].type=Function\ local Chunk=Struct{ChunkHeader{name=\"header\"},Function{name=\"body\"}}local function validate(chunk)if type(chunk)==\"function\"then\ return validate(string.dump(chunk))end\ local f=Chunk:unpack(chunk,1)local chunk2=Chunk:pack(f)if chunk==chunk2 then return true end\ local i\ local len=math.min(#chunk,#chunk2)for i=1,len do\ local a=chunk:sub(i,i)local b=chunk:sub(i,i)if a~=b then\ return false,(\"chunk roundtripping failed: \"..\"first byte difference at index %d\"):format(i)end\ end\ return false,(\"chunk round tripping failed: \"..\"original length %d vs. %d\"):format(#chunk,#chunk2)end\ return{disassemble=function(chunk)return Chunk:unpack(chunk,1)end,assemble=function(disassembled)return Chunk:pack(disassembled)end,validate=validate}end)local cs=require\"minichunkspy\"local function ___adjust_chunk(chunk,newname,lineshift)local c=cs.disassemble(string.dump(chunk));c.body.name=newname;lineshift=-c.body.line;local function shiftlines(c)c.line=c.line+lineshift;c.last_line=c.last_line+lineshift;for i,line in ipairs(c.source_lines)do\ c.source_lines[i]=line+lineshift;end\ for i,f in ipairs(c.prototypes)do\ shiftlines(f);end\ end\ shiftlines(c.body);return assert(loadstring(cs.assemble(c),newname))();end\ "function require_resource(t)return e[t]or error("resource '"..tostring(t).."' not found");end end pcall(require,"luarocks.require"); local o={v="verbose",vv="very_verbose",o="output",q="quiet",qq="very_quiet",g="debug"} local e={use_http=false,module_compat=not not _ENV}; for t,a in ipairs(arg)do if a:match("^%-")then local t=a:match("^%-%-?([^%s=]+)()") t=(o[t]or t):gsub("%-+","_"); if t:match("^no_")then t=t:sub(4,-1); e[t]=false; else e[t]=a:match("=(.*)$")or true; end else base_path=a; end end if e.very_verbose then e.verbose=true;end if e.very_quiet then e.quiet=true;end local t=function()end local t,o,s,h=t,t,t,t; if not e.very_quiet then t=print;end if not e.quiet then o=print;end if e.verbose or e.very_verbose then s=print;end if e.very_verbose then h=print;end print=s; local i,l,n={},{},{}; function Module(e) if i[e]then s("Ignoring duplicate module definition for "..e); return function()end end local t=#i+1; i[t]={name=e,url=___fetch_url}; i[e]=i[t]; return function(e) i[t].path=e; end end function Resource(t,a) local e=#n+1; n[e]={name=t,path=a or t}; return function(t) n[e].path=t; end end function AutoFetchURL(e) ___fetch_url=e; end function Main(e) table.insert(l,e); end function Output(t) if e.output==nil then out_fn=t; end end function Option(t) t=t:gsub("%-","_"); if e[t]==nil then e[t]=true; return function(a) e[t]=a; end else return function()end; end end function GetOption(t) return e[t:gsub('%-','_')]; end function Message(t) if not e.quiet then o(t); end end function Error(a) if not e.very_quiet then t(a); end end function Exit() os.exit(1); end base_path=(base_path or"."):gsub("/$","").."/" squishy_file=base_path.."squishy"; out_fn=e.output; local a,r=pcall(dofile,squishy_file); if not a then t("Couldn't read squishy file: "..r); os.exit(1); end if not out_fn then t("No output file specified by user or squishy file"); os.exit(1); elseif#l==0 and#i==0 and#n==0 then t("No files, modules or resources. Not going to generate an empty file."); os.exit(1); end local r={}; function r.filesystem(e) local e,t=io.open(e); if not e then return false,t;end local t=e:read("*a"); e:close(); return t; end if e.use_http then function r.http(t) local e=require"socket.http"; local t,e=e.request(t); if e==200 then return t; end return false,"HTTP status code: "..tostring(e); end else function r.http(e) return false,"Module not found. Re-squish with --use-http option to fetch it from "..e; end end s("Resolving modules..."); do local e=package.config:sub(1,1); local n=package.config:sub(5,5); local o=package.path:gsub("[^;]+",function(t) if not t:match("^%"..e)then return base_path..t; end end):gsub("/%./","/"); local a=package.cpath:gsub("[^;]+",function(t) if not t:match("^%"..e)then return base_path..t; end end):gsub("/%./","/"); function resolve_module(t,a) t=t:gsub("%.",e); for e in a:gmatch("[^;]+")do e=e:gsub("%"..n,t); h("Looking for "..e) local t=io.open(e); if t then h("Found!"); t:close(); return e; end end return nil; end for a,e in ipairs(i)do if not e.path then e.path=resolve_module(e.name,o); if not e.path then t("Couldn't resolve module: "..e.name); else e.path=e.path:gsub("^"..base_path:gsub("%p","%%%1"),""); end end end end for a,e in ipairs(i)do if not e.path then t("Exiting due to missing modules without a path"); os.exit(1); end end if e.list_files or e.list_missing_files then local function t(t) if e.list_missing_files then local e=io.open(t); if e then e:close(); return; end end io.write(t,"\n"); end for a,e in pairs(l)do t(e); end for a,e in ipairs(i)do t(e.path); end for a,e in ipairs(n)do t(e.path); end return; end o("Writing "..out_fn.."..."); local a,d=io.open(out_fn,"w+"); if not a then t("Couldn't open output file: "..tostring(d)); os.exit(1); end if e.executable then if e.executable==true then a:write("#!/usr/bin/env lua5.2\n"); else a:write(e.executable,"\n"); end end s("Packing modules..."); for o,i in ipairs(i)do local d,s=i.name,i.path; if i.path:sub(1,1)~="/"then s=base_path..i.path; end h("Packing "..d.." ("..s..")..."); local o,n=r.filesystem(s); if(not o)and i.url then local e=i.url:gsub("%?",i.path); h("Fetching: "..e) if e:match("^https?://")then o,n=r.http(e); elseif e:match("^file://")or e:match("^[/%.]")then local e,t=io.open((e:gsub("^file://",""))); if e then o,n=e:read("*a"); e:close(); else o,n=nil,t; end end end if o then o=o:gsub("^#[^\r\n]*\r?\n",""); if not e.debug then a:write("package.preload['",d,"'] = (function (...)\n"); if e.module_compat then a:write[[ local _ENV = _ENV; local function module(name, ...) local t = package.loaded[name] or _ENV[name] or { _NAME = name }; package.loaded[name] = t; for i = 1, select("#", ...) do (select(i, ...))(t); end _ENV = t; _M = t; return t; end ]]; end a:write(o); a:write(" end)\n"); else a:write("package.preload['",d,"'] = assert(loadstring(\n"); a:write(("%q\n"):format(o)); a:write(", ",("%q"):format("@"..s),"))\n"); end else t("Couldn't pack module '"..d.."': "..(n or"unknown error... path to module file correct?")); os.exit(1); end end if#n>0 then s("Packing resources...") a:write("do local resources = {};\n"); for o,e in ipairs(n)do local i,e=e.name,e.path; local e,o=io.open(base_path..e,"rb"); if not e then t("Couldn't load resource: "..tostring(o)); os.exit(1); end local t=e:read("*a"); local e=0; t:gsub("(=+)",function(t)e=math.max(e,#t);end); a:write(("resources[%q] = %q"):format(i,t)); end if e.virtual_io then local e=require_resource("vio"); if not e then t("Virtual IO requested but is not enabled in this build of squish"); else a:write(e,"\n") a:write[[local io_open, io_lines = io.open, io.lines; function io.open(fn, mode) if not resources[fn] then return io_open(fn, mode); else return vio.open(resources[fn]); end end function io.lines(fn) if not resources[fn] then return io_lines(fn); else return vio.open(resources[fn]):lines() end end local _dofile = dofile; function dofile(fn) if not resources[fn] then return _dofile(fn); else return assert(loadstring(resources[fn]))(); end end local _loadfile = loadfile; function loadfile(fn) if not resources[fn] then return _loadfile(fn); else return loadstring(resources[fn], "@"..fn); end end ]] end end a:write[[function require_resource(name) return resources[name] or error("resource '"..tostring(name).."' not found"); end end ]] end h("Finalising...") for e,o in pairs(l)do local e,i=io.open(base_path..o); if not e then t("Failed to open "..o..": "..i); os.exit(1); else a:write((e:read("*a"):gsub("^#.-\n",""))); e:close(); end end a:close(); o("OK!"); local h=require"optlex" local r=require"optparser" local a=require"llex" local d=require"lparser" local i={ none={}; debug={"whitespace","locals","entropy","comments","numbers"}; default={"comments","whitespace","emptylines","numbers","locals"}; basic={"comments","whitespace","emptylines"}; full={"comments","whitespace","emptylines","eols","strings","numbers","locals","entropy"}; } if e.minify_level and not i[e.minify_level]then t("Unknown minify level: "..e.minify_level); t("Available minify levels: none, basic, default, full, debug"); end for a,t in ipairs(i[e.minify_level or"default"]or{})do if e["minify_"..t]==nil then e["minify_"..t]=true; end end local n={ ["opt-locals"]=e.minify_locals; ["opt-comments"]=e.minify_comments; ["opt-entropy"]=e.minify_entropy; ["opt-whitespace"]=e.minify_whitespace; ["opt-emptylines"]=e.minify_emptylines; ["opt-eols"]=e.minify_eols; ["opt-strings"]=e.minify_strings; ["opt-numbers"]=e.minify_numbers; } local function i(e) t("minify: "..e);os.exit(1); end local function u(t) local e=io.open(t,"rb") if not e then i("cannot open \""..t.."\" for reading")end local a=e:read("*a") if not a then i("cannot read from \""..t.."\"")end e:close() return a end local function l(t,a) local e=io.open(t,"wb") if not e then i("cannot open \""..t.."\" for writing")end local a=e:write(a) if not a then i("cannot write to \""..t.."\"")end e:close() end function minify_string(e) a.init(e) a.llex() local t,e,a =a.tok,a.seminfo,a.tokln if n["opt-locals"]then r.print=print d.init(t,e,a) local a,o=d.parser() r.optimize(n,t,e,a,o) end h.print=print t,e,a =h.optimize(n,t,e,a) local e=table.concat(e) if string.find(e,"\r\n",1,1)or string.find(e,"\n\r",1,1)then h.warn.mixedeol=true end return e; end function minify_file(e,t) local e=u(e); e=minify_string(e); l(t,e); end if e.minify~=false then o("Minifying "..out_fn.."..."); minify_file(out_fn,out_fn); o("OK!"); end local h=require"llex" local i=128; local n={"and","break","do","else","elseif", "end","false","for","function","if", "in","local","nil","not","or","repeat", "return","then","true","until","while"} function uglify_file(l,o) local s,a=io.open(l); if not s then t("Can't open input file for reading: "..tostring(a)); return; end local a,r=io.open(o..".uglified","w+b"); if not a then t("Can't open output file for writing: "..tostring(r)); return; end local t=s:read("*a"); s:close(); local r,s=t:match("^(#.-\n)(.+)$"); local s=s or t; if r then a:write(r) end while i+#n<=255 and s:find("["..string.char(i).."-"..string.char(i+#n-1).."]")do i=i+1; end if i+#n>255 then a:write(s); a:close(); os.rename(o..".uglified",o); return; end local d={} for t,e in ipairs(n)do d[e]=string.char(i+t); end local r=0; t:gsub("(=+)",function(e)r=math.max(r,#e);end); h.init(s,"@"..l); h.llex() local s=h.seminfo; if e.uglify_level=="full"and i+#n<255 then local e={}; for o,a in ipairs(h.tok)do if a=="TK_NAME"or a=="TK_STRING"then local t=string.format("%q,%q",a,s[o]); if not e[t]then e[t]={type=a,value=s[o],count=0}; e[#e+1]=e[t]; end e[t].count=e[t].count+1; end end for t=1,#e do local e=e[t]; e.score=(e.count)*(#e.value-1)-#string.format("%q",e.value)-1; end table.sort(e,function(e,t)return e.score>t.score;end); local t=255-(i+#n); for t=t+1,#e do e[t]=nil; end local a=#n; for t,e in ipairs(e)do if e.score>0 then table.insert(n,e.value); d[e.value]=string.char(i+a+t); end end end a:write("local base_char,keywords=",tostring(i),",{"); for t,e in ipairs(n)do a:write(string.format("%q",e),','); end a:write[[}; function prettify(code) return code:gsub("["..string.char(base_char).."-"..string.char(base_char+#keywords).."]", function (c) return keywords[c:byte()-base_char]; end) end ]] a:write[[return setfenv(assert(loadstring(prettify]] a:write("[",string.rep("=",r+1),"["); for t,e in ipairs(h.tok)do if e=="TK_KEYWORD"or e=="TK_NAME"or e=="TK_STRING"then local e=d[s[t]]; if e then a:write(e); else a:write(s[t]); end else a:write(s[t]); end end a:write("]",string.rep("=",r+1),"]"); a:write(", '@",o,"')), getfenv())()"); a:close(); os.rename(o..".uglified",o); end if e.uglify then o("Uglifying "..out_fn.."..."); uglify_file(out_fn,out_fn); o("OK!"); end local i=require"minichunkspy" function compile_string(a,t) local a=string.dump(loadstring(a,t)); if((not e.debug)or e.compile_strip)and e.compile_strip~=false then local a=i.disassemble(a); local function t(e) e.source_lines,e.locals,e.upvalues={},{},{}; for a,e in ipairs(e.prototypes)do t(e); end end s("Stripping debug info..."); t(a.body); return i.assemble(a); end return a; end function compile_file(a,e) local o,a=io.open(a); if not o then t("Can't open input file for reading: "..tostring(a)); return; end local a,i=io.open(e..".compiled","w+"); if not a then t("Can't open output file for writing: "..tostring(i)); return; end local i=o:read("*a"); o:close(); local t,o=i:match("^(#.-\n)(.+)$"); local o=o or i; if t then a:write(t) end a:write(compile_string(o,e)); os.rename(e..".compiled",e); end if e.compile then o("Compiling "..out_fn.."..."); compile_file(out_fn,out_fn); o("OK!"); end function gzip_file(e,a) local o,e=io.open(e); if not o then t("Can't open input file for reading: "..tostring(e)); return; end local e,i=io.open(a..".gzipped","wb+"); if not e then t("Can't open output file for writing: "..tostring(i)); return; end local n=o:read("*a"); o:close(); local i,o=n:match("^(#.-\n)(.+)$"); local o=o or n; if i then e:write(i) end local i,n=io.open(a..".pregzip","wb+"); if not i then t("Can't open temp file for writing: "..tostring(n)); return; end i:write(o); i:close(); local t=io.popen("gzip -c '"..a..".pregzip'"); o=t:read("*a"); t:close(); os.remove(a..".pregzip"); local t=0; o:gsub("(=+)",function(e)t=math.max(t,#e);end); e:write("local ungz = (function ()",require_resource"gunzip.lua"," end)()\n"); e:write[[return assert(loadstring((function (i)local o={} ungz{input=i,output=function(b)table.insert(o,string.char(b))end}return table.concat(o)end) ]]; e:write((string.format("%q",o):gsub("\026","\\026"))); e:write(", '@",a,"'))()"); e:close(); os.rename(a..".gzipped",a); end if e.gzip then o("Gzipping "..out_fn.."..."); gzip_file(out_fn,out_fn); o("OK!"); end