local i=require(script.Parent.LuaZ)local r={}r.RESERVED="\084\075\095\065\078\068 \097\110\100\n\084\075\095\066\082\069\065\075 \098\114\101\097\107\n\084\075\095\067\079\078\084\073\078\085\069 \099\111\110\116\105\110\117\101\n\084\075\095\068\079 \100\111\n\084\075\095\069\076\083\069 \101\108\115\101\n\084\075\095\069\076\083\069\073\070 \101\108\115\101\105\102\n\084\075\095\069\078\068 \101\110\100\n\084\075\095\070\065\076\083\069 \102\097\108\115\101\n\084\075\095\070\079\082 \102\111\114\n\084\075\095\070\085\078\067\084\073\079\078 \102\117\110\099\116\105\111\110\n\084\075\095\073\070 \105\102\n\084\075\095\073\078 \105\110\n\084\075\095\076\079\067\065\076 \108\111\099\097\108\n\084\075\095\078\073\076 \110\105\108\n\084\075\095\078\079\084 \110\111\116\n\084\075\095\079\082 \111\114\n\084\075\095\082\069\080\069\065\084 \114\101\112\101\097\116\n\084\075\095\082\069\084\085\082\078 \114\101\116\117\114\110\n\084\075\095\084\072\069\078 \116\104\101\110\n\084\075\095\084\082\085\069 \116\114\117\101\n\084\075\095\085\078\084\073\076 \117\110\116\105\108\n\084\075\095\087\072\073\076\069 \119\104\105\108\101\n\084\075\095\065\083\083\073\071\078\095\065\068\068 \043\061\n\084\075\095\065\083\083\073\071\078\095\083\085\066 -\061\n\084\075\095\065\083\083\073\071\078\095\077\085\076 \042\061\n\084\075\095\065\083\083\073\071\078\095\068\073\086 \047\061\n\084\075\095\065\083\083\073\071\078\095\077\079\068 \037\061\n\084\075\095\065\083\083\073\071\078\095\080\079\087 \094\061\n\084\075\095\065\083\083\073\071\078\095\067\079\078\067\065\084 \046\046\061\n\084\075\095\067\079\078\067\065\084 \046\046\n\084\075\095\068\079\084\083 \046\046\046\n\084\075\095\069\081 \061\061\n\084\075\095\071\069 \062\061\n\084\075\095\076\069 \060\061\n\084\075\095\078\069 ~\061\n\084\075\095\078\065\077\069 \060\110\097\109\101\062\n\084\075\095\078\085\077\066\069\082 \060\110\117\109\098\101\114\062\n\084\075\095\083\084\082\073\078\071 \060\115\116\114\105\110\103\062\n\084\075\095\069\079\083 \060\101\111\102\062"r.MAXSRC=80 r.MAX_INT=2147483645 r.LUA_QS="\'\037\115\'"r.LUA_COMPAT_LSTR=1 r.DEOP={getfenv=true,setfenv=true,_ENV=true}r.GLOBALVARS="\095\071 \095\086\069\082\083\073\079\078\n\n\097\115\115\101\114\116 \099\111\108\108\101\099\116\103\097\114\098\097\103\101 \100\111\102\105\108\101 \101\114\114\111\114 \103\101\116\109\101\116\097\116\097\098\108\101 \105\112\097\105\114\115\n\108\111\097\100 \108\111\097\100\102\105\108\101 \109\111\100\117\108\101 \110\101\120\116 \112\097\105\114\115 \112\099\097\108\108\n\112\114\105\110\116 \114\097\119\101\113\117\097\108 \114\097\119\103\101\116 \114\097\119\115\101\116 \114\101\113\117\105\114\101 \115\101\108\101\099\116\n\115\101\116\109\101\116\097\116\097\098\108\101 \116\111\110\117\109\098\101\114 \116\111\115\116\114\105\110\103 \116\121\112\101 \117\110\112\097\099\107 \120\112\099\097\108\108\n\110\101\119\112\114\111\120\121 \103\099\105\110\102\111 \119\097\114\110\n\n\103\097\109\101 \112\108\117\103\105\110 \115\099\114\105\112\116 \115\104\097\114\101\100 \119\111\114\107\115\112\097\099\101\n\n\099\111\114\111\117\116\105\110\101 \100\101\098\117\103 \105\111 \109\097\116\104 \111\115 \112\097\099\107\097\103\101\n\115\116\114\105\110\103 \116\097\098\108\101 \098\105\116\051\050 \117\116\102\056\n\n\068\101\098\117\103\103\101\114\077\097\110\097\103\101\114 \100\101\108\097\121 \080\108\117\103\105\110\077\097\110\097\103\101\114 \115\101\116\116\105\110\103\115 \115\112\097\119\110 \116\105\099\107\n\116\105\109\101 \085\115\101\114\083\101\116\116\105\110\103\115 \119\097\105\116\n\n\116\097\115\107\n\n\065\120\101\115 \066\114\105\099\107\067\111\108\111\114 \067\097\116\097\108\111\103\083\101\097\114\099\104\080\097\114\097\109\115 \067\070\114\097\109\101 \067\111\108\111\114\051 \067\111\108\111\114\083\101\113\117\101\110\099\101\n\067\111\108\111\114\083\101\113\117\101\110\099\101\075\101\121\112\111\105\110\116 \068\097\116\101\084\105\109\101 \068\111\099\107\087\105\100\103\101\116\080\108\117\103\105\110\071\117\105\073\110\102\111 \069\110\117\109 \070\097\099\101\115 \070\108\111\097\116\067\117\114\118\101\075\101\121\n\070\111\110\116 \073\110\115\116\097\110\099\101 \078\117\109\098\101\114\082\097\110\103\101 \078\117\109\098\101\114\083\101\113\117\101\110\099\101 \078\117\109\098\101\114\083\101\113\117\101\110\099\101\075\101\121\112\111\105\110\116 \079\118\101\114\108\097\112\080\097\114\097\109\115\n\080\097\116\104\087\097\121\112\111\105\110\116 \080\104\121\115\105\099\097\108\080\114\111\112\101\114\116\105\101\115 \082\097\110\100\111\109 \082\097\121 \082\097\121\099\097\115\116\080\097\114\097\109\115 \082\101\099\116\n\082\101\103\105\111\110\051 \082\101\103\105\111\110\051\105\110\116\049\054 \082\111\116\097\116\105\111\110\067\117\114\118\101\075\101\121 \083\104\097\114\101\100\084\097\098\108\101 \084\119\101\101\110\073\110\102\111 \085\068\105\109\n\085\068\105\109\050 \086\101\099\116\111\114\050 \086\101\099\116\111\114\050\105\110\116\049\054 \086\101\099\116\111\114\051 \086\101\099\116\111\114\051\105\110\116\049\054\n"function r.init(i)local r,F,T={},{},{}for i in string.gmatch(i.RESERVED,"\091\094\n\093\043")do local T,R,N,M=string.find(i,"\040\037\083\043\041\037\115\043\040\037\083\043\041")r[N]=M F[M]=N end for i in string.gmatch(i.GLOBALVARS,"\091\094\037\115\093\043")do T[i]=true end i.tokens=r i.enums=F i.globalvars=T end function r.chunkid(F,i,r)local T local R=string.sub(i,1,1)if R=="\061"then T=string.sub(i,2,r)else if R=="\064"then i=string.sub(i,2)r=r-7 local F=#i T=""if F>r then i=string.sub(i,(1+F)-r)T=T.."\046\046\046"end T=T..i else local F=string.find(i,"\091\n\r\093")F=F and F-1 or#i r=r-16 if F>r then F=r end T="\091\115\116\114\105\110\103 \""if F<#i then T=T..(string.sub(i,1,F).."\046\046\046")else T=T..i end T=T.."\"\093"end end return T end function r.token2str(F,i,r)if string.sub(r,1,3)~="\084\075\095"then if string.find(r,"\037\099")then return string.format("\099\104\097\114\040\037\100\041",string.byte(r))end return r else end return F.tokens[r]end function r.lexerror(T,i,r,F)local function R(i,r)if r=="\084\075\095\078\065\077\069"or r=="\084\075\095\083\084\082\073\078\071"or r=="\084\075\095\078\085\077\066\069\082"then return i.buff else return T:token2str(i,r)end end local N=T:chunkid(i.source,T.MAXSRC)local M=string.format("\037\115\058\037\100\058 \037\115",N,i.linenumber,r)if F then M=string.format("\037\115 \110\101\097\114 "..T.LUA_QS,M,R(i,F))end error(M)end function r.syntaxerror(F,i,r)F:lexerror(i,r,i.t.token)end function r.currIsNewline(r,i)return i.current=="\n"or i.current=="\r"end function r.inclinenumber(r,i)local F=i.current r:nextc(i)if r:currIsNewline(i)and i.current~=F then r:nextc(i)end i.linenumber=i.linenumber+1 if i.linenumber>=r.MAX_INT then r:syntaxerror(i,"\099\104\117\110\107 \104\097\115 \116\111\111 \109\097\110\121 \108\105\110\101\115")end end function r.setinput(R,i,r,F,T)if not r then r={}end if not r.lookahead then r.lookahead={}end if not r.t then r.t={}end r.decpoint="\046"r.L=i r.lookahead.token="\084\075\095\069\079\083"r.z=F r.fs=nil r.linenumber=1 r.lastline=1 r.source=T r.safeenv=true r.usedglobals={}R:nextc(r)end function r.check_next(F,i,r)if not string.find(r,i.current,1,1)then return false end F:save_and_next(i)return true end function r.next(r,i)i.lastline=i.linenumber if i.lookahead.token~="\084\075\095\069\079\083"then i.t.seminfo=i.lookahead.seminfo i.t.token=i.lookahead.token i.lookahead.token="\084\075\095\069\079\083"else i.t.token,i.t.seminfo,i.linenumber=r:poptk(i)end end function r.lookahead(r,i)i.lookahead.token,i.lookahead.seminfo,i.lookahead.linenumber=r:poptk(i)end function r.nextc(F,r)local T=i:zgetc(r.z)r.current=T return T end function r.save(F,i,r)local T=i.buff i.buff=T..r end function r.save_and_next(r,i)r:save(i,i.current)return r:nextc(i)end function r.str2d(r,i)if string.match(string.lower(i),"\091\094\098\037\100\097-\102\095\093\095")or string.match(string.lower(i),"\095\091\094\037\100\097-\102\095\093")then return nil end i=string.gsub(i,"\095","")local F=tonumber(i)if F then return F end if string.lower(string.sub(i,1,2))=="\048\120"then F=tonumber(i,16)if F then return F end elseif string.lower(string.sub(i,1,2))=="\048\098"then if string.match(string.sub(i,3),"\091\094\048\049\093")then return nil end local r=string.reverse(string.sub(i,3))local F=0 for i=1,string.len(r),1 do F=F+bit32.lshift(string.sub(r,i,i)=="\049"and 1 or 0,i-1)end return F end return nil end function r.buffreplace(T,i,r,F)local R,N="",i.buff for i=1,#N,1 do local T=string.sub(N,i,i)if T==r then T=F end R=R..T end i.buff=R end function r.trydecpoint(F,i,r)local T=i.decpoint F:buffreplace(i,T,i.decpoint)local R=F:str2d(i.buff)r.seminfo=R if not R then F:buffreplace(i,i.decpoint,"\046")F:lexerror(i,"\109\097\108\102\111\114\109\101\100 \110\117\109\098\101\114","\084\075\095\078\085\077\066\069\082")end end function r.read_numeral(F,i,r)repeat F:save_and_next(i)until string.find(i.current,"\037\068")and i.current~="\046"if F:check_next(i,"\069\101")then F:check_next(i,"\043-")end while string.find(i.current,"\094\037\119\036")or i.current=="\095"do F:save_and_next(i)end F:buffreplace(i,"\046",i.decpoint)local T=F:str2d(i.buff)r.seminfo=T if not T then F:trydecpoint(i,r)end end function r.skip_sep(r,i)local F=0 local T=i.current r:save_and_next(i)while i.current=="\061"do r:save_and_next(i)F=F+1 end return i.current==T and F or-F-1 end function r.read_long_string(T,i,r,F)local R=0 T:save_and_next(i)if T:currIsNewline(i)then T:inclinenumber(i)end while true do local N=i.current if N=="\069\079\090"then T:lexerror(i,r and"\117\110\102\105\110\105\115\104\101\100 \108\111\110\103 \115\116\114\105\110\103"or"\117\110\102\105\110\105\115\104\101\100 \108\111\110\103 \099\111\109\109\101\110\116","\084\075\095\069\079\083")elseif N=="\091"then if T.LUA_COMPAT_LSTR then if T:skip_sep(i)==F then T:save_and_next(i)R=R+1 if T.LUA_COMPAT_LSTR==1 then if F==0 then T:lexerror(i,"\110\101\115\116\105\110\103 \111\102 \091\091\046\046\046\093\093 \105\115 \100\101\112\114\101\099\097\116\101\100","\091")end end end end elseif N=="\093"then if T:skip_sep(i)==F then T:save_and_next(i)if T.LUA_COMPAT_LSTR and T.LUA_COMPAT_LSTR==2 then R=R-1 if F==0 and R>=0 then break end end break end elseif T:currIsNewline(i)then T:save(i,"\n")T:inclinenumber(i)if not r then i.buff=""end else if r then T:save_and_next(i)else T:nextc(i)end end end if r then local T=3+F r.seminfo=string.sub(i.buff,T,-T)end end function r.read_string(R,i,F,T)R:save_and_next(i)while i.current~=F do local T=i.current if T=="\069\079\090"then R:lexerror(i,"\117\110\102\105\110\105\115\104\101\100 \115\116\114\105\110\103","\084\075\095\069\079\083")elseif R:currIsNewline(i)then R:lexerror(i,"\117\110\102\105\110\105\115\104\101\100 \115\116\114\105\110\103","\084\075\095\083\084\082\073\078\071")elseif T=="\092"then T=R:nextc(i)if R:currIsNewline(i)then R:save(i,"\n")R:inclinenumber(i)elseif T~="\069\079\090"then local N=string.find("\097\098\102\110\114\116\118",T,1,1)if N then R:save(i,string.sub("\a\b\012\n\r\t\v",N,N))R:nextc(i)elseif T=="\117"then assert(utf8 and utf8.char,"\078\111 \117\116\102\056 \108\105\098\114\097\114\121 \102\111\117\110\100\033 \067\097\110\110\111\116 \100\101\099\111\100\101 \085\084\070\056 \115\116\114\105\110\103 \108\105\116\101\114\097\108\033")if R:nextc(i)~="\123"then R:lexerror("\083\111\117\110\100\115 \108\105\107\101 \097 \115\107\105\108\108 \105\115\115\117\101","\084\075\095\083\084\082\073\078\071")end local r=""while true do T=R:nextc(i)if T=="\125"then break elseif string.match(T,"\037\120")then r=r..T else R:lexerror(string.format("\073\110\118\097\108\105\100 \117\110\105\099\111\100\101 \099\104\097\114\097\099\116\101\114 \115\101\113\117\101\110\099\101\046 \069\120\112\101\099\116\101\100 \097\108\112\104\097\110\117\109\101\114\105\099 \099\104\097\114\097\099\116\101\114\044 \103\111\116 \037\115\046 \068\105\100 \121\111\117 \102\111\114\103\101\116 \116\111 \099\108\111\115\101 \116\104\101 \099\111\100\101 \115\101\113\117\101\110\099\101 \119\105\116\104 \097 \099\117\114\108\121 \098\114\097\099\107\101\116\063",T),"\084\075\095\083\084\082\073\078\071")end end if not tonumber(r,16)or not utf8.char(tonumber(r,16))then R:lexerror(string.format("\073\110\118\097\108\105\100 \085\084\070\056 \099\104\097\114 \037\115\046 \069\120\112\101\099\116\101\100 \097 \118\097\108\105\100 \085\084\070\056 \099\104\097\114\097\099\116\101\114 \099\111\100\101",r),"\084\075\095\083\084\082\073\078\071")else R:save(i,utf8.char(tonumber(r)))end elseif string.lower(T)=="\120"then local r=R:nextc(i)..R:nextc(i)if not string.match(string.upper(r),"\037\120")then R:lexerror(string.format("\073\110\118\097\108\105\100 \104\101\120 \115\116\114\105\110\103 \108\105\116\101\114\097\108\046 \069\120\112\101\099\116\101\100 \118\097\108\105\100 \115\116\114\105\110\103 \108\105\116\101\114\097\108\044 \103\111\116 \037\115",r),"\084\075\095\083\084\082\073\078\071")else R:save(i,string.char(tonumber(r,16)))end elseif string.lower(T)=="\122"then local T=r:nextc(i)if T==F then break else R:save(i,T)end elseif not string.find(T,"\037\100")then R:save_and_next(i)else T,N=0,0 repeat T=10*T+i.current R:nextc(i)N=N+1 until N>=3 or not string.find(i.current,"\037\100")if T>255 then R:lexerror(i,"\101\115\099\097\112\101 \115\101\113\117\101\110\099\101 \116\111\111 \108\097\114\103\101","\084\075\095\083\084\082\073\078\071")end R:save(i,string.char(T))end end else R:save_and_next(i)end end R:save_and_next(i)T.seminfo=string.sub(i.buff,2,-2)end function r.poptk(F,i)if i.lexercache then local r=i.lexercache local F=r[r.n]r.n,r[r.n]=r.n-1,nil return F.type or"\084\075\095\069\079\083",F.seminfo or"",F.line end local T={}i.lexercache=T while true do local F=r:llex(i,i.t)table.insert(T,{type=F;seminfo=i.t.seminfo;line=i.linenumber})if F=="\084\075\095\069\079\083"then break end end local R=#T T.n=R i.linenumber,i.lastline,i.lookahead.token=1,1,"\084\075\095\069\079\083"for i=1,math.floor(R/2),1 do local r=(R-i)+1 T[i],T[r]=T[r],T[i]end local N=i.usedglobals if i.safeenv and#N>0 then for i=#N,1,-1 do T.n=T.n+2 T[T.n-1],T[T.n]={type="\084\075\095\078\065\077\069",seminfo=N[i],line=1},{type="\044";seminfo="\044";line=1}end T[T.n]={type="\061",seminfo="\061";line=1}for i=#N,1,-1 do T.n=T.n+2 T[T.n-1],T[T.n]={type="\084\075\095\078\065\077\069";seminfo=N[i];line=1},{type="\044";seminfo="\044";line=1}end T[T.n]={type="\084\075\095\076\079\067\065\076";seminfo="\108\111\099\097\108",line=1}end return F:poptk(i)end function r.llex(F,i,r)i.buff=""while true do local T=i.current if F:currIsNewline(i)then F:inclinenumber(i)elseif T=="-"then T=F:nextc(i)if T=="\061"then F:nextc(i)return"\084\075\095\065\083\083\073\071\078\095\083\085\066"elseif T~="-"then return"-"end local r=-1 if F:nextc(i)=="\091"then r=F:skip_sep(i)i.buff=""end if r>=0 then F:read_long_string(i,nil,r)i.buff=""else while not F:currIsNewline(i)and i.current~="\069\079\090"do F:nextc(i)end end elseif T=="\091"then local T=F:skip_sep(i)if T>=0 then F:read_long_string(i,r,T)return"\084\075\095\083\084\082\073\078\071"elseif T==-1 then return"\091"else F:lexerror(i,"\105\110\118\097\108\105\100 \108\111\110\103 \115\116\114\105\110\103 \100\101\108\105\109\105\116\101\114","\084\075\095\083\084\082\073\078\071")end elseif T=="\043"then T=F:nextc(i)if T~="\061"then return"\043"else F:nextc(i)return"\084\075\095\065\083\083\073\071\078\095\065\068\068"end elseif T=="\042"then T=F:nextc(i)if T~="\061"then return"\042"else F:nextc(i)return"\084\075\095\065\083\083\073\071\078\095\077\085\076"end elseif T=="\047"then T=F:nextc(i)if T~="\061"then return"\047"else F:nextc(i)return"\084\075\095\065\083\083\073\071\078\095\068\073\086"end elseif T=="\037"then T=F:nextc(i)if T~="\061"then return"\037"else F:nextc(i)return"\084\075\095\065\083\083\073\071\078\095\077\079\068"end elseif T=="\094"then T=F:nextc(i)if T~="\061"then return"\094"else F:nextc(i)return"\084\075\095\065\083\083\073\071\078\095\080\079\087"end elseif T=="\061"then T=F:nextc(i)if T~="\061"then return"\061"else F:nextc(i)return"\084\075\095\069\081"end elseif T=="\060"then T=F:nextc(i)if T~="\061"then return"\060"else F:nextc(i)return"\084\075\095\076\069"end elseif T=="\062"then T=F:nextc(i)if T~="\061"then return"\062"else F:nextc(i)return"\084\075\095\071\069"end elseif T=="~"then T=F:nextc(i)if T~="\061"then return"~"else F:nextc(i)return"\084\075\095\078\069"end elseif T=="\""or T=="\'"then F:read_string(i,T,r)return"\084\075\095\083\084\082\073\078\071"elseif T=="\046"then T=F:save_and_next(i)if F:check_next(i,"\046")then if F:check_next(i,"\046")then return"\084\075\095\068\079\084\083"else return"\084\075\095\067\079\078\067\065\084"end elseif not string.find(T,"\037\100")then return"\046"else F:read_numeral(i,r)return"\084\075\095\078\085\077\066\069\082"end elseif T=="\069\079\090"then return"\084\075\095\069\079\083"else if string.find(T,"\037\115")then F:nextc(i)elseif string.find(T,"\037\100")then F:read_numeral(i,r)return"\084\075\095\078\085\077\066\069\082"elseif string.find(T,"\091\095\037\097\093")then repeat T=F:save_and_next(i)until T=="\069\079\090"or not string.find(T,"\091\095\037\119\093")local R=i.buff local N=F.enums[R]if N then return N end if F.DEOP[R]then i.safeenv=false elseif F.globalvars[R]and not table.find(i.usedglobals,R)then table.insert(i.usedglobals,R)end r.seminfo=R return"\084\075\095\078\065\077\069"else F:nextc(i)return T end end end end return r
--# selene: allow(incorrect_standard_library_use, multiple_statements, shadowing, unused_variable, empty_if, divide_by_zero, unbalanced_assignments)
--[[--------------------------------------------------------------------

  llex.lua
  Lua lexical analyzer in Lua
  This file is part of Yueliang.

  Copyright (c) 2005-2006 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:
-- * intended to 'imitate' llex.c code; performance is not a concern
-- * tokens are strings; code structure largely retained
-- * deleted stuff (compared to llex.c) are noted, comments retained
-- * nextc() returns the currently read character to simplify coding
--   here; next() in llex.c does not return anything
-- * compatibility code is marked with "--#" comments
--
-- Added:
-- * luaX:chunkid (function luaO_chunkid from lobject.c)
-- * luaX:str2d (function luaO_str2d from lobject.c)
-- * luaX.LUA_QS used in luaX:lexerror (from luaconf.h)
-- * luaX.LUA_COMPAT_LSTR in luaX:read_long_string (from luaconf.h)
-- * luaX.MAX_INT used in luaX:inclinenumber (from llimits.h)
-- Luau specific additions by ccuser44:
--   * Added Luau number handling
--   * Added post 5.1 string handling
--   * Added env localisation aiding for parser
--   * Made lexer pre-lex lex tree instead of using on-the-fly lexing.
--     Necessary for env localisation and more efficient than building
--     a parse tree (which would require full pre-lexing as well)
--
-- To use the lexer:
-- (1) luaX:init() to initialize the lexer
-- (2) luaX:setinput() to set the input stream to lex
-- (3) call luaX:next() or luaX:luaX:lookahead() to get tokens,
--     until "TK_EOS": luaX:next()
-- * since EOZ is returned as a string, be careful when regexp testing
--
-- Not implemented:
-- * luaX_newstring: not required by this Lua implementation
-- * buffer MAX_SIZET size limit (from llimits.h) test not implemented
--   in the interest of performance
-- * locale-aware number handling is largely redundant as Lua's
--   tonumber() function is already capable of this
--
-- Changed in 5.1.x:
-- * TK_NAME token order moved down
-- * string representation for TK_NAME, TK_NUMBER, TK_STRING changed
-- * token struct renamed to lower case (LS -> ls)
-- * LexState struct: removed nestlevel, added decpoint
-- * error message functions have been greatly simplified
-- * token2string renamed to luaX_tokens, exposed in llex.h
-- * lexer now handles all kinds of newlines, including CRLF
-- * shbang first line handling removed from luaX:setinput;
--   it is now done in lauxlib.c (luaL_loadfile)
-- * next(ls) macro renamed to nextc(ls) due to new luaX_next function
-- * EXTRABUFF and MAXNOCHECK removed due to lexer changes
-- * checkbuffer(ls, len) macro deleted
-- * luaX:read_numeral now has 3 support functions: luaX:trydecpoint,
--   luaX:buffreplace and (luaO_str2d from lobject.c) luaX:str2d
-- * luaX:read_numeral is now more promiscuous in slurping characters;
--   hexadecimal numbers was added, locale-aware decimal points too
-- * luaX:skip_sep is new; used by luaX:read_long_string
-- * luaX:read_long_string handles new-style long blocks, with some
--   optional compatibility code
-- * luaX:llex: parts changed to support new-style long blocks
-- * luaX:llex: readname functionality has been folded in
-- * luaX:llex: removed test for control characters
--
--------------------------------------------------------------------]]

local luaZ = require(script.Parent.LuaZ)

local luaX = {}

-- FIRST_RESERVED is not required as tokens are manipulated as strings
-- TOKEN_LEN deleted; maximum length of a reserved word not needed

------------------------------------------------------------------------
-- "ORDER RESERVED" deleted; enumeration in one place: luaX.RESERVED
------------------------------------------------------------------------

-- terminal symbols denoted by reserved words: TK_AND to TK_WHILE
-- other terminal symbols: TK_NAME to TK_EOS
luaX.RESERVED = [[
TK_AND and
TK_BREAK break
TK_CONTINUE continue
TK_DO do
TK_ELSE else
TK_ELSEIF elseif
TK_END end
TK_FALSE false
TK_FOR for
TK_FUNCTION function
TK_IF if
TK_IN in
TK_LOCAL local
TK_NIL nil
TK_NOT not
TK_OR or
TK_REPEAT repeat
TK_RETURN return
TK_THEN then
TK_TRUE true
TK_UNTIL until
TK_WHILE while
TK_ASSIGN_ADD +=
TK_ASSIGN_SUB -=
TK_ASSIGN_MUL *=
TK_ASSIGN_DIV /=
TK_ASSIGN_MOD %=
TK_ASSIGN_POW ^=
TK_ASSIGN_CONCAT ..=
TK_CONCAT ..
TK_DOTS ...
TK_EQ ==
TK_GE >=
TK_LE <=
TK_NE ~=
TK_NAME <name>
TK_NUMBER <number>
TK_STRING <string>
TK_EOS <eof>]]

-- NUM_RESERVED is not required; number of reserved words

--[[--------------------------------------------------------------------
-- Instead of passing seminfo, the Token struct (e.g. ls.t) is passed
-- so that lexer functions can use its table element, ls.t.seminfo
--
-- SemInfo (struct no longer needed, a mixed-type value is used)
--
-- Token (struct of ls.t and ls.lookahead):
--   token  -- token symbol
--   seminfo  -- semantics information
--
-- LexState (struct of ls; ls is initialized by luaX:setinput):
--   current  -- current character (charint)
--   linenumber  -- input line counter
--   lastline  -- line of last token 'consumed'
--   t  -- current token (table: struct Token)
--   lookahead  -- look ahead token (table: struct Token)
--   fs  -- 'FuncState' is private to the parser
--   L -- LuaState
--   z  -- input stream
--   buff  -- buffer for tokens
--   source  -- current source name
--   decpoint -- locale decimal point
--   nestlevel  -- level of nested non-terminals
----------------------------------------------------------------------]]

-- luaX.tokens (was luaX_tokens) is now a hash; see luaX:init

luaX.MAXSRC = 80
luaX.MAX_INT = 2147483645       -- constants from elsewhere (see above)
luaX.LUA_QS = "'%s'"
luaX.LUA_COMPAT_LSTR = 1
--luaX.MAX_SIZET = 4294967293

------------------------------------------------------------------------
-- LuaU specific constants
-- * luaX.DEOP: Tokens that cause env deoptimisation
-- * luaX.GLOBALVARS: Tokens that are globals in the env
------------------------------------------------------------------------
luaX.DEOP = {
	["getf".."env"] = true, ["setf".."env"] = true, ["_".."ENV"] = true
}
luaX.GLOBALVARS = [[
_G _VERSION

assert collectgarbage dofile error getmetatable ipairs
load loadfile module next pairs pcall
print rawequal rawget rawset require select
setmetatable tonumber tostring type unpack xpcall
newproxy gcinfo warn

game plugin script shared workspace

coroutine debug io math os package
string table bit32 utf8

DebuggerManager delay PluginManager settings spawn tick
time UserSettings wait

task

Axes BrickColor CatalogSearchParams CFrame Color3 ColorSequence
ColorSequenceKeypoint DateTime DockWidgetPluginGuiInfo Enum Faces FloatCurveKey
Font Instance NumberRange NumberSequence NumberSequenceKeypoint OverlapParams
PathWaypoint PhysicalProperties Random Ray RaycastParams Rect
Region3 Region3int16 RotationCurveKey SharedTable TweenInfo UDim
UDim2 Vector2 Vector2int16 Vector3 Vector3int16
]]

------------------------------------------------------------------------
-- initialize lexer
-- * original luaX_init has code to create and register token strings
-- * luaX.tokens: TK_* -> token
-- * luaX.enums:  token -> TK_* (used in luaX:llex)
------------------------------------------------------------------------
function luaX:init()
  local tokens, enums, globalvars = {}, {}, {}
  for v in string.gmatch(self.RESERVED, "[^\n]+") do
    local _, _, tok, str = string.find(v, "(%S+)%s+(%S+)")
    tokens[tok] = str
    enums[str] = tok
  end
  for v in string.gmatch(self.GLOBALVARS, "[^%s]+") do
    globalvars[v] = true
  end
  self.tokens = tokens
  self.enums = enums
  self.globalvars = globalvars
end

------------------------------------------------------------------------
-- returns a suitably-formatted chunk name or id
-- * from lobject.c, used in llex.c and ldebug.c
-- * the result, out, is returned (was first argument)
------------------------------------------------------------------------
function luaX:chunkid(source, bufflen)
  local out
  local first = string.sub(source, 1, 1)
  if first == "=" then
    out = string.sub(source, 2, bufflen)  -- remove first char
  else  -- out = "source", or "...source"
    if first == "@" then
      source = string.sub(source, 2)  -- skip the '@'
      bufflen = bufflen - #" '...' "
      local l = #source
      out = ""
      if l > bufflen then
        source = string.sub(source, 1 + l - bufflen)  -- get last part of file name
        out = out.."..."
      end
      out = out..source
    else  -- out = [string "string"]
      local len = string.find(source, "[\n\r]")  -- stop at first newline
      len = len and (len - 1) or #source
      bufflen = bufflen - #(" [string \"...\"] ")
      if len > bufflen then len = bufflen end
      out = "[string \""
      if len < #source then  -- must truncate?
        out = out..string.sub(source, 1, len).."..."
      else
        out = out..source
      end
      out = out.."\"]"
    end
  end
  return out
end

--[[--------------------------------------------------------------------
-- Support functions for lexer
-- * all lexer errors eventually reaches lexerror:
     syntaxerror -> lexerror
----------------------------------------------------------------------]]

------------------------------------------------------------------------
-- look up token and return keyword if found (also called by parser)
------------------------------------------------------------------------
function luaX:token2str(ls, token)
  if string.sub(token, 1, 3) ~= "TK_" then
    if string.find(token, "%c") then
      return string.format("char(%d)", string.byte(token))
    end
    return token
  else
  end
    return self.tokens[token]
end

------------------------------------------------------------------------
-- throws a lexer error
-- * txtToken has been made local to luaX:lexerror
-- * can't communicate LUA_ERRSYNTAX, so it is unimplemented
------------------------------------------------------------------------
function luaX:lexerror(ls, msg, token)
  local function txtToken(ls, token)
    if token == "TK_NAME" or
       token == "TK_STRING" or
       token == "TK_NUMBER" then
      return ls.buff
    else
      return self:token2str(ls, token)
    end
  end
  local buff = self:chunkid(ls.source, self.MAXSRC)
  local msg = string.format("%s:%d: %s", buff, ls.linenumber, msg)
  if token then
    msg = string.format("%s near "..self.LUA_QS, msg, txtToken(ls, token))
  end
  -- luaD_throw(ls->L, LUA_ERRSYNTAX)
  error(msg)
end

------------------------------------------------------------------------
-- throws a syntax error (mainly called by parser)
-- * ls.t.token has to be set by the function calling luaX:llex
--   (see luaX:next and luaX:lookahead elsewhere in this file)
------------------------------------------------------------------------
function luaX:syntaxerror(ls, msg)
  self:lexerror(ls, msg, ls.t.token)
end

------------------------------------------------------------------------
-- move on to next line
------------------------------------------------------------------------
function luaX:currIsNewline(ls)
  return ls.current == "\n" or ls.current == "\r"
end

function luaX:inclinenumber(ls)
  local old = ls.current
  -- lua_assert(currIsNewline(ls))
  self:nextc(ls)  -- skip '\n' or '\r'
  if self:currIsNewline(ls) and ls.current ~= old then
    self:nextc(ls)  -- skip '\n\r' or '\r\n'
  end
  ls.linenumber = ls.linenumber + 1
  if ls.linenumber >= self.MAX_INT then
    self:syntaxerror(ls, "chunk has too many lines")
  end
end

------------------------------------------------------------------------
-- initializes an input stream for lexing
-- * if ls (the lexer state) is passed as a table, then it is filled in,
--   otherwise it has to be retrieved as a return value
-- * LUA_MINBUFFER not used; buffer handling not required any more
------------------------------------------------------------------------
function luaX:setinput(L, ls, z, source)
  if not ls then ls = {} end  -- create struct
  if not ls.lookahead then ls.lookahead = {} end
  if not ls.t then ls.t = {} end
  ls.decpoint = "."
  ls.L = L
  ls.lookahead.token = "TK_EOS"  -- no look-ahead token
  ls.z = z
  ls.fs = nil
  ls.linenumber = 1
  ls.lastline = 1
  ls.source = source
  ls.safeenv = true
  ls.usedglobals = {}
  self:nextc(ls)  -- read first char
end

--[[--------------------------------------------------------------------
-- LEXICAL ANALYZER
----------------------------------------------------------------------]]

------------------------------------------------------------------------
-- checks if current character read is found in the set 'set'
------------------------------------------------------------------------
function luaX:check_next(ls, set)
  if not string.find(set, ls.current, 1, 1) then
    return false
  end
  self:save_and_next(ls)
  return true
end

------------------------------------------------------------------------
-- retrieve next token, checking the lookahead buffer if necessary
-- * note that the macro next(ls) in llex.c is now luaX:nextc
-- * utilized used in lparser.c (various places)
------------------------------------------------------------------------
function luaX:next(ls)
  ls.lastline = ls.linenumber
  if ls.lookahead.token ~= "TK_EOS" then  -- is there a look-ahead token?
    -- this must be copy-by-value
    ls.t.seminfo = ls.lookahead.seminfo  -- use this one
    ls.t.token = ls.lookahead.token
    ls.lookahead.token = "TK_EOS"  -- and discharge it
  else
    ls.t.token, ls.t.seminfo, ls.linenumber = self:poptk(ls)  -- read next token
  end
end

------------------------------------------------------------------------
-- fill in the lookahead buffer
-- * utilized used in lparser.c:constructor
-- * Does currently nothing because of lexer caching
------------------------------------------------------------------------
function luaX:lookahead(ls)
  -- lua_assert(ls.lookahead.token == "TK_EOS")
  ls.lookahead.token, ls.lookahead.seminfo, ls.lookahead.linenumber = self:poptk(ls)--self:llex(ls, ls.lookahead)
end

------------------------------------------------------------------------
-- gets the next character and returns it
-- * this is the next() macro in llex.c; see notes at the beginning
------------------------------------------------------------------------
function luaX:nextc(ls)
  local c = luaZ:zgetc(ls.z)
  ls.current = c
  return c
end

------------------------------------------------------------------------
-- saves the given character into the token buffer
-- * buffer handling code removed, not used in this implementation
-- * test for maximum token buffer length not used, makes things faster
------------------------------------------------------------------------

function luaX:save(ls, c)
  local buff = ls.buff
  -- if you want to use this, please uncomment luaX.MAX_SIZET further up
  --if #buff > self.MAX_SIZET then
  --  self:lexerror(ls, "lexical element too long")
  --end
  ls.buff = buff..c
end

------------------------------------------------------------------------
-- save current character into token buffer, grabs next character
-- * like luaX:nextc, returns the character read for convenience
------------------------------------------------------------------------
function luaX:save_and_next(ls)
  self:save(ls, ls.current)
  return self:nextc(ls)
end

------------------------------------------------------------------------
-- LUA_NUMBER
-- * luaX:read_numeral is the main lexer function to read a number
-- * luaX:str2d, luaX:buffreplace, luaX:trydecpoint are support functions
------------------------------------------------------------------------

------------------------------------------------------------------------
-- string to number converter (was luaO_str2d from lobject.c)
-- * returns the number, nil if fails (originally returns a boolean)
-- * conversion function originally lua_str2number(s,p), a macro which
--   maps to the strtod() function by default (from luaconf.h)
-- * ccuser44 was here to add support for binary intiger constants and
--   intiger decimal seperators
------------------------------------------------------------------------
function luaX:str2d(s)
	-- Support for Luau decimal seperators for integer literals
	if string.match(string.lower(s), "[^b%da-f_]_") or string.match(string.lower(s), "_[^%da-f_]") then
		return nil
	end
	s = string.gsub(s, "_", "")

	local result = tonumber(s)
	if result then return result end
	-- conversion failed

	if string.lower(string.sub(s, 1, 2)) == "0x" then  -- maybe an hexadecimal constant?
		result = tonumber(s, 16)
		if result then return result end  -- most common case
		-- Was: invalid trailing characters?
		-- In C, this function then skips over trailing spaces.
		-- true is returned if nothing else is found except for spaces.
		-- If there is still something else, then it returns a false.
		-- All this is not necessary using Lua's tonumber.
	elseif string.lower(string.sub(s, 1, 2)) == "0b" then  -- binary intiger constants
		if string.match(string.sub(s, 3), "[^01]") then
			return nil
		end

		local bin = string.reverse(string.sub(s, 3))
		local sum = 0

		for i = 1, string.len(bin) do
			sum = sum + bit32.lshift(string.sub(bin, i, i) == "1" and 1 or 0, i - 1)
		end

		return sum
	end
	return nil
end

------------------------------------------------------------------------
-- single-character replacement, for locale-aware decimal points
------------------------------------------------------------------------
function luaX:buffreplace(ls, from, to)
  local result, buff = "", ls.buff
  for p = 1, #buff do
    local c = string.sub(buff, p, p)
    if c == from then c = to end
    result = result..c
  end
  ls.buff = result
end

------------------------------------------------------------------------
-- Attempt to convert a number by translating '.' decimal points to
-- the decimal point character used by the current locale. This is not
-- needed in Yueliang as Lua's tonumber() is already locale-aware.
-- Instead, the code is here in case the user implements localeconv().
------------------------------------------------------------------------
function luaX:trydecpoint(ls, Token)
  -- format error: try to update decimal point separator
  local old = ls.decpoint
  -- translate the following to Lua if you implement localeconv():
  -- struct lconv *cv = localeconv();
  -- ls->decpoint = (cv ? cv->decimal_point[0] : '.');
  self:buffreplace(ls, old, ls.decpoint)  -- try updated decimal separator
  local seminfo = self:str2d(ls.buff)
  Token.seminfo = seminfo
  if not seminfo then
    -- format error with correct decimal point: no more options
    self:buffreplace(ls, ls.decpoint, ".")  -- undo change (for error message)
    self:lexerror(ls, "malformed number", "TK_NUMBER")
  end
end

------------------------------------------------------------------------
-- main number conversion function
-- * "^%w$" needed in the scan in order to detect "EOZ"
------------------------------------------------------------------------
function luaX:read_numeral(ls, Token)
  -- lua_assert(string.find(ls.current, "%d"))
  repeat
    self:save_and_next(ls)
  until string.find(ls.current, "%D") and ls.current ~= "."
  if self:check_next(ls, "Ee") then  -- 'E'?
    self:check_next(ls, "+-")  -- optional exponent sign
  end
  while string.find(ls.current, "^%w$") or ls.current == "_" do
    self:save_and_next(ls)
  end
  self:buffreplace(ls, ".", ls.decpoint)  -- follow locale for decimal point
  local seminfo = self:str2d(ls.buff)
  Token.seminfo = seminfo
  if not seminfo then  -- format error?
    self:trydecpoint(ls, Token) -- try to update decimal point separator
  end
end

------------------------------------------------------------------------
-- count separators ("=") in a long string delimiter
-- * used by luaX:read_long_string
------------------------------------------------------------------------
function luaX:skip_sep(ls)
  local count = 0
  local s = ls.current
  -- lua_assert(s == "[" or s == "]")
  self:save_and_next(ls)
  while ls.current == "=" do
    self:save_and_next(ls)
    count = count + 1
  end
  return (ls.current == s) and count or (-count) - 1
end

------------------------------------------------------------------------
-- reads a long string or long comment
------------------------------------------------------------------------
function luaX:read_long_string(ls, Token, sep)
  local cont = 0
  self:save_and_next(ls)  -- skip 2nd '['
  if self:currIsNewline(ls) then  -- string starts with a newline?
    self:inclinenumber(ls)  -- skip it
  end
  while true do
    local c = ls.current
    if c == "EOZ" then
      self:lexerror(ls, Token and "unfinished long string" or
                    "unfinished long comment", "TK_EOS")
    elseif c == "[" then
      --# compatibility code start
      if self.LUA_COMPAT_LSTR then
        if self:skip_sep(ls) == sep then
          self:save_and_next(ls)  -- skip 2nd '['
          cont = cont + 1
          --# compatibility code start
          if self.LUA_COMPAT_LSTR == 1 then
            if sep == 0 then
              self:lexerror(ls, "nesting of [[...]] is deprecated", "[")
            end
          end
          --# compatibility code end
        end
      end
      --# compatibility code end
    elseif c == "]" then
      if self:skip_sep(ls) == sep then
        self:save_and_next(ls)  -- skip 2nd ']'
        --# compatibility code start
        if self.LUA_COMPAT_LSTR and self.LUA_COMPAT_LSTR == 2 then
          cont = cont - 1
          if sep == 0 and cont >= 0 then break end
        end
        --# compatibility code end
        break
      end
    elseif self:currIsNewline(ls) then
      self:save(ls, "\n")
      self:inclinenumber(ls)
      if not Token then ls.buff = "" end -- avoid wasting space
    else  -- default
      if Token then
        self:save_and_next(ls)
      else
        self:nextc(ls)
      end
    end--if c
  end--while
  if Token then
    local p = 3 + sep
    Token.seminfo = string.sub(ls.buff, p, -p)
  end
end

------------------------------------------------------------------------
-- reads a string
-- * has been restructured significantly compared to the original C code
-- * ccuser44 was here to add support for UTF8 string literals,
-- hex numerical string literals and the \z string literal
------------------------------------------------------------------------

function luaX:read_string(ls, del, Token)
	self:save_and_next(ls)
	while ls.current ~= del do
		local c = ls.current
		if c == "EOZ" then
			self:lexerror(ls, "unfinished string", "TK_EOS")
		elseif self:currIsNewline(ls) then
			self:lexerror(ls, "unfinished string", "TK_STRING")
		elseif c == "\\" then
			c = self:nextc(ls)  -- do not save the '\'
			if self:currIsNewline(ls) then  -- go through
				self:save(ls, "\n")
				self:inclinenumber(ls)
			elseif c ~= "EOZ" then -- will raise an error next loop
				-- escapes handling greatly simplified here:
				local i = string.find("abfnrtv", c, 1, 1)
				if i then
					self:save(ls, string.sub("\a\b\f\n\r\t\v", i, i))
					self:nextc(ls)
				elseif c == "u" then -- UTF8 string literal
					assert(utf8 and utf8.char, "No utf8 library found! Cannot decode UTF8 string literal!")

					if self:nextc(ls) ~= "{" then
						self:lexerror("Sounds like a skill issue", "TK_STRING")
					end

					local unicodeCharacter = ""

					while true do
						c = self:nextc(ls)

						if c == "}" then
							break
						elseif string.match(c, "%x") then
							unicodeCharacter = unicodeCharacter .. c
						else
							self:lexerror(string.format("Invalid unicode character sequence. Expected alphanumeric character, got %s. Did you forget to close the code sequence with a curly bracket?", c), "TK_STRING")
						end
					end

					if not tonumber(unicodeCharacter, 16) or not utf8.char(tonumber(unicodeCharacter, 16)) then
						self:lexerror(string.format("Invalid UTF8 char %s. Expected a valid UTF8 character code", unicodeCharacter), "TK_STRING")
					else
						self:save(ls, utf8.char(tonumber(unicodeCharacter)))
					end
				elseif string.lower(c) == "x" then -- Hex numeral literal
					local hexNum = self:nextc(ls)..self:nextc(ls)

					if not string.match(string.upper(hexNum), "%x") then
						self:lexerror(string.format("Invalid hex string literal. Expected valid string literal, got %s", hexNum), "TK_STRING")
					else
						self:save(ls, string.char(tonumber(hexNum, 16)))
					end
				elseif string.lower(c) == "z" then -- Support \z string literal. I'm not sure why you would want to use this
					local c = luaX:nextc(ls)

					if c == del then
						break
					else
						self:save(ls, c)
					end
				elseif not string.find(c, "%d") then
					self:save_and_next(ls)  -- handles \\, \", \', and \?
				else  -- \xxx
					c, i = 0, 0
					repeat
						c = 10 * c + ls.current
						self:nextc(ls)
						i = i + 1
					until i >= 3 or not string.find(ls.current, "%d")
					if c > 255 then  -- UCHAR_MAX
						self:lexerror(ls, "escape sequence too large", "TK_STRING")
					end
					self:save(ls, string.char(c))
				end
			end
		else
			self:save_and_next(ls)
		end--if c
	end--while
	self:save_and_next(ls)  -- skip delimiter
	Token.seminfo = string.sub(ls.buff, 2, -2)
end

------------------------------------------------------------------------
-- lexer cache
-- * Pre-lex the whole lex tree and then cache it
--   Allow global optimisation by scanning all lex tokens before parsing
------------------------------------------------------------------------

function luaX:poptk(ls)
	if ls.lexercache then
		local tkdata = ls.lexercache
		local data = tkdata[tkdata.n]
		tkdata.n, tkdata[tkdata.n] = tkdata.n - 1, nil

		return data.type or "TK_EOS", data.seminfo or "", data.line
	end

	-- Generate lex tree stack
	local tkdata = {}
	ls.lexercache = tkdata
	while true do
		local type = luaX:llex(ls, ls.t)

		table.insert(tkdata, {
			type = type,
			seminfo = ls.t.seminfo,
			line = ls.linenumber,
		})

		if type == "TK_EOS" then
			break
		end
	end

	-- Reverse lex tree stack
	local len = #tkdata
	tkdata.n = len
	ls.linenumber, ls.lastline, ls.lookahead.token = 1, 1, "TK_EOS"
	for i = 1, math.floor(len/2) do
		local j = len - i + 1
		tkdata[i], tkdata[j] = tkdata[j], tkdata[i]
	end

	-- Ugly hack to support global localisation without parser logic
	-- TODO: Switch to parser logic LOCALEXP(name) = GLOBALEXP(name), ...
	local usedglobals = ls.usedglobals
	if ls.safeenv and #usedglobals > 0 then
		for i = #usedglobals, 1, -1 do
			tkdata.n = tkdata.n + 2
			tkdata[tkdata.n - 1], tkdata[tkdata.n] = {
				type = "TK_NAME",
				seminfo = usedglobals[i],
				line = 1
			}, {
				type = ",",
				seminfo = ",",
				line = 1
			}
		end
		tkdata[tkdata.n] = {
			type = "=",
			seminfo = "=",
			line = 1
		}
		for i = #usedglobals, 1, -1 do
			tkdata.n = tkdata.n + 2
			tkdata[tkdata.n - 1], tkdata[tkdata.n] = {
				type = "TK_NAME",
				seminfo = usedglobals[i],
				line = 1
			}, {
				type = ",",
				seminfo = ",",
				line = 1
			}
		end
		tkdata[tkdata.n] = {
			type = "TK_LOCAL",
			seminfo = "local",
			line = 1
		}
	end

	return self:poptk(ls)
end

------------------------------------------------------------------------
-- main lexer function
------------------------------------------------------------------------
function luaX:llex(ls, Token)
  ls.buff = ""
  while true do
    local c = ls.current
    ----------------------------------------------------------------
    if self:currIsNewline(ls) then
      self:inclinenumber(ls)
    ----------------------------------------------------------------
    elseif c == "-" then
      c = self:nextc(ls)
      if c == "=" then self:nextc(ls); return "TK_ASSIGN_SUB" -- Luau Compound 
      elseif c ~= "-" then return "-" end
      -- else is a comment
      local sep = -1
      if self:nextc(ls) == '[' then
        sep = self:skip_sep(ls)
        ls.buff = ""  -- 'skip_sep' may dirty the buffer
      end
      if sep >= 0 then
        self:read_long_string(ls, nil, sep)  -- long comment
        ls.buff = ""
      else  -- else short comment
        while not self:currIsNewline(ls) and ls.current ~= "EOZ" do
          self:nextc(ls)
        end
      end
    ----------------------------------------------------------------
    elseif c == "[" then
      local sep = self:skip_sep(ls)
      if sep >= 0 then
        self:read_long_string(ls, Token, sep)
        return "TK_STRING"
      elseif sep == -1 then
        return "["
      else
        self:lexerror(ls, "invalid long string delimiter", "TK_STRING")
      end
    ---------------------Luau Compound Start------------------------
    elseif c == "+" then
      c = self:nextc(ls)
      if c ~= "=" then return "+"
      else self:nextc(ls); return "TK_ASSIGN_ADD" end
    ----------------------------------------------------------------
    elseif c == "*" then
      c = self:nextc(ls)
      if c ~= "=" then return "*"
      else self:nextc(ls); return "TK_ASSIGN_MUL" end
    ----------------------------------------------------------------
    elseif c == "/" then
      c = self:nextc(ls)
      if c ~= "=" then return "/"
      else self:nextc(ls); return "TK_ASSIGN_DIV" end
    ----------------------------------------------------------------
    elseif c == "%" then
      c = self:nextc(ls)
      if c ~= "=" then return "%"
      else self:nextc(ls); return "TK_ASSIGN_MOD" end
    ----------------------------------------------------------------
    elseif c == "^" then
      c = self:nextc(ls)
      if c ~= "=" then return "^"
      else self:nextc(ls); return "TK_ASSIGN_POW" end
    ----------------------------------------------------------------
    --             TODO: TK_ASSIGN_CONCAT support                 --
    ----------------------Luau Compound End-------------------------
    elseif c == "=" then
      c = self:nextc(ls)
      if c ~= "=" then return "="
      else self:nextc(ls); return "TK_EQ" end
    ----------------------------------------------------------------
    elseif c == "<" then
      c = self:nextc(ls)
      if c ~= "=" then return "<"
      else self:nextc(ls); return "TK_LE" end
    ----------------------------------------------------------------
    elseif c == ">" then
      c = self:nextc(ls)
      if c ~= "=" then return ">"
      else self:nextc(ls); return "TK_GE" end
    ----------------------------------------------------------------
    elseif c == "~" then
      c = self:nextc(ls)
      if c ~= "=" then return "~"
      else self:nextc(ls); return "TK_NE" end
    ----------------------------------------------------------------
    elseif c == "\"" or c == "'" then
      self:read_string(ls, c, Token)
      return "TK_STRING"
    ----------------------------------------------------------------
    elseif c == "." then
      c = self:save_and_next(ls)
      if self:check_next(ls, ".") then
        if self:check_next(ls, ".") then
          return "TK_DOTS"   -- ...
        else return "TK_CONCAT"   -- ..
        end
      elseif not string.find(c, "%d") then
        return "."
      else
        self:read_numeral(ls, Token)
        return "TK_NUMBER"
      end
    ----------------------------------------------------------------
    elseif c == "EOZ" then
      return "TK_EOS"
    ----------------------------------------------------------------
    else  -- default
      if string.find(c, "%s") then
        -- lua_assert(self:currIsNewline(ls))
        self:nextc(ls)
      elseif string.find(c, "%d") then
        self:read_numeral(ls, Token)
        return "TK_NUMBER"
      elseif string.find(c, "[_%a]") then
        -- identifier or reserved word
        repeat
          c = self:save_and_next(ls)
        until c == "EOZ" or not string.find(c, "[_%w]")
        local ts = ls.buff
        local tok = self.enums[ts]
        if tok then return tok end  -- reserved word?

		-- Global optimisation helper
		if self.DEOP[ts] then
		  ls.safeenv = false
		elseif self.globalvars[ts] and not table.find(ls.usedglobals, ts) then
		  table.insert(ls.usedglobals, ts)
		end

        Token.seminfo = ts
        return "TK_NAME"
      else
        self:nextc(ls)
        return c  -- single-char tokens (+ - / ...)
      end
    ----------------------------------------------------------------
    end--if c
  end--while
end

return luaX
