2018-06-09 15:05:46 -04:00

988 lines
27 KiB
Lua

require("bin")
parseManager={}
parseManager.__index=parseManager
parseManager.chunks={}
parseManager.stats={}
parseManager.stack={}
parseManager.cFuncs={}
parseManager.mainENV={}
parseManager.currentENV=parseManager.mainENV
parseManager.entry="START"
parseManager.methods={}
parseManager.lastCall=nil
parseManager.currentHandle=nil
parseManager.currentHandleName=nil
function readonlytable(tab)
return setmetatable({},{
__index=tab,
__newindex=function()
error("Attempt to modify read-only table!")
end,
__metatable=false
})
end
function debug(...)
if parseManager.stats.debugging then
print("<DEBUG>",...)
end
end
function parseManager:newENV()
local env={}
function env:getParent()
return getmetatable(self).__index
end
setmetatable(env,{__index=self.currentENV})
return env
end
function parseManager:setENV(env)
self.currentENV=env
end
function parseManager:defualtENV()
self:setENV(self.mainENV)
end
function parseManager:exposeNamespace(name,ref)
self.mainENV[name]=ref
end
function parseManager:load(path,c)
local c = c
if not c then
c = {}
setmetatable(c,parseManager)
end
local file
if type(path)=="table" then
if path.Type=="bin" then
file = path
else
error("Currently unsupported path type!")
end
elseif type(path)=="string" then
if bin.fileExists(path) then
file=bin.load(path)
else
error("File: "..path.." does not exist!")
end
end
-- process the data
file.data=file.data:gsub('%b""',function(a) a=a:gsub("//","\2") return a end)
file.data=file.data:gsub("%b''",function(a) a=a:gsub("//","\2") return a end)
file.data=file.data:gsub("//.-\n","\n")
file.data=file.data:gsub('%b""',function(a) a=a:gsub(";","\1") return a end)
file.data=file.data:gsub("%b''",function(a) a=a:gsub(";","\1") return a end)
file.data=file.data:gsub(";\n","\n")
file.data=file.data:gsub(";\r","\r")
file.data=file.data:gsub(";","\n")
file.data=file.data:gsub("\r\n","\n")
file.data=file.data:gsub("\n\n","\n")
file.data=file.data:gsub("\1",";")
file.data=file.data:gsub("\2","//")
file.data=file.data:gsub("\t","")
file:trim()
for fn in file:gmatch("LOAD (.-)\n") do
debug("L",fn)
self:load(fn,c)
end
for fn in file:gmatch("ENABLE (.-)\n") do
debug("E",fn)
self.stats[string.lower(fn)]=true
end
for fn in file:gmatch("DISABLE (.-)\n") do
debug("D",fn)
self.stats[string.lower(fn)]=false
end
for fn in file:gmatch("ENTRY (.-)\n") do
debug("E",fn)
self.entry=fn
end
for name,data in file:gmatch("%[(.-)[:.-]?%].-{(.-)}") do
local ctype="BLOCK"
if name:find(":") then
ctype=name:match(":(.+)")
name=name:match("(.-):")
end
c.chunks[name]={}
c.chunks[name].type=ctype
c.chunks[name].pos=1
c.chunks[name].labels={}
c.chunks[name].path=path
c.chunks[name].name=name
parseManager.currentHandleName=name
parseManager.currentHandle=c
c:compile(name,ctype,data)
end
--c.chunks=readonlytable(c.chunks)
return c
end
function parseManager:extractState()
return {name=self.currentChunk.name,pos = self.currentChunk.pos,variables = self.mainENV,cc = self.currentENV}
end
function parseManager:injectState(tbl)
self.chunks[tbl.name].pos=tbl.pos
self.currentChunk=self.chunks[tbl.name]
self.mainENV = tbl.variables
self.currentENV = tbl.cc
end
function parseManager.split(s,pat)
local pat=pat or ","
local res = {}
local start = 1
local state = 0
local c = '.'
local elem = ''
for i = 1, #s do
c = s:sub(i, i)
if state == 0 or state == 3 then -- start state or space after comma
if state == 3 and c == ' ' then
state = 0 -- skipped the space after the comma
else
state = 0
if c == '"' or c=="'" then
state = 1
elem = elem .. '"'
elseif c=="[" then
state = 1
elem = elem .. '['
elseif c == pat then
res[#res + 1] = elem
elem = ''
state = 3 -- skip over the next space if present
else
elem = elem .. c
end
end
elseif state == 1 then -- inside quotes
if c == '"' or c=="'" then --quote detection could be done here
state = 0
elem = elem .. '"'
elseif c=="]" then
state = 0
elem = elem .. ']'
elseif c == '\\' then
state = 2
else
elem = elem .. c
end
elseif state == 2 then -- after \ in string
elem = elem .. c
state = 1
end
end
res[#res + 1] = elem
return res
end
function deepcopy(orig)
local orig_type = type(orig)
local copy
if orig_type == 'table' then
copy = {}
for orig_key, orig_value in next, orig, nil do
copy[deepcopy(orig_key)] = deepcopy(orig_value)
end
setmetatable(copy, deepcopy(getmetatable(orig)))
else -- number, string, boolean, etc
copy = orig
end
return copy
end
local function concat(tab,sep)
if not tab then return "" end
for g=1,#tab do
if type(tab[g])=="table" then
tab[g]="<"..(tab[g][1] or "!NEW!").."["..(tab[g][2] or "").."]>"
end
if type(tab[g])=="string" then
tab[g]=tab[g]:gsub("\1","")
end
tab[g]=tostring(tab[g])
end
return table.concat(tab,sep)
end
function parseManager:dump()
local bytecode = deepcopy(self.chunks)
local str=""
for i,v in pairs(bytecode) do
str=str.."BLOCK: ["..i.."]\n"
for k=1,#v do
if type(v[k].Func)=="table" and v[k].Func.IsALookup==true then
if v[k].Type=="fwor" then
str=str.."\t"..v[k].Func[2].." "..concat(v[k].args,", ").."\n"
elseif v[k].Type=="fwr" then
str=str.."\t"..concat(v[k].vars,", ").." <- "..v[k].Func[2].." "..concat(v[k].args,", ").."\n"
end
elseif v[k].Type=="fwor" then
str=str.."\t"..v[k].Func.." "..concat(v[k].args,", ").."\n"
elseif v[k].Type=="funcblock" then
str=str.."\tFUNCTION: args("..concat(v[k].args,", ")..")\n"
elseif v[k].Type=="return" then
str=str.."\tRETURN: rets("..concat(v[k].RETArgs,", ")..")\n"
elseif v[k].Type=="label" then
str=str.."\t::"..v[k].label.."::\n"
elseif v[k].Type=="fwr" then
str=str.."\t"..concat(v[k].vars,", ").." <- "..v[k].Func.." "..concat(v[k].args,", ").."\n"
elseif v[k].Type=="choice" then
local opt={}
local met={}
local args={}
for i=1,#v[k] do
opt[#opt+1]=v[k][i][1]
met[#met+1]=v[k][i][2].Func
args[#args+1]=concat(v[k][i][2].args," ")
end
str=str.."\tCHOICE["..v[k].prompt.."]$C<"..concat(opt,", ")..">$F<"..concat(met,", ")..">$A<"..concat(args,", ")..">\n"
elseif v[k].Type=="text" then
str=str.."\tDISP_MSG \""..v[k].text.."\"\n"
elseif v[k].Type=="assign" then
str=str.."\t"..concat(v[k].vars,", ").." <- "..concat(v[k].vals,", ").."\n"
else
str=str.."\tUnknown Code!: "..tostring(v[k].data).."\n"
end
end
end
return str
end
function table.print(tbl, indent)
if not indent then indent = 0 end
for k, v in pairs(tbl) do
formatting = string.rep(' ', indent) .. k .. ': '
if type(v) == 'table' then
print(formatting)
table.print(v, indent+1)
else
print(formatting .. tostring(v))
end
end
end
function parseManager:pushError(err,sym)
error(err.." "..tostring(sym))
end
local function pieceList(list,self,name)
if #list==0 then
return {}
end
local list=parseManager.split(list)
local L={}
local mathass=1
for i=1,#list do
if list[i]:match("[%w_]-%[.-%]") then
local dict,sym=list[i]:match("([%w_]-)%[(.-)%]")
if tonumber(sym) then
L[#L+1]={"\1"..dict,tonumber(sym),IsALookup=true}
elseif sym:sub(1,1)=="\"" and sym:sub(-1,-1)=="\"" then
L[#L+1]={"\1"..dict,sym:sub(2,-2),IsALookup=true}
end
elseif list[i]:sub(1,1)=="[" and list[i]:sub(-1,-1)=="]" then
L[#L+1]=pieceList(list[i]:sub(2,-2),self,name)
elseif tonumber(list[i]) then
L[#L+1]=tonumber(list[i])
elseif list[i]:sub(1,1)=="\"" and list[i]:sub(-1,-1)=="\"" then
L[#L+1]=list[i]:sub(2,-2)
elseif list[i]:match("[%w_]-%..-") then
local dict,sym=list[i]:match("([%w_]-)%.(.+)")
L[#L+1]={"\1"..dict,sym,IsALookup=true}
elseif list[i]=="true" then
L[#L+1]=true
elseif list[i]=="false" then
L[#L+1]=false
elseif list[i]:match("[%w_]+")==list[i] then
L[#L+1]="\1"..list[i]
elseif list[i]:match("[_%w%+%-/%*%^%(%)%%]+") then
local char="$"..string.char(mathass+64)
self:compileExpr(char,list[i],name)
mathass=mathass+1
L[#L+1]="\1"..char
else
self:pushError("Invalid Syntax!",list[i])
end
end
return L
end
local function pieceAssign(a,self,name)
local dict,ind=a:match("(.-)%[(.+)%]")
local var
if dict and ind then
if ind:sub(1,1)=="\"" and ind:sub(-1,-1)=="\"" then
var={dict,ind:sub(2,-2)}
elseif tonumber(ind) then
var={dict,tonumber(ind)}
elseif ind:match("[%w_]+")==ind then
var={dict,"\1"..ind}
elseif ind:match("[_%w%+%-/%*%^%(%)%%]+") then
local sym="@A"
self:compileExpr(sym,ind,name)
var={dict,"\1"..sym}
else
self:pushError("Invalid way to index a dictonary/array!",ind)
end
elseif a:match("[%w_]+")==a then
var="\1"..a
elseif a:match("[%w_]-%..-") then
local dict,sym=a:match("([%w_]-)%.(.+)")
var={dict,sym,IsALookup=true}
elseif a:find(",") then
local list = parseManager.split(a)
var={}
for i=1,#list do
table.insert(var,pieceAssign(list[i],self,name))
end
else
self:pushError("Invalid Syntax, Assignment is invalid!",a)
end
return var
end
function parseManager:compileAssign(assignA,assignB,name)
local listA=parseManager.split(assignA)
local listB=parseManager.split(assignB)
local assign={
Type="assign",
vars={},
vals={}
}
for k=1,#listA do
local mathTest=false
debug("VAL: "..listB[k])
debug("NAME: "..listA[k])
if listB[k]:sub(1,1)=="[" and listB[k]:sub(-1,-1)=="]" then
if listB[k]:match("%[%]") then
assign.vals[#assign.vals+1]={}
else
assign.vals[#assign.vals+1]=pieceList(listB[k]:sub(2,-2),self,name)
table.print(assign.vals[#assign.vals])
end
elseif listB[k]:match("[%w_]-%[.-%]") then
local dict,sym=listB[k]:match("([%w_]-)%[(.-)%]")
if tonumber(sym) then
assign.vals[#assign.vals+1]={"\1"..dict,tonumber(sym),IsALookup=true}
elseif sym:sub(1,1)=="\"" and sym:sub(-1,-1)=="\"" then
assign.vals[#assign.vals+1]={"\1"..dict,sym:sub(2,-2),IsALookup=true}
end
elseif listB[k]:match("[%w_]-%..-") then
local dict,sym=listB[k]:match("([%w_]-)%.(.+)")
assign.vals[#assign.vals+1]={"\1"..dict,sym,IsALookup=true}
elseif tonumber(listB[k]) then
assign.vals[#assign.vals+1]=tonumber(listB[k])
elseif listB[k]:sub(1,1)=="\"" and listB[k]:sub(-1,-1)=="\"" then
assign.vals[#assign.vals+1]=listB[k]:sub(2,-2)
elseif listB[k]=="true" then
assign.vals[#assign.vals+1]=true
elseif listB[k]=="false" then
assign.vals[#assign.vals+1]=false
elseif listB[k]:match("[%w_]+")==listB[k] then
assign.vals[#assign.vals+1]="\1"..listB[k]
elseif listB[k]:match("[_%w%+%-/%*%^%(%)%%]+")==listB[k] then
mathTest=true
self:compileExpr(listA[k],listB[k],name)
else
self:pushError("Invalid Systax:",listB[k])
end
if not mathTest then
assign.vars[#assign.vars+1]=pieceAssign(listA[k],self,name)
else
print("FUCK!!!!!!!!!!!")
end
end
table.print(assign)
table.insert(self.chunks[name],assign)
end
function parseManager:compileCondition(condition,iff,elsee,name)
self:compileLogic(condition,iff,elsee,name)
end
function parseManager:compileExpr(eql,expr,name)
local cmds={}
expr=expr:gsub("([%W])(%-%d)",function(b,a)
return b.."(0-"..a:match("%d+")..")"
end)
local mathAss=1
function packFunc(l,o,r)
local l=tonumber(l) or l
local o=tonumber(o) or o
local r=tonumber(r) or r
if type(l)=="string" and l:match("[%w_]") then
l="\1"..l
end
if type(r)=="string" and r:match("[%w_]") then
r="\1"..r
end
if type(o)=="string" and o:match("[%w_]") then
o="\1"..o
end
if l=="@" then
l=r
r=""
end
if type(l)=="string" then
if l:find("\3") then
if type(o)=="number" then
cmds[#cmds+1]={Func=l:match("\3(.+)"),args={o}}
else
if o=="@" then o="" end
if o=="" then o=nil end
cmds[#cmds+1]={Func=l:match("\3(.+)"),o}
end
return
end
end
if l=="@" then -- Fancy movement of math
local n=#cmds
cmds[n]["vars"]={"\1%"..string.char(mathAss+64)}
l="\1%"..string.char(mathAss+64)
mathAss=mathAss+1
cmds[n+1]["vars"]={"\1%"..string.char(mathAss+64)}
r="\1%"..string.char(mathAss+64)
mathAss=mathAss+1
end
if r=="@" then -- Fancy movement of math
local n=#cmds
cmds[n]["vars"]={"\1%"..string.char(mathAss+64)}
r="\1%"..string.char(mathAss+64)
mathAss=mathAss+1
-- cmds[n]["vars"]={"\1%"..string.char(mathAss+64)}
-- l="\1%"..string.char(mathAss+64)
-- mathAss=mathAss+1
end
if r=="" then
local n=#cmds
cmds[n]["vars"]={"\1%"..string.char(mathAss+64)}
r=l
l="\1%"..string.char(mathAss+64)
mathAss=mathAss+1
end
if o=="+" then
cmds[#cmds+1]={Func="ADD",args={l,(r or "")}}
elseif o=="-" then
cmds[#cmds+1]={Func="SUB",args={l,(r or "")}}
elseif o=="/" then
cmds[#cmds+1]={Func="DIV",args={l,(r or "")}}
elseif o=="*" then
cmds[#cmds+1]={Func="MUL",args={l,(r or "")}}
elseif o=="^" then
cmds[#cmds+1]={Func="POW",args={l,(r or "")}}
elseif o=="%" then
cmds[#cmds+1]={Func="MOD",args={l,(r or "")}}
else
self:pushError("Something went wrong!",tostring(l)..","..tostring(o)..","..tostring(r))
end
end
function parseManager:pieceExpr(expr)
local count=0
for i,v in pairs(self.methods) do
expr=expr:gsub(i.."(%b())",function(a)
a=a:sub(2,-2)
if a:sub(1,1)=="-" then
a="0"..a
end
packFunc("\3"..i,self:pieceExpr(a))
return "@"
end)
end
for i,v in pairs(self.cFuncs) do
expr=expr:gsub(i.."(%b())",function(a)
a=a:sub(2,-2)
if a:sub(1,1)=="-" then
a="0"..a
end
packFunc("\3"..i,self:pieceExpr(a))
return "@"
end)
end--self.cFuncs
expr=expr:gsub("%b()",function(a)
return self:pieceExpr(a:sub(2,-2))
end)
local loop
for l,o,r in expr:gmatch("(.*)([%+%^%-%*/%%])(.*)") do
loop=true
if l:match("[%+%^%-%*/%%]") then
packFunc(self:pieceExpr(l),o,r)
else
packFunc(l,o,r)
end
end
if loop then
return "@"
else
return expr
end
end
if expr:match("[!%$&_%w%+%-/%*%^%(%)%%]+")==expr then
parseManager:pieceExpr(expr)
cmds[#cmds]["vars"]={"\1"..eql}
for i=1,#cmds do
if cmds[i].vars then
cmds[i].Type="fwr"
else
cmds[i].Type="fwor"
end
if not name then
--self:pushError("Unknown Error:",name)
else
table.insert(self.chunks[name],cmds[i])
end
end
else
--self:pushError("Invalid math Expression!",expr)
end
end
function parseManager:compileFWR(FWR,vars,args,name)
vars=pieceAssign(vars,self,name)
if type(vars)=="string" then
vars={vars}
end
table.insert(self.chunks[name],{
Type="fwr",
Func=FWR,
vars=vars,
args=pieceList(args,self,name),
})
end
function parseManager:compileFWOR(FWOR,args,name)
table.insert(self.chunks[name],{
Type="fwor",
Func=FWOR,
args=pieceList(args,self,name),
})
end
function parseManager:compileLabel(label,name)
self.chunks[name].labels[label]=#self.chunks[name]+1 -- store this inside the chunk
table.insert(self.chunks[name],{
Type="label",
pos=#self.chunks[name]+1,
label=label,
})
end
function parseManager:compileLine(line,name)
table.insert(self.chunks[name],{
Type="text",
text=line
})
end
function parseManager:compileLogic(condition,iff,elsee,name)
local cmds={}
local function pieceLogic(conds)
conds=conds.." or 1==0"
conds=conds:gsub(" and ","\4")
conds=conds:gsub(" or ","\5")
conds=conds:gsub("(\".*[\4].*\")",function(a)
return a:gsub("\4"," and ")
end)
conds=conds:gsub("(\".*[\5].*\")",function(a)
return a:gsub("\4"," or ")
end)
local count=0
local mathass=0
_conds=conds:gsub("%s*\5".."1==0","")
local cmds={}
for l,eq,r in conds:gmatch("(.-)([=~!><][=]*)(.-)%s*[\4\5]") do
charL=string.char(count+65)
charM=string.char(mathass+65)
count=count+1
cmds={
Type="fwr",
Func="COMPARE",
args={[3]=eq},
vars={"\1!"..charL},
}
local l,r=(l:gsub("[\4\5\6]*%(","")),(r:gsub("%)",""))
if l=="true" then
cmds.args[1]=true
elseif l=="false" then
cmds.args[1]=false
elseif tonumber(l) then
cmds.args[1]=tonumber(l)
elseif l:match("[%w_]+")==l then
cmds.args[1]="\1"..l
elseif l:match("[_%w%+%-/%*%^%(%)%%]+")==l then
self:compileExpr("&"..charM,l,name)
cmds.args[1]="\1&"..charM
mathass=mathass+1
elseif l:sub(1,1)=="\"" and l:sub(-1,-1) then
cmds.args[1]=l:sub(2,-2)
else
self:pushError("Invalid Syntax in logical expression!",l)
end
r=r:gsub("%s*\5".."1==0","")
charM=string.char(mathass+65)
if r=="true" then
cmds.args[2]=true
elseif r=="false" then
cmds.args[2]=false
elseif tonumber(r) then
cmds.args[2]=tonumber(r)
elseif r:match("[%w_]+")==r then
cmds.args[2]="\1"..r
elseif r:match("[_%w%+%-/%*%^%(%)%%]+")==r then
self:compileExpr("&"..charM,r,name)
cmds.args[2]="\1&"..charM
mathass=mathass+1
elseif r:sub(1,1)=="\"" and r:sub(-1,-1) then
cmds.args[2]=r:sub(2,-2)
else
self:pushError("Invalid Syntax in logical expression!",r)
end
l=l:gsub("%%","%%%%");r=r:gsub("%%","%%%%");l=l:gsub("%+","%%%+");r=r:gsub("%+","%%%+");l=l:gsub("%*","%%%*");r=r:gsub("%*","%%%*");l=l:gsub("%-","%%%-");r=r:gsub("%-","%%%-");l=l:gsub("%^","%%%^");r=r:gsub("%^","%%%^");l=l:gsub("%$","%%%$");r=r:gsub("%$","%%%$");l=l:gsub("%.","%%%.");r=r:gsub("%.","%%%.");l=l:gsub("%[","%%%[");r=r:gsub("%[","%%%[");l=l:gsub("%]","%%%]");r=r:gsub("%]","%%%]");l=l:gsub("%?","%%%?");r=r:gsub("%?","%%%?");l=l:gsub("%(","%%%(");r=r:gsub("%(","%%%(");l=l:gsub("%)","%%%)");r=r:gsub("%)","%%%)")
_conds=_conds:gsub(l.."%s*"..eq.."%s*"..r,"!"..charL)
table.insert(self.chunks[name],cmds)
end
_conds=_conds:gsub("\4","*")
_conds=_conds:gsub("\5","+")
if not _conds:find("%*") and not _conds:find("%+") then
cmds.vars[1]="\1L$"
else
self:compileExpr("L$",_conds,name)
end
table.insert(self.chunks[name],{
Type="fwor",
Func="CSIM",
args={"\1L$"},
})
FWORi,argsi=iff:match("^([%w_]+)%s*%((.*)%)")
FWORe,argse=elsee:match("^([%w_]+)%s*%((.*)%)")
self:compileFWOR(FWORi,argsi,name)
self:compileFWOR(FWORe,argse,name)
end
pieceLogic(condition)
end
local function trim1(s)
return (s:gsub("^%s*(.-)%s*$", "%1"))
end
function parseManager:compile(name,ctype,data)
local isFBlock,FBArgs=ctype:match("(f)unction%((.*)%)")
--Check if we are dealing with a FBlock
if isFBlock=="f" then
self.cFuncs[name]=true
-- if self.methods[name] then
-- self:pushError("You cannot create a method with the same name as a standard method or duplicate method names!",name)
-- end
self.methods[name]=function(...)
self:Invoke(name,{},...)
end
self.mainENV[name]=self.methods[name]
table.insert(self.chunks[name],{
Type="funcblock",
args=pieceList(FBArgs,self,name)
})
end
debug("COMPILING Block: "..name)
local data=bin.new(data):lines()
local choiceBlock=false
local choice={}
for i=1,#data do
data[i]=trim1(data[i])
if data[i]~="" then
if data[i]:match(".-\"<%s*") then
choiceBlock=true
choice={}
j=0
end
if choiceBlock then
if data[i]:find(">") then
choiceBlock=false
table.insert(self.chunks[name],choice)
else
dat=data[i]:gsub("<","")
if j==0 then
choice.Type="choice"
choice.prompt=dat:sub(2,-2)
j=1
else
local a,b=dat:match("\"(.-)\"%s*(.+)")
if b then
local f,ag=b:match("^([%w_]+)%s*%((.*)%)")
if ag~="" then
choice[#choice+1]={a,{
Type="fwor",
Func=f,
args=pieceList(ag,self,name),
}}
else
choice[#choice+1]={a,{
Type="fwor",
Func=f,
args={},
}}
end
end
end
end
else
local cmd={}
local Return,RETArgs=data[i]:match("(return)%s*(.*)$")
local line=data[i]:match("^\"(.+)\"")
local assignA,assignB=data[i]:match("^([%w,%[%]\"_%(%)%+%-%*%%%./]+)%s*=%s*(.+)")
local vars,FWR,args=data[i]:match("([\"%[%]%w_,]+)%s*=%s*([%w_]+)%s*%((.*)%)$")
local FWOR
if not args then
FWOR,args=data[i]:match("^([%w_]+)%s*%((.*)%)$")
end
local label=data[i]:match("::(.*)::")
local condition,iff,elsee=data[i]:match("if%s*(.+)%s*then%s*(.-%))%s*|%s*(.+%))")
------
local vars2,FWR2,args2=data[i]:match("([%[%]\"%w_,]+)%s*=%s*([%.:%w_]+)%s*%((.*)%)$")
if not args2 then
FWOR2,args2=data[i]:match("^([%.:%w_]+)%s*%((.*)%)$")
end
------
if line then
self:compileLine(line,name)
elseif condition then
self:compileCondition(condition,iff,elsee,name)
elseif FWR then
self:compileFWR(FWR,vars,args,name)
elseif FWOR then
self:compileFWOR(FWOR,args,name)
elseif FWR2 then
local dict,dot,sym=FWR2:match("([%w_]-)([%.:])(.+)")
if dot==":" then
args2=dict..","..args2
end
self:compileFWR({dict,sym,IsALookup=true},vars2,args2,name)
elseif FWOR2 then
local dict,dot,sym=FWOR2:match("([%w_]-)([%.:])(.+)")
if dot==":" then
args2=dict..","..args2
end
self:compileFWOR({dict,sym,IsALookup=true},args2,name)
elseif assignA then
self:compileAssign(assignA,assignB,name)
elseif label then
self:compileLabel(label,name)
elseif Return and isFBlock then
table.insert(self.chunks[name],{
Type="return",
RETArgs=pieceList(RETArgs,self,name)
})
elseif Return and not(isFBlock) then
self:pushError("Attempt to call return in a non function block!",data[i])
else
table.insert(self.chunks[name],{
Type="customdata",
data=data[i],
})
end
end
end
end
end
function parseManager:testDict(dict)
if type(dict[1])=="string" then
if dict[1]:sub(1,1)=="\1" and dict.IsALookup then
return true
end
else
return
end
end
function parseManager:dataToValue(name,envF) -- includes \1\
envF=envF or self.currentENV
local tab=name
if type(name)=="string" then
if name:sub(1,1)=="\1" then
return self:parseHeader(envF[name:sub(2)])
else
return self:parseHeader(name)
end
elseif type(name)=="table" then
if name.__index then
return name
end
if self:testDict(name) then
return envF[name[1]:sub(2,-1)][self:dataToValue(name[2])]
else
tab={}
for i=1,#name do
tab[i]=self:dataToValue(name[i],envF)
end
end
end
return tab or {}
end
function parseManager:define(t)
for i,v in pairs(t) do
self.methods[i]=v
end
end
function push(s,n)
table.insert(s,n)
end
function pop(s)
return table.remove(s)
end
function peek(s)
return s[#s]
end
function parseManager:Invoke(func,vars,...)
local name=func
local func=self.chunks[func]
if func then
if func.type:sub(1,1)=="f" then
local returndata={}
self.fArgs={...}
if #self.fArgs==0 then
self.fArgs={self.lastCall}
end
push(self.stack,{chunk=self.currentChunk,pos=self.currentChunk.pos,env=self.currentENV,vars=vars})
self.methods.JUMP(self,name)
return
else
self:pushError("Attempt to call a non function block!",name)
end
else
self:pushError("Attempt to call a non existing function!",name)
end
end
function parseManager:parseHeader(data)
if type(data)=="string" then
data=data:gsub("%$([%w_:%.%[%]\"']+)%$",function(dat)
debug("PARSE: "..dat)
if dat:find(":") then
-- for later use
elseif dat:find("%[") then
-- for dicts
else
-- regular strings
debug("PARSE DATA: "..tostring(self.currentENV[dat]))
if self.currentENV[dat]~=nil then
if type(self.currentENV[dat])=="table" then
local str=""
for i=1,#self.currentENV[dat] do
str=str..tostring(self.currentENV[dat][i])..","
end
str=str:sub(1,-2)
return "["..str.."]"
else
return tostring(self.currentENV[dat])
end
else
return "nil"
end
end
end)
end
return data
end
function parseManager:pairAssign(vars,vals,envF)
for i=1,#vars do
debug("ASSIGN NAME: "..tostring(vars[i]))
debug("ASSIGN DATA: "..tostring(self:dataToValue(vals[i],envF)))
if type(vars[i])=="table" then
if type(self.currentENV[vars[i][1]])~="table" then
self:pushError("Attempt to index a non table object:",vars[i][1].."[\""..vars[i][2].."\"]")
end
self.currentENV[vars[i][1]][self:dataToValue(vars[i][2])]=self:dataToValue(vals[i],envF)
else
self.currentENV[vars[i]:sub(2,-1)]=self:dataToValue(vals[i],envF)
end
end
end
function parseManager:next(block,choice)
if self.entry then
block = block or self.entry
self.entry = nil
end
local chunk = self.currentChunk or self.chunks[block] or self.chunks["START"]
self.currentChunk=chunk
if choice then
local c=self.choiceData[choice][2]
local args=self:dataToValue(c.args)
if not self.methods[c.Func] then
self.lastCall=self:Invoke(c.Func,"lastCall",unpack(args))
else
self.lastCall=self.methods[c.Func](self,unpack(args))
end
return {Type="method"}
end
local ret
local data=chunk[chunk.pos]
if not data then return end
if data.Type=="label" then
chunk.pos=chunk.pos+1
data=chunk[chunk.pos]
end
chunk.pos=chunk.pos+1
debug("TYPE: "..data.Type)
if data.Type=="text" then
self.lastCall=nil
return {Type="text",text=self:parseHeader(data.text)}
elseif data.Type=="funcblock" then
local env=self.currentENV
self.currentENV=self:newENV()
self:pairAssign(data.args,self.fArgs,env)
return {Type="FBLOCK"}
elseif data.Type=="return" then
local obj=pop(self.stack)
local chunk=obj.chunk
local pos=obj.pos
local env=obj.env
local vars=obj.vars
local name=chunk.name
local env=self.currentENV
chunk.pos=pos
self.currentENV=env
self:pairAssign(vars,data.RETArgs,env)
self.currentChunk=chunk
return {Type="method"}
elseif data.Type=="fwr" then
local args=self:dataToValue(data.args)
local rets={}
local Func
local Ext=false
if type(data.Func)=="table" then
Ext=true
Func=self.currentENV[data.Func[1]][data.Func[2]]
else
Func=self.methods[data.Func]
end
if Ext then
rets={Func(unpack(args))}
else
if type(Func)~="function" then
rets={self:Invoke(data.Func,data.vars,unpack(args))}
return {Type="method"}
else
rets={Func(self,unpack(args))}
end
end
if #rets~=0 then
self:pairAssign(data.vars,rets)
end
self.lastCall=nil
return {Type="method"}
elseif data.Type=="fwor" then
local args=self:dataToValue(data.args)
local Func
local Ext=false
if type(data.Func)=="table" then
Ext=true
Func=self.currentENV[data.Func[1]][data.Func[2]]
else
Func=self.methods[data.Func]
end
if Ext then
self.lastCall=Func(unpack(args))
else
if type(Func)~="function" then
self.lastCall=self:Invoke(data.Func,"lastCall",unpack(args))
return {Type="method"}
else
self.lastCall=Func(self,unpack(args))
end
end
return {Type="method"}
elseif data.Type=="choice" then
self.choiceData=data
local CList={}
for i=1,#data do
CList[#CList+1]=self:parseHeader(data[i][1])
end
self.lastCall=nil
return {Type="choice",prompt=self:parseHeader(data.prompt),CList}
elseif data.Type=="assign" then
self:pairAssign(data.vars,data.vals)
self.lastCall=nil
return {Type="assign"}
else
self.lastCall=nil
return {Type="Custom Syntax"}
end
return rets
end
require("parseManager.standardDefine")