Documentation for this module may be created at Module:Parser/doc
--this is a side project JBed is working on
--it is sort of writing Lua within Lua
--i wonder how that could be useful?
parser = {}
local userError = require("Dev:User error")
table = require "Module:Table"
function parser.string(s, ...)
--limitations: doesn't recognise "\n" et al
-- doesn't recognise use of functions or unpassed variables
local args = table.pack and table.pack(...) or arg
local t = mw.text.split(s, "")
local a = ""
local p = ""
local quot = {"'", '"'}
local cquo = false
local litc = {"\\"}
local lit = false
local clv = 2
--clv: 0 = unreadable, 1 = expecting concat, 2= readable, 3= quoting, 4= literaling, 5=variabling
for i=1, #t do
if clv == 0 then
if t[i] == " " then
elseif t[i] =="." then clv = 1
else return nil
end
elseif clv == 1 then
if t[i] == "." then clv = 2
else return nil
end
elseif clv == 2 then
if t[i] == " " then
elseif t[i] == "{" then clv = 5
elseif t[i] == quot[1] then cquo = quot[1] clv = 3
elseif t[i] == quot[2] then cquo = quot[2] clv = 3
else return
end
elseif clv == 3 then
if t[i] == "\\" then clv = 4
elseif t[i] == cquo then clv = 0
else a = a .. t[i]
end
elseif clv == 4 then
a = a .. t[i]
elseif clv == 5 then
if t[i] == "}" then a = a .. args[tonumber(p)] p = "" clv = 0
elseif tostring(tonumber(t[i])) == t[i] then p = p .. t[i]
else return nil
end
else return nil
end
end
return a
end
function parser.tablevalue(a, b)
local spl = mw.text.split(a, "=")
local var = table.remove(spl, 1)
local tab = parser.value(table.concat(spl, "="))
var = table.remove(mw.text.split(mw.text.trim(var), " "))
local sta = mw.text.trim(b)
local par
if sta:find("^" .. var .. "%.") then
par = mw.text.split(mw.text.split(sta, "%.")[2], " ")[1]
elseif sta:find("^" .. var .. "%[") then
par = mw.text.split(mw.text.split(sta, "%[")[2], "%]")[1]
par = parser.value(par)
end
if par == nil then return userError("No property selection stated") end
return tab[par]
end
function parser.value(s, type)
type = type and type:upper():sub(1, 3) or nil
local expr = require "Module:Expr"
local ALTTYPE = function(s, key)
if s == "true" then return true
elseif s == "false" then return false
elseif s == "nil" then return nil
elseif string.find(s, "^function") then return function() end
elseif string.gsub(s, "[_%a][_%w]*", "_") == "_" and key then return parser.string("'" .. s .. "'")
elseif string.find(s, "^'") or string.find(s, '^"') then return parser.string(s)
else return pcall(function() expr.calc(s) end) and expr.calc(s) or parser.retrieve(s) end
end
function BRACKETS(s, type)
s = mw.text.trim(s)
local tab = {"{", "}"}
if type == "PAR" then tab = {"(", ")"}
elseif type == "SQU" then tab = {"[", "]"} end
if not string.find(s, tab[1], 1, true) and not string.find(s, tab[2], 1, true) then return ALTTYPE(s) end
local f, l = 0, 0
local litch = "\\"
local litfl = false
local nest = 0
local c = mw.text.split(s, "")
for i=1, #c do
if litfl == true then litfl = false
elseif c[i] == litch then litfl = true
elseif c[i]==tab[1] then
nest = nest + 1
if f == 0 then f = i end
elseif c[i]==tab[2] then
nest = nest - 1
if nest == 0 then
l = i
break
end
end
end
if l == 0 or f == 0 then print("what's up") end
return SPLIT(string.sub(s, f+1, l-1)), s:sub(l+1)
end
function SPLIT(s)
s = mw.text.trim(s)
local tab = {"{", "}"}
local c = mw.text.split(s, "")
local t = {}
local key = false
local val = ""
local pro = {"[", "]"}
local str = {'"', "'"}
local strAct = ""
local lit = "\\"
local litFlag = false
local ass = "="
local sep = ","
local m = 0--0 = Normal. 1 = Propertying, 2 = Tabling, 3 = Stringing
local mStack = {m}
function mE(v) if v then table.insert(mStack, m) m = v else m = mStack[#mStack] table.remove(mStack, #mStack) end end
local word = ""
local c = mw.text.split(s, "")
for i =1, #c do
local n = c[i]
if m == 0 then
if n == pro[1] then
mE(1)
elseif n == tab[1] then
mE(2)
elseif n == str[1] or n == str[2] then
mE(3) strAct = n val = val .. n
elseif n == ass then
key = val val = ""
elseif n == " " then
elseif n == sep then
t[ALTTYPE(key or #t+1, true)] = BRACKETS(val) key = false val = ""
else val = val .. n end
if i == #c then t[ALTTYPE(key or #t+1, true)] = BRACKETS(val) end
elseif m == 1 then
if key then return "ERROR" end
if n == pro[2] then
mE(0)
elseif n == tab[1] then
mE(2)
elseif n == str[1] or str[2] then
mE(3) strAct = n val = val .. n
else val = val .. n end
elseif m == 2 then
if n == tab[2] then
mE() t[ALTTYPE(key or #t+1, true)] = BRACKETS("{" .. val .. "}")
else val = val .. n end
elseif m == 3 then
if litFlag then litFlag = false
elseif n == lit then litFlag = true
elseif n == strAct then mE() val = val .. strAct
else
val = val .. n
end
if i == #c then t[ALTTYPE(key or #t+1, true)] = BRACKETS(val) end
end
end
return t
end
return BRACKETS(s, type)
end
function parser.retrieve(a)
if type(a)=="table" and a.args then a = a.args[1] end
local op = { prop = ".", meth = ":", inde = "[", para = "(" }
--function lessthanall(a, ...)
-- if type(a) ~= type(arg[1]) and type(arg[1]) == "table" then arg = arg[1] end
-- for i=1, #arg do
-- if arg[i] and not (a < arg[i]) then return false end
-- end
-- return true
--end
function minind(...)
local ind = 1
--local arg = table.pack(...)
if #arg == 0 then return nil, nil end
local m = arg[1]
for i=2, #arg do
if arg[i] < m then m = arg[i] ind=i end
end
return m, ind
end
local mode = 1
local next, prev
local self
local val = _G
if a:sub(1, 4) == "expr" then _G.expr = require "Module:Expr"
elseif a:sub(1, 5) == "color" then _G.color = require "Module:Color"
elseif a:sub(1, 6) == "parser" then _G.parser = require "Module:Parser"
elseif a:sub(1, 6) == "tabber" then _G.tabber = require "Module:Tabber"
end
function retself(a) return a end
while a ~= "" do
local opon
if val == _G and a:sub(1, 1) == "(" then val = retself mode = 4 a = a:sub(2) end
if mode == 3 then
opon, a = parser.value("[" .. a, "SQU")
elseif mode == 4 then
opon, a = parser.value("(" .. a, "PAR")
if prev == 2 then table.insert(opon, 1, self) end
end
local ix = {}
for k,v in pairs(op) do
ix[k] = a:find(v, nil, true) or 0xFF
end
local m, next = minind(ix.prop, ix.meth, ix.inde, ix.para)
if not opon then opon = a:sub(1, m-1) end
a = a:sub(m+1)
if val == _G and a == "" then val = parser.value(opon) break end
local params = false
local pstr
if mode == 1 then
val = val[opon]
elseif mode == 2 then
self = val
val = val[opon]
elseif mode == 3 then
val = val[table.unpack(opon)]
elseif mode == 4 then
val = val(table.unpack(opon))
end
prev = mode
mode = next
end
return tostring(val) == "table" and table.tostring(val) or tostring(val)
end
return parser