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: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()
	print(file.data)
	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.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,", ")..">"
			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)
			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%+%-/%*%^%(%)%%]+") 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)
		end
	end
	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*(.+)")
						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
			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]=data[i][1]
		end
		self.lastCall=nil
		return {Type="choice",prompt=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")
