Module:Params: Difference between revisions

Created page with " --- --- --- LOCAL ENVIRONMENT --- --- ________________________________ --- --- --- --Abstract utilities -- ---------------------------- -- Helper function for `string.gsub()` (for managing zero-padded numbers) local function zero_padded (str) return ('%03d%s'):format(#str, str) end -- Helper function for `table.sort()` (for natural sorting) local fu..."
 
The directives ‘with_pattern_isep’, ‘with_plain_isep’, ‘with_pattern_psep’ and ‘with_plain_psep’ have been renamed respectively to ‘splitter_pattern’, ‘splitter_string’, ‘setter_pattern’, and ‘setter_string’
Line 32: Line 32:




-- Remove numerical elements from a table, shifting everything to the left
-- Remove some numeric elements from a table, shifting everything to the left
local function remove_numerical_keys (tbl, idx, len)
local function remove_numeric_keys (tbl, idx, len)
local cache = {}
local cache = {}
local tmp = idx + len - 1
local tmp = idx + len - 1
Line 105: Line 105:


-- Move a key from a table to another, but only if under a different name and
-- Move a key from a table to another, but only if under a different name and
-- always parsing numerical strings as numbers
-- always parsing numeric strings as numbers
local function steal_if_renamed (val, src, skey, dest, dkey)
local function steal_if_renamed (val, src, skey, dest, dkey)
local realkey = tonumber(dkey) or dkey:match'^%s*(.-)%s*$'
local realkey = tonumber(dkey) or dkey:match'^%s*(.-)%s*$'
Line 173: Line 173:
f = 'footer',
f = 'footer',
n = 'ifngiven'
n = 'ifngiven'
}
-- Possible trimming modes for the `parsing` modifier
local trim_parse_opts = {
trim_none = { false, false },
trim_positional = { false, true },
trim_named = { true, false },
trim_all = { true, true }
}
-- Possible string modes for the iteration separator in the `parsing` and
-- `reinterpreting` modifiers
local isep_parse_opts = {
splitter_pattern = false,
splitter_string = true
}
-- Possible string modes for the key-value separator in the `parsing` and
-- `reinterpreting` modifiers
local psep_parse_opts = {
setter_pattern = false,
setter_string = true
}
}


Line 184: Line 209:




-- Functions listed here declare that they don't need the `frame.args`
-- Hard-coded name of the module (to avoid going through `frame:getTitle()`)
local modulename = 'Module:Params'
 
 
-- The functions listed here declare that they don't need the `frame.args`
-- metatable to be copied into a regular table; if they are modifiers they also
-- metatable to be copied into a regular table; if they are modifiers they also
-- guarantee that they will make available their own (modified) copy
-- guarantee that they will make their own (modified) copy available
local refpipe = {
local refpipe = {
call_for_each_group = true,
coins = true,
count = true,
count = true,
value_of = true,
for_each = true,
list = true,
list = true,
list_values = true,
list_values = true,
for_each = true,
value_of = true
call_for_each_group = true
}
}




-- Functions listed here declare that they don't need the
-- The functions listed here declare that they don't need the
-- `frame:getParent().args` metatable to be copied into a regular table; if  
-- `frame:getParent().args` metatable to be copied into a regular table; if  
-- they are modifiers they also guarantee that they will make available their
-- they are modifiers they also guarantee that they will make their own
-- own (modified) copy
-- (modified) copy available
local refparams = {
local refparams = {
--inserting = true,
call_for_each_group = true,
grouping_by_calling = true,
combining_by_calling = true,
count = true,
concat_and_call = true,
concat_and_call = true,
concat_and_invoke = true,
concat_and_invoke = true,
concat_and_magic = true,
concat_and_magic = true,
count = true,
--inserting = true,
grouping_by_calling = true,
value_of = true,
value_of = true,
call_for_each_group = true
with_name_matching = true
}
}




-- Maximum number of numerical parameters that can be filled, if missing (we
-- Maximum number of numeric parameters that can be filled, if missing (we
-- chose an arbitrary number for this constant; you can discuss about its
-- chose an arbitrary number for this constant; you can discuss about its
-- optimal value at Module talk:Params)
-- optimal value at Module talk:Params)
Line 223: Line 255:




-- Functions that can only be invoked in first position
-- Functions and modifiers that can only be invoked in first position
local static_iface = {}
local static_iface = {}




-- Create a new context
-- Create a new context
local function context_new ()
local function context_new (frame)
local ctx = {}
local ctx = {}
ctx.luaname = 'Module:Params' --[[ or `frame:getTitle()` ]]--
ctx.frame = frame
ctx.oparams = frame.args
ctx.firstposonly = static_iface
ctx.iterfunc = pairs
ctx.iterfunc = pairs
ctx.sorttype = 0
ctx.sorttype = 0
ctx.firstposonly = static_iface
ctx.n_parents = 0
ctx.n_children = 0
ctx.n_available = maxfill
ctx.n_available = maxfill
return ctx
return ctx
Line 245: Line 280:
nextfn = ctx.pipe[n_forward]:match'^%s*(.*%S)'
nextfn = ctx.pipe[n_forward]:match'^%s*(.*%S)'
end
end
if nextfn == nil then error(ctx.luaname ..
if nextfn == nil then error(modulename ..
': You must specify a function to call', 0) end
': You must specify a function to call', 0) end
if library[nextfn] == nil then
if library[nextfn] == nil then
if ctx.firstposonly[nextfn] == nil then error(ctx.luaname ..
if ctx.firstposonly[nextfn] == nil then error(modulename ..
': The function ‘' .. nextfn .. '’ does not exist', 0)
': The function ‘' .. nextfn .. '’ does not exist', 0)
else error(ctx.luaname .. ': The ‘' .. nextfn ..
else error(modulename .. ': The ‘' .. nextfn ..
'’ directive can only appear in first position', 0)
'’ directive can only appear in first position', 0)
end
end
end
end
remove_numerical_keys(ctx.pipe, 1, n_forward)
remove_numeric_keys(ctx.pipe, 1, n_forward)
return library[nextfn]
return library[nextfn]
end
end
Line 263: Line 298:
local fn = start_with
local fn = start_with
repeat fn = fn(ctx) until not fn
repeat fn = fn(ctx) until not fn
if ctx.n_parents > 0 then error(modulename ..
': One or more ‘merging_substack’ directives are missing', 0) end
if ctx.n_children > 0 then error(modulename ..
', For some of the snapshots either the ‘flushing’ directive is missing or a group has not been properly closed with ‘merging_substack’', 0) end
end
-- Add a new stack of parameters to `ctx.children`
local function push_cloned_stack (ctx, tbl)
local newparams = {}
local currsnap = ctx.n_children + 1
if ctx.children == nil then ctx.children = { newparams }
else ctx.children[currsnap] = newparams end
for key, val in pairs(tbl) do newparams[key] = val end
ctx.n_children = currsnap
end
end




-- Parse user arguments of type `...|[let]|[...][number of additional
-- Parse optional user arguments of type `...|[let]|[...][number of additional
-- parameters]|[parameter 1]|[parameter 2]|[...]`
-- parameters]|[parameter 1]|[parameter 2]|[...]`
local function parse_child_args (src, start_from, append_after)
local function load_child_opts (src, start_from, append_after)
local names
local names
local tmp
local tmp
local dest = {}
local tbl = {}
local pin = start_from
local pin = start_from
if src[pin] ~= nil and src[pin]:match'^%s*let%s*$' then
if src[pin] ~= nil and src[pin]:match'^%s*let%s*$' then
Line 286: Line 336:
if tmp < 0 then tmp = -1 end
if tmp < 0 then tmp = -1 end
local shf = append_after - pin
local shf = append_after - pin
for idx = pin + 1, pin + tmp do dest[idx + shf] = src[idx] end
for idx = pin + 1, pin + tmp do tbl[idx + shf] = src[idx] end
pin = pin + tmp + 1
pin = pin + tmp + 1
end
end
if names ~= nil then
if names ~= nil then
for key, val in pairs(names) do dest[key] = val end
for key, val in pairs(names) do tbl[key] = val end
end
end
return dest, pin
return tbl, pin
end
end




-- Parse the arguments of some of the `mapping_*` and `renaming_*` class of
-- Load the optional arguments of some of the `mapping_*` and `renaming_*`
-- modifiers
-- class of modifiers
local function parse_callback_args (src, n_skip, default_style)
local function load_callback_opts (src, n_skip, default_style)
local style
local style
local shf
local shf
Line 324: Line 374:
else n_exist = math.max(n_exist, varg) end
else n_exist = math.max(n_exist, varg) end
end
end
local dest, nargs = parse_child_args(src, style[2] + shf, n_exist)
local dest, nargs = load_child_opts(src, style[2] + shf, n_exist)
tmp = style[1]
tmp = style[1]
if (tmp == 3 or tmp == 2) and dest[karg] ~= nil then
if (tmp == 3 or tmp == 2) and dest[karg] ~= nil then
Line 336: Line 386:
-- Parse the arguments of some of the `mapping_*` and `renaming_*` class of
-- Parse the arguments of some of the `mapping_*` and `renaming_*` class of
-- modifiers
-- modifiers
local function parse_replace_args (opts, fname)
local function load_replace_args (opts, fname)
if opts[1] == nil then error(ctx.luaname ..
if opts[1] == nil then error(modulename ..
', ‘' .. fname .. '’: No pattern string was given', 0) end
', ‘' .. fname .. '’: No pattern string was given', 0) end
if opts[2] == nil then error(ctx.luaname ..
if opts[2] == nil then error(modulename ..
', ‘' .. fname .. '’: No replacement string was given', 0) end
', ‘' .. fname .. '’: No replacement string was given', 0) end
local ptn = opts[1]
local ptn = opts[1]
Line 355: Line 405:


-- Parse the arguments of the `with_*_matching` class of modifiers
-- Parse the arguments of the `with_*_matching` class of modifiers
local function parse_pattern_args (ctx, fname)
local function load_pattern_args (opts, fname)
local state = 0
local state = 0
local cnt = 1
local cnt = 1
Line 361: Line 411:
local nptns = 0
local nptns = 0
local ptns = {}
local ptns = {}
for _, val in ipairs(ctx.pipe) do
for _, val in ipairs(opts) do
if state == 0 then
if state == 0 then
nptns = nptns + 1
nptns = nptns + 1
Line 379: Line 429:
cnt = cnt + 1
cnt = cnt + 1
end
end
if state == 0 then error(ctx.luaname .. ', ‘' .. fname ..
if state == 0 then error(modulename .. ', ‘' .. fname ..
'’: No pattern was given', 0) end
'’: No pattern was given', 0) end
return ptns, cnt
return ptns, nptns, cnt
end
 
 
-- Load the optional arguments of the `parsing` and `reinterpreting` modifiers
local function load_parse_opts (opts, start_from)
local argc = start_from
local tmp
local optslots = { true, true, true }
local noptslots = 3
local trimn = true
local trimu = false
local iplain = true
local pplain = true
local isp = '|'
local psp = '='
repeat
noptslots = noptslots - 1
tmp = opts[argc]
if tmp == nil then break end
tmp = tmp:match'^%s*(.-)%s*$'
if optslots[1] ~= nil and trim_parse_opts[tmp] ~= nil then
tmp = trim_parse_opts[tmp]
trimn = tmp[1]
trimu = tmp[2]
optslots[1] = nil
elseif optslots[2] ~= nil and isep_parse_opts[tmp] ~= nil then
argc = argc + 1
iplain = isep_parse_opts[tmp]
isp = opts[argc]
optslots[2] = nil
elseif optslots[3] ~= nil and psep_parse_opts[tmp] ~= nil then
argc = argc + 1
pplain = psep_parse_opts[tmp]
psp = opts[argc]
optslots[3] = nil
else break end
argc = argc + 1
until noptslots < 1
return isp, iplain, psp, pplain, trimn, trimu, argc
end
end


Line 449: Line 538:




-- Return a new table that contains `src` regrouped according to the numerical
-- Return a new table that contains `src` regrouped according to the numeric
-- suffixes in its keys
-- suffixes in its keys
local function make_groups (src)
local function make_groups (src)
Line 475: Line 564:




-- Concatenate the numerical keys from the table of parameters to the numerical
-- Populate a table by parsing a parameter string
-- keys from the table of options; non-numerical keys from the table of options
local function parse_parameter_string (tbl, str, isp, ipl, psp, ppl, trn, tru)
-- will prevail over colliding non-numerical keys from the table of parameters
local key
local val
local spos1
local spos2
local pos1
local pos2
local pos3 = 0
local idx = 1
local lenplone = #str + 1
if isp == nil or isp == '' then
if psp == nil or psp == '' then
if tru then tbl[idx] = str:match'^%s*(.-)%s*$'
else tbl[idx] = str end
return tbl
end
spos1, spos2 = str:find(psp, 1, ppl)
if spos1 == nil then
key = idx
if tru then val = str:match'^%s*(.-)%s*$'
else val = str end
idx = idx + 1
else
key = str:sub(1, spos1 - 1)
key = tonumber(key) or key:match'^%s*(.-)%s*$'
val = str:sub(spos2 + 1)
if trn then val = val:match'^%s*(.-)%s*$' end
end
tbl[key] = val
return tbl
end
if psp == nil or psp == '' then
repeat
pos1 = pos3 + 1
pos2, pos3 = str:find(isp, pos1, ipl)
val = str:sub(pos1, (pos2 or lenplone) - 1)
if tru then val = val:match'^%s*(.-)%s*$' end
tbl[idx] = val
idx = idx + 1
until pos2 == nil
return tbl
end
repeat
pos1 = pos3 + 1
pos2, pos3 = str:find(isp, pos1, ipl)
val = str:sub(pos1, (pos2 or lenplone) - 1)
spos1, spos2 = val:find(psp, 1, ppl)
if spos1 == nil then
key = idx
if tru then val = val:match'^%s*(.-)%s*$' end
idx = idx + 1
else
key = val:sub(1, spos1 - 1)
key = tonumber(key) or key:match'^%s*(.-)%s*$'
val = val:sub(spos2 + 1)
if trn then val = val:match'^%s*(.-)%s*$' end
end
tbl[key] = val
until pos2 == nil
return tbl
end
 
 
-- Concatenate the numeric keys from the table of parameters to the numeric
-- keys from the table of options; non-numeric keys from the table of options
-- will prevail over colliding non-numeric keys from the table of parameters
local function concat_params (ctx)
local function concat_params (ctx)
local tbl = ctx.params
local tbl = ctx.params
local size = table.maxn(ctx.pipe)
local nmax = table.maxn(ctx.pipe)
local retval = {}
local retval = {}
if ctx.subset == 1 then
if ctx.subset == 1 then
-- We need only the sequence
-- We need only the sequence
for key, val in ipairs(tbl) do retval[key + size] = val end
for key, val in ipairs(tbl) do retval[key + nmax] = val end
else
else
if ctx.subset == -1 then
if ctx.subset == -1 then
for key, val in ipairs(tbl) do tbl[key] = nil end
for key in ipairs(tbl) do tbl[key] = nil end
end
end
for key, val in pairs(tbl) do
for key, val in pairs(tbl) do
if type(key) == 'number' then retval[key + size] = val
if type(key) == 'number' and key > 0 then
retval[key + nmax] = val
else retval[key] = val end
else retval[key] = val end
end
end
Line 552: Line 706:
-- Syntax:  #invoke:params|sequential|pipe to
-- Syntax:  #invoke:params|sequential|pipe to
library.sequential = function (ctx)
library.sequential = function (ctx)
if ctx.subset == -1 then error(ctx.luaname ..
if ctx.subset == -1 then error(modulename ..
': The two directives ‘non-sequential’ and ‘sequential’ are in contradiction with each other', 0) end
': The two directives ‘non-sequential’ and ‘sequential’ are in contradiction with each other', 0) end
if ctx.sorttype > 0 then error(ctx.luaname ..
if ctx.sorttype > 0 then error(modulename ..
': The ‘all_sorted’ and ‘reassorted’ directives are redundant when followed by ‘sequential’', 0) end
': The ‘all_sorted’ and ‘reassorted’ directives are redundant when followed by ‘sequential’', 0) end
ctx.iterfunc = ipairs
ctx.iterfunc = ipairs
Line 564: Line 718:
-- Syntax:  #invoke:params|non-sequential|pipe to
-- Syntax:  #invoke:params|non-sequential|pipe to
library['non-sequential'] = function (ctx)
library['non-sequential'] = function (ctx)
if ctx.subset == 1 then error(ctx.luaname ..
if ctx.subset == 1 then error(modulename ..
': The two directives ‘sequential’ and ‘non-sequential’ are in contradiction with each other', 0) end
': The two directives ‘sequential’ and ‘non-sequential’ are in contradiction with each other', 0) end
ctx.iterfunc = pairs
ctx.iterfunc = pairs
Line 574: Line 728:
-- Syntax:  #invoke:params|all_sorted|pipe to
-- Syntax:  #invoke:params|all_sorted|pipe to
library.all_sorted = function (ctx)
library.all_sorted = function (ctx)
if ctx.subset == 1 then error(ctx.luaname ..
if ctx.subset == 1 then error(modulename ..
': The ‘all_sorted’ directive is redundant after ‘sequential’', 0) end
': The ‘all_sorted’ directive is redundant after ‘sequential’', 0) end
if ctx.sorttype == 2 then error(ctx.luaname ..
if ctx.sorttype == 2 then error(modulename ..
': The two directives ‘reassorted’ and ‘sequential’ are in contradiction with each other', 0) end
': The two directives ‘reassorted’ and ‘sequential’ are in contradiction with each other', 0) end
ctx.sorttype = 1
ctx.sorttype = 1
Line 585: Line 739:
-- Syntax:  #invoke:params|reassorted|pipe to
-- Syntax:  #invoke:params|reassorted|pipe to
library.reassorted = function (ctx)
library.reassorted = function (ctx)
if ctx.subset == 1 then error(ctx.luaname ..
if ctx.subset == 1 then error(modulename ..
': The ‘reassorted’ directive is redundant after ‘sequential’', 0) end
': The ‘reassorted’ directive is redundant after ‘sequential’', 0) end
if ctx.sorttype == 1 then error(ctx.luaname ..
if ctx.sorttype == 1 then error(modulename ..
': The two directives ‘sequential’ and ‘reassorted’ are in contradiction with each other', 0) end
': The two directives ‘sequential’ and ‘reassorted’ are in contradiction with each other', 0) end
ctx.sorttype = 2
ctx.sorttype = 2
Line 601: Line 755:
cmd = cmd:gsub('%s+', ''):gsub('/+', '/'):match'^/*(.*[^/])'
cmd = cmd:gsub('%s+', ''):gsub('/+', '/'):match'^/*(.*[^/])'
end
end
if cmd == nil then error(ctx.luaname ..
if cmd == nil then error(modulename ..
', ‘setting’: No directive was given', 0) end
', ‘setting’: No directive was given', 0) end
local sep = string.byte('/')
local sep = string.byte('/')
Line 618: Line 772:
else
else
vname = memoryslots[string.char(chr)]
vname = memoryslots[string.char(chr)]
if vname == nil then error(ctx.luaname ..
if vname == nil then error(modulename ..
', ‘setting’: Unknown slot ‘' ..
', ‘setting’: Unknown slot ‘' ..
string.char(chr) .. '’', 0) end
string.char(chr) .. '’', 0) end
Line 669: Line 823:
if nmax ~= nil and nmax - nmin > nnums then
if nmax ~= nil and nmax - nmin > nnums then
ctx.n_available = ctx.n_available + nmin + nnums - nmax
ctx.n_available = ctx.n_available + nmin + nnums - nmax
if ctx.n_available < 0 then error(ctx.luaname ..
if ctx.n_available < 0 then error(modulename ..
', ‘filling_the_gaps’: It is possible to fill at most ' ..
', ‘filling_the_gaps’: It is possible to fill at most ' ..
tostring(maxfill) .. ' parameters', 0) end
tostring(maxfill) .. ' parameters', 0) end
Line 682: Line 836:
library.clearing = function (ctx)
library.clearing = function (ctx)
local tbl = ctx.params
local tbl = ctx.params
local numericals = {}
local numerics = {}
for key, val in pairs(tbl) do
for key, val in pairs(tbl) do
if type(key) == 'number' then
if type(key) == 'number' then
numericals[key] = val
numerics[key] = val
tbl[key] = nil
tbl[key] = nil
end
end
end
end
for key, val in ipairs(numericals) do tbl[key] = val end
for key, val in ipairs(numerics) do tbl[key] = val end
return context_iterate(ctx, 1)
return context_iterate(ctx, 1)
end
end
Line 697: Line 851:
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(ctx.luaname ..
if lcut == nil then error(modulename ..
', ‘cutting’: Left cut must be a number', 0) end
', ‘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(ctx.luaname ..
if rcut == nil then error(modulename ..
', ‘cutting’: Right cut must be a number', 0) end
', ‘cutting’: Right cut must be a number', 0) end
local tbl = ctx.params
local tbl = ctx.params
Line 732: Line 886:
library.cropping = function (ctx)
library.cropping = function (ctx)
local lcut = tonumber(ctx.pipe[1])
local lcut = tonumber(ctx.pipe[1])
if lcut == nil then error(ctx.luaname ..
if lcut == nil then error(modulename ..
', ‘cropping’: Left crop must be a number', 0) end
', ‘cropping’: Left crop must be a number', 0) end
local rcut = tonumber(ctx.pipe[2])
local rcut = tonumber(ctx.pipe[2])
if rcut == nil then error(ctx.luaname ..
if rcut == nil then error(modulename ..
', ‘cropping’: Right crop must be a number', 0) end
', ‘cropping’: Right crop must be a number', 0) end
local tbl = ctx.params
local tbl = ctx.params
Line 776: Line 930:
library.purging = function (ctx)
library.purging = function (ctx)
local idx = tonumber(ctx.pipe[1])
local idx = tonumber(ctx.pipe[1])
if idx == nil then error(ctx.luaname ..
if idx == nil then error(modulename ..
', ‘purging’: Start offset must be a number', 0) end
', ‘purging’: Start offset must be a number', 0) end
local len = tonumber(ctx.pipe[2])
local len = tonumber(ctx.pipe[2])
if len == nil then error(ctx.luaname ..
if len == nil then error(modulename ..
', ‘purging’: Length must be a number', 0) end
', ‘purging’: Length must be a number', 0) end
local tbl = ctx.params
local tbl = ctx.params
Line 795: Line 949:
library.backpurging = function (ctx)
library.backpurging = function (ctx)
local last = tonumber(ctx.pipe[1])
local last = tonumber(ctx.pipe[1])
if last == nil then error(ctx.luaname ..
if last == nil then error(modulename ..
', ‘backpurging’: Start offset must be a number', 0) end
', ‘backpurging’: Start offset must be a number', 0) end
local len = tonumber(ctx.pipe[2])
local len = tonumber(ctx.pipe[2])
if len == nil then error(ctx.luaname ..
if len == nil then error(modulename ..
', ‘backpurging’: Length must be a number', 0) end
', ‘backpurging’: Length must be a number', 0) end
local idx
local idx
Line 822: Line 976:
library.rotating = function (ctx)
library.rotating = function (ctx)
local tbl = ctx.params
local tbl = ctx.params
local numericals = {}
local numerics = {}
local nmax = 0
local nmax = 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
numericals[key] = val
numerics[key] = val
tbl[key] = nil
tbl[key] = nil
if key > nmax then nmax = key end
if key > nmax then nmax = key end
end
end
end
end
for key, val in pairs(numericals) do tbl[nmax - key + 1] = val end
for key, val in pairs(numerics) do tbl[nmax - key + 1] = val end
return context_iterate(ctx, 1)
return context_iterate(ctx, 1)
end
end
Line 842: Line 996:
local shift = #tbl + 1
local shift = #tbl + 1
if shift < 2 then return library.rotating(ctx) end
if shift < 2 then return library.rotating(ctx) end
local numericals = {}
local numerics = {}
for key, val in pairs(tbl) do
for key, val in pairs(tbl) do
if type(key) == 'number' then
if type(key) == 'number' then
numericals[key] = val
numerics[key] = val
tbl[key] = nil
tbl[key] = nil
end
end
end
end
for key, val in pairs(numericals) do tbl[shift - key] = val end
for key, val in pairs(numerics) do tbl[shift - key] = val end
return context_iterate(ctx, 1)
return context_iterate(ctx, 1)
end
end
Line 859: Line 1,013:
library.mirroring = function (ctx)
library.mirroring = function (ctx)
local tbl = ctx.params
local tbl = ctx.params
local numericals = {}
local numerics = {}
local nmax
local nmax
local nmin
local nmin
for key, val in pairs(tbl) do
for key, val in pairs(tbl) do
if type(key) == 'number' then
if type(key) == 'number' then
numericals[key] = val
numerics[key] = val
tbl[key] = nil
tbl[key] = nil
if nmax == nil then
if nmax == nil then
Line 873: Line 1,027:
end
end
end
end
for key, val in pairs(numericals) do tbl[nmax + nmin - key] = val end
for key, val in pairs(numerics) do tbl[nmax + nmin - key] = val end
return context_iterate(ctx, 1)
return context_iterate(ctx, 1)
end
end
Line 920: Line 1,074:
-- this function MUST create a copy of it before returning
-- this function MUST create a copy of it before returning
local idx = tonumber(ctx.pipe[1])
local idx = tonumber(ctx.pipe[1])
if idx == nil then error(ctx.luaname ..
if idx == nil then error(modulename ..
', ‘inserting’: Position must be a number', 0) end
', ‘inserting’: Position must be a number', 0) end
local len = tonumber(ctx.pipe[2])
local len = tonumber(ctx.pipe[2])
if len == nil or len < 1 then error(ctx.luaname ..
if len == nil or len < 1 then error(modulename ..
', ‘inserting’: The amount must be a number greater than zero', 0) end
', ‘inserting’: The amount must be a number greater than zero', 0) end
local opts = ctx.pipe
local opts = ctx.pipe
Line 936: Line 1,090:
-- Syntax:  #invoke:params|imposing|name|value|pipe to
-- Syntax:  #invoke:params|imposing|name|value|pipe to
library.imposing = function (ctx)
library.imposing = function (ctx)
if ctx.pipe[1] == nil then error(ctx.luaname ..
if ctx.pipe[1] == nil then error(modulename ..
', ‘imposing’: Missing parameter name to impose', 0) end
', ‘imposing’: Missing parameter name to impose', 0) end
local key = ctx.pipe[1]:match'^%s*(.-)%s*$'
local key = ctx.pipe[1]:match'^%s*(.-)%s*$'
Line 946: Line 1,100:
-- Syntax:  #invoke:params|providing|name|value|pipe to
-- Syntax:  #invoke:params|providing|name|value|pipe to
library.providing = function (ctx)
library.providing = function (ctx)
if ctx.pipe[1] == nil then error(ctx.luaname ..
if ctx.pipe[1] == nil then error(modulename ..
', ‘providing’: Missing parameter name to provide', 0) end
', ‘providing’: Missing parameter name to provide', 0) end
local key = ctx.pipe[1]:match'^%s*(.-)%s*$'
local key = ctx.pipe[1]:match'^%s*(.-)%s*$'
Line 957: Line 1,111:
-- Syntax:  #invoke:params|discarding|name|[how many]|pipe to
-- Syntax:  #invoke:params|discarding|name|[how many]|pipe to
library.discarding = function (ctx)
library.discarding = function (ctx)
if ctx.pipe[1] == nil then error(ctx.luaname ..
if ctx.pipe[1] == nil then error(modulename ..
', ‘discarding’: Missing parameter name to discard', 0) end
', ‘discarding’: Missing parameter name to discard', 0) end
local key = ctx.pipe[1]
local key = ctx.pipe[1]
Line 966: Line 1,120:
end
end
key = tonumber(key)
key = tonumber(key)
if key == nil then error(ctx.luaname ..
if key == nil then error(modulename ..
', ‘discarding’: A range was provided, but the initial parameter name is not numerical', 0) end
', ‘discarding’: A range was provided, but the initial parameter name is not numeric', 0) end
if len < 1 then error(ctx.luaname ..
if len < 1 then error(modulename ..
', ‘discarding’: A range can only be a number greater than zero', 0) end
', ‘discarding’: A range can only be a number greater than zero', 0) end
for idx = key, key + len - 1 do ctx.params[idx] = nil end
for idx = key, key + len - 1 do ctx.params[idx] = nil end
Line 975: Line 1,129:




-- Syntax:  #invoke:params|with_name_matching|target 1|[plain flag 1]|[or]
-- Syntax:  #invoke:params|excluding_non-numeric_names|pipe to
--            |[target 2]|[plain flag 2]|[or]|[...]|[target N]|[plain flag
library['excluding_non-numeric_names'] = function (ctx)
--            N]|pipe to
local tmp = ctx.params
library.with_name_matching = function (ctx)
for key, val in pairs(tmp) do
if type(key) ~= 'number' then tmp[key] = nil end
end
return context_iterate(ctx, 1)
end
 
 
-- Syntax:  #invoke:params|excluding_numeric_names|pipe to
library.excluding_numeric_names = function (ctx)
local tmp = ctx.params
for key, val in pairs(tmp) do
if type(key) == 'number' then tmp[key] = nil end
end
return context_iterate(ctx, 1)
end
 
 
-- Syntax:  #invoke:params|with_name_matching|target 1|[plain flag 1]|[or]
--            |[target 2]|[plain flag 2]|[or]|[...]|[target N]|[plain flag
--            N]|pipe to
library.with_name_matching = function (ctx)
-- NOTE: `ctx.params` might be the original metatable! As a modifier,
-- this function MUST create a copy of it before returning
local targets, nptns, argc = load_pattern_args(ctx.pipe, targets,
'with_name_matching')
local tmp
local ptn
local tbl = ctx.params
local tbl = ctx.params
local targets, argc = parse_pattern_args(ctx, targets,
local newparams = {}
'with_name_matching')
for idx = 1, nptns do
local nomatch
ptn = targets[idx]
for key in pairs(tbl) do
if ptn[3] then
nomatch = true
tmp = tonumber(ptn[1]) or ptn[1]
for _, ptn in ipairs(targets) do
newparams[tmp] = tbl[tmp]
if not ptn[3] then
else
if string.find(key, ptn[1], 1, ptn[2]) then
for key, val in pairs(tbl) do
nomatch = false
if tostring(key):find(ptn[1], 1, ptn[2]) then
break
newparams[key] = val
end
end
elseif key == ptn[1] then
nomatch = false
break
end
end
end
end
if nomatch then tbl[key] = nil end
end
end
ctx.params = newparams
return context_iterate(ctx, argc)
return context_iterate(ctx, argc)
end
end
Line 1,006: Line 1,183:
--            flag N]|pipe to
--            flag N]|pipe to
library.with_name_not_matching = function (ctx)
library.with_name_not_matching = function (ctx)
local targets, nptns, argc = load_pattern_args(ctx.pipe, targets,
'with_name_not_matching')
local tbl = ctx.params
local tbl = ctx.params
local targets, argc = parse_pattern_args(ctx, targets,
if nptns == 1 and targets[1][3] then
'with_name_not_matching')
local tmp = targets[1][1]
tbl[tonumber(tmp) or tmp] = nil
return context_iterate(ctx, argc)
end
local yesmatch
local yesmatch
local ptn
for key in pairs(tbl) do
for key in pairs(tbl) do
yesmatch = true
yesmatch = true
for _, ptn in ipairs(targets) do
for idx = 1, nptns do
ptn = targets[idx]
if ptn[3] then
if ptn[3] then
if key ~= ptn[1] then
if tostring(key) ~= ptn[1] then
yesmatch = false
yesmatch = false
break
break
end
end
elseif not string.find(key, ptn[1], 1, ptn[2]) then
elseif not tostring(key):find(ptn[1], 1, ptn[2]) then
yesmatch = false
yesmatch = false
break
break
Line 1,034: Line 1,218:
library.with_value_matching = function (ctx)
library.with_value_matching = function (ctx)
local tbl = ctx.params
local tbl = ctx.params
local targets, argc = parse_pattern_args(ctx, targets,
local targets, nptns, argc = load_pattern_args(ctx.pipe, targets,
'with_value_matching')
'with_value_matching')
local nomatch
local nomatch
local ptn
for key, val in pairs(tbl) do
for key, val in pairs(tbl) do
nomatch = true
nomatch = true
for _, ptn in ipairs(targets) do
for idx = 1, nptns do
ptn = targets[idx]
if ptn[3] then
if ptn[3] then
if val == ptn[1] then
if val == ptn[1] then
Line 1,045: Line 1,231:
break
break
end
end
elseif string.find(val, ptn[1], 1, ptn[2]) then
elseif val:find(ptn[1], 1, ptn[2]) then
nomatch = false
nomatch = false
break
break
Line 1,061: Line 1,247:
library.with_value_not_matching = function (ctx)
library.with_value_not_matching = function (ctx)
local tbl = ctx.params
local tbl = ctx.params
local targets, argc = parse_pattern_args(ctx, targets,
local targets, nptns, argc = load_pattern_args(ctx.pipe, targets,
'with_value_not_matching')
'with_value_not_matching')
local yesmatch
local yesmatch
local ptn
for key, val in pairs(tbl) do
for key, val in pairs(tbl) do
yesmatch = true
yesmatch = true
for _, ptn in ipairs(targets) do
for idx = 1, nptns do
ptn = targets[idx]
if ptn[3] then
if ptn[3] then
if val ~= ptn[1] then
if val ~= ptn[1] then
Line 1,072: Line 1,260:
break
break
end
end
elseif not string.find(val, ptn[1], 1, ptn[2]) then
elseif not val:find(ptn[1], 1, ptn[2]) then
yesmatch = false
yesmatch = false
break
break
Line 1,098: Line 1,286:
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(ctx.luaname ..
if tname == nil then error(modulename ..
', ‘mapping_by_calling’: No template name was provided', 0) end
', ‘mapping_by_calling’: No template name was provided', 0) end
local margs, argc, looptype, karg, varg = parse_callback_args(opts, 1,
local margs, argc, looptype, karg, varg = load_callback_opts(opts, 1,
mapping_styles.values_only)
mapping_styles.values_only)
local model = { title = tname, args = margs }
local model = { title = tname, args = margs }
Line 1,118: Line 1,306:
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(ctx.luaname ..
if mname == nil then error(modulename ..
', ‘mapping_by_invoking’: No module name was provided', 0) end
', ‘mapping_by_invoking’: 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(ctx.luaname ..
if fname == nil then error(modulename ..
', ‘mapping_by_invoking’: No function name was provided', 0) end
', ‘mapping_by_invoking’: No function name was provided', 0) end
local margs, argc, looptype, karg, varg = parse_callback_args(opts, 2,
local margs, argc, looptype, karg, varg = load_callback_opts(opts, 2,
mapping_styles.values_only)
mapping_styles.values_only)
local model = { title = 'Module:' .. mname, args = margs }
local model = { title = 'Module:' .. mname, args = margs }
local mfunc = require(model.title)[fname]
local mfunc = require(model.title)[fname]
if mfunc == nil then error(ctx.luaname ..
if mfunc == nil then error(modulename ..
', ‘mapping_by_invoking’: The function ‘' .. fname ..
', ‘mapping_by_invoking’: The function ‘' .. fname ..
'’ does not exist', 0) end
'’ does not exist', 0) end
value_maps[looptype](ctx.params, margs, karg, varg, function ()
value_maps[looptype](ctx.params, margs, karg, varg, function ()
return mfunc(ctx.frame:newChild(model))
return tostring(mfunc(ctx.frame:newChild(model)))
end)
end)
return context_iterate(ctx, argc)
return context_iterate(ctx, argc)
Line 1,144: Line 1,332:
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(ctx.luaname ..
if magic == nil then error(modulename ..
', ‘mapping_by_magic’: No parser function was provided', 0) end
', ‘mapping_by_magic’: No parser function was provided', 0) end
local margs, argc, looptype, karg, varg = parse_callback_args(opts, 1,
local margs, argc, looptype, karg, varg = load_callback_opts(opts, 1,
mapping_styles.values_only)
mapping_styles.values_only)
value_maps[looptype](ctx.params, margs, karg, varg, function ()
value_maps[looptype](ctx.params, margs, karg, varg, function ()
Line 1,159: Line 1,347:
library.mapping_by_replacing = function (ctx)
library.mapping_by_replacing = function (ctx)
local ptn, repl, nmax, is_strict, argc, die =
local ptn, repl, nmax, is_strict, argc, die =
parse_replace_args(ctx.pipe, 'mapping_by_replacing')
load_replace_args(ctx.pipe, 'mapping_by_replacing')
if die then return context_iterate(ctx, argc) end
if die then return context_iterate(ctx, argc) end
local tbl = ctx.params
local tbl = ctx.params
Line 1,186: Line 1,374:
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(ctx.luaname ..
if tname == nil then error(modulename ..
', ‘renaming_by_calling’: No template name was provided', 0) end
', ‘renaming_by_calling’: No template name was provided', 0) end
local rargs, argc, looptype, karg, varg = parse_callback_args(opts, 1,
local rargs, argc, looptype, karg, varg = load_callback_opts(opts, 1,
mapping_styles.names_only)
mapping_styles.names_only)
local model = { title = tname, args = rargs }
local model = { title = tname, args = rargs }
Line 1,206: Line 1,394:
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(ctx.luaname ..
if mname == nil then error(modulename ..
', ‘renaming_by_invoking’: No module name was provided', 0) end
', ‘renaming_by_invoking’: 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(ctx.luaname ..
if fname == nil then error(modulename ..
', ‘renaming_by_invoking’: No function name was provided', 0) end
', ‘renaming_by_invoking’: No function name was provided', 0) end
local rargs, argc, looptype, karg, varg = parse_callback_args(opts, 2,
local rargs, argc, looptype, karg, varg = load_callback_opts(opts, 2,
mapping_styles.names_only)
mapping_styles.names_only)
local model = { title = 'Module:' .. mname, args = rargs }
local model = { title = 'Module:' .. mname, args = rargs }
local mfunc = require(model.title)[fname]
local mfunc = require(model.title)[fname]
if mfunc == nil then error(ctx.luaname ..
if mfunc == nil then error(modulename ..
', ‘renaming_by_invoking’: The function ‘' .. fname ..
', ‘renaming_by_invoking’: The function ‘' .. fname ..
'’ does not exist', 0) end
'’ does not exist', 0) end
map_names(ctx.params, rargs, karg, varg, looptype, function ()
map_names(ctx.params, rargs, karg, varg, looptype, function ()
return mfunc(ctx.frame:newChild(model))
local tmp = mfunc(ctx.frame:newChild(model))
return tonumber(tmp) or tostring(tmp)
end)
end)
return context_iterate(ctx, argc)
return context_iterate(ctx, argc)
Line 1,232: Line 1,421:
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(ctx.luaname ..
if magic == nil then error(modulename ..
', ‘renaming_by_magic’: No parser function was provided', 0) end
', ‘renaming_by_magic’: No parser function was provided', 0) end
local rargs, argc, looptype, karg, varg = parse_callback_args(opts, 1,
local rargs, argc, looptype, karg, varg = load_callback_opts(opts, 1,
mapping_styles.names_only)
mapping_styles.names_only)
map_names(ctx.params, rargs, karg, varg, looptype, function ()
map_names(ctx.params, rargs, karg, varg, looptype, function ()
Line 1,247: Line 1,436:
library.renaming_by_replacing = function (ctx)
library.renaming_by_replacing = function (ctx)
local ptn, repl, nmax, is_strict, argc, die =
local ptn, repl, nmax, is_strict, argc, die =
parse_replace_args(ctx.pipe, 'renaming_by_replacing')
load_replace_args(ctx.pipe, 'renaming_by_replacing')
if die then return context_iterate(ctx, argc) end
if die then return context_iterate(ctx, argc) end
local tbl = ctx.params
local tbl = ctx.params
Line 1,280: Line 1,469:
local tmp
local tmp
if opts[1] ~= nil then tmp = opts[1]:match'^%s*(.*%S)' end
if opts[1] ~= nil then tmp = opts[1]:match'^%s*(.*%S)' end
if tmp == nil then error(ctx.luaname ..
if tmp == nil then error(modulename ..
', ‘grouping_by_calling’: No template name was provided', 0) end
', ‘grouping_by_calling’: No template name was provided', 0) end
local model = { title = tmp }
local model = { title = tmp }
local tmp, argc = parse_child_args(opts, 2, 0)
local tmp, argc = load_child_opts(opts, 2, 0)
local gargs = {}
local gargs = {}
for key, val in pairs(tmp) do
for key, val in pairs(tmp) do
Line 1,301: Line 1,490:




-- Syntax:  #invoke:params|parsing|string to parse|[trim flag]|[iteration
--            delimiter setter]|[...]|[key-value delimiter setter]|[...]|pipe to
library.parsing = function (ctx)
local opts = ctx.pipe
if opts[1] == nil then error(modulename ..
', ‘parsing’: No string to parse was provided', 0) end
local isep, iplain, psep, pplain, trimnamed, trimunnamed, argc =
load_parse_opts(opts, 2)
parse_parameter_string(ctx.params, opts[1], isep, iplain, psep, pplain,
trimnamed, trimunnamed)
return context_iterate(ctx, argc)
end


--[[ Functions ]]--
 
-----------------------------
-- Syntax:  #invoke:params|reinterpreting|parameter to reinterpret|[trim
--            flag]|[iteration delimiter setter]|[...]|[key-value delimiter
--            setter]|[...]|pipe to
library.reinterpreting = function (ctx)
local opts = ctx.pipe
if opts[1] == nil then error(modulename ..
', ‘reinterpreting’: No parameter to reinterpret was provided', 0) end
local isep, iplain, psep, pplain, trimnamed, trimunnamed, argc =
load_parse_opts(opts, 2)
local tbl = ctx.params
local tmp = tonumber(opts[1]) or opts[1]:match'^%s*(.-)%s*$'
local str = tbl[tmp]
if str ~= nil then
tbl[tmp] = nil
parse_parameter_string(tbl, str, isep, iplain, psep, pplain,
trimnamed, trimunnamed)
end
return context_iterate(ctx, argc)
end




-- Syntax:  #invoke:params|count
-- Syntax:  #invoke:params|combining_by_calling|template name|new parameter
library.count = function (ctx)
--            name|pipe to
-- NOTE: `ctx.pipe` and `ctx.params` might be the original metatables!
library.combining_by_calling = function (ctx)
local retval = 0
-- NOTE: `ctx.params` might be the original metatable! As a modifier,
for _ in ctx.iterfunc(ctx.params) do retval = retval + 1 end
-- this function MUST create a copy of it before returning
if ctx.subset == -1 then retval = retval - #ctx.params end
local tname = ctx.pipe[1]
ctx.text = retval
if tname ~= nil then tname = tname:match'^%s*(.*%S)'
return false
else error(modulename ..
', ‘combining_by_calling’: No template name was provided', 0) end
local merge_into = ctx.pipe[2]
if merge_into == nil then error(modulename ..
', ‘combining_by_calling’: No parameter name was provided', 0) end
merge_into = tonumber(merge_into) or merge_into:match'^%s*(.-)%s*$'
ctx.params = {
[merge_into] = ctx.frame:expandTemplate{
title = tname,
args = ctx.params
}
}
return context_iterate(ctx, 3)
end
end




-- Syntax:  #invoke:args|concat_and_call|template name|[prepend 1]|[prepend 2]
-- Syntax:  #invoke:params|snapshotting|pipe to
--           |[...]|[item n]|[named item 1=value 1]|[...]|[named item n=value
library.snapshotting = function (ctx)
--            n]|[...]
push_cloned_stack(ctx, ctx.params)
library.concat_and_call = function (ctx)
return context_iterate(ctx, 1)
-- NOTE: `ctx.params` might be the original metatable!
end
 
 
-- Syntax:  #invoke:params|remembering|pipe to
library.remembering = function (ctx)
push_cloned_stack(ctx, ctx.oparams)
return context_iterate(ctx, 1)
end
 
 
-- Syntax:  #invoke:params|entering_substack|[new]|pipe to
library.entering_substack = function (ctx)
local tbl = ctx.params
local ncurrparent = ctx.n_parents + 1
if ctx.parents == nil then ctx.parents = { tbl }
else ctx.parents[ncurrparent] = tbl end
ctx.n_parents = ncurrparent
if ctx.pipe[1] ~= nil and ctx.pipe[1]:match'^%s*new%s*$' then
ctx.params = {}
return context_iterate(ctx, 2)
end
local currsnap = ctx.n_children
if currsnap > 0 then
ctx.params = ctx.children[currsnap]
ctx.children[currsnap] = nil
ctx.n_children = currsnap - 1
else
local newparams = {}
for key, val in pairs(tbl) do newparams[key] = val end
ctx.params = newparams
end
return context_iterate(ctx, 1)
end
 
 
-- Syntax:  #invoke:params|pulling|parameter name|pipe to
library.pulling = function (ctx)
local opts = ctx.pipe
local opts = ctx.pipe
local tname
if opts[1] == nil then error(modulename ..
if opts[1] ~= nil then tname = opts[1]:match'^%s*(.*%S)' end
', ‘pulling’: No parameter to pull was provided', 0) end
if tname == nil then error(ctx.luaname ..
local parent
', ‘concat_and_call’: No template name was provided', 0) end
local tmp = ctx.n_parents
remove_numerical_keys(opts, 1, 1)
if tmp < 1 then parent = ctx.oparams else parent = ctx.parents[tmp] end
ctx.text = ctx.frame:expandTemplate{
tmp = tonumber(opts[1]) or opts[1]:match'^%s*(.-)%s*$'
title = tname,
if parent[tmp] ~= nil then ctx.params[tmp] = parent[tmp] end
args = concat_params(ctx)
return context_iterate(ctx, 2)
}
return false
end
end




-- Syntax:  #invoke:args|concat_and_invoke|module name|function name|[prepend
-- Syntax:  #invoke:params|detaching_substack|pipe to
--            1]|[prepend 2]|[...]|[item n]|[named item 1=value 1]|[...]|[named
library.detaching_substack = function (ctx)
--            item n=value n]|[...]
local ncurrparent = ctx.n_parents
library.concat_and_invoke = function (ctx)
if ncurrparent < 1 then error(modulename ..
-- NOTE: `ctx.params` might be the original metatable!
', ‘detaching_substack’: No substack has been created', 0) end
local opts = ctx.pipe
local parent = ctx.parents[ncurrparent]
local mname
for key in pairs(ctx.params) do parent[key] = nil end
local fname
return context_iterate(ctx, 1)
if opts[1] ~= nil then mname = opts[1]:match'^%s*(.*%S)' end
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
-- Syntax:  #invoke:params|leaving_substack|pipe to
if fname == nil then error(ctx.luaname ..
library.leaving_substack = function (ctx)
', ‘concat_and_invoke’: No function name was provided', 0) end
local ncurrparent = ctx.n_parents
remove_numerical_keys(opts, 1, 2)
if ncurrparent < 1 then error(modulename ..
local mfunc = require('Module:' .. mname)[fname]
', ‘leaving_substack’: No substack has been created', 0) end
if mfunc == nil then error(ctx.luaname ..
local currsnap = ctx.n_children + 1
', ‘concat_and_invoke’: The function ‘' .. fname ..
if ctx.children == nil then ctx.children = { ctx.params }
'’ does not exist', 0) end
else ctx.children[currsnap] = ctx.params end
ctx.text = mfunc(ctx.frame:newChild{
ctx.params = ctx.parents[ncurrparent]
title = 'Module:' .. fname,
ctx.parents[ncurrparent] = nil
args = concat_params(ctx)
ctx.n_parents = ncurrparent - 1
})
ctx.n_children = currsnap
return false
return context_iterate(ctx, 1)
end
end




-- Syntax:  #invoke:args|concat_and_magic|parser function|[prepend 1]|[prepend
-- Syntax:  #invoke:params|merging_substack|pipe to
--            2]|[...]|[item n]|[named item 1=value 1]|[...]|[named item n=
library.merging_substack = function (ctx)
--            value n]|[...]
local ncurrparent = ctx.n_parents
library.concat_and_magic = function (ctx)
if ncurrparent < 1 then error(modulename ..
-- NOTE: `ctx.params` might be the original metatable!
', ‘merging_substack’: No substack has been created', 0) end
local opts = ctx.pipe
local parent = ctx.parents[ncurrparent]
local magic
local child = ctx.params
if opts[1] ~= nil then magic = opts[1]:match'^%s*(.*%S)' end
ctx.params = parent
if magic == nil then error(ctx.luaname ..
ctx.parents[ncurrparent] = nil
', ‘concat_and_magic’: No parser function was provided', 0) end
ctx.n_parents = ncurrparent - 1
remove_numerical_keys(opts, 1, 1)
for key, val in pairs(child) do parent[key] = val end
ctx.text = ctx.frame:callParserFunction(magic, concat_params(ctx))
return context_iterate(ctx, 1)
return false
end
end




-- Syntax:  #invoke:params|value_of|parameter name
-- Syntax:  #invoke:params|flushing|pipe to
library.value_of = function (ctx)
library.flushing = function (ctx)
-- NOTE: `ctx.pipe` and `ctx.params` might be the original metatables!
if ctx.n_children < 1 then error(modulename ..
local opts = ctx.pipe
', ‘flushing’: There are no substacks to flush', 0) end
local kstr
local parent = ctx.params
if opts[1] ~= nil then kstr = opts[1]:match'^%s*(.*%S)' end
local currsnap = ctx.n_children
if kstr == nil then error(ctx.luaname ..
for key, val in pairs(ctx.children[currsnap]) do parent[key] = val end
', ‘value_of’: No parameter name was provided', 0) end
ctx.children[currsnap] = nil
local knum = tonumber(kstr)
ctx.n_children = currsnap - 1
local len = #ctx.params
return context_iterate(ctx, 1)
local val = ctx.params[knum or kstr]
if val ~= nil and (
ctx.subset ~= -1 or knum == nil or knum > len or knum < 1
) and (
ctx.subset ~= 1 or (knum ~= nil and knum <= len and knum > 0)
) then
ctx.text = (ctx.header or '') .. val .. (ctx.footer or '')
return false
end
ctx.text = ctx.ifngiven or ''
return false
end
end




-- Syntax:  #invoke:params|list
 
library.list = function (ctx)
--[[ Functions ]]--
-- NOTE: `ctx.pipe` might be the original metatable!
-----------------------------
local kvs = ctx.pairsep or ''
 
local pps = ctx.itersep or ''
 
local ret = {}
-- Syntax:  #invoke:params|count
local nss = 0
library.count = function (ctx)
flush_params(
-- NOTE: `ctx.pipe` and `ctx.params` might be the original metatables!
ctx,
local retval = 0
function (key, val)
for _ in ctx.iterfunc(ctx.params) do retval = retval + 1 end
ret[nss + 1] = pps
if ctx.subset == -1 then retval = retval - #ctx.params end
ret[nss + 2] = key
ctx.text = retval
ret[nss + 3] = kvs
return false
ret[nss + 4] = val
end
nss = nss + 4
 
end
 
)
-- Syntax:  #invoke:args|concat_and_call|template name|[prepend 1]|[prepend 2]
if nss > 0 then
--            |[...]|[item n]|[named item 1=value 1]|[...]|[named item n=value
if nss > 4 and ctx.lastsep ~= nil then
--            n]|[...]
ret[nss - 3] = ctx.lastsep
library.concat_and_call = function (ctx)
end
-- NOTE: `ctx.params` might be the original metatable!
ret[1] = ctx.header or ''
local opts = ctx.pipe
if ctx.footer ~= nil then ret[nss + 1] = ctx.footer end
local tname
ctx.text = table.concat(ret)
if opts[1] ~= nil then tname = opts[1]:match'^%s*(.*%S)' end
return false
if tname == nil then error(modulename ..
end
', ‘concat_and_call’: No template name was provided', 0) end
ctx.text = ctx.ifngiven or ''
remove_numeric_keys(opts, 1, 1)
return false
ctx.text = ctx.frame:expandTemplate{
end
title = tname,
 
args = concat_params(ctx)
 
}
-- Syntax:  #invoke:params|list_values
return false
library.list_values = function (ctx)
end
-- NOTE: `ctx.pipe` might be the original metatable!
 
local pps = ctx.itersep or ''
 
local ret = {}
-- Syntax:  #invoke:args|concat_and_invoke|module name|function name|[prepend
local nss = 0
--            1]|[prepend 2]|[...]|[item n]|[named item 1=value 1]|[...]|[named
flush_params(
--            item n=value n]|[...]
ctx,
library.concat_and_invoke = function (ctx)
function (key, val)
-- NOTE: `ctx.params` might be the original metatable!
ret[nss + 1] = pps
local opts = ctx.pipe
ret[nss + 2] = val
local mname
nss = nss + 2
local fname
end
if opts[1] ~= nil then mname = opts[1]:match'^%s*(.*%S)' end
)
if mname == nil then error(modulename ..
if nss > 0 then
', ‘concat_and_invoke’: No module name was provided', 0) end
if nss > 2 and ctx.lastsep ~= nil then
if opts[2] ~= nil then fname = opts[2]:match'^%s*(.*%S)' end
ret[nss - 1] = ctx.lastsep
if fname == nil then error(modulename ..
end
', ‘concat_and_invoke’: No function name was provided', 0) end
ret[1] = ctx.header or ''
remove_numeric_keys(opts, 1, 2)
if ctx.footer ~= nil then ret[nss + 1] = ctx.footer end
local mfunc = require('Module:' .. mname)[fname]
ctx.text = table.concat(ret)
if mfunc == nil then error(modulename ..
return false
', ‘concat_and_invoke’: The function ‘' .. fname ..
'’ does not exist', 0) end
ctx.text = mfunc(ctx.frame:newChild{
title = 'Module:' .. fname,
args = concat_params(ctx)
})
return false
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]|[...]
library.concat_and_magic = function (ctx)
-- NOTE: `ctx.params` might be the original metatable!
local opts = ctx.pipe
local magic
if opts[1] ~= nil then magic = opts[1]:match'^%s*(.*%S)' end
if magic == nil then error(modulename ..
', ‘concat_and_magic’: No parser function was provided', 0) end
remove_numeric_keys(opts, 1, 1)
ctx.text = ctx.frame:callParserFunction(magic, concat_params(ctx))
return false
end
 
 
-- Syntax:  #invoke:params|value_of|parameter name
library.value_of = function (ctx)
-- NOTE: `ctx.pipe` and `ctx.params` might be the original metatables!
local opts = ctx.pipe
local kstr
if opts[1] ~= nil then kstr = opts[1]:match'^%s*(.*%S)' end
if kstr == nil then error(modulename ..
', ‘value_of’: No parameter name was provided', 0) end
local knum = tonumber(kstr)
local len = #ctx.params  -- No worries: unused when in first position
local val = ctx.params[knum or kstr]
if val ~= nil and (
ctx.subset ~= -1 or knum == nil or knum > len or knum < 1
) and (
ctx.subset ~= 1 or (knum ~= nil and knum <= len and knum > 0)
) then
ctx.text = (ctx.header or '') .. val .. (ctx.footer or '')
return false
end
ctx.text = ctx.ifngiven or ''
return false
end
 
 
-- Syntax:  #invoke:params|list
library.list = function (ctx)
-- NOTE: `ctx.pipe` might be the original metatable!
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
ctx.text = table.concat(ret)
return false
end
ctx.text = ctx.ifngiven or ''
return false
end
 
 
-- Syntax:  #invoke:params|list_values
library.list_values = function (ctx)
-- NOTE: `ctx.pipe` might be the original metatable!
-- NOTE: `library.coins()` and `library.unique_coins()` rely on us
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
ctx.text = table.concat(ret)
return false
end
ctx.text = ctx.ifngiven or ''
return false
end
 
 
-- Syntax:  #invoke:params|coins|[first coin = value 1]|[second coin = value
--            2]|[...]|[last coin = value N]
library.coins = function (ctx)
-- NOTE: `ctx.pipe` might be the original metatable!
local opts = ctx.pipe
local tbl = ctx.params
for key, val in pairs(tbl) do tbl[key] = opts[tonumber(val) or val] end
return library.list_values(ctx)
end
 
 
-- Syntax:  #invoke:params|unique_coins|[first coin = value 1]|[second coin =
--            value 2]|[...]|[last coin = value N]
library.unique_coins = function (ctx)
local opts = ctx.pipe
local tbl = ctx.params
local tmp
for key, val in pairs(tbl) do
tmp = tonumber(val) or val
tbl[key] = opts[tmp]
opts[tmp] = nil
end
end
ctx.text = ctx.ifngiven or ''
return library.list_values(ctx)
return false
end
end


Line 1,498: Line 1,880:
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(ctx.luaname ..
if tname == nil then error(modulename ..
', ‘call_for_each’: No template name was provided', 0) end
', ‘call_for_each’: No template name was provided', 0) end
local model = { title = tname, args = opts }
local model = { title = tname, args = opts }
Line 1,537: Line 1,919:
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(ctx.luaname ..
if mname == nil then error(modulename ..
', ‘invoke_for_each’: No module name was provided', 0) end
', ‘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(ctx.luaname ..
if fname == nil then error(modulename ..
', ‘invoke_for_each’: No function name was provided', 0) end
', ‘invoke_for_each’: No function name was provided', 0) end
local model = { title = 'Module:' .. mname, args = opts }
local model = { title = 'Module:' .. mname, args = opts }
Line 1,578: Line 1,960:
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(ctx.luaname ..
if magic == nil then error(modulename ..
', ‘magic_for_each’: No parser function was provided', 0) end
', ‘magic_for_each’: No parser function was provided', 0) end
local ccs = ctx.itersep or ''
local ccs = ctx.itersep or ''
Line 1,616: Line 1,998:
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(ctx.luaname ..
if tname == nil then error(modulename ..
', ‘call_for_each_value’: No template name was provided', 0) end
', ‘call_for_each_value’: No template name was provided', 0) end
local model = { title = tname, args = opts }
local model = { title = tname, args = opts }
Line 1,653: Line 2,035:
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(ctx.luaname ..
if mname == nil then error(modulename ..
', ‘invoke_for_each_value’: No module name was provided', 0) end
', ‘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(ctx.luaname ..
if fname == nil then error(modulename ..
', ‘invoke_for_each_value’: No function name was provided', 0) end
', ‘invoke_for_each_value’: No function name was provided', 0) end
local model = { title = 'Module:' .. mname, args = opts }
local model = { title = 'Module:' .. mname, args = opts }
Line 1,663: Line 2,045:
local ret = {}
local ret = {}
local nss = 0
local nss = 0
remove_numerical_keys(opts, 1, 1)
remove_numeric_keys(opts, 1, 1)
flush_params(
flush_params(
ctx,
ctx,
Line 1,694: Line 2,076:
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(ctx.luaname ..
if magic == nil then error(modulename ..
', ‘magic_for_each_value’: No parser function was provided', 0) end
', ‘magic_for_each_value’: No parser function was provided', 0) end
local ccs = ctx.itersep or ''
local ccs = ctx.itersep or ''
Line 1,731: Line 2,113:
local tmp
local tmp
if opts[1] ~= nil then tmp = opts[1]:match'^%s*(.*%S)' end
if opts[1] ~= nil then tmp = opts[1]:match'^%s*(.*%S)' end
if tmp == nil then error(ctx.luaname ..
if tmp == nil then error(modulename ..
', ‘call_for_each_group’: No template name was provided', 0) end
', ‘call_for_each_group’: No template name was provided', 0) end
local model = { title = tmp }
local model = { title = tmp }
Line 1,782: Line 2,164:


-- Syntax:  #invoke:params|new|pipe to
-- Syntax:  #invoke:params|new|pipe to
--[[
static_iface.new = function (frame)
static_iface.new = function (frame)
local ctx = context_new()
local ctx = context_new(frame:getParent())
ctx.frame = frame:getParent()
ctx.pipe = copy_or_ref_table(frame.args, false)
ctx.pipe = copy_or_ref_table(frame.args, false)
ctx.params = {}
ctx.params = {}
Line 1,791: Line 2,171:
return ctx.text
return ctx.text
end
end
]]--




Line 1,810: Line 2,189:




return setmetatable(static_iface, {
return setmetatable({}, {
__index = function (iface, _fname_)
__index = function (_, query)
local ctx = context_new()
local fname = query:match'^%s*(.*%S)'
local fname = _fname_:match'^%s*(.*%S)'
if fname == nil then error(modulename ..
if fname == nil then error(ctx.luaname ..
': You must specify a function to call', 0) end
': You must specify a function to call', 0) end
if library[fname] == nil then error(ctx.luaname ..
local func = static_iface[fname]
if func ~= nil then return func end
func = library[fname]
if func == nil then error(modulename ..
': The function ‘' .. fname .. '’ does not exist', 0) end
': The function ‘' .. fname .. '’ does not exist', 0) end
local func = library[fname]
return function (frame)
return function (frame)
ctx.frame = frame:getParent()
local ctx = context_new(frame:getParent())
ctx.pipe = copy_or_ref_table(frame.args,
ctx.pipe = copy_or_ref_table(frame.args,
refpipe[fname])
refpipe[fname])
ctx.params = copy_or_ref_table(ctx.frame.args,
ctx.params = copy_or_ref_table(ctx.oparams,
refparams[fname])
refparams[fname])
main_loop(ctx, func)
main_loop(ctx, func)