Module:Script-MBTL
Jump to navigation
Jump to search
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" then
return Token:new(Type.BUTTON,"A")
elseif word=="B" then
return Token:new(Type.BUTTON,"B")
elseif word=="C" then
return Token:new(Type.BUTTON,"C")
elseif word=="D" then
return Token:new(Type.BUTTON,"D")
elseif 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 nil
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")
else
self.buffer = self.backup_buffer
self.readb = self.backup_readb
self.peek = " "
if not color[word:sub(1,1)] then error("unrecognized word") end
return self:wswitch(word:sub(1,1))
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
elseif not self:follow(self.v.COMBOLISTP) then return error("illegal token: " .. self.look.targ)
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
ret_line = self:formatElem(self.look)
self:move()
ret_line = ret_line .. self:inputn()
ret_line = ret_line .. self:inputlistp()
return ret_line
elseif not self:follow(self.v.INPUTLISTP) then return error("illegal token: " .. self.look.targ)
else return "" end
end,
inputn = function(self)
if self:first(self.v.INPUTN) then
return (self:input())
elseif not self:follow(self.v.INPUTN) then return error("illegal token: " .. self.look.targ)
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
elseif not self:follow(self.v.BLOCKLISTP) then return error("illegal token: " .. self.look.targ)
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
elseif not self:follow(self.v.PREFIXLIST) then return error("illegal token: " .. self.look.targ)
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
elseif not self:follow(self.v.DIR) then return error("illegal token: " .. self.look.targ)
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
elseif not self:follow(self.v.BTNSLISTP) then return error("illegal token: " .. self.look.targ)
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
elseif not self:follow(self.v.SUFFIXLIST) then return error("illegal token: " .. self.look.targ)
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()
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 error("illegal token: " .. self.look.targ) 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
elseif not self:follow(self.v.BTNP) then return error("illegal token: " .. self.look.targ)
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
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,
follow = function(self, var)
if var==self.v.COMBOLISTP then return self.look.targ=="(" or self.look.targ==")" or self.look.ttype==Type.CONNECTOR 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
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