Module:Params: Difference between revisions

From Climate Wiki
Jump to navigation Jump to search
m (Comment only)
 
m (1 revision imported)
 
(4 intermediate revisions by 2 users not shown)
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('No function name was given', 0)
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 "' .. nextfn .. '" does not exist', 0)
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 do_for_each_param(ctx, fn)
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[#nums + 1] = key
nlen = nlen + 1
nums[nlen] = key
else
else
words[#words + 1] = key
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, #nums do fn(nums[idx], tbl[nums[idx]]) end
for idx = 1, nlen do fn(nums[idx], tbl[nums[idx]]) end
for idx = 1, #words do fn(words[idx], tbl[words[idx]]) end
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[#ptns + 1] = { val, false }
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[#ptns][2] = state end
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:




--[[ Piped modifiers ]]--
--[[ 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 "non-sequential" and "sequential" are in contradiction with each other', 0) end
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 "all_sorted" directive is redundant when followed by "sequential"', 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.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 "sequential" and "non-sequential" are in contradiction with each other', 0) end
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 "all_sorted" directive is redundant after "sequential"', 0) end
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('setting: No directive was given', 0) end
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('setting: Unknown slot "' ..
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[#indices + 1] = key
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, #indices do tbl[idx] = store[indices[idx]] end
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('cutting: Left cut must be a number', 0) end
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('cutting: Right cut must be a number', 0) end
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 361: Line 371:
for key, val in pairs(tbl) do tbl[key] = val:match'^%s*(.-)%s*$' end
for key, val in pairs(tbl) do tbl[key] = val:match'^%s*(.-)%s*$' end
return context_iterate(ctx, 1)
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
end






--[[ Piped functions ]]--
--[[ 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('concat_and_call: No template name was provided', 0) end
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('concat_and_invoke: No module name was provided', 0) 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 opts[2] ~= nil then fname = opts[2]:match'^%s*(.*%S)' end
if fname == nil then error('concat_and_invoke: No function name was provided', 0) 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, 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('value_of: No parameter name was provided', 0) end
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.params >= keynum
ctx.subset == -1 and keynum ~= nil and len >= keynum
) or (
) or (
ctx.subset == 1 and (keynum == nil or #ctx.params < keynum)
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 kvs = ctx.pairsep or ''
local ret = {}
local sep = ctx.header or ''
local nss = 0
local las = ctx.footer or ''
flush_params(
local foo = ctx.ifngiven or ''
local ret = ''
do_for_each_param(
ctx,
ctx,
function(key, val)
function(key, val)
ret = ret .. sep .. key .. kvs .. val
ret[nss + 1] = pps
sep = pps
ret[nss + 2] = key
foo = las
ret[nss + 3] = kvs
ret[nss + 4] = val
nss = nss + 4
end
end
)
)
return ret .. foo
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 sep = ctx.header or ''
local ret = {}
local las = ctx.footer or ''
local nss = 0
local foo = ctx.ifngiven or ''
flush_params(
local ret = ''
do_for_each_param(
ctx,
ctx,
function(key, val)
function(key, val)
ret = ret .. sep .. val
ret[nss + 1] = pps
sep = pps
ret[nss + 2] = val
foo = las
nss = nss + 2
end
end
)
)
return ret .. foo
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 las = ctx.footer or ''
local ret = {}
local sep = ctx.header or ''
local nss = 0
local foo = ctx.ifngiven or ''
flush_params(
local txt = ctx.pipe[1] or ''
local ret = ''
do_for_each_param(
ctx,
ctx,
function(key, val)
function(key, val)
ret = ret .. sep .. string.gsub(
ret[nss + 1] = pps
string.gsub(txt, '%$#', key),
ret[nss + 2] = txt:gsub('%$#', key):gsub('%$@', val)
'%$@',
nss = nss + 2
val
)
sep = pps
foo = las
end
end
)
)
return ret .. foo
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('call_for_each: No template name was provided', 0) 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 ccs = ctx.itersep or ''
local sep = ctx.header or ''
local ret = {}
local las = ctx.footer or ''
local nss = 0
local foo = ctx.ifngiven or ''
local model = { title = tname, args = opts }
local ret = ''
 
table.insert(opts, 1, true)
table.insert(opts, 1, true)
 
flush_params(
do_for_each_param(
ctx,
ctx,
function(key, val)
function(key, val)
opts[1] = key
opts[1] = key
opts[2] = val
opts[2] = val
ret = ret .. sep .. ctx.frame:expandTemplate(model)
ret[nss + 1] = ccs
sep = ccs
ret[nss + 2] = ctx.frame:expandTemplate(model)
foo = las
nss = nss + 2
end
end
)
)
 
if nss > 0 then
return ret .. foo
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('invoke_for_each: No module name was provided', 0) 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 opts[2] ~= nil then fname = opts[2]:match'^%s*(.*%S)' end
if fname == nil then error('invoke_for_each: No function name was provided', 0) end
if fname == nil then error(ctx.luaname .. ', ‘invoke_for_each’: No function name was provided', 0) end
 
local ccs = ctx.itersep or ''
local sep = ctx.header or ''
local las = ctx.footer or ''
local foo = ctx.ifngiven or ''
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 ret = ''
local ccs = ctx.itersep or ''
 
local ret = {}
do_for_each_param(
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 .. sep .. mfunc(ctx.frame:newChild(model))
ret[nss + 1] = ccs
sep = ccs
ret[nss + 2] = mfunc(ctx.frame:newChild(model))
foo = las
nss = nss + 2
end
end
)
)
 
if nss > 0 then
return ret .. foo
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('magic_for_each: No parser function was provided', 0) end
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 sep = ctx.header or ''
local ret = {}
local las = ctx.footer or ''
local nss = 0
local foo = ctx.ifngiven or ''
local ret = ''
 
table.insert(opts, 1, true)
table.insert(opts, 1, true)
 
flush_params(
do_for_each_param(
ctx,
ctx,
function(key, val)
function(key, val)
opts[1] = key
opts[1] = key
opts[2] = val
opts[2] = val
ret = ret .. sep .. ctx.frame:callParserFunction(magic, opts)
ret[nss + 1] = ccs
sep = ccs
ret[nss + 2] = ctx.frame:callParserFunction(magic,
foo = las
opts)
nss = nss + 2
end
end
)
)
 
if nss > 0 then
return ret .. foo
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('call_for_each_value: No template name was provided', 0) 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 ccs = ctx.itersep or ''
local sep = ctx.header or ''
local ret = {}
local las = ctx.footer or ''
local nss = 0
local foo = ctx.ifngiven or ''
flush_params(
local model = { title = tname, args = opts }
local ret = ''
 
do_for_each_param(
ctx,
ctx,
function(key, val)
function(key, val)
opts[1] = val
opts[1] = val
ret = ret .. sep .. ctx.frame:expandTemplate(model)
ret[nss + 1] = ccs
sep = ccs
ret[nss + 2] = ctx.frame:expandTemplate(model)
foo = las
nss = nss + 2
end
end
)
)
 
if nss > 0 then
return ret .. foo
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('invoke_for_each_value: No module name was provided', 0) 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 opts[2] ~= nil then fname = opts[2]:match'^%s*(.*%S)' end
if fname == nil then error('invoke_for_each_value: No function name was provided', 0) end
if fname == nil then error(ctx.luaname .. ', ‘invoke_for_each_value’: No function name was provided', 0) end
 
local ccs = ctx.itersep or ''
local sep = ctx.header or ''
local las = ctx.footer or ''
local foo = ctx.ifngiven or ''
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 ret = ''
local ccs = ctx.itersep or ''
 
local ret = {}
local nss = 0
table.remove(opts, 1)
table.remove(opts, 1)
 
flush_params(
do_for_each_param(
ctx,
ctx,
function(key, val)
function(key, val)
opts[1] = val
opts[1] = val
ret = ret .. sep .. mfunc(ctx.frame:newChild(model))
ret[nss + 1] = ccs
sep = ccs
ret[nss + 2] = mfunc(ctx.frame:newChild(model))
foo = las
nss = nss + 2
end
end
)
)
 
if nss > 0 then
return ret .. foo
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('magic_for_each_value: No parser function was provided', 0) 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 ccs = ctx.itersep or ''
local sep = ctx.header or ''
local ret = {}
local las = ctx.footer or ''
local nss = 0
local foo = ctx.ifngiven or ''
flush_params(
local ret = ''
 
do_for_each_param(
ctx,
ctx,
function(key, val)
function(key, val)
opts[1] = val
opts[1] = val
ret = ret .. sep .. ctx.frame:callParserFunction(magic,
ret[nss + 1] = ccs
ret[nss + 2] = ctx.frame:callParserFunction(magic,
opts)
opts)
sep = ccs
nss = nss + 2
foo = las
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


return ret .. foo


-- See iface.self()
library.self = function(ctx)
return ctx.frame:getTitle()
end
end


Line 705: Line 934:




--[[ Non-piped modifiers ]]--
--[[ Modifiers ]]--
------------------------------------
------------------------------------


Line 782: Line 1,011:
iface.trimming_values = function(frame)
iface.trimming_values = function(frame)
return context_init(frame, library.trimming_values, false, false)
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
end






--[[ Non-piped functions ]]--
 
--[[ Functions ]]--
----------------------------------------
----------------------------------------


Line 809: 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


Line 881: Line 1,153:
iface.magic_for_each_value = function(frame)
iface.magic_for_each_value = function(frame)
return context_init(frame, library.magic_for_each_value, false, false)
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
end




return iface
return iface

Latest revision as of 03:02, 8 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