Module:Params: Difference between revisions
Jump to navigation
Jump to search
m (1 revision imported) |
(Performance only, no changes: avoid computing the length when possible) |
||
Line 16: | Line 16: | ||
local memoryslots = { | local memoryslots = { | ||
i = 'itersep', | i = 'itersep', | ||
l = 'lastsep', | |||
p = 'pairsep', | p = 'pairsep', | ||
h = 'header', | h = 'header', | ||
Line 39: | Line 40: | ||
local function context_init(frame, funcname, refpipe, refparams) | local function context_init(frame, funcname, refpipe, refparams) | ||
local ctx = {} | local ctx = {} | ||
ctx.luaname = 'Module:Params' --[[ or `frame:getTitle()` ]]-- | |||
ctx.iterfunc = pairs | ctx.iterfunc = pairs | ||
ctx.pipe = copy_or_ref_table(frame.args, refpipe) | ctx.pipe = copy_or_ref_table(frame.args, refpipe) | ||
Line 54: | Line 56: | ||
end | end | ||
if nextfn == nil then | if nextfn == nil then | ||
error(' | error(ctx.luaname .. ': You must specify a function to call', 0) | ||
end | end | ||
if library[nextfn] == nil then | if library[nextfn] == nil then | ||
error('The function | error(ctx.luaname .. ': The function ‘' .. nextfn .. '’ does not exist', 0) | ||
end | end | ||
for idx = n_forward, 1, -1 do table.remove(ctx.pipe, idx) end | for idx = n_forward, 1, -1 do table.remove(ctx.pipe, idx) end | ||
Line 94: | Line 96: | ||
local function | local function flush_params(ctx, fn) | ||
local tbl = ctx.params | local tbl = ctx.params | ||
if ctx.subset == 1 then | if ctx.subset == 1 then | ||
Line 106: | Line 108: | ||
local nums = {} | local nums = {} | ||
local words = {} | local words = {} | ||
local nlen = 0 | |||
local wlen = 0 | |||
for key, val in pairs(tbl) do | for key, val in pairs(tbl) do | ||
if type(key) == 'number' then | if type(key) == 'number' then | ||
nums[ | nlen = nlen + 1 | ||
nums[nlen] = key | |||
else | else | ||
words[ | wlen = wlen + 1 | ||
words[wlen] = key | |||
end | end | ||
Line 116: | Line 122: | ||
table.sort(nums) | table.sort(nums) | ||
table.sort(words) | table.sort(words) | ||
for idx = 1, | for idx = 1, nlen do fn(nums[idx], tbl[nums[idx]]) end | ||
for idx = 1, | for idx = 1, wlen do fn(words[idx], tbl[words[idx]]) end | ||
return | return | ||
end | end | ||
Line 135: | Line 141: | ||
local cnt = 1 | local cnt = 1 | ||
local keyw | local keyw | ||
local nptns = 0 | |||
for _, val in ipairs(opts) do | for _, val in ipairs(opts) do | ||
if state == 0 then | if state == 0 then | ||
ptns[ | nptns = nptns + 1 | ||
ptns[nptns] = { val, false } | |||
state = -1 | state = -1 | ||
else | else | ||
Line 144: | Line 152: | ||
else | else | ||
state = mkeywords[keyw] | state = mkeywords[keyw] | ||
if state ~= 0 then ptns[ | if state ~= 0 then ptns[nptns][2] = state end | ||
end | end | ||
end | end | ||
cnt = cnt + 1 | cnt = cnt + 1 | ||
end | end | ||
if state == 0 then error(fname .. ': No pattern was given', 0) end | if state == 0 then error(ctx.luaname .. ', ‘' .. fname .. '’: No pattern was given', 0) end | ||
return cnt | return cnt | ||
end | end | ||
Line 155: | Line 163: | ||
--[[ | --[[ Library's modifiers ]]-- | ||
-------------------------------- | -------------------------------- | ||
Line 161: | Line 169: | ||
-- See iface.sequential() | -- See iface.sequential() | ||
library.sequential = function(ctx) | library.sequential = function(ctx) | ||
if ctx.subset == -1 then error('The two directives | if ctx.subset == -1 then error(ctx.luaname .. ': The two directives ‘non-sequential’ and ‘sequential’ are in contradiction with each other', 0) end | ||
if ctx.dosort then error('The | if ctx.dosort then error(ctx.luaname .. ': The ‘all_sorted’ directive is redundant when followed by ‘sequential’', 0) end | ||
ctx.iterfunc = ipairs | ctx.iterfunc = ipairs | ||
ctx.subset = 1 | ctx.subset = 1 | ||
Line 171: | Line 179: | ||
-- See iface['non-sequential']() | -- See iface['non-sequential']() | ||
library['non-sequential'] = function(ctx) | library['non-sequential'] = function(ctx) | ||
if ctx.subset == 1 then error('The two directives | if ctx.subset == 1 then error(ctx.luaname .. ': The two directives ‘sequential’ and ‘non-sequential’ are in contradiction with each other', 0) end | ||
ctx.iterfunc = pairs | ctx.iterfunc = pairs | ||
ctx.subset = -1 | ctx.subset = -1 | ||
Line 180: | Line 188: | ||
-- See iface.all_sorted() | -- See iface.all_sorted() | ||
library.all_sorted = function(ctx) | library.all_sorted = function(ctx) | ||
if ctx.subset == 1 then error('The | if ctx.subset == 1 then error(ctx.luaname .. ': The ‘all_sorted’ directive is redundant after ‘sequential’', 0) end | ||
ctx.dosort = true | ctx.dosort = true | ||
return context_iterate(ctx, 1) | return context_iterate(ctx, 1) | ||
Line 193: | Line 201: | ||
cmd = opts[1]:gsub('%s+', ''):gsub('/+', '/'):match'^/*(.*[^/])' | cmd = opts[1]:gsub('%s+', ''):gsub('/+', '/'):match'^/*(.*[^/])' | ||
end | end | ||
if cmd == nil then error(' | if cmd == nil then error(ctx.luaname .. ', ‘setting’: No directive was given', 0) end | ||
local sep = string.byte('/') | local sep = string.byte('/') | ||
local argc = 2 | local argc = 2 | ||
Line 209: | Line 217: | ||
else | else | ||
vname = memoryslots[string.char(chr)] | vname = memoryslots[string.char(chr)] | ||
if vname == nil then error(' | if vname == nil then error(ctx.luaname .. ', ‘setting’: Unknown slot "' .. | ||
string.char(chr) .. '"', 0) end | string.char(chr) .. '"', 0) end | ||
table.insert(dest, vname) | table.insert(dest, vname) | ||
Line 224: | Line 232: | ||
local store = {} | local store = {} | ||
local indices = {} | local indices = {} | ||
local newlen = 0 | |||
for key, val in pairs(tbl) do | for key, val in pairs(tbl) do | ||
if type(key) == 'number' then | if type(key) == 'number' then | ||
indices[ | newlen = newlen + 1 | ||
indices[newlen] = key | |||
store[key] = val | store[key] = val | ||
tbl[key] = nil | tbl[key] = nil | ||
Line 232: | Line 242: | ||
end | end | ||
table.sort(indices) | table.sort(indices) | ||
for idx = 1, | for idx = 1, newlen do tbl[idx] = store[indices[idx]] end | ||
return context_iterate(ctx, 1) | return context_iterate(ctx, 1) | ||
end | end | ||
Line 240: | Line 250: | ||
library.cutting = function(ctx) | library.cutting = function(ctx) | ||
local lcut = tonumber(ctx.pipe[1]) | local lcut = tonumber(ctx.pipe[1]) | ||
if lcut == nil then error(' | if lcut == nil then error(ctx.luaname .. ', ‘cutting’: Left cut must be a number', 0) end | ||
local rcut = tonumber(ctx.pipe[2]) | local rcut = tonumber(ctx.pipe[2]) | ||
if rcut == nil then error(' | if rcut == nil then error(ctx.luaname .. ', ‘cutting’: Right cut must be a number', 0) end | ||
local tbl = ctx.params | local tbl = ctx.params | ||
local len = #tbl | local len = #tbl | ||
Line 364: | Line 374: | ||
-- See iface.mapping_values_by_calling() | |||
library.mapping_values_by_calling = function(ctx) | |||
local opts = ctx.pipe | |||
local tname | |||
if opts[1] ~= nil then tname = opts[1]:match'^%s*(.*%S)' end | |||
if tname == nil then error(ctx.luaname .. ', ‘mapping_values_by_calling’: No template name was provided', 0) end | |||
local nargs | |||
local margs = {} | |||
local tmp = tonumber(opts[2]) | |||
if tmp == nil then | |||
nargs = 1 | |||
elseif tmp < 1 then | |||
nargs = 2 | |||
else | |||
nargs = tmp + 2 | |||
for idx = 3, nargs do margs[idx] = opts[idx] end | |||
end | |||
local model = { title = tname, args = margs } | |||
local tbl = ctx.params | |||
if ctx.subset == 1 then | |||
for key, val in ipairs(tbl) do | |||
margs[1] = key | |||
margs[2] = val | |||
tbl[key] = ctx.frame:expandTemplate(model) | |||
end | |||
elseif ctx.subset == -1 then | |||
tmp = {} | |||
for key, val in pairs(tbl) do tmp[key] = true end | |||
for key, val in ipairs(tmp) do tmp[key] = nil end | |||
for key in pairs(tmp) do | |||
margs[1] = key | |||
margs[2] = tbl[key] | |||
tbl[key] = ctx.frame:expandTemplate(model) | |||
end | |||
else | |||
for key, val in pairs(tbl) do | |||
margs[1] = key | |||
margs[2] = val | |||
tbl[key] = ctx.frame:expandTemplate(model) | |||
end | |||
end | |||
return context_iterate(ctx, nargs + 1) | |||
end | |||
-- See iface.mapping_values_by_invoking() | |||
library.mapping_values_by_invoking = function(ctx) | |||
local opts = ctx.pipe | |||
local mname | |||
local fname | |||
if opts[1] ~= nil then mname = opts[1]:match'^%s*(.*%S)' end | |||
if mname == nil then error(ctx.luaname .. ', ‘mapping_values_by_invoking’: No module name was provided', 0) end | |||
if opts[2] ~= nil then fname = opts[2]:match'^%s*(.*%S)' end | |||
if fname == nil then error(ctx.luaname .. ', ‘mapping_values_by_invoking’: No function name was provided', 0) end | |||
local nargs | |||
local margs = {} | |||
local tmp = tonumber(opts[3]) | |||
if tmp == nil then | |||
nargs = 2 | |||
elseif tmp < 1 then | |||
nargs = 3 | |||
else | |||
nargs = tmp + 3 | |||
for idx = 4, nargs do margs[idx - 1] = opts[idx] end | |||
end | |||
local model = { title = 'Module:' .. mname, args = margs } | |||
local mfunc = require(model.title)[fname] | |||
local tbl = ctx.params | |||
if ctx.subset == 1 then | |||
for key, val in ipairs(tbl) do | |||
margs[1] = key | |||
margs[2] = val | |||
tbl[key] = mfunc(ctx.frame:newChild(model)) | |||
end | |||
elseif ctx.subset == -1 then | |||
tmp = {} | |||
for key, val in pairs(tbl) do tmp[key] = true end | |||
for key, val in ipairs(tmp) do tmp[key] = nil end | |||
for key in pairs(tmp) do | |||
margs[1] = key | |||
margs[2] = tbl[key] | |||
tbl[key] = mfunc(ctx.frame:newChild(model)) | |||
end | |||
else | |||
for key, val in pairs(tbl) do | |||
margs[1] = key | |||
margs[2] = val | |||
tbl[key] = mfunc(ctx.frame:newChild(model)) | |||
end | |||
end | |||
return context_iterate(ctx, nargs + 1) | |||
end | |||
--[[ | |||
-- See iface.mapping_values_blindly_by_calling() | |||
library.mapping_values_blindly_by_calling = function(ctx) | |||
local opts = ctx.pipe | |||
local tname | |||
if opts[1] ~= nil then tname = opts[1]:match'^%s*(.*%S)' end | |||
if tname == nil then error(ctx.luaname .. ', ‘mapping_values_blindly_by_calling’: No template name was provided', 0) end | |||
local nargs | |||
local margs = {} | |||
local tmp = tonumber(opts[2]) | |||
if tmp == nil then | |||
nargs = 1 | |||
elseif tmp < 1 then | |||
nargs = 2 | |||
else | |||
nargs = tmp + 2 | |||
for idx = 3, nargs do margs[idx - 1] = opts[idx] end | |||
end | |||
local model = { title = tname, args = margs } | |||
local tbl = ctx.params | |||
if ctx.subset == 1 then | |||
for key, val in ipairs(tbl) do | |||
margs[1] = val | |||
tbl[key] = ctx.frame:expandTemplate(model) | |||
end | |||
elseif ctx.subset == -1 then | |||
tmp = {} | |||
for key, val in pairs(tbl) do tmp[key] = true end | |||
for key, val in ipairs(tmp) do tmp[key] = nil end | |||
for key in pairs(tmp) do | |||
margs[1] = tbl[key] | |||
tbl[key] = ctx.frame:expandTemplate(model) | |||
end | |||
else | |||
for key, val in pairs(tbl) do | |||
margs[1] = val | |||
tbl[key] = ctx.frame:expandTemplate(model) | |||
end | |||
end | |||
return context_iterate(ctx, nargs + 1) | |||
end | |||
-- See iface.mapping_values_blindly_by_invoking() | |||
library.mapping_values_blindly_by_invoking = function(ctx) | |||
local opts = ctx.pipe | |||
local mname | |||
local fname | |||
if opts[1] ~= nil then mname = opts[1]:match'^%s*(.*%S)' end | |||
if mname == nil then error(ctx.luaname .. ', ‘mapping_values_blindly_by_invoking’: No module name was provided', 0) end | |||
if opts[2] ~= nil then fname = opts[2]:match'^%s*(.*%S)' end | |||
if fname == nil then error(ctx.luaname .. ', ‘mapping_values_blindly_by_invoking’: No function name was provided', 0) end | |||
local nargs | |||
local margs = {} | |||
local tmp = tonumber(opts[3]) | |||
if tmp == nil then | |||
nargs = 2 | |||
elseif tmp < 1 then | |||
nargs = 3 | |||
else | |||
nargs = tmp + 3 | |||
for idx = 4, nargs do margs[idx - 2] = opts[idx] end | |||
end | |||
local model = { title = 'Module:' .. mname, args = margs } | |||
local mfunc = require(model.title)[fname] | |||
local tbl = ctx.params | |||
if ctx.subset == 1 then | |||
for key, val in ipairs(tbl) do | |||
margs[1] = val | |||
tbl[key] = mfunc(ctx.frame:newChild(model)) | |||
end | |||
elseif ctx.subset == -1 then | |||
tmp = {} | |||
for key, val in pairs(tbl) do tmp[key] = true end | |||
for key, val in ipairs(tmp) do tmp[key] = nil end | |||
for key in pairs(tmp) do | |||
margs[1] = tbl[key] | |||
tbl[key] = mfunc(ctx.frame:newChild(model)) | |||
end | |||
else | |||
for key, val in pairs(tbl) do | |||
margs[1] = val | |||
tbl[key] = mfunc(ctx.frame:newChild(model)) | |||
end | |||
end | |||
return context_iterate(ctx, nargs + 1) | |||
end | |||
--[[ Library's functions ]]-- | |||
------------------------------------ | ------------------------------------ | ||
Line 383: | Line 579: | ||
local tname | local tname | ||
if opts[1] ~= nil then tname = opts[1]:match'^%s*(.*%S)' end | if opts[1] ~= nil then tname = opts[1]:match'^%s*(.*%S)' end | ||
if tname == nil then error(' | if tname == nil then error(ctx.luaname .. ', ‘concat_and_call’: No template name was provided', 0) end | ||
table.remove(opts, 1) | table.remove(opts, 1) | ||
return ctx.frame:expandTemplate{ | return ctx.frame:expandTemplate{ | ||
Line 398: | Line 594: | ||
local fname | local fname | ||
if opts[1] ~= nil then mname = opts[1]:match'^%s*(.*%S)' end | if opts[1] ~= nil then mname = opts[1]:match'^%s*(.*%S)' end | ||
if mname == nil then error(' | if mname == nil then error(ctx.luaname .. ', ‘concat_and_invoke’: No module name was provided', 0) end | ||
if opts[2] ~= nil then fname = opts[2]:match'^%s*(.*%S)' end | if opts[2] ~= nil then fname = opts[2]:match'^%s*(.*%S)' end | ||
if fname == nil then error(' | if fname == nil then error(ctx.luaname .. ', ‘concat_and_invoke’: No function name was provided', 0) end | ||
table.remove(opts, 2) | table.remove(opts, 2) | ||
table.remove(opts, 1) | table.remove(opts, 1) | ||
Line 407: | Line 603: | ||
args = concat_params(ctx) | args = concat_params(ctx) | ||
}) | }) | ||
end | |||
-- See iface.concat_and_magic() | |||
library.concat_and_magic = function(ctx) | |||
local opts = ctx.pipe | |||
local magic | |||
if opts[1] ~= nil then magic = opts[1]:match'^%s*(.*%S)' end | |||
if magic == nil then error(ctx.luaname .. ', ‘concat_and_magic’: No parser function was provided', 0) end | |||
table.remove(opts, 1) | |||
return ctx.frame:callParserFunction(magic, concat_params(ctx)) | |||
end | end | ||
Line 415: | Line 622: | ||
local keystr | local keystr | ||
if opts[1] ~= nil then keystr = opts[1]:match'^%s*(.*%S)' end | if opts[1] ~= nil then keystr = opts[1]:match'^%s*(.*%S)' end | ||
if keystr == nil then error(' | if keystr == nil then error(ctx.luaname .. ', ‘value_of’: No parameter name was provided', 0) end | ||
local keynum = tonumber(keystr) | local keynum = tonumber(keystr) | ||
local len = #ctx.params | |||
if ( | if ( | ||
ctx.subset == -1 and keynum ~= nil and | ctx.subset == -1 and keynum ~= nil and len >= keynum | ||
) or ( | ) or ( | ||
ctx.subset == 1 and (keynum == nil or | ctx.subset == 1 and (keynum == nil or len < keynum) | ||
) then return (ctx.ifngiven or '') end | ) then return (ctx.ifngiven or '') end | ||
local val = ctx.params[keynum or keystr] | local val = ctx.params[keynum or keystr] | ||
Line 430: | Line 638: | ||
-- See iface.list() | -- See iface.list() | ||
library.list = function(ctx) | library.list = function(ctx) | ||
local kvs = ctx.pairsep or '' | |||
local pps = ctx.itersep or '' | local pps = ctx.itersep or '' | ||
local | local ret = {} | ||
local nss = 0 | |||
flush_params( | |||
local | |||
ctx, | ctx, | ||
function(key, val) | function(key, val) | ||
ret = ret | ret[nss + 1] = pps | ||
ret[nss + 2] = key | |||
ret[nss + 3] = kvs | |||
ret[nss + 4] = val | |||
nss = nss + 4 | |||
end | end | ||
) | ) | ||
return ret . | if nss > 0 then | ||
if nss > 4 and ctx.lastsep ~= nil then | |||
ret[nss - 3] = ctx.lastsep | |||
end | |||
ret[1] = ctx.header or '' | |||
if ctx.footer ~= nil then ret[nss + 1] = ctx.footer end | |||
return table.concat(ret) | |||
end | |||
return ctx.ifngiven or '' | |||
end | end | ||
Line 451: | Line 667: | ||
library.list_values = function(ctx) | library.list_values = function(ctx) | ||
local pps = ctx.itersep or '' | local pps = ctx.itersep or '' | ||
local | local ret = {} | ||
local nss = 0 | |||
local | flush_params( | ||
ctx, | ctx, | ||
function(key, val) | function(key, val) | ||
ret = | ret[nss + 1] = pps | ||
ret[nss + 2] = val | |||
nss = nss + 2 | |||
end | end | ||
) | ) | ||
return ret . | if nss > 0 then | ||
if nss > 2 and ctx.lastsep ~= nil then | |||
ret[nss - 1] = ctx.lastsep | |||
end | |||
ret[1] = ctx.header or '' | |||
if ctx.footer ~= nil then ret[nss + 1] = ctx.footer end | |||
return table.concat(ret) | |||
end | |||
return ctx.ifngiven or '' | |||
end | end | ||
Line 469: | Line 691: | ||
-- See iface.for_each() | -- See iface.for_each() | ||
library.for_each = function(ctx) | library.for_each = function(ctx) | ||
local txt = ctx.pipe[1] or '' | |||
local pps = ctx.itersep or '' | local pps = ctx.itersep or '' | ||
local | local ret = {} | ||
local nss = 0 | |||
flush_params( | |||
local | |||
ctx, | ctx, | ||
function(key, val) | function(key, val) | ||
ret = ret | ret[nss + 1] = pps | ||
ret[nss + 2] = txt:gsub('%$#', key):gsub('%$@', val) | |||
nss = nss + 2 | |||
end | end | ||
) | ) | ||
return ret . | if nss > 0 then | ||
if nss > 2 and ctx.lastsep ~= nil then | |||
ret[nss - 1] = ctx.lastsep | |||
end | |||
ret[1] = ctx.header or '' | |||
if ctx.footer ~= nil then ret[nss + 1] = ctx.footer end | |||
return table.concat(ret) | |||
end | |||
return ctx.ifngiven or '' | |||
end | end | ||
Line 493: | Line 717: | ||
-- See iface.call_for_each() | -- See iface.call_for_each() | ||
library.call_for_each = function(ctx) | library.call_for_each = function(ctx) | ||
local opts = ctx.pipe | local opts = ctx.pipe | ||
local tname | local tname | ||
if opts[1] ~= nil then tname = opts[1]:match'^%s*(.*%S)' end | if opts[1] ~= nil then tname = opts[1]:match'^%s*(.*%S)' end | ||
if tname == nil then error(' | if tname == nil then error(ctx.luaname .. ', ‘call_for_each’: No template name was provided', 0) end | ||
local model = { title = tname, args = opts } | |||
local ccs = ctx.itersep or '' | local ccs = ctx.itersep or '' | ||
local | local ret = {} | ||
local nss = 0 | |||
local | |||
table.insert(opts, 1, true) | table.insert(opts, 1, true) | ||
flush_params( | |||
ctx, | ctx, | ||
function(key, val) | function(key, val) | ||
opts[1] = key | opts[1] = key | ||
opts[2] = val | opts[2] = val | ||
ret = ret | ret[nss + 1] = ccs | ||
ret[nss + 2] = ctx.frame:expandTemplate(model) | |||
nss = nss + 2 | |||
end | end | ||
) | ) | ||
if nss > 0 then | |||
if nss > 2 and ctx.lastsep ~= nil then | |||
ret[nss - 1] = ctx.lastsep | |||
end | |||
ret[1] = ctx.header or '' | |||
if ctx.footer ~= nil then ret[nss + 1] = ctx.footer end | |||
return table.concat(ret) | |||
end | |||
return ctx.ifngiven or '' | |||
end | end | ||
Line 527: | Line 750: | ||
-- See iface.invoke_for_each() | -- See iface.invoke_for_each() | ||
library.invoke_for_each = function(ctx) | library.invoke_for_each = function(ctx) | ||
local opts = ctx.pipe | local opts = ctx.pipe | ||
local mname | local mname | ||
local fname | local fname | ||
if opts[1] ~= nil then mname = opts[1]:match'^%s*(.*%S)' end | if opts[1] ~= nil then mname = opts[1]:match'^%s*(.*%S)' end | ||
if mname == nil then error(' | if mname == nil then error(ctx.luaname .. ', ‘invoke_for_each’: No module name was provided', 0) end | ||
if opts[2] ~= nil then fname = opts[2]:match'^%s*(.*%S)' end | if opts[2] ~= nil then fname = opts[2]:match'^%s*(.*%S)' end | ||
if fname == nil then error(' | if fname == nil then error(ctx.luaname .. ', ‘invoke_for_each’: No function name was provided', 0) end | ||
local model = { title = 'Module:' .. mname, args = opts } | local model = { title = 'Module:' .. mname, args = opts } | ||
local mfunc = require(model.title)[fname] | local mfunc = require(model.title)[fname] | ||
local | local ccs = ctx.itersep or '' | ||
local ret = {} | |||
local nss = 0 | |||
flush_params( | |||
ctx, | ctx, | ||
function(key, val) | function(key, val) | ||
opts[1] = key | opts[1] = key | ||
opts[2] = val | opts[2] = val | ||
ret = ret | ret[nss + 1] = ccs | ||
ret[nss + 2] = mfunc(ctx.frame:newChild(model)) | |||
nss = nss + 2 | |||
end | end | ||
) | ) | ||
if nss > 0 then | |||
if nss > 2 and ctx.lastsep ~= nil then | |||
ret[nss - 1] = ctx.lastsep | |||
end | |||
ret[1] = ctx.header or '' | |||
if ctx.footer ~= nil then ret[nss + 1] = ctx.footer end | |||
return table.concat(ret) | |||
end | |||
return ctx.ifngiven or '' | |||
end | end | ||
Line 563: | Line 786: | ||
-- See iface.magic_for_each() | -- See iface.magic_for_each() | ||
library.magic_for_each = function(ctx) | library.magic_for_each = function(ctx) | ||
local opts = ctx.pipe | local opts = ctx.pipe | ||
local magic | local magic | ||
if opts[1] ~= nil then magic = opts[1]:match'^%s*(.*%S)' end | if opts[1] ~= nil then magic = opts[1]:match'^%s*(.*%S)' end | ||
if magic == nil then error(' | if magic == nil then error(ctx.luaname .. ', ‘magic_for_each’: No parser function was provided', 0) end | ||
local ccs = ctx.itersep or '' | local ccs = ctx.itersep or '' | ||
local | local ret = {} | ||
local nss = 0 | |||
local | |||
table.insert(opts, 1, true) | table.insert(opts, 1, true) | ||
flush_params( | |||
ctx, | ctx, | ||
function(key, val) | function(key, val) | ||
opts[1] = key | opts[1] = key | ||
opts[2] = val | opts[2] = val | ||
ret = ret | ret[nss + 1] = ccs | ||
ret[nss + 2] = ctx.frame:callParserFunction(magic, | |||
opts) | |||
nss = nss + 2 | |||
end | end | ||
) | ) | ||
if nss > 0 then | |||
if nss > 2 and ctx.lastsep ~= nil then | |||
ret[nss - 1] = ctx.lastsep | |||
end | |||
ret[1] = ctx.header or '' | |||
if ctx.footer ~= nil then ret[nss + 1] = ctx.footer end | |||
return table.concat(ret) | |||
end | |||
return ctx.ifngiven or '' | |||
end | end | ||
Line 596: | Line 819: | ||
-- See iface.call_for_each_value() | -- See iface.call_for_each_value() | ||
library.call_for_each_value = function(ctx) | library.call_for_each_value = function(ctx) | ||
local opts = ctx.pipe | local opts = ctx.pipe | ||
local tname | local tname | ||
if opts[1] ~= nil then tname = opts[1]:match'^%s*(.*%S)' end | if opts[1] ~= nil then tname = opts[1]:match'^%s*(.*%S)' end | ||
if tname == nil then error(' | if tname == nil then error(ctx.luaname .. ', ‘call_for_each_value’: No template name was provided', 0) end | ||
local model = { title = tname, args = opts } | |||
local ccs = ctx.itersep or '' | local ccs = ctx.itersep or '' | ||
local | local ret = {} | ||
local nss = 0 | |||
flush_params( | |||
local | |||
ctx, | ctx, | ||
function(key, val) | function(key, val) | ||
opts[1] = val | opts[1] = val | ||
ret = ret | ret[nss + 1] = ccs | ||
ret[nss + 2] = ctx.frame:expandTemplate(model) | |||
nss = nss + 2 | |||
end | end | ||
) | ) | ||
if nss > 0 then | |||
if nss > 2 and ctx.lastsep ~= nil then | |||
ret[nss - 1] = ctx.lastsep | |||
end | |||
ret[1] = ctx.header or '' | |||
if ctx.footer ~= nil then ret[nss + 1] = ctx.footer end | |||
return table.concat(ret) | |||
end | |||
return ctx.ifngiven or '' | |||
end | end | ||
Line 627: | Line 850: | ||
-- See iface.invoke_for_each_value() | -- See iface.invoke_for_each_value() | ||
library.invoke_for_each_value = function(ctx) | library.invoke_for_each_value = function(ctx) | ||
local opts = ctx.pipe | local opts = ctx.pipe | ||
local mname | local mname | ||
local fname | local fname | ||
if opts[1] ~= nil then mname = opts[1]:match'^%s*(.*%S)' end | if opts[1] ~= nil then mname = opts[1]:match'^%s*(.*%S)' end | ||
if mname == nil then error(' | if mname == nil then error(ctx.luaname .. ', ‘invoke_for_each_value’: No module name was provided', 0) end | ||
if opts[2] ~= nil then fname = opts[2]:match'^%s*(.*%S)' end | if opts[2] ~= nil then fname = opts[2]:match'^%s*(.*%S)' end | ||
if fname == nil then error(' | if fname == nil then error(ctx.luaname .. ', ‘invoke_for_each_value’: No function name was provided', 0) end | ||
local model = { title = 'Module:' .. mname, args = opts } | local model = { title = 'Module:' .. mname, args = opts } | ||
local mfunc = require(model.title)[fname] | local mfunc = require(model.title)[fname] | ||
local | local ccs = ctx.itersep or '' | ||
local ret = {} | |||
local nss = 0 | |||
table.remove(opts, 1) | table.remove(opts, 1) | ||
flush_params( | |||
ctx, | ctx, | ||
function(key, val) | function(key, val) | ||
opts[1] = val | opts[1] = val | ||
ret = ret | ret[nss + 1] = ccs | ||
ret[nss + 2] = mfunc(ctx.frame:newChild(model)) | |||
nss = nss + 2 | |||
end | end | ||
) | ) | ||
if nss > 0 then | |||
return | if nss > 2 and ctx.lastsep ~= nil then | ||
ret[nss - 1] = ctx.lastsep | |||
end | |||
ret[1] = ctx.header or '' | |||
if ctx.footer ~= nil then ret[nss + 1] = ctx.footer end | |||
return table.concat(ret) | |||
end | |||
return ctx.ifngiven or '' | |||
end | end | ||
Line 664: | Line 887: | ||
-- See iface.magic_for_each_value() | -- See iface.magic_for_each_value() | ||
library.magic_for_each_value = function(ctx) | library.magic_for_each_value = function(ctx) | ||
local opts = ctx.pipe | local opts = ctx.pipe | ||
local magic | local magic | ||
if opts[1] ~= nil then magic = opts[1]:match'^%s*(.*%S)' end | if opts[1] ~= nil then magic = opts[1]:match'^%s*(.*%S)' end | ||
if magic == nil then error(' | if magic == nil then error(ctx.luaname .. ', ‘magic_for_each_value’: No parser function was provided', 0) end | ||
local ccs = ctx.itersep or '' | local ccs = ctx.itersep or '' | ||
local | local ret = {} | ||
local nss = 0 | |||
local | flush_params( | ||
ctx, | ctx, | ||
function(key, val) | function(key, val) | ||
opts[1] = val | opts[1] = val | ||
ret = ret | ret[nss + 1] = ccs | ||
ret[nss + 2] = ctx.frame:callParserFunction(magic, | |||
opts) | opts) | ||
nss = nss + 2 | |||
end | end | ||
) | ) | ||
if nss > 0 then | |||
if nss > 2 and ctx.lastsep ~= nil then | |||
ret[nss - 1] = ctx.lastsep | |||
end | |||
ret[1] = ctx.header or '' | |||
if ctx.footer ~= nil then ret[nss + 1] = ctx.footer end | |||
return table.concat(ret) | |||
end | |||
return ctx.ifngiven or '' | |||
end | end | ||
Line 711: | Line 934: | ||
--[[ | --[[ Modifiers ]]-- | ||
------------------------------------ | ------------------------------------ | ||
Line 791: | Line 1,014: | ||
-- Syntax: #invoke:params|mapping_values_by_calling|template name|[number of additional | |||
-- arguments]|[argument 1]|[argument 2]|[...]|[argument N]|function | |||
-- name | |||
iface.mapping_values_by_calling = function(frame) | |||
return context_init(frame, library.mapping_values_by_calling, false, false) | |||
end | |||
-- Syntax: #invoke:params|mapping_values_by_invoking|module name|function name|[number of | |||
-- additional arguments]|[argument 1]|[argument 2]|[...]|[argument | |||
-- N]|function name | |||
iface.mapping_values_by_invoking = function(frame) | |||
return context_init(frame, library.mapping_values_by_invoking, false, false) | |||
end | |||
--[[ | |||
-- Syntax: #invoke:params|mapping_values_blindly_by_calling|template name|[number of | |||
-- additional arguments]|[argument 1]|[argument 2]|[...]|[argument | |||
-- N]|function name | |||
iface.mapping_values_blindly_by_calling = function(frame) | |||
return context_init(frame, library.mapping_values_blindly_by_calling, false, | |||
false) | |||
end | |||
-- Syntax: #invoke:params|mapping_values_blindly_by_invoking|module name|function name | |||
-- |[number of additional arguments]|[argument 1]|[argument 2]|[...] | |||
-- |[argument N]|function name | |||
iface.mapping_values_blindly_by_invoking = function(frame) | |||
return context_init(frame, library.mapping_values_blindly_by_invoking, false, | |||
false) | |||
end | |||
--[[ Functions ]]-- | |||
---------------------------------------- | ---------------------------------------- | ||
Line 815: | Line 1,073: | ||
iface.concat_and_invoke = function(frame) | iface.concat_and_invoke = function(frame) | ||
return context_init(frame, library.concat_and_invoke, false, true) | return context_init(frame, library.concat_and_invoke, false, true) | ||
end | |||
-- Syntax: #invoke:args|concat_and_magic|parser function|[prepend 1]|[prepend | |||
-- 2]|[...]|[item n]|[named item 1=value 1]|[...]|[named item n= | |||
-- value n]|[...] | |||
iface.concat_and_magic = function(frame) | |||
return context_init(frame, library.concat_and_magic, false, true) | |||
end | end | ||
Revision as of 17:41, 4 February 2024
Documentation for this module may be created at Module:Params/doc
--- --- --- LOCAL ENVIRONMENT --- --- ________________________________ --- --- --- -- Special user-given keywords (functions and modifiers MUST avoid these names) local mkeywords = { -- ['pattern'] = false, ['plain'] = true, ['or'] = 0 } -- Set directives local memoryslots = { i = 'itersep', l = 'lastsep', p = 'pairsep', h = 'header', f = 'footer', n = 'ifngiven' } -- The private table of functions local library = {} -- Return a copy or a reference to a table local function copy_or_ref_table(src, refonly) if refonly then return src end newtab = {} for key, val in pairs(src) do newtab[key] = val end return newtab end -- Prepare the context local function context_init(frame, funcname, refpipe, refparams) local ctx = {} ctx.luaname = 'Module:Params' --[[ or `frame:getTitle()` ]]-- ctx.iterfunc = pairs ctx.pipe = copy_or_ref_table(frame.args, refpipe) ctx.frame = frame:getParent() ctx.params = copy_or_ref_table(ctx.frame.args, refparams) return funcname(ctx) end -- Move to the next action within the user-given list local function context_iterate(ctx, n_forward) local nextfn if ctx.pipe[n_forward] ~= nil then nextfn = ctx.pipe[n_forward]:match'^%s*(.*%S)' end if nextfn == nil then error(ctx.luaname .. ': You must specify a function to call', 0) end if library[nextfn] == nil then error(ctx.luaname .. ': The function ‘' .. nextfn .. '’ does not exist', 0) end for idx = n_forward, 1, -1 do table.remove(ctx.pipe, idx) end return library[nextfn](ctx) end -- Concatenate the numerical keys from the table of parameters to the numerical -- keys from the table of options; non-numerical keys from the table of options -- will prevail over colliding non-numerical keys from the table of parameters local function concat_params(ctx) local shift = table.maxn(ctx.pipe) local newargs = {} if ctx.subset == 1 then -- We need only the sequence for key, val in ipairs(ctx.params) do newargs[key + shift] = val end else if ctx.subset == -1 then for key, val in ipairs(ctx.params) do ctx.params[key] = nil end end for key, val in pairs(ctx.params) do if type(key) == 'number' then newargs[key + shift] = val else newargs[key] = val end end end for key, val in pairs(ctx.pipe) do newargs[key] = val end return newargs end local function flush_params(ctx, fn) local tbl = ctx.params if ctx.subset == 1 then for key, val in ipairs(tbl) do fn(key, val) end return end if ctx.subset == -1 then for key, val in ipairs(tbl) do tbl[key] = nil end end if ctx.dosort then local nums = {} local words = {} local nlen = 0 local wlen = 0 for key, val in pairs(tbl) do if type(key) == 'number' then nlen = nlen + 1 nums[nlen] = key else wlen = wlen + 1 words[wlen] = key end end table.sort(nums) table.sort(words) for idx = 1, nlen do fn(nums[idx], tbl[nums[idx]]) end for idx = 1, wlen do fn(words[idx], tbl[words[idx]]) end return end if ctx.subset ~= -1 then for key, val in ipairs(tbl) do fn(key, val) tbl[key] = nil end end for key, val in pairs(tbl) do fn(key, val) end end -- Parse the arguments of the `with_*_matching` class of modifiers local function parse_match_args(opts, ptns, fname) local state = 0 local cnt = 1 local keyw local nptns = 0 for _, val in ipairs(opts) do if state == 0 then nptns = nptns + 1 ptns[nptns] = { val, false } state = -1 else keyw = val:match'^%s*(.*%S)' if keyw == nil or mkeywords[keyw] == nil then break else state = mkeywords[keyw] if state ~= 0 then ptns[nptns][2] = state end end end cnt = cnt + 1 end if state == 0 then error(ctx.luaname .. ', ‘' .. fname .. '’: No pattern was given', 0) end return cnt end --[[ Library's modifiers ]]-- -------------------------------- -- See iface.sequential() library.sequential = function(ctx) if ctx.subset == -1 then error(ctx.luaname .. ': The two directives ‘non-sequential’ and ‘sequential’ are in contradiction with each other', 0) end if ctx.dosort then error(ctx.luaname .. ': The ‘all_sorted’ directive is redundant when followed by ‘sequential’', 0) end ctx.iterfunc = ipairs ctx.subset = 1 return context_iterate(ctx, 1) end -- See iface['non-sequential']() library['non-sequential'] = function(ctx) if ctx.subset == 1 then error(ctx.luaname .. ': The two directives ‘sequential’ and ‘non-sequential’ are in contradiction with each other', 0) end ctx.iterfunc = pairs ctx.subset = -1 return context_iterate(ctx, 1) end -- See iface.all_sorted() library.all_sorted = function(ctx) if ctx.subset == 1 then error(ctx.luaname .. ': The ‘all_sorted’ directive is redundant after ‘sequential’', 0) end ctx.dosort = true return context_iterate(ctx, 1) end -- See iface.setting() library.setting = function(ctx) local opts = ctx.pipe local cmd if opts[1] ~= nil then cmd = opts[1]:gsub('%s+', ''):gsub('/+', '/'):match'^/*(.*[^/])' end if cmd == nil then error(ctx.luaname .. ', ‘setting’: No directive was given', 0) end local sep = string.byte('/') local argc = 2 local dest = {} local vname local chr for idx = 1, #cmd do chr = cmd:byte(idx) if chr == sep then for key, val in ipairs(dest) do ctx[val] = opts[argc] dest[key] = nil end argc = argc + 1 else vname = memoryslots[string.char(chr)] if vname == nil then error(ctx.luaname .. ', ‘setting’: Unknown slot "' .. string.char(chr) .. '"', 0) end table.insert(dest, vname) end end for key, val in ipairs(dest) do ctx[val] = opts[argc] end return context_iterate(ctx, argc + 1) end -- See iface.squeezing() library.squeezing = function(ctx) local tbl = ctx.params local store = {} local indices = {} local newlen = 0 for key, val in pairs(tbl) do if type(key) == 'number' then newlen = newlen + 1 indices[newlen] = key store[key] = val tbl[key] = nil end end table.sort(indices) for idx = 1, newlen do tbl[idx] = store[indices[idx]] end return context_iterate(ctx, 1) end -- See iface.cutting() library.cutting = function(ctx) local lcut = tonumber(ctx.pipe[1]) if lcut == nil then error(ctx.luaname .. ', ‘cutting’: Left cut must be a number', 0) end local rcut = tonumber(ctx.pipe[2]) if rcut == nil then error(ctx.luaname .. ', ‘cutting’: Right cut must be a number', 0) end local tbl = ctx.params local len = #tbl if lcut < 0 then lcut = len + lcut end if rcut < 0 then rcut = len + rcut end local tot = lcut + rcut if tot > 0 then local cache = {} if tot >= len then for key, val in ipairs(tbl) do tbl[key] = nil end tot = len else for idx = len - rcut + 1, len, 1 do tbl[idx] = nil end for idx = 1, lcut, 1 do tbl[idx] = nil end end for key, val in pairs(tbl) do if type(key) == 'number' and key > 0 then if key > len then cache[key - tot] = val else cache[key - lcut] = val end tbl[key] = nil end end for key, val in pairs(cache) do tbl[key] = val end end return context_iterate(ctx, 3) end -- See iface.with_name_matching() library.with_name_matching = function(ctx) local tbl = ctx.params local patterns = {} local argc = parse_match_args(ctx.pipe, patterns, 'with_name_matching') local nomatch for key in pairs(tbl) do nomatch = true for _, ptn in ipairs(patterns) do if string.find(key, ptn[1], 1, ptn[2]) then nomatch = false break end end if nomatch then tbl[key] = nil end end return context_iterate(ctx, argc) end -- See iface.with_name_not_matching() library.with_name_not_matching = function(ctx) local tbl = ctx.params local patterns = {} local argc = parse_match_args(ctx.pipe, patterns, 'with_name_not_matching') local yesmatch for key in pairs(tbl) do yesmatch = true for _, ptn in ipairs(patterns) do if not string.find(key, ptn[1], 1, ptn[2]) then yesmatch = false break end end if yesmatch then tbl[key] = nil end end return context_iterate(ctx, argc) end -- See iface.with_value_matching() library.with_value_matching = function(ctx) local tbl = ctx.params local patterns = {} local argc = parse_match_args(ctx.pipe, patterns, 'with_value_matching') local nomatch for key, val in pairs(tbl) do nomatch = true for _, ptn in ipairs(patterns) do if string.find(val, ptn[1], 1, ptn[2]) then nomatch = false break end end if nomatch then tbl[key] = nil end end return context_iterate(ctx, argc) end -- See iface.with_value_not_matching() library.with_value_not_matching = function(ctx) local tbl = ctx.params local patterns = {} local argc = parse_match_args(ctx.pipe, patterns, 'with_value_not_matching') local yesmatch for key, val in pairs(tbl) do yesmatch = true for _, ptn in ipairs(patterns) do if not string.find(val, ptn[1], 1, ptn[2]) then yesmatch = false break end end if yesmatch then tbl[key] = nil end end return context_iterate(ctx, argc) end -- See iface.trimming_values() library.trimming_values = function(ctx) local tbl = ctx.params for key, val in pairs(tbl) do tbl[key] = val:match'^%s*(.-)%s*$' end return context_iterate(ctx, 1) end -- See iface.mapping_values_by_calling() library.mapping_values_by_calling = function(ctx) local opts = ctx.pipe local tname if opts[1] ~= nil then tname = opts[1]:match'^%s*(.*%S)' end if tname == nil then error(ctx.luaname .. ', ‘mapping_values_by_calling’: No template name was provided', 0) end local nargs local margs = {} local tmp = tonumber(opts[2]) if tmp == nil then nargs = 1 elseif tmp < 1 then nargs = 2 else nargs = tmp + 2 for idx = 3, nargs do margs[idx] = opts[idx] end end local model = { title = tname, args = margs } local tbl = ctx.params if ctx.subset == 1 then for key, val in ipairs(tbl) do margs[1] = key margs[2] = val tbl[key] = ctx.frame:expandTemplate(model) end elseif ctx.subset == -1 then tmp = {} for key, val in pairs(tbl) do tmp[key] = true end for key, val in ipairs(tmp) do tmp[key] = nil end for key in pairs(tmp) do margs[1] = key margs[2] = tbl[key] tbl[key] = ctx.frame:expandTemplate(model) end else for key, val in pairs(tbl) do margs[1] = key margs[2] = val tbl[key] = ctx.frame:expandTemplate(model) end end return context_iterate(ctx, nargs + 1) end -- See iface.mapping_values_by_invoking() library.mapping_values_by_invoking = function(ctx) local opts = ctx.pipe local mname local fname if opts[1] ~= nil then mname = opts[1]:match'^%s*(.*%S)' end if mname == nil then error(ctx.luaname .. ', ‘mapping_values_by_invoking’: No module name was provided', 0) end if opts[2] ~= nil then fname = opts[2]:match'^%s*(.*%S)' end if fname == nil then error(ctx.luaname .. ', ‘mapping_values_by_invoking’: No function name was provided', 0) end local nargs local margs = {} local tmp = tonumber(opts[3]) if tmp == nil then nargs = 2 elseif tmp < 1 then nargs = 3 else nargs = tmp + 3 for idx = 4, nargs do margs[idx - 1] = opts[idx] end end local model = { title = 'Module:' .. mname, args = margs } local mfunc = require(model.title)[fname] local tbl = ctx.params if ctx.subset == 1 then for key, val in ipairs(tbl) do margs[1] = key margs[2] = val tbl[key] = mfunc(ctx.frame:newChild(model)) end elseif ctx.subset == -1 then tmp = {} for key, val in pairs(tbl) do tmp[key] = true end for key, val in ipairs(tmp) do tmp[key] = nil end for key in pairs(tmp) do margs[1] = key margs[2] = tbl[key] tbl[key] = mfunc(ctx.frame:newChild(model)) end else for key, val in pairs(tbl) do margs[1] = key margs[2] = val tbl[key] = mfunc(ctx.frame:newChild(model)) end end return context_iterate(ctx, nargs + 1) end -- See iface.mapping_values_blindly_by_calling() library.mapping_values_blindly_by_calling = function(ctx) local opts = ctx.pipe local tname if opts[1] ~= nil then tname = opts[1]:match'^%s*(.*%S)' end if tname == nil then error(ctx.luaname .. ', ‘mapping_values_blindly_by_calling’: No template name was provided', 0) end local nargs local margs = {} local tmp = tonumber(opts[2]) if tmp == nil then nargs = 1 elseif tmp < 1 then nargs = 2 else nargs = tmp + 2 for idx = 3, nargs do margs[idx - 1] = opts[idx] end end local model = { title = tname, args = margs } local tbl = ctx.params if ctx.subset == 1 then for key, val in ipairs(tbl) do margs[1] = val tbl[key] = ctx.frame:expandTemplate(model) end elseif ctx.subset == -1 then tmp = {} for key, val in pairs(tbl) do tmp[key] = true end for key, val in ipairs(tmp) do tmp[key] = nil end for key in pairs(tmp) do margs[1] = tbl[key] tbl[key] = ctx.frame:expandTemplate(model) end else for key, val in pairs(tbl) do margs[1] = val tbl[key] = ctx.frame:expandTemplate(model) end end return context_iterate(ctx, nargs + 1) end -- See iface.mapping_values_blindly_by_invoking() library.mapping_values_blindly_by_invoking = function(ctx) local opts = ctx.pipe local mname local fname if opts[1] ~= nil then mname = opts[1]:match'^%s*(.*%S)' end if mname == nil then error(ctx.luaname .. ', ‘mapping_values_blindly_by_invoking’: No module name was provided', 0) end if opts[2] ~= nil then fname = opts[2]:match'^%s*(.*%S)' end if fname == nil then error(ctx.luaname .. ', ‘mapping_values_blindly_by_invoking’: No function name was provided', 0) end local nargs local margs = {} local tmp = tonumber(opts[3]) if tmp == nil then nargs = 2 elseif tmp < 1 then nargs = 3 else nargs = tmp + 3 for idx = 4, nargs do margs[idx - 2] = opts[idx] end end local model = { title = 'Module:' .. mname, args = margs } local mfunc = require(model.title)[fname] local tbl = ctx.params if ctx.subset == 1 then for key, val in ipairs(tbl) do margs[1] = val tbl[key] = mfunc(ctx.frame:newChild(model)) end elseif ctx.subset == -1 then tmp = {} for key, val in pairs(tbl) do tmp[key] = true end for key, val in ipairs(tmp) do tmp[key] = nil end for key in pairs(tmp) do margs[1] = tbl[key] tbl[key] = mfunc(ctx.frame:newChild(model)) end else for key, val in pairs(tbl) do margs[1] = val tbl[key] = mfunc(ctx.frame:newChild(model)) end end return context_iterate(ctx, nargs + 1) end --[[ Library's functions ]]-- ------------------------------------ -- See iface.count() library.count = function(ctx) local count = 0 for _ in ctx.iterfunc(ctx.params) do count = count + 1 end if ctx.subset == -1 then count = count - #ctx.params end return count end -- See iface.concat_and_call() library.concat_and_call = function(ctx) local opts = ctx.pipe local tname if opts[1] ~= nil then tname = opts[1]:match'^%s*(.*%S)' end if tname == nil then error(ctx.luaname .. ', ‘concat_and_call’: No template name was provided', 0) end table.remove(opts, 1) return ctx.frame:expandTemplate{ title = tname, args = concat_params(ctx) } end -- See iface.concat_and_invoke() library.concat_and_invoke = function(ctx) local opts = ctx.pipe local mname local fname if opts[1] ~= nil then mname = opts[1]:match'^%s*(.*%S)' end if mname == nil then error(ctx.luaname .. ', ‘concat_and_invoke’: No module name was provided', 0) end if opts[2] ~= nil then fname = opts[2]:match'^%s*(.*%S)' end if fname == nil then error(ctx.luaname .. ', ‘concat_and_invoke’: No function name was provided', 0) end table.remove(opts, 2) table.remove(opts, 1) return require('Module:' .. mname)[fname](ctx.frame:newChild{ title = 'Module:' .. fname, args = concat_params(ctx) }) end -- See iface.concat_and_magic() library.concat_and_magic = function(ctx) local opts = ctx.pipe local magic if opts[1] ~= nil then magic = opts[1]:match'^%s*(.*%S)' end if magic == nil then error(ctx.luaname .. ', ‘concat_and_magic’: No parser function was provided', 0) end table.remove(opts, 1) return ctx.frame:callParserFunction(magic, concat_params(ctx)) end -- See iface.value_of() library.value_of = function(ctx) local opts = ctx.pipe local keystr if opts[1] ~= nil then keystr = opts[1]:match'^%s*(.*%S)' end if keystr == nil then error(ctx.luaname .. ', ‘value_of’: No parameter name was provided', 0) end local keynum = tonumber(keystr) local len = #ctx.params if ( ctx.subset == -1 and keynum ~= nil and len >= keynum ) or ( ctx.subset == 1 and (keynum == nil or len < keynum) ) then return (ctx.ifngiven or '') end local val = ctx.params[keynum or keystr] if val == nil then return (ctx.ifngiven or '') end return (ctx.header or '') .. val .. (ctx.footer or '') end -- See iface.list() library.list = function(ctx) local kvs = ctx.pairsep or '' local pps = ctx.itersep or '' local ret = {} local nss = 0 flush_params( ctx, function(key, val) ret[nss + 1] = pps ret[nss + 2] = key ret[nss + 3] = kvs ret[nss + 4] = val nss = nss + 4 end ) if nss > 0 then if nss > 4 and ctx.lastsep ~= nil then ret[nss - 3] = ctx.lastsep end ret[1] = ctx.header or '' if ctx.footer ~= nil then ret[nss + 1] = ctx.footer end return table.concat(ret) end return ctx.ifngiven or '' end -- See iface.list_values() library.list_values = function(ctx) local pps = ctx.itersep or '' local ret = {} local nss = 0 flush_params( ctx, function(key, val) ret[nss + 1] = pps ret[nss + 2] = val nss = nss + 2 end ) if nss > 0 then if nss > 2 and ctx.lastsep ~= nil then ret[nss - 1] = ctx.lastsep end ret[1] = ctx.header or '' if ctx.footer ~= nil then ret[nss + 1] = ctx.footer end return table.concat(ret) end return ctx.ifngiven or '' end -- See iface.for_each() library.for_each = function(ctx) local txt = ctx.pipe[1] or '' local pps = ctx.itersep or '' local ret = {} local nss = 0 flush_params( ctx, function(key, val) ret[nss + 1] = pps ret[nss + 2] = txt:gsub('%$#', key):gsub('%$@', val) nss = nss + 2 end ) if nss > 0 then if nss > 2 and ctx.lastsep ~= nil then ret[nss - 1] = ctx.lastsep end ret[1] = ctx.header or '' if ctx.footer ~= nil then ret[nss + 1] = ctx.footer end return table.concat(ret) end return ctx.ifngiven or '' end -- See iface.call_for_each() library.call_for_each = function(ctx) local opts = ctx.pipe local tname if opts[1] ~= nil then tname = opts[1]:match'^%s*(.*%S)' end if tname == nil then error(ctx.luaname .. ', ‘call_for_each’: No template name was provided', 0) end local model = { title = tname, args = opts } local ccs = ctx.itersep or '' local ret = {} local nss = 0 table.insert(opts, 1, true) flush_params( ctx, function(key, val) opts[1] = key opts[2] = val ret[nss + 1] = ccs ret[nss + 2] = ctx.frame:expandTemplate(model) nss = nss + 2 end ) if nss > 0 then if nss > 2 and ctx.lastsep ~= nil then ret[nss - 1] = ctx.lastsep end ret[1] = ctx.header or '' if ctx.footer ~= nil then ret[nss + 1] = ctx.footer end return table.concat(ret) end return ctx.ifngiven or '' end -- See iface.invoke_for_each() library.invoke_for_each = function(ctx) local opts = ctx.pipe local mname local fname if opts[1] ~= nil then mname = opts[1]:match'^%s*(.*%S)' end if mname == nil then error(ctx.luaname .. ', ‘invoke_for_each’: No module name was provided', 0) end if opts[2] ~= nil then fname = opts[2]:match'^%s*(.*%S)' end if fname == nil then error(ctx.luaname .. ', ‘invoke_for_each’: No function name was provided', 0) end local model = { title = 'Module:' .. mname, args = opts } local mfunc = require(model.title)[fname] local ccs = ctx.itersep or '' local ret = {} local nss = 0 flush_params( ctx, function(key, val) opts[1] = key opts[2] = val ret[nss + 1] = ccs ret[nss + 2] = mfunc(ctx.frame:newChild(model)) nss = nss + 2 end ) if nss > 0 then if nss > 2 and ctx.lastsep ~= nil then ret[nss - 1] = ctx.lastsep end ret[1] = ctx.header or '' if ctx.footer ~= nil then ret[nss + 1] = ctx.footer end return table.concat(ret) end return ctx.ifngiven or '' end -- See iface.magic_for_each() library.magic_for_each = function(ctx) local opts = ctx.pipe local magic if opts[1] ~= nil then magic = opts[1]:match'^%s*(.*%S)' end if magic == nil then error(ctx.luaname .. ', ‘magic_for_each’: No parser function was provided', 0) end local ccs = ctx.itersep or '' local ret = {} local nss = 0 table.insert(opts, 1, true) flush_params( ctx, function(key, val) opts[1] = key opts[2] = val ret[nss + 1] = ccs ret[nss + 2] = ctx.frame:callParserFunction(magic, opts) nss = nss + 2 end ) if nss > 0 then if nss > 2 and ctx.lastsep ~= nil then ret[nss - 1] = ctx.lastsep end ret[1] = ctx.header or '' if ctx.footer ~= nil then ret[nss + 1] = ctx.footer end return table.concat(ret) end return ctx.ifngiven or '' end -- See iface.call_for_each_value() library.call_for_each_value = function(ctx) local opts = ctx.pipe local tname if opts[1] ~= nil then tname = opts[1]:match'^%s*(.*%S)' end if tname == nil then error(ctx.luaname .. ', ‘call_for_each_value’: No template name was provided', 0) end local model = { title = tname, args = opts } local ccs = ctx.itersep or '' local ret = {} local nss = 0 flush_params( ctx, function(key, val) opts[1] = val ret[nss + 1] = ccs ret[nss + 2] = ctx.frame:expandTemplate(model) nss = nss + 2 end ) if nss > 0 then if nss > 2 and ctx.lastsep ~= nil then ret[nss - 1] = ctx.lastsep end ret[1] = ctx.header or '' if ctx.footer ~= nil then ret[nss + 1] = ctx.footer end return table.concat(ret) end return ctx.ifngiven or '' end -- See iface.invoke_for_each_value() library.invoke_for_each_value = function(ctx) local opts = ctx.pipe local mname local fname if opts[1] ~= nil then mname = opts[1]:match'^%s*(.*%S)' end if mname == nil then error(ctx.luaname .. ', ‘invoke_for_each_value’: No module name was provided', 0) end if opts[2] ~= nil then fname = opts[2]:match'^%s*(.*%S)' end if fname == nil then error(ctx.luaname .. ', ‘invoke_for_each_value’: No function name was provided', 0) end local model = { title = 'Module:' .. mname, args = opts } local mfunc = require(model.title)[fname] local ccs = ctx.itersep or '' local ret = {} local nss = 0 table.remove(opts, 1) flush_params( ctx, function(key, val) opts[1] = val ret[nss + 1] = ccs ret[nss + 2] = mfunc(ctx.frame:newChild(model)) nss = nss + 2 end ) if nss > 0 then if nss > 2 and ctx.lastsep ~= nil then ret[nss - 1] = ctx.lastsep end ret[1] = ctx.header or '' if ctx.footer ~= nil then ret[nss + 1] = ctx.footer end return table.concat(ret) end return ctx.ifngiven or '' end -- See iface.magic_for_each_value() library.magic_for_each_value = function(ctx) local opts = ctx.pipe local magic if opts[1] ~= nil then magic = opts[1]:match'^%s*(.*%S)' end if magic == nil then error(ctx.luaname .. ', ‘magic_for_each_value’: No parser function was provided', 0) end local ccs = ctx.itersep or '' local ret = {} local nss = 0 flush_params( ctx, function(key, val) opts[1] = val ret[nss + 1] = ccs ret[nss + 2] = ctx.frame:callParserFunction(magic, opts) nss = nss + 2 end ) if nss > 0 then if nss > 2 and ctx.lastsep ~= nil then ret[nss - 1] = ctx.lastsep end ret[1] = ctx.header or '' if ctx.footer ~= nil then ret[nss + 1] = ctx.footer end return table.concat(ret) end return ctx.ifngiven or '' end -- See iface.self() library.self = function(ctx) return ctx.frame:getTitle() end --- --- --- PUBLIC ENVIRONMENT --- --- ________________________________ --- --- --- -- The public table of functions local iface = {} --[[ Modifiers ]]-- ------------------------------------ -- Syntax: #invoke:params|sequential|function name iface.sequential = function(frame) return context_init(frame, library.sequential, false, false) end -- Syntax: #invoke:params|non-sequential|function name iface['non-sequential'] = function(frame) return context_init(frame, library['non-sequential'], false, false) end -- Syntax: #invoke:params|sort|function name iface.all_sorted = function(frame) return context_init(frame, library.all_sorted, false, false) end -- Syntax: #invoke:params|setting|directives|...|function name iface.setting = function(frame) return context_init(frame, library.setting, false, false) end -- Syntax: #invoke:params|squeezing|function name iface.squeezing = function(frame) return context_init(frame, library.squeezing, false, false) end -- Syntax: #invoke:params|cutting|left cut|right cut|function name iface.cutting = function(frame) return context_init(frame, library.cutting, false, false) end -- Syntax: #invoke:params|with_name_matching|pattern 1|[plain flag 1]|[or] -- |[pattern 2]|[plain flag 2]|[or]|[...]|[pattern N]|[plain flag -- N]|function name iface.with_name_matching = function(frame) return context_init(frame, library.with_name_matching, false, false) end -- Syntax: #invoke:params|with_name_not_matching|pattern 1|[plain flag 1] -- |[and]|[pattern 2]|[plain flag 2]|[and]|[...]|[pattern N]|[plain -- flag N]|function name iface.with_name_not_matching = function(frame) return context_init(frame, library.with_name_not_matching, false, false) end -- Syntax: #invoke:params|with_value_matching|pattern 1|[plain flag 1]|[or] -- |[pattern 2]|[plain flag 2]|[or]|[...]|[pattern N]|[plain flag -- N]|function name iface.with_value_matching = function(frame) return context_init(frame, library.with_value_matching, false, false) end -- Syntax: #invoke:params|with_value_not_matching|pattern 1|[plain flag 1] -- |[and]|[pattern 2]|[plain flag 2]|[and]|[...]|[pattern N]|[plain -- flag N]|function name iface.with_value_not_matching = function(frame) return context_init(frame, library.with_value_not_matching, false, false) end -- Syntax: #invoke:params|trimming_values|function name iface.trimming_values = function(frame) return context_init(frame, library.trimming_values, false, false) end -- Syntax: #invoke:params|mapping_values_by_calling|template name|[number of additional -- arguments]|[argument 1]|[argument 2]|[...]|[argument N]|function -- name iface.mapping_values_by_calling = function(frame) return context_init(frame, library.mapping_values_by_calling, false, false) end -- Syntax: #invoke:params|mapping_values_by_invoking|module name|function name|[number of -- additional arguments]|[argument 1]|[argument 2]|[...]|[argument -- N]|function name iface.mapping_values_by_invoking = function(frame) return context_init(frame, library.mapping_values_by_invoking, false, false) end -- Syntax: #invoke:params|mapping_values_blindly_by_calling|template name|[number of -- additional arguments]|[argument 1]|[argument 2]|[...]|[argument -- N]|function name iface.mapping_values_blindly_by_calling = function(frame) return context_init(frame, library.mapping_values_blindly_by_calling, false, false) end -- Syntax: #invoke:params|mapping_values_blindly_by_invoking|module name|function name -- |[number of additional arguments]|[argument 1]|[argument 2]|[...] -- |[argument N]|function name iface.mapping_values_blindly_by_invoking = function(frame) return context_init(frame, library.mapping_values_blindly_by_invoking, false, false) end --[[ Functions ]]-- ---------------------------------------- -- Syntax: #invoke:params|count iface.count = function(frame) return context_init(frame, library.count, true, true) end -- Syntax: #invoke:args|concat_and_call|template name|[prepend 1]|[prepend 2] -- |[...]|[item n]|[named item 1=value 1]|[...]|[named item n=value -- n]|[...] iface.concat_and_call = function(frame) return context_init(frame, library.concat_and_call, false, true) end -- Syntax: #invoke:args|concat_and_invoke|module name|function name|[prepend -- 1]|[prepend 2]|[...]|[item n]|[named item 1=value 1]|[...]|[named -- item n=value n]|[...] iface.concat_and_invoke = function(frame) return context_init(frame, library.concat_and_invoke, false, true) end -- Syntax: #invoke:args|concat_and_magic|parser function|[prepend 1]|[prepend -- 2]|[...]|[item n]|[named item 1=value 1]|[...]|[named item n= -- value n]|[...] iface.concat_and_magic = function(frame) return context_init(frame, library.concat_and_magic, false, true) end -- Syntax: #invoke:params|value_of|parameter name iface.value_of = function(frame) return context_init(frame, library.value_of, true, true) end -- Syntax: #invoke:params|list iface.list = function(frame) return context_init(frame, library.list, true, false) end -- Syntax: #invoke:params|list_values iface.list_values = function(frame) return context_init(frame, library.list_values, true, false) end -- Syntax: #invoke:params|for_each|wikitext iface.for_each = function(frame) return context_init(frame, library.for_each, true, false) end -- Syntax: #invoke:params|call_for_each|template name|[append 1]|[append 2] -- |[...]|[append n]|[named param 1=value 1]|[...]|[named param -- n=value n]|[...] iface.call_for_each = function(frame) return context_init(frame, library.call_for_each, false, false) end -- Syntax: #invoke:params|invoke_for_each|module name|module function|[append -- 1]|[append 2]|[...]|[append n]|[named param 1=value 1]|[...] -- |[named param n=value n]|[...] iface.invoke_for_each = function(frame) return context_init(frame, library.invoke_for_each, false, false) end -- Syntax: #invoke:params|magic_for_each|parser function|[append 1]|[append 2] -- |[...]|[append n]|[named param 1=value 1]|[...]|[named param -- n=value n]|[...] iface.magic_for_each = function(frame) return context_init(frame, library.magic_for_each, false, false) end -- Syntax: #invoke:params|call_for_each_value|template name|[append 1]|[append -- 2]|[...]|[append n]|[named param 1=value 1]|[...]|[named param -- n=value n]|[...] iface.call_for_each_value = function(frame) return context_init(frame, library.call_for_each_value, false, false) end -- Syntax: #invoke:params|invoke_for_each_value|module name|[append 1]|[append -- 2]|[...]|[append n]|[named param 1=value 1]|[...]|[named param -- n=value n]|[...] iface.invoke_for_each_value = function(frame) return context_init(frame, library.invoke_for_each_value, false, false) end -- Syntax: #invoke:params|magic_for_each_value|parser function|[append 1] -- |[append 2]|[...]|[append n]|[named param 1=value 1]|[...]|[named -- param n=value n]|[...] iface.magic_for_each_value = function(frame) return context_init(frame, library.magic_for_each_value, false, false) end -- Syntax: #invoke:params|self iface.self = function(frame) return frame:getParent():getTitle() end return iface