Not a member of Pastebin yet?
Sign Up,
it unlocks many cool features!
- local c=require("30log")local function d(...)local e={}for t,n in ipairs({...})do
- e[n]=true
- end
- return e
- end
- local n=c("Lexer")function n:init(t,n,e)self.pos=1
- self.col=1
- self.line=1
- self.source=t
- self.file=n or"<unnamed>"self.colored=type(e)=="boolean"and e or true
- self.highlight={}end
- function n:peek(e)e=e or 0
- return self.source:sub(self.pos+e,(utf8.offset(self.source,2,self.pos+e)or(self.pos+e+1))-1)end
- function n:next()if self.nsaved then
- self.nsaved=nil
- return"\n"end
- local e=self.source:sub(self.pos,utf8.offset(self.source,2,self.pos)-1)self.pos=self.pos+#e
- self.col=self.col+1
- if e=="\r"or e=="\n"then
- if e=="\r"and self:peek()=="\n"then
- self.pos=self.pos+1
- self.nsaved=true
- end
- self.col=1
- self.line=self.line+1
- end
- return e
- end
- function n:pmatch(e)local e={self.source:sub(self.pos):find("^"..e)}if#e==0 then return end
- local t,n=table.remove(e,1),table.remove(e,1)return self.source:sub(self.pos+t-1,self.pos+n-1),table.unpack(e)end
- function n:match(e)local e={self:pmatch(e)}if#e>0 then
- self.pos=self.pos+#e[1]self.col=self.col+#e[1]return table.unpack(e)end
- end
- function n:getline(n)if n<1 then return end
- local e=1
- for t in self.source:gmatch("([^\r\n]*)\r?\n?")do
- if e==n then
- return t
- end
- e=e+1
- end
- end
- function n:showSlice(e,n)if self.colored then
- for e in self:lex()do end
- end
- local l=math.ceil(math.log(math.max(e[1],e[3]),10))if l==0 then l=1 end
- if self.colored then
- print(("\27[1;34m%s-->\27[0m %s:%d:%d"):format((" "):rep(l),self.file,e[1],e[2]))else
- print(("%s--> %s:%d:%d"):format((" "):rep(l),self.file,e[1],e[2]))end
- for n=e[1]-2,e[3]+2 do
- local t=self:getline(n)if not t then goto continue end
- if self.colored then
- io.write(("\27[1;34m%"..l.."d |\27[0m "):format(n))local e=1
- while#t>0 do
- local l=t:sub(1,utf8.offset(t,2)-1)if self.highlight[n]and self.highlight[n][e]then
- io.write("\27[0m"..self.highlight[n][e])end
- io.write(l)e=e+1
- t=t:sub(utf8.offset(t,2))end
- print("\27[0m")end
- if n>=e[1]and n<=e[3]then
- if self.colored then
- io.write("\27[1;34m")end
- io.write((" "):rep(l+1).."| ")if self.colored then
- io.write("\27[31m")end
- io.write((" "):rep(n==e[1]and(e[2]-1)or 0))io.write(("~"):rep((n==e[3]and e[4]or(utf8.len(t)+1))-(n==e[1]and e[2]or 1)))io.write((n==e[3]and"^"or""))if self.colored then
- io.write("\27[0m")end
- io.write("\n")end::continue::end
- return l
- end
- function n:error(e,t)coroutine.yield("error",e,t)end
- n.COLORS={keyword="\27[1;36m",punct="\27[1;37m",number="\27[33m",string="\27[32m",name="",comment="\27[37m"}function n:pushcolor(e,t)if not self.colored then
- return
- end
- if n.KEYWORDS[e]then
- e="keyword"end
- if n.OPS[3][e]then
- e="punct"end
- local n=n.COLORS[e]for e=t[1],t[3]do
- if not self.highlight[e]then
- self.highlight[e]={}end
- self.highlight[e][e==t[1]and t[2]or 1]=n
- end
- end
- function n:token(e,l,t)if not self.colored then
- coroutine.yield(e,l,t)return
- end
- self:pushcolor(e,t)coroutine.yield(e,l,t)end
- n.WHITESPACE=d(" ","\t","\n","\v","\f","\r")n.KEYWORDS=d("and","break","do","else","elseif","end","false","for","function","goto","if","in","local","nil","not","or","repeat","return","then","true","until","while")n.OPS={}n.OPS[3]=d("+","-","*","/","%","^","#","&","~","|","<<",">>","//","==","~=","<=",">=","<",">","=","(",")","{","}","[","]","::",";",":",",",".","..","...")n.OPS[1]={}do
- for e in pairs(n.OPS[3])do
- n.OPS[1][e:sub(1,1)]=true
- end
- end
- n.OPS[2]={}do
- for e in pairs(n.OPS[3])do
- n.OPS[2][e:sub(1,2)]=true
- end
- end
- function n.isnamehead(e)return(e>="a"and e<="z")or(e>="A"and e<="Z")or e=="_"end
- function n.isdigit(e)return(e>="0"and e<="9")end
- function n:lexc()local e=""while self:peek()~=""do
- local t=self:peek()if self:pmatch("%-%-")then
- self:comment()goto continue
- end
- if self:pmatch("%[=*%[")then
- self:longstring()goto continue
- end
- if#e==0 and n.OPS[1][t]then
- self.broken=nil
- e=e..t
- self:next()goto continue
- elseif#e==1 and n.OPS[2][e..t]and not self.broken then
- e=e..t
- self:next()goto continue
- elseif#e==2 and n.OPS[3][e..t]and not self.broken then
- e=e..t
- self:next()goto continue
- elseif#e>0 then
- self:token(e,nil,{self.line,self.col-#e,self.line,self.col-1})e=""self.broken=nil
- end
- if#e==0 and n.OPS[1][t]then
- self.broken=nil
- e=e..t
- self:next()goto continue
- elseif#e==1 and n.OPS[2][e..t]and not self.broken then
- e=e..t
- self:next()goto continue
- elseif#e==2 and n.OPS[3][e..t]and not self.broken then
- e=e..t
- self:next()goto continue
- end
- if n.WHITESPACE[t]then
- self:next()elseif t=="'"or t=='"'then
- self:string()elseif n.isnamehead(t)then
- self:name()elseif n.isdigit(t)or(t=="."and n.isdigit((self:peek(1))))then
- self:number()else
- self:error(("unexpected symbol `%s`"):format(t),{self.line,self.col,self.line,self.col})end::continue::end
- if#e>0 then
- self:token(e,nil,{self.line,self.col-1,self.line,self.col-1})end
- end
- function n:name()local t,l=self.line,self.col
- local e=self:match("[a-zA-Z_][a-zA-Z0-9_]*")if n.KEYWORDS[e]then
- self:token(e,nil,{t,l,self.line,self.col-1})else
- self:token("name",e,{t,l,self.line,self.col-1})end
- end
- function n:number()local t,l=self.line,self.col
- local e
- e=self:match("0[xX]%x+%.?%x*[eEpP][+-]?%d+")e=e or self:match("0[xX]%x+%.?%x*")e=e or self:match("0[xX]%x*%.?%x+[eEpP][+-]?%d+")e=e or self:match("0[xX]%x*%.?%x+")e=e or self:match("%d+%.?%d*[eE][+-]?%d+")e=e or self:match("%d+%.?%d*")e=e or self:match("%d*%.?%d+[eE][+-]?%d+")e=e or self:match("%d*%.?%d+")if n.isnamehead(self:peek())then
- e=nil
- end
- if e then
- self:token("number",tonumber(e),{t,l,self.line,self.col-1})else
- self:error("malformed number",{t,l,t,l})end
- end
- function n:comment()self.broken=true
- local e,t=self.line,self.col
- self:next()self:next()local o,l=self:match("%[(=*)%[")if not l then
- self:match("[^\r\n]*")self:pushcolor("comment",{e,t,self.line,self.col})return
- else
- local n=self:match("(.-)%]"..l.."%]")self:pushcolor("comment",{e,t,self.line,self.col})if n then return end
- end
- self:error("unfinished long comment",{e,t,e,t+3+#l})end
- n.CESCAPES={["a"]="\a",["b"]="\b",["f"]="\f",["n"]="\n",["r"]="\r",["t"]="\t",["v"]="\v",["\\"]="\\",['"']='"',["'"]="'",}function n:longstring()local n,e=self.line,self.col
- local l,t=self:match("%[(=*)%[")local o,l=self:match("(.-)%]"..t.."%]")if l then
- self:token("string",l,{n,e,self.line,self.col})else
- self:error("unfinished long string",{n,e,n,e+1+#t})end
- end
- function n:string()local l,t=self.line,self.col
- local e=1
- local d=self:next()local r=false
- local i=""while true do
- local o=self:peek()if o==""then
- self:error(("`%s` expected to close the string, found EOF"):format(d),{l,t+e,l,t})end
- if not r then
- if o=="\\"then
- r=true
- elseif o==d then
- self:next()self:token("string",i,{l,t,self.line,self.col-1})return
- elseif o=="\n"or o=="\r"then
- self:error(("`%s` expected to close the string, found EOL"):format(d),{l,t+e,l,t+e})else
- i=i..o
- end
- elseif n.CESCAPES[o]then
- i=i..n.CESCAPES[o]r=false
- elseif o=="z"then
- self:next()e=e+1
- while n.WHITESPACE[self:peek()]do
- self:next()e=e+1
- end
- r=false
- goto continue
- elseif o=="x"then
- self:next()e=e+1
- local n=self:match("%x%x")if not n then
- self:error("invalid hexadecimal escape sequence",{l,t+e-2,l,t+e-1})end
- e=e+2
- i=i..string.char(tonumber(n,16))r=false
- goto continue
- elseif n.isdigit(o)then
- local n=self:match("%d%d?%d?")if tonumber(n)>255 then
- self:error("invalid decimal escape sequence (too large)",{l,t+e-1,l,t+e+#n-1})end
- e=e+#n
- i=i..string.char(tonumber(n))r=false
- goto continue
- elseif o=="u"then
- self:next()e=e+1
- local n,o=self:match("{(%x+)}")if not n then
- self:error("invalid UTF-8 escape sequence",{l,t+e-2,l,t+e-1})end
- if not pcall(utf8.char,tonumber(o,16))then
- self:error("invalid UTF-8 escape sequence (out of range)",{l,t+e-2,l,t+e+#n-1})end
- e=e+#n
- i=i..utf8.char(tonumber(o,16))r=false
- goto continue
- else
- self:error("invalid escape sequence",{l,t+e-1,l,t+e-1})end
- self:next()e=e+1::continue::end
- end
- function n:lex()local e=coroutine.create(function()return self:lexc()end)local n=false
- return function()local e={coroutine.resume(e)}if not n and table.remove(e,1)then
- if e[1]=="error"then
- n=true
- end
- return e[1],e[2],e[3]end
- end
- end
- local e=c("Parser")function e:init(e)self.l=e
- self.tokens=self.l:lex()self.saved={}self.pos=1
- end
- function e:peek()if not self.saved[self.pos]then
- self.saved[self.pos]={self.tokens()}end
- return table.unpack(self.saved[self.pos])end
- function e:next()local e={self:peek()}if self.saving then
- self.pos=self.pos+1
- self.previous=self.saved[self.pos-2]else
- self.previous=table.remove(self.saved,self.pos)end
- return table.unpack(e)end
- function e:save()self.saving=true
- end
- function e:restore()self.saving=false
- self.pos=1
- end
- function e:commit()self.saved={self.saved[self.pos]}self.saving=false
- self.pos=1
- end
- function e.node(e,n,t)return{ty=e,data=n,slice=t}end
- local function t(e)return e:gsub("\\","\\\\"):gsub("\n","\\n"):gsub("\r","\\r"):gsub("'","\\'"):gsub("\t","\\t"):gsub("\v","\\v"):gsub("\f","\\f"):gsub("\a","\\a"):gsub("\b","\\b")end
- function e:showNode(o)local function n(e)if e.ty=="name"then
- return e.data
- elseif e.ty=="number"then
- return tostring(e.data)elseif e.ty=="nil"then
- return"nil"elseif e.ty=="boolean"then
- return tostring(e.data)elseif e.ty=="string"then
- return("('%s')"):format(t(e.data))elseif e.ty=="dots"then
- return"..."elseif e.ty=="binop"then
- return"("..n(e.data.lhs).." "..e.data.op.." "..n(e.data.rhs)..")"elseif e.ty=="unop"then
- return e.data.op.." "..n(e.data.node)elseif e.ty=="index"then
- return n(e.data.indexing).."["..n(e.data.index).."]"elseif e.ty=="call"then
- local t=n(e.data.callable).."("for l,e in ipairs(e.data.args)do
- if l>1 then
- t=t..", "end
- t=t..n(e)end
- return t..")"elseif e.ty=="methodcall"then
- local t=n(e.data.callable)..":"..n(e.data.method).."("for l,e in ipairs(e.data.args)do
- if l>1 then
- t=t..", "end
- t=t..n(e)end
- return t..")"elseif e.ty=="table"then
- local t="{"local l={}for e,l in ipairs(e.data.seq)do
- if e>1 then
- t=t..", "end
- t=t..n(l)end
- for e,l in pairs(e.data.map)do
- t=t.."["..n(e).."] = "..n(l)..", "end
- return t.."}"elseif e.ty=="emptystat"then
- return";"elseif e.ty=="do"then
- local t="do"for l,e in ipairs(e.data)do
- t=t.."\n"..n(e)end
- return t.."\nend"elseif e.ty=="if"then
- local t="if "..n(e.data.cond).." then"for l,e in ipairs(e.data.block)do
- t=t.."\n"..n(e)end
- for l,e in ipairs(e.data.pelseif)do
- t=t.."\nelseif "..n(e.cond).." then"for l,e in ipairs(e.block)do
- t=t.."\n"..n(e)end
- end
- if e.data.pelse then
- t=t.."\nelse"for l,e in ipairs(e.data.pelse)do
- t=t.."\n"..n(e)end
- end
- return t.."\nend"elseif e.ty=="while"then
- local t="while "..n(e.data.cond).." do"for l,e in ipairs(e.data.block)do
- t=t.."\n"..n(e)end
- return t.."\nend"elseif e.ty=="repeat"then
- local t="repeat"for l,e in ipairs(e.data.block)do
- t=t.."\n"..n(e)end
- return t.."\nuntil "..n(e.data.cond)elseif e.ty=="goto"then
- return"goto "..n(e.data)elseif e.ty=="label"then
- return"::"..n(e.data).."::"elseif e.ty=="break"then
- return"break"elseif e.ty=="return"then
- local t="return "for e,l in ipairs(e.data)do
- if e>1 then
- t=t..", "end
- t=t..n(l)end
- return t
- elseif e.ty=="for"then
- local t="for "if e.data.counter then
- t=t..n(e.data.counter).." = "..n(e.data.init)..", "..n(e.data.limit)..(e.data.step
- and(", "..n(e.data.step))or"")else
- for e,l in ipairs(e.data.names)do
- if e>1 then
- t=t..", "end
- t=t..n(l)end
- t=t.." in "for l,e in ipairs(e.data.exps)do
- if l>1 then
- t=t..", "end
- t=t..n(e)end
- end
- t=t.." do"for l,e in ipairs(e.data.block)do
- t=t.."\n"..n(e)end
- return t.."\nend"elseif e.ty=="assign"then
- local t=""for e,l in ipairs(e.data.vars)do
- if e>1 then
- t=t..", "end
- t=t..n(l)end
- t=t.." = "for l,e in ipairs(e.data.exps)do
- if l>1 then
- t=t..", "end
- t=t..n(e)end
- return t
- elseif e.ty=="decl"then
- local t="local "for e,l in ipairs(e.data.names)do
- if e>1 then
- t=t..", "end
- t=t..n(l)end
- if e.data.exps then
- t=t.." = "for l,e in ipairs(e.data.exps)do
- if l>1 then
- t=t..", "end
- t=t..n(e)end
- end
- return t
- elseif e.ty=="funcbody"then
- local t="function("for l,e in ipairs(e.data.pars)do
- if l>1 then
- t=t..", "end
- t=t..n(e)end
- t=t..")"for l,e in ipairs(e.data.block)do
- t=t.."\n"..n(e)end
- return t.."\nend"end
- end
- print(n(o))end
- function e:expected(l,t,e,o)if e=="error"then
- return nil,o,t
- end
- if n.KEYWORDS[e]then
- return nil,("%s expected, found keyword `%s`"):format(l,e),t
- end
- if n.OPS[3][e]then
- return nil,("%s expected, found `%s`"):format(l,e),t
- end
- if e=="number"then
- return nil,("%s expected, found number literal"):format(l),t
- end
- if e=="string"then
- return nil,("%s expected, found string literal"):format(l),t
- end
- if e=="EOF"then
- return nil,("%s expected, found EOF"):format(l),t
- end
- if e=="name"then
- return nil,("%s expected, found identifier"):format(l),t
- end
- return nil,("%s expected"):format(l),t
- end
- function e:unexpected(n,e)return nil,("unexpected %s"):format(n),e.slice
- end
- function e:name()local l,i=self.l.line,self.l.col
- local n,o,t=self:peek()if n and n=="name"then
- self:next()return e.node(n,o,t)else
- return self:expected("name",t or{l,i,l,i},n,o)end
- end
- function e:number()local t,l=self.l.line,self.l.col
- local n,o,i=self:peek()if n and n=="number"then
- self:next()return e.node(n,o,i)else
- return self:expected("number",i or{t,l,t,l},n,o)end
- end
- function e:string()local i,o=self.l.line,self.l.col
- local n,l,t=self:peek()if n and n=="string"then
- self:next()return e.node(n,l,t)else
- return self:expected("string",t or{i,o,i,o},n,l)end
- end
- function e:litntf()local l,o=self.l.line,self.l.col
- local n,i,t=self:peek()if n and n=="nil"then
- self:next()return e.node(n,i,t)elseif n and(n=="true"or n=="false")then
- self:next()return e.node("boolean",n=="true",t)else
- return self:expected("expression",t or{l,o,l,o},n,i)end
- end
- function e:expr()return self:l0()end
- function e:explist()local e,t,n=self:expr()if not e then return nil,t,n end
- local e={e}while true do
- if self:peek()==","then
- self:next()else
- break
- end
- local n,t,l=self:expr()if not n then return nil,t,l end
- table.insert(e,n)end
- return e
- end
- function e:namelist()local e,n,t=self:name()if not e then return nil,n,t end
- local e={e}while true do
- if self:peek()==","then
- self:save()self:next()else
- break
- end
- local n,t,t=self:name()if not n then
- self:restore()return e
- end
- self:commit()table.insert(e,n)end
- return e
- end
- function e:varlist()local e,n,t=self:var()if not e then return nil,n,t end
- local e={e}while true do
- if self:peek()==","then
- self:next()else
- break
- end
- local n,l,t=self:var()if not n then return nil,l,t end
- table.insert(e,n)end
- return e
- end
- function e:table()local t,l,n=self:peek()if t~="{"then
- return self:expected("`{`",n or{startLine,startCol,startLine,startCol},t,l)end
- self:next()local s,a=n[1],n[2]local t,l=s,a
- local c={map={},seq={}}local d=true
- while true do
- if d and self:peek()=="}"then
- break
- end
- if self:peek()=="error"then
- local t,e,n=self:peek()return nil,e,n
- end
- if not d then
- local e,n,n=self:peek()if e~=","and e~=";"then
- break
- else
- self:next()end
- end
- if self:peek()=="}"then
- break
- end
- local n,e,i,o,a,r
- e,i,o=self:expr()if self:peek()=="error"then
- local t,n,e=self:peek()return nil,n,e
- end
- if self:peek()=="["then
- self:next()n,i,o=self:expr()if not n then return nil,i,o end
- local e,t,n=self:next()if e~="]"then
- return self:expected("`]`",n or{self.l.line,self.l.col,self.l.line,self.l.col},e,t)end
- a=true
- elseif e then
- n=e
- e=nil
- r=true
- else
- return nil,i,o
- end
- if a or self:peek()=="="then
- if r and n.ty~="name"then
- return self:expected("table index",n.slice,"expression")end
- if r then
- n.ty="string"end
- local o,l,t=self:next()if o~="="then
- return self:expected("`=`",t or{self.l.line,self.l.col,self.l.line,self.l.col},o,l)end
- e,l,t=self:expr()if not e then return nil,l,t end
- c.map[n]=e
- else
- e=n
- table.insert(c.seq,e)end
- t,l=e.slice[3],e.slice[4]d=false
- end
- if self:peek()==","or self:peek()==";"then
- local e=select(3,self:peek())t,l=e[3],e[4]self:next()end
- local o,i,n=self:next()if o~="}"then
- return self:expected("`}`",n or{t,l+1,t,l+1},o,i)end
- return e.node("table",c,{s,a,n[3],n[4]})end
- function e:args()local n,t=self.l.line,self.l.col
- if self:peek()=="("then
- self:next()if self:peek()==")"then
- local e=select(3,self:next())return{},nil,{n,t,e[3],e[4]}end
- local e,l,o=self:explist()if not e then return nil,l,o end
- local l=e[#e].slice
- local i,r,o=self:next()if i~=")"then
- return self:expected("`)`",o or{l[3],l[4]+1,l[3],l[4]+1},i,r)end
- return e,nil,{n,t,o[3],o[4]}end
- local e,l
- e,_,l=self:string()if not e then
- e,_,l=self:table()end
- if e then
- return{e},nil,{n,t,e.slice[3],e.slice[4]}end
- return self:expected("function arguments",{n,t,n,t})end
- function e:prefixexp()local n
- if self:peek()=="("then
- self:next()local e,t,l=self:expr()if not e then return nil,t,l end
- local t,l,o=self:next()if t~=")"then
- return self:expected("`)`",o or{e.slice[3],e.slice[4]+1,e.slice[3],e.slice[4]+1},t,l)end
- n=e
- else
- n,_,slice=self:name()end
- if not n then
- return self:expected("expression",slice,select(1,self:peek()),select(2,self:peek()))end
- while true do
- local t=self:peek()if t=="."then
- self:next()local t,o,l=self:name()if not t then return o,l end
- t.ty="string"n=e.node("index",{indexing=n,index=t},{n.slice[1],n.slice[2],t.slice[3],t.slice[4]})elseif t=="["then
- local t,t
- self:next()local o,t,l=self:expr()if not o then return nil,t,l end
- local l,i,t=self:next()if l~="]"then
- return self:expected("a closing square bracket",t or{self.l.line,self.l.col,self.l.line,self.l.col},l,i)end
- n=e.node("index",{indexing=n,index=o},{n.slice[1],n.slice[2],t[3],t[4]})elseif t=="("or t=="{"or t=="string"then
- local l,o,t=self:args()if not l then return nil,o,t end
- n=e.node("call",{callable=n,args=l},{n.slice[1],n.slice[2],t[3],t[4]})elseif t==":"then
- self:next()local o,l,t=self:name()if not o then return l,t end
- local l,i,t=self:args()if not l then return nil,i,t end
- n=e.node("methodcall",{callable=n,method=o,args=l},{n.slice[1],n.slice[2],t[3],t[4]})else
- break
- end
- end
- return n
- end
- function e:var()local e,n,t=self:prefixexp()if not e then return nil,n,t end
- if e.ty=="call"or e.ty=="methodcall"then
- return nil,"function call is not a variable",e.slice
- end
- return e
- end
- function e:parlist()if self:peek()=="..."then
- local n=select(3,self:peek())self:next()return{e.node("dots",nil,n)}end
- local t,n,l=self:namelist()if not t then return nil,n,l end
- if self:peek()==","then
- local n=select(3,self:next())if self:peek()~="..."then
- return self:expected("expression or `...`",{n[1],n[2]+1,n[3],n[4]+1})end
- local n=select(3,self:next())table.insert(t,e.node("dots",nil,n))end
- return t
- end
- function e:funcbody(s)local t,l,n=self:peek()if t~="("then
- return self:expected("`(`",n or{self.l.line,self.l.col,self.l.line,self.l.col},t,l)end
- self:next()local r,c=n[1],n[2]local l,o=r,c
- local n=self:parlist()or{}l,o=n[#n]and n[#n].slice[3]or l,n[#n]and n[#n].slice[4]or o
- local t,d,i=self:next()if t~=")"then
- return self:expected("`)`",i or{self.l.line,self.l.col,self.l.line,self.l.col},t,d)end
- local t,d,i=self:block()if not t then return nil,d,i end
- l,o=t[#t]and t[#t].slice[3]or l,t[#t]and t[#t].slice[4]or o
- local d,a,i=self:peek()if d~="end"then
- return self:expected("`end`",i or{l,o+1,l,o+1},d,a)end
- self:next()if s then
- table.insert(n,1,e.node("name","self"))end
- return e.node("funcbody",{pars=n,block=t},{r,c,i[3],i[4]})end
- function e:functiondef()local e,t,n=self:peek()if e~="function"then
- return self:expected("`function`",n or{self.l.line,self.l.col,self.l.line,self.l.col},e,t)end
- self:next()return self:funcbody()end
- function e:term()local n,n,n,n,n
- if not self:peek()then
- local e=self.previous and self.previous[3]return self:expected("expression",e and{e[3],e[4]+1,e[3],e[4]+1}or{self.l.line,self.l.col,self.l.line,self.l.col},"EOF")end
- if self:peek()=="error"then
- local e={self:peek()}e[1]=nil
- return table.unpack(e)end
- local n=self:peek()if n=="number"then
- return self:number()elseif n=="nil"or n=="true"or n=="false"then
- return self:litntf()elseif n=="string"then
- return self:string()elseif n=="{"then
- return self:table()elseif n=="function"then
- return self:functiondef()elseif n=="..."then
- return e.node("dots",nil,select(3,self:next()))else
- return self:prefixexp()end
- end
- function e.lassoc(o,...)local i=d(...)return function(n)local d,r=n.l.line,n.l.col
- local t,l,c=o(n)if not t then
- return nil,l,c
- end
- local t=t
- while true do
- local l=n:peek()if i[l]then
- n:next()local n,i,o=o(n)if not n then
- return nil,i,o
- end
- t=e.node("binop",{op=l,lhs=t,rhs=n},{d,r,n.slice[3],n.slice[4]})else
- break
- end
- end
- return t
- end
- end
- function e.rassoc(n,...)local r=d(...)local function o(t)local n,l,i=n(t)if not n then
- return n,l,i
- end
- local l=t:peek()if not r[l]then
- return n
- end
- t:next()local t=o(t)if t then
- return e.node("binop",{op=l,lhs=n,rhs=t},{n.slice[1],n.slice[2],t.slice[3],t.slice[4]})else
- return n
- end
- end
- return o
- end
- function e.unop(o,...)local i=d(...)local function t(n)local d,r=n.l.line,n.l.col
- local l=n:peek()if i[l]then
- n:next()else
- return o(n)end
- local t,o,i=t(n)if not t then return nil,o,i end
- return e.node("unop",{op=l,node=t},{d,r,n.l.line,n.l.col-1})end
- return t
- end
- e.l11=e.rassoc(e.term,"^")e.l10=e.unop(e.l11,"not","#","-","~")e.l9=e.lassoc(e.l10,"*","/","//","%")e.l8=e.lassoc(e.l9,"+","-")e.l7=e.rassoc(e.l8,"..")e.l6=e.lassoc(e.l7,"<<",">>")e.l5=e.lassoc(e.l6,"&")e.l4=e.lassoc(e.l5,"~")e.l3=e.lassoc(e.l4,"|")e.l2=e.lassoc(e.l3,"<",">","<=",">=","~=","==")e.l1=e.lassoc(e.l2,"and")e.l0=e.lassoc(e.l1,"or")function e:block()local n={}local e,t,l
- while true do
- e,t,l=self:stat()if t then return nil,t,l end
- if not e then break end
- table.insert(n,e)end
- if self:peek()and self:peek()=="return"then
- table.insert(n,self:returnstat())end
- local e,l,t=self:peek()if e and e~="end"and e~="until"and e~="else"and e~="elseif"then
- return self:expected("statement",t,e,l)end
- return n,l,t
- end
- function e:funcname()local n,t,l=self:name()if not n then return nil,t,l end
- local l
- while true do
- if self:peek()~="."then
- break
- end
- self:next()local t,o,l=self:name()if not t then return nil,o,l end
- t.ty="string"n=e.node("index",{indexing=n,index=t},{n.slice[1],n.slice[2],t.slice[3],t.slice[4]})end
- if self:peek()==":"then
- self:next()local t,o,i=self:name()if not t then return nil,o,i end
- t.ty="string"n=e.node("index",{indexing=n,index=t},{n.slice[1],n.slice[2],t.slice[3],t.slice[4]})l=true
- end
- return n,l
- end
- function e:stat()if self.savedstat then
- local e=self.savedstat
- self.savedstat=nil
- return e
- end
- local n,l,t=self:peek()if not n then
- return
- end
- if n=="error"then
- return nil,l,t
- end
- if n=="return"then return end
- if n==";"then
- local n=select(3,self:peek())self:next()return e.node("emptystat",nil,n)elseif n=="do"then
- return self:dostat()elseif n=="while"then
- return self:whilestat()elseif n=="repeat"then
- return self:repeatstat()elseif n=="if"then
- return self:ifstat()elseif n=="goto"then
- return self:gotostat()elseif n=="::"then
- return self:labelstat()elseif n=="break"then
- local n=select(3,self:peek())self:next()return e.node("break",nil,n)elseif n=="for"then
- return self:forstat()end
- if n=="local"then
- self:next()local n=self:namelist()if n and self:peek()=="="then
- self:next()local l,o,i=self:explist()if not l then return nil,o,i end
- return e.node("decl",{names=n,exps=l},{t[1],t[2],l[#l].slice[3],l[#l].slice[4]})elseif n then
- return e.node("decl",{names=n},{t[1],t[2],n[#n].slice[3],n[#n].slice[4]})elseif self:peek()=="function"then
- self:next()local n,o,l=self:name()if not n then return nil,o,l end
- local l,o,i=self:funcbody()if not l then return nil,o,i end
- self.savedstat=e.node("assign",{vars={n},exps={l}},{t[1],t[2],l.slice[3],l.slice[4]})return e.node("decl",{names={n}},{t[1],t[2],n.slice[3],n.slice[4]})end
- end
- if n=="function"then
- self:next()local l,n,o=self:funcname()if not l then return nil,n,o end
- local n,o,i=self:funcbody(n)if not n then return nil,o,i end
- return e.node("assign",{vars={l},exps={n}},{t[1],t[2],n.slice[3],n.slice[4]})end
- local t,n,n=self:prefixexp()if t and(t.ty=="methodcall"or t.ty=="call")then
- return t
- end
- local n={}if t then
- table.insert(n,t)end
- if self:peek()==","then
- self:next()local e,l,t=self:varlist()if not e then return nil,l,t end
- for t,e in ipairs(e)do
- table.insert(n,e)end
- end
- if#n>0 then
- local t,l,o=self:next()if t~="="then
- return self:expected("`=`",o or{n[#n].slice[3],n[#n].slice[4]+1,n[#n].slice[3],n[#n].slice[4]+1},t,l)end
- local t,o,l=self:explist()if not t then return nil,o,l end
- return e.node("assign",{vars=n,exps=t},{n[1].slice[1],n[1].slice[2],t[#t].slice[3],t[#t].slice[4]})end
- end
- function e:dostat()local n,t,l=self:next()if n~="do"then
- return self:expected("`do`",slice or{self.l.line,self.l.col,self.l.line,self.l.col},n,t)end
- local n,t,o=self:block()if not n then return nil,t,o end
- local o,i,t=self:next()if o~="end"then
- return self:expected("`end`",t or{n[#n].slice[3],n[#n].slice[4]+1,n[#n].slice[3],n[#n].slice[4]+1},o,i)end
- return e.node("do",n,{l[1],l[2],t[3],t[4]})end
- function e:whilestat()local n,t,l=self:next()if n~="while"then
- return self:expected("`while`",slice or{self.l.line,self.l.col,self.l.line,self.l.col},n,t)end
- local o,t,n=self:expr()if not o then return nil,t,n end
- local n,i,t=self:next()if n~="do"then
- return self:expected("`do`",t or{self.l.line,self.l.col,self.l.line,self.l.col},n,i)end
- local n,t,i=self:block()if not n then return nil,t,i end
- local i,r,t=self:next()if i~="end"then
- return self:expected("`end`",t or{n[#n].slice[3],n[#n].slice[4]+1,n[#n].slice[3],n[#n].slice[4]+1},i,r)end
- return e.node("while",{cond=o,block=n},{l[1],l[2],t[3],t[4]})end
- function e:repeatstat()local n,t,l=self:next()if n~="repeat"then
- return self:expected("`repeat`",slice or{self.l.line,self.l.col,self.l.line,self.l.col},n,t)end
- local n,o,t=self:block()if not n then return nil,o,t end
- local t,i,o=self:next()if t~="until"then
- return self:expected("`until`",o or{n[#n].slice[3],n[#n].slice[4]+1,n[#n].slice[3],n[#n].slice[4]+1},t,i)end
- local t,o,i=self:expr()if not t then return nil,o,i end
- return e.node("repeat",{cond=t,block=n},{l[1],l[2],t.slice[3],t.slice[4]})end
- function e:ifstat()local t,l
- local n,o,a=self:next()if n~="if"then
- return self:expected("`if`",slice or{self.l.line,self.l.col,self.l.line,self.l.col},n,o)end
- local i,n,o=self:expr()if not i then return nil,n,o end
- local o,r,n=self:next()if o~="then"then
- return self:expected("`then`",n or{i.slice[3],i.slice[4]+1,i.slice[3],i.slice[4]+1},o,r)end
- t,l=n[3],n[4]local o,r,n=self:block()if not o then return nil,r,n end
- local c={}local n
- if#o>0 then
- t,l=o[#o].slice[3],o[#o].slice[4]end
- while true do
- local e,n,n=self:peek()if e=="elseif"then
- self:next()else
- break
- end
- local n,e,o=self:expr()if not n then return nil,e,o end
- local o,i,e=self:next()if o~="then"then
- return self:expected("`then`",e or{n.slice[3],n.slice[4]+1,n.slice[3],n.slice[4]+1},o,i)end
- t,l=e[3],e[4]local e,i,o=self:block()if not e then return nil,i,o end
- if#e>0 then
- t,l=e[#e].slice[3],e[#e].slice[4]end
- table.insert(c,{cond=n,block=e})end
- if self:peek()=="else"then
- local e=select(3,self:peek())t,l=e[3],e[4]self:next()n,r,e=self:block()if not n then return nil,r,e end
- if#n>0 then
- t,l=n[#n].slice[3],n[#n].slice[4]end
- end
- local d,s,r=self:next()if d~="end"then
- return self:expected("`end`",r or{t,l+1,t,l+1},d,s)end
- return e.node("if",{cond=i,block=o,pelseif=c,pelse=n},{a[1],a[2],r[3],r[4]})end
- function e:gotostat()local n,l,t=self:next()if n~="goto"then
- return self:expected("`goto`",slice or{self.l.line,self.l.col,self.l.line,self.l.col},n,l)end
- local n,o,l=self:name()if not n then return nil,o,l end
- return e.node("goto",n,{t[1],t[2],n.slice[3],n.slice[4]})end
- function e:labelstat()local n,t,o=self:next()if n~="::"then
- return self:expected("`::`",slice or{self.l.line,self.l.col,self.l.line,self.l.col},n,t)end
- local l,i,t=self:name()if not l then return nil,i,t end
- local i,r,t=self:next()if i~="::"then
- return self:expected("`::`",t or{self.l.line,self.l.col,self.l.line,self.l.col},n,r)end
- return e.node("label",l,{o[1],o[2],t[3],t[4]})end
- function e:returnstat()local n,l,t=self:peek()if n~="return"then
- return self:expected("`return`",slice or{self.l.line,self.l.col,self.l.line,self.l.col},n,l)end
- self:next()local n=self:explist()if not n then
- n={}end
- local l=n[#n]and n[#n].slice or t
- return e.node("return",n,{t[1],t[2],l[3],l[4]})end
- function e:forstat()local n,t,c=self:next()if n~="for"then
- return self:expected("`for`",slice or{self.l.line,self.l.col,self.l.line,self.l.col},n,t)end
- local l,n,t=self:name()if not l then return nil,n,t end
- local d,r,n,t,i
- if self:peek()=="="then
- local e=select(3,self:peek())self:next()d,r,step,other=table.unpack(self:explist())if not d then
- return self:expected("expression (for-loop initializer)",{e[3],e[4]+1,e[3],e[4]+1})end
- if not r then
- return self:expected("expression (for-loop limit)",{e[3],e[4]+1,e[3],e[4]+1})end
- if other then
- return self:unexpected("expression",other)end
- else
- local n,e
- t={}if self:peek()==","then
- self:next()t,n,e=self:namelist()if not t then return nil,n,e end
- end
- table.insert(t,1,l)local t,n,e=self:next()if t~="in"then
- return self:expected("`in`",e or{self.l.line,self.l.col,self.l.line,self.l.col},t,n)end
- i,n,e=self:explist()if not i then return nil,n,e end
- l=nil
- end
- local n,a,o=self:next()if n~="do"then
- return self:expected("`do`",o or{self.l.line,self.l.col,self.l.line,self.l.col},n,a)end
- local n,o,a=self:block()if not n then return nil,o,a end
- local a,s,o=self:next()if a~="end"then
- return self:expected("`end`",o or{n[#n].slice[3],n[#n].slice[4]+1,n[#n].slice[3],n[#n].slice[4]+1},a,s)end
- return e.node("for",{counter=l,names=t,exps=i,block=n,init=d,limit=r,step=step},{c[1],c[2],o[3],o[4]})end
- return{Lexer=n,Parser=e}
Advertisement
Add Comment
Please, Sign In to add comment