local i={}local r=require(script.Parent.LuaX)local F=(require(script.Parent.LuaK))(i)local T=require(script.Parent.LuaP)i.LUA_QS=r.LUA_QS or"\'\037\115\'"i.SHRT_MAX=32767 i.LUAI_MAXVARS=200 i.LUAI_MAXUPVALUES=60 i.MAX_INT=r.MAX_INT or 2147483645 i.LUAI_MAXCCALLS=200 i.VARARG_HASARG=1 i.HASARG_MASK=2 i.VARARG_ISVARARG=2 i.VARARG_NEEDSARG=4 i.LUA_MULTRET=-1 function i.LUA_QL(r,i)return"\'"..(i.."\'")end function i.growvector(G,i,r,F,T,R,N,M)if F>=N then error(M)end end function i.newproto(r,i)local F={}F.k={}F.sizek=0 F.p={}F.sizep=0 F.code={}F.sizecode=0 F.sizelineinfo=0 F.sizeupvalues=0 F.nups=0 F.upvalues={}F.numparams=0 F.is_vararg=0 F.maxstacksize=0 F.lineinfo={}F.sizelocvars=0 F.locvars={}F.lineDefined=0 F.lastlinedefined=0 F.source=nil return F end function i.int2fb(r,i)local F=0 while i>=16 do i=math.floor((i+1)/2)F=F+1 end if i<8 then return i else return(F+1)*8+(i-8)end end function i.hasmultret(r,i)return i=="\086\067\065\076\076"or i=="\086\086\065\082\065\082\071"end function i.getlocvar(F,i,r)return i.f.locvars[i.actvar[r]]end function i.checklimit(R,i,r,F,T)if r>F then R:errorlimit(i,F,T)end end function i.anchor_token(r,i)if i.t.token=="\084\075\095\078\065\077\069"or i.t.token=="\084\075\095\083\084\082\073\078\071"then end end function i.error_expected(T,i,F)r:syntaxerror(i,string.format(T.LUA_QS.." \101\120\112\101\099\116\101\100",r:token2str(i,F)))end function i.errorlimit(R,i,F,T)local N=i.f.lineDefined==0 and string.format("\109\097\105\110 \102\117\110\099\116\105\111\110 \104\097\115 \109\111\114\101 \116\104\097\110 \037\100 \037\115",F,T)or string.format("\102\117\110\099\116\105\111\110 \097\116 \108\105\110\101 \037\100 \104\097\115 \109\111\114\101 \116\104\097\110 \037\100 \037\115",i.f.lineDefined,F,T)r:lexerror(i.ls,N,0)end function i.testnext(T,i,F)if i.t.token==F then r:next(i)return true else return false end end function i.check(F,i,r)if i.t.token~=r then F:error_expected(i,r)end end function i.checknext(T,i,F)T:check(i,F)r:next(i)end function i.check_condition(R,i,F,T)if not F then r:syntaxerror(i,T)end end function i.check_match(N,i,F,T,R)if not N:testnext(i,F)then if R==i.linenumber then N:error_expected(i,F)else r:syntaxerror(i,string.format(N.LUA_QS..(" \101\120\112\101\099\116\101\100 \040\116\111 \099\108\111\115\101 "..(N.LUA_QS.." \097\116 \108\105\110\101 \037\100\041")),r:token2str(i,F),r:token2str(i,T),R))end end end function i.str_checkname(F,i)F:check(i,"\084\075\095\078\065\077\069")local T=i.t.seminfo r:next(i)return T end function i.init_exp(R,i,r,T)i.f,i.t=F.NO_JUMP,F.NO_JUMP i.k=r i.info=T end function i.codestring(R,i,r,T)R:init_exp(r,"\086\075",F:stringK(i.fs,T))end function i.checkname(F,i,r)F:codestring(i,r,F:str_checkname(i))end function i.registerlocalvar(F,i,r)local T=i.fs local R=T.f F:growvector(i.L,R.locvars,T.nlocvars,R.sizelocvars,nil,F.SHRT_MAX,"\116\111\111 \109\097\110\121 \108\111\099\097\108 \118\097\114\105\097\098\108\101\115")R.locvars[T.nlocvars]={}R.locvars[T.nlocvars].varname=r local N=T.nlocvars T.nlocvars=T.nlocvars+1 return N end function i.new_localvarliteral(T,i,r,F)T:new_localvar(i,r,F)end function i.new_localvar(T,i,r,F)local R=i.fs T:checklimit(R,(R.nactvar+F)+1,T.LUAI_MAXVARS,"\108\111\099\097\108 \118\097\114\105\097\098\108\101\115")R.actvar[R.nactvar+F]=T:registerlocalvar(i,r)end function i.adjustlocalvars(F,i,r)local T=i.fs T.nactvar=T.nactvar+r for i=r,1,-1 do(F:getlocvar(T,T.nactvar-i)).startpc=T.pc end end function i.removevars(F,i,r)local T=i.fs while T.nactvar>r do T.nactvar=T.nactvar-1;(F:getlocvar(T,T.nactvar)).endpc=T.pc end end function i.indexupvalue(T,i,r,F)local R=i.f for T=0,R.nups-1,1 do if i.upvalues[T].k==F.k and i.upvalues[T].info==F.info then assert(R.upvalues[T]==r)return T end end T:checklimit(i,R.nups+1,T.LUAI_MAXUPVALUES,"\117\112\118\097\108\117\101\115")T:growvector(i.L,R.upvalues,R.nups,R.sizeupvalues,nil,T.MAX_INT,"")R.upvalues[R.nups]=r assert(F.k=="\086\076\079\067\065\076"or F.k=="\086\085\080\086\065\076")i.upvalues[R.nups]={k=F.k,info=F.info}local N=R.nups R.nups=R.nups+1 return N end function i.searchvar(F,i,r)for T=i.nactvar-1,0,-1 do if r==(F:getlocvar(i,T)).varname then return T end end return-1 end function i.markupval(F,i,r)local T=i.bl while T and T.nactvar>r do T=T.previous end if T then T.upval=true end end function i.singlevaraux(N,i,r,F,R)if i==nil then N:init_exp(F,"\086\071\076\079\066\065\076",T.NO_REG)return"\086\071\076\079\066\065\076"else local T=N:searchvar(i,r)if T>=0 then N:init_exp(F,"\086\076\079\067\065\076",T)if R==0 then N:markupval(i,T)end return"\086\076\079\067\065\076"else if N:singlevaraux(i.prev,r,F,0)=="\086\071\076\079\066\065\076"then return"\086\071\076\079\066\065\076"end F.info=N:indexupvalue(i,r,F)F.k="\086\085\080\086\065\076"return"\086\085\080\086\065\076"end end end function i.singlevar(T,i,r)local R=T:str_checkname(i)local N=i.fs if T:singlevaraux(N,R,r,1)=="\086\071\076\079\066\065\076"then r.info=F:stringK(N,R)end end function i.adjust_assign(N,i,r,T,R)local M=i.fs local G=r-T if N:hasmultret(R.k)then G=G+1 if G<=0 then G=0 end F:setreturns(M,R,G)if G>1 then F:reserveregs(M,G-1)end else if R.k~="\086\086\079\073\068"then F:exp2nextreg(M,R)end if G>0 then local i=M.freereg F:reserveregs(M,G)F:_nil(M,i,G)end end end function i.enterlevel(F,i)i.L.nCcalls=i.L.nCcalls+1 if i.L.nCcalls>F.LUAI_MAXCCALLS then r:lexerror(i,"\099\104\117\110\107 \104\097\115 \116\111\111 \109\097\110\121 \115\121\110\116\097\120 \108\101\118\101\108\115",0)end end function i.leavelevel(r,i)i.L.nCcalls=i.L.nCcalls-1 end function i.enterblock(R,i,r,T)r.breaklist=F.NO_JUMP r.isbreakable=T r.nactvar=i.nactvar r.upval=false r.previous=i.bl i.bl=r assert(i.freereg==i.nactvar)end function i.leaveblock(r,i)local T=i.bl i.bl=T.previous r:removevars(i.ls,T.nactvar)if T.upval then F:codeABC(i,"\079\080\095\067\076\079\083\069",T.nactvar,0,0)end assert(not T.isbreakable or not T.upval)assert(T.nactvar==i.nactvar)i.freereg=i.nactvar F:patchtohere(i,T.breaklist)end function i.pushclosure(N,i,r,R)local M=i.fs local G=M.f N:growvector(i.L,G.p,M.np,G.sizep,nil,T.MAXARG_Bx,"\099\111\110\115\116\097\110\116 \116\097\098\108\101 \111\118\101\114\102\108\111\119")G.p[M.np]=r.f M.np=M.np+1 N:init_exp(R,"\086\082\069\076\079\067\065\066\076\069",F:codeABx(M,"\079\080\095\067\076\079\083\085\082\069",0,M.np-1))for i=0,r.f.nups-1,1 do local T=r.upvalues[i].k=="\086\076\079\067\065\076"and"\079\080\095\077\079\086\069"or"\079\080\095\071\069\084\085\080\086\065\076"F:codeABC(M,T,0,r.upvalues[i].info,0)end end function i.open_func(T,i,r)local R=i.L local N=T:newproto(i.L)r.f=N r.prev=i.fs r.ls=i r.L=R i.fs=r r.pc=0 r.lasttarget=-1 r.jpc=F.NO_JUMP r.freereg=0 r.nk=0 r.np=0 r.nlocvars=0 r.nactvar=0 r.bl=nil N.source=i.source N.maxstacksize=2 r.h={}end function i.close_func(r,i)local T=i.L local R=i.fs local N=R.f r:removevars(i,0)F:ret(R,0,0)N.sizecode=R.pc N.sizelineinfo=R.pc N.sizek=R.nk N.sizep=R.np N.sizelocvars=R.nlocvars N.sizeupvalues=N.nups assert(R.bl==nil)i.fs=R.prev if R then r:anchor_token(i)end end function i.parser(N,i,F,T,R)local M={}M.t={}M.lookahead={}local G={}G.upvalues={}G.actvar={}i.nCcalls=0 M.buff=T r:setinput(i,M,F,R)N:open_func(M,G)G.f.is_vararg=N.VARARG_ISVARARG r:next(M)N:chunk(M)N:check(M,"\084\075\095\069\079\083")N:close_func(M)assert(G.prev==nil)assert(G.f.nups==0)assert(M.fs==nil)return G.f end function i.field(R,i,T)local N=i.fs local M={}F:exp2anyreg(N,T)r:next(i)R:checkname(i,M)F:indexed(N,T,M)end function i.yindex(R,i,T)r:next(i)R:expr(i,T)F:exp2val(i.fs,T)R:checknext(i,"\093")end function i.recfield(T,i,r)local R=i.fs local N=i.fs.freereg local M,G={},{}if i.t.token=="\084\075\095\078\065\077\069"then T:checklimit(R,r.nh,T.MAX_INT,"\105\116\101\109\115 \105\110 \097 \099\111\110\115\116\114\117\099\116\111\114")T:checkname(i,M)else T:yindex(i,M)end r.nh=r.nh+1 T:checknext(i,"\061")local f=F:exp2RK(R,M)T:expr(i,G)F:codeABC(R,"\079\080\095\083\069\084\084\065\066\076\069",r.t.info,f,F:exp2RK(R,G))R.freereg=N end function i.closelistfield(R,i,r)if r.v.k=="\086\086\079\073\068"then return end F:exp2nextreg(i,r.v)r.v.k="\086\086\079\073\068"if r.tostore==T.LFIELDS_PER_FLUSH then F:setlist(i,r.t.info,r.na,r.tostore)r.tostore=0 end end function i.lastlistfield(T,i,r)if r.tostore==0 then return end if T:hasmultret(r.v.k)then F:setmultret(i,r.v)F:setlist(i,r.t.info,r.na,T.LUA_MULTRET)r.na=r.na-1 else if r.v.k~="\086\086\079\073\068"then F:exp2nextreg(i,r.v)end F:setlist(i,r.t.info,r.na,r.tostore)end end function i.listfield(F,i,r)F:expr(i,r.v)F:checklimit(i.fs,r.na,F.MAX_INT,"\105\116\101\109\115 \105\110 \097 \099\111\110\115\116\114\117\099\116\111\114")r.na=r.na+1 r.tostore=r.tostore+1 end function i.constructor(N,i,R)local M=i.fs local G=i.linenumber local f=F:codeABC(M,"\079\080\095\078\069\087\084\065\066\076\069",0,0,0)local S={}S.v={}S.na,S.nh,S.tostore=0,0,0 S.t=R N:init_exp(R,"\086\082\069\076\079\067\065\066\076\069",f)N:init_exp(S.v,"\086\086\079\073\068",0)F:exp2nextreg(i.fs,R)N:checknext(i,"\123")repeat assert(S.v.k=="\086\086\079\073\068"or S.tostore>0)if i.t.token=="\125"then break end N:closelistfield(M,S)local F=i.t.token if F=="\084\075\095\078\065\077\069"then r:lookahead(i)if i.lookahead.token~="\061"then N:listfield(i,S)else N:recfield(i,S)end elseif F=="\091"then N:recfield(i,S)else N:listfield(i,S)end until not N:testnext(i,"\044")and not N:testnext(i,"\059")N:check_match(i,"\125","\123",G)N:lastlistfield(M,S)T:SETARG_B(M.f.code[f],N:int2fb(S.na))T:SETARG_C(M.f.code[f],N:int2fb(S.nh))end function i.parlist(T,i)local R=i.fs local N=R.f local M=0 N.is_vararg=0 if i.t.token~="\041"then repeat local F=i.t.token if F=="\084\075\095\078\065\077\069"then T:new_localvar(i,T:str_checkname(i),M)M=M+1 elseif F=="\084\075\095\068\079\084\083"then r:next(i)T:new_localvarliteral(i,"\097\114\103",M)M=M+1 N.is_vararg=T.VARARG_HASARG+T.VARARG_NEEDSARG N.is_vararg=N.is_vararg+T.VARARG_ISVARARG else r:syntaxerror(i,"\060\110\097\109\101\062 \111\114 "..(T:LUA_QL("\046\046\046").." \101\120\112\101\099\116\101\100"))end until N.is_vararg~=0 or not T:testnext(i,"\044")end T:adjustlocalvars(i,M)N.numparams=R.nactvar-N.is_vararg%T.HASARG_MASK F:reserveregs(R,R.nactvar)end function i.body(R,i,r,F,T)local N={}N.upvalues={}N.actvar={}R:open_func(i,N)N.f.lineDefined=T R:checknext(i,"\040")if F then R:new_localvarliteral(i,"\115\101\108\102",0)R:adjustlocalvars(i,1)end R:parlist(i)R:checknext(i,"\041")R:chunk(i)N.f.lastlinedefined=i.linenumber R:check_match(i,"\084\075\095\069\078\068","\084\075\095\070\085\078\067\084\073\079\078",T)R:close_func(i)R:pushclosure(i,N,r)end function i.explist1(T,i,r)local R=1 T:expr(i,r)while T:testnext(i,"\044")do F:exp2nextreg(i.fs,r)T:expr(i,r)R=R+1 end return R end function i.funcargs(R,i,T)local N=i.fs local M={}local G local f=i.linenumber local S=i.t.token if S=="\040"then if f~=i.lastline then r:syntaxerror(i,"\097\109\098\105\103\117\111\117\115 \115\121\110\116\097\120 \040\102\117\110\099\116\105\111\110 \099\097\108\108 \120 \110\101\119 \115\116\097\116\101\109\101\110\116\041")end r:next(i)if i.t.token=="\041"then M.k="\086\086\079\073\068"else R:explist1(i,M)F:setmultret(N,M)end R:check_match(i,"\041","\040",f)elseif S=="\123"then R:constructor(i,M)elseif S=="\084\075\095\083\084\082\073\078\071"then R:codestring(i,M,i.t.seminfo)r:next(i)else r:syntaxerror(i,"\102\117\110\099\116\105\111\110 \097\114\103\117\109\101\110\116\115 \101\120\112\101\099\116\101\100")return end assert(T.k=="\086\078\079\078\082\069\076\079\067")local C=T.info if R:hasmultret(M.k)then G=R.LUA_MULTRET else if M.k~="\086\086\079\073\068"then F:exp2nextreg(N,M)end G=N.freereg-(C+1)end R:init_exp(T,"\086\067\065\076\076",F:codeABC(N,"\079\080\095\067\065\076\076",C,G+1,2))F:fixline(N,f)N.freereg=C+1 end function i.prefixexp(R,i,T)local N=i.t.token if N=="\040"then local N=i.linenumber r:next(i)R:expr(i,T)R:check_match(i,"\041","\040",N)F:dischargevars(i.fs,T)elseif N=="\084\075\095\078\065\077\069"then R:singlevar(i,T)else r:syntaxerror(i,"\117\110\101\120\112\101\099\116\101\100 \115\121\109\098\111\108")end return end function i.primaryexp(R,i,T)local N=i.fs R:prefixexp(i,T)while true do local M=i.t.token if M=="\046"then R:field(i,T)elseif M=="\091"then local r={}F:exp2anyreg(N,T)R:yindex(i,r)F:indexed(N,T,r)elseif M=="\058"then local M={}r:next(i)R:checkname(i,M)F:_self(N,T,M)R:funcargs(i,T)elseif M=="\040"or M=="\084\075\095\083\084\082\073\078\071"or M=="\123"then F:exp2nextreg(N,T)R:funcargs(i,T)else return end end end function i.simpleexp(R,i,T)local N=i.t.token if N=="\084\075\095\078\085\077\066\069\082"then R:init_exp(T,"\086\075\078\085\077",0)T.nval=i.t.seminfo elseif N=="\084\075\095\083\084\082\073\078\071"then R:codestring(i,T,i.t.seminfo)elseif N=="\084\075\095\078\073\076"then R:init_exp(T,"\086\078\073\076",0)elseif N=="\084\075\095\084\082\085\069"then R:init_exp(T,"\086\084\082\085\069",0)elseif N=="\084\075\095\070\065\076\083\069"then R:init_exp(T,"\086\070\065\076\083\069",0)elseif N=="\084\075\095\068\079\084\083"then local r=i.fs R:check_condition(i,r.f.is_vararg~=0,"\099\097\110\110\111\116 \117\115\101 "..(R:LUA_QL("\046\046\046").." \111\117\116\115\105\100\101 \097 \118\097\114\097\114\103 \102\117\110\099\116\105\111\110"))local N=r.f.is_vararg if N>=R.VARARG_NEEDSARG then r.f.is_vararg=N-R.VARARG_NEEDSARG end R:init_exp(T,"\086\086\065\082\065\082\071",F:codeABC(r,"\079\080\095\086\065\082\065\082\071",0,1,0))elseif N=="\123"then R:constructor(i,T)return elseif N=="\084\075\095\070\085\078\067\084\073\079\078"then r:next(i)R:body(i,T,false,i.linenumber)return else R:primaryexp(i,T)return end r:next(i)end function i.getunopr(r,i)if i=="\084\075\095\078\079\084"then return"\079\080\082\095\078\079\084"elseif i=="-"then return"\079\080\082\095\077\073\078\085\083"elseif i=="\035"then return"\079\080\082\095\076\069\078"else return"\079\080\082\095\078\079\085\078\079\080\082"end end i.getbinopr_table={["\043"]="\079\080\082\095\065\068\068",["-"]="\079\080\082\095\083\085\066";["\042"]="\079\080\082\095\077\085\076";["\047"]="\079\080\082\095\068\073\086",["\037"]="\079\080\082\095\077\079\068",["\094"]="\079\080\082\095\080\079\087",TK_CONCAT="\079\080\082\095\067\079\078\067\065\084",TK_NE="\079\080\082\095\078\069";TK_EQ="\079\080\082\095\069\081";["\060"]="\079\080\082\095\076\084";TK_LE="\079\080\082\095\076\069",["\062"]="\079\080\082\095\071\084";TK_GE="\079\080\082\095\071\069",TK_AND="\079\080\082\095\065\078\068";TK_OR="\079\080\082\095\079\082"}function i.getbinopr(r,i)local F=r.getbinopr_table[i]if F then return F else return"\079\080\082\095\078\079\066\073\078\079\080\082"end end i.COMPOUND_OP_TRANSLATE={TK_ASSIGN_ADD="\079\080\095\065\068\068";TK_ASSIGN_SUB="\079\080\095\083\085\066";TK_ASSIGN_MUL="\079\080\095\077\085\076";TK_ASSIGN_DIV="\079\080\095\068\073\086";TK_ASSIGN_MOD="\079\080\095\077\079\068";TK_ASSIGN_POW="\079\080\095\080\079\087"}function i.getcompopr(r,i)local F=r.COMPOUND_OP_TRANSLATE[i]if F then return F else return"\079\080\095\078\079\067\079\077\079\080\082"end end i.priority={{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};{2;2};{1,1}}i.UNARY_PRIORITY=8 function i.subexpr(N,i,T,R)N:enterlevel(i)local M=N:getunopr(i.t.token)if M~="\079\080\082\095\078\079\085\078\079\080\082"then r:next(i)N:subexpr(i,T,N.UNARY_PRIORITY)F:prefix(i.fs,M,T)else N:simpleexp(i,T)end local G=N:getbinopr(i.t.token)while G~="\079\080\082\095\078\079\066\073\078\079\080\082"and N.priority[F.BinOpr[G]+1][1]>R do local R={}r:next(i)F:infix(i.fs,G,T)local M=N:subexpr(i,R,N.priority[F.BinOpr[G]+1][2])F:posfix(i.fs,G,T,R)G=M end N:leavelevel(i)return G end function i.expr(F,i,r)F:subexpr(i,r,0)end function i.block_follow(r,i)if i=="\084\075\095\069\076\083\069"or i=="\084\075\095\069\076\083\069\073\070"or i=="\084\075\095\069\078\068"or i=="\084\075\095\085\078\084\073\076"or i=="\084\075\095\069\079\083"then return true else return false end end function i.block(r,i)local T=i.fs local R={}r:enterblock(T,R,false)r:chunk(i)assert(R.breaklist==F.NO_JUMP)r:leaveblock(T)end function i.check_conflict(R,i,r,T)local N=i.fs local M=N.freereg local G=false while r do if r.v.k=="\086\073\078\068\069\088\069\068"then if r.v.info==T.info then G=true r.v.info=M end if r.v.aux==T.info then G=true r.v.aux=M end end r=r.prev end if G then F:codeABC(N,"\079\080\095\077\079\086\069",N.freereg,T.info,0)F:reserveregs(N,1)end end function i.assignment(N,i,T,R)local M={}local G=T.v.k N:check_condition(i,G=="\086\076\079\067\065\076"or G=="\086\085\080\086\065\076"or G=="\086\071\076\079\066\065\076"or G=="\086\073\078\068\069\088\069\068","\115\121\110\116\097\120 \101\114\114\111\114")if N:testnext(i,"\044")then local r={}r.v={}r.prev=T N:primaryexp(i,r.v)if r.v.k=="\086\076\079\067\065\076"then N:check_conflict(i,T,r.v)end N:checklimit(i.fs,R,N.LUAI_MAXCCALLS-i.L.nCcalls,"\118\097\114\105\097\098\108\101\115 \105\110 \097\115\115\105\103\110\109\101\110\116")N:assignment(i,r,R+1)else local G=N:getcompopr(i.t.token)if G~="\079\080\095\078\079\067\079\077\079\080\082"then r:next(i)else N:checknext(i,"\061")end local f=N:explist1(i,M)if f~=R then N:adjust_assign(i,R,f,M)if f>R then i.fs.freereg=i.fs.freereg-(f-R)end else F:setoneret(i.fs,M)if G~="\079\080\095\078\079\067\079\077\079\080\082"then F:exp2val(i.fs,T.v)F:exp2val(i.fs,M)F:codearith(i.fs,G,T.v,M)end F:storevar(i.fs,T.v,M)return end end N:init_exp(M,"\086\078\079\078\082\069\076\079\067",i.fs.freereg-1)F:storevar(i.fs,T.v,M)end function i.cond(r,i)local T={}r:expr(i,T)if T.k=="\086\078\073\076"then T.k="\086\070\065\076\083\069"end F:goiftrue(i.fs,T)return T.f end function i.breakstat(T,i)local R=i.fs local N=R.bl local M=false while N and not N.isbreakable do if N.upval then M=true end N=N.previous end if not N then r:syntaxerror(i,"\110\111 \108\111\111\112 \116\111 \098\114\101\097\107")end if M then F:codeABC(R,"\079\080\095\067\076\079\083\069",N.nactvar,0,0)end N.breaklist=F:concat(R,N.breaklist,F:jump(R))end function i.continuestat(T,i)local R=i.fs local N=R.bl local M=false while N and not N.isbreakable do if N.upval then M=true end N=N.previous end if not N then r:syntaxerror(i,"\110\111 \108\111\111\112 \116\111 \099\111\110\116\105\110\117\101")end if M then F:codeABC(R,"\079\080\095\067\076\079\083\069",N.nactvar,0,0)end F:codeAsBx(R,"\079\080\095\074\077\080",0,N.breaklist.previous)end function i.whilestat(R,i,T)local N=i.fs local M={}r:next(i)local G=F:getlabel(N)local f=R:cond(i)R:enterblock(N,M,true)R:checknext(i,"\084\075\095\068\079")R:block(i)F:patchlist(N,F:jump(N),G)R:check_match(i,"\084\075\095\069\078\068","\084\075\095\087\072\073\076\069",T)R:leaveblock(N)F:patchtohere(N,f)end function i.repeatstat(R,i,T)local N=i.fs local M=F:getlabel(N)local G,f={},{}R:enterblock(N,G,true)R:enterblock(N,f,false)r:next(i)R:chunk(i)R:check_match(i,"\084\075\095\085\078\084\073\076","\084\075\095\082\069\080\069\065\084",T)local S=R:cond(i)if not f.upval then R:leaveblock(N)F:patchlist(i.fs,S,M)else R:breakstat(i)F:patchtohere(i.fs,S)R:leaveblock(N)F:patchlist(i.fs,F:jump(N),M)end R:leaveblock(N)end function i.exp1(r,i)local T={}r:expr(i,T)local R=T.k F:exp2nextreg(i.fs,T)return R end function i.forbody(M,i,r,T,R,N)local G={}local f=i.fs M:adjustlocalvars(i,3)M:checknext(i,"\084\075\095\068\079")local S=N and F:codeAsBx(f,"\079\080\095\070\079\082\080\082\069\080",r,F.NO_JUMP)or F:jump(f)M:enterblock(f,G,false)M:adjustlocalvars(i,R)F:reserveregs(f,R)M:block(i)M:leaveblock(f)F:patchtohere(f,S)local C=N and F:codeAsBx(f,"\079\080\095\070\079\082\076\079\079\080",r,F.NO_JUMP)or F:codeABC(f,"\079\080\095\084\070\079\082\076\079\079\080",r,0,R)F:fixline(f,T)F:patchlist(f,N and C or F:jump(f),S+1)end function i.fornum(R,i,r,T)local N=i.fs local M=N.freereg R:new_localvarliteral(i,"\040\102\111\114 \105\110\100\101\120\041",0)R:new_localvarliteral(i,"\040\102\111\114 \108\105\109\105\116\041",1)R:new_localvarliteral(i,"\040\102\111\114 \115\116\101\112\041",2)R:new_localvar(i,r,3)R:checknext(i,"\061")R:exp1(i)R:checknext(i,"\044")R:exp1(i)if R:testnext(i,"\044")then R:exp1(i)else F:codeABx(N,"\079\080\095\076\079\065\068\075",N.freereg,F:numberK(N,1))F:reserveregs(N,1)end R:forbody(i,M,T,1,true)end function i.forlist(T,i,r)local R=i.fs local N={}local M=0 local G=R.freereg T:new_localvarliteral(i,"\040\102\111\114 \103\101\110\101\114\097\116\111\114\041",M)M=M+1 T:new_localvarliteral(i,"\040\102\111\114 \115\116\097\116\101\041",M)M=M+1 T:new_localvarliteral(i,"\040\102\111\114 \099\111\110\116\114\111\108\041",M)M=M+1 T:new_localvar(i,r,M)M=M+1 while T:testnext(i,"\044")do T:new_localvar(i,T:str_checkname(i),M)M=M+1 end T:checknext(i,"\084\075\095\073\078")local f=i.linenumber T:adjust_assign(i,3,T:explist1(i,N),N)F:checkstack(R,3)T:forbody(i,G,f,M-3,false)end function i.forstat(T,i,F)local R=i.fs local N={}T:enterblock(R,N,true)r:next(i)local M=T:str_checkname(i)local G=i.t.token if G=="\061"then T:fornum(i,M,F)elseif G=="\044"or G=="\084\075\095\073\078"then T:forlist(i,M)else r:syntaxerror(i,T:LUA_QL("\061")..(" \111\114 "..(T:LUA_QL("\105\110").." \101\120\112\101\099\116\101\100")))end T:check_match(i,"\084\075\095\069\078\068","\084\075\095\070\079\082",F)T:leaveblock(R)end function i.test_then_block(F,i)r:next(i)local T=F:cond(i)F:checknext(i,"\084\075\095\084\072\069\078")F:block(i)return T end function i.ifstat(R,i,T)local N=i.fs local M=F.NO_JUMP local G=R:test_then_block(i)while i.t.token=="\084\075\095\069\076\083\069\073\070"do M=F:concat(N,M,F:jump(N))F:patchtohere(N,G)G=R:test_then_block(i)end if i.t.token=="\084\075\095\069\076\083\069"then M=F:concat(N,M,F:jump(N))F:patchtohere(N,G)r:next(i)R:block(i)else M=F:concat(N,M,G)end F:patchtohere(N,M)R:check_match(i,"\084\075\095\069\078\068","\084\075\095\073\070",T)end function i.localfunc(r,i)local T,R={},{}local N=i.fs r:new_localvar(i,r:str_checkname(i),0)r:init_exp(T,"\086\076\079\067\065\076",N.freereg)F:reserveregs(N,1)r:adjustlocalvars(i,1)r:body(i,R,false,i.linenumber)F:storevar(N,T,R);(r:getlocvar(N,N.nactvar-1)).startpc=N.pc end function i.localstat(r,i)local F=0 local T local R={}repeat r:new_localvar(i,r:str_checkname(i),F)F=F+1 until not r:testnext(i,"\044")if r:testnext(i,"\061")then T=r:explist1(i,R)else R.k="\086\086\079\073\068"T=0 end r:adjust_assign(i,F,T,R)r:adjustlocalvars(i,F)end function i.funcname(F,i,r)local T=false F:singlevar(i,r)while i.t.token=="\046"do F:field(i,r)end if i.t.token=="\058"then T=true F:field(i,r)end return T end function i.funcstat(R,i,T)local N,M={},{}r:next(i)local G=R:funcname(i,N)R:body(i,M,G,T)F:storevar(i.fs,N,M)F:fixline(i.fs,T)end function i.exprstat(r,i)local R=i.fs local N={}N.v={}r:primaryexp(i,N.v)if N.v.k=="\086\067\065\076\076"then T:SETARG_C(F:getcode(R,N.v),1)else N.prev=nil r:assignment(i,N,1)end end function i.retstat(R,i)local N=i.fs local M={}local G,f r:next(i)if R:block_follow(i.t.token)or i.t.token=="\059"then G,f=0,0 else f=R:explist1(i,M)if R:hasmultret(M.k)then F:setmultret(N,M)if M.k=="\086\067\065\076\076"and f==1 then T:SET_OPCODE(F:getcode(N,M),"\079\080\095\084\065\073\076\067\065\076\076")assert(T:GETARG_A(F:getcode(N,M))==N.nactvar)end G=N.nactvar f=R.LUA_MULTRET else if f==1 then G=F:exp2anyreg(N,M)else F:exp2nextreg(N,M)G=N.nactvar assert(f==N.freereg-G)end end end F:ret(N,G,f)end function i.statement(F,i)local T=i.linenumber local R=i.t.token if R=="\084\075\095\073\070"then F:ifstat(i,T)return false elseif R=="\084\075\095\087\072\073\076\069"then F:whilestat(i,T)return false elseif R=="\084\075\095\068\079"then r:next(i)F:block(i)F:check_match(i,"\084\075\095\069\078\068","\084\075\095\068\079",T)return false elseif R=="\084\075\095\070\079\082"then F:forstat(i,T)return false elseif R=="\084\075\095\082\069\080\069\065\084"then F:repeatstat(i,T)return false elseif R=="\084\075\095\070\085\078\067\084\073\079\078"then F:funcstat(i,T)return false elseif R=="\084\075\095\076\079\067\065\076"then r:next(i)if F:testnext(i,"\084\075\095\070\085\078\067\084\073\079\078")then F:localfunc(i)else F:localstat(i)end return false elseif R=="\084\075\095\082\069\084\085\082\078"then F:retstat(i)return true elseif R=="\084\075\095\066\082\069\065\075"then r:next(i)F:breakstat(i)return true elseif R=="\084\075\095\067\079\078\084\073\078\085\069"then r:next(i)F:continuestat(i)return true else F:exprstat(i)return false end end function i.chunk(r,i)local F=false r:enterlevel(i)while not F and not r:block_follow(i.t.token)do F=r:statement(i)r:testnext(i,"\059")assert(i.fs.f.maxstacksize>=i.fs.freereg and i.fs.freereg>=i.fs.nactvar)i.fs.freereg=i.fs.nactvar end r:leavelevel(i)end return i
--# selene: allow(incorrect_standard_library_use, multiple_statements, shadowing, unused_variable, empty_if, divide_by_zero, unbalanced_assignments)
--[[--------------------------------------------------------------------

  lparser.lua
  Lua 5 parser in Lua
  This file is part of Yueliang.

  Copyright (c) 2005-2007 Kein-Hong Man <khman@users.sf.net>
  The COPYRIGHT file describes the conditions
  under which this software may be distributed.

  See the ChangeLog for more information.

----------------------------------------------------------------------]]

--[[--------------------------------------------------------------------
-- Notes:
-- * some unused C code that were not converted are kept as comments
-- * LUA_COMPAT_VARARG option changed into a comment block
-- * for value/size specific code added, look for 'NOTE: '
--
-- Not implemented:
-- * luaX_newstring not needed by this Lua implementation
-- * luaG_checkcode() in assert is not currently implemented
--
-- Added:
-- * some constants added from various header files
-- * luaY.LUA_QS used in error_expected, check_match (from luaconf.h)
-- * luaY:LUA_QL needed for error messages (from luaconf.h)
-- * luaY:growvector (from lmem.h) -- skeleton only, limit checking
-- * luaY.SHRT_MAX (from <limits.h>) for registerlocalvar
-- * luaY:newproto (from lfunc.c)
-- * luaY:int2fb (from lobject.c)
-- * NOTE: HASARG_MASK, for implementing a VARARG_HASARG bit operation
-- * NOTE: value-specific code for VARARG_NEEDSARG to replace a bitop
--
-- Changed in 5.1.x:
-- * various code changes are not detailed...
-- * names of constants may have changed, e.g. added a LUAI_ prefix
-- * struct expkind: added VKNUM, VVARARG; VCALL's info changed?
-- * struct expdesc: added nval
-- * struct FuncState: upvalues data type changed to upvaldesc
-- * macro hasmultret is new
-- * function checklimit moved to parser from lexer
-- * functions anchor_token, errorlimit, checknext are new
-- * checknext is new, equivalent to 5.0.x's check, see check too
-- * luaY:next and luaY:lookahead moved to lexer
-- * break keyword no longer skipped in luaY:breakstat
-- * function new_localvarstr replaced by new_localvarliteral
-- * registerlocalvar limits local variables to SHRT_MAX
-- * create_local deleted, new_localvarliteral used instead
-- * constant LUAI_MAXUPVALUES increased to 60
-- * constants MAXPARAMS, LUA_MAXPARSERLEVEL, MAXSTACK removed
-- * function interface changed: singlevaraux, singlevar
-- * enterlevel and leavelevel uses nCcalls to track call depth
-- * added a name argument to main entry function, luaY:parser
-- * function luaY_index changed to yindex
-- * luaY:int2fb()'s table size encoding format has been changed
-- * luaY:log2() no longer needed for table constructors
-- * function code_params deleted, functionality folded in parlist
-- * vararg flags handling (is_vararg) changes; also see VARARG_*
-- * LUA_COMPATUPSYNTAX section for old-style upvalues removed
-- * repeatstat() calls chunk() instead of block()
-- * function interface changed: cond, test_then_block
-- * while statement implementation considerably simplified; MAXEXPWHILE
--   and EXTRAEXP no longer required, no limits to the complexity of a
--   while condition
-- * repeat, forbody statement implementation has major changes,
--   mostly due to new scoping behaviour of local variables
-- * OPR_MULT renamed to OPR_MUL
----------------------------------------------------------------------]]

--requires luaP, luaX, luaK
local luaY = {}
local luaX = require(script.Parent.LuaX)
local luaK = require(script.Parent.LuaK)(luaY)
local luaP = require(script.Parent.LuaP)

--[[--------------------------------------------------------------------
-- Expression descriptor
-- * expkind changed to string constants; luaY:assignment was the only
--   function to use a relational operator with this enumeration
-- VVOID       -- no value
-- VNIL        -- no value
-- VTRUE       -- no value
-- VFALSE      -- no value
-- VK          -- info = index of constant in 'k'
-- VKNUM       -- nval = numerical value
-- VLOCAL      -- info = local register
-- VUPVAL,     -- info = index of upvalue in 'upvalues'
-- VGLOBAL     -- info = index of table; aux = index of global name in 'k'
-- VINDEXED    -- info = table register; aux = index register (or 'k')
-- VJMP        -- info = instruction pc
-- VRELOCABLE  -- info = instruction pc
-- VNONRELOC   -- info = result register
-- VCALL       -- info = instruction pc
-- VVARARG     -- info = instruction pc
} ----------------------------------------------------------------------]]

--[[--------------------------------------------------------------------
-- * expdesc in Lua 5.1.x has a union u and another struct s; this Lua
--   implementation ignores all instances of u and s usage
-- struct expdesc:
--   k  -- (enum: expkind)
--   info, aux -- (int, int)
--   nval -- (lua_Number)
--   t  -- patch list of 'exit when true'
--   f  -- patch list of 'exit when false'
----------------------------------------------------------------------]]

--[[--------------------------------------------------------------------
-- struct upvaldesc:
--   k  -- (lu_byte)
--   info -- (lu_byte)
----------------------------------------------------------------------]]

--[[--------------------------------------------------------------------
-- state needed to generate code for a given function
-- struct FuncState:
--   f  -- current function header (table: Proto)
--   h  -- table to find (and reuse) elements in 'k' (table: Table)
--   prev  -- enclosing function (table: FuncState)
--   ls  -- lexical state (table: LexState)
--   L  -- copy of the Lua state (table: lua_State)
--   bl  -- chain of current blocks (table: BlockCnt)
--   pc  -- next position to code (equivalent to 'ncode')
--   lasttarget   -- 'pc' of last 'jump target'
--   jpc  -- list of pending jumps to 'pc'
--   freereg  -- first free register
--   nk  -- number of elements in 'k'
--   np  -- number of elements in 'p'
--   nlocvars  -- number of elements in 'locvars'
--   nactvar  -- number of active local variables
--   upvalues[LUAI_MAXUPVALUES]  -- upvalues (table: upvaldesc)
--   actvar[LUAI_MAXVARS]  -- declared-variable stack
----------------------------------------------------------------------]]

------------------------------------------------------------------------
-- constants used by parser
-- * picks up duplicate values from luaX if required
------------------------------------------------------------------------

luaY.LUA_QS = luaX.LUA_QS or "'%s'"  -- (from luaconf.h)

luaY.SHRT_MAX = 32767 -- (from <limits.h>)
luaY.LUAI_MAXVARS = 200  -- (luaconf.h)
luaY.LUAI_MAXUPVALUES = 60  -- (luaconf.h)
luaY.MAX_INT = luaX.MAX_INT or 2147483645  -- (from llimits.h)
  -- * INT_MAX-2 for 32-bit systems
luaY.LUAI_MAXCCALLS = 200  -- (from luaconf.h)

luaY.VARARG_HASARG = 1  -- (from lobject.h)
-- NOTE: HASARG_MASK is value-specific
luaY.HASARG_MASK = 2 -- this was added for a bitop in parlist()
luaY.VARARG_ISVARARG = 2
-- NOTE: there is some value-specific code that involves VARARG_NEEDSARG
luaY.VARARG_NEEDSARG = 4

luaY.LUA_MULTRET = -1  -- (lua.h)

--[[--------------------------------------------------------------------
-- other functions
----------------------------------------------------------------------]]

------------------------------------------------------------------------
-- LUA_QL describes how error messages quote program elements.
-- CHANGE it if you want a different appearance. (from luaconf.h)
------------------------------------------------------------------------
function luaY:LUA_QL(x)
  return "'"..x.."'"
end

------------------------------------------------------------------------
-- this is a stripped-down luaM_growvector (from lmem.h) which is a
-- macro based on luaM_growaux (in lmem.c); all the following does is
-- reproduce the size limit checking logic of the original function
-- so that error behaviour is identical; all arguments preserved for
-- convenience, even those which are unused
-- * set the t field to nil, since this originally does a sizeof(t)
-- * size (originally a pointer) is never updated, their final values
--   are set by luaY:close_func(), so overall things should still work
------------------------------------------------------------------------
function luaY:growvector(L, v, nelems, size, t, limit, e)
  if nelems >= limit then
    error(e)  -- was luaG_runerror
  end
end

------------------------------------------------------------------------
-- initialize a new function prototype structure (from lfunc.c)
-- * used only in open_func()
------------------------------------------------------------------------
function luaY:newproto(L)
  local f = {} -- Proto
  -- luaC_link(L, obj2gco(f), LUA_TPROTO); /* GC */
  f.k = {}
  f.sizek = 0
  f.p = {}
  f.sizep = 0
  f.code = {}
  f.sizecode = 0
  f.sizelineinfo = 0
  f.sizeupvalues = 0
  f.nups = 0
  f.upvalues = {}
  f.numparams = 0
  f.is_vararg = 0
  f.maxstacksize = 0
  f.lineinfo = {}
  f.sizelocvars = 0
  f.locvars = {}
  f.lineDefined = 0
  f.lastlinedefined = 0
  f.source = nil
  return f
end

------------------------------------------------------------------------
-- converts an integer to a "floating point byte", represented as
-- (eeeeexxx), where the real value is (1xxx) * 2^(eeeee - 1) if
-- eeeee != 0 and (xxx) otherwise.
------------------------------------------------------------------------
function luaY:int2fb(x)
  local e = 0  -- exponent
  while x >= 16 do
    x = math.floor((x + 1) / 2)
    e = e + 1
  end
  if x < 8 then
    return x
  else
    return ((e + 1) * 8) + (x - 8)
  end
end

--[[--------------------------------------------------------------------
-- parser functions
----------------------------------------------------------------------]]

------------------------------------------------------------------------
-- true of the kind of expression produces multiple return values
------------------------------------------------------------------------
function luaY:hasmultret(k)
  return k == "VCALL" or k == "VVARARG"
end

------------------------------------------------------------------------
-- convenience function to access active local i, returns entry
------------------------------------------------------------------------
function luaY:getlocvar(fs, i)
  return fs.f.locvars[ fs.actvar[i] ]
end

------------------------------------------------------------------------
-- check a limit, string m provided as an error message
------------------------------------------------------------------------
function luaY:checklimit(fs, v, l, m)
  if v > l then self:errorlimit(fs, l, m) end
end

--[[--------------------------------------------------------------------
-- nodes for block list (list of active blocks)
-- struct BlockCnt:
--   previous  -- chain (table: BlockCnt)
--   breaklist  -- list of jumps out of this loop
--   nactvar  -- # active local variables outside the breakable structure
--   upval  -- true if some variable in the block is an upvalue (boolean)
--   isbreakable  -- true if 'block' is a loop (boolean)
----------------------------------------------------------------------]]

------------------------------------------------------------------------
-- prototypes for recursive non-terminal functions
------------------------------------------------------------------------
-- prototypes deleted; not required in Lua

------------------------------------------------------------------------
-- reanchor if last token is has a constant string, see close_func()
-- * used only in close_func()
------------------------------------------------------------------------
function luaY:anchor_token(ls)
  if ls.t.token == "TK_NAME" or ls.t.token == "TK_STRING" then
    -- not relevant to Lua implementation of parser
    -- local ts = ls.t.seminfo
    -- luaX_newstring(ls, getstr(ts), ts->tsv.len); /* C */
  end
end

------------------------------------------------------------------------
-- throws a syntax error if token expected is not there
------------------------------------------------------------------------
function luaY:error_expected(ls, token)
  luaX:syntaxerror(ls,
    string.format(self.LUA_QS.." expected", luaX:token2str(ls, token)))
end

------------------------------------------------------------------------
-- prepares error message for display, for limits exceeded
-- * used only in checklimit()
------------------------------------------------------------------------
function luaY:errorlimit(fs, limit, what)
  local msg = (fs.f.lineDefined == 0) and
    string.format("main function has more than %d %s", limit, what) or
    string.format("function at line %d has more than %d %s",
                  fs.f.lineDefined, limit, what)
  luaX:lexerror(fs.ls, msg, 0)
end

------------------------------------------------------------------------
-- tests for a token, returns outcome
-- * return value changed to boolean
------------------------------------------------------------------------
function luaY:testnext(ls, c)
  if ls.t.token == c then
    luaX:next(ls)
    return true
  else
    return false
  end
end

------------------------------------------------------------------------
-- check for existence of a token, throws error if not found
------------------------------------------------------------------------
function luaY:check(ls, c)
  if ls.t.token ~= c then
    self:error_expected(ls, c)
  end
end

------------------------------------------------------------------------
-- verify existence of a token, then skip it
------------------------------------------------------------------------
function luaY:checknext(ls, c)
  self:check(ls, c)
  luaX:next(ls)
end

------------------------------------------------------------------------
-- throws error if condition not matched
------------------------------------------------------------------------
function luaY:check_condition(ls, c, msg)
  if not c then luaX:syntaxerror(ls, msg) end
end

------------------------------------------------------------------------
-- verifies token conditions are met or else throw error
------------------------------------------------------------------------
function luaY:check_match(ls, what, who, where)
  if not self:testnext(ls, what) then
    if where == ls.linenumber then
      self:error_expected(ls, what)
    else
      luaX:syntaxerror(ls, string.format(
        self.LUA_QS.." expected (to close "..self.LUA_QS.." at line %d)",
        luaX:token2str(ls, what), luaX:token2str(ls, who), where))
    end
  end
end

------------------------------------------------------------------------
-- expect that token is a name, return the name
------------------------------------------------------------------------
function luaY:str_checkname(ls)
  self:check(ls, "TK_NAME")
  local ts = ls.t.seminfo
  luaX:next(ls)
  return ts
end

------------------------------------------------------------------------
-- initialize a struct expdesc, expression description data structure
------------------------------------------------------------------------
function luaY:init_exp(e, k, i)
  e.f, e.t = luaK.NO_JUMP, luaK.NO_JUMP
  e.k = k
  e.info = i
end

------------------------------------------------------------------------
-- adds given string s in string pool, sets e as VK
------------------------------------------------------------------------
function luaY:codestring(ls, e, s)
  self:init_exp(e, "VK", luaK:stringK(ls.fs, s))
end

------------------------------------------------------------------------
-- consume a name token, adds it to string pool, sets e as VK
------------------------------------------------------------------------
function luaY:checkname(ls, e)
  self:codestring(ls, e, self:str_checkname(ls))
end

------------------------------------------------------------------------
-- creates struct entry for a local variable
-- * used only in new_localvar()
------------------------------------------------------------------------
function luaY:registerlocalvar(ls, varname)
  local fs = ls.fs
  local f = fs.f
  self:growvector(ls.L, f.locvars, fs.nlocvars, f.sizelocvars,
                  nil, self.SHRT_MAX, "too many local variables")
  -- loop to initialize empty f.locvar positions not required
  f.locvars[fs.nlocvars] = {} -- LocVar
  f.locvars[fs.nlocvars].varname = varname
  -- luaC_objbarrier(ls.L, f, varname) /* GC */
  local nlocvars = fs.nlocvars
  fs.nlocvars = fs.nlocvars + 1
  return nlocvars
end

------------------------------------------------------------------------
-- creates a new local variable given a name and an offset from nactvar
-- * used in fornum(), forlist(), parlist(), body()
------------------------------------------------------------------------
function luaY:new_localvarliteral(ls, v, n)
  self:new_localvar(ls, v, n)
end

------------------------------------------------------------------------
-- register a local variable, set in active variable list
------------------------------------------------------------------------
function luaY:new_localvar(ls, name, n)
  local fs = ls.fs
  self:checklimit(fs, fs.nactvar + n + 1, self.LUAI_MAXVARS, "local variables")
  fs.actvar[fs.nactvar + n] = self:registerlocalvar(ls, name)
end

------------------------------------------------------------------------
-- adds nvars number of new local variables, set debug information
------------------------------------------------------------------------
function luaY:adjustlocalvars(ls, nvars)
  local fs = ls.fs
  fs.nactvar = fs.nactvar + nvars
  for i = nvars, 1, -1 do
    self:getlocvar(fs, fs.nactvar - i).startpc = fs.pc
  end
end

------------------------------------------------------------------------
-- removes a number of locals, set debug information
------------------------------------------------------------------------
function luaY:removevars(ls, tolevel)
  local fs = ls.fs
  while fs.nactvar > tolevel do
    fs.nactvar = fs.nactvar - 1
    self:getlocvar(fs, fs.nactvar).endpc = fs.pc
  end
end

------------------------------------------------------------------------
-- returns an existing upvalue index based on the given name, or
-- creates a new upvalue struct entry and returns the new index
-- * used only in singlevaraux()
------------------------------------------------------------------------
function luaY:indexupvalue(fs, name, v)
  local f = fs.f
  for i = 0, f.nups - 1 do
    if fs.upvalues[i].k == v.k and fs.upvalues[i].info == v.info then
      assert(f.upvalues[i] == name)
      return i
    end
  end
  -- new one
  self:checklimit(fs, f.nups + 1, self.LUAI_MAXUPVALUES, "upvalues")
  self:growvector(fs.L, f.upvalues, f.nups, f.sizeupvalues,
                  nil, self.MAX_INT, "")
  -- loop to initialize empty f.upvalues positions not required
  f.upvalues[f.nups] = name
  -- luaC_objbarrier(fs->L, f, name); /* GC */
  assert(v.k == "VLOCAL" or v.k == "VUPVAL")
  -- this is a partial copy; only k & info fields used
  fs.upvalues[f.nups] = { k = v.k, info = v.info }
  local nups = f.nups
  f.nups = f.nups + 1
  return nups
end

------------------------------------------------------------------------
-- search the local variable namespace of the given fs for a match
-- * used only in singlevaraux()
------------------------------------------------------------------------
function luaY:searchvar(fs, n)
  for i = fs.nactvar - 1, 0, -1 do
    if n == self:getlocvar(fs, i).varname then
      return i
    end
  end
  return -1  -- not found
end

------------------------------------------------------------------------
-- * mark upvalue flags in function states up to a given level
-- * used only in singlevaraux()
------------------------------------------------------------------------
function luaY:markupval(fs, level)
  local bl = fs.bl
  while bl and bl.nactvar > level do bl = bl.previous end
  if bl then bl.upval = true end
end

------------------------------------------------------------------------
-- handle locals, globals and upvalues and related processing
-- * search mechanism is recursive, calls itself to search parents
-- * used only in singlevar()
------------------------------------------------------------------------
function luaY:singlevaraux(fs, n, var, base)
  if fs == nil then  -- no more levels?
    self:init_exp(var, "VGLOBAL", luaP.NO_REG)  -- default is global variable
    return "VGLOBAL"
  else
    local v = self:searchvar(fs, n)  -- look up at current level
    if v >= 0 then
      self:init_exp(var, "VLOCAL", v)
      if base == 0 then
        self:markupval(fs, v)  -- local will be used as an upval
      end
      return "VLOCAL"
    else  -- not found at current level; try upper one
      if self:singlevaraux(fs.prev, n, var, 0) == "VGLOBAL" then
        return "VGLOBAL"
      end
      var.info = self:indexupvalue(fs, n, var)  -- else was LOCAL or UPVAL
      var.k = "VUPVAL"  -- upvalue in this level
      return "VUPVAL"
    end--if v
  end--if fs
end

------------------------------------------------------------------------
-- consume a name token, creates a variable (global|local|upvalue)
-- * used in prefixexp(), funcname()
------------------------------------------------------------------------
function luaY:singlevar(ls, var)
  local varname = self:str_checkname(ls)
  local fs = ls.fs
  if self:singlevaraux(fs, varname, var, 1) == "VGLOBAL" then
    var.info = luaK:stringK(fs, varname)  -- info points to global name
  end
end

------------------------------------------------------------------------
-- adjust RHS to match LHS in an assignment
-- * used in assignment(), forlist(), localstat()
------------------------------------------------------------------------
function luaY:adjust_assign(ls, nvars, nexps, e)
  local fs = ls.fs
  local extra = nvars - nexps
  if self:hasmultret(e.k) then
    extra = extra + 1  -- includes call itself
    if extra <= 0 then extra = 0 end
    luaK:setreturns(fs, e, extra)  -- last exp. provides the difference
    if extra > 1 then luaK:reserveregs(fs, extra - 1) end
  else
    if e.k ~= "VVOID" then luaK:exp2nextreg(fs, e) end  -- close last expression
    if extra > 0 then
      local reg = fs.freereg
      luaK:reserveregs(fs, extra)
      luaK:_nil(fs, reg, extra)
    end
  end
end

------------------------------------------------------------------------
-- tracks and limits parsing depth, assert check at end of parsing
------------------------------------------------------------------------
function luaY:enterlevel(ls)
  ls.L.nCcalls = ls.L.nCcalls + 1
  if ls.L.nCcalls > self.LUAI_MAXCCALLS then
    luaX:lexerror(ls, "chunk has too many syntax levels", 0)
  end
end

------------------------------------------------------------------------
-- tracks parsing depth, a pair with luaY:enterlevel()
------------------------------------------------------------------------
function luaY:leavelevel(ls)
  ls.L.nCcalls = ls.L.nCcalls - 1
end

------------------------------------------------------------------------
-- enters a code unit, initializes elements
------------------------------------------------------------------------
function luaY:enterblock(fs, bl, isbreakable)
  bl.breaklist = luaK.NO_JUMP
  bl.isbreakable = isbreakable
  bl.nactvar = fs.nactvar
  bl.upval = false
  bl.previous = fs.bl
  fs.bl = bl
  assert(fs.freereg == fs.nactvar)
end

------------------------------------------------------------------------
-- leaves a code unit, close any upvalues
------------------------------------------------------------------------
function luaY:leaveblock(fs)
  local bl = fs.bl
  fs.bl = bl.previous
  self:removevars(fs.ls, bl.nactvar)
  if bl.upval then
    luaK:codeABC(fs, "OP_CLOSE", bl.nactvar, 0, 0)
  end
  -- a block either controls scope or breaks (never both)
  assert(not bl.isbreakable or not bl.upval)
  assert(bl.nactvar == fs.nactvar)
  fs.freereg = fs.nactvar  -- free registers
  luaK:patchtohere(fs, bl.breaklist)
end

------------------------------------------------------------------------
-- implement the instantiation of a function prototype, append list of
-- upvalues after the instantiation instruction
-- * used only in body()
------------------------------------------------------------------------
function luaY:pushclosure(ls, func, v)
  local fs = ls.fs
  local f = fs.f
  self:growvector(ls.L, f.p, fs.np, f.sizep, nil,
                  luaP.MAXARG_Bx, "constant table overflow")
  -- loop to initialize empty f.p positions not required
  f.p[fs.np] = func.f
  fs.np = fs.np + 1
  -- luaC_objbarrier(ls->L, f, func->f); /* C */
  self:init_exp(v, "VRELOCABLE", luaK:codeABx(fs, "OP_CLOSURE", 0, fs.np - 1))
  for i = 0, func.f.nups - 1 do
    local o = (func.upvalues[i].k == "VLOCAL") and "OP_MOVE" or "OP_GETUPVAL"
    luaK:codeABC(fs, o, 0, func.upvalues[i].info, 0)
  end
end

------------------------------------------------------------------------
-- opening of a function
------------------------------------------------------------------------
function luaY:open_func(ls, fs)
  local L = ls.L
  local f = self:newproto(ls.L)
  fs.f = f
  fs.prev = ls.fs  -- linked list of funcstates
  fs.ls = ls
  fs.L = L
  ls.fs = fs
  fs.pc = 0
  fs.lasttarget = -1
  fs.jpc = luaK.NO_JUMP
  fs.freereg = 0
  fs.nk = 0
  fs.np = 0
  fs.nlocvars = 0
  fs.nactvar = 0
  fs.bl = nil
  f.source = ls.source
  f.maxstacksize = 2  -- registers 0/1 are always valid
  fs.h = {}  -- constant table; was luaH_new call
  -- anchor table of constants and prototype (to avoid being collected)
  -- sethvalue2s(L, L->top, fs->h); incr_top(L); /* C */
  -- setptvalue2s(L, L->top, f); incr_top(L);
end

------------------------------------------------------------------------
-- closing of a function
------------------------------------------------------------------------
function luaY:close_func(ls)
  local L = ls.L
  local fs = ls.fs
  local f = fs.f
  self:removevars(ls, 0)
  luaK:ret(fs, 0, 0)  -- final return
  -- luaM_reallocvector deleted for f->code, f->lineinfo, f->k, f->p,
  -- f->locvars, f->upvalues; not required for Lua table arrays
  f.sizecode = fs.pc
  f.sizelineinfo = fs.pc
  f.sizek = fs.nk
  f.sizep = fs.np
  f.sizelocvars = fs.nlocvars
  f.sizeupvalues = f.nups
  --assert(luaG_checkcode(f))  -- currently not implemented
  assert(fs.bl == nil)
  ls.fs = fs.prev
  -- the following is not required for this implementation; kept here
  -- for completeness
  -- L->top -= 2;  /* remove table and prototype from the stack */
  -- last token read was anchored in defunct function; must reanchor it
  if fs then self:anchor_token(ls) end
end

------------------------------------------------------------------------
-- parser initialization function
-- * note additional sub-tables needed for LexState, FuncState
------------------------------------------------------------------------
function luaY:parser(L, z, buff, name)
  local lexstate = {}  -- LexState
        lexstate.t = {}
        lexstate.lookahead = {}
  local funcstate = {}  -- FuncState
        funcstate.upvalues = {}
        funcstate.actvar = {}
  -- the following nCcalls initialization added for convenience
  L.nCcalls = 0
  lexstate.buff = buff
  luaX:setinput(L, lexstate, z, name)
  self:open_func(lexstate, funcstate)
  funcstate.f.is_vararg = self.VARARG_ISVARARG  -- main func. is always vararg
  luaX:next(lexstate)  -- read first token
  self:chunk(lexstate)
  self:check(lexstate, "TK_EOS")
  self:close_func(lexstate)
  assert(funcstate.prev == nil)
  assert(funcstate.f.nups == 0)
  assert(lexstate.fs == nil)
  return funcstate.f
end

--[[--------------------------------------------------------------------
-- GRAMMAR RULES
----------------------------------------------------------------------]]

------------------------------------------------------------------------
-- parse a function name suffix, for function call specifications
-- * used in primaryexp(), funcname()
------------------------------------------------------------------------
function luaY:field(ls, v)
  -- field -> ['.' | ':'] NAME
  local fs = ls.fs
  local key = {}  -- expdesc
  luaK:exp2anyreg(fs, v)
  luaX:next(ls)  -- skip the dot or colon
  self:checkname(ls, key)
  luaK:indexed(fs, v, key)
end

------------------------------------------------------------------------
-- parse a table indexing suffix, for constructors, expressions
-- * used in recfield(), primaryexp()
------------------------------------------------------------------------
function luaY:yindex(ls, v)
  -- index -> '[' expr ']'
  luaX:next(ls)  -- skip the '['
  self:expr(ls, v)
  luaK:exp2val(ls.fs, v)
  self:checknext(ls, "]")
end

--[[--------------------------------------------------------------------
-- Rules for Constructors
----------------------------------------------------------------------]]

--[[--------------------------------------------------------------------
-- struct ConsControl:
--   v  -- last list item read (table: struct expdesc)
--   t  -- table descriptor (table: struct expdesc)
--   nh  -- total number of 'record' elements
--   na  -- total number of array elements
--   tostore  -- number of array elements pending to be stored
----------------------------------------------------------------------]]

------------------------------------------------------------------------
-- parse a table record (hash) field
-- * used in constructor()
------------------------------------------------------------------------
function luaY:recfield(ls, cc)
  -- recfield -> (NAME | '['exp1']') = exp1
  local fs = ls.fs
  local reg = ls.fs.freereg
  local key, val = {}, {}  -- expdesc
  if ls.t.token == "TK_NAME" then
    self:checklimit(fs, cc.nh, self.MAX_INT, "items in a constructor")
    self:checkname(ls, key)
  else  -- ls->t.token == '['
    self:yindex(ls, key)
  end
  cc.nh = cc.nh + 1
  self:checknext(ls, "=")
  local rkkey = luaK:exp2RK(fs, key)
  self:expr(ls, val)
  luaK:codeABC(fs, "OP_SETTABLE", cc.t.info, rkkey, luaK:exp2RK(fs, val))
  fs.freereg = reg  -- free registers
end

------------------------------------------------------------------------
-- emit a set list instruction if enough elements (LFIELDS_PER_FLUSH)
-- * used in constructor()
------------------------------------------------------------------------
function luaY:closelistfield(fs, cc)
  if cc.v.k == "VVOID" then return end  -- there is no list item
  luaK:exp2nextreg(fs, cc.v)
  cc.v.k = "VVOID"
  if cc.tostore == luaP.LFIELDS_PER_FLUSH then
    luaK:setlist(fs, cc.t.info, cc.na, cc.tostore)  -- flush
    cc.tostore = 0  -- no more items pending
  end
end

------------------------------------------------------------------------
-- emit a set list instruction at the end of parsing list constructor
-- * used in constructor()
------------------------------------------------------------------------
function luaY:lastlistfield(fs, cc)
  if cc.tostore == 0 then return end
  if self:hasmultret(cc.v.k) then
    luaK:setmultret(fs, cc.v)
    luaK:setlist(fs, cc.t.info, cc.na, self.LUA_MULTRET)
    cc.na = cc.na - 1  -- do not count last expression (unknown number of elements)
  else
    if cc.v.k ~= "VVOID" then
      luaK:exp2nextreg(fs, cc.v)
    end
    luaK:setlist(fs, cc.t.info, cc.na, cc.tostore)
  end
end

------------------------------------------------------------------------
-- parse a table list (array) field
-- * used in constructor()
------------------------------------------------------------------------
function luaY:listfield(ls, cc)
  self:expr(ls, cc.v)
  self:checklimit(ls.fs, cc.na, self.MAX_INT, "items in a constructor")
  cc.na = cc.na + 1
  cc.tostore = cc.tostore + 1
end

------------------------------------------------------------------------
-- parse a table constructor
-- * used in funcargs(), simpleexp()
------------------------------------------------------------------------
function luaY:constructor(ls, t)
  -- constructor -> '{' [ field { fieldsep field } [ fieldsep ] ] '}'
  -- field -> recfield | listfield
  -- fieldsep -> ',' | ';'
  local fs = ls.fs
  local line = ls.linenumber
  local pc = luaK:codeABC(fs, "OP_NEWTABLE", 0, 0, 0)
  local cc = {}  -- ConsControl
        cc.v = {}
  cc.na, cc.nh, cc.tostore = 0, 0, 0
  cc.t = t
  self:init_exp(t, "VRELOCABLE", pc)
  self:init_exp(cc.v, "VVOID", 0)  -- no value (yet)
  luaK:exp2nextreg(ls.fs, t)  -- fix it at stack top (for gc)
  self:checknext(ls, "{")
  repeat
    assert(cc.v.k == "VVOID" or cc.tostore > 0)
    if ls.t.token == "}" then break end
    self:closelistfield(fs, cc)
    local c = ls.t.token

    if c == "TK_NAME" then  -- may be listfields or recfields
      luaX:lookahead(ls)
      if ls.lookahead.token ~= "=" then  -- expression?
        self:listfield(ls, cc)
      else
        self:recfield(ls, cc)
      end
    elseif c == "[" then  -- constructor_item -> recfield
      self:recfield(ls, cc)
    else  -- constructor_part -> listfield
      self:listfield(ls, cc)
    end
  until not self:testnext(ls, ",") and not self:testnext(ls, ";")
  self:check_match(ls, "}", "{", line)
  self:lastlistfield(fs, cc)
  luaP:SETARG_B(fs.f.code[pc], self:int2fb(cc.na)) -- set initial array size
  luaP:SETARG_C(fs.f.code[pc], self:int2fb(cc.nh)) -- set initial table size
end

-- }======================================================================

------------------------------------------------------------------------
-- parse the arguments (parameters) of a function declaration
-- * used in body()
------------------------------------------------------------------------
function luaY:parlist(ls)
  -- parlist -> [ param { ',' param } ]
  local fs = ls.fs
  local f = fs.f
  local nparams = 0
  f.is_vararg = 0
  if ls.t.token ~= ")" then  -- is 'parlist' not empty?
    repeat
      local c = ls.t.token
      if c == "TK_NAME" then  -- param -> NAME
        self:new_localvar(ls, self:str_checkname(ls), nparams)
        nparams = nparams + 1
      elseif c == "TK_DOTS" then  -- param -> `...'
        luaX:next(ls)
-- [[
-- #if defined(LUA_COMPAT_VARARG)
        -- use `arg' as default name
        self:new_localvarliteral(ls, "arg", nparams)
        nparams = nparams + 1
        f.is_vararg = self.VARARG_HASARG + self.VARARG_NEEDSARG
-- #endif
--]]
        f.is_vararg = f.is_vararg + self.VARARG_ISVARARG
      else
        luaX:syntaxerror(ls, "<name> or "..self:LUA_QL("...").." expected")
      end
    until f.is_vararg ~= 0 or not self:testnext(ls, ",")
  end--if
  self:adjustlocalvars(ls, nparams)
  -- NOTE: the following works only when HASARG_MASK is 2!
  f.numparams = fs.nactvar - (f.is_vararg % self.HASARG_MASK)
  luaK:reserveregs(fs, fs.nactvar)  -- reserve register for parameters
end

------------------------------------------------------------------------
-- parse function declaration body
-- * used in simpleexp(), localfunc(), funcstat()
------------------------------------------------------------------------
function luaY:body(ls, e, needself, line)
  -- body ->  '(' parlist ')' chunk END
  local new_fs = {}  -- FuncState
        new_fs.upvalues = {}
        new_fs.actvar = {}
  self:open_func(ls, new_fs)
  new_fs.f.lineDefined = line
  self:checknext(ls, "(")
  if needself then
    self:new_localvarliteral(ls, "self", 0)
    self:adjustlocalvars(ls, 1)
  end
  self:parlist(ls)
  self:checknext(ls, ")")
  self:chunk(ls)
  new_fs.f.lastlinedefined = ls.linenumber
  self:check_match(ls, "TK_END", "TK_FUNCTION", line)
  self:close_func(ls)
  self:pushclosure(ls, new_fs, e)
end

------------------------------------------------------------------------
-- parse a list of comma-separated expressions
-- * used is multiple locations
------------------------------------------------------------------------
function luaY:explist1(ls, v)
  -- explist1 -> expr { ',' expr }
  local n = 1  -- at least one expression
  self:expr(ls, v)
  while self:testnext(ls, ",") do
    luaK:exp2nextreg(ls.fs, v)
    self:expr(ls, v)
    n = n + 1
  end
  return n
end

------------------------------------------------------------------------
-- parse the parameters of a function call
-- * contrast with parlist(), used in function declarations
-- * used in primaryexp()
------------------------------------------------------------------------
function luaY:funcargs(ls, f)
  local fs = ls.fs
  local args = {}  -- expdesc
  local nparams
  local line = ls.linenumber
  local c = ls.t.token
  if c == "(" then  -- funcargs -> '(' [ explist1 ] ')'
    if line ~= ls.lastline then
      luaX:syntaxerror(ls, "ambiguous syntax (function call x new statement)")
    end
    luaX:next(ls)
    if ls.t.token == ")" then  -- arg list is empty?
      args.k = "VVOID"
    else
      self:explist1(ls, args)
      luaK:setmultret(fs, args)
    end
    self:check_match(ls, ")", "(", line)
  elseif c == "{" then  -- funcargs -> constructor
    self:constructor(ls, args)
  elseif c == "TK_STRING" then  -- funcargs -> STRING
    self:codestring(ls, args, ls.t.seminfo)
    luaX:next(ls)  -- must use 'seminfo' before 'next'
  else
    luaX:syntaxerror(ls, "function arguments expected")
    return
  end
  assert(f.k == "VNONRELOC")
  local base = f.info  -- base register for call
  if self:hasmultret(args.k) then
    nparams = self.LUA_MULTRET  -- open call
  else
    if args.k ~= "VVOID" then
      luaK:exp2nextreg(fs, args)  -- close last argument
    end
    nparams = fs.freereg - (base + 1)
  end
  self:init_exp(f, "VCALL", luaK:codeABC(fs, "OP_CALL", base, nparams + 1, 2))
  luaK:fixline(fs, line)
  fs.freereg = base + 1  -- call remove function and arguments and leaves
                         -- (unless changed) one result
end

--[[--------------------------------------------------------------------
-- Expression parsing
----------------------------------------------------------------------]]

------------------------------------------------------------------------
-- parses an expression in parentheses or a single variable
-- * used in primaryexp()
------------------------------------------------------------------------
function luaY:prefixexp(ls, v)
  -- prefixexp -> NAME | '(' expr ')'
  local c = ls.t.token
  if c == "(" then
    local line = ls.linenumber
    luaX:next(ls)
    self:expr(ls, v)
    self:check_match(ls, ")", "(", line)
    luaK:dischargevars(ls.fs, v)
  elseif c == "TK_NAME" then
    self:singlevar(ls, v)
  else
    luaX:syntaxerror(ls, "unexpected symbol")
  end--if c
  return
end

------------------------------------------------------------------------
-- parses a prefixexp (an expression in parentheses or a single variable)
-- or a function call specification
-- * used in simpleexp(), assignment(), exprstat()
------------------------------------------------------------------------
function luaY:primaryexp(ls, v)
  -- primaryexp ->
  --    prefixexp { '.' NAME | '[' exp ']' | ':' NAME funcargs | funcargs }
  local fs = ls.fs
  self:prefixexp(ls, v)
  while true do
    local c = ls.t.token
    if c == "." then  -- field
      self:field(ls, v)
    elseif c == "[" then  -- '[' exp1 ']'
      local key = {}  -- expdesc
      luaK:exp2anyreg(fs, v)
      self:yindex(ls, key)
      luaK:indexed(fs, v, key)
    elseif c == ":" then  -- ':' NAME funcargs
      local key = {}  -- expdesc
      luaX:next(ls)
      self:checkname(ls, key)
      luaK:_self(fs, v, key)
      self:funcargs(ls, v)
    elseif c == "(" or c == "TK_STRING" or c == "{" then  -- funcargs
      luaK:exp2nextreg(fs, v)
      self:funcargs(ls, v)
    else
      return
    end--if c
  end--while
end

------------------------------------------------------------------------
-- parses general expression types, constants handled here
-- * used in subexpr()
------------------------------------------------------------------------
function luaY:simpleexp(ls, v)
  -- simpleexp -> NUMBER | STRING | NIL | TRUE | FALSE | ... |
  --              constructor | FUNCTION body | primaryexp
  local c = ls.t.token
  if c == "TK_NUMBER" then
    self:init_exp(v, "VKNUM", 0)
    v.nval = ls.t.seminfo
  elseif c == "TK_STRING" then
    self:codestring(ls, v, ls.t.seminfo)
  elseif c == "TK_NIL" then
    self:init_exp(v, "VNIL", 0)
  elseif c == "TK_TRUE" then
    self:init_exp(v, "VTRUE", 0)
  elseif c == "TK_FALSE" then
    self:init_exp(v, "VFALSE", 0)
  elseif c == "TK_DOTS" then  -- vararg
    local fs = ls.fs
    self:check_condition(ls, fs.f.is_vararg ~= 0,
                    "cannot use "..self:LUA_QL("...").." outside a vararg function");
    -- NOTE: the following substitutes for a bitop, but is value-specific
    local is_vararg = fs.f.is_vararg
    if is_vararg >= self.VARARG_NEEDSARG then
      fs.f.is_vararg = is_vararg - self.VARARG_NEEDSARG  -- don't need 'arg'
    end
    self:init_exp(v, "VVARARG", luaK:codeABC(fs, "OP_VARARG", 0, 1, 0))
  elseif c == "{" then  -- constructor
    self:constructor(ls, v)
    return
  elseif c == "TK_FUNCTION" then
    luaX:next(ls)
    self:body(ls, v, false, ls.linenumber)
    return
  else
    self:primaryexp(ls, v)
    return
  end--if c
  luaX:next(ls)
end

------------------------------------------------------------------------
-- Translates unary operators tokens if found, otherwise returns
-- OPR_NOUNOPR. getunopr() and getbinopr() are used in subexpr().
-- * used in subexpr()
------------------------------------------------------------------------
function luaY:getunopr(op)
  if op == "TK_NOT" then
    return "OPR_NOT"
  elseif op == "-" then
    return "OPR_MINUS"
  elseif op == "#" then
    return "OPR_LEN"
  else
    return "OPR_NOUNOPR"
  end
end

------------------------------------------------------------------------
-- Translates binary operator tokens if found, otherwise returns
-- OPR_NOBINOPR. Code generation uses OPR_* style tokens.
-- * used in subexpr()
------------------------------------------------------------------------
luaY.getbinopr_table = {
  ["+"] = "OPR_ADD",
  ["-"] = "OPR_SUB",
  ["*"] = "OPR_MUL",
  ["/"] = "OPR_DIV",
  ["%"] = "OPR_MOD",
  ["^"] = "OPR_POW",
  ["TK_CONCAT"] = "OPR_CONCAT",
  ["TK_NE"] = "OPR_NE",
  ["TK_EQ"] = "OPR_EQ",
  ["<"] = "OPR_LT",
  ["TK_LE"] = "OPR_LE",
  [">"] = "OPR_GT",
  ["TK_GE"] = "OPR_GE",
  ["TK_AND"] = "OPR_AND",
  ["TK_OR"] = "OPR_OR",
}
function luaY:getbinopr(op)
  local opr = self.getbinopr_table[op]
  if opr then return opr else return "OPR_NOBINOPR" end
end

------------------------------------------------------------------------
-- // Luau compound operator translation
-- Also the concat operator is an odd one out, concatting uses a different type of operation
-- because concatting concats a range of operators, I guess its an optimisation or something
-- ccuser44 added this array, but never actually implemented it (?), so moo1210 did. 
------------------------------------------------------------------------
luaY.COMPOUND_OP_TRANSLATE = {
	TK_ASSIGN_ADD = "OP_ADD",
	TK_ASSIGN_SUB = "OP_SUB",
	TK_ASSIGN_MUL = "OP_MUL",
	TK_ASSIGN_DIV = "OP_DIV",
	TK_ASSIGN_MOD = "OP_MOD",
	TK_ASSIGN_POW = "OP_POW",
}
function luaY:getcompopr(op)
  local opr = self.COMPOUND_OP_TRANSLATE[op]
  if opr then return opr else return "OP_NOCOMOPR" end
end


------------------------------------------------------------------------
-- the following priority table consists of pairs of left/right values
-- for binary operators (was a static const struct); grep for ORDER OPR
-- * the following struct is replaced:
--   static const struct {
--     lu_byte left;  /* left priority for each binary operator */
--     lu_byte right; /* right priority */
--   } priority[] = {  /* ORDER OPR */
------------------------------------------------------------------------
luaY.priority = {
  {6, 6}, {6, 6}, {7, 7}, {7, 7}, {7, 7}, -- `+' `-' `/' `%'
  {10, 9}, {5, 4},                 -- power and concat (right associative)
  {3, 3}, {3, 3},                  -- equality
  {3, 3}, {3, 3}, {3, 3}, {3, 3},  -- order
  {2, 2}, {1, 1}                   -- logical (and/or)
}

luaY.UNARY_PRIORITY = 8  -- priority for unary operators

------------------------------------------------------------------------
-- Parse subexpressions. Includes handling of unary operators and binary
-- operators. A subexpr is given the rhs priority level of the operator
-- immediately left of it, if any (limit is -1 if none,) and if a binop
-- is found, limit is compared with the lhs priority level of the binop
-- in order to determine which executes first.
------------------------------------------------------------------------

------------------------------------------------------------------------
-- subexpr -> (simpleexp | unop subexpr) { binop subexpr }
-- where 'binop' is any binary operator with a priority higher than 'limit'
-- * for priority lookups with self.priority[], 1=left and 2=right
-- * recursively called
-- * used in expr()
------------------------------------------------------------------------
function luaY:subexpr(ls, v, limit)
  self:enterlevel(ls)
  local uop = self:getunopr(ls.t.token)
  if uop ~= "OPR_NOUNOPR" then
    luaX:next(ls)
    self:subexpr(ls, v, self.UNARY_PRIORITY)
    luaK:prefix(ls.fs, uop, v)
  else
    self:simpleexp(ls, v)
  end
  -- expand while operators have priorities higher than 'limit'
  local op = self:getbinopr(ls.t.token)
  while op ~= "OPR_NOBINOPR" and self.priority[luaK.BinOpr[op] + 1][1] > limit do
    local v2 = {}  -- expdesc
    luaX:next(ls)
    luaK:infix(ls.fs, op, v)
    -- read sub-expression with higher priority
    local nextop = self:subexpr(ls, v2, self.priority[luaK.BinOpr[op] + 1][2])
    luaK:posfix(ls.fs, op, v, v2)
    op = nextop
  end
  self:leavelevel(ls)
  return op  -- return first untreated operator
end

------------------------------------------------------------------------
-- Expression parsing starts here. Function subexpr is entered with the
-- left operator (which is non-existent) priority of -1, which is lower
-- than all actual operators. Expr information is returned in parm v.
-- * used in multiple locations
------------------------------------------------------------------------
function luaY:expr(ls, v)
  self:subexpr(ls, v, 0)
end

-- }====================================================================

--[[--------------------------------------------------------------------
-- Rules for Statements
----------------------------------------------------------------------]]

------------------------------------------------------------------------
-- checks next token, used as a look-ahead
-- * returns boolean instead of 0|1
-- * used in retstat(), chunk()
------------------------------------------------------------------------
function luaY:block_follow(token)
  if token == "TK_ELSE" or token == "TK_ELSEIF" or token == "TK_END"
     or token == "TK_UNTIL" or token == "TK_EOS" then
    return true
  else
    return false
  end
end

------------------------------------------------------------------------
-- parse a code block or unit
-- * used in multiple functions
------------------------------------------------------------------------
function luaY:block(ls)
  -- block -> chunk
  local fs = ls.fs
  local bl = {}  -- BlockCnt
  self:enterblock(fs, bl, false)
  self:chunk(ls)
  assert(bl.breaklist == luaK.NO_JUMP)
  self:leaveblock(fs)
end

------------------------------------------------------------------------
-- structure to chain all variables in the left-hand side of an
-- assignment
-- struct LHS_assign:
--   prev  -- (table: struct LHS_assign)
--   v  -- variable (global, local, upvalue, or indexed) (table: expdesc)
------------------------------------------------------------------------

------------------------------------------------------------------------
-- check whether, in an assignment to a local variable, the local variable
-- is needed in a previous assignment (to a table). If so, save original
-- local value in a safe place and use this safe copy in the previous
-- assignment.
-- * used in assignment()
------------------------------------------------------------------------
function luaY:check_conflict(ls, lh, v)
  local fs = ls.fs
  local extra = fs.freereg  -- eventual position to save local variable
  local conflict = false
  while lh do
    if lh.v.k == "VINDEXED" then
      if lh.v.info == v.info then  -- conflict?
        conflict = true
        lh.v.info = extra  -- previous assignment will use safe copy
      end
      if lh.v.aux == v.info then  -- conflict?
        conflict = true
        lh.v.aux = extra  -- previous assignment will use safe copy
      end
    end
    lh = lh.prev
  end
  if conflict then
    luaK:codeABC(fs, "OP_MOVE", fs.freereg, v.info, 0)  -- make copy
    luaK:reserveregs(fs, 1)
  end
end

------------------------------------------------------------------------
-- parse a variable assignment sequence
-- * recursively called
-- * used in exprstat()
------------------------------------------------------------------------
function luaY:assignment(ls, lh, nvars)
  local e = {}  -- expdesc
  -- test was: VLOCAL <= lh->v.k && lh->v.k <= VINDEXED
  local c = lh.v.k
  self:check_condition(ls, c == "VLOCAL" or c == "VUPVAL" or c == "VGLOBAL"
                       or c == "VINDEXED", "syntax error")
  if self:testnext(ls, ",") then  -- assignment -> ',' primaryexp assignment
    local nv = {}  -- LHS_assign
          nv.v = {}
    nv.prev = lh
    self:primaryexp(ls, nv.v)
    if nv.v.k == "VLOCAL" then
      self:check_conflict(ls, lh, nv.v)
    end
    self:checklimit(ls.fs, nvars, self.LUAI_MAXCCALLS - ls.L.nCcalls,
                    "variables in assignment")
    self:assignment(ls, nv, nvars + 1)
  else  -- assignment -> '=' explist1
    local compOpr = self:getcompopr(ls.t.token)
    if compOpr ~= "OP_NOCOMOPR" then
      luaX:next(ls)
    else
      self:checknext(ls, "=")
    end
    local nexps = self:explist1(ls, e)
    if nexps ~= nvars then
      self:adjust_assign(ls, nvars, nexps, e)
      if nexps > nvars then
        ls.fs.freereg = ls.fs.freereg - (nexps - nvars)  -- remove extra values
      end
    else
      luaK:setoneret(ls.fs, e)  -- close last expression
      if compOpr ~= "OP_NOCOMOPR" then
        luaK:exp2val(ls.fs, lh.v)
        luaK:exp2val(ls.fs, e)
        luaK:codearith(ls.fs, compOpr, lh.v, e)
      end
      luaK:storevar(ls.fs, lh.v, e)
      return  -- avoid default
    end
  end
  self:init_exp(e, "VNONRELOC", ls.fs.freereg - 1)  -- default assignment
  luaK:storevar(ls.fs, lh.v, e)
end

------------------------------------------------------------------------
-- parse condition in a repeat statement or an if control structure
-- * used in repeatstat(), test_then_block()
------------------------------------------------------------------------
function luaY:cond(ls)
  -- cond -> exp
  local v = {}  -- expdesc
  self:expr(ls, v)  -- read condition
  if v.k == "VNIL" then v.k = "VFALSE" end  -- 'falses' are all equal here
  luaK:goiftrue(ls.fs, v)
  return v.f
end

------------------------------------------------------------------------
-- parse a break statement
-- * used in statements()
------------------------------------------------------------------------
function luaY:breakstat(ls)
  -- stat -> BREAK
  local fs = ls.fs
  local bl = fs.bl
  local upval = false
  while bl and not bl.isbreakable do
    if bl.upval then upval = true end
    bl = bl.previous
  end
  if not bl then
    luaX:syntaxerror(ls, "no loop to break")
  end
  if upval then
    luaK:codeABC(fs, "OP_CLOSE", bl.nactvar, 0, 0)
  end
  bl.breaklist = luaK:concat(fs, bl.breaklist, luaK:jump(fs))
end

------------------------------------------------------------------------
-- parse a continue statement
-- * used in statements()
------------------------------------------------------------------------
function luaY:continuestat(ls)
	-- stat -> CONTINUE
	local fs = ls.fs
	local bl = fs.bl
	local upval = false
	while bl and not bl.isbreakable do
		if bl.upval then upval = true end
		bl = bl.previous
	end
	if not bl then
		luaX:syntaxerror(ls, "no loop to continue")
	end
	if upval then
		luaK:codeABC(fs, "OP_CLOSE", bl.nactvar, 0, 0)
	end
	luaK:codeAsBx(fs, "OP_JMP", 0, bl.breaklist.previous) -- This is correct from what I can tell from compiling Luau bytecode and testing it
end

------------------------------------------------------------------------
-- parse a while-do control structure, body processed by block()
-- * with dynamic array sizes, MAXEXPWHILE + EXTRAEXP limits imposed by
--   the function's implementation can be removed
-- * used in statements()
------------------------------------------------------------------------
function luaY:whilestat(ls, line)
  -- whilestat -> WHILE cond DO block END
  local fs = ls.fs
  local bl = {}  -- BlockCnt
  luaX:next(ls)  -- skip WHILE
  local whileinit = luaK:getlabel(fs)
  local condexit = self:cond(ls)
  self:enterblock(fs, bl, true)
  self:checknext(ls, "TK_DO")
  self:block(ls)
  luaK:patchlist(fs, luaK:jump(fs), whileinit)
  self:check_match(ls, "TK_END", "TK_WHILE", line)
  self:leaveblock(fs)
  luaK:patchtohere(fs, condexit)  -- false conditions finish the loop
end

------------------------------------------------------------------------
-- parse a repeat-until control structure, body parsed by chunk()
-- * used in statements()
------------------------------------------------------------------------
function luaY:repeatstat(ls, line)
  -- repeatstat -> REPEAT block UNTIL cond
  local fs = ls.fs
  local repeat_init = luaK:getlabel(fs)
  local bl1, bl2 = {}, {}  -- BlockCnt
  self:enterblock(fs, bl1, true)  -- loop block
  self:enterblock(fs, bl2, false)  -- scope block
  luaX:next(ls)  -- skip REPEAT
  self:chunk(ls)
  self:check_match(ls, "TK_UNTIL", "TK_REPEAT", line)
  local condexit = self:cond(ls)  -- read condition (inside scope block)
  if not bl2.upval then  -- no upvalues?
    self:leaveblock(fs)  -- finish scope
    luaK:patchlist(ls.fs, condexit, repeat_init)  -- close the loop
  else  -- complete semantics when there are upvalues
    self:breakstat(ls)  -- if condition then break
    luaK:patchtohere(ls.fs, condexit)  -- else...
    self:leaveblock(fs)  -- finish scope...
    luaK:patchlist(ls.fs, luaK:jump(fs), repeat_init)  -- and repeat
  end
  self:leaveblock(fs)  -- finish loop
end

------------------------------------------------------------------------
-- parse the single expressions needed in numerical for loops
-- * used in fornum()
------------------------------------------------------------------------
function luaY:exp1(ls)
  local e = {}  -- expdesc
  self:expr(ls, e)
  local k = e.k
  luaK:exp2nextreg(ls.fs, e)
  return k
end

------------------------------------------------------------------------
-- parse a for loop body for both versions of the for loop
-- * used in fornum(), forlist()
------------------------------------------------------------------------
function luaY:forbody(ls, base, line, nvars, isnum)
  -- forbody -> DO block
  local bl = {}  -- BlockCnt
  local fs = ls.fs
  self:adjustlocalvars(ls, 3)  -- control variables
  self:checknext(ls, "TK_DO")
  local prep = isnum and luaK:codeAsBx(fs, "OP_FORPREP", base, luaK.NO_JUMP)
                     or luaK:jump(fs)
  self:enterblock(fs, bl, false)  -- scope for declared variables
  self:adjustlocalvars(ls, nvars)
  luaK:reserveregs(fs, nvars)
  self:block(ls)
  self:leaveblock(fs)  -- end of scope for declared variables
  luaK:patchtohere(fs, prep)
  local endfor = isnum and luaK:codeAsBx(fs, "OP_FORLOOP", base, luaK.NO_JUMP)
                       or luaK:codeABC(fs, "OP_TFORLOOP", base, 0, nvars)
  luaK:fixline(fs, line)  -- pretend that `OP_FOR' starts the loop
  luaK:patchlist(fs, isnum and endfor or luaK:jump(fs), prep + 1)
end

------------------------------------------------------------------------
-- parse a numerical for loop, calls forbody()
-- * used in forstat()
------------------------------------------------------------------------
function luaY:fornum(ls, varname, line)
  -- fornum -> NAME = exp1,exp1[,exp1] forbody
  local fs = ls.fs
  local base = fs.freereg
  self:new_localvarliteral(ls, "(for index)", 0)
  self:new_localvarliteral(ls, "(for limit)", 1)
  self:new_localvarliteral(ls, "(for step)", 2)
  self:new_localvar(ls, varname, 3)
  self:checknext(ls, '=')
  self:exp1(ls)  -- initial value
  self:checknext(ls, ",")
  self:exp1(ls)  -- limit
  if self:testnext(ls, ",") then
    self:exp1(ls)  -- optional step
  else  -- default step = 1
    luaK:codeABx(fs, "OP_LOADK", fs.freereg, luaK:numberK(fs, 1))
    luaK:reserveregs(fs, 1)
  end
  self:forbody(ls, base, line, 1, true)
end

------------------------------------------------------------------------
-- parse a generic for loop, calls forbody()
-- * used in forstat()
------------------------------------------------------------------------
function luaY:forlist(ls, indexname)
  -- forlist -> NAME {,NAME} IN explist1 forbody
  local fs = ls.fs
  local e = {}  -- expdesc
  local nvars = 0
  local base = fs.freereg
  -- create control variables
  self:new_localvarliteral(ls, "(for generator)", nvars)
  nvars = nvars + 1
  self:new_localvarliteral(ls, "(for state)", nvars)
  nvars = nvars + 1
  self:new_localvarliteral(ls, "(for control)", nvars)
  nvars = nvars + 1
  -- create declared variables
  self:new_localvar(ls, indexname, nvars)
  nvars = nvars + 1
  while self:testnext(ls, ",") do
    self:new_localvar(ls, self:str_checkname(ls), nvars)
    nvars = nvars + 1
  end
  self:checknext(ls, "TK_IN")
  local line = ls.linenumber
  self:adjust_assign(ls, 3, self:explist1(ls, e), e)
  luaK:checkstack(fs, 3)  -- extra space to call generator
  self:forbody(ls, base, line, nvars - 3, false)
end

------------------------------------------------------------------------
-- initial parsing for a for loop, calls fornum() or forlist()
-- * used in statements()
------------------------------------------------------------------------
function luaY:forstat(ls, line)
  -- forstat -> FOR (fornum | forlist) END
  local fs = ls.fs
  local bl = {}  -- BlockCnt
  self:enterblock(fs, bl, true)  -- scope for loop and control variables
  luaX:next(ls)  -- skip `for'
  local varname = self:str_checkname(ls)  -- first variable name
  local c = ls.t.token
  if c == "=" then
    self:fornum(ls, varname, line)
  elseif c == "," or c == "TK_IN" then
    self:forlist(ls, varname)
  else
    luaX:syntaxerror(ls, self:LUA_QL("=").." or "..self:LUA_QL("in").." expected")
  end
  self:check_match(ls, "TK_END", "TK_FOR", line)
  self:leaveblock(fs)  -- loop scope (`break' jumps to this point)
end

------------------------------------------------------------------------
-- parse part of an if control structure, including the condition
-- * used in ifstat()
------------------------------------------------------------------------
function luaY:test_then_block(ls)
  -- test_then_block -> [IF | ELSEIF] cond THEN block
  luaX:next(ls)  -- skip IF or ELSEIF
  local condexit = self:cond(ls)
  self:checknext(ls, "TK_THEN")
  self:block(ls)  -- `then' part
  return condexit
end

------------------------------------------------------------------------
-- parse an if control structure
-- * used in statements()
------------------------------------------------------------------------
function luaY:ifstat(ls, line)
  -- ifstat -> IF cond THEN block {ELSEIF cond THEN block} [ELSE block] END
  local fs = ls.fs
  local escapelist = luaK.NO_JUMP
  local flist = self:test_then_block(ls)  -- IF cond THEN block
  while ls.t.token == "TK_ELSEIF" do
    escapelist = luaK:concat(fs, escapelist, luaK:jump(fs))
    luaK:patchtohere(fs, flist)
    flist = self:test_then_block(ls)  -- ELSEIF cond THEN block
  end
  if ls.t.token == "TK_ELSE" then
    escapelist = luaK:concat(fs, escapelist, luaK:jump(fs))
    luaK:patchtohere(fs, flist)
    luaX:next(ls)  -- skip ELSE (after patch, for correct line info)
    self:block(ls)  -- 'else' part
  else
    escapelist = luaK:concat(fs, escapelist, flist)
  end
  luaK:patchtohere(fs, escapelist)
  self:check_match(ls, "TK_END", "TK_IF", line)
end

------------------------------------------------------------------------
-- parse a local function statement
-- * used in statements()
------------------------------------------------------------------------
function luaY:localfunc(ls)
  local v, b = {}, {}  -- expdesc
  local fs = ls.fs
  self:new_localvar(ls, self:str_checkname(ls), 0)
  self:init_exp(v, "VLOCAL", fs.freereg)
  luaK:reserveregs(fs, 1)
  self:adjustlocalvars(ls, 1)
  self:body(ls, b, false, ls.linenumber)
  luaK:storevar(fs, v, b)
  -- debug information will only see the variable after this point!
  self:getlocvar(fs, fs.nactvar - 1).startpc = fs.pc
end

------------------------------------------------------------------------
-- parse a local variable declaration statement
-- * used in statements()
------------------------------------------------------------------------
function luaY:localstat(ls)
  -- stat -> LOCAL NAME {',' NAME} ['=' explist1]
  local nvars = 0
  local nexps
  local e = {}  -- expdesc
  repeat
    self:new_localvar(ls, self:str_checkname(ls), nvars)
    nvars = nvars + 1
  until not self:testnext(ls, ",")
  if self:testnext(ls, "=") then
    nexps = self:explist1(ls, e)
  else
    e.k = "VVOID"
    nexps = 0
  end
  self:adjust_assign(ls, nvars, nexps, e)
  self:adjustlocalvars(ls, nvars)
end

------------------------------------------------------------------------
-- parse a function name specification
-- * used in funcstat()
------------------------------------------------------------------------
function luaY:funcname(ls, v)
  -- funcname -> NAME {field} [':' NAME]
  local needself = false
  self:singlevar(ls, v)
  while ls.t.token == "." do
    self:field(ls, v)
  end
  if ls.t.token == ":" then
    needself = true
    self:field(ls, v)
  end
  return needself
end

------------------------------------------------------------------------
-- parse a function statement
-- * used in statements()
------------------------------------------------------------------------
function luaY:funcstat(ls, line)
  -- funcstat -> FUNCTION funcname body
  local v, b = {}, {}  -- expdesc
  luaX:next(ls)  -- skip FUNCTION
  local needself = self:funcname(ls, v)
  self:body(ls, b, needself, line)
  luaK:storevar(ls.fs, v, b)
  luaK:fixline(ls.fs, line)  -- definition 'happens' in the first line
end

------------------------------------------------------------------------
-- parse a function call with no returns or an assignment statement
-- * used in statements()
------------------------------------------------------------------------
function luaY:exprstat(ls)
  -- stat -> func | assignment
  local fs = ls.fs
  local v = {}  -- LHS_assign
        v.v = {}
  self:primaryexp(ls, v.v)
  if v.v.k == "VCALL" then  -- stat -> func
    luaP:SETARG_C(luaK:getcode(fs, v.v), 1)  -- call statement uses no results
  else  -- stat -> assignment
    v.prev = nil
    self:assignment(ls, v, 1)
  end
end

------------------------------------------------------------------------
-- parse a return statement
-- * used in statements()
------------------------------------------------------------------------
function luaY:retstat(ls)
  -- stat -> RETURN explist
  local fs = ls.fs
  local e = {}  -- expdesc
  local first, nret  -- registers with returned values
  luaX:next(ls)  -- skip RETURN
  if self:block_follow(ls.t.token) or ls.t.token == ";" then
    first, nret = 0, 0  -- return no values
  else
    nret = self:explist1(ls, e)  -- optional return values
    if self:hasmultret(e.k) then
      luaK:setmultret(fs, e)
      if e.k == "VCALL" and nret == 1 then  -- tail call?
        luaP:SET_OPCODE(luaK:getcode(fs, e), "OP_TAILCALL")
        assert(luaP:GETARG_A(luaK:getcode(fs, e)) == fs.nactvar)
      end
      first = fs.nactvar
      nret = self.LUA_MULTRET  -- return all values
    else
      if nret == 1 then  -- only one single value?
        first = luaK:exp2anyreg(fs, e)
      else
        luaK:exp2nextreg(fs, e)  -- values must go to the 'stack'
        first = fs.nactvar  -- return all 'active' values
        assert(nret == fs.freereg - first)
      end
    end--if
  end--if
  luaK:ret(fs, first, nret)
end

------------------------------------------------------------------------
-- initial parsing for statements, calls a lot of functions
-- * returns boolean instead of 0|1
-- * used in chunk()
------------------------------------------------------------------------
function luaY:statement(ls)
  local line = ls.linenumber  -- may be needed for error messages
  local c = ls.t.token
  if c == "TK_IF" then  -- stat -> ifstat
    self:ifstat(ls, line)
    return false
  elseif c == "TK_WHILE" then  -- stat -> whilestat
    self:whilestat(ls, line)
    return false
  elseif c == "TK_DO" then  -- stat -> DO block END
    luaX:next(ls)  -- skip DO
    self:block(ls)
    self:check_match(ls, "TK_END", "TK_DO", line)
    return false
  elseif c == "TK_FOR" then  -- stat -> forstat
    self:forstat(ls, line)
    return false
  elseif c == "TK_REPEAT" then  -- stat -> repeatstat
    self:repeatstat(ls, line)
    return false
  elseif c == "TK_FUNCTION" then  -- stat -> funcstat
    self:funcstat(ls, line)
    return false
  elseif c == "TK_LOCAL" then  -- stat -> localstat
    luaX:next(ls)  -- skip LOCAL
    if self:testnext(ls, "TK_FUNCTION") then  -- local function?
      self:localfunc(ls)
    else
      self:localstat(ls)
    end
    return false
  elseif c == "TK_RETURN" then  -- stat -> retstat
    self:retstat(ls)
    return true  -- must be last statement
  elseif c == "TK_BREAK" then  -- stat -> breakstat
    luaX:next(ls)  -- skip BREAK
    self:breakstat(ls)
    return true  -- must be last statement
  elseif c == "TK_CONTINUE" then  -- stat -> continuestat
    luaX:next(ls)  -- skip CONTINUE
    self:continuestat(ls)
    return true  -- must be last statement
  else
    self:exprstat(ls)
    return false  -- to avoid warnings
  end--if c
end

------------------------------------------------------------------------
-- parse a chunk, which consists of a bunch of statements
-- * used in parser(), body(), block(), repeatstat()
------------------------------------------------------------------------
function luaY:chunk(ls)
  -- chunk -> { stat [';'] }
  local islast = false
  self:enterlevel(ls)
  while not islast and not self:block_follow(ls.t.token) do
    islast = self:statement(ls)
    self:testnext(ls, ";")
    assert(ls.fs.f.maxstacksize >= ls.fs.freereg and
               ls.fs.freereg >= ls.fs.nactvar)
    ls.fs.freereg = ls.fs.nactvar  -- free registers
  end
  self:leavelevel(ls)
end

-- }======================================================================
return luaY
