Module:Params: Difference between revisions

From All Skies Encyclopaedia
imported>Grufo
m (Internal nomenclature (no changes))
imported>Grufo
(New functions `magic_for_each` and `magic_for_each_value`; new `setting` modifier; structural changes in all iterating functions; general code review)
Line 5: Line 5:




-- Set directives
-- Default separator between different arguments
local arg_sep = '|'
local slots = {
i = 'itersep',

p = 'pairsep',

h = 'header',
-- Default separator between keys and values
f = 'footer',
local keyval_sep = '='
n = 'ifngiven'
}




Line 39: Line 41:
-- Move to the next action within the user-given list
-- Move to the next action within the user-given list
local function context_iterate(ctx, n_forward)
local function context_iterate(ctx, n_forward)
local nextfn = ctx.pipe[n_forward]:match'^%s*(.*%S)'
local nextfn
if ctx.pipe[n_forward] ~= nil then
nextfn = ctx.pipe[n_forward]:match'^%s*(.*%S)'
end
if nextfn == nil then
if nextfn == nil then
error('You must specify a function to call', 0)
error('End of arguments reached without a function call', 0)
end
end
if library[nextfn] == nil then
if library[nextfn] == nil then
Line 92: Line 97:




-- See iface.'non-sequential']()
-- See iface['non-sequential']()
library['non-sequential'] = function(ctx)
library['non-sequential'] = function(ctx)
if ctx.subset == 1 then
if ctx.subset == 1 then
Line 101: Line 106:
for key, val in ipairs(ctx.params) do ctx.params[key] = nil end
for key, val in ipairs(ctx.params) do ctx.params[key] = nil end
return context_iterate(ctx, 1)
return context_iterate(ctx, 1)
end


-- See iface.setting()
library.setting = function(ctx)

local opts = ctx.pipe

local cmd = (opts[1] or
''):gsub('%s+', ''):gsub('/+', '/'):match'^/*(.*[^/])'

if cmd == nil then
error('No directive was given about what variables to set', 0)
end

local target = string.byte('/')
local arglen = 2
local aggregate = {}
local varname
local chr

for idx = 1, #cmd do
chr = cmd:byte(idx)
if chr == target then
for key, val in ipairs(aggregate) do
ctx[val] = opts[arglen]
aggregate[key] = nil
end
arglen = arglen + 1
else
varname = slots[string.char(chr)]
if varname == nil then error('Unknown slot "' ..
string.char(chr) .. '"', 0) end
table.insert(aggregate, varname)
end
end

for key, val in ipairs(aggregate) do ctx[val] = opts[arglen] end

return context_iterate(ctx, arglen + 1)

end
end


Line 182: Line 228:
for _ in ctx.iterfunc(ctx.params) do count = count + 1 end
for _ in ctx.iterfunc(ctx.params) do count = count + 1 end
return count
return count
end


-- See iface.concat_and_call()
library.concat_and_call = function(ctx)

local opts = ctx.pipe
local tname = opts[1]

if tname == nil then error('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 = opts[1]

if mname == nil then error('No module name was provided', 0) end
if opts[2] == nil then error('No function name was provided', 0) end

local fname = opts[2]:match'^%s*(.*%S)'

table.remove(opts, 2)
table.remove(opts, 1)

return require('Module:' .. mname)[fname](ctx.frame:newChild{
title = 'Module:' .. fname,
args = concat_params(ctx)
})

end
end


Line 191: Line 277:
if keystr == '' then error('No parameter name was provided', 0) end
if keystr == '' then error('No parameter name was provided', 0) end
local val = ctx.params[tonumber(keystr) or keystr]
local val = ctx.params[tonumber(keystr) or keystr]
if val == nil then return '' end
if val == nil then return (ctx.ifngiven or '') end
return (opts[2] or '') .. val .. (opts[3] or '')
return (ctx.header or '') .. val .. (ctx.footer or '')
end
end





Line 200: Line 285:
library.list = function(ctx)
library.list = function(ctx)


local opts = ctx.pipe
local pps = ctx.itersep or ''
local aas
local kvs = ctx.pairsep or ''
local kvs
local sep = ctx.header or ''
local las
local las = ctx.footer or ''
local hea
local foo = ctx.ifngiven or ''
local sep = ''
local foo = ''

if opts[1] ~= nil then kvs = opts[1] else kvs = keyval_sep end
if opts[2] ~= nil then aas = opts[2] else aas = arg_sep end
if opts[3] ~= nil then hea = opts[3] else hea = '' end
if opts[4] ~= nil then las = opts[4] else las = '' end

local ret = ''
local ret = ''


if ctx.subset ~= -1 then
if ctx.subset ~= -1 then
for key, val in ipairs(ctx.params) do
for key, val in ipairs(ctx.params) do
ret = ret .. hea .. sep .. key .. kvs .. val
ret = ret .. sep .. key .. kvs .. val
sep = aas
sep = pps
hea = ''
foo = las
foo = las
ctx.params[key] = nil
ctx.params[key] = nil
Line 227: Line 303:
if ctx.subset ~= 1 then
if ctx.subset ~= 1 then
for key, val in pairs(ctx.params) do
for key, val in pairs(ctx.params) do
ret = ret .. hea .. sep .. key .. kvs .. val
ret = ret .. sep .. key .. kvs .. val
sep = aas
sep = pps
hea = ''
foo = las
foo = las
end
end
Line 242: Line 317:
library.list_values = function(ctx)
library.list_values = function(ctx)


local opts = ctx.pipe
local pps = ctx.itersep or ''
local aas
local sep = ctx.header or ''
local las
local las = ctx.footer or ''
local hea
local foo = ctx.ifngiven or ''
local sep = ''
local foo = ''

if opts[1] ~= nil then aas = opts[1] else aas = arg_sep end
if opts[2] ~= nil then hea = opts[2] else hea = '' end
if opts[3] ~= nil then las = opts[3] else las = '' end

local ret = ''
local ret = ''


if ctx.subset ~= -1 then
if ctx.subset ~= -1 then
for key, val in ipairs(ctx.params) do
for key, val in ipairs(ctx.params) do
ret = ret .. hea .. sep .. val
ret = ret .. sep .. val
sep = aas
sep = pps
hea = ''
foo = las
foo = las
ctx.params[key] = nil
ctx.params[key] = nil
Line 267: Line 334:
if ctx.subset ~= 1 then
if ctx.subset ~= 1 then
for key, val in pairs(ctx.params) do
for key, val in pairs(ctx.params) do
ret = ret .. hea .. sep .. val
ret = ret .. sep .. val
sep = aas
sep = pps
hea = ''
foo = las
foo = las
end
end
Line 282: Line 348:
library.for_each = function(ctx)
library.for_each = function(ctx)


local las
local pps = ctx.itersep or ''
local hea
local las = ctx.footer or ''
local sep = ctx.header or ''
local foo = ctx.ifngiven or ''
local txt = ctx.pipe[1]
local txt = ctx.pipe[1]
local foo = ''

if txt == nil then return '' end
if ctx.pipe[2] ~= nil then hea = ctx.pipe[2] else hea = '' end
if ctx.pipe[3] ~= nil then las = ctx.pipe[3] else las = '' end

local ret = ''
local ret = ''


if ctx.subset ~= -1 then
if ctx.subset ~= -1 then
for key, val in ipairs(ctx.params) do
for key, val in ipairs(ctx.params) do
ret = ret .. hea .. string.gsub(
ret = ret .. sep .. string.gsub(
string.gsub(txt, '%$#', key),
string.gsub(txt, '%$#', key),
'%$@',
'%$@',
val
val
)
)
hea = ''
sep = pps
foo = las
foo = las
ctx.params[key] = nil
ctx.params[key] = nil
Line 308: Line 370:
if ctx.subset ~= 1 then
if ctx.subset ~= 1 then
for key, val in pairs(ctx.params) do
for key, val in pairs(ctx.params) do
ret = ret .. hea .. string.gsub(
ret = ret .. sep .. string.gsub(
string.gsub(txt, '%$#', key),
string.gsub(txt, '%$#', key),
'%$@',
'%$@',
val
val
)
)
hea = ''
sep = pps
foo = las
foo = las
end
end
Line 323: Line 385:




-- See iface.concat_and_call()
-- See iface.call_for_each()
library.concat_and_call = function(ctx)
library.call_for_each = function(ctx)


local opts = ctx.pipe
local opts = ctx.pipe
local tname = opts[1]


if tname == nil then error('No template name was provided', 0) end
if opts[1] == nil then error('No template name was provided', 0) end


local ccs = ctx.itersep or ''
table.remove(opts, 1)
local sep = ctx.header or ''
local las = ctx.footer or ''
local foo = ctx.ifngiven or ''
local ret = ''


local model = { title = opts[1]:match'^%s*(.*%S)', args = opts }
return ctx.frame:expandTemplate{
title = tname,
args = concat_params(ctx)
}


table.insert(opts, 1, true)
end


if ctx.subset ~= -1 then
for key, val in ipairs(ctx.params) do
opts[1] = key
opts[2] = val
ret = ret .. sep .. ctx.frame:expandTemplate(model)
sep = ccs
foo = las
ctx.params[key] = nil
end
end


if ctx.subset ~= 1 then
-- See iface.concat_and_invoke()
for key, val in pairs(ctx.params) do
library.concat_and_invoke = function(ctx)
opts[1] = key
opts[2] = val
ret = ret .. sep .. ctx.frame:expandTemplate(model)
sep = ccs
foo = las
end
end


return ret .. foo
local opts = ctx.pipe
local mname = opts[1]

if mname == nil then error('No module name was provided', 0) end
if opts[2] == nil then error('No function name was provided', 0) end

local fname = opts[2]:match'^%s*(.*%S)'

table.remove(opts, 2)
table.remove(opts, 1)

return require('Module:' .. mname)[fname](ctx.frame:newChild{
title = 'Module:' .. fname,
args = concat_params(ctx)
})


end
end




-- See iface.call_for_each()
-- See iface.invoke_for_each()
library.call_for_each = function(ctx)
library.invoke_for_each = function(ctx)


local opts = ctx.pipe
local opts = ctx.pipe


if opts[1] == nil then error('No template name was provided', 0) end
if opts[1] == nil then error('No module name was provided', 0) end
if opts[2] == nil then error('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 ret = ''
local ret = ''
local model = { title = opts[1], args = opts }


local model = { title = 'Module:' .. opts[1]:match'^%s*(.*%S)', args = opts }
table.insert(opts, 1, true)
local mfunc = require(model.title)[opts[2]:match'^%s*(.*%S)']


if ctx.subset ~= -1 then
if ctx.subset ~= -1 then
Line 379: Line 449:
opts[1] = key
opts[1] = key
opts[2] = val
opts[2] = val
ret = ret .. ctx.frame:expandTemplate(model)
ret = ret .. sep .. mfunc(ctx.frame:newChild(model))
sep = ccs
foo = las
ctx.params[key] = nil
ctx.params[key] = nil
end
end
Line 388: Line 460:
opts[1] = key
opts[1] = key
opts[2] = val
opts[2] = val
ret = ret .. ctx.frame:expandTemplate(model)
ret = ret .. sep .. mfunc(ctx.frame:newChild(model))
sep = ccs
foo = las
end
end
end
end


return ret
return ret .. foo


end
end




-- See iface.invoke_for_each()
-- See iface.magic_for_each()
library.invoke_for_each = function(ctx)
library.magic_for_each = function(ctx)


local opts = ctx.pipe
local opts = ctx.pipe


if opts[1] == nil then error('No module name was provided', 0) end
if opts[1] == nil then error('No template name was provided', 0) end
if opts[2] == nil then error('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 magic = opts[1]:match'^%s*(.*%S)'
local ret = ''
local ret = ''

local model = { title = 'Module:' .. opts[1], args = opts }
table.insert(opts, 1, true)
local mfunc = require(model.title)[opts[2]:match'^%s*(.*%S)']


if ctx.subset ~= -1 then
if ctx.subset ~= -1 then
Line 413: Line 491:
opts[1] = key
opts[1] = key
opts[2] = val
opts[2] = val
ret = ret .. mfunc(ctx.frame:newChild(model))
ret = ret .. sep .. ctx.frame:callParserFunction(magic, opts)
sep = ccs
foo = las
ctx.params[key] = nil
ctx.params[key] = nil
end
end
Line 422: Line 502:
opts[1] = key
opts[1] = key
opts[2] = val
opts[2] = val
ret = ret .. mfunc(ctx.frame:newChild(model))
ret = ret .. sep .. ctx.frame:callParserFunction(magic, opts)
sep = ccs
foo = las
end
end
end
end


return ret
return ret .. foo


end
end
Line 438: Line 520:
if opts[1] == nil then error('No template name was provided', 0) end
if opts[1] == nil then error('No template 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 ret = ''
local ret = ''

local model = { title = opts[1], args = opts }
local model = { title = opts[1]:match'^%s*(.*%S)', args = opts }


if ctx.subset ~= -1 then
if ctx.subset ~= -1 then
for key, val in ipairs(ctx.params) do
for key, val in ipairs(ctx.params) do
opts[1] = val
opts[1] = val
ret = ret .. ctx.frame:expandTemplate(model)
ret = ret .. sep .. ctx.frame:expandTemplate(model)
sep = ccs
foo = las
ctx.params[key] = nil
ctx.params[key] = nil
end
end
Line 452: Line 541:
for key, val in pairs(ctx.params) do
for key, val in pairs(ctx.params) do
opts[1] = val
opts[1] = val
ret = ret .. ctx.frame:expandTemplate(model)
ret = ret .. sep .. ctx.frame:expandTemplate(model)
sep = ccs
foo = las
end
end
end
end


return ret
return ret .. foo


end
end
Line 469: Line 560:
if opts[2] == nil then error('No function name was provided', 0) end
if opts[2] == nil then error('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 ret = ''
local ret = ''

local model = { title = 'Module:' .. opts[1], args = opts }
local model = { title = 'Module:' .. opts[1]:match'^%s*(.*%S)', args = opts }
local mfunc = require(model.title)[opts[2]:match'^%s*(.*%S)']
local mfunc = require(model.title)[opts[2]:match'^%s*(.*%S)']


Line 478: Line 574:
for key, val in ipairs(ctx.params) do
for key, val in ipairs(ctx.params) do
opts[1] = val
opts[1] = val
ret = ret .. mfunc(ctx.frame:newChild(model))
ret = ret .. sep .. mfunc(ctx.frame:newChild(model))
sep = ccs
foo = las
ctx.params[key] = nil
ctx.params[key] = nil
end
end
Line 486: Line 584:
for key, val in pairs(ctx.params) do
for key, val in pairs(ctx.params) do
opts[1] = val
opts[1] = val
ret = ret .. mfunc(ctx.frame:newChild(model))
ret = ret .. sep .. mfunc(ctx.frame:newChild(model))
sep = ccs
foo = las
end
end
end
end


return ret
return ret .. foo

end


-- See iface.magic_for_each_value()
library.magic_for_each_value = function(ctx)

local opts = ctx.pipe

if opts[1] == nil then error('No template 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 magic = opts[1]:match'^%s*(.*%S)'
local ret = ''

if ctx.subset ~= -1 then
for key, val in ipairs(ctx.params) do
opts[1] = val
ret = ret .. sep .. ctx.frame:callParserFunction(magic, opts)
sep = ccs
foo = las
ctx.params[key] = nil
end
end

if ctx.subset ~= 1 then
for key, val in pairs(ctx.params) do
opts[1] = val
ret = ret .. sep .. ctx.frame:callParserFunction(magic, opts)
sep = ccs
foo = las
end
end

return ret .. foo


end
end
Line 520: Line 658:
iface['non-sequential'] = function(frame)
iface['non-sequential'] = function(frame)
return context_init(frame, library['non-sequential'], false, false)
return context_init(frame, library['non-sequential'], false, false)
end


-- Syntax: #invoke:params|setting|directives|...|function name
iface.setting = function(frame)
return context_init(frame, library.setting, false, false)
end
end


Line 564: Line 708:




-- Syntax: #invoke:params|value_of|parameter name|[header]|[footer]
-- 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:params|value_of|parameter name
iface.value_of = function(frame)
iface.value_of = function(frame)
return context_init(frame, library.value_of, true, true)
return context_init(frame, library.value_of, true, true)
Line 570: Line 730:




-- Syntax: #invoke:params|list|[key-value separator]|[argument separator]
-- Syntax: #invoke:params|list
-- |[header]|[footer]
iface.list = function(frame)
iface.list = function(frame)
return context_init(frame, library.list, true, false)
return context_init(frame, library.list, true, false)
Line 577: Line 736:




-- Syntax: #invoke:params|list_values|[argument separator]|[header]|[footer]
-- Syntax: #invoke:params|list_values
iface.list_values = function(frame)
iface.list_values = function(frame)
return context_init(frame, library.list_values, true, false)
return context_init(frame, library.list_values, true, false)
Line 583: Line 742:




-- Syntax: #invoke:params|for_each|wikitext|[header]|[footer]
-- Syntax: #invoke:params|for_each|wikitext
iface.for_each = function(frame)
iface.for_each = function(frame)
return context_init(frame, library.for_each, true, false)
return context_init(frame, library.for_each, true, false)
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
end


Line 621: Line 764:




-- Syntax: #invoke:params|call_for_each_value|template name|[append 1]
-- Syntax: #invoke:params|magic_for_each|parser function|[append 1]|[append 2]
-- |[append 2]|[...]|[append n]|[named param 1=value 1]|[...]
-- |[...]|[append n]|[named param 1=value 1]|[...]|[named param
-- |[named param n=value n]|[...]
-- 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)
iface.call_for_each_value = function(frame)
return context_init(frame, library.call_for_each_value, false, false)
return context_init(frame, library.call_for_each_value, false, false)
Line 629: Line 780:




-- Syntax: #invoke:params|invoke_for_each_value|module name|module function
-- Syntax: #invoke:params|invoke_for_each_value|module name|[append 1]|[append
-- |[append 1]|[append 2]|[...]|[append n]|[named param 1=value 1]
-- 2]|[...]|[append n]|[named param 1=value 1]|[...]|[named param
-- |[...]|[named param n=value n]|[...]
-- n=value n]|[...]
iface.invoke_for_each_value = function(frame)
iface.invoke_for_each_value = function(frame)
return context_init(frame, library.invoke_for_each_value, false, false)
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
end



Revision as of 07:19, 12 July 2023

Documentation for this module may be created at Module:Params/doc

	---                                        ---
	---     LOCAL ENVIRONMENT                  ---
	---    ________________________________    ---
	---                                        ---


-- Set directives
local slots = {
	i = 'itersep',
	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.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('End of arguments reached without a function call', 0)
	end
	if library[nextfn] == nil then
		error('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
		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



	--[[ Piping piped functions ]]--
	--------------------------------


-- See iface.sequential()
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
	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('The two directives `sequential` and `non-sequential` are in contradiction with each other', 0)
	end
	ctx.iterfunc = pairs
	ctx.subset = -1
	for key, val in ipairs(ctx.params) do ctx.params[key] = nil end
	return context_iterate(ctx, 1)
end


-- See iface.setting()
library.setting = function(ctx)

	local opts = ctx.pipe

	local cmd = (opts[1] or
			''):gsub('%s+', ''):gsub('/+', '/'):match'^/*(.*[^/])'

	if cmd == nil then
		error('No directive was given about what variables to set', 0)
	end

	local target = string.byte('/')
	local arglen = 2
	local aggregate = {}
	local varname
	local chr

	for idx = 1, #cmd do
		chr = cmd:byte(idx)
		if chr == target then
			for key, val in ipairs(aggregate) do
				ctx[val] = opts[arglen]
				aggregate[key] = nil
			end
			arglen = arglen + 1
		else
			varname = slots[string.char(chr)]
			if varname == nil then error('Unknown slot "' ..
				string.char(chr) .. '"', 0) end
			table.insert(aggregate, varname)
		end
	end

	for key, val in ipairs(aggregate) do ctx[val] = opts[arglen] end

	return context_iterate(ctx, arglen + 1)

end


-- See iface.cutting()
library.cutting = function(ctx)
	local lcut = tonumber(ctx.pipe[1])
	if lcut == nil then error('Left trim must be a number', 0) end
	local rcut = tonumber(ctx.pipe[2])
	if rcut == nil then error('Right trim must be a number', 0) end
	if ctx.subset == -1 then return context_iterate(ctx, 3) end
	local tbl = ctx.params
	local tlen = #tbl
	if lcut < 0 then lcut = tlen + lcut end
	if rcut < 0 then rcut = tlen + rcut end
	if lcut + rcut > 0 then
		if lcut + rcut >= tlen then
			for key, val in ipairs(tbl) do tbl[key] = nil end
		else
			local last = tlen - rcut + 1
			for idx = tlen, last, -1 do tbl[idx] = nil end
			for _ = 1, lcut, 1 do table.remove(tbl, 1) end
		end
	end
	return context_iterate(ctx, 3)
end


-- See iface.with_name_matching()
library.with_name_matching = function(ctx)
	for key, val in ctx.iterfunc(ctx.params) do
		if not string.find(key, ctx.pipe[1], 1, false) then
			ctx.params[key] = nil
		end
	end
	return context_iterate(ctx, 2)
end


-- See iface.with_name_not_matching()
library.with_name_not_matching = function(ctx)
	for key, val in ctx.iterfunc(ctx.params) do
		if string.find(key, ctx.pipe[1], 1, false) then
			ctx.params[key] = nil
		end
	end
	return context_iterate(ctx, 2)
end


-- See iface.with_value_matching()
library.with_value_matching = function(ctx)
	for key, val in ctx.iterfunc(ctx.params) do
		if not string.find(val, ctx.pipe[1], 1, false) then
			ctx.params[key] = nil
		end
	end
	return context_iterate(ctx, 2)
end


-- See iface.with_value_not_matching()
library.with_value_not_matching = function(ctx)
	for key, val in ctx.iterfunc(ctx.params) do
		if string.find(val, ctx.pipe[1], 1, false) then
			ctx.params[key] = nil
		end
	end
	return context_iterate(ctx, 2)
end



	--[[ Non-piping piped functions ]]--
	------------------------------------


-- See iface.count()
library.count = function(ctx)
	local count = 0
	for _ in ctx.iterfunc(ctx.params) do count = count + 1 end
	return count
end


-- See iface.concat_and_call()
library.concat_and_call = function(ctx)

	local opts = ctx.pipe
	local tname = opts[1]

	if tname == nil then error('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 = opts[1]

	if mname == nil then error('No module name was provided', 0) end
	if opts[2] == nil then error('No function name was provided', 0) end

	local fname = opts[2]:match'^%s*(.*%S)'

	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.value_of()
library.value_of = function(ctx)
	local opts = ctx.pipe
	local keystr = (opts[1] or ''):match'^%s*(.*%S)'
	if keystr == '' then error('No parameter name was provided', 0) end
	local val = ctx.params[tonumber(keystr) 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 pps = ctx.itersep or ''
	local kvs = ctx.pairsep or ''
	local sep = ctx.header or ''
	local las = ctx.footer or ''
	local foo = ctx.ifngiven or ''
	local ret = ''

	if ctx.subset ~= -1 then
		for key, val in ipairs(ctx.params) do
			ret = ret .. sep .. key .. kvs .. val
			sep = pps
			foo = las
			ctx.params[key] = nil
		end
	end

	if ctx.subset ~= 1 then
		for key, val in pairs(ctx.params) do
			ret = ret .. sep .. key .. kvs .. val
			sep = pps
			foo = las
		end
	end

	return ret .. foo

end


-- See iface.list_values()
library.list_values = function(ctx)

	local pps = ctx.itersep or ''
	local sep = ctx.header or ''
	local las = ctx.footer or ''
	local foo = ctx.ifngiven or ''
	local ret = ''

	if ctx.subset ~= -1 then
		for key, val in ipairs(ctx.params) do
			ret = ret .. sep .. val
			sep = pps
			foo = las
			ctx.params[key] = nil
		end
	end

	if ctx.subset ~= 1 then
		for key, val in pairs(ctx.params) do
			ret = ret .. sep .. val
			sep = pps
			foo = las
		end
	end

	return ret .. foo

end


-- See iface.for_each()
library.for_each = function(ctx)

	local pps = ctx.itersep or ''
	local las = ctx.footer or ''
	local sep = ctx.header or ''
	local foo = ctx.ifngiven or ''
	local txt = ctx.pipe[1]
	local ret = ''

	if ctx.subset ~= -1 then
		for key, val in ipairs(ctx.params) do
			ret = ret .. sep .. string.gsub(
				string.gsub(txt, '%$#', key),
				'%$@',
				val
			)
			sep = pps
			foo = las
			ctx.params[key] = nil
		end
	end

	if ctx.subset ~= 1 then
		for key, val in pairs(ctx.params) do
			ret = ret .. sep .. string.gsub(
				string.gsub(txt, '%$#', key),
				'%$@',
				val
			)
			sep = pps
			foo = las
		end
	end

	return ret .. foo

end


-- See iface.call_for_each()
library.call_for_each = function(ctx)

	local opts = ctx.pipe

	if opts[1] == nil then error('No template 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 ret = ''

	local model = { title = opts[1]:match'^%s*(.*%S)', args = opts }

	table.insert(opts, 1, true)

	if ctx.subset ~= -1 then
		for key, val in ipairs(ctx.params) do
			opts[1] = key
			opts[2] = val
			ret = ret .. sep .. ctx.frame:expandTemplate(model)
			sep = ccs
			foo = las
			ctx.params[key] = nil
		end
	end

	if ctx.subset ~= 1 then
		for key, val in pairs(ctx.params) do
			opts[1] = key
			opts[2] = val
			ret = ret .. sep .. ctx.frame:expandTemplate(model)
			sep = ccs
			foo = las
		end
	end

	return ret .. foo

end


-- See iface.invoke_for_each()
library.invoke_for_each = function(ctx)

	local opts = ctx.pipe

	if opts[1] == nil then error('No module name was provided', 0) end
	if opts[2] == nil then error('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 ret = ''

	local model = { title = 'Module:' .. opts[1]:match'^%s*(.*%S)', args = opts }
	local mfunc = require(model.title)[opts[2]:match'^%s*(.*%S)']

	if ctx.subset ~= -1 then
		for key, val in ipairs(ctx.params) do
			opts[1] = key
			opts[2] = val
			ret = ret .. sep .. mfunc(ctx.frame:newChild(model))
			sep = ccs
			foo = las
			ctx.params[key] = nil
		end
	end

	if ctx.subset ~= 1 then
		for key, val in pairs(ctx.params) do
			opts[1] = key
			opts[2] = val
			ret = ret .. sep .. mfunc(ctx.frame:newChild(model))
			sep = ccs
			foo = las
		end
	end

	return ret .. foo

end


-- See iface.magic_for_each()
library.magic_for_each = function(ctx)

	local opts = ctx.pipe

	if opts[1] == nil then error('No template 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 magic = opts[1]:match'^%s*(.*%S)'
	local ret = ''

	table.insert(opts, 1, true)

	if ctx.subset ~= -1 then
		for key, val in ipairs(ctx.params) do
			opts[1] = key
			opts[2] = val
			ret = ret .. sep .. ctx.frame:callParserFunction(magic, opts)
			sep = ccs
			foo = las
			ctx.params[key] = nil
		end
	end

	if ctx.subset ~= 1 then
		for key, val in pairs(ctx.params) do
			opts[1] = key
			opts[2] = val
			ret = ret .. sep .. ctx.frame:callParserFunction(magic, opts)
			sep = ccs
			foo = las
		end
	end

	return ret .. foo

end


-- See iface.call_for_each_value()
library.call_for_each_value = function(ctx)

	local opts = ctx.pipe

	if opts[1] == nil then error('No template 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 ret = ''

	local model = { title = opts[1]:match'^%s*(.*%S)', args = opts }

	if ctx.subset ~= -1 then
		for key, val in ipairs(ctx.params) do
			opts[1] = val
			ret = ret .. sep .. ctx.frame:expandTemplate(model)
			sep = ccs
			foo = las
			ctx.params[key] = nil
		end
	end

	if ctx.subset ~= 1 then
		for key, val in pairs(ctx.params) do
			opts[1] = val
			ret = ret .. sep .. ctx.frame:expandTemplate(model)
			sep = ccs
			foo = las
		end
	end

	return ret .. foo

end


-- See iface.invoke_for_each_value()
library.invoke_for_each_value = function(ctx)

	local opts = ctx.pipe

	if opts[1] == nil then error('No module name was provided', 0) end
	if opts[2] == nil then error('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 ret = ''

	local model = { title = 'Module:' .. opts[1]:match'^%s*(.*%S)', args = opts }
	local mfunc = require(model.title)[opts[2]:match'^%s*(.*%S)']

	table.remove(opts, 1)

	if ctx.subset ~= -1 then
		for key, val in ipairs(ctx.params) do
			opts[1] = val
			ret = ret .. sep .. mfunc(ctx.frame:newChild(model))
			sep = ccs
			foo = las
			ctx.params[key] = nil
		end
	end

	if ctx.subset ~= 1 then
		for key, val in pairs(ctx.params) do
			opts[1] = val
			ret = ret .. sep .. mfunc(ctx.frame:newChild(model))
			sep = ccs
			foo = las
		end
	end

	return ret .. foo

end


-- See iface.magic_for_each_value()
library.magic_for_each_value = function(ctx)

	local opts = ctx.pipe

	if opts[1] == nil then error('No template 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 magic = opts[1]:match'^%s*(.*%S)'
	local ret = ''

	if ctx.subset ~= -1 then
		for key, val in ipairs(ctx.params) do
			opts[1] = val
			ret = ret .. sep .. ctx.frame:callParserFunction(magic, opts)
			sep = ccs
			foo = las
			ctx.params[key] = nil
		end
	end

	if ctx.subset ~= 1 then
		for key, val in pairs(ctx.params) do
			opts[1] = val
			ret = ret .. sep .. ctx.frame:callParserFunction(magic, opts)
			sep = ccs
			foo = las
		end
	end

	return ret .. foo

end



	---                                        ---
	---     PUBLIC ENVIRONMENT                 ---
	---    ________________________________    ---
	---                                        ---


-- The public table of functions
local iface = {}



	--[[ Piping interface functions ]]--
	------------------------------------


-- 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|setting|directives|...|function name
iface.setting = function(frame)
	return context_init(frame, library.setting, false, false)
end


-- Syntax:  #invoke:params|cutting|left trim|right trim|function name
iface.cutting = function(frame)
	return context_init(frame, library.cutting, false, false)
end


-- Syntax:  #invoke:params|with_name_matching|pattern|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|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|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|function name
iface.with_value_not_matching = function(frame)
	return context_init(frame, library.with_value_not_matching, false, false)
end



	--[[ Non-piping interface 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: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


return iface