Module:Script-MBTL: Difference between revisions

From Mizuumi Wiki
Jump to navigation Jump to search
(adding more error correction because people can't follow the notation written in the combo legend)
(adding space after unknown words)
 
(36 intermediate revisions by 2 users not shown)
Line 21: Line 21:
return t
return t
end
end
}
local color = {
["A"] = "#e2258a",
["B"] = "#ff7606",
["C"] = "#36b270",
["D"] = "#1e8bcb",
["X"] = "#686868",
}
}


Line 87: Line 95:
else
else
if tonumber(self.peek) == nil then
if tonumber(self.peek) == nil then
w = ""
local w = ""
self.backup_buffer = self.buffer
self.backup_buffer = self.buffer
self.backup_readb = self.readb
self.backup_readb = self.readb
Line 97: Line 105:
return self:wswitch(w)
return self:wswitch(w)
else
else
d = ""
local d = ""
repeat
repeat
d = d .. self.peek
d = d .. self.peek
Line 117: Line 125:
elseif word=="tk" or word=="TK" then
elseif word=="tk" or word=="TK" then
return Token:new(Type.PREFIX,"tk.")
return Token:new(Type.PREFIX,"tk.")
elseif word=="md" or word=="microdash" then
elseif word=="md" then
return Token:new(Type.PREFIX,"md.")
return Token:new(Type.PREFIX,"md.")
elseif word=="A" then
elseif word=="A" or word=="a" then
return Token:new(Type.BUTTON,"A")
return Token:new(Type.BUTTON,"A")
elseif word=="B" then
elseif word=="B" or word=="b" then
return Token:new(Type.BUTTON,"B")
return Token:new(Type.BUTTON,"B")
elseif word=="C" then
elseif word=="C" or word=="c" then
return Token:new(Type.BUTTON,"C")
return Token:new(Type.BUTTON,"C")
elseif word=="D" then
elseif word=="D" or word=="d" then
return Token:new(Type.BUTTON,"D")
return Token:new(Type.BUTTON,"D")
elseif word=="X" then
elseif word=="X" or word=="x" then
return Token:new(Type.BUTTON,"X")
return Token:new(Type.BUTTON,"X")
elseif word=="jc" then
elseif word=="jc" then
Line 133: Line 141:
elseif word=="sj" or word=="superjump" then
elseif word=="sj" or word=="superjump" then
return Token:new(Type.WORD,"sj")
return Token:new(Type.WORD,"sj")
elseif word=="sjc" or word=="SJC" then
return Token:new(Type.WORD,"sjc")
elseif word=="djc" then
elseif word=="djc" then
return Token:new(Type.WORD,"djc")
return Token:new(Type.WORD,"djc")
Line 160: Line 170:
self.peek = " "
self.peek = " "
return Token:new(Type.WORD,"RB2")
return Token:new(Type.WORD,"RB2")
else return nil
else return Token:new(Type.WORD,"RB")
end
end
elseif word=="Delay" or word=="delay" then
return Token:new(Type.WORD,"delay")
elseif word=="Heat" or word=="heat" then
elseif word=="Heat" or word=="heat" then
return Token:new(Type.WORD,"Heat")
return Token:new(Type.WORD,"Heat")
Line 168: Line 180:
elseif word=="Airdash" or word=="airdash" then
elseif word=="Airdash" or word=="airdash" then
return Token:new(Type.WORD,"Airdash")
return Token:new(Type.WORD,"Airdash")
elseif word=="Microdash" or word=="microdash" then
return Token:new(Type.WORD,"Microdash")
elseif word=="Throw" or word=="throw" then
elseif word=="Throw" or word=="throw" then
return Token:new(Type.WORD,"Throw")
return Token:new(Type.WORD,"Throw")
Line 174: Line 188:
elseif word=="Jump" or word=="jump" then
elseif word=="Jump" or word=="jump" then
return Token:new(Type.WORD,"Jump")
return Token:new(Type.WORD,"Jump")
elseif word=="Doublejump" or word=="doublejump" then
return Token:new(Type.WORD,"Doublejump")
elseif word=="Land" or word=="land" then
return Token:new(Type.WORD,"land")
elseif word=="Air" or word=="air" then
return Token:new(Type.WORD,"Air ")
elseif word=="Ground" or word=="ground" then
return Token:new(Type.WORD,"Ground ")
elseif word=="Run" or word=="run" then
return Token:new(Type.WORD,"run ")
elseif word=="Under" or word=="under" then
return Token:new(Type.WORD,"under")
elseif word=="Rebeat" or word=="rebeat" then
elseif word=="Rebeat" or word=="rebeat" then
return Token:new(Type.WORD,"Rebeat")
return Token:new(Type.WORD,"Rebeat")
Line 180: Line 206:
elseif word=="Ender" or word=="ender" then
elseif word=="Ender" or word=="ender" then
return Token:new(Type.WORD,"Ender")
return Token:new(Type.WORD,"Ender")
--DAN specific
elseif word=="Bell" or word=="bell" then
return Token:new(Type.WORD,"Bell")
else
else
self.buffer = self.backup_buffer
temp = word
self.readb = self.backup_readb
allbuttons = true
return self:wswitch(word:sub(1,1))
for i=1,temp:len() do
if not color[temp:sub(1,1)] then allbuttons = false end
temp = temp:sub(2,-1)
end
if not allbuttons then return Token:new(Type.WORD,word.." ") else
self.buffer = self.backup_buffer
self.readb = self.backup_readb
self.peek = " "
return self:wswitch(word:sub(1,1))
end
end
end
end,
end,
}
local color = {
["A"] = "#e2258a",
["B"] = "#ff7606",
["C"] = "#36b270",
["D"] = "#1e8bcb",
["X"] = "#686868",
}
}


Line 231: Line 261:
local cp_line = self:combolistp()
local cp_line = self:combolistp()
return c_line..cp_line
return c_line..cp_line
elseif not self:follow(self.v.COMBOLISTP) then return error("illegal token: " .. self.look.targ)
else return "" end
else return "" end
end,
end,
Line 242: Line 271:
self:move()
self:move()
ret_line = ret_line .. self:inputlist()
ret_line = ret_line .. self:inputlist()
ret_line = ret_line .. self:combolistp()
if self.look.targ==")" then
if self.look.targ==")" then
ret_line = ret_line .. self:formatElem(self.look)
ret_line = ret_line .. self:formatElem(self.look)
Line 264: Line 292:
if self:first(self.v.INPUTLISTP) then
if self:first(self.v.INPUTLISTP) then
local ret_line
local ret_line
ret_line = self:formatElem(self.look)
if self.look.ttype==Type.CONNECTOR then
self:move()
ret_line = self:formatElem(self.look)
ret_line = ret_line .. self:inputn()
self:move()
ret_line = ret_line .. self:inputlistp()
ret_line = ret_line .. self:inputn()
ret_line = ret_line .. self:inputlistp()
else
ret_line = self:inputn()
ret_line = ret_line .. self:inputlistp()
end
return ret_line
return ret_line
elseif not self:follow(self.v.INPUTLISTP) then return error("illegal token: " .. self.look.targ)
else return "" end
else return "" end
end,
end,
Line 276: Line 308:
if self:first(self.v.INPUTN) then
if self:first(self.v.INPUTN) then
return (self:input())
return (self:input())
elseif not self:follow(self.v.INPUTN) then return error("illegal token: " .. self.look.targ)
else return "" end
else return "" end
end,
end,
Line 286: Line 317:
ret_line = self:formatElem(self.look)
ret_line = self:formatElem(self.look)
self:move()
self:move()
elseif self.look.ttype==Type.CONNECTOR then
  ret_line = self:formatElem(self.look)
  self:move()
else ret_line = self:blocklist() end
else ret_line = self:blocklist() end
return ret_line
return ret_line
Line 308: Line 342:
ret_line = ret_line .. self:blocklistp()
ret_line = ret_line .. self:blocklistp()
return ret_line
return ret_line
elseif not self:follow(self.v.BLOCKLISTP) then return error("illegal token: " .. self.look.targ)
else return "" end
else return "" end
end,
end,
Line 346: Line 379:
ret_line = ret_line .. self:prefixlist()
ret_line = ret_line .. self:prefixlist()
return ret_line
return ret_line
elseif not self:follow(self.v.PREFIXLIST) then return error("illegal token: " .. self.look.targ)
else return "" end
else return "" end
end,
end,
Line 363: Line 395:
self:move()
self:move()
return d
return d
elseif not self:follow(self.v.DIR) then return error("illegal token: " .. self.look.targ)
else return "" end
else return "" end
end,
end,
Line 379: Line 410:
if self:first(self.v.BTNSLISTP) then
if self:first(self.v.BTNSLISTP) then
local ret_line
local ret_line
ret_line = self:formatElem(self.look)
if self.look.targ=="~" then
self:move()
ret_line = self:formatElem(self.look)
ret_line = ret_line .. self:btns()
self:move()
ret_line = ret_line .. self:btnslistp()
ret_line = ret_line .. self:btns()
return ret_line
ret_line = ret_line .. self:btnslistp()
elseif not self:follow(self.v.BTNSLISTP) then return error("illegal token: " .. self.look.targ)
return ret_line
elseif self:first(self.v.BTNS) then
ret_line = self:btns()
ret_line = ret_line .. self:btnslistp()
return ret_line
end
else return "" end
else return "" end
end,
end,
Line 403: Line 439:
ret_line = ret_line .. self:suffixlist(mainb)
ret_line = ret_line .. self:suffixlist(mainb)
return ret_line
return ret_line
elseif not self:follow(self.v.SUFFIXLIST) then return error("illegal token: " .. self.look.targ)
else return "" end
else return "" end
end,
end,
Line 416: Line 451:
sufbody = self:formatElem("w",mainb)
sufbody = self:formatElem("w",mainb)
self:move()
self:move()
elseif self:first(self.v.BTNSLIST) then
sufbody = self:btnslist()
else  
else  
sufbody = self:formatElem(self:dir(),mainb)
sufbody = self:formatElem(self:dir(),mainb)
Line 487: Line 524:
return ret_line
return ret_line
end
end
else error("illegal token: " .. self.look.targ) end
else return "" end
end,
end,
Line 502: Line 539:
return ret_line
return ret_line
else error("illegal token: " .. self.look.targ) end
else error("illegal token: " .. self.look.targ) end
elseif not self:follow(self.v.BTNP) then return error("illegal token: " .. self.look.targ)
else return "" end
else return "" end
end,
end,
Line 511: Line 547:
elseif var==self.v.COMBO then return self.look.targ=="(" or self:first(self.v.INPUTLIST)
elseif var==self.v.COMBO then return self.look.targ=="(" or self:first(self.v.INPUTLIST)
elseif var==self.v.INPUTLIST then return self:first(self.v.INPUT)
elseif var==self.v.INPUTLIST then return self:first(self.v.INPUT)
elseif var==self.v.INPUTLISTP then return self.look.ttype==Type.CONNECTOR
elseif var==self.v.INPUTLISTP then return self.look.ttype==Type.CONNECTOR or self.look.ttype==Type.WORD
elseif var==self.v.INPUTN then return self:first(self.v.INPUT)
elseif var==self.v.INPUTN then return self:first(self.v.INPUT)
elseif var==self.v.INPUT then return self.look.ttype==Type.WORD or self:first(self.v.BLOCKLIST)
elseif var==self.v.INPUT then return self.look.ttype==Type.WORD or self.look.ttype==Type.CONNECTOR or self:first(self.v.BLOCKLIST)
elseif var==self.v.BLOCKLIST then return self:first(self.v.BLOCK)
elseif var==self.v.BLOCKLIST then return self:first(self.v.BLOCK)
elseif var==self.v.BLOCKLISTP then return self.look.targ=="/"
elseif var==self.v.BLOCKLISTP then return self.look.targ=="/"
Line 524: Line 560:
elseif var==self.v.DIR then return self.look.ttype==Type.DIRECTION
elseif var==self.v.DIR then return self.look.ttype==Type.DIRECTION
elseif var==self.v.BTNSLIST then return self:first(self.v.BTNS)
elseif var==self.v.BTNSLIST then return self:first(self.v.BTNS)
elseif var==self.v.BTNSLISTP then return self.look.targ=="~"
elseif var==self.v.BTNSLISTP then return self.look.targ=="~" or self:first(self.v.BTNS)
elseif var==self.v.BTNS then return self.look.ttype==Type.DIRECTION or self:first(self.v.BTN)
elseif var==self.v.BTNS then return self.look.ttype==Type.DIRECTION or self:first(self.v.BTN)
elseif var==self.v.SUFFIXLIST then return self:first(self.v.SUFFIX)
elseif var==self.v.SUFFIXLIST then return self:first(self.v.SUFFIX)
Line 530: Line 566:
elseif var==self.v.BTN then return self.look.ttype==Type.BUTTON or self.look.targ=="AT" or self.look.targ=="[" or self.look.targ=="]" or self.look.targ=="{"
elseif var==self.v.BTN then return self.look.ttype==Type.BUTTON or self.look.targ=="AT" or self.look.targ=="[" or self.look.targ=="]" or self.look.targ=="{"
elseif var==self.v.BTNP then return self.look.targ=="+"
elseif var==self.v.BTNP then return self.look.targ=="+"
else return false end
end,
follow = function(self, var)
if var==self.v.COMBOLISTP then return self.look.targ=="(" or self.look.targ==")" or self.look.targ=="EOF"
elseif var==self.v.INPUTLISTP then return self.look.ttype==Type.WORD or self.look.ttype==Type.PREFIX or self.look.ttype==Type.BUTTON or self.look.ttype==Type.DIRECTION or self.look.targ==")" or self.look.targ=="(" or self.look.targ=="]" or self.look.targ=="[" or self.look.targ=="{" or self.look.targ=="EOF"
elseif var==self.v.INPUTN then return self.look.ttype==Type.CONNECTOR or self.look.ttype==Type.WORD or self.look.ttype==Type.PREFIX or self.look.ttype==Type.BUTTON or self.look.ttype==Type.DIRECTION or self.look.targ==")" or self.look.targ=="(" or self.look.targ=="]" or self.look.targ=="[" or self.look.targ=="{" or self.look.targ=="EOF"
elseif var==self.v.BLOCKLISTP then return self.look.ttype==Type.CONNECTOR or self.look.ttype==Type.WORD or self.look.ttype==Type.PREFIX or self.look.ttype==Type.BUTTON or self.look.ttype==Type.DIRECTION or self.look.targ==")" or self.look.targ=="(" or self.look.targ=="]" or self.look.targ=="[" or self.look.targ=="{" or self.look.targ=="EOF"
elseif var==self.v.PREFIXLIST then return self.look.ttype==Type.BUTTON or self.look.ttype==Type.DIRECTION or self.look.targ=="]" or self.look.targ=="[" or self.look.targ=="]" or self.look.targ=="{"
elseif var==self.v.DIR then return self.look.ttype==Type.BUTTON or self.look.targ=="]" or self.look.targ=="[" or self.look.targ=="]" or self.look.targ=="{"
elseif var==self.v.BTNSLISTP then return self.look.ttype==Type.CONNECTOR or self.look.ttype==Type.WORD or self.look.ttype==Type.PREFIX or self.look.ttype==Type.BUTTON or self.look.ttype==Type.DIRECTION or self.look.targ=="/" or self.look.targ==")" or self.look.targ=="(" or self.look.targ=="]" or self.look.targ=="[" or self.look.targ=="{" or self.look.targ=="EOF"
elseif var==self.v.SUFFIXLIST then return self.look.ttype==Type.CONNECTOR or self.look.ttype==Type.WORD or self.look.ttype==Type.PREFIX or self.look.ttype==Type.BUTTON or self.look.ttype==Type.DIRECTION or self.look.targ=="/" or self.look.targ=="~" or self.look.targ==")" or self.look.targ=="(" or self.look.targ=="]" or self.look.targ=="[" or self.look.targ=="{" or self.look.targ=="EOF"
elseif var==self.v.BTNP then return self.look.ttype==Type.CONNECTOR or self.look.ttype==Type.WORD or self.look.ttype==Type.PREFIX or self.look.ttype==Type.BUTTON or self.look.ttype==Type.DIRECTION or self.look.targ=="/" or self.look.targ=="~" or self.look.targ==")" or self.look.targ=="(" or self.look.targ=="]" or self.look.targ=="[" or self.look.targ=="{" or self.look.targ=="}" or self.look.targ=="EOF"
else return false end
else return false end
end,
end,

Latest revision as of 10:23, 14 January 2024

Documentation for this module may be created at Module:Script-MBTL/doc

local p = {}

--custom script for the IS wiki, feel free to make a copy of it or take any part of the code for other wikis. ohoho I DID!!!!! 
--MBTL wiki fork

--split multiple properties passed as a single param to a template call and return the converted property text


--local objects used by p.gameInput()
local Type = {WORD=0, CONNECTOR=1, PREFIX=2, SUFFIX=3, SYMBOL=4, BUTTON=5, DIRECTION=6, SYS=7}

local Token = {
	ttype = nil,
	targ = nil,
	new = function(self,typ,arg)
		t = {}
		self.ttype = typ
		self.targ = arg
		setmetatable(t,self)
		self.__index = self
		return t
	end
}

local color = {
	["A"] = "#e2258a",
	["B"] = "#ff7606",
	["C"] = "#36b270",
	["D"] = "#1e8bcb",
	["X"] = "#686868",
}

local lexer = {
	buffer = "",
	readb = "",
	peek = " ",
	backup_buffer = "",
	backup_readb = "",
	newBuffer = function(self,buf)
		self.buffer = buf
	end,
	readch = function(self)
		if self.buffer:len() >= 1 then
			local r = self.buffer:sub(1,1)
			self.readb = self.readb .. r
			self.buffer = self.buffer:sub(2,-1)
			self.peek = r
		else
			self.peek = ":EOF:"
		end
	end,
	scan = function(self)
		while self.peek==" " or self.peek=="\t" or self.peek=="\n" or self.peek=="\r" do
			self:readch()
		end
		return self:cswitch()
	end,
	cswitch = function(self)
		if self.peek == ">" then 
			self.peek = " "
			return Token:new(Type.CONNECTOR," > ")
		elseif self.peek == "," then
			self.peek = " "
			return Token:new(Type.CONNECTOR," , ")
		elseif self.peek == "(" then
			self.peek = " "
			return Token:new(Type.SYMBOL,"(")
		elseif self.peek == ")" then
			self.peek = " "
			return Token:new(Type.SYMBOL,")")
		elseif self.peek == "[" then
			self.peek = " "
			return Token:new(Type.SYMBOL,"[")
		elseif self.peek == "]" then
			self.peek = " "
			return Token:new(Type.SYMBOL,"]")
		elseif self.peek == "{" then
			self.peek = " "
			return Token:new(Type.SYMBOL,"{")
		elseif self.peek == "}" then
			self.peek = " "
			return Token:new(Type.SYMBOL,"}")
		elseif self.peek == "~" then
			self.peek = " "
			return Token:new(Type.CONNECTOR,"~")
		elseif self.peek == "+" then
			self.peek = " "
			return Token:new(Type.CONNECTOR,"+")
		elseif self.peek == "/" then
			self.peek = " "
			return Token:new(Type.CONNECTOR,"/")
		elseif self.peek == ":EOF:" then
			self.peek = " "
			return Token:new(Type.SYS,"EOF")
		else
			if tonumber(self.peek) == nil then
				local w = ""
				self.backup_buffer = self.buffer
				self.backup_readb = self.readb
				repeat
					w = w .. self.peek
					self:readch()
				until self.peek:match("%a")==nil or self.peek:match(":EOF:") --peek is not a letter or reached EOF
				if self.peek=="." then self.peek=" " end
				return self:wswitch(w)
			else
				local d = ""
				repeat
					d = d .. self.peek
					self:readch()
				until tonumber(self.peek) == nil
				return Token:new(Type.DIRECTION,d)
			end
		end
	end,
	wswitch = function(self,word)
		if word=="dl" then
			return Token:new(Type.PREFIX,"dl.")
		elseif word=="j" or word=="J" then
			return Token:new(Type.PREFIX,"j.")
		elseif word=="dj" or word=="DJ" then
			return Token:new(Type.PREFIX,"dj.")
		elseif word=="w" or word=="W" then
			return Token:new(Type.PREFIX,"w.")
		elseif word=="tk" or word=="TK" then
			return Token:new(Type.PREFIX,"tk.")
		elseif word=="md" then
			return Token:new(Type.PREFIX,"md.")
		elseif word=="A" or word=="a" then
			return Token:new(Type.BUTTON,"A")
		elseif word=="B" or word=="b" then
			return Token:new(Type.BUTTON,"B")
		elseif word=="C" or word=="c" then
			return Token:new(Type.BUTTON,"C")
		elseif word=="D" or word=="d" then
			return Token:new(Type.BUTTON,"D")
		elseif word=="X" or word=="x" then
			return Token:new(Type.BUTTON,"X")
		elseif word=="jc" then
			return Token:new(Type.WORD,"jc")
		elseif word=="sj" or word=="superjump" then
			return Token:new(Type.WORD,"sj")
		elseif word=="sjc" or word=="SJC" then
			return Token:new(Type.WORD,"sjc")
		elseif word=="djc" then
			return Token:new(Type.WORD,"djc")
		elseif word=="IAD" or word=="iad" then
			return Token:new(Type.WORD,"IAD")
		elseif word=="AT" or word=="at" then
			return Token:new(Type.WORD,"AT")
		elseif word=="OR" or word=="or" then
			return Token:new(Type.WORD," OR ")
		elseif word=="CH" or word=="ch" then
			return Token:new(Type.WORD,"CH ")
		elseif word=="FC" or word=="fc" then
			return Token:new(Type.WORD,"FC ")
		elseif word=="OTG" or word=="otg" then
			return Token:new(Type.WORD,"OTG ")
		elseif word=="MD" then
			return Token:new(Type.WORD,"MD")
		elseif word=="AD" or word=="ad" then
			return Token:new(Type.WORD,"AD")
		elseif word=="LA" or word=="la" then
			return Token:new(Type.WORD,"LA")
		elseif word=="RB" or word=="rb" then
			if self.peek=="1" then
				self.peek = " "
				return Token:new(Type.WORD,"RB1")
			elseif self.peek=="2" then
				self.peek = " "
				return Token:new(Type.WORD,"RB2")
			else return Token:new(Type.WORD,"RB")
			end
		elseif word=="Delay" or word=="delay" then
			return Token:new(Type.WORD,"delay")
		elseif word=="Heat" or word=="heat" then
			return Token:new(Type.WORD,"Heat")
		elseif word=="Dash" or word=="dash" then
			return Token:new(Type.WORD,"Dash")
		elseif word=="Airdash" or word=="airdash" then
			return Token:new(Type.WORD,"Airdash")
		elseif word=="Microdash" or word=="microdash" then
			return Token:new(Type.WORD,"Microdash")
		elseif word=="Throw" or word=="throw" then
			return Token:new(Type.WORD,"Throw")
		elseif word=="Sideswap" or word=="sideswap" then
			return Token:new(Type.WORD,"Sideswap")
		elseif word=="Jump" or word=="jump" then
			return Token:new(Type.WORD,"Jump")
		elseif word=="Doublejump" or word=="doublejump" then
			return Token:new(Type.WORD,"Doublejump")
		elseif word=="Land" or word=="land" then
			return Token:new(Type.WORD,"land")
		elseif word=="Air" or word=="air" then
			return Token:new(Type.WORD,"Air ")
		elseif word=="Ground" or word=="ground" then
			return Token:new(Type.WORD,"Ground ")
		elseif word=="Run" or word=="run" then
			return Token:new(Type.WORD,"run ")
		elseif word=="Under" or word=="under" then
			return Token:new(Type.WORD,"under")
		elseif word=="Rebeat" or word=="rebeat" then
			return Token:new(Type.WORD,"Rebeat")
		elseif word=="Starter" or word=="starter" then
			return Token:new(Type.WORD,"Starter")
		elseif word=="Ender" or word=="ender" then
			return Token:new(Type.WORD,"Ender")
		--DAN specific
		elseif word=="Bell" or word=="bell" then
			return Token:new(Type.WORD,"Bell")
		else
			temp = word
			allbuttons = true
			for i=1,temp:len() do
				if not color[temp:sub(1,1)] then allbuttons = false end
				temp = temp:sub(2,-1)
			end
			if not allbuttons then return Token:new(Type.WORD,word.." ") else
				self.buffer = self.backup_buffer
				self.readb = self.backup_readb
				self.peek = " "
				return self:wswitch(word:sub(1,1))
			end
		end
	end,
}

local parser = {
	v = {COMBOLIST=0, COMBOLISTP=1, COMBO=2, INPUTLIST=3, INPUTLISTP=4, INPUTN=5, INPUT=6, BLOCKLIST=7, BLOCKLISTP=8, BLOCK=9, UCPREFIXLIST=10, UCPREFIX=11, PREFIXLIST=12, PREFIX=13, DIR=14, BTNSLIST=15, BTNSLISTP=16, BTNS=17, SUFFIXLIST=18, SUFFIX=19, BTN=20, BTNP=21},
	look = Token:new(Type.SYS,"START"),
	
	move = function(self)
		self.look = lexer:scan()
	end,
	
	formatElem = function(self,t,clr)
		if clr then
			return "<span style=\"color:" .. clr .. ";\">" .. (t.targ or t) .. "</span>" --works because the or is lazy so if t is a token it will not return t even if it's technically not nil because t.targ comes first
		else
			return t.targ or t
		end
	end,
	
	start = function(self)
		self:move()
		return (self:combolist()) --only return the line parameter
	end,
	
	combolist = function(self)
		if self:first(self.v.COMBOLIST) then
			local c_line = self:combo()
			local cp_line = self:combolistp()
			if self.look.targ~="EOF" then error("illegal token: " .. self.look.targ) end
			return c_line..cp_line
		else error("illegal starting token") end
	end,
	
	combolistp = function(self)
		if self:first(self.v.COMBOLISTP) then
			local c_line = self:combo()
			local cp_line = self:combolistp()
			return c_line..cp_line
		else return "" end
	end,
	
	combo = function(self)
		if self:first(self.v.COMBO) then
			local ret_line
			if self.look.targ=="(" then
				ret_line = self:formatElem(self.look)
				self:move()
				ret_line = ret_line .. self:inputlist()
				if self.look.targ==")" then
					ret_line = ret_line .. self:formatElem(self.look)
					self:move()
				else error("illegal token: " .. self.look.targ) end
			else ret_line = self:inputlist() end
			return ret_line
		else error("illegal token: " .. self.look.targ) end
	end,
	
	inputlist = function(self)
		if self:first(self.v.INPUTLIST) then
			local ret_line
			ret_line = self:input()
			ret_line = ret_line .. self:inputlistp()
			return ret_line
		else error("illegal token: " .. self.look.targ) end
	end,
	
	inputlistp = function(self)
		if self:first(self.v.INPUTLISTP) then
			local ret_line
			if self.look.ttype==Type.CONNECTOR then
				ret_line = self:formatElem(self.look)
				self:move()
				ret_line = ret_line .. self:inputn()
				ret_line = ret_line .. self:inputlistp()
			else
				ret_line = self:inputn()
				ret_line = ret_line .. self:inputlistp()
			end
			return ret_line
		else return "" end
	end,
	
	inputn = function(self)
		if self:first(self.v.INPUTN) then
			return (self:input())
		else return "" end
	end,
	
	input = function(self)
		if self:first(self.v.INPUT) then
			local ret_line
			if self.look.ttype==Type.WORD then
				ret_line = self:formatElem(self.look)
				self:move()
			elseif self.look.ttype==Type.CONNECTOR then
			  ret_line = self:formatElem(self.look)
			  self:move()
			else ret_line = self:blocklist() end
			return ret_line
		else error("illegal token: " .. self.look.targ) end
	end,
	
	blocklist = function(self)
		if self:first(self.v.BLOCKLIST) then
			local ret_line
			ret_line = self:block()
			ret_line = ret_line .. self:blocklistp()
			return ret_line
		else error("illegal token: " .. self.look.targ) end
	end,
	
	blocklistp = function(self)
		if self:first(self.v.BLOCKLISTP) then
			local ret_line
			ret_line = self:formatElem(self.look)
			self:move()
			ret_line = ret_line .. self:block()
			ret_line = ret_line .. self:blocklistp()
			return ret_line
		else return "" end
	end,
	
	block = function(self)
		if self:first(self.v.BLOCK) then
			local ret_line
			local up = self:ucprefixlist()
			local pf = self:prefixlist()
			local bl_line, bl_button = self:btnslist()
			ret_line = self:formatElem(up) .. self:formatElem(pf,bl_button) .. bl_line
			return ret_line
		else error("illegal token: " .. self.look.targ) end
	end,
	
	ucprefixlist = function(self)
		if self:first(self.v.UCPREFIXLIST) then
			local ret_line
			ret_line = self:ucprefix()
			ret_line = ret_line .. self:ucprefixlist()
			return ret_line
		else return "" end
	end,
	
	ucprefix = function(self)
		if self:first(self.v.UCPREFIX) then
			local u = self.look.targ
			self:move()
			return u
		else return "" end
	end,
	
	prefixlist = function(self)
		if self:first(self.v.PREFIXLIST) then
			local ret_line
			ret_line = self:prefix()
			ret_line = ret_line .. self:prefixlist()
			return ret_line
		else return "" end
	end,
	
	prefix = function(self)
		if self:first(self.v.PREFIX) then
			local p = self.look.targ
			self:move()
			return p
		else error("illegal token: " .. self.look.targ) end
	end,
	
	dir = function(self)
		if self:first(self.v.DIR) then
			local d = self.look.targ
			self:move()
			return d
		else return "" end
	end,
	
	btnslist = function(self)
		if self:first(self.v.BTNSLIST) then
			local ret_line, ret_button
			ret_line, ret_button = self:btns()
			ret_line = ret_line .. self:btnslistp()
			return ret_line, ret_button
		else error("illegal token: " .. self.look.targ) end
	end,
	
	btnslistp = function(self)
		if self:first(self.v.BTNSLISTP) then
			local ret_line
			if self.look.targ=="~" then
				ret_line = self:formatElem(self.look)
				self:move()
				ret_line = ret_line .. self:btns()
				ret_line = ret_line .. self:btnslistp()
				return ret_line
			elseif self:first(self.v.BTNS) then
				ret_line = self:btns()
				ret_line = ret_line .. self:btnslistp()
				return ret_line
			end
		else return "" end
	end,
	
	btns = function(self)
		if self:first(self.v.BTNS) then
			local dr = self:dir()
			local b_line, b_button = self:btn()
			b_line = self:formatElem(dr,b_button) .. b_line .. self:suffixlist(b_button)
			return b_line, b_button
		else error("illegal token: " .. self.look.targ) end
	end,
	
	suffixlist = function(self,mainb)
		if self:first(self.v.SUFFIXLIST) then
			local ret_line
			ret_line = self:suffix(mainb)
			ret_line = ret_line .. self:suffixlist(mainb)
			return ret_line
		else return "" end
	end,
	
	suffix = function(self,mainb)
		if self:first(self.v.SUFFIX) then
			local ret_line
			ret_line = self:formatElem(self.look, mainb)
			self:move()
			local sufbody = ""
			if self.look.targ=="w." then
				sufbody = self:formatElem("w",mainb)
				self:move()
			elseif self:first(self.v.BTNSLIST) then
				sufbody = self:btnslist()
			else 
				sufbody = self:formatElem(self:dir(),mainb)
			end
			ret_line = ret_line .. sufbody
			if self.look.targ==")" then
				ret_line = ret_line .. self:formatElem(self.look,mainb)
				self:move()
				return ret_line
			else error("illegal token: " .. self.look.targ) end
		else error("illegal token: " .. self.look.targ) end
	end,
	
	btn = function(self)
		if self:first(self.v.BTN) then
			local ret_line, ret_button
			if self.look.ttype==Type.BUTTON then
				ret_button = color[self.look.targ]
				ret_line = self:formatElem(self.look,ret_button)
				self:move()
				ret_line = ret_line .. self:btnp()
				return ret_line, ret_button
			elseif self.look.targ=="[" then
				local pre = self.look.targ
				self:move()
				if self.look.ttype==Type.BUTTON then
					ret_button = color[self.look.targ]
					ret_line = self:formatElem(pre,ret_button)
					ret_line = ret_line .. self:formatElem(self.look,ret_button)
					self:move()
					ret_line = ret_line .. self:btnp()
					if self.look.targ=="]" then
						ret_line = ret_line .. self:formatElem(self.look,ret_button)
						self:move()
						return ret_line, ret_button
					else error("illegal token: " .. self.look.targ) end
				else error("illegal token: " .. self.look.targ) end
			elseif self.look.targ=="]" then
				local pre = self.look.targ
				self:move()
				if self.look.ttype==Type.BUTTON then
					ret_button = color[self.look.targ]
					ret_line = self:formatElem(pre,ret_button)
					ret_line = ret_line .. self:formatElem(self.look,ret_button)
					self:move()
					ret_line = ret_line .. self:btnp()
					if self.look.targ=="[" then
						ret_line = ret_line .. self:formatElem(self.look,ret_button)
						self:move()
						return ret_line, ret_button
					else error("illegal token: " .. self.look.targ) end
				else error("illegal token: " .. self.look.targ) end
			elseif self.look.targ=="{" then
				local pre = self.look.targ
				self:move()
				if self.look.ttype==Type.BUTTON then
					ret_button = color[self.look.targ]
					ret_line = self:formatElem(pre,ret_button)
					ret_line = ret_line .. self:formatElem(self.look,ret_button)
					self:move()
					ret_line = ret_line .. self:btnp()
					if self.look.targ=="}" then
						ret_line = ret_line .. self:formatElem(self.look,ret_button)
						self:move()
						return ret_line, ret_button
					else error("illegal token: " .. self.look.targ) end
				else error("illegal token: " .. self.look.targ) end
			elseif self.look.targ=="AT" then
				ret_line = self:formatElem(self.look)
				self:move()
				return ret_line
			end
		else return "" end
	end,
	
	btnp = function(self)
		if self:first(self.v.BTNP) then
			local ret_line
			ret_line = self:formatElem(self.look)
			self:move()
			if self.look.ttype==Type.BUTTON then
				local subb = color[self.look.targ]
				ret_line = ret_line .. self:formatElem(self.look,subb)
				self:move()
				ret_line = ret_line .. self:btnp()
				return ret_line
			else error("illegal token: " .. self.look.targ) end
		else return "" end
	end,
	
	first = function(self,var)
		if var==self.v.COMBOLIST then return self:first(self.v.COMBO)
		elseif var==self.v.COMBOLISTP then return self:first(self.v.COMBO)
		elseif var==self.v.COMBO then return self.look.targ=="(" or self:first(self.v.INPUTLIST)
		elseif var==self.v.INPUTLIST then return self:first(self.v.INPUT)
		elseif var==self.v.INPUTLISTP then return self.look.ttype==Type.CONNECTOR or self.look.ttype==Type.WORD
		elseif var==self.v.INPUTN then return self:first(self.v.INPUT)
		elseif var==self.v.INPUT then return self.look.ttype==Type.WORD or self.look.ttype==Type.CONNECTOR or self:first(self.v.BLOCKLIST)
		elseif var==self.v.BLOCKLIST then return self:first(self.v.BLOCK)
		elseif var==self.v.BLOCKLISTP then return self.look.targ=="/"
		elseif var==self.v.BLOCK then return self.look.ttype==Type.DIRECTION or self:first(self.v.PREFIXLIST) or self:first(self.v.BTNSLIST)
		elseif var==self.v.UCPREFIXLIST then return self:first(self.v.UCPREFIX)
		elseif var==self.v.COMBOLISTP then return self:first(self.v.COMBO)
		elseif var==self.v.UCPREFIX then return self.look.targ=="dl." or self.look.targ=="tk." or self.look.targ=="w."
		elseif var==self.v.PREFIXLIST then return self:first(self.v.PREFIX)
		elseif var==self.v.PREFIX then return self.look.ttype==Type.PREFIX
		elseif var==self.v.DIR then return self.look.ttype==Type.DIRECTION
		elseif var==self.v.BTNSLIST then return self:first(self.v.BTNS)
		elseif var==self.v.BTNSLISTP then return self.look.targ=="~" or self:first(self.v.BTNS)
		elseif var==self.v.BTNS then return self.look.ttype==Type.DIRECTION or self:first(self.v.BTN)
		elseif var==self.v.SUFFIXLIST then return self:first(self.v.SUFFIX)
		elseif var==self.v.SUFFIX then return self.look.targ=="("
		elseif var==self.v.BTN then return self.look.ttype==Type.BUTTON or self.look.targ=="AT" or self.look.targ=="[" or self.look.targ=="]" or self.look.targ=="{"
		elseif var==self.v.BTNP then return self.look.targ=="+"
		else return false end
	end,
}


--actual method functions
	
function p.multiprop(frame)
	
	local str = frame.args[1]
	local sep = ","
	local t={}
	--split properties
	for str in string.gmatch(str, "([^"..sep.."]+)") do
			table.insert(t, str)
	end
	--get the string done
	for index, prop in ipairs(t) do
		if prop:sub(1,1) == "%s" then
			prop = prop:sub(2,-1)
		end
		expanded = frame:expandTemplate{ title="Property-MBTL", args={prop,"IGNOREPROPERTYERROR"}}
		t[index] = expanded
	end
	
	ret = table.concat(t,", ")
	
	return ret
end

--color code and format game inputs.
--supports entire combos as arguments.
function p.gameInput(frame)
	
	local str = frame.args[1]
	lexer:newBuffer(str) --set the input string as the input buffer
	return parser:start()
	
end

return p