Module:Params

From The Unofficial Isekai:Slow Life Wiki
Revision as of 19:25, 31 July 2025 by FaeriMagic (talk | contribs) (Imported from Wikipedia.)
(diff) ← Older revision | Latest revision (diff) | Newer revision → (diff)
Jump to navigation Jump to search

The <syntaxhighlight lang="wikitext" inline>Script error: You must specify a function to call.</syntaxhighlight> module is designed to be adopted by those templates that want to have a deep control of their parameters. It is particularly useful to variadic templates, to which it offers the possibility to count, list, map and propagate the parameters received without knowing their number in advance.

The module offers elegant shortcuts to non variadic templates as well. Outside templates it has virtually no applications; hence, if you plan to make experiments, make sure to do them from within a template, or you will not be able to see much (you can use {{Template sandbox}} for that). Under Template:Rel you can find helper templates that can be specifically used for testing the module's capabilities in flexible ways. Finally, under Template:Rel you can find some of the examples shown in this documentation page.

Template:A note In case your template uses <syntaxhighlight lang="wikitext" inline>Script error: You must specify a function to call.</syntaxhighlight>, please add Template:Tji to its documentation page, so that if breaking changes will be introduced in the future the template will be easily traceable without performing an “in source” search.

Please, do not edit this module without having done extensive testing in the module's sandbox first.

General usage

Among the possibilities that the module offers there is that of performing a series of actions after novel arguments have been concatenated to templates' incoming parameters. As this makes it necessary to keep the argument slots clean from interference, instead of named arguments in order to specify options this module uses piping functions (i.e. functions that expect to be piped instead of returning to the caller), or modifiers. This creates a syntax similar to the following example:

<syntaxhighlight lang="wikitext">Lua error: Module:Params: The function ‘[modifier]’ does not exist.</syntaxhighlight>

For instance, as the name suggests, the list function lists the parameters wherewith a template was called. By default it does not add delimiters, but returns an indistinct blob of text in which keys and values are sticked to each other. However, by using the setting modifier, we are able to declare a key-value delimiter (p) and an iteration delimiter (i). And so, if we imagined a template named <syntaxhighlight lang="wikitext" inline>Template:Example template</syntaxhighlight> containing the following wikitext,

<syntaxhighlight lang="wikitext"></syntaxhighlight>

and such template were called with the following parameters,

Template:Tj

the following result would be produced:

Beast of Bodmin: A large feline inhabiting Bodmin Moor
Morgawr: A sea serpent
Owlman: A giant owl-like creature

We can also do more sophisticated things; for instance, by exploiting the possibility to set a header (h) and a footer (f), we can transform the previous code into a generator of definition lists,

<syntaxhighlight lang="wikitext"></syntaxhighlight>

thus yielding:

Beast of Bodmin
A large feline inhabiting Bodmin Moor
Morgawr
A sea serpent
Owlman
A giant owl-like creature

By placing the with_name_matching modifier before the list function we will be able to filter some parameters out – such as, for instance, all parameter names that do not end with an “n”:

<syntaxhighlight lang="wikitext"></syntaxhighlight>

Thus, the previous code will produce:

Beast of Bodmin
A large feline inhabiting Bodmin Moor
Owlman
A giant owl-like creature

This mechanism has the intrinsic advantage that it allows concatenating infinite modifiers. And so, in order to get the accurate result that we want to obtain we could write:

<syntaxhighlight lang="wikitext"></syntaxhighlight>

The two modifiers sequential and non-sequential refer to a technical jargon used in wikitext: given a parameter list, the subgroup of sequential parameters is constituted by the largest group of consecutive numeric parameters starting from Template:Tjp – this is known as the parameters' “sequence”. A parameter list that does not have a first parameter specified does not possess a sequence.

Functions

Here follows the list of functions. You might want to see also § Modifiers.

Template:Vpad

self

Template:Infobox

Brief
Return the name of the current template
Syntax
<syntaxhighlight lang="wikitext" inline>Module:Params/doc</syntaxhighlight>

This argumentless function guarantees that the name of the template invoking this module is shown, regardless if this is transcluded or not.

As a possible example, if a Wikipedia page named Page X contained only a transclusion of a template named <syntaxhighlight lang="wikitext" inline>Template:Foobar</syntaxhighlight>, and the latter contained the following wikitext,

<syntaxhighlight lang="wikitext">Module:Params/doc

Module:Params</syntaxhighlight>

if we visited Template:Foobar we would see,

Template:Foobar

Template:Foobar

whereas if we visited Page X we would see:

Template:Foobar

Page X

Therefore by writing

<syntaxhighlight lang="wikitext">Page is being transcluded</syntaxhighlight>

it is possible to understand whether a page is being transcluded or not. For most cases the Template:Tag and Template:Tag will offer a simpler solution, however there can be cases in which this becomes the way to go.

If Page X transcluded <syntaxhighlight lang="wikitext" inline>Template:Foobar 2</syntaxhighlight> and the latter were a redirect to <syntaxhighlight lang="wikitext" inline>Template:Foobar</syntaxhighlight>, we would still see

Template:Foobar

Page X

A typical use case of this function is that of providing stable links for editing transcluded templates. E.g.:

<syntaxhighlight lang="wikitext">Template:Edit</syntaxhighlight>

Another possible use case is that of transcluding a subtemplate. E.g.:

<syntaxhighlight lang="wikitext">Module:Params/doc/my subtemplate</syntaxhighlight>

Template:Vpad

count

Template:Infobox

Brief
Count the number of parameters wherewith a template was called
Syntax
<syntaxhighlight lang="wikitext" inline>0</syntaxhighlight>

This function does not take arguments.

The number that this function yields depends on the modifiers that precede it. For instance, in a template that is called with both named and unnamed parameters,

<syntaxhighlight lang="wikitext" inline>0</syntaxhighlight>

and

<syntaxhighlight lang="wikitext" inline>0</syntaxhighlight>

will return different results.

Template:Vpad

concat_and_call

Template:Infobox

Brief
Prepend positive numeric arguments to the current parameters, or impose non-numeric or negative numeric arguments, then propagate everything to a custom template
Syntax
<syntaxhighlight lang="wikitext" inline>Lua error: expandTemplate: template "template name" does not exist.</syntaxhighlight>

This function comes in handy in case of wrapper templates. For example, if our <syntaxhighlight lang="wikitext" inline>Template:Wrapper template</syntaxhighlight> had the following code,

<syntaxhighlight lang="wikitext">Lua error: expandTemplate: template "foobar" does not exist.</syntaxhighlight>

and were called with,

Template:Tj

the following call to the <syntaxhighlight lang="wikitext" inline>Template:Foobar</syntaxhighlight> template would be performed:

Template:Tj

By using the cutting modifier it is possible to impose numeric positive parameters instead of prepending them. For instance, the following code echoes all incoming parameters to <syntaxhighlight lang="wikitext" inline>Template:My template</syntaxhighlight>, with the exception of Template:Para, which is replaced with hello world:

<syntaxhighlight lang="wikitext">Lua error: expandTemplate: template "my template" does not exist.</syntaxhighlight>

If the numeric parameters to replace are a limited number, as in the example above, a better alternative might be that of using imposing.

If no other argument besides the template name is provided this function simply echoes the current parameters to another template.

Template:Vpad

Template:A note All arguments passed to this function except the template name will not be trimmed of their leading and trailing spaces. The concat_and_call function name itself, however, will be trimmed of its surrounding spaces.

Template:Vpad

concat_and_invoke

Template:Infobox

Brief
Prepend positive numeric arguments to the current parameters, or impose non-numeric or negative numeric arguments, then propagate everything to a custom module
Syntax
<syntaxhighlight lang="wikitext" inline>Lua error in package.lua at line 80: module 'Module:module name' not found.</syntaxhighlight>

Exactly like concat_and_call, but invokes a module instead of calling a template.

Template:Vpad

Template:A note All arguments passed to this function except the module name and the function name will not be trimmed of their leading and trailing spaces. The concat_and_invoke function name itself, however, will be trimmed of its surrounding spaces.

Template:Vpad

concat_and_magic

Template:Infobox

Brief
Prepend positive numeric arguments to the current parameters, or impose non-numeric or negative numeric arguments, then propagate everything to a custom parser function
Syntax
<syntaxhighlight lang="wikitext" inline>Lua error: callParserFunction: function "parser function" was not found.</syntaxhighlight>

Exactly like concat_and_call, but calls a parser function instead of a template.

Template:Vpad

Template:A note All arguments passed to this function except the magic word will not be trimmed of their leading and trailing spaces. The concat_and_magic function name itself, however, will be trimmed of its surrounding spaces.

Template:Vpad

value_of

Template:Infobox

Brief
Get the value of a single parameter
Syntax
<syntaxhighlight lang="wikitext" inline></syntaxhighlight>

Without modifiers this function is similar to writing <syntaxhighlight lang="wikitext" inline></syntaxhighlight>. With modifiers, however, it allows reaching parameters that would be unreachable without knowing their number in advance. For instance, writing

<syntaxhighlight lang="wikitext"></syntaxhighlight>

will expand to the value of the second-last sequential parameter, independently of how many parameters the template was called with. If no matching parameter is found this function expands to nothing. A header (h), a footer (f), and a fallback text (n) can be declared via the setting modifier – the strings assigned to the key-value pair delimiter (p), the iteration delimiter (i) and the last iteration delimiter (l) will be ignored.

For instance, the {{If then show}} template could be rewritten as

<syntaxhighlight lang="wikitext"></syntaxhighlight>

Simplifying, the following wikitext expands to the first parameter that is not empty:

<syntaxhighlight lang="wikitext"></syntaxhighlight>

Whereas the following wikitext expands to the first parameter that is not blank (i.e. neither empty nor containing only whitespaces)

<syntaxhighlight lang="wikitext"></syntaxhighlight>

Template:Vpad

list

Template:Infobox

Brief
List the template parameters (both their names and their values)
Syntax
<syntaxhighlight lang="wikitext" inline></syntaxhighlight>

This function does not take arguments.

If the setting modifier was not placed earlier, this function will not add delimiters, but will return an indistinct blob of text in which keys and values are sticked to each other. A header (h), a key-value pair delimiter (p), an iteration delimiter (i), a last iteration delimiter (l), a footer (f), and a fallback text (n) can be declared via setting.

For example, the following code

<syntaxhighlight lang="wikitext">No parameters were passed</syntaxhighlight>

will generate an output similar to the following.

Parameters passed: Owlman (A giant owl-like creature); Beast of Bodmin (A large feline inhabiting Bodmin Moor); Morgawr (A sea serpent)

Template:Vpad

list_values

Template:Infobox

Brief
List the values of the incoming parameters
Syntax
<syntaxhighlight lang="wikitext" inline></syntaxhighlight>

This function does not take arguments.

The sequential modifier often accompanies this function. If the setting modifier was not placed earlier, this function will not add delimiters, but will return an indistinct blob of text in which values are sticked to each other. A header (h), an iteration delimiter (i), a last iteration delimiter (l), a footer (f), and a fallback text (n) can be declared via setting – the string assigned to the key-value pair delimiter (p) will be ignored.

For example, the following code

<syntaxhighlight lang="wikitext">No parameters were passed</syntaxhighlight>

will generate an output similar to the following.

Values of parameters passed: A giant owl-like creature; A large feline inhabiting Bodmin Moor; A sea serpent.

Template:Vpad

coins

Template:Infobox

Brief
Associate custom strings to possible parameter values and list the custom string when the associated value is present
Syntax
<syntaxhighlight lang="wikitext" inline></syntaxhighlight>

This function is identical to the unique_coins function, except that it allows the repetition of identical flags. See there for more information.

Template:Vpad

unique_coins

Template:Infobox

Brief
Associate custom strings to possible parameter values and list the custom string when the associated value is present, but not more than once
Syntax
<syntaxhighlight lang="wikitext" inline></syntaxhighlight>

This function is used to detect the existence of flag parameters. For this reason, it is often accompanied by the sequential modifier (or, equivalently, by ...|excluding_non-numeric_names|clearing|...). For a similar function that allows the repetition of identical flags, see the coins function.

A typical use case of this function is that of constructing URLs. For example, the following template named <syntaxhighlight lang="wikitext" inline>Template:Example template</syntaxhighlight> checks for the html, xml, comments and removenowiki flags in order to append respectively the following strings to the final URL: &wpGenerateRawHtml=1, &wpGenerateXml=1, &wpRemoveComments=0, &wpRemoveNowiki=1.

<syntaxhighlight lang="wikitext">Template:Error</syntaxhighlight>

And so, when transcluded as,

<syntaxhighlight lang="wikitext">Template:Example template</syntaxhighlight>

it will generate the following output:

Module:Params/doc/examples/link to expanded template

A copy of the example above is available at {{Template:Rel}}.

If the setting modifier was not placed earlier, this function will not add delimiters, but will return an indistinct blob of text in which values are sticked to each other. A header (h), an iteration delimiter (i), a last iteration delimiter (l), a footer (f), and a fallback text (n) can be declared via setting – the string assigned to the key-value pair delimiter (p) will be ignored.

Template:Vpad

call_for_each

Template:Infobox

Brief
For each parameter passed to the current template, call a custom template with at least two parameters (key and value)
Syntax
<syntaxhighlight lang="wikitext" inline></syntaxhighlight>

Some functions are like shortcuts. The X_for_each|F functions are similar to mapping_by_X(ing)|F|(names_and_values|)list_values. The latter syntax (i.e. the modifier version) allows a values_and_names flag to invert the order from key-value to value-key.

All unnamed arguments following the template name will be placed after the key-value pair. Named arguments will be passed verbatim. A header (h), an iteration delimiter (i), a last iteration delimiter (l), a footer (f), and a fallback text (n) can be declared via the setting modifier – the string assigned to the key-value pair delimiter (p) will be ignored.

Calling a template for each key-value pair with

<syntaxhighlight lang="wikitext"></syntaxhighlight>

will be different from writing

<syntaxhighlight lang="wikitext"></syntaxhighlight>

In the first example each key-value pair will be passed to the <syntaxhighlight lang="wikitext" inline>Template:Foobar</syntaxhighlight> template, while in the second example the $# and $@ tokens will be expanded after the <syntaxhighlight lang="wikitext" inline>Template:Foobar</syntaxhighlight> template has been called. In most cases this will make no difference, however there are several situations where it will lead to nonsensical results.

Template:Vpad

Template:A note All arguments passed to this function except the template name will not be trimmed of their leading and trailing spaces. The call_for_each function name itself, however, will be trimmed of its surrounding spaces.

Template:Vpad

invoke_for_each

Template:Infobox

Brief
For each parameter passed to the current template, invoke a custom module function with at least two arguments (key and value)
Syntax
<syntaxhighlight lang="wikitext" inline>Lua error in package.lua at line 80: module 'Module:module name' not found.</syntaxhighlight>

Exactly like call_for_each, but invokes a module instead of calling a template.

Invoking a module function for each key-value pair with

<syntaxhighlight lang="wikitext">Lua error in package.lua at line 80: module 'Module:foobar' not found.</syntaxhighlight>

will be different from writing

<syntaxhighlight lang="wikitext"></syntaxhighlight>

In the first example each key-value pair will be passed to the <syntaxhighlight lang="wikitext" inline>Script error: No such module "foobar".</syntaxhighlight> module function, while in the second example the $# and $@ tokens will be expanded after the module function has been invoked. There might be cases in which this will make no difference, however there are several situations where it will lead to nonsensical results.

Template:Vpad

Template:A note All arguments passed to this function except the module name and the function name will not be trimmed of their leading and trailing spaces. The invoke_for_each function name itself, however, will be trimmed of its surrounding spaces.

Template:Vpad

magic_for_each

Template:Infobox

Brief
For each parameter passed to the current template, call a magic word with at least two arguments (key and value)
Syntax
<syntaxhighlight lang="wikitext" inline></syntaxhighlight>

Exactly like call_for_each, but calls a parser function instead of a template.

Template:Vpad

Template:A note All arguments passed to this function except the magic word will not be trimmed of their leading and trailing spaces. The magic_for_each function name itself, however, will be trimmed of its surrounding spaces.

Template:Vpad

call_for_each_value

Template:Infobox

Brief
For each parameter passed to the current template, call a custom template with at least one parameter (i.e. the parameter's value)
Syntax
<syntaxhighlight lang="wikitext" inline></syntaxhighlight>

The sequential modifier often accompanies this function. All unnamed arguments following the template name will be appended after the value parameter. Named arguments will be passed verbatim. A header (h), an iteration delimiter (i), a last iteration delimiter (l), a footer (f), and a fallback text (n) can be declared via the setting modifier – the string assigned to the key-value pair delimiter (p) will be ignored.

For example, calling {{tl}} with each parameter can be done by writing

<syntaxhighlight lang="wikitext"></syntaxhighlight>

This will be different from writing

<syntaxhighlight lang="wikitext"></syntaxhighlight>

In the first example each value will be passed to the {{tl}} template, while in the second example the $@ token will be expanded after the {{tl}} template has been called. Here this will make no difference, however there are several situations where it will lead to nonsensical results.

Template:Vpad

Template:A note All arguments passed to this function except the template name will not be trimmed of their leading and trailing spaces. The call_for_each_value function name itself, however, will be trimmed of its surrounding spaces.

Template:Vpad

invoke_for_each_value

Template:Infobox

Brief
For each parameter passed to the current template, invoke a custom module function with at least one argument (i.e. the parameter's value)
Syntax
<syntaxhighlight lang="wikitext" inline>Lua error in package.lua at line 80: module 'Module:module name' not found.</syntaxhighlight>

Exactly like call_for_each_value, but invokes a module instead of calling a template.

Invoking a module function for each value with

<syntaxhighlight lang="wikitext">Lua error in package.lua at line 80: module 'Module:foobar' not found.</syntaxhighlight>

will be different from writing

<syntaxhighlight lang="wikitext"></syntaxhighlight>

In the first example each value will be passed to the Template:Ml module function, while in the second example the $@ token will be expanded after the module function has been invoked. There might be cases in which this will make no difference, however there are several situations where it will lead to nonsensical results.

Template:Vpad

Template:A note All arguments passed to this function except the module name and the function name will not be trimmed of their leading and trailing spaces. The invoke_for_each_value function name itself, however, will be trimmed of its surrounding spaces.

Template:Vpad

magic_for_each_value

Template:Infobox

Brief
For each parameter passed to the current template, call a magic word with at least one argument (i.e. the parameter's value)
Syntax
<syntaxhighlight lang="wikitext" inline></syntaxhighlight>

Exactly like call_for_each_value, but calls a parser function instead of a template.

For example, if a template had the following code,

<syntaxhighlight lang="wikitext"></syntaxhighlight>

and were transcluded as <syntaxhighlight lang="wikitext" inline>Template:Example template</syntaxhighlight>, the {{urlencode:...|QUERY}} parser function would be called for each incoming parameter as first argument and with QUERY as second argument, and finally the returned text would be prefixed with &preloadparams%5b%5d=. This would generate,

&preloadparams%5b%5d=hello+world&preloadparams%5b%5d=%C3%A0%C3%A8%C3%AC%C3%B2%C3%B9&preloadparams%5b%5d=foo+bar

which can be used to allow the creation of pages with preloaded text and parameters.

Template:Vpad

Template:A note All arguments passed to this function except the magic word will not be trimmed of their leading and trailing spaces. The magic_for_each_value function name itself, however, will be trimmed of its surrounding spaces.

Template:Vpad

call_for_each_group

Template:Infobox

Brief
Call a custom template for each group of parameters that have the same numeric suffix
Syntax
<syntaxhighlight lang="wikitext" inline></syntaxhighlight>

The custom template will be repeatedly called with the numeric id of the group (i.e. the numeric suffix) as parameter zero (i.e. Template:Param). This will be an empty string for the group of incoming parameters that do not have a numeric suffix. A hyphen before the numeric suffix will be interpreted as a minus sign (and therefore the group id will be treated as a negative number). Numeric incoming parameters will be treated as if their prefix is an empty string (these can be captured using {{{}}} or {{{|fallback text}}} in the callback template). Spaces between the prefix and the numeric suffix will be ignored (therefore writing Template:Para will be identical to writing Template:Para – in case of collisions one of the two values will be discarded). In the unlikely scenario that the prefix is itself a number (e.g. Template:Para, Template:Para, etc.), if this is 0 or a negative number it will be decreased by one unit in order to leave the parameter zero undisturbed (so 0 will become -1, -1 will become -2, and so on – if needed, you can use ...|purging|0|1|... in the callback template to renormalize these numbers).

All unnamed arguments that follow the template name in the invocation of this module will appear as sequential parameters in each call. Named arguments will be passed verbatim. Both named and unnamed arguments passed to this function will be given precedence in case of collisions. Numeric argument names below 1 will be decreased by one unit (i.e. ...|call_for_each_group|example template|0=Hello world|... will become Template:Para in the callback template – see above).

A header (h), an iteration delimiter (i), a last iteration delimiter (l), a footer (f), and a fallback text (n) can be declared via the setting modifier – the string assigned to the key-value pair delimiter (p) will be ignored.

If you are a module writer, you might recognize some distant similarities between this function and TableTools.affixNums.

For example, if a template named <syntaxhighlight lang="wikitext" inline>Template:Foobar</syntaxhighlight> contained the following code,

<syntaxhighlight lang="wikitext"></syntaxhighlight>

writing

<syntaxhighlight lang="wikitext">Template:Foobar</syntaxhighlight>

will be equivalent to writing

<syntaxhighlight lang="wikitext">Template:Example templateTemplate:Example templateTemplate:Example templateTemplate:Example template</syntaxhighlight>

The modifiers sequential, non-sequential, all_sorted and reassorted will affect what groups of parameters will be iterated, not what parameters will be grouped. Before calling this function you will likely want to reduce the list of parameters via one of the with_*_matching group of modifiers (for instance ...|with_name_matching|.%-%d+$|or|[^%-]%d+$|call_for_each_group|... leaves only the parameters in which both the prefix and the numeric suffix are not empty strings). The reassorted modifier often accompanies this function.

Template:Vpad

Template:Warnsign In writing templates, there is often the habit of signaling multilevel substitutions using the <syntaxhighlight lang="wikitext" inline>safesubst:</syntaxhighlight> notation. This is a dangerous practice, because <syntaxhighlight lang="wikitext" inline>safesubst:</syntaxhighlight> means “write the parameter with an empty name, otherwise write safesubst:”. Due to the fact that call_for_each_group can pass parameters with an empty name, a callback template should never use <syntaxhighlight lang="wikitext" inline>safesubst:</syntaxhighlight> to notate multilevel substitutions, but should use instead <syntaxhighlight lang="wikitext" inline>safesubst:</syntaxhighlight>. Not following this advice can lead to bugs that are hard to debug.

Template:Vpad

At {{Template:Rel}} you can find an example of how to use this function to list authors the same way {{Cite book}} does. For instance, writing

<syntaxhighlight lang="wikitext">Module:Params/doc/examples/list of authors</syntaxhighlight>

will generate

Module:Params/doc/examples/list of authors

See also {{Template:Rel}} for an example of how to exploit this function to create infoboxes, and {{Template:Rel}} for an example of how to exploit this function to create n-column tables.

Template:Vpad

Template:A note All arguments passed to this function except the template name will not be trimmed of their leading and trailing spaces. The call_for_each_group function name itself, however, will be trimmed of its surrounding spaces.

Template:Vpad

for_each

Template:Infobox

Brief
For each parameter passed to the current template, expand all occurrences of $# and $@ within a given text as key and value respectively
Syntax
<syntaxhighlight lang="wikitext" inline></syntaxhighlight>

Example:

<syntaxhighlight lang="wikitext"></syntaxhighlight>

The text returned by this function is not expanded further (currently this module does not offer an expand_for_each function). If you need wikitext expansion, use either concat_and_call to propagate the incoming parameters altogether to the {{for nowiki}} template, or mapping_by_calling to propagate the incoming parameters one by one to {{expand wikitext}}.

Example #1 (wikitext expanded via the {{for nowiki}} template – suggested):

<syntaxhighlight lang="wikitext">Lua error: expandTemplate: template "for nowiki" does not exist.</syntaxhighlight>

Example #2 (wikitext expanded via the {{expand wikitext}} template – less efficient but more flexible):

<syntaxhighlight lang="wikitext"></syntaxhighlight>

Template:Vpad

Template:A note The argument passed to this function will not be trimmed of its leading and trailing spaces. The for_each function name itself, however, will be trimmed of its surrounding spaces.

Template:Vpad

Modifiers (piping functions)

The following are modifiers, i.e. functions that expect to be piped instead of returning to the caller. Each of them can be followed by either another modifier or a non-piping function. The actions that modifiers do are done sequentially, in the same order chosen during the invocation of this module. Some modifiers, however, after signaling their presence to the modifiers that might follow, add their action to the queue of actions that will be done last (e.g. sequential, non-sequential, all_sorted, reassorted).

Template:Vpad

sequential

Template:Infobox

Brief
(IN FUNCTIONS ONLY, DOES NOT AFFECT MODIFIERS) Reduce the parameter list to the subgroup of consecutive parameters that follow Template:Tjp
Syntax
<syntaxhighlight lang="wikitext" inline>Lua error: Module:Params: The function ‘pipe function name’ does not exist.</syntaxhighlight>

Example:

<syntaxhighlight lang="wikitext">0</syntaxhighlight>

This modifier does not take arguments besides the name of the function that will follow.

Using sequential together with non-sequential will generate an error.

Template:Vpad

Template:A note Like non-sequential, the sequential modifier permanently marks a query. For instance, writing <syntaxhighlight lang="wikitext" inline>Lua error: Module:Params: The function ‘...’ does not exist.</syntaxhighlight> will first mark the query as “sequential”, then will discard the first element from the sequence (leaving all the others intact). And so, no matter how many other parameters will be present, nothing will be shown.

Template:Vpad

non-sequential

Template:Infobox

Brief
(IN FUNCTIONS ONLY, DOES NOT AFFECT MODIFIERS) Reduce the parameter list by discarding the subgroup of consecutive parameters that follow Template:Tjp
Syntax
<syntaxhighlight lang="wikitext" inline>Lua error: Module:Params: The function ‘pipe function name’ does not exist.</syntaxhighlight>

Example:

<syntaxhighlight lang="wikitext"></syntaxhighlight>

This modifier does not take arguments besides the name of the function that will follow.

Using non-sequential together with sequential will generate an error.

Template:Vpad

Template:A note Like sequential, the non-sequential modifier permanently marks a query, and no matter what transformations will follow (see squeezing) the parameters' “sequence” will not be shown.

Template:Vpad

all_sorted

Template:Infobox

Brief
(IN FUNCTIONS ONLY, DOES NOT AFFECT MODIFIERS) When the time will come, all parameters will be dispatched sorted: first the numeric ones in ascending order, then the rest in natural order
Syntax
<syntaxhighlight lang="wikitext" inline>Lua error: Module:Params: The function ‘pipe function name’ does not exist.</syntaxhighlight>

Template:A note This modifier sorts the way functions iterate across all parameters based on their names. If you want to sort sequential parameters based on their values, see sorting_sequential_values.

Example:

<syntaxhighlight lang="wikitext"></syntaxhighlight>

This modifier does not take arguments besides the name of the function that will follow.

Normally only sequential parameters are dispatched sorted, whereas non-sequential ones are dispatched randomly. The all_sorted modifier ensures that nothing is left out of (natural) order. Attention must be paid to the fact that parameters whose name is a negative number will appear first. To avoid this the squeezing modifier can be used.[1]

The all_sorted modifier only affects the way parameters are shown, but has no effects on functions that do not iterate or cannot impose an order, such as:

Template:Vpad

Template:A note The all_sorted modifier cannot be used with functions that propagate several parameters together in a single call, like concat_and_call, concat_and_invoke, and concat_and_magic, because during a call the order of arguments is always lost. For the same reason, it is not possible to guess the order of named parameters a template was transcluded with.

Template:Vpad

reassorted

Template:Infobox

Brief
(IN FUNCTIONS ONLY, DOES NOT AFFECT MODIFIERS) When the time will come, all parameters will be dispatched sorted: first non numeric ones in natural order, then the numeric ones in ascending order
Syntax
<syntaxhighlight lang="wikitext" inline>Lua error: Module:Params: The function ‘pipe function name’ does not exist.</syntaxhighlight>

This modifier is identical to all_sorted, but numbers are iterated last (as in “bar, foo, hello, zebra, 1, 2, 3, …”).

Template:Vpad

Template:A note The reassorted modifier cannot be used with functions that propagate several parameters together in a single call, like concat_and_call, concat_and_invoke, and concat_and_magic, because during a call the order of arguments is always lost. For the same reason, it is not possible to guess the order of named parameters a template was transcluded with.

Template:Vpad

setting

Template:Infobox

Brief
Define glue strings
Syntax
<syntaxhighlight lang="wikitext" inline>Lua error: Module:Params, ‘setting’: Unknown slot ‘d’.</syntaxhighlight>

This modifier allows some internal variables to be set and later be used by functions. It takes a variable number of arguments, relying on the first argument to understand how many other arguments to read. A few examples will introduce it better than words:

  • <syntaxhighlight lang="wikitext" inline></syntaxhighlight>
    ↳ Set the value of iteration delimiter to |, then list all values
  • <syntaxhighlight lang="wikitext" inline></syntaxhighlight>
    ↳ Set the value of both header text and iteration delimiter to |, then list all values
  • <syntaxhighlight lang="wikitext" inline></syntaxhighlight>
    ↳ Set the value of both header text and iteration delimiter to |, set key-value pair delimiter to =, then list all parameters
  • <syntaxhighlight lang="wikitext" inline>No parameters were passed</syntaxhighlight>
    ↳ Set the value of both header text and iteration delimiter to |, set key-value pair delimiter to =, set fallback text to No parameters were passed, then list all parameters

The first argument is a slash-separated list of lists of slots to assign; one slot is referred by exactly one character and each list of slots maps exactly one argument. A slot indicates which internal variable to set. If more than one slot is aggregated within the same slash-separated list the same text will be assigned to more than one variable.

The slots available are the following:

Slots Variable Description
p Key-value pair delimiter The string of text that will be placed between each parameter name and its value; it is never inserted by functions that only iterate between values, or by functions that pass the key-value pairs to external calls.
i Iteration delimiter The string of text that will be placed between each iteration; it is never inserted unless there are two or more parameters to show when l is not given, or three or more parameters when l is given.
l Last iteration delimiter The string of text that will be placed between the second last and the last iteration; it is never inserted unless there are two or more parameters to show; if omitted defaults to i.
h Header text The string of text that will be placed before the iteration begins; it is never inserted if there are no parameters to show.
f Footer text The string of text that will be placed after the iteration is over; it is never inserted if there are no parameters to show.
n Fallback text The string of text that will be placed if there are no parameters to show.

All space characters in the directives arguments are discarded. Therefore writing <syntaxhighlight lang="wikitext" inline>Lua error: Module:Params: You must specify a function to call.</syntaxhighlight> will be equivalent to writing

<syntaxhighlight lang="wikitext">Lua error: Module:Params: You must specify a function to call.</syntaxhighlight>

In theory, instead of assigning different slots at once (i.e. <syntaxhighlight lang="wikitext" inline>Template:...</syntaxhighlight>), it is possible to write separate invocations of setting for each variable, as in <syntaxhighlight lang="wikitext" inline>Template:...</syntaxhighlight>. This method however will be slightly less efficient.

Sometimes it might be necessary to make the values assigned depend on conditional expressions. For instance, the following imaginary <syntaxhighlight lang="wikitext" inline>Template:Foobar see also</syntaxhighlight> template uses the #ifexpr parser function to properly show the “and” conjunction and possibly an Oxford comma when more than two page names are provided:

<syntaxhighlight lang="wikitext">Template:Hatnote</syntaxhighlight>

You can find this example at {{Template:Rel}}. For instance, <syntaxhighlight lang="wikitext" inline>Module:Params/doc/examples/Oxford comma</syntaxhighlight> will generate

Module:Params/doc/examples/Oxford comma

Template:Vpad

Template:A note The setting modifier will be trimmed of its surrounding spaces. The directives argument will be stripped of all space characters, including internal spaces. All the other arguments passed to this modifier will be parsed verbatim (i.e. leading and trailing spaces will not be removed).

Template:Vpad

squeezing

Template:Infobox

Brief
Rearrange all parameters that have numeric names to form a compact sequence starting from 1, keeping the same order
Syntax
<syntaxhighlight lang="wikitext" inline>Lua error: Module:Params: The function ‘pipe function name’ does not exist.</syntaxhighlight>

Example:

<syntaxhighlight lang="wikitext"></syntaxhighlight>

This modifier does not take arguments besides the name of the function that will follow. If you are a module writer, you might recognize some similarities between this function and TableTools.compressSparseArray.

The following three concatenations will lead to the same result of discarding all parameters with numeric names:

  1. <syntaxhighlight lang="wikitext" inline>Template:...</syntaxhighlight>
  2. <syntaxhighlight lang="wikitext" inline>Template:...</syntaxhighlight>
  3. <syntaxhighlight lang="wikitext" inline>Template:...</syntaxhighlight>
  4. <syntaxhighlight lang="wikitext" inline>Template:...</syntaxhighlight>

The first solution is the most optimized one. Furthermore, in the last two solutions the numeric parameters are discarded just before the final function is invoked (sometimes this might be a wanted result).

Template:Vpad

filling_the_gaps

Template:Infobox

Brief
Assign an empty string to all undefined numeric parameters between 1 or a lower numeric parameter name provided and the maximum numeric parameter provided
Syntax
<syntaxhighlight lang="wikitext" inline>Lua error: Module:Params: The function ‘pipe function name’ does not exist.</syntaxhighlight>

Example:

<syntaxhighlight lang="wikitext"></syntaxhighlight>

This modifier does not take arguments besides the name of the function that will follow.

Note that when all numeric parameters are lower than 1, the gap between 1 and the maximum numeric parameter will not be filled. The following table provides some examples.

Numeric parameters provided
Before calling filling_the_gaps After calling filling_the_gaps
1 1
2 1, 2
6, 9 1, 2, 3, 4, 5, 6, 7, 8, 9
-5, -3 -5, -4, -3
-5, -3, 1 -5, -4, -3, -2, -1, 0, 1
-1 -1
-2 -2

Template:A note There is a safety limit of at most 1024 undefined parameters that can be filled using this modifier.

Template:Vpad

clearing

Template:Infobox

Brief
Remove all numeric parameters that are not in the sequence
Syntax
<syntaxhighlight lang="wikitext" inline>Lua error: Module:Params: The function ‘pipe function name’ does not exist.</syntaxhighlight>

This modifier does not take arguments besides the name of the function that will follow.

Unlike sequential – which affects only the way parameters are shown – this modifier actually removes all non-sequential numeric parameters, albeit leaves non-numeric parameters intact.

Example:

<syntaxhighlight lang="wikitext"></syntaxhighlight>

If you want to remove also non-numeric parameters, add the excluding_non-numeric_names modifier:

<syntaxhighlight lang="wikitext"></syntaxhighlight>

If you want instead to remove sequential parameters and leave the rest, use <syntaxhighlight lang="wikitext" inline>Template:...</syntaxhighlight>:

<syntaxhighlight lang="wikitext"></syntaxhighlight>

Template:Vpad

cutting

Template:Infobox

Brief
Remove zero or more parameters from the beginning and the end of the parameters' sequence
Syntax
<syntaxhighlight lang="wikitext" inline>Lua error: Module:Params, ‘cutting’: Left cut must be a number.</syntaxhighlight>

The first argument indicates how many sequential parameters must be removed from the beginning of the parameter sequence, the second argument indicates how many sequential parameters must be removed from the end of the parameter list. If any of the two arguments contains a negative number its absolute value indicates what must be left on the opposite side – i.e. <syntaxhighlight lang="wikitext" inline></syntaxhighlight> indicates that the last three arguments must not be discarded.

Example:

<syntaxhighlight lang="wikitext"></syntaxhighlight>

If the absolute value of the sum of the two arguments (left and right cut) is greater than the number of sequential parameters available, the behavior will be the same as if the sum had been equal to the number of sequential parameters available, both when this is a positive value and when it is a negative value (with opposite results). After the desired sequential parameters have been discarded, all numeric parameters will be shifted accordingly.

In some cases it might be necessary to concatenate more than one invocation of the cutting modifier. For instance, the following code prints the last unnamed parameter passed, but only if at least two parameters were passed:

<syntaxhighlight lang="wikitext"></syntaxhighlight>

Template:A note Although <syntaxhighlight lang="wikitext" inline>Lua error: Module:Params: The function ‘...’ does not exist.</syntaxhighlight> de facto gets rid of all sequential parameters, in most cases it is clearer and more idiomatic to write <syntaxhighlight lang="wikitext" inline>Lua error: Module:Params: The function ‘...’ does not exist.</syntaxhighlight> to obtain the same effect. The last method however cannot be used when it is important that sequential parameters are removed before a particular modifier is called, because non-sequential does not take effect until the final function is invoked. Writing instead <syntaxhighlight lang="wikitext" inline>Lua error: Module:Params: The function ‘...’ does not exist.</syntaxhighlight> will leave zero arguments to show.

Template:Vpad

cropping

Template:Infobox

Brief
Remove zero or more parameters from the beginning and the end of the list of numeric parameters (not only the sequential ones)
Syntax
<syntaxhighlight lang="wikitext" inline>Lua error: Module:Params, ‘cropping’: Left crop must be a number.</syntaxhighlight>

This modifier is very similar to cutting, but instead of removing arguments from the extremities of the parameters' sequence, arguments will be removed counting from the first and the last numeric arguments given (i.e. Template:Para and Template:Para in the case of <syntaxhighlight lang="wikitext" inline>Template:Foobar</syntaxhighlight>). If any of the two arguments contains a negative number its absolute value indicates what must be left on the opposite side.

Example:

<syntaxhighlight lang="wikitext"></syntaxhighlight>

For instance, when a template transcluded as <syntaxhighlight lang="wikitext" inline>Template:Example template</syntaxhighlight> uses the cutting modifier with 2 and 1 as arguments, as in the example above, the following parameters will be left:

-2: minus two
0: zero
16: nineteen
17: twenty]

If instead the template uses the cropping modifier with 2 and 1 as arguments, the following parameters will be left:

0: zero
1: one
2: two
3: three
19: nineteen

If the absolute value of the sum of the two arguments (left and right crop) is greater than the difference between the largest and the lowest numeric parameters available, the behavior will be the same as if the sum had been equal to the number of numeric parameters available, both when this is a positive value and when it is a negative value (with opposite results). When sequential parameters are present among the discarded parameters, all the remaining numeric parameters greater than zero will be shifted accordingly.

Template:Vpad

purging

Template:Infobox

Brief
Remove zero or more parameters from any point of the list of numeric parameters, shifting everything accordingly
Syntax
<syntaxhighlight lang="wikitext" inline>Lua error: Module:Params, ‘purging’: Start offset must be a number.</syntaxhighlight>

The first argument indicates at which point in the parameter list the removal must begin, the second argument indicates how many parameters must be discarded among it and what lies on the right side. If the second argument contains zero or a negative number its absolute value indicates what must be left at the end of the right side of the list of numeric parameters – i.e. <syntaxhighlight lang="wikitext" inline></syntaxhighlight> indicates that every numeric argument whose numeric name is greater than 4 must be removed.

Example #1 (purge the first parameter):

<syntaxhighlight lang="wikitext"></syntaxhighlight>

Example #2 (purge the second, third, and four parameters):

<syntaxhighlight lang="wikitext"></syntaxhighlight>

Template:Vpad

backpurging

Template:Infobox

Brief
Remove zero or more parameters from any point of the list of numeric parameters, moving backwards and shifting everything accordingly
Syntax
<syntaxhighlight lang="wikitext" inline>Lua error: Module:Params, ‘backpurging’: Start offset must be a number.</syntaxhighlight>

The first argument indicates at which point in the parameter list the removal must begin, the second argument indicates how many parameters must be discarded among it and what lies on the left side. If the second argument contains zero or a negative number its absolute value indicates what must be left at the end of the left side of the list of numeric parameters – i.e. <syntaxhighlight lang="wikitext" inline></syntaxhighlight> indicates that every numeric argument whose numeric name is less than 6 must be removed.

Example:

<syntaxhighlight lang="wikitext"></syntaxhighlight>

The following code removes all parameters with negative and zero numeric names, then lists the rest:

<syntaxhighlight lang="wikitext"></syntaxhighlight>

Template:Vpad

reversing_numeric_names

Template:Infobox

Brief
Reverse the order of all numeric parameters (not only sequential ones), making sure that the largest numeric parameter and Template:Para are swapped
Syntax
<syntaxhighlight lang="wikitext" inline>Lua error: Module:Params: The function ‘pipe function name’ does not exist.</syntaxhighlight>

This modifier does not take arguments besides the name of the function that will follow.

Example:

<syntaxhighlight lang="wikitext"></syntaxhighlight>

Template:A note If negative parameters are present this function becomes non-invertible. This means that <syntaxhighlight lang="wikitext" inline>Lua error: Module:Params: The function ‘...’ does not exist.</syntaxhighlight> will not restore the original parameter names, but will shift all numeric parameters so that what formerly was the smallest parameter name will now become Template:Para. Template:Vpad

sorting_sequential_values

Template:Infobox

Brief
Sort the order of sequential values
Syntax
<syntaxhighlight lang="wikitext" inline>Lua error: Module:Params: The function ‘[criterion]’ does not exist.</syntaxhighlight>

Template:A note This modifier sorts sequential parameters based on their values. If you want to sort the way functions iterate across all parameters based on their names, see all_sorted.

This modifier optionally supports one argument to specify the sorting criterion. If this is omitted it is assumed that sequential values must be ordered alphabetically. Currently the only other possible criterion is naturally, for ordering sequential values in natural sort order.

Example (alphabetical sort order):

<syntaxhighlight lang="wikitext"></syntaxhighlight>

Example (natural sort order):

<syntaxhighlight lang="wikitext"></syntaxhighlight> Template:Vpad

imposing

Template:Infobox

Brief
Impose a new value to a parameter
Syntax
<syntaxhighlight lang="wikitext" inline>Lua error: Module:Params: The function ‘pipe function name’ does not exist.</syntaxhighlight>

Example:

<syntaxhighlight lang="wikitext">[hello: world][foo: bar]</syntaxhighlight>

Template:Vpad

Template:A note The value assigned will not be trimmed of its leading and trailing spaces. The name of the parameter and the imposing modifier name itself, however, will be trimmed of their surrounding spaces.

Template:Vpad

providing

Template:Infobox

Brief
Assign a new value to a parameter, but only when missing
Syntax
<syntaxhighlight lang="wikitext" inline>Lua error: Module:Params: The function ‘pipe function name’ does not exist.</syntaxhighlight>

Example:

<syntaxhighlight lang="wikitext">[hello: world][foo: bar]</syntaxhighlight>

Template:Vpad

Template:A note The value assigned will not be trimmed of its leading and trailing spaces. The name of the parameter and the providing modifier name itself, however, will be trimmed of their surrounding spaces.

Template:Vpad

discarding

Template:Infobox

Brief
Discard one or more numeric parameters or one non-numeric parameter
Syntax
<syntaxhighlight lang="wikitext" inline>Lua error: Module:Params: The function ‘[how many]’ does not exist.</syntaxhighlight>

If, and only if, the name of the parameter is numeric, it is possible to add a second argument to indicate how many contiguous parameters must be discarded starting from the first argument. If the discarded parameters is part of the parameters' sequence one or more holes will be created. To avoid creating holes, use purging or backpurging.

Example #1 (discard the parameter named Template:Para):

<syntaxhighlight lang="wikitext"></syntaxhighlight>

Example #2 (discard the parameter named Template:Para):

<syntaxhighlight lang="wikitext"></syntaxhighlight>

Example #3 (discard the parameters named Template:Para, Template:Para, Template:Para and Template:Para):

<syntaxhighlight lang="wikitext"></syntaxhighlight>

It is possible to use this modifier to check for unknown parameters:

<syntaxhighlight lang="wikitext">Everything is good: do something</syntaxhighlight>

You can find this example at {{Template:Rel}}. For instance, <syntaxhighlight lang="wikitext" inline>Module:Params/doc/examples/check for unknown parameters</syntaxhighlight> will generate

Module:Params/doc/examples/check for unknown parameters

For simple cases like this, however, specialized modules are available; you might want to have a look at:

When used to discard single parameters, this modifier is equivalent to writing ...|with_name_not_matching|parameter name|strict|.... However, due to the fact that with_name_not_matching needs to cross-check for the possible presence of or keywords, using discarding will be slightly more efficient.

Template:A note All arguments passed to this modifier and the discarding modifier name itself will be trimmed of their surrounding spaces.

Template:Vpad

excluding_non-numeric_names

Template:Infobox

Brief
Discard all non-numeric parameters
Syntax
<syntaxhighlight lang="wikitext" inline>Lua error: Module:Params: The function ‘pipe function name’ does not exist.</syntaxhighlight>

This modifier is only syntax sugar for ...|with_name_matching|^%-?%d+$|... (but using a slighly faster optimization). For the inverse modifier, see excluding_numeric_names. If you want to remove also non-sequential parameters, add the clearing modifier to the pipeline (...|excluding_non-numeric_names|clearing|...).

Template:Vpad

excluding_numeric_names

Template:Infobox

Brief
Discard all numeric parameters (not only the sequential ones)
Syntax
<syntaxhighlight lang="wikitext" inline>Lua error: Module:Params: The function ‘pipe function name’ does not exist.</syntaxhighlight>

This modifier is only syntax sugar for ...|with_name_not_matching|^%-?%d+$|... (but using a slighly faster optimization). For the inverse modifier, see excluding_non-numeric_names.

Template:Vpad

with_name_matching

Template:Infobox

Brief
Discard all parameters whose name does not match any of the given patterns
Syntax
<syntaxhighlight lang="wikitext" inline>Lua error: Module:Params: The function ‘[plain flag 1]’ does not exist.</syntaxhighlight>

Internally this modifier uses Lua's string.find() function to find whether parameter names match against given patterns; therefore, unless a plain flag is set, please use the same syntax of Lua patterns. The plain flag can be either plain or strict or omitted. When omitted it is assumed that the target string is a Lua pattern. The difference between plain and strict is that the latter also requires that the lengths match (this happens only when the two strings are 100% identical). In order to facilitate wikitext scripting in the plain flag argument, the pattern keyword is available too, equivalent to omitting the argument.

To express a logical OR the or keyword is available. To express a logical AND instead, concatenate more invocations of with_name_matching.

Template:Vpad

For the sake of argument we will imagine that we are invoking with_name_matching from within the {{Infobox artery}} template, and this is being called with the following parameters:

Template:Tj

Template:Vpad

Test cases:

  • List only the parameters whose names match against the ^Image pattern:
    ↳ <syntaxhighlight lang="wikitext" inline></syntaxhighlight>
    Template:Highlight round
  • List the parameters whose names match against both patterns ^Image and %d+$:
    ↳ <syntaxhighlight lang="wikitext" inline></syntaxhighlight>
    Template:Highlight round
  • List the parameters whose names match against either the ^Name or the ^Latin$ pattern:
    ↳ <syntaxhighlight lang="wikitext" inline></syntaxhighlight>
    Template:Highlight round
  • List the parameters whose names match against either the ma plain string or the me$ pattern:
    ↳ <syntaxhighlight lang="wikitext" inline></syntaxhighlight>
    Template:Highlight round

Template:Vpad

Using with_name_matching it is easy to emulate the behaviour of Module:Enumerate (or similar modules). For instance, the following examples creates a bullet list of all the parameters passed of type |foobar1, |foobar2|foobarN:

<syntaxhighlight lang="wikitext"></syntaxhighlight>

It is possible to see this example live at {{Template:Rel}}.

Template:Vpad

Template:A note The target arguments passed to this modifier will not be trimmed of their leading and trailing spaces. The or, plain, strict and pattern keywords, and the with_name_matching modifier name itself, however, will be trimmed of their surrounding spaces.

Template:Vpad

with_name_not_matching

Template:Infobox

Brief
Discard all parameters whose name matches all the given patterns
Syntax
<syntaxhighlight lang="wikitext" inline>Lua error: Module:Params: The function ‘[plain flag 1]’ does not exist.</syntaxhighlight>

Internally this modifier uses Lua's string.find() function to find whether parameter names match against given patterns; therefore, unless a plain flag is set, please use the same syntax of Lua patterns. The plain flag can be either plain or strict or omitted. When omitted it is assumed that the target string is a Lua pattern. The difference between plain and strict is that the latter also requires that the lengths match (this happens only when the two strings are 100% identical). In order to facilitate wikitext scripting in the plain flag argument, the pattern keyword is available too, equivalent to omitting the argument.

To express a logical OR the or keyword is available. To express a logical AND instead, concatenate more invocations of with_name_not_matching.

Template:Vpad

For the sake of argument we will imagine that we are invoking with_name_not_matching from within the {{Infobox artery}} template, and this is being transcluded using the same parameters that we had imagined in the previous example at with_name_matching:

  • List only the parameters whose names do not match against the a pattern:
    <syntaxhighlight lang="wikitext" inline></syntaxhighlight>
    Template:Highlight round
  • List the parameters whose names do not match against the a plain string and do not match against the l plain string either:
    <syntaxhighlight lang="wikitext" inline></syntaxhighlight>
    Template:Highlight round
  • List the parameters whose names do not match against either the a plain string or the n plain string:
    <syntaxhighlight lang="wikitext" inline></syntaxhighlight>
    Template:Highlight round

Template:Vpad

Template:N.b. For the sake of efficiency, please don't use this modifier with the strict flag unless accompanied by or, use discarding instead!

Template:A note The target arguments passed to this modifier will not be trimmed of their leading and trailing spaces. The or, plain, strict and pattern keywords, and the with_name_not_matching modifier name itself, however, will be trimmed of their surrounding spaces.

Template:Vpad

with_value_matching

Template:Infobox

Brief
Discard all parameters whose value does not match any of the given patterns
Syntax
<syntaxhighlight lang="wikitext" inline>Lua error: Module:Params: The function ‘[plain flag 1]’ does not exist.</syntaxhighlight>

Exactly like with_name_matching, but applied to parameter values instead of names.

Internally this modifier uses Lua's string.find() function to find whether parameter names match against given patterns; therefore, unless a plain flag is set, please use the same syntax of Lua patterns. The plain flag can be either plain or strict or omitted. When omitted it is assumed that the target string is a Lua pattern. The difference between plain and strict is that the latter also requires that the lengths match (this happens only when the two strings are 100% identical). In order to facilitate wikitext scripting in the plain flag argument, the pattern keyword is available too, equivalent to omitting the argument.

Example:

<syntaxhighlight lang="wikitext">0</syntaxhighlight>

Template:Vpad

Template:A note The target arguments passed to this modifier will not be trimmed of their leading and trailing spaces. The or, plain, strict and pattern keywords, and the with_value_matching modifier name itself, however, will be trimmed of their surrounding spaces.

Template:Vpad

with_value_not_matching

Template:Infobox

Brief
Discard all parameters whose value matches all the given patterns
Syntax
<syntaxhighlight lang="wikitext" inline>Lua error: Module:Params: The function ‘[plain flag 1]’ does not exist.</syntaxhighlight>

Exactly like with_name_not_matching, but applied to parameter values instead of names.

Internally this modifier uses Lua's string.find() function to find whether parameter names match against given patterns; therefore, unless a plain flag is set, please use the same syntax of Lua patterns. The plain flag can be either plain or strict or omitted. When omitted it is assumed that the target string is a Lua pattern. The difference between plain and strict is that the latter also requires that the lengths match (this happens only when the two strings are 100% identical). In order to facilitate wikitext scripting in the plain flag argument, the pattern keyword is available too, equivalent to omitting the argument.

For instance, before calling list, the following code will get rid of all blank parameters (i.e. parameters whose values contain only zero or more spaces):

<syntaxhighlight lang="wikitext"></syntaxhighlight>

A typical use case of this modifier is that of purging all empty incoming parameters before calling another template, especially when this distinguishes between empty and undefined parameters.

<syntaxhighlight lang="wikitext">Lua error: expandTemplate: template "my template" does not exist.</syntaxhighlight>

Template:Vpad

Template:A note The target arguments passed to this modifier will not be trimmed of their leading and trailing spaces. The or, plain, strict and pattern keywords, and the with_value_not_matching modifier name itself, however, will be trimmed of their surrounding spaces.

Template:Vpad

trimming_values

Template:Infobox

Brief
Remove leading and trailing spaces from values
Syntax
<syntaxhighlight lang="wikitext" inline>Lua error: Module:Params: The function ‘pipe function name’ does not exist.</syntaxhighlight>

This modifier does not take arguments besides the name of the function that will follow.

Most modifiers are order-dependent, therefore placing trimming_values in different positions can generate different results. For instance, imagining our <syntaxhighlight lang="wikitext" inline>Template:Example template</syntaxhighlight> being called with the following spaced arguments: <syntaxhighlight lang="wikitext" inline>Template:Example template</syntaxhighlight>. If <syntaxhighlight lang="wikitext" inline>Template:Example template</syntaxhighlight> contained the following code,

<syntaxhighlight lang="wikitext"></syntaxhighlight>

the following text would be printed: 1=wanna|2=be|3=my|4=friend|5=?. But if instead it contained the following code,

<syntaxhighlight lang="wikitext"></syntaxhighlight>

no arguments would be shown.

Order affects also performance, and how many values will be trimmed of their leading and trailing spaces will depend on where trimming_values is placed. For instance, if a template were invoked with 50 parameters and its code contained <syntaxhighlight lang="wikitext" inline></syntaxhighlight>, first all its values would be trimmed of leading and trailing blank spaces and then its first 49 parameters would be discarded. On the other hand, writing <syntaxhighlight lang="wikitext" inline></syntaxhighlight> would first discard 49 parameters and then trim the only value left, resulting in a more efficient code. As a general rule, placing trimming_values as the last modifier is usually the best choice.

In most cases placing trimming_values together with non-sequential will result in an empty call with no effects, because non-sequential parameters are normally stripped of their leading and trailing spaces by default – this however depends on the caller, and if the current template is being called by a module it is in theory possible in specific conditions for named parameters to retain their leading and trailing spaces (namely in non-sequential numeric parameters).

Using trimming_values makes this module behave like many Wikipedia modules behave. For example, if we wanted to emulate Template:Ml, writing

<syntaxhighlight lang="wikitext"></syntaxhighlight>

will be equivalent to writing,

<syntaxhighlight lang="wikitext">Script error: No such module "separated entries".</syntaxhighlight>

whereas writing

<syntaxhighlight lang="wikitext"></syntaxhighlight>

will be equivalent to writing

<syntaxhighlight lang="wikitext">Script error: No such module "separated entries".</syntaxhighlight>

The {{Template:Rel}} example template shows how to call any arbitrary template trimming all parameters beforehand.

Template:Vpad

converting_values_to_lowercase

Template:Infobox

Brief
Convert all parameter values to lower case
Syntax
<syntaxhighlight lang="wikitext" inline>Lua error: Module:Params: The function ‘pipe function name’ does not exist.</syntaxhighlight>

This modifier does not take arguments besides the name of the function that will follow.

This modifier converts all parameter values to lower case. It is identical to writing ...|mapping_by_magic|lc|..., but without the burden of calling a parser function.

Template:Vpad

converting_values_to_uppercase

Template:Infobox

Brief
Convert all parameter values to upper case
Syntax
<syntaxhighlight lang="wikitext" inline>Lua error: Module:Params: The function ‘pipe function name’ does not exist.</syntaxhighlight>

This modifier does not take arguments besides the name of the function that will follow.

This modifier converts all parameter values to upper case. It is identical to writing ...|mapping_by_magic|uc|..., but without the burden of calling a parser function.

Template:Vpad

mapping_by_calling

Template:Infobox

Brief
Map all parameter values, replacing their content with the expansion of a given template repeatedly called with one parameter (the parameter's value)
Syntax
<syntaxhighlight lang="wikitext" inline>Lua error: Module:Params: The function ‘[call style]’ does not exist.</syntaxhighlight>

This modifier (temporarily) changes the content of the parameters the current template is being called with, replacing each of them with the text returned by another template. The latter will be repeatedly called with at least one parameter as first sequential parameter: the parameter's value.

It is possible to pass the parameter's value as a different parameter, or pass the parameter's name as well, by specifying a call style flag immediately after the template name (see below).

If the call style flag or (if omitted) the template name is followed by one or more groups of three arguments led by the let keyword (i.e. let|name|value), these will be passed to the mapping template.

If the last group of three arguments or (if omitted) the call style flag or (if omitted) the template name is followed by a number, this will be parsed as the amount of positional parameters to add. These will always follow the current parameter's name and/or value if any of the latter are passed using a numeric name greater than zero.

In case of collisions, the parameters assigned via the let keyword will be given precedence over everything else.

For instance, before listing all parameters,

<syntaxhighlight lang="wikitext"></syntaxhighlight>

will replace each value with the expansion of <syntaxhighlight lang="wikitext" inline>Template:Foobar</syntaxhighlight> (where VALUE indicates each different value).

On the other hand,

<syntaxhighlight lang="wikitext"></syntaxhighlight>

will do the same, but using the expansion of <syntaxhighlight lang="wikitext" inline>Template:Foobar</syntaxhighlight> (where NAME and VALUE indicate each different name and value).

Possible call style flags are:

Call style flag Example Corresponding call
names_and_values <syntaxhighlight lang="wikitext" inline></syntaxhighlight> <syntaxhighlight lang="wikitext" inline>Template:Example template</syntaxhighlight>
values_and_names <syntaxhighlight lang="wikitext" inline></syntaxhighlight> <syntaxhighlight lang="wikitext" inline>Template:Example template</syntaxhighlight>
names_only <syntaxhighlight lang="wikitext" inline></syntaxhighlight> <syntaxhighlight lang="wikitext" inline>Template:Example template</syntaxhighlight>
values_only <syntaxhighlight lang="wikitext" inline></syntaxhighlight> <syntaxhighlight lang="wikitext" inline>Template:Example template</syntaxhighlight>
names_and_values_as|...|... <syntaxhighlight lang="wikitext" inline></syntaxhighlight> <syntaxhighlight lang="wikitext" inline>Template:Example template</syntaxhighlight>
names_only_as|... <syntaxhighlight lang="wikitext" inline></syntaxhighlight> <syntaxhighlight lang="wikitext" inline>Template:Example template</syntaxhighlight>
values_only_as|... <syntaxhighlight lang="wikitext" inline></syntaxhighlight> <syntaxhighlight lang="wikitext" inline>Template:Example template</syntaxhighlight>
blindly <syntaxhighlight lang="wikitext" inline></syntaxhighlight> <syntaxhighlight lang="wikitext" inline>Template:Example template</syntaxhighlight>

If the call style flags argument is omitted it defaults to values_only.

Template:Vpad

Template:A note All arguments passed to this modifier except the mapping_by_calling modifier name itself, the template name, the call style flag, the let keyword, the passed parameter names, and the number of additional parameters will not be trimmed of their leading and trailing spaces.

Template:Vpad

mapping_by_invoking

Template:Infobox

Brief
Map all parameter values, replacing their content with the text returned by a given module function repeatedly invoked with at least one argument (the parameter's value)
Syntax
<syntaxhighlight lang="wikitext" inline>Lua error in package.lua at line 80: module 'Module:module name' not found.</syntaxhighlight>

This modifier (temporarily) changes the content of the parameters the current template is being called with, replacing each of them with the text returned by a custom module function. The latter will be repeatedly called with at least one argument as first sequential argument: the parameter's value.

It is possible to pass the parameter's value as a different argument, or pass the parameter's name as well, by specifying a call style flag immediately after the function name (see mapping_by_calling for the list of possible flags). If omitted, the call style flags argument defaults to values_only.

If the call style flag or (if omitted) the function name is followed by one or more groups of three arguments led by the let keyword (i.e. let|name|value), these will be passed to the mapping module function.

If the last group of three arguments or (if omitted) the call style flag or (if omitted) the function name is followed by a number, this will be parsed as the amount of positional parameters to add. These will always follow the current parameter's name and/or value if any of the latter are passed using a numeric name greater than zero.

In case of collisions, the arguments assigned via the let keyword will be given precedence over everything else.

For instance, before listing all parameters,

<syntaxhighlight lang="wikitext">Lua error in package.lua at line 80: module 'Module:foobar' not found.</syntaxhighlight>

will replace each value with the expansion of <syntaxhighlight lang="wikitext" inline>Script error: No such module "foobar".</syntaxhighlight> (where VALUE indicates each different value).

On the other hand,

<syntaxhighlight lang="wikitext">Lua error in package.lua at line 80: module 'Module:foobar' not found.</syntaxhighlight>

will do the same, but using the expansion of <syntaxhighlight lang="wikitext" inline>Script error: No such module "foobar".</syntaxhighlight> (where NAME and VALUE indicate each different name and value).

Template:Vpad

Template:A note All arguments passed to this modifier except the mapping_by_invoking modifier name itself, the module name, the function name, the call style flag, the let keyword, the passed parameter names, and the number of additional arguments will not be trimmed of their leading and trailing spaces.

Template:Vpad

mapping_by_magic

Template:Infobox

Brief
Map all parameter values, replacing their content with the expansion of a given parser function repeatedly called with at least one argument (the parameter's value)
Syntax
<syntaxhighlight lang="wikitext" inline>Lua error: Module:Params: The function ‘[call style]’ does not exist.</syntaxhighlight>

This modifier (temporarily) changes the content of the parameters the current template is being called with, replacing each of them with the text returned by a parser function. The latter will be repeatedly called with at least one argument as first sequential argument: the parameter's value.

It is possible to pass the parameter's value as a different argument, or pass the parameter's name as well, by specifying a call style flag immediately after the parser function name (see mapping_by_calling for the list of possible flags). If omitted, the call style flags argument defaults to values_only.

If the call style flag or (if omitted) the template name is followed by one or more groups of three arguments led by the let keyword (i.e. let|name|value), these will be passed to the parser function.

If the last group of three arguments or (if omitted) the call style flag or (if omitted) the template name is followed by a number, this will be parsed as the amount of positional arguments to add. These will always follow the current parameter's name and/or value if any of the latter are passed using a numeric name greater than zero.

In case of collisions, the arguments assigned via the let keyword will be given precedence over everything else.

For instance, before listing all parameters,

<syntaxhighlight lang="wikitext"></syntaxhighlight>

will replace each value with the expansion of <syntaxhighlight lang="wikitext" inline>VALUE</syntaxhighlight> (where VALUE indicates each different value).

On the other hand,

<syntaxhighlight lang="wikitext"></syntaxhighlight>

will do the same, but using the expansion of <syntaxhighlight lang="wikitext" inline>They are many</syntaxhighlight> (where NAME and VALUE indicate each different name and value).

Template:Vpad

Template:A note All arguments passed to this modifier except the mapping_by_magic modifier name itself, the parser function's name, the call style flag, the let keyword, the passed parameter names, and the number of additional arguments will not be trimmed of their leading and trailing spaces.

Template:Vpad

mapping_by_replacing

Template:Infobox

Brief
Map all parameter values performing string substitutions
Syntax
<syntaxhighlight lang="wikitext" inline>Lua error: Module:Params: The function ‘[count]’ does not exist.</syntaxhighlight>

This modifier (temporarily) changes the content of the parameters the current template is being called with, replacing each of them with the result of a string substitution. Its syntax is very simlar to Template:Mfl.

Internally the modifier uses Lua's string.gsub() function to perform substitutions; therefore, unless a plain flag is set, please use the same syntax of Lua patterns. The plain flag can be either plain or strict or omitted. When omitted it is assumed that the target string is a Lua pattern. The difference between plain and strict is that the latter also requires that the lengths match (this happens only when the two strings are 100% identical). In strict mode the replace argument will not accept directives (e.g. %0, %1, etc.). In order to facilitate wikitext scripting in the plain flag argument, the pattern keyword is available too, equivalent to omitting the argument.

The count argument prescribes how many substitutions will be performed at most. If blank or omitted, all matches found will be substituted.

This modifier uses string.gsub() for performance reasons; if you need to use mw.ustring.gsub() instead, you will need to invoke the replace function from Module:String via ...|mapping_by_invoking|string|replace|....

The following table shows examples of equivalent instructions. Please be aware that invoking mw.ustring.gsub() can be much slower.

string.gsub() mw.ustring.gsub() (via Module:String)
...|mapping_by_replacing|target|replace|... ...|mapping_by_invoking|string|replace|4|target|replace||false|...
...|mapping_by_replacing|target|replace|count|... ...|mapping_by_invoking|string|replace|4|target|replace|count|false|...
...|mapping_by_replacing|target|replace|plain|... ...|mapping_by_invoking|string|replace|2|target|replace|...
or, equivalently,
...|mapping_by_invoking|string|replace|4|target|replace||true|...
...|mapping_by_replacing|target|replace|count|plain|... ...|mapping_by_invoking|string|replace|3|target|replace|count|...
or, equivalently,
...|mapping_by_invoking|string|replace|4|target|replace|count|true|...

There is not a corresponding translation for the strict flag in Module:String. However, as it goes with the plain flag, in that case you won't need mw.ustring.gsub() in the first place.

For example,

<syntaxhighlight lang="wikitext">...|mapping_by_renaming|foo|bar|1|...</syntaxhighlight>

will be equivalent to writing

<syntaxhighlight lang="wikitext">...|mapping_by_invoking|string|replace|4|foo|bar|1|false|...</syntaxhighlight>

The first syntax, however, will be less computationally expensive.

At {{Template:Rel}} you can find an example on how to exploit this function to create “informal” infoboxes.

Template:Vpad

Template:A note The target and replace arguments passed to this modifier will not be trimmed of their leading and trailing spaces. The or, plain, strict and pattern keywords, the count argument, and the mapping_by_replacing modifier name itself, however, will be trimmed of their surrounding spaces.

Template:Vpad

mapping_by_mixing

Template:Infobox

Brief
Map all parameter values replacing their current values with the expansion of a custom string containing the $# and $@ placeholders
Syntax
<syntaxhighlight lang="wikitext" inline>Lua error: Module:Params: The function ‘pipe function name’ does not exist.</syntaxhighlight>

This modifier (temporarily) changes the content of the parameters the current template is being called with, replacing each of them with the expansion of a custom string that expects the same syntax as the for_each function.

For instance, the following code will wrap all parameter values in quotes

<syntaxhighlight lang="wikitext">...|mapping_by_mixing|“$@”|...</syntaxhighlight>

whereas the following code will replace all values with the string [NAME::VALUE], where NAME and VALUE are each parameter's name and value:

<syntaxhighlight lang="wikitext">...|mapping_by_mixing|[$#::$@]|...</syntaxhighlight> Template:Vpad

Template:A note Both the mixing string argument and the mapping_by_mixing modifier name itself will be trimmed of their surrounding spaces.

Template:Vpad

converting_names_to_lowercase

Template:Infobox

Brief
Convert all parameter names to lower case
Syntax
<syntaxhighlight lang="wikitext" inline>Lua error: Module:Params: The function ‘pipe function name’ does not exist.</syntaxhighlight>

This modifier does not take arguments besides the name of the function that will follow.

This modifier converts all parameter names to lower case. It is identical to writing ...|renaming_by_magic|lc|..., but without the burden of calling a parser function.

Template:A note In case of collisions between identical names, only one parameter, randomly chosen, will be left for a given name.

Template:Vpad

converting_names_to_uppercase

Template:Infobox

Brief
Convert all parameter names to upper case
Syntax
<syntaxhighlight lang="wikitext" inline>Lua error: Module:Params: The function ‘pipe function name’ does not exist.</syntaxhighlight>

This modifier does not take arguments besides the name of the function that will follow.

This modifier converts all parameter names to upper case. It is identical to writing ...|renaming_by_magic|uc|..., but without the burden of calling a parser function.

Template:A note In case of collisions between identical names, only one parameter, randomly chosen, will be left for a given name.

Template:Vpad

renaming_by_calling

Template:Infobox

Brief
Rename all parameters, replacing their former names with the expansion of a given template repeatedly called with at least one parameter (the parameter's former name)
Syntax
<syntaxhighlight lang="wikitext" inline>Lua error: Module:Params: The function ‘[call style]’ does not exist.</syntaxhighlight>

This modifier works similarly to mapping_by_calling, but instead of replacing parameters' values it renames the parameters themselves. Care must be used knowing that if a new name collides with another new name one of the two parameters will be removed without knowing which one. New names and old names do not create collisions. If a name is returned identical it will be considered as “unchanged” and in case of conflicts the renamed one will prevail. Possible leading and trailing spaces in the new names are always stripped. Here, if omitted, the call style flags argument defaults to names_only.

For instance, the following example uses {{2x}} to rename all incoming parameters by doubling their names:

<syntaxhighlight lang="wikitext"></syntaxhighlight>

Same, but adding a hyphen in between:

<syntaxhighlight lang="wikitext"></syntaxhighlight>

The following example calls the {{P1}} template to rename all parameters using their value as their new name:

<syntaxhighlight lang="wikitext"></syntaxhighlight>

This modifier can be particularly useful for sanitizing parameter names (e.g. collapsing several spaces into single spaces, changing the letter case, and so on).

Template:Vpad

Template:A note All arguments passed to this modifier except the renaming_by_calling modifier name itself, the template name, the call style flag, the let keyword, the passed parameter names, and the number of additional arguments will not be trimmed of their leading and trailing spaces.

Template:Vpad

renaming_by_invoking

Template:Infobox

Brief
Rename all parameters, replacing their former names with the text returned by a given module function repeatedly called with at least one argument (the parameter's former name)
Syntax
<syntaxhighlight lang="wikitext" inline>Lua error in package.lua at line 80: module 'Module:module name' not found.</syntaxhighlight>

This modifier works similarly to mapping_by_invoking, but instead of replacing parameters' values it renames the parameters themselves. Care must be used knowing that if a new name collides with another new name one of the two parameters will be removed without knowing which one. New names and old names do not create collisions. If a name is returned identical it will be considered as “unchanged” and in case of conflicts the renamed one will prevail. Possible leading and trailing spaces in the new names are always stripped. Here, if omitted, the call style flags argument defaults to names_only.

For instance, the following example uses Template:Mfl to rename all parameters of type Template:Para, Template:Para, … Template:Para into Template:Para, Template:ParaTemplate:Para, thus creating a novel sequence:

<syntaxhighlight lang="wikitext">Lua error in package.lua at line 80: module 'Module:string' not found.</syntaxhighlight>

This modifier can be particularly useful for sanitizing parameter names (e.g. collapsing several spaces into single spaces, changing the letter case, and so on).

Template:Vpad

Template:A note All arguments passed to this modifier except the renaming_by_invoking modifier name itself, the module name, the function name, the call style flag, the let keyword, the passed parameter names, and the number of additional arguments will not be trimmed of their leading and trailing spaces.

Template:Vpad

renaming_by_magic

Template:Infobox

Brief
Rename all parameters, replacing their former names with the text returned by a given parser function repeatedly called with at least one argument (the parameter's former name)
Syntax
<syntaxhighlight lang="wikitext" inline>Lua error: Module:Params: The function ‘[call style]’ does not exist.</syntaxhighlight>

This modifier works similarly to mapping_by_magic, but instead of replacing parameters' values it renames the parameters themselves. Care must be used knowing that if a new name collides with another new name one of the two parameters will be removed without knowing which one. New names and old names do not create collisions. If a name is returned identical it will be considered as “unchanged” and in case of conflicts the renamed one will prevail. Possible leading and trailing spaces in the new names are always stripped. Here, if omitted, the call style flags argument defaults to names_only.

For instance, the following example uses {{#expr}} to transform all numeric parameters into even numbers (you can replace the expression %0 * 2 with any other expression):

<syntaxhighlight lang="wikitext"></syntaxhighlight>

Template:Vpad

Template:A note All arguments passed to this modifier except the renaming_by_magic modifier name itself, the parser function name, the call style flag, the let keyword, the passed parameter names, and the number of additional arguments will not be trimmed of their leading and trailing spaces.

Template:Vpad

renaming_by_replacing

Template:Infobox

Brief
Rename all parameters, replacing their former names with the text returned by a string substitutions
Syntax
<syntaxhighlight lang="wikitext" inline>Lua error: Module:Params: The function ‘[count]’ does not exist.</syntaxhighlight>

This modifier works similarly to mapping_by_replacing, but instead of replacing parameters' values it renames the parameters themselves. Care must be used knowing that if a new name collides with another new name one of the two parameters will be removed without knowing which one. New names and old names do not create collisions. If a name is returned identical it will be considered as “unchanged” and in case of conflicts the renamed one will prevail. Possible leading and trailing spaces in the new names are always stripped (however they are not stripped while searching for the name to replace).

Since there can be only one parameter name that matches exactly a literal string, when used with the strict flag this modifier directly accesses the requested key without looping through the entire list of parameters (so it will be much faster).

For instance, the following example renames all parameters of type Template:Para, Template:Para, … Template:Para into Template:Para, Template:ParaTemplate:Para, thus creating a novel sequence:

<syntaxhighlight lang="wikitext"></syntaxhighlight>

This modifier can be particularly useful for sanitizing parameter names (e.g. collapsing several spaces into single spaces, changing the letter case, and so on).

For performance reasons this modifier uses string.gsub(); if you need to use mw.ustring.gsub() instead, you will need to invoke the replace function from Module:String via ...|renaming_by_invoking|string|replace|....

The following table shows examples of equivalent instructions. Please be aware that invoking mw.ustring.gsub() can be much slower.

string.gsub() mw.ustring.gsub() (via Module:String)
...|renaming_by_replacing|target|replace|... ...|renaming_by_invoking|string|replace|4|target|replace||false|...
...|renaming_by_replacing|target|replace|count|... ...|renaming_by_invoking|string|replace|4|target|replace|count|false|...
...|renaming_by_replacing|target|replace|plain|... ...|renaming_by_invoking|string|replace|2|target|replace|...
or, equivalently,
...|renaming_by_invoking|string|replace|4|target|replace||true|...
...|renaming_by_replacing|target|replace|count|plain|... ...|renaming_by_invoking|string|replace|3|target|replace|count|...
or, equivalently,
...|renaming_by_invoking|string|replace|4|target|replace|count|true|...

There is not a corresponding translation for the strict flag in Module:String. However, as it goes with the plain flag, in that case you won't need mw.ustring.gsub() in the first place.

Template:Vpad

Template:A note The target and replace arguments passed to this modifier will not be trimmed of their leading and trailing spaces. The or, plain, strict and pattern keywords, the count argument, and the mapping_by_replacing modifier name itself, however, will be trimmed of their surrounding spaces.

Template:Vpad

renaming_by_mixing

Template:Infobox

Brief
Rename all parameters, replacing their former names with the expansion of a custom string containing the $# and $@ placeholders
Syntax
<syntaxhighlight lang="wikitext" inline>Lua error: Module:Params: The function ‘pipe function name’ does not exist.</syntaxhighlight>

This modifier (temporarily) changes the content of the parameters the current template is being called with, replacing each of them with the expansion of a custom string that expects the same syntax as the for_each function.

For instance, the following code will wrap all parameter names in quotes

<syntaxhighlight lang="wikitext">...|renaming_by_mixing|“$#”|...</syntaxhighlight>

whereas the following code will replace all parameter names with the string [NAME::VALUE], where NAME and VALUE are each parameter's name and value:

<syntaxhighlight lang="wikitext">...|renaming_by_mixing|[$#::$@]|...</syntaxhighlight> Template:Vpad

Template:A note The mixing string argument passed to this modifier will not be trimmed of its leading and trailing spaces. The renaming_by_mixing modifier name itself, however, will be trimmed of their surrounding spaces.

Template:Vpad

grouping_by_calling

Template:Infobox

Brief
Group the parameters that have the same numeric suffix into novel parameters, whose names will be numbers and whose values will be decided by a custom template
Syntax
<syntaxhighlight lang="wikitext" inline>Lua error: Module:Params: The function ‘[let]’ does not exist.</syntaxhighlight>

This is the piping version of call_for_each_group. This means that after calling this modifier the old parameters will be (temporarily) gone and the only parameters left will be novel parameters whose names will be numbers (or an empty string if parameters without a numeric suffix were present) and whose content will be decided by a custom template.

Like other modifiers in the mapping_* and renaming_* family, it is possible to impose own parameters on the callback template by using the syntax ...|[let]|[...]|[number of additional arguments]|[argument 1]|[argument 2]|[...]|[argument N]|.... Unlike the other mapping_* and renaming_* modifiers, however (but like call_for_each_group), sequential parameters here will not be prepended, but will replace possible parsed parameters.

And so, writing

<syntaxhighlight lang="wikitext">Lua error: Module:Params: The function ‘...’ does not exist.</syntaxhighlight>

is identical to writing

<syntaxhighlight lang="wikitext">Lua error: Module:Params: The function ‘...’ does not exist.</syntaxhighlight>

In the example above the main difference will be that the first solution will allow to pass the newly grouped parameters at once to another template or module (via concat_and_call or concat_and_invoke) or, if needed, perform further fine-tuning operations concerning the new parameters.

Please refer to the documentation of call_for_each_group for further information on the parameters passed to the callback template.

Template:Vpad

Template:A note All arguments passed to this modifier except the grouping_by_calling modifier name itself, the template name, the let keyword, the passed parameter names, and the number of additional parameters will not be trimmed of their leading and trailing spaces.

Template:Vpad

parsing

Template:Infobox

Brief
Create new parameters by parsing a parameter string
Syntax
<syntaxhighlight lang="wikitext" inline>Lua error: Module:Params: The function ‘[trim flag]’ does not exist.</syntaxhighlight>

This modifier allows to add an infinity of new parameters by using a parameter string. By default this expects | as separator between parameters and = as separator between keys and values, but it is possible to specify other strings or patterns. The parsed parameters will overwrite existing parameters of the same name. For this reason, the new directive often accompanies this modifier.

Examples:

  • <syntaxhighlight lang="wikitext" inline>[1:one][2:two][3:three][hello:world][foo:bar]</syntaxhighlight>
    ↳ [1:one][2:two][3:three][hello:world][foo:bar]
  • <syntaxhighlight lang="wikitext" inline>[1:one][2:two][3:three][hello:world][foo:bar]</syntaxhighlight>
    ↳ [1:one][2:two][3:three][hello:world][foo:bar]
  • <syntaxhighlight lang="wikitext" inline>[1:one][2:two][3: three ][hello:world][foo: bar ]</syntaxhighlight>
    ↳ [1:one][2:two][3: three ][hello:world][foo: bar ]

The trim flag argument can be placed in any position after the string to parse (not necessarily in second position) and can have one of the following values: trim_none, trim_named, trim_positional, trim_all. If omitted, it defaults to trim_named.

The iteration delimiter setter can be placed in any position after the string to parse (not necessarily in third position), must be immediately followed by a user-given string, and can be either splitter_string or splitter_pattern. If omitted, the two arguments default to splitter_string|{{!}}. If the custom string is empty (but not if it is blank but not empty) the string to parse will be assumed not to have any iteration delimiters (this will result in one single parameter being parsed).

The key-value delimiter setter can be placed in any position after the string to parse (not necessarily in fifth position), must be immediately followed by a user-given string, and can be either setter_string or setter_pattern. If omitted, the two arguments default to setter_string|{{=}}. If the custom string is empty (but not if it is blank but not empty) the string to parse will be assumed not to have any key-value delimiters (this will result in a sequence-only list of parameters being parsed).

Possible options
Setting a trim flag Setting an iteration delimiter Setting a key-value delimiter
trim_none
trim_named
trim_positional
trim_all
splitter_string|...
splitter_pattern|...
setter_string|...
setter_pattern|...

Template:Vpad

Template:A note All arguments passed to this modifier except the parsing modifier name itself, the trim flag, iteration delimiter setter and key-value delimiter setter arguments will not be trimmed of their leading and trailing spaces.

Template:Vpad

reinterpreting

Template:Infobox

Brief
Use the content of a parameter as a parameter string to parse, after removing the parameter itself
Syntax
<syntaxhighlight lang="wikitext" inline>Lua error: Module:Params: The function ‘[trim flag]’ does not exist.</syntaxhighlight>

This modifier works exactly like parsing, but takes the content of a disposable parameter as input. See there for further information. The parameter passed to this modifier will be immediately deleted. The parsed parameters will overwrite existing parameters of the same name.

Example:

<syntaxhighlight lang="wikitext">Lua error: expandTemplate: template "See also" does not exist.</syntaxhighlight>

An example that shows how to use this function to transclude a custom template with custom parameters is available at {{Template:Rel}}.

Template:Vpad

Template:A note All arguments passed to this modifier except the reinterpreting modifier name itself, the parameter name, the trim flag, iteration delimiter setter and key-value delimiter setter arguments will not be trimmed of their leading and trailing spaces.

Template:Vpad

mixing_names_and_values

Template:Infobox

Brief
Rewrite all parameters, replacing names and values with the expansion of two custom strings containing the $# and $@ placeholders
Syntax
<syntaxhighlight lang="wikitext" inline>Lua error: Module:Params: The function ‘pipe function name’ does not exist.</syntaxhighlight>

This modifier (temporarily) changes names and values of the parameters the current template is being called with, replacing each of them with the expansion of two custom strings that expect the same syntax as the for_each function.

For instance, the following code will wrap all parameter names and values in quotes

<syntaxhighlight lang="wikitext">...|mixing_names_and_values|“$#”|“$@”|...</syntaxhighlight>

whereas the following code will replace all names with the string VALUE/NAME and all values with the string [NAME::VALUE], where NAME and VALUE are each parameter's name and value:

<syntaxhighlight lang="wikitext">...|mixing_names_and_values|$@/$#|[$#::$@]|...</syntaxhighlight> Template:Vpad

Template:A note The value mixing string argument passed to this modifier will not be trimmed of its leading and trailing spaces. The name mixing string argument and mixing_names_and_values modifier name itself, however, will be trimmed of their surrounding spaces.

Template:Vpad

combining_by_calling

Template:Infobox

Brief
Pass all current parameters to a custom template and save the returned output as a new parameter
Syntax
<syntaxhighlight lang="wikitext" inline>Lua error: expandTemplate: template "template name" does not exist.</syntaxhighlight>

This is the piping version of concat_and_call. This means that after calling this modifier the old parameters will be (temporarily) gone and the only parameter left will be what is specified in the new parameter name argument.

Since after using this modifier all parameters will be grouped into one single parameter, to pass additional parameters to the callback template you can safely use imposing or parsing.

For instance, using Template:Rel as callback template, a template named <syntaxhighlight lang="wikitext" inline>Template:Example template</syntaxhighlight> with the following content,

<syntaxhighlight lang="wikitext">Lua error: expandTemplate: template "module:params/testcases/tdummy echo sb" does not exist.</syntaxhighlight>

when transcluded as <syntaxhighlight lang="wikitext" inline>Template:Example template</syntaxhighlight> will produce

Lua error: expandTemplate: template "module:params/testcases/tdummy echo sb" does not exist.

Template:Vpad

snapshotting

Template:Infobox

Brief
Push a copy of the current parameter list to the queue of parameter lists
Syntax
<syntaxhighlight lang="wikitext" inline>Lua error: Module:Params: The function ‘pipe function name’ does not exist.</syntaxhighlight>

This modifier does not take arguments besides the name of the function that will follow.

This module has a stacking mechanism that allows to isolate groups of parameters, work separately on them, and then merge them back to the original stack. The modifiers dedicated to this mechanism are:

Every time the snapshotting modifier is used, the current list of parameters (together with their values) will be copied and added to a queue. When the entering_substack modifier is used, the list of parameters on top of the queue will temporarily become the current parameters, and all other modifiers will affect only this substack. After completing the job, the merging_substack will merge the current substack to the parent stack.

If no parameter lists have been snapshotted before calling entering_substack, the latter will automatically make a snapshot of the current parameters. Once inside a substack, it is possible to enter a subsubstack using the same machinery.

The detaching_substack modifier erases the current parameters from the parent stack, allowing the current stack to rename its parameters freely and merge them back to the parent stack, renamed.

It is possible to leave a substack without merging it to the parent by using the leaving_substack modifier. In this case, at some point it will be necessary to call flushing in order to merge the stack previously left unmerged. Alternatively, it will be possible to enter it again by calling entering_substack, and finally merge it via merging_substack.

An example will probably clarify the mechanism better than anything else:

<syntaxhighlight lang="wikitext">[1:This value once was “one”][2:two][3:three][4:four][This was called “foo”:bar][This was called “hello”:world]</syntaxhighlight>

The code above will result in:

[1:This value once was “one”][2:two][3:three][4:four][This was called “foo”:bar][This was called “hello”:world]

Template:Vpad

remembering

Template:Infobox

Brief
Push a copy of the original (unmodified) parameter list to the queue of snapshots
Syntax
<syntaxhighlight lang="wikitext" inline>Lua error: Module:Params: The function ‘pipe function name’ does not exist.</syntaxhighlight>

This modifier does not take arguments besides the name of the function that will follow.

This modifier is somewhat similar to snapshotting, except that it retrieves the parameters that were originally passed to the calling template before being affected by the module's modifiers. The modifier works also after the new directive. See snapshotting for more information on the stacking mechanism.

Template:Vpad

entering_substack

Template:Infobox

Brief
Enter the first stack in the queue of parameter lists, or copy the current parameters into a substack if the queue is empty
Syntax
<syntaxhighlight lang="wikitext" inline>Lua error: Module:Params: The function ‘[new]’ does not exist.</syntaxhighlight>

This modifier does not take arguments besides the name of the function that will follow.

See snapshotting for more information on the stacking mechanism. Once in a substack, it is possible to go back to the parent stack using two different modifiers: merging_substack and leaving_substack.

Template:Vpad

pulling

Template:Infobox

Brief
Pull a single parameter from the parent stack or from the stack of the original parameters
Syntax
<syntaxhighlight lang="wikitext" inline>Lua error: Module:Params: The function ‘pipe function name’ does not exist.</syntaxhighlight>

See snapshotting for more information on the stacking mechanism. If this modifer is not used in a substack, the parameter will be pulled from the original (unmodified) parameter list.

Template:Vpad

detaching_substack

Template:Infobox

Brief
Remove from the parent stack the parameters that are present in the current stack
Syntax
<syntaxhighlight lang="wikitext" inline>Lua error: Module:Params, ‘detaching_substack’: No substack has been created.</syntaxhighlight>

This modifier does not take arguments besides the name of the function that will follow.

This modifer can only be used in a substack. See snapshotting for more information on the stacking mechanism.

Template:Vpad

leaving_substack

Template:Infobox

Brief
Leave the current substack without merging it, and return to the parent stack
Syntax
<syntaxhighlight lang="wikitext" inline>Lua error: Module:Params, ‘leaving_substack’: No substack has been created.</syntaxhighlight>

This modifier does not take arguments besides the name of the function that will follow.

This modifer can only be used in a substack. See snapshotting for more information on the stacking mechanism.

See flushing for an example of how to use this modifier.

Template:Vpad

merging_substack

Template:Infobox

Brief
Leave the current stack after merging it with the parent stack, then return to the latter
Syntax
<syntaxhighlight lang="wikitext" inline>Lua error: Module:Params, ‘merging_substack’: No substack has been created.</syntaxhighlight>

This modifier does not take arguments besides the name of the function that will follow.

This modifer can only be used in a substack. See snapshotting for more information on the stacking mechanism.

Template:Vpad

flushing

Template:Infobox

Brief
Merge the first stack in the queue of snapshotted parameters with the current stack.
Syntax
<syntaxhighlight lang="wikitext" inline>Lua error: Module:Params, ‘flushing’: There are no substacks to flush.</syntaxhighlight>

This modifier does not take arguments besides the name of the function that will follow.

This modifier is used in conjunction with either leaving_substack or snapshotting. See snapshotting for more information on the stacking mechanism.

In the following wrapper of an <syntaxhighlight lang="wikitext" inline>Template:Example template</syntaxhighlight>, the three parameters Template:Para, Template:Para, and Template:Para are used as aliases for Template:Para, Template:Para, and Template:Para respectively. The flushing modifier ensures that in case both are present, the named alias will have the precedence over the positional alias.

<syntaxhighlight lang="wikitext">Lua error: expandTemplate: template "example template" does not exist.</syntaxhighlight>

Template:Vpad

new

Template:Infobox

Brief
Get rid of all the incoming parameters and create a new (empty) parameter stack
Syntax
<syntaxhighlight lang="wikitext" inline>Lua error: Module:Params: The function ‘pipe function name’ does not exist.</syntaxhighlight>

This modifier does not take arguments besides the name of the function that will follow.

This modifier can only appear in first position, or if substacks are present, immediately after the entering_substack directive. When in first position its main purpose is that of extending the facilities offered by this module (e.g. mapping_by_replacing, with_value_matching, etc.) to custom lists of strings, independently of the incoming parameters. When inside a stack, it signals that the snapshot of the current parameters must be ignored for that stack. The existence of the new modifier also facilitates debugging the module.

The newly created parameter stack can be populated via parsing, imposing or providing. The incoming parameters can always be retrieved back using the remembering and pulling modifiers.

Examples:

  • <syntaxhighlight lang="wikitext" inline>!foo!bar</syntaxhighlight>
    ↳ !foo!bar

Template:Vpad

Subpages

The complete list of subpages is available here.

Notes

  1. To be precise, the order will not be strictly alphabetical, because this would imply that a template called with the following parameters <syntaxhighlight lang="wikitext" inline>Template:Foobar</syntaxhighlight> would see them reordered as follows: <syntaxhighlight lang="wikitext" inline>Template:Foobar</syntaxhighlight> (with the dot in the middle between negative and positive numbers). To avoid this, numbers are always displayed first (i.e. <syntaxhighlight lang="wikitext" inline>Template:Foobar</syntaxhighlight>).

See also

Template:Sandbox other


require[[strict]]


	---                                        ---
	---     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 function natural_sort (var1, var2)
	return tostring(var1):gsub('%d+', zero_padded) <
		tostring(var2):gsub('%d+', zero_padded)
end


-- Return a copy or a reference to a table
local function copy_or_ref_table (src, refonly)
	if refonly then return src end
	local newtab = {}
	for key, val in pairs(src) do newtab[key] = val end
	return newtab
end


-- Remove some numeric elements from a table, shifting everything to the left
local function remove_numeric_keys (tbl, idx, len)
	local cache = {}
	local tmp = idx + len - 1
	for key, val in pairs(tbl) do
		if type(key) == 'number' and key >= idx then
			if key > tmp then cache[key - len] = val end
			tbl[key] = nil
		end
	end
	for key, val in pairs(cache) do tbl[key] = val end
end


-- Make a reduced copy of a table (shifting in both directions if necessary)
local function copy_table_reduced (tbl, idx, len)
	local ret = {}
	local tmp = idx + len - 1
	if idx > 0 then
		for key, val in pairs(tbl) do
			if type(key) ~= 'number' or key < idx then
				ret[key] = val
			elseif key > tmp then ret[key - len] = val end
		end
	elseif tmp > 0 then
		local nshift = 1 - idx
		for key, val in pairs(tbl) do
			if type(key) ~= 'number' then ret[key] = val
			elseif key > tmp then ret[key - tmp] = val
			elseif key < idx then ret[key + nshift] = val end
		end
	else
		for key, val in pairs(tbl) do
			if type(key) ~= 'number' or key > tmp then
				ret[key] = val
			elseif key < idx then ret[key + len] = val end
		end
	end
	return ret
end


-- Make an expanded copy of a table (shifting in both directions if necessary)
--[[
local function copy_table_expanded (tbl, idx, len)
	local ret = {}
	local tmp = idx + len - 1
	if idx > 0 then
		for key, val in pairs(tbl) do
			if type(key) ~= 'number' or key < idx then
				ret[key] = val
			else ret[key + len] = val end
		end
	elseif tmp > 0 then
		local nshift = idx - 1
		for key, val in pairs(tbl) do
			if type(key) ~= 'number' then ret[key] = val
			elseif key > 0 then ret[key + tmp] = val
			elseif key < 1 then ret[key + nshift] = val end
		end
	else
		for key, val in pairs(tbl) do
			if type(key) ~= 'number' or key > tmp then
				ret[key] = val
			else ret[key - len] = val end
		end
	end
	return ret
end
]]--


-- Move a key from a table to another, but only if under a different name and
-- always parsing numeric strings as numbers
local function steal_if_renamed (val, src, skey, dest, dkey)
	local realkey = tonumber(dkey) or dkey:match'^%s*(.-)%s*$'
	if skey ~= realkey then
		dest[realkey] = val
		src[skey] = nil
	end
end



	--[[ Public strings ]]--
	------------------------


-- Special match keywords (functions and modifiers MUST avoid these names)
local mkeywords = {
	['or'] = 0,
	pattern = 1,
	plain = 2,
	strict = 3
}


-- Sort functions (functions and modifiers MUST avoid these names)
local sortfunctions = {
	--alphabetically = false, -- Simply uncommenting enables the option
	naturally = natural_sort
}


-- Callback styles for the `mapping_*` and `renaming_*` class of modifiers
-- (functions and modifiers MUST avoid these names)
--[[

Meanings of the columns:

  col[1] = Loop type (0-3)
  col[2] = Number of module arguments that the style requires (1-3)
  col[3] = Minimum number of sequential parameters passed to the callback
  col[4] = Name of the callback parameter where to place each parameter name
  col[5] = Name of the callback parameter where to place each parameter value
  col[6] = Argument in the modifier's invocation that will override `col[4]`
  col[7] = Argument in the modifier's invocation that will override `col[5]`

A value of `-1` indicates that no meaningful value is stored (i.e. `nil`)

]]--
local mapping_styles = {
	names_and_values = { 3, 2, 2, 1, 2, -1, -1 },
	values_and_names = { 3, 2, 2, 2, 1, -1, -1 },
	values_only = { 1, 2, 1, -1, 1, -1, -1 },
	names_only = { 2, 2, 1, 1, -1, -1, -1 },
	names_and_values_as = { 3, 4, 0, -1, -1, 2, 3 },
	names_only_as = { 2, 3, 0, -1, -1, 2, -1 },
	values_only_as = { 1, 3, 0, -1, -1, -1, 2 },
	blindly = { 0, 2, 0, -1, -1, -1, -1 }
}


-- Memory slots (functions and modifiers MUST avoid these names)
local memoryslots = {
	i = 'itersep',
	l = 'lastsep',
	p = 'pairsep',
	h = 'header',
	f = 'footer',
	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
}


-- Functions and modifiers MUST avoid these names too: `let`



	--[[ Module's private environment ]]--
	--------------------------------------


-- 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
-- guarantee that they will make their own (modified) copy available
local refpipe = {
	call_for_each_group = true,
	coins = true,
	count = true,
	for_each = true,
	list = true,
	list_values = true,
	value_of = true
}


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


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


-- The private table of functions
local library = {}


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


-- Create a new context
local function context_new (frame)
	local ctx = {}
	ctx.frame = frame
	ctx.oparams = frame.args
	ctx.firstposonly = static_iface
	ctx.iterfunc = pairs
	ctx.sorttype = 0
	ctx.n_parents = 0
	ctx.n_children = 0
	ctx.n_available = maxfill
	return 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(modulename ..
		': You must specify a function to call', 0) end
	if library[nextfn] == nil then
		if ctx.firstposonly[nextfn] == nil then error(modulename ..
			': The function ‘' .. nextfn .. '’ does not exist', 0)
		else error(modulename .. ': The ‘' .. nextfn ..
			'’ directive can only appear in first position', 0)
		end
	end
	remove_numeric_keys(ctx.pipe, 1, n_forward)
	return library[nextfn]
end


-- Main loop
local function main_loop (ctx, start_with)
	local fn = start_with
	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


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


-- Load the optional arguments of some of the `mapping_*` and `renaming_*`
-- class of modifiers
local function load_callback_opts (src, n_skip, default_style)
	local style
	local shf
	local tmp = src[n_skip + 1]
	if tmp ~= nil then style = mapping_styles[tmp:match'^%s*(.-)%s*$'] end
	if style == nil then
		style = default_style
		shf = n_skip - 1
	else shf = n_skip end
	local n_exist = style[3]
	local karg = style[4]
	local varg = style[5]
	tmp = style[6]
	if tmp > -1 then
		tmp = src[tmp + shf]
		karg = tonumber(tmp)
		if karg == nil then karg = tmp:match'^%s*(.-)%s*$'
		else n_exist = math.max(n_exist, karg) end
	end
	tmp = style[7]
	if tmp > -1 then
		tmp = src[tmp + shf]
		varg = tonumber(tmp)
		if varg == nil then varg = tmp:match'^%s*(.-)%s*$'
		else n_exist = math.max(n_exist, varg) end
	end
	local dest, nargs = load_child_opts(src, style[2] + shf, n_exist)
	tmp = style[1]
	if (tmp == 3 or tmp == 2) and dest[karg] ~= nil then
		tmp = tmp - 2 end
	if (tmp == 3 or tmp == 1) and dest[varg] ~= nil then
		tmp = tmp - 1 end
	return dest, nargs, tmp, karg, varg
end


-- Parse the arguments of some of the `mapping_*` and `renaming_*` class of
-- modifiers
local function load_replace_args (opts, fname)
	if opts[1] == nil then error(modulename ..
		', ‘' .. fname .. '’: No pattern string was given', 0) end
	if opts[2] == nil then error(modulename ..
		', ‘' .. fname .. '’: No replacement string was given', 0) end
	local ptn = opts[1]
	local repl = opts[2]
	local argc = 3
	local nmax = tonumber(opts[3])
	if nmax ~= nil or (opts[3] or ''):match'^%s*$' ~= nil then argc = 4 end
	local flg = opts[argc]
	if flg ~= nil then flg = mkeywords[flg:match'^%s*(.-)%s*$'] end
	if flg == 0 then flg = nil elseif flg ~= nil then argc = argc + 1 end
	return ptn, repl, nmax, flg, argc, (nmax ~= nil and nmax < 1) or
		(flg == 3 and ptn == repl)
end


-- Parse the arguments of the `with_*_matching` class of modifiers
local function load_pattern_args (opts, fname)
	local state = 0
	local cnt = 1
	local keyw
	local nptns = 0
	local ptns = {}
	for _, val in ipairs(opts) do
		if state == 0 then
			nptns = nptns + 1
			ptns[nptns] = { val, false, false }
			state = -1
		else
			keyw = val:match'^%s*(.*%S)'
			if keyw == nil or mkeywords[keyw] == nil or (
				state > 0 and mkeywords[keyw] > 0
			) then break
			else
				state = mkeywords[keyw]
				if state > 1 then ptns[nptns][2] = true end
				if state == 3 then ptns[nptns][3] = true end
			end
		end
		cnt = cnt + 1
	end
	if state == 0 then error(modulename .. ', ‘' .. fname ..
		'’: No pattern was given', 0) end
	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


-- Map parameters' values using a custom callback and a referenced table
local value_maps = {
	[0] = function (tbl, margs, karg, varg, fn)
		for key in pairs(tbl) do tbl[key] = fn() end
	end,
	[1] = function (tbl, margs, karg, varg, fn)
		for key, val in pairs(tbl) do
			margs[varg] = val
			tbl[key] = fn()
		end
	end,
	[2] = function (tbl, margs, karg, varg, fn)
		for key in pairs(tbl) do
			margs[karg] = key
			tbl[key] = fn()
		end
	end,
	[3] = function (tbl, margs, karg, varg, fn)
		for key, val in pairs(tbl) do
			margs[karg] = key
			margs[varg] = val
			tbl[key] = fn()
		end
	end
}


-- Private table for `map_names()`
local name_thieves = {
	[0] = function (cache, tbl, rargs, karg, varg, fn)
		for key, val in pairs(tbl) do
			steal_if_renamed(val, tbl, key, cache, fn())
		end
	end,
	[1] = function (cache, tbl, rargs, karg, varg, fn)
		for key, val in pairs(tbl) do
			rargs[varg] = val
			steal_if_renamed(val, tbl, key, cache, fn())
		end
	end,
	[2] = function (cache, tbl, rargs, karg, varg, fn)
		for key, val in pairs(tbl) do
			rargs[karg] = key
			steal_if_renamed(val, tbl, key, cache, fn())
		end
	end,
	[3] = function (cache, tbl, rargs, karg, varg, fn)
		for key, val in pairs(tbl) do
			rargs[karg] = key
			rargs[varg] = val
			steal_if_renamed(val, tbl, key, cache, fn())
		end
	end
}


-- Map parameters' names using a custom callback and a referenced table
local function map_names (tbl, rargs, karg, varg, looptype, fn)
	local cache = {}
	name_thieves[looptype](cache, tbl, rargs, karg, varg, fn)
	for key, val in pairs(cache) do tbl[key] = val end
end


-- Return a new table that contains `src` regrouped according to the numeric
-- suffixes in its keys
local function make_groups (src)
	-- NOTE: `src` might be the original metatable!
	local tmp
	local prefix
	local gid
	local groups = {}
	for key, val in pairs(src) do
		-- `key` must only be a string or a number...
		gid = tonumber(key)
		if gid == nil then
			prefix, gid = key:match'^%s*(.-)%s*(%-?%d*)%s*$'
			gid = tonumber(gid) or ''
		else prefix = '' end
		if groups[gid] == nil then groups[gid] = {} end
		tmp = tonumber(prefix)
		if tmp ~= nil then
			if tmp < 1 then prefix = tmp - 1 else prefix = tmp end
		end
		groups[gid][prefix] = val
	end
	return groups
end


-- Split into parts a string containing the `$#` and `$@` placeholders and
-- return the information as a skeleton table, a canvas table and a length
local function parse_placeholder_string (target)
	local skel = {}
	local canvas = {}
	local idx = 1
	local s_pos = 1
	local e_pos = string.find(target, '%$[@#]', 1, false)
	while e_pos ~= nil do
		canvas[idx] = target:sub(s_pos, e_pos - 1)
		skel[idx + 1] = target:sub(e_pos, e_pos + 1) == '$@'
		idx = idx + 2
		s_pos = e_pos + 2
		e_pos = string.find(target, '%$[@#]', s_pos, false)
	end
	if (s_pos > target:len()) then idx = idx - 1
	else canvas[idx] = target:sub(s_pos) end
	return skel, canvas, idx
end


-- Populate a table by parsing a parameter string
local function parse_parameter_string (tbl, str, isp, ipl, psp, ppl, trn, tru)
	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 tbl = ctx.params
	local nmax = table.maxn(ctx.pipe)
	local retval = {}
	if ctx.subset == 1 then
		-- We need only the sequence
		for key, val in ipairs(tbl) do retval[key + nmax] = val end
	else
		if ctx.subset == -1 then
			for key in ipairs(tbl) do tbl[key] = nil end
		end
		for key, val in pairs(tbl) do
			if type(key) == 'number' and key > 0 then
				retval[key + nmax] = val
			else retval[key] = val end
		end
	end
	for key, val in pairs(ctx.pipe) do retval[key] = val end
	return retval
end


-- Flush the parameters by calling a custom function for each value (after this
-- function has been invoked `ctx.params` will be no longer usable)
local function flush_params (ctx, fn)
	local tbl = ctx.params
	if ctx.subset == 1 then
		for key, val in ipairs(tbl) do fn(key, val) end
		return
	end
	if ctx.subset == -1 then
		for key, val in ipairs(tbl) do tbl[key] = nil end
	end
	if ctx.sorttype > 0 then
		local nums = {}
		local words = {}
		local nn = 0
		local nw = 0
		for key, val in pairs(tbl) do
			if type(key) == 'number' then
				nn = nn + 1
				nums[nn] = key
			else
				nw = nw + 1
				words[nw] = key
			end
		end
		table.sort(nums)
		table.sort(words, natural_sort)
		if ctx.sorttype == 2 then
			for idx = 1, nw do fn(words[idx], tbl[words[idx]]) end
			for idx = 1, nn do fn(nums[idx], tbl[nums[idx]]) end
			return
		end
		for idx = 1, nn do fn(nums[idx], tbl[nums[idx]]) end
		for idx = 1, nw do fn(words[idx], tbl[words[idx]]) end
		return
	end
	if ctx.subset ~= -1 then
		for key, val in ipairs(tbl) do
			fn(key, val)
			tbl[key] = nil
		end
	end
	for key, val in pairs(tbl) do fn(key, val) end
end



	--[[ Modifiers ]]--
	-----------------------------


-- Syntax:  #invoke:params|sequential|pipe to
library.sequential = function (ctx)
	if ctx.subset == -1 then error(modulename ..
		': The two directives ‘non-sequential’ and ‘sequential’ are in contradiction with each other', 0) end
	if ctx.sorttype > 0 then error(modulename ..
		': The ‘all_sorted’ and ‘reassorted’ directives are redundant when followed by ‘sequential’', 0) end
	ctx.iterfunc = ipairs
	ctx.subset = 1
	return context_iterate(ctx, 1)
end


-- Syntax:  #invoke:params|non-sequential|pipe to
library['non-sequential'] = function (ctx)
	if ctx.subset == 1 then error(modulename ..
		': The two directives ‘sequential’ and ‘non-sequential’ are in contradiction with each other', 0) end
	ctx.iterfunc = pairs
	ctx.subset = -1
	return context_iterate(ctx, 1)
end


-- Syntax:  #invoke:params|all_sorted|pipe to
library.all_sorted = function (ctx)
	if ctx.subset == 1 then error(modulename ..
		': The ‘all_sorted’ directive is redundant after ‘sequential’', 0) end
	if ctx.sorttype == 2 then error(modulename ..
		': The two directives ‘reassorted’ and ‘sequential’ are in contradiction with each other', 0) end
	ctx.sorttype = 1
	return context_iterate(ctx, 1)
end


-- Syntax:  #invoke:params|reassorted|pipe to
library.reassorted = function (ctx)
	if ctx.subset == 1 then error(modulename ..
		': The ‘reassorted’ directive is redundant after ‘sequential’', 0) end
	if ctx.sorttype == 1 then error(modulename ..
		': The two directives ‘sequential’ and ‘reassorted’ are in contradiction with each other', 0) end
	ctx.sorttype = 2
	return context_iterate(ctx, 1)
end


-- Syntax:  #invoke:params|setting|directives|...|pipe to
library.setting = function (ctx)
	local opts = ctx.pipe
	local cmd = opts[1]
	if cmd ~= nil then
		cmd = cmd:gsub('%s+', ''):gsub('/+', '/'):match'^/*(.*[^/])'
	end
	if cmd == nil then error(modulename ..
		', ‘setting’: No directive was given', 0) end
	local sep = string.byte('/')
	local argc = 2
	local dest = {}
	local vname
	local chr
	for idx = 1, #cmd do
		chr = cmd:byte(idx)
		if chr == sep then
			for key, val in ipairs(dest) do
				ctx[val] = opts[argc]
				dest[key] = nil
			end
			argc = argc + 1
		else
			vname = memoryslots[string.char(chr)]
			if vname == nil then error(modulename ..
				', ‘setting’: Unknown slot ‘' ..
				string.char(chr) .. '’', 0) end
			table.insert(dest, vname)
		end
	end
	for key, val in ipairs(dest) do ctx[val] = opts[argc] end
	return context_iterate(ctx, argc + 1)
end


-- Syntax:  #invoke:params|squeezing|pipe to
library.squeezing = function (ctx)
	local tbl = ctx.params
	local store = {}
	local indices = {}
	local newlen = 0
	for key, val in pairs(tbl) do
		if type(key) == 'number' then
			newlen = newlen + 1
			indices[newlen] = key
			store[key] = val
			tbl[key] = nil
		end
	end
	table.sort(indices)
	for idx = 1, newlen do tbl[idx] = store[indices[idx]] end
	return context_iterate(ctx, 1)
end


-- Syntax:  #invoke:params|filling_the_gaps|pipe to
library.filling_the_gaps = function (ctx)
	local tbl = ctx.params
	local nmin = 1
	local nmax = nil
	local nnums = -1
	local tmp = {}
	for key, val in pairs(tbl) do
		if type(key) == 'number' then
			if nmax == nil then
				if key < nmin then nmin = key end
				nmax = key
			elseif key > nmax then nmax = key
			elseif key < nmin then nmin = key end
			nnums = nnums + 1
			tmp[key] = val
		end
	end
	if nmax ~= nil and nmax - nmin > nnums then
		ctx.n_available = ctx.n_available + nmin + nnums - nmax
		if ctx.n_available < 0 then error(modulename ..
			', ‘filling_the_gaps’: It is possible to fill at most ' ..
			tostring(maxfill) .. ' parameters', 0) end
		for idx = nmin, nmax, 1 do tbl[idx] = '' end
		for key, val in pairs(tmp) do tbl[key] = val end
	end
	return context_iterate(ctx, 1)
end


-- Syntax:  #invoke:params|clearing|pipe to
library.clearing = function (ctx)
	local tbl = ctx.params
	local numerics = {}
	for key, val in pairs(tbl) do
		if type(key) == 'number' then
			numerics[key] = val
			tbl[key] = nil
		end
	end
	for key, val in ipairs(numerics) do tbl[key] = val end
	return context_iterate(ctx, 1)
end


-- Syntax:  #invoke:params|cutting|left cut|right cut|pipe to
library.cutting = function (ctx)
	local lcut = tonumber(ctx.pipe[1])
	if lcut == nil then error(modulename ..
		', ‘cutting’: Left cut must be a number', 0) end
	local rcut = tonumber(ctx.pipe[2])
	if rcut == nil then error(modulename ..
		', ‘cutting’: Right cut must be a number', 0) end
	local tbl = ctx.params
	local len = #tbl
	if lcut < 0 then lcut = len + lcut end
	if rcut < 0 then rcut = len + rcut end
	local tot = lcut + rcut
	if tot > 0 then
		local cache = {}
		if tot >= len then
			for key in ipairs(tbl) do tbl[key] = nil end
			tot = len
		else
			for idx = len - rcut + 1, len, 1 do tbl[idx] = nil end
			for idx = 1, lcut, 1 do tbl[idx] = nil end
		end
		for key, val in pairs(tbl) do
			if type(key) == 'number' and key > 0 then
				if key > len then cache[key - tot] = val
				else cache[key - lcut] = val end
				tbl[key] = nil
			end
		end
		for key, val in pairs(cache) do tbl[key] = val end
	end
	return context_iterate(ctx, 3)
end


-- Syntax:  #invoke:params|cropping|left crop|right crop|pipe to
library.cropping = function (ctx)
	local lcut = tonumber(ctx.pipe[1])
	if lcut == nil then error(modulename ..
		', ‘cropping’: Left crop must be a number', 0) end
	local rcut = tonumber(ctx.pipe[2])
	if rcut == nil then error(modulename ..
		', ‘cropping’: Right crop must be a number', 0) end
	local tbl = ctx.params
	local nmin
	local nmax
	for key in pairs(tbl) do
		if type(key) == 'number' then
			if nmin == nil then
				nmin = key
				nmax = key
			elseif key > nmax then nmax = key
			elseif key < nmin then nmin = key end
		end
	end
	if nmin ~= nil then
		local len = nmax - nmin + 1
		if lcut < 0 then lcut = len + lcut end
		if rcut < 0 then rcut = len + rcut end
		if lcut + rcut - len > -1 then
			for key in pairs(tbl) do
				if type(key) == 'number' then tbl[key] = nil end
			end
		elseif lcut + rcut > 0 then
			for idx = nmax - rcut + 1, nmax do tbl[idx] = nil end
			for idx = nmin, nmin + lcut - 1 do tbl[idx] = nil end
			local lshift = nmin + lcut - 1
			if lshift > 0 then
				for idx = lshift + 1, nmax, 1 do
					tbl[idx - lshift] = tbl[idx]
					tbl[idx] = nil
				end
			end
		end
	end
	return context_iterate(ctx, 3)
end


-- Syntax:  #invoke:params|purging|start offset|length|pipe to
library.purging = function (ctx)
	local idx = tonumber(ctx.pipe[1])
	if idx == nil then error(modulename ..
		', ‘purging’: Start offset must be a number', 0) end
	local len = tonumber(ctx.pipe[2])
	if len == nil then error(modulename ..
		', ‘purging’: Length must be a number', 0) end
	local tbl = ctx.params
	if len < 1 then
		len = len + table.maxn(tbl)
		if idx > len then return context_iterate(ctx, 3) end
		len = len - idx + 1
	end
	ctx.params = copy_table_reduced(tbl, idx, len)
	return context_iterate(ctx, 3)
end


-- Syntax:  #invoke:params|backpurging|start offset|length|pipe to
library.backpurging = function (ctx)
	local last = tonumber(ctx.pipe[1])
	if last == nil then error(modulename ..
		', ‘backpurging’: Start offset must be a number', 0) end
	local len = tonumber(ctx.pipe[2])
	if len == nil then error(modulename ..
		', ‘backpurging’: Length must be a number', 0) end
	local idx
	local tbl = ctx.params
	if len > 0 then
		idx = last - len + 1
	else
		for key in pairs(tbl) do
			if type(key) == 'number' and (idx == nil or
				key < idx) then idx = key end
		end
		if idx == nil then return context_iterate(ctx, 3) end
		idx = idx - len
		if last < idx then return context_iterate(ctx, 3) end
		len = last - idx + 1
	end
	ctx.params = copy_table_reduced(ctx.params, idx, len)
	return context_iterate(ctx, 3)
end


-- Syntax:  #invoke:params|reversing_numeric_names|pipe to
library.reversing_numeric_names = function (ctx)
	local tbl = ctx.params
	local numerics = {}
	local nmax = 0
	for key, val in pairs(tbl) do
		if type(key) == 'number' then
			numerics[key] = val
			tbl[key] = nil
			if key > nmax then nmax = key end
		end
	end
	for key, val in pairs(numerics) do tbl[nmax - key + 1] = val end
	return context_iterate(ctx, 1)
end


-- Syntax:  #invoke:params|pivoting_numeric_names|pipe to
--[[
library.pivoting_numeric_names = function (ctx)
	local tbl = ctx.params
	local shift = #tbl + 1
	if shift < 2 then return library.reversing_numeric_names(ctx) end
	local numerics = {}
	for key, val in pairs(tbl) do
		if type(key) == 'number' then
			numerics[key] = val
			tbl[key] = nil
		end
	end
	for key, val in pairs(numerics) do tbl[shift - key] = val end
	return context_iterate(ctx, 1)
end
]]--


-- Syntax:  #invoke:params|mirroring_numeric_names|pipe to
--[[
library.mirroring_numeric_names = function (ctx)
	local tbl = ctx.params
	local numerics = {}
	local nmax
	local nmin
	for key, val in pairs(tbl) do
		if type(key) == 'number' then
			numerics[key] = val
			tbl[key] = nil
			if nmax == nil then
				nmax = key
				nmin = key
			elseif key > nmax then nmax = key
			elseif key < nmin then nmin = key end
		end
	end
	for key, val in pairs(numerics) do tbl[nmax + nmin - key] = val end
	return context_iterate(ctx, 1)
end
]]--


-- Syntax:  #invoke:params|swapping_numeric_names|pipe to
--[[
library.swapping_numeric_names = function (ctx)
	local tbl = ctx.params
	local cache = {}
	local nsize = 0
	local tmp
	for key in pairs(tbl) do
		if type(key) == 'number' then
			nsize = nsize + 1
			cache[nsize] = key
		end
	end
	table.sort(cache)
	for idx = math.floor(nsize / 2), 1, -1 do
		tmp = tbl[cache[idx] ]
		tbl[cache[idx] ] = tbl[cache[nsize - idx + 1] ]
		tbl[cache[nsize - idx + 1] ] = tmp
	end
	return context_iterate(ctx, 1)
end
]]--


-- Syntax:  #invoke:params|sorting_sequential_values|[criterion]|pipe to
library.sorting_sequential_values = function (ctx)
	local sortfn
	if ctx.pipe[1] ~= nil then sortfn = sortfunctions[ctx.pipe[1]] end
	if sortfn then table.sort(ctx.params, sortfn)
	else table.sort(ctx.params) end -- i.e. either `false` or `nil`
	if sortfn == nil then return context_iterate(ctx, 1) end
	return context_iterate(ctx, 2)
end


-- Syntax:  #invoke:params|inserting|position|how many|...|pipe to
--[[
library.inserting = function (ctx)
	-- NOTE: `ctx.params` might be the original metatable! As a modifier,
	-- this function MUST create a copy of it before returning
	local idx = tonumber(ctx.pipe[1])
	if idx == nil then error(modulename ..
		', ‘inserting’: Position must be a number', 0) end
	local len = tonumber(ctx.pipe[2])
	if len == nil or len < 1 then error(modulename ..
		', ‘inserting’: The amount must be a number greater than zero', 0) end
	local opts = ctx.pipe
	local tbl = copy_table_expanded(ctx.params, idx, len)
	for key = idx, idx + len - 1 do tbl[key] = opts[key - idx + 3] end
	ctx.params = tbl
	return context_iterate(ctx, len + 3)
end
]]--


-- Syntax:  #invoke:params|imposing|name|value|pipe to
library.imposing = function (ctx)
	if ctx.pipe[1] == nil then error(modulename ..
		', ‘imposing’: Missing parameter name to impose', 0) end
	local key = ctx.pipe[1]:match'^%s*(.-)%s*$'
	ctx.params[tonumber(key) or key] = ctx.pipe[2]
	return context_iterate(ctx, 3)
end


-- Syntax:  #invoke:params|providing|name|value|pipe to
library.providing = function (ctx)
	if ctx.pipe[1] == nil then error(modulename ..
		', ‘providing’: Missing parameter name to provide', 0) end
	local key = ctx.pipe[1]:match'^%s*(.-)%s*$'
	key = tonumber(key) or key
	if ctx.params[key] == nil then ctx.params[key] = ctx.pipe[2] end
	return context_iterate(ctx, 3)
end


-- Syntax:  #invoke:params|discarding|name|[how many]|pipe to
library.discarding = function (ctx)
	if ctx.pipe[1] == nil then error(modulename ..
		', ‘discarding’: Missing parameter name to discard', 0) end
	local key = ctx.pipe[1]
	local len = tonumber(ctx.pipe[2])
	if len == nil then
		ctx.params[tonumber(key) or key:match'^%s*(.-)%s*$'] = nil
		return context_iterate(ctx, 2)
	end
	key = tonumber(key)
	if key == nil then error(modulename ..
		', ‘discarding’: A range was provided, but the initial parameter name is not numeric', 0) end
	if len < 1 then error(modulename ..
		', ‘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
	return context_iterate(ctx, 3)
end


-- Syntax:  #invoke:params|excluding_non-numeric_names|pipe to
library['excluding_non-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|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,
		'with_name_matching')
	local tmp
	local ptn
	local tbl = ctx.params
	local newparams = {}
	for idx = 1, nptns do
		ptn = targets[idx]
		if ptn[3] then
			tmp = tonumber(ptn[1]) or ptn[1]
			newparams[tmp] = tbl[tmp]
		else
			for key, val in pairs(tbl) do
				if tostring(key):find(ptn[1], 1, ptn[2]) then
					newparams[key] = val
				end
			end
		end
	end
	ctx.params = newparams
	return context_iterate(ctx, argc)
end


-- Syntax:  #invoke:params|with_name_not_matching|target 1|[plain flag 1]
--            |[and]|[target 2]|[plain flag 2]|[and]|[...]|[target N]|[plain
--            flag N]|pipe to
library.with_name_not_matching = function (ctx)
	local targets, nptns, argc = load_pattern_args(ctx.pipe,
		'with_name_not_matching')
	local tbl = ctx.params
	if nptns == 1 and targets[1][3] then
		local tmp = targets[1][1]
		tbl[tonumber(tmp) or tmp] = nil
		return context_iterate(ctx, argc)
	end
	local yesmatch
	local ptn
	for key in pairs(tbl) do
		yesmatch = true
		for idx = 1, nptns do
			ptn = targets[idx]
			if ptn[3] then
				if tostring(key) ~= ptn[1] then
					yesmatch = false
					break
				end
			elseif not tostring(key):find(ptn[1], 1, ptn[2]) then
				yesmatch = false
				break
			end
		end
		if yesmatch then tbl[key] = nil end
	end
	return context_iterate(ctx, argc)
end


-- Syntax:  #invoke:params|with_value_matching|target 1|[plain flag 1]|[or]
--            |[target 2]|[plain flag 2]|[or]|[...]|[target N]|[plain flag
--            N]|pipe to
library.with_value_matching = function (ctx)
	local tbl = ctx.params
	local targets, nptns, argc = load_pattern_args(ctx.pipe,
		'with_value_matching')
	local nomatch
	local ptn
	for key, val in pairs(tbl) do
		nomatch = true
		for idx = 1, nptns do
			ptn = targets[idx]
			if ptn[3] then
				if val == ptn[1] then
					nomatch = false
					break
				end
			elseif val:find(ptn[1], 1, ptn[2]) then
				nomatch = false
				break
			end
		end
		if nomatch then tbl[key] = nil end
	end
	return context_iterate(ctx, argc)
end


-- Syntax:  #invoke:params|with_value_not_matching|target 1|[plain flag 1]
--            |[and]|[target 2]|[plain flag 2]|[and]|[...]|[target N]|[plain
--            flag N]|pipe to
library.with_value_not_matching = function (ctx)
	local tbl = ctx.params
	local targets, nptns, argc = load_pattern_args(ctx.pipe,
		'with_value_not_matching')
	local yesmatch
	local ptn
	for key, val in pairs(tbl) do
		yesmatch = true
		for idx = 1, nptns do
			ptn = targets[idx]
			if ptn[3] then
				if val ~= ptn[1] then
					yesmatch = false
					break
				end
			elseif not val:find(ptn[1], 1, ptn[2]) then
				yesmatch = false
				break
			end
		end
		if yesmatch then tbl[key] = nil end
	end
	return context_iterate(ctx, argc)
end


-- Syntax:  #invoke:params|trimming_values|pipe to
library.trimming_values = function (ctx)
	local tbl = ctx.params
	for key, val in pairs(tbl) do tbl[key] = val:match'^%s*(.-)%s*$' end
	return context_iterate(ctx, 1)
end


-- Syntax:  #invoke:params|converting_values_to_lowercase|pipe to
library.converting_values_to_lowercase = function (ctx)
	local tbl = ctx.params
	for key, val in pairs(tbl) do tbl[key] = val:lower() end
	return context_iterate(ctx, 1)
end


-- Syntax:  #invoke:params|converting_values_to_uppercase|pipe to
library.converting_values_to_uppercase = function (ctx)
	local tbl = ctx.params
	for key, val in pairs(tbl) do tbl[key] = val:upper() end
	return context_iterate(ctx, 1)
end


-- Syntax:  #invoke:params|mapping_by_calling|template name|[call
--            style]|[let]|[...][number of additional parameters]|[parameter
--            1]|[parameter 2]|[...]|[parameter N]|pipe to
library.mapping_by_calling = function (ctx)
	local opts = ctx.pipe
	local tname
	if opts[1] ~= nil then tname = opts[1]:match'^%s*(.*%S)' end
	if tname == nil then error(modulename ..
		', ‘mapping_by_calling’: No template name was provided', 0) end
	local margs, argc, looptype, karg, varg = load_callback_opts(opts, 1,
		mapping_styles.values_only)
	local model = { title = tname, args = margs }
	value_maps[looptype](ctx.params, margs, karg, varg, function ()
		return ctx.frame:expandTemplate(model)
	end)
	return context_iterate(ctx, argc)
end


-- Syntax:  #invoke:params|mapping_by_invoking|module name|function
--            name|[call style]|[let]|[...]|[number of additional
--            arguments]|[argument 1]|[argument 2]|[...]|[argument N]|pipe to
library.mapping_by_invoking = function (ctx)
	local opts = ctx.pipe
	local mname
	local fname
	if opts[1] ~= nil then mname = opts[1]:match'^%s*(.*%S)' end
	if mname == nil then error(modulename ..
		', ‘mapping_by_invoking’: No module name was provided', 0) end
	if opts[2] ~= nil then fname = opts[2]:match'^%s*(.*%S)' end
	if fname == nil then error(modulename ..
		', ‘mapping_by_invoking’: No function name was provided', 0) end
	local margs, argc, looptype, karg, varg = load_callback_opts(opts, 2,
		mapping_styles.values_only)
	local model = { title = 'Module:' .. mname, args = margs }
	local mfunc = require(model.title)[fname]
	if mfunc == nil then error(modulename ..
		', ‘mapping_by_invoking’: The function ‘' .. fname ..
		'’ does not exist', 0) end
	value_maps[looptype](ctx.params, margs, karg, varg, function ()
		return tostring(mfunc(ctx.frame:newChild(model)))
	end)
	return context_iterate(ctx, argc)
end


-- Syntax:  #invoke:params|mapping_by_magic|parser function|[call
--            style]|[let]|[...][number of additional arguments]|[argument
--            1]|[argument 2]|[...]|[argument N]|pipe to
library.mapping_by_magic = function (ctx)
	local opts = ctx.pipe
	local magic
	if opts[1] ~= nil then magic = opts[1]:match'^%s*(.*%S)' end
	if magic == nil then error(modulename ..
		', ‘mapping_by_magic’: No parser function was provided', 0) end
	local margs, argc, looptype, karg, varg = load_callback_opts(opts, 1,
		mapping_styles.values_only)
	value_maps[looptype](ctx.params, margs, karg, varg, function ()
		return ctx.frame:callParserFunction(magic, margs)
	end)
	return context_iterate(ctx, argc)
end


-- Syntax:  #invoke:params|mapping_by_replacing|target|replace|[count]|[plain
--            flag]|pipe to
library.mapping_by_replacing = function (ctx)
	local ptn, repl, nmax, flg, argc, die =
		load_replace_args(ctx.pipe, 'mapping_by_replacing')
	if die then return context_iterate(ctx, argc) end
	local tbl = ctx.params
	if flg == 3 then
		for key, val in pairs(tbl) do
			if val == ptn then tbl[key] = repl end
		end
	else
		if flg == 2 then
			-- Copied from Module:String's `str._escapePattern()`
			ptn = ptn:gsub('[%(%)%.%%%+%-%*%?%[%^%$%]]', '%%%0')
		end
		for key, val in pairs(tbl) do
			tbl[key] = val:gsub(ptn, repl, nmax)
		end
	end
	return context_iterate(ctx, argc)
end


-- Syntax:  #invoke:params|mapping_by_mixing|mixing string|pipe to
library.mapping_by_mixing = function (ctx)
	if ctx.pipe[1] == nil then error(modulename ..
		', ‘mapping_by_mixing’: No mixing string was provided', 0) end
	local mix = ctx.pipe[1]
	local tbl = ctx.params
	if mix == '$#' then
		for key in pairs(tbl) do tbl[key] = key end
		return context_iterate(ctx, 2)
	end
	local skel, cnv, n_parts = parse_placeholder_string(mix)
	for key, val in pairs(tbl) do
		for idx = 2, n_parts, 2 do
			if skel[idx] then cnv[idx] = val else cnv[idx] = tostring(key) end
		end
		tbl[key] = table.concat(cnv)
	end
	return context_iterate(ctx, 2)
end


-- Syntax:  #invoke:params|mapping_to_names|pipe to
--[[
library.mapping_to_names = function (ctx)
	local tbl = ctx.params
	for key in pairs(tbl) do tbl[key] = key end
	return context_iterate(ctx, 1)
end
]]--


-- Syntax:  #invoke:params|converting_names_to_lowercase|pipe to
library.converting_names_to_lowercase = function (ctx)
	-- NOTE: `ctx.params` might be the original metatable! As a modifier,
	-- this function MUST create a copy of it before returning
	local cache = {}
	for key, val in pairs(ctx.params) do
		if type(key) == 'string' then cache[key:lower()] = val else
		cache[key] = val end
	end
	ctx.params = cache
	return context_iterate(ctx, 1)
end


-- Syntax:  #invoke:params|converting_names_to_uppercase|pipe to
library.converting_names_to_uppercase = function (ctx)
	-- NOTE: `ctx.params` might be the original metatable! As a modifier,
	-- this function MUST create a copy of it before returning
	local cache = {}
	for key, val in pairs(ctx.params) do
		if type(key) == 'string' then cache[key:upper()] = val else
		cache[key] = val end
	end
	ctx.params = cache
	return context_iterate(ctx, 1)
end


-- Syntax:  #invoke:params|renaming_by_calling|template name|[call
--            style]|[let]|[...][number of additional parameters]|[parameter
--            1]|[parameter 2]|[...]|[parameter N]|pipe to
library.renaming_by_calling = function (ctx)
	local opts = ctx.pipe
	local tname
	if opts[1] ~= nil then tname = opts[1]:match'^%s*(.*%S)' end
	if tname == nil then error(modulename ..
		', ‘renaming_by_calling’: No template name was provided', 0) end
	local rargs, argc, looptype, karg, varg = load_callback_opts(opts, 1,
		mapping_styles.names_only)
	local model = { title = tname, args = rargs }
	map_names(ctx.params, rargs, karg, varg, looptype, function ()
		return ctx.frame:expandTemplate(model)
	end)
	return context_iterate(ctx, argc)
end


-- Syntax:  #invoke:params|renaming_by_invoking|module name|function
--            name|[call style]|[let]|[...]|[number of additional
--            arguments]|[argument 1]|[argument 2]|[...]|[argument N]|pipe to
library.renaming_by_invoking = function (ctx)
	local opts = ctx.pipe
	local mname
	local fname
	if opts[1] ~= nil then mname = opts[1]:match'^%s*(.*%S)' end
	if mname == nil then error(modulename ..
		', ‘renaming_by_invoking’: No module name was provided', 0) end
	if opts[2] ~= nil then fname = opts[2]:match'^%s*(.*%S)' end
	if fname == nil then error(modulename ..
		', ‘renaming_by_invoking’: No function name was provided', 0) end
	local rargs, argc, looptype, karg, varg = load_callback_opts(opts, 2,
		mapping_styles.names_only)
	local model = { title = 'Module:' .. mname, args = rargs }
	local mfunc = require(model.title)[fname]
	if mfunc == nil then error(modulename ..
		', ‘renaming_by_invoking’: The function ‘' .. fname ..
		'’ does not exist', 0) end
	map_names(ctx.params, rargs, karg, varg, looptype, function ()
		local tmp = mfunc(ctx.frame:newChild(model))
		return tonumber(tmp) or tostring(tmp)
	end)
	return context_iterate(ctx, argc)
end


-- Syntax:  #invoke:params|renaming_by_magic|parser function|[call
--            style]|[let]|[...][number of additional arguments]|[argument
--            1]|[argument 2]|[...]|[argument N]|pipe to
library.renaming_by_magic = function (ctx)
	local opts = ctx.pipe
	local magic
	if opts[1] ~= nil then magic = opts[1]:match'^%s*(.*%S)' end
	if magic == nil then error(modulename ..
		', ‘renaming_by_magic’: No parser function was provided', 0) end
	local rargs, argc, looptype, karg, varg = load_callback_opts(opts, 1,
		mapping_styles.names_only)
	map_names(ctx.params, rargs, karg, varg, looptype, function ()
		return ctx.frame:callParserFunction(magic, rargs)
	end)
	return context_iterate(ctx, argc)
end


-- Syntax:  #invoke:params|renaming_by_replacing|target|replace|[count]|[plain
--            flag]|pipe to
library.renaming_by_replacing = function (ctx)
	local ptn, repl, nmax, flg, argc, die =
		load_replace_args(ctx.pipe, 'renaming_by_replacing')
	if die then return context_iterate(ctx, argc) end
	local tbl = ctx.params
	if flg == 3 then
		local key = tonumber(ptn) or ptn:match'^%s*(.-)%s*$'
		local val = tbl[key]
		if val ~= nil then
			tbl[key] = nil
			tbl[tonumber(repl) or repl:match'^%s*(.-)%s*$'] = val
		end
	else
		if flg == 2 then
			-- Copied from Module:String's `str._escapePattern()`
			ptn = ptn:gsub('[%(%)%.%%%+%-%*%?%[%^%$%]]', '%%%0')
		end
		local cache = {}
		for key, val in pairs(tbl) do
			steal_if_renamed(val, tbl, key, cache,
				tostring(key):gsub(ptn, repl, nmax))
		end
		for key, val in pairs(cache) do tbl[key] = val end
	end
	return context_iterate(ctx, argc)
end


-- Syntax:  #invoke:params|renaming_by_mixing|mixing string|pipe to
library.renaming_by_mixing = function (ctx)
	-- NOTE: `ctx.params` might be the original metatable! As a modifier,
	-- this function MUST create a copy of it before returning
	if ctx.pipe[1] == nil then error(modulename ..
		', ‘renaming_by_mixing’: No mixing string was provided', 0) end
	local mix = ctx.pipe[1]:match'^%s*(.-)%s*$'
	local cache = {}
	if mix == '$@' then
		for _, val in pairs(ctx.params) do cache[val] = val end
	else
		local skel, canvas, n_parts = parse_placeholder_string(mix)
		local tmp
		for key, val in pairs(ctx.params) do
			for idx = 2, n_parts, 2 do
				if skel[idx] then canvas[idx] = val
				else canvas[idx] = tostring(key) end
			end
			tmp = table.concat(canvas)
			cache[tonumber(tmp) or tmp] = val
		end
	end
	ctx.params = cache
	return context_iterate(ctx, 2)
end


-- Syntax:  #invoke:params|renaming_to_values|pipe to
--[[
library.renaming_to_values = function (ctx)
	-- NOTE: `ctx.params` might be the original metatable! As a modifier,
	-- this function MUST create a copy of it before returning
	local cache = {}
	for _, val in pairs(ctx.params) do cache[val] = val end
	ctx.params = cache
	return context_iterate(ctx, 1)
end
]]--


-- Syntax:  #invoke:params|grouping_by_calling|template
--            name|[let]|[...]|[number of additional arguments]|[argument
--            1]|[argument 2]|[...]|[argument N]|pipe to
library.grouping_by_calling = function (ctx)
	-- NOTE: `ctx.params` might be the original metatable! As a modifier,
	-- this function MUST create a copy of it before returning
	local opts = ctx.pipe
	local tmp
	if opts[1] ~= nil then tmp = opts[1]:match'^%s*(.*%S)' end
	if tmp == nil then error(modulename ..
		', ‘grouping_by_calling’: No template name was provided', 0) end
	local model = { title = tmp }
	local tmp, argc = load_child_opts(opts, 2, 0)
	local gargs = {}
	for key, val in pairs(tmp) do
		if type(key) == 'number' and key < 1 then gargs[key - 1] = val
		else gargs[key] = val end
	end
	local groups = make_groups(ctx.params)
	for gid, group in pairs(groups) do
		for key, val in pairs(gargs) do group[key] = val end
		group[0] = gid
		model.args = group
		groups[gid] = ctx.frame:expandTemplate(model)
	end
	ctx.params = groups
	return context_iterate(ctx, argc)
end


-- 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


-- 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|mixing_names_and_values|mixing string|pipe to
library.mixing_names_and_values = function (ctx)
	-- NOTE: `ctx.params` might be the original metatable! As a modifier,
	-- this function MUST create a copy of it before returning
	if ctx.pipe[1] == nil then error(modulename ..
		', ‘mixing_names_and_values’: No mixing string was provided for parameter names', 0) end
	if ctx.pipe[2] == nil then error(modulename ..
		', ‘mixing_names_and_values’: No mixing string was provided for parameter values', 0) end
	local mix_k = ctx.pipe[1]:match'^%s*(.-)%s*$'
	local mix_v = ctx.pipe[2]
	local cache = {}
	if mix_k == '$@' and mix_v == '$@' then
		for _, val in pairs(ctx.params) do cache[val] = val end
	elseif mix_k == '$@' and mix_v == '$#' then
		for key, val in pairs(ctx.params) do cache[val] = key end
	elseif mix_k == '$#' and mix_v == '$#' then
		for _, val in pairs(ctx.params) do cache[key] = key end
	else
		local skel_k, cnv_k, n_parts_k = parse_placeholder_string(mix_k)
		local skel_v, cnv_v, n_parts_v = parse_placeholder_string(mix_v)
		local tmp
		for key, val in pairs(ctx.params) do
			tmp = tostring(key)
			for idx = 2, n_parts_k, 2 do
				if skel_k[idx] then cnv_k[idx] = val else cnv_k[idx] = tmp end
			end
			for idx = 2, n_parts_v, 2 do
				if skel_v[idx] then cnv_v[idx] = val else cnv_v[idx] = tmp end
			end
			tmp = table.concat(cnv_k)
			cache[tonumber(tmp) or tmp] = table.concat(cnv_v)
		end
	end
	ctx.params = cache
	return context_iterate(ctx, 3)
end


-- Syntax:  #invoke:params|swapping_names_and_values|pipe to
--[[
library.swapping_names_and_values = function (ctx)
	-- NOTE: `ctx.params` might be the original metatable! As a modifier,
	-- this function MUST create a copy of it before returning
	local cache = {}
	for key, val in pairs(ctx.params) do cache[val] = key end
	ctx.params = cache
	return context_iterate(ctx, 1)
end
]]--


-- Syntax:  #invoke:params|combining_by_calling|template name|new parameter
--            name|pipe to
library.combining_by_calling = function (ctx)
	-- NOTE: `ctx.params` might be the original metatable! As a modifier,
	-- this function MUST create a copy of it before returning
	local tname = ctx.pipe[1]
	if tname ~= nil then tname = tname:match'^%s*(.*%S)'
	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


-- Syntax:  #invoke:params|snapshotting|pipe to
library.snapshotting = function (ctx)
	push_cloned_stack(ctx, ctx.params)
	return context_iterate(ctx, 1)
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
	if opts[1] == nil then error(modulename ..
		', ‘pulling’: No parameter to pull was provided', 0) end
	local parent
	local tmp = ctx.n_parents
	if tmp < 1 then parent = ctx.oparams else parent = ctx.parents[tmp] end
	tmp = tonumber(opts[1]) or opts[1]:match'^%s*(.-)%s*$'
	if parent[tmp] ~= nil then ctx.params[tmp] = parent[tmp] end
	return context_iterate(ctx, 2)
end


-- Syntax:  #invoke:params|detaching_substack|pipe to
library.detaching_substack = function (ctx)
	local ncurrparent = ctx.n_parents
	if ncurrparent < 1 then error(modulename ..
		', ‘detaching_substack’: No substack has been created', 0) end
	local parent = ctx.parents[ncurrparent]
	for key in pairs(ctx.params) do parent[key] = nil end
	return context_iterate(ctx, 1)
end


-- Syntax:  #invoke:params|leaving_substack|pipe to
library.leaving_substack = function (ctx)
	local ncurrparent = ctx.n_parents
	if ncurrparent < 1 then error(modulename ..
		', ‘leaving_substack’: No substack has been created', 0) end
	local currsnap = ctx.n_children + 1
	if ctx.children == nil then ctx.children = { ctx.params }
	else ctx.children[currsnap] = ctx.params end
	ctx.params = ctx.parents[ncurrparent]
	ctx.parents[ncurrparent] = nil
	ctx.n_parents = ncurrparent - 1
	ctx.n_children = currsnap
	return context_iterate(ctx, 1)
end


-- Syntax:  #invoke:params|merging_substack|pipe to
library.merging_substack = function (ctx)
	local ncurrparent = ctx.n_parents
	if ncurrparent < 1 then error(modulename ..
		', ‘merging_substack’: No substack has been created', 0) end
	local parent = ctx.parents[ncurrparent]
	local child = ctx.params
	ctx.params = parent
	ctx.parents[ncurrparent] = nil
	ctx.n_parents = ncurrparent - 1
	for key, val in pairs(child) do parent[key] = val end
	return context_iterate(ctx, 1)
end


-- Syntax:  #invoke:params|flushing|pipe to
library.flushing = function (ctx)
	if ctx.n_children < 1 then error(modulename ..
		', ‘flushing’: There are no substacks to flush', 0) end
	local parent = ctx.params
	local currsnap = ctx.n_children
	for key, val in pairs(ctx.children[currsnap]) do parent[key] = val end
	ctx.children[currsnap] = nil
	ctx.n_children = currsnap - 1
	return context_iterate(ctx, 1)
end



	--[[ Functions ]]--
	-----------------------------


-- Syntax:  #invoke:params|count
library.count = function (ctx)
	-- NOTE: `ctx.pipe` and `ctx.params` might be the original metatables!
	local retval = 0
	for _ in ctx.iterfunc(ctx.params) do retval = retval + 1 end
	if ctx.subset == -1 then retval = retval - #ctx.params end
	ctx.text = retval
	return 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]|[...]
library.concat_and_call = function (ctx)
	-- NOTE: `ctx.params` might be the original metatable!
	local opts = ctx.pipe
	local tname
	if opts[1] ~= nil then tname = opts[1]:match'^%s*(.*%S)' end
	if tname == nil then error(modulename ..
		', ‘concat_and_call’: No template name was provided', 0) end
	remove_numeric_keys(opts, 1, 1)
	ctx.text = ctx.frame:expandTemplate{
		title = tname,
		args = concat_params(ctx)
	}
	return false
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]|[...]
library.concat_and_invoke = function (ctx)
	-- NOTE: `ctx.params` might be the original metatable!
	local opts = ctx.pipe
	local mname
	local fname
	if opts[1] ~= nil then mname = opts[1]:match'^%s*(.*%S)' end
	if mname == nil then error(modulename ..
		', ‘concat_and_invoke’: No module name was provided', 0) end
	if opts[2] ~= nil then fname = opts[2]:match'^%s*(.*%S)' end
	if fname == nil then error(modulename ..
		', ‘concat_and_invoke’: No function name was provided', 0) end
	remove_numeric_keys(opts, 1, 2)
	local mfunc = require('Module:' .. mname)[fname]
	if mfunc == nil then error(modulename ..
		', ‘concat_and_invoke’: The function ‘' .. fname ..
		'’ does not exist', 0) end
	ctx.text = mfunc(ctx.frame:newChild{
		title = 'Module:' .. mname,
		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
	return library.list_values(ctx)
end


-- Syntax:  #invoke:params|for_each|wikitext
library.for_each = function (ctx)
	-- NOTE: `ctx.pipe` might be the original metatable!
	local txt = ctx.pipe[1] or ''
	local pps = ctx.itersep or ''
	local ret = {}
	local nss = 0
	local skel, cnv, n_parts = parse_placeholder_string(txt)
	flush_params(
		ctx,
		function (key, val)
			for idx = 2, n_parts, 2 do
				if skel[idx] then cnv[idx] = val
				else cnv[idx] = tostring(key) end
			end
			ret[nss + 1] = pps
			ret[nss + 2] = table.concat(cnv)
			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|call_for_each|template name|[append 1]|[append 2]
--            |[...]|[append n]|[named param 1=value 1]|[...]|[named param
--            n=value n]|[...]
library.call_for_each = function (ctx)
	local opts = ctx.pipe
	local tname
	if opts[1] ~= nil then tname = opts[1]:match'^%s*(.*%S)' end
	if tname == nil then error(modulename ..
		', ‘call_for_each’: No template name was provided', 0) end
	local model = { title = tname, args = opts }
	local ccs = ctx.itersep or ''
	local ret = {}
	local nss = 0
	table.insert(opts, 1, true)
	flush_params(
		ctx,
		function (key, val)
			opts[1] = key
			opts[2] = val
			ret[nss + 1] = ccs
			ret[nss + 2] = ctx.frame:expandTemplate(model)
			nss = nss + 2
		end
	)
	if nss > 0 then
		if nss > 2 and ctx.lastsep ~= nil then
			ret[nss - 1] = ctx.lastsep
		end
		ret[1] = ctx.header or ''
		if ctx.footer ~= nil then ret[nss + 1] = ctx.footer end
		ctx.text = table.concat(ret)
		return false
	end
	ctx.text = ctx.ifngiven or ''
	return 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]|[...]
library.invoke_for_each = function (ctx)
	local opts = ctx.pipe
	local mname
	local fname
	if opts[1] ~= nil then mname = opts[1]:match'^%s*(.*%S)' end
	if mname == nil then error(modulename ..
		', ‘invoke_for_each’: No module name was provided', 0) end
	if opts[2] ~= nil then fname = opts[2]:match'^%s*(.*%S)' end
	if fname == nil then error(modulename ..
		', ‘invoke_for_each’: No function name was provided', 0) end
	local model = { title = 'Module:' .. mname, args = opts }
	local mfunc = require(model.title)[fname]
	local ccs = ctx.itersep or ''
	local ret = {}
	local nss = 0
	flush_params(
		ctx,
		function (key, val)
			opts[1] = key
			opts[2] = val
			ret[nss + 1] = ccs
			ret[nss + 2] = mfunc(ctx.frame:newChild(model))
			nss = nss + 2
		end
	)
	if nss > 0 then
		if nss > 2 and ctx.lastsep ~= nil then
			ret[nss - 1] = ctx.lastsep
		end
		ret[1] = ctx.header or ''
		if ctx.footer ~= nil then ret[nss + 1] = ctx.footer end
		ctx.text = table.concat(ret)
		return false
	end
	ctx.text = ctx.ifngiven or ''
	return 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]|[...]
library.magic_for_each = function (ctx)
	local opts = ctx.pipe
	local magic
	if opts[1] ~= nil then magic = opts[1]:match'^%s*(.*%S)' end
	if magic == nil then error(modulename ..
		', ‘magic_for_each’: No parser function was provided', 0) end
	local ccs = ctx.itersep or ''
	local ret = {}
	local nss = 0
	table.insert(opts, 1, true)
	flush_params(
		ctx,
		function (key, val)
			opts[1] = key
			opts[2] = val
			ret[nss + 1] = ccs
			ret[nss + 2] = ctx.frame:callParserFunction(magic, opts)
			nss = nss + 2
		end
	)
	if nss > 0 then
		if nss > 2 and ctx.lastsep ~= nil then
			ret[nss - 1] = ctx.lastsep
		end
		ret[1] = ctx.header or ''
		if ctx.footer ~= nil then ret[nss + 1] = ctx.footer end
		ctx.text = table.concat(ret)
		return false
	end
	ctx.text = ctx.ifngiven or ''
	return 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]|[...]
library.call_for_each_value = function (ctx)
	local opts = ctx.pipe
	local tname
	if opts[1] ~= nil then tname = opts[1]:match'^%s*(.*%S)' end
	if tname == nil then error(modulename ..
		', ‘call_for_each_value’: No template name was provided', 0) end
	local model = { title = tname, args = opts }
	local ccs = ctx.itersep or ''
	local ret = {}
	local nss = 0
	flush_params(
		ctx,
		function (key, val)
			opts[1] = val
			ret[nss + 1] = ccs
			ret[nss + 2] = ctx.frame:expandTemplate(model)
			nss = nss + 2
		end
	)
	if nss > 0 then
		if nss > 2 and ctx.lastsep ~= nil then
			ret[nss - 1] = ctx.lastsep
		end
		ret[1] = ctx.header or ''
		if ctx.footer ~= nil then ret[nss + 1] = ctx.footer end
		ctx.text = table.concat(ret)
		return false
	end
	ctx.text = ctx.ifngiven or ''
	return 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]|[...]
library.invoke_for_each_value = function (ctx)
	local opts = ctx.pipe
	local mname
	local fname
	if opts[1] ~= nil then mname = opts[1]:match'^%s*(.*%S)' end
	if mname == nil then error(modulename ..
		', ‘invoke_for_each_value’: No module name was provided', 0) end
	if opts[2] ~= nil then fname = opts[2]:match'^%s*(.*%S)' end
	if fname == nil then error(modulename ..
		', ‘invoke_for_each_value’: No function name was provided', 0) end
	local model = { title = 'Module:' .. mname, args = opts }
	local mfunc = require(model.title)[fname]
	local ccs = ctx.itersep or ''
	local ret = {}
	local nss = 0
	remove_numeric_keys(opts, 1, 1)
	flush_params(
		ctx,
		function (key, val)
			opts[1] = val
			ret[nss + 1] = ccs
			ret[nss + 2] = mfunc(ctx.frame:newChild(model))
			nss = nss + 2
		end
	)
	if nss > 0 then
		if nss > 2 and ctx.lastsep ~= nil then
			ret[nss - 1] = ctx.lastsep
		end
		ret[1] = ctx.header or ''
		if ctx.footer ~= nil then ret[nss + 1] = ctx.footer end
		ctx.text = table.concat(ret)
		return false
	end
	ctx.text = ctx.ifngiven or ''
	return 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]|[...]
library.magic_for_each_value = function (ctx)
	local opts = ctx.pipe
	local magic
	if opts[1] ~= nil then magic = opts[1]:match'^%s*(.*%S)' end
	if magic == nil then error(modulename ..
		', ‘magic_for_each_value’: No parser function was provided', 0) end
	local ccs = ctx.itersep or ''
	local ret = {}
	local nss = 0
	flush_params(
		ctx,
		function (key, val)
			opts[1] = val
			ret[nss + 1] = ccs
			ret[nss + 2] = ctx.frame:callParserFunction(magic, opts)
			nss = nss + 2
		end
	)
	if nss > 0 then
		if nss > 2 and ctx.lastsep ~= nil then
			ret[nss - 1] = ctx.lastsep
		end
		ret[1] = ctx.header or ''
		if ctx.footer ~= nil then ret[nss + 1] = ctx.footer end
		ctx.text = table.concat(ret)
		return false
	end
	ctx.text = ctx.ifngiven or ''
	return false
end


-- Syntax:  #invoke:params|call_for_each_group|template name|[append 1]|[append
--            2]|[...]|[append n]|[named param 1=value 1]|[...]|[named param
--            n=value n]|[...]
library.call_for_each_group = function (ctx)
	-- NOTE: `ctx.pipe` and `ctx.params` might be the original metatables!
	local opts = ctx.pipe
	local tmp
	if opts[1] ~= nil then tmp = opts[1]:match'^%s*(.*%S)' end
	if tmp == nil then error(modulename ..
		', ‘call_for_each_group’: No template name was provided', 0) end
	local model = { title = tmp }
	local ccs = ctx.itersep or ''
	local nss = 0
	local ret = {}
	opts = {}
	for key, val in pairs(ctx.pipe) do
		if type(key) == 'number' then opts[key - 1] = val
		else opts[key] = val end
	end
	ctx.pipe = opts
	ctx.params = make_groups(ctx.params)
	flush_params(
		ctx,
		function (gid, group)
			for key, val in pairs(opts) do group[key] = val end
			group[0] = gid
			model.args = group
			ret[nss + 1] = ccs
			ret[nss + 2] = ctx.frame:expandTemplate(model)
			nss = nss + 2
		end
	)
	if nss > 0 then
		if nss > 2 and ctx.lastsep ~= nil then
			ret[nss - 1] = ctx.lastsep
		end
		ret[1] = ctx.header or ''
		if ctx.footer ~= nil then ret[nss + 1] = ctx.footer end
		ctx.text = table.concat(ret)
		return false
	end
	ctx.text = ctx.ifngiven or ''
	return false
end



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



	--[[ First-position-only modifiers ]]--
	---------------------------------------


-- Syntax:  #invoke:params|new|pipe to
static_iface.new = function (frame)
	local ctx = context_new(frame:getParent())
	ctx.pipe = copy_or_ref_table(frame.args, false)
	ctx.params = {}
	main_loop(ctx, context_iterate(ctx, 1))
	return ctx.text
end



	--[[ First-position-only functions ]]--
	---------------------------------------


-- Syntax:  #invoke:params|self
static_iface.self = function (frame)
	return frame:getParent():getTitle()
end



	--[[ Public metatable of functions ]]--
	---------------------------------------


return setmetatable({}, {
	__index = function (_, query)
		local fname = query:match'^%s*(.*%S)'
		if fname == nil then error(modulename ..
			': You must specify a function to call', 0) end
		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
		return function (frame)
			local ctx = context_new(frame:getParent())
			ctx.pipe = copy_or_ref_table(frame.args, refpipe[fname])
			ctx.params = copy_or_ref_table(ctx.oparams, refparams[fname])
			main_loop(ctx, func)
			return ctx.text
		end
	end
})