Jump to content

Module:Params

Permanently protected module
From Wikipedia, the free encyclopedia

--- ------ LOCAL ENVIRONMENT ------ ________________________________ ------ -----[[ Abstract utilities ]]-------------------------------- Helper function for `string.gsub()` (for managing zero-padded numbers)localfunctionzero_padded(str)return('%03d%s'):format(#str,str)end-- Helper function for `table.sort()` (for natural sorting)localfunctionnatural_sort(var1,var2)returntostring(var1):gsub('%d+',zero_padded)<tostring(var2):gsub('%d+',zero_padded)end-- Return a copy or a reference to a tablelocalfunctioncopy_or_ref_table(src,refonly)ifrefonlythenreturnsrcendnewtab={}forkey,valinpairs(src)donewtab[key]=valendreturnnewtabend-- Remove some numeric elements from a table, shifting everything to the leftlocalfunctionremove_numeric_keys(tbl,idx,len)localcache={}localtmp=idx+len-1forkey,valinpairs(tbl)doiftype(key)=='number'andkey>=idxthenifkey>tmpthencache[key-len]=valendtbl[key]=nilendendforkey,valinpairs(cache)dotbl[key]=valendend-- Make a reduced copy of a table (shifting in both directions if necessary)localfunctioncopy_table_reduced(tbl,idx,len)localret={}localtmp=idx+len-1ifidx>0thenforkey,valinpairs(tbl)doiftype(key)~='number'orkey<idxthenret[key]=valelseifkey>tmpthenret[key-len]=valendendelseiftmp>0thenlocalnshift=1-idxforkey,valinpairs(tbl)doiftype(key)~='number'thenret[key]=valelseifkey>tmpthenret[key-tmp]=valelseifkey<idxthenret[key+nshift]=valendendelseforkey,valinpairs(tbl)doiftype(key)~='number'orkey>tmpthenret[key]=valelseifkey<idxthenret[key+len]=valendendendreturnretend-- 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 retend]]---- Move a key from a table to another, but only if under a different name and-- always parsing numeric strings as numberslocalfunctionsteal_if_renamed(val,src,skey,dest,dkey)localrealkey=tonumber(dkey)ordkey:match'^%s*(.-)%s*$'ifskey~=realkeythendest[realkey]=valsrc[skey]=nilendend--[[ Public strings ]]---------------------------- Special match keywords (functions and modifiers MUST avoid these names)localmkeywords={['or']=0,pattern=1,plain=2,strict=3}-- Sort functions (functions and modifiers MUST avoid these names)localsortfunctions={--alphabetically = false, -- Simply uncommenting enables the optionnaturally=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`)]]--localmapping_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)localmemoryslots={i='itersep',l='lastsep',p='pairsep',h='header',f='footer',n='ifngiven'}-- Possible trimming modes for the `parsing` modifierlocaltrim_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` modifierslocalisep_parse_opts={splitter_pattern=false,splitter_string=true}-- Possible string modes for the key-value separator in the `parsing` and-- `reinterpreting` modifierslocalpsep_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()`)localmodulename='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 availablelocalrefpipe={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 availablelocalrefparams={call_for_each_group=true,combining_by_calling=true,concat_and_call=true,concat_and_invoke=true,concat_and_magic=true,count=true,--inserting = true,grouping_by_calling=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)localmaxfill=1024-- The private table of functionslocallibrary={}-- Functions and modifiers that can only be invoked in first positionlocalstatic_iface={}-- Create a new contextlocalfunctioncontext_new(frame)localctx={}ctx.frame=framectx.oparams=frame.argsctx.firstposonly=static_ifacectx.iterfunc=pairsctx.sorttype=0ctx.n_parents=0ctx.n_children=0ctx.n_available=maxfillreturnctxend-- Move to the next action within the user-given listlocalfunctioncontext_iterate(ctx,n_forward)localnextfnifctx.pipe[n_forward]~=nilthennextfn=ctx.pipe[n_forward]:match'^%s*(.*%S)'endifnextfn==nilthenerror(modulename..': You must specify a function to call',0)endiflibrary[nextfn]==nilthenifctx.firstposonly[nextfn]==nilthenerror(modulename..': The function ‘'..nextfn..'’ does not exist',0)elseerror(modulename..': The ‘'..nextfn..'’ directive can only appear in first position',0)endendremove_numeric_keys(ctx.pipe,1,n_forward)returnlibrary[nextfn]end-- Main looplocalfunctionmain_loop(ctx,start_with)localfn=start_withrepeatfn=fn(ctx)untilnotfnifctx.n_parents>0thenerror(modulename..': One or more ‘merging_substack’ directives are missing',0)endifctx.n_children>0thenerror(modulename..', For some of the snapshots either the ‘flushing’ directive is missing or a group has not been properly closed with ‘merging_substack’',0)endend-- Add a new stack of parameters to `ctx.children`localfunctionpush_cloned_stack(ctx,tbl)localnewparams={}localcurrsnap=ctx.n_children+1ifctx.children==nilthenctx.children={newparams}elsectx.children[currsnap]=newparamsendforkey,valinpairs(tbl)donewparams[key]=valendctx.n_children=currsnapend-- Parse optional user arguments of type `...|[let]|[...][number of additional-- parameters]|[parameter 1]|[parameter 2]|[...]`localfunctionload_child_opts(src,start_from,append_after)localnameslocaltmplocaltbl={}localpin=start_fromifsrc[pin]~=nilandsrc[pin]:match'^%s*let%s*$'thennames={}repeattmp=src[pin+1]or''names[tonumber(tmp)ortmp:match'^%s*(.-)%s*$'or'']=src[pin+2]pin=pin+3untilsrc[pin]==nilornotsrc[pin]:match'^%s*let%s*$'endtmp=tonumber(src[pin])iftmp~=niltheniftmp<0thentmp=-1endlocalshf=append_after-pinforidx=pin+1,pin+tmpdotbl[idx+shf]=src[idx]endpin=pin+tmp+1endifnames~=nilthenforkey,valinpairs(names)dotbl[key]=valendendreturntbl,pinend-- Load the optional arguments of some of the `mapping_*` and `renaming_*`-- class of modifierslocalfunctionload_callback_opts(src,n_skip,default_style)localstylelocalshflocaltmp=src[n_skip+1]iftmp~=nilthenstyle=mapping_styles[tmp:match'^%s*(.-)%s*$']endifstyle==nilthenstyle=default_styleshf=n_skip-1elseshf=n_skipendlocaln_exist=style[3]localkarg=style[4]localvarg=style[5]tmp=style[6]iftmp>-1thentmp=src[tmp+shf]karg=tonumber(tmp)ifkarg==nilthenkarg=tmp:match'^%s*(.-)%s*$'elsen_exist=math.max(n_exist,karg)endendtmp=style[7]iftmp>-1thentmp=src[tmp+shf]varg=tonumber(tmp)ifvarg==nilthenvarg=tmp:match'^%s*(.-)%s*$'elsen_exist=math.max(n_exist,varg)endendlocaldest,nargs=load_child_opts(src,style[2]+shf,n_exist)tmp=style[1]if(tmp==3ortmp==2)anddest[karg]~=nilthentmp=tmp-2endif(tmp==3ortmp==1)anddest[varg]~=nilthentmp=tmp-1endreturndest,nargs,tmp,karg,vargend-- Parse the arguments of some of the `mapping_*` and `renaming_*` class of-- modifierslocalfunctionload_replace_args(opts,fname)ifopts[1]==nilthenerror(modulename..', ‘'..fname..'’: No pattern string was given',0)endifopts[2]==nilthenerror(modulename..', ‘'..fname..'’: No replacement string was given',0)endlocalptn=opts[1]localrepl=opts[2]localargc=3localnmax=tonumber(opts[3])ifnmax~=nilor(opts[3]or''):match'^%s*$'~=nilthenargc=4endlocalflg=opts[argc]ifflg~=nilthenflg=mkeywords[flg:match'^%s*(.-)%s*$']endifflg==0thenflg=nilelseifflg~=nilthenargc=argc+1endreturnptn,repl,nmax,flg==3,argc,(nmax~=nilandnmax<1)or(flg==3andptn==repl)end-- Parse the arguments of the `with_*_matching` class of modifierslocalfunctionload_pattern_args(opts,fname)localstate=0localcnt=1localkeywlocalnptns=0localptns={}for_,valinipairs(opts)doifstate==0thennptns=nptns+1ptns[nptns]={val,false,false}state=-1elsekeyw=val:match'^%s*(.*%S)'ifkeyw==nilormkeywords[keyw]==nilor(state>0andmkeywords[keyw]>0)thenbreakelsestate=mkeywords[keyw]ifstate>1thenptns[nptns][2]=trueendifstate==3thenptns[nptns][3]=trueendendendcnt=cnt+1endifstate==0thenerror(modulename..', ‘'..fname..'’: No pattern was given',0)endreturnptns,nptns,cntend-- Load the optional arguments of the `parsing` and `reinterpreting` modifierslocalfunctionload_parse_opts(opts,start_from)localargc=start_fromlocaltmplocaloptslots={true,true,true}localnoptslots=3localtrimn=truelocaltrimu=falselocaliplain=truelocalpplain=truelocalisp='|'localpsp='='repeatnoptslots=noptslots-1tmp=opts[argc]iftmp==nilthenbreakendtmp=tmp:match'^%s*(.-)%s*$'ifoptslots[1]~=nilandtrim_parse_opts[tmp]~=nilthentmp=trim_parse_opts[tmp]trimn=tmp[1]trimu=tmp[2]optslots[1]=nilelseifoptslots[2]~=nilandisep_parse_opts[tmp]~=nilthenargc=argc+1iplain=isep_parse_opts[tmp]isp=opts[argc]optslots[2]=nilelseifoptslots[3]~=nilandpsep_parse_opts[tmp]~=nilthenargc=argc+1pplain=psep_parse_opts[tmp]psp=opts[argc]optslots[3]=nilelsebreakendargc=argc+1untilnoptslots<1returnisp,iplain,psp,pplain,trimn,trimu,argcend-- Map parameters' values using a custom callback and a referenced tablelocalvalue_maps={[0]=function(tbl,margs,karg,varg,fn)forkeyinpairs(tbl)dotbl[key]=fn()endend,[1]=function(tbl,margs,karg,varg,fn)forkey,valinpairs(tbl)domargs[varg]=valtbl[key]=fn()endend,[2]=function(tbl,margs,karg,varg,fn)forkeyinpairs(tbl)domargs[karg]=keytbl[key]=fn()endend,[3]=function(tbl,margs,karg,varg,fn)forkey,valinpairs(tbl)domargs[karg]=keymargs[varg]=valtbl[key]=fn()endend}-- Private table for `map_names()`localname_thieves_maps={[0]=function(cache,tbl,rargs,karg,varg,fn)forkey,valinpairs(tbl)dosteal_if_renamed(val,tbl,key,cache,fn())endend,[1]=function(cache,tbl,rargs,karg,varg,fn)forkey,valinpairs(tbl)dorargs[varg]=valsteal_if_renamed(val,tbl,key,cache,fn())endend,[2]=function(cache,tbl,rargs,karg,varg,fn)forkey,valinpairs(tbl)dorargs[karg]=keysteal_if_renamed(val,tbl,key,cache,fn())endend,[3]=function(cache,tbl,rargs,karg,varg,fn)forkey,valinpairs(tbl)dorargs[karg]=keyrargs[varg]=valsteal_if_renamed(val,tbl,key,cache,fn())endend}-- Map parameters' names using a custom callback and a referenced tablelocalfunctionmap_names(tbl,rargs,karg,varg,looptype,fn)localcache={}name_thieves_maps[looptype](cache,tbl,rargs,karg,varg,fn)forkey,valinpairs(cache)dotbl[key]=valendend-- Return a new table that contains `src` regrouped according to the numeric-- suffixes in its keyslocalfunctionmake_groups(src)-- NOTE: `src` might be the original metatable!localtmplocalprefixlocalgidlocalgroups={}forkey,valinpairs(src)do-- `key` must only be a string or a number...gid=tonumber(key)ifgid==nilthenprefix,gid=key:match'^%s*(.-)%s*(%-?%d*)%s*$'gid=tonumber(gid)or''elseprefix=''endifgroups[gid]==nilthengroups[gid]={}endtmp=tonumber(prefix)iftmp~=niltheniftmp<1thenprefix=tmp-1elseprefix=tmpendendgroups[gid][prefix]=valendreturngroupsend-- Populate a table by parsing a parameter stringlocalfunctionparse_parameter_string(tbl,str,isp,ipl,psp,ppl,trn,tru)localkeylocalvallocalspos1localspos2localpos1localpos2localpos3=0localidx=1locallenplone=#str+1ifisp==nilorisp==''thenifpsp==nilorpsp==''theniftruthentbl[idx]=str:match'^%s*(.-)%s*$'elsetbl[idx]=strendreturntblendspos1,spos2=str:find(psp,1,ppl)ifspos1==nilthenkey=idxiftruthenval=str:match'^%s*(.-)%s*$'elseval=strendidx=idx+1elsekey=str:sub(1,spos1-1)key=tonumber(key)orkey:match'^%s*(.-)%s*$'val=str:sub(spos2+1)iftrnthenval=val:match'^%s*(.-)%s*$'endendtbl[key]=valreturntblendifpsp==nilorpsp==''thenrepeatpos1=pos3+1pos2,pos3=str:find(isp,pos1,ipl)val=str:sub(pos1,(pos2orlenplone)-1)iftruthenval=val:match'^%s*(.-)%s*$'endtbl[idx]=validx=idx+1untilpos2==nilreturntblendrepeatpos1=pos3+1pos2,pos3=str:find(isp,pos1,ipl)val=str:sub(pos1,(pos2orlenplone)-1)spos1,spos2=val:find(psp,1,ppl)ifspos1==nilthenkey=idxiftruthenval=val:match'^%s*(.-)%s*$'endidx=idx+1elsekey=val:sub(1,spos1-1)key=tonumber(key)orkey:match'^%s*(.-)%s*$'val=val:sub(spos2+1)iftrnthenval=val:match'^%s*(.-)%s*$'endendtbl[key]=valuntilpos2==nilreturntblend-- 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 parameterslocalfunctionconcat_params(ctx)localtbl=ctx.paramslocalnmax=table.maxn(ctx.pipe)localretval={}ifctx.subset==1then-- We need only the sequenceforkey,valinipairs(tbl)doretval[key+nmax]=valendelseifctx.subset==-1thenforkeyinipairs(tbl)dotbl[key]=nilendendforkey,valinpairs(tbl)doiftype(key)=='number'andkey>0thenretval[key+nmax]=valelseretval[key]=valendendendforkey,valinpairs(ctx.pipe)doretval[key]=valendreturnretvalend-- Flush the parameters by calling a custom function for each value (after this-- function has been invoked `ctx.params` will be no longer usable)localfunctionflush_params(ctx,fn)localtbl=ctx.paramsifctx.subset==1thenforkey,valinipairs(tbl)dofn(key,val)endreturnendifctx.subset==-1thenforkey,valinipairs(tbl)dotbl[key]=nilendendifctx.sorttype>0thenlocalnums={}localwords={}localnn=0localnw=0forkey,valinpairs(tbl)doiftype(key)=='number'thennn=nn+1nums[nn]=keyelsenw=nw+1words[nw]=keyendendtable.sort(nums)table.sort(words,natural_sort)ifctx.sorttype==2thenforidx=1,nwdofn(words[idx],tbl[words[idx]])endforidx=1,nndofn(nums[idx],tbl[nums[idx]])endreturnendforidx=1,nndofn(nums[idx],tbl[nums[idx]])endforidx=1,nwdofn(words[idx],tbl[words[idx]])endreturnendifctx.subset~=-1thenforkey,valinipairs(tbl)dofn(key,val)tbl[key]=nilendendforkey,valinpairs(tbl)dofn(key,val)endend--[[ Modifiers ]]--------------------------------- Syntax: #invoke:params|sequential|pipe tolibrary.sequential=function(ctx)ifctx.subset==-1thenerror(modulename..': The two directives ‘non-sequential’ and ‘sequential’ are in contradiction with each other',0)endifctx.sorttype>0thenerror(modulename..': The ‘all_sorted’ and ‘reassorted’ directives are redundant when followed by ‘sequential’',0)endctx.iterfunc=ipairsctx.subset=1returncontext_iterate(ctx,1)end-- Syntax: #invoke:params|non-sequential|pipe tolibrary['non-sequential']=function(ctx)ifctx.subset==1thenerror(modulename..': The two directives ‘sequential’ and ‘non-sequential’ are in contradiction with each other',0)endctx.iterfunc=pairsctx.subset=-1returncontext_iterate(ctx,1)end-- Syntax: #invoke:params|all_sorted|pipe tolibrary.all_sorted=function(ctx)ifctx.subset==1thenerror(modulename..': The ‘all_sorted’ directive is redundant after ‘sequential’',0)endifctx.sorttype==2thenerror(modulename..': The two directives ‘reassorted’ and ‘sequential’ are in contradiction with each other',0)endctx.sorttype=1returncontext_iterate(ctx,1)end-- Syntax: #invoke:params|reassorted|pipe tolibrary.reassorted=function(ctx)ifctx.subset==1thenerror(modulename..': The ‘reassorted’ directive is redundant after ‘sequential’',0)endifctx.sorttype==1thenerror(modulename..': The two directives ‘sequential’ and ‘reassorted’ are in contradiction with each other',0)endctx.sorttype=2returncontext_iterate(ctx,1)end-- Syntax: #invoke:params|setting|directives|...|pipe tolibrary.setting=function(ctx)localopts=ctx.pipelocalcmd=opts[1]ifcmd~=nilthencmd=cmd:gsub('%s+',''):gsub('/+','/'):match'^/*(.*[^/])'endifcmd==nilthenerror(modulename..', ‘setting’: No directive was given',0)endlocalsep=string.byte('/')localargc=2localdest={}localvnamelocalchrforidx=1,#cmddochr=cmd:byte(idx)ifchr==septhenforkey,valinipairs(dest)doctx[val]=opts[argc]dest[key]=nilendargc=argc+1elsevname=memoryslots[string.char(chr)]ifvname==nilthenerror(modulename..', ‘setting’: Unknown slot ‘'..string.char(chr)..'’',0)endtable.insert(dest,vname)endendforkey,valinipairs(dest)doctx[val]=opts[argc]endreturncontext_iterate(ctx,argc+1)end-- Syntax: #invoke:params|squeezing|pipe tolibrary.squeezing=function(ctx)localtbl=ctx.paramslocalstore={}localindices={}localnewlen=0forkey,valinpairs(tbl)doiftype(key)=='number'thennewlen=newlen+1indices[newlen]=keystore[key]=valtbl[key]=nilendendtable.sort(indices)foridx=1,newlendotbl[idx]=store[indices[idx]]endreturncontext_iterate(ctx,1)end-- Syntax: #invoke:params|filling_the_gaps|pipe tolibrary.filling_the_gaps=function(ctx)localtbl=ctx.paramslocalnmin=1localnmax=nillocalnnums=-1localtmp={}forkey,valinpairs(tbl)doiftype(key)=='number'thenifnmax==nilthenifkey<nminthennmin=keyendnmax=keyelseifkey>nmaxthennmax=keyelseifkey<nminthennmin=keyendnnums=nnums+1tmp[key]=valendendifnmax~=nilandnmax-nmin>nnumsthenctx.n_available=ctx.n_available+nmin+nnums-nmaxifctx.n_available<0thenerror(modulename..', ‘filling_the_gaps’: It is possible to fill at most '..tostring(maxfill)..' parameters',0)endforidx=nmin,nmax,1dotbl[idx]=''endforkey,valinpairs(tmp)dotbl[key]=valendendreturncontext_iterate(ctx,1)end-- Syntax: #invoke:params|clearing|pipe tolibrary.clearing=function(ctx)localtbl=ctx.paramslocalnumerics={}forkey,valinpairs(tbl)doiftype(key)=='number'thennumerics[key]=valtbl[key]=nilendendforkey,valinipairs(numerics)dotbl[key]=valendreturncontext_iterate(ctx,1)end-- Syntax: #invoke:params|cutting|left cut|right cut|pipe tolibrary.cutting=function(ctx)locallcut=tonumber(ctx.pipe[1])iflcut==nilthenerror(modulename..', ‘cutting’: Left cut must be a number',0)endlocalrcut=tonumber(ctx.pipe[2])ifrcut==nilthenerror(modulename..', ‘cutting’: Right cut must be a number',0)endlocaltbl=ctx.paramslocallen=#tbliflcut<0thenlcut=len+lcutendifrcut<0thenrcut=len+rcutendlocaltot=lcut+rcutiftot>0thenlocalcache={}iftot>=lenthenforkeyinipairs(tbl)dotbl[key]=nilendtot=lenelseforidx=len-rcut+1,len,1dotbl[idx]=nilendforidx=1,lcut,1dotbl[idx]=nilendendforkey,valinpairs(tbl)doiftype(key)=='number'andkey>0thenifkey>lenthencache[key-tot]=valelsecache[key-lcut]=valendtbl[key]=nilendendforkey,valinpairs(cache)dotbl[key]=valendendreturncontext_iterate(ctx,3)end-- Syntax: #invoke:params|cropping|left crop|right crop|pipe tolibrary.cropping=function(ctx)locallcut=tonumber(ctx.pipe[1])iflcut==nilthenerror(modulename..', ‘cropping’: Left crop must be a number',0)endlocalrcut=tonumber(ctx.pipe[2])ifrcut==nilthenerror(modulename..', ‘cropping’: Right crop must be a number',0)endlocaltbl=ctx.paramslocalnminlocalnmaxforkeyinpairs(tbl)doiftype(key)=='number'thenifnmin==nilthennmin=keynmax=keyelseifkey>nmaxthennmax=keyelseifkey<nminthennmin=keyendendendifnmin~=nilthenlocallen=nmax-nmin+1iflcut<0thenlcut=len+lcutendifrcut<0thenrcut=len+rcutendiflcut+rcut-len>-1thenforkeyinpairs(tbl)doiftype(key)=='number'thentbl[key]=nilendendelseiflcut+rcut>0thenforidx=nmax-rcut+1,nmaxdotbl[idx]=nilendforidx=nmin,nmin+lcut-1dotbl[idx]=nilendlocallshift=nmin+lcut-1iflshift>0thenforidx=lshift+1,nmax,1dotbl[idx-lshift]=tbl[idx]tbl[idx]=nilendendendendreturncontext_iterate(ctx,3)end-- Syntax: #invoke:params|purging|start offset|length|pipe tolibrary.purging=function(ctx)localidx=tonumber(ctx.pipe[1])ifidx==nilthenerror(modulename..', ‘purging’: Start offset must be a number',0)endlocallen=tonumber(ctx.pipe[2])iflen==nilthenerror(modulename..', ‘purging’: Length must be a number',0)endlocaltbl=ctx.paramsiflen<1thenlen=len+table.maxn(tbl)ifidx>lenthenreturncontext_iterate(ctx,3)endlen=len-idx+1endctx.params=copy_table_reduced(tbl,idx,len)returncontext_iterate(ctx,3)end-- Syntax: #invoke:params|backpurging|start offset|length|pipe tolibrary.backpurging=function(ctx)locallast=tonumber(ctx.pipe[1])iflast==nilthenerror(modulename..', ‘backpurging’: Start offset must be a number',0)endlocallen=tonumber(ctx.pipe[2])iflen==nilthenerror(modulename..', ‘backpurging’: Length must be a number',0)endlocalidxlocaltbl=ctx.paramsiflen>0thenidx=last-len+1elseforkeyinpairs(tbl)doiftype(key)=='number'and(idx==nilorkey<idx)thenidx=keyendendifidx==nilthenreturncontext_iterate(ctx,3)endidx=idx-leniflast<idxthenreturncontext_iterate(ctx,3)endlen=last-idx+1endctx.params=copy_table_reduced(ctx.params,idx,len)returncontext_iterate(ctx,3)end-- Syntax: #invoke:params|rotating|pipe tolibrary.rotating=function(ctx)localtbl=ctx.paramslocalnumerics={}localnmax=0forkey,valinpairs(tbl)doiftype(key)=='number'thennumerics[key]=valtbl[key]=nilifkey>nmaxthennmax=keyendendendforkey,valinpairs(numerics)dotbl[nmax-key+1]=valendreturncontext_iterate(ctx,1)end-- Syntax: #invoke:params|pivoting|pipe to--[[library.pivoting = function (ctx) local tbl = ctx.params local shift = #tbl + 1 if shift < 2 then return library.rotating(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|pipe to--[[library.mirroring = 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|pipe to--[[library.swapping = 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 tolibrary.sorting_sequential_values=function(ctx)localsortfnifctx.pipe[1]~=nilthensortfn=sortfunctions[ctx.pipe[1]]endifsortfnthentable.sort(ctx.params,sortfn)elsetable.sort(ctx.params)end-- i.e. either `false` or `nil`ifsortfn==nilthenreturncontext_iterate(ctx,1)endreturncontext_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 tolibrary.imposing=function(ctx)ifctx.pipe[1]==nilthenerror(modulename..', ‘imposing’: Missing parameter name to impose',0)endlocalkey=ctx.pipe[1]:match'^%s*(.-)%s*$'ctx.params[tonumber(key)orkey]=ctx.pipe[2]returncontext_iterate(ctx,3)end-- Syntax: #invoke:params|providing|name|value|pipe tolibrary.providing=function(ctx)ifctx.pipe[1]==nilthenerror(modulename..', ‘providing’: Missing parameter name to provide',0)endlocalkey=ctx.pipe[1]:match'^%s*(.-)%s*$'key=tonumber(key)orkeyifctx.params[key]==nilthenctx.params[key]=ctx.pipe[2]endreturncontext_iterate(ctx,3)end-- Syntax: #invoke:params|discarding|name|[how many]|pipe tolibrary.discarding=function(ctx)ifctx.pipe[1]==nilthenerror(modulename..', ‘discarding’: Missing parameter name to discard',0)endlocalkey=ctx.pipe[1]locallen=tonumber(ctx.pipe[2])iflen==nilthenctx.params[tonumber(key)orkey:match'^%s*(.-)%s*$']=nilreturncontext_iterate(ctx,2)endkey=tonumber(key)ifkey==nilthenerror(modulename..', ‘discarding’: A range was provided, but the initial parameter name is not numeric',0)endiflen<1thenerror(modulename..', ‘discarding’: A range can only be a number greater than zero',0)endforidx=key,key+len-1doctx.params[idx]=nilendreturncontext_iterate(ctx,3)end-- Syntax: #invoke:params|excluding_non-numeric_names|pipe tolibrary['excluding_non-numeric_names']=function(ctx)localtmp=ctx.paramsforkey,valinpairs(tmp)doiftype(key)~='number'thentmp[key]=nilendendreturncontext_iterate(ctx,1)end-- Syntax: #invoke:params|excluding_numeric_names|pipe tolibrary.excluding_numeric_names=function(ctx)localtmp=ctx.paramsforkey,valinpairs(tmp)doiftype(key)=='number'thentmp[key]=nilendendreturncontext_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 tolibrary.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 returninglocaltargets,nptns,argc=load_pattern_args(ctx.pipe,targets,'with_name_matching')localtmplocalptnlocaltbl=ctx.paramslocalnewparams={}foridx=1,nptnsdoptn=targets[idx]ifptn[3]thentmp=tonumber(ptn[1])orptn[1]newparams[tmp]=tbl[tmp]elseforkey,valinpairs(tbl)doiftostring(key):find(ptn[1],1,ptn[2])thennewparams[key]=valendendendendctx.params=newparamsreturncontext_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 tolibrary.with_name_not_matching=function(ctx)localtargets,nptns,argc=load_pattern_args(ctx.pipe,targets,'with_name_not_matching')localtbl=ctx.paramsifnptns==1andtargets[1][3]thenlocaltmp=targets[1][1]tbl[tonumber(tmp)ortmp]=nilreturncontext_iterate(ctx,argc)endlocalyesmatchlocalptnforkeyinpairs(tbl)doyesmatch=trueforidx=1,nptnsdoptn=targets[idx]ifptn[3]theniftostring(key)~=ptn[1]thenyesmatch=falsebreakendelseifnottostring(key):find(ptn[1],1,ptn[2])thenyesmatch=falsebreakendendifyesmatchthentbl[key]=nilendendreturncontext_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 tolibrary.with_value_matching=function(ctx)localtbl=ctx.paramslocaltargets,nptns,argc=load_pattern_args(ctx.pipe,targets,'with_value_matching')localnomatchlocalptnforkey,valinpairs(tbl)donomatch=trueforidx=1,nptnsdoptn=targets[idx]ifptn[3]thenifval==ptn[1]thennomatch=falsebreakendelseifval:find(ptn[1],1,ptn[2])thennomatch=falsebreakendendifnomatchthentbl[key]=nilendendreturncontext_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 tolibrary.with_value_not_matching=function(ctx)localtbl=ctx.paramslocaltargets,nptns,argc=load_pattern_args(ctx.pipe,targets,'with_value_not_matching')localyesmatchlocalptnforkey,valinpairs(tbl)doyesmatch=trueforidx=1,nptnsdoptn=targets[idx]ifptn[3]thenifval~=ptn[1]thenyesmatch=falsebreakendelseifnotval:find(ptn[1],1,ptn[2])thenyesmatch=falsebreakendendifyesmatchthentbl[key]=nilendendreturncontext_iterate(ctx,argc)end-- Syntax: #invoke:params|trimming_values|pipe tolibrary.trimming_values=function(ctx)localtbl=ctx.paramsforkey,valinpairs(tbl)dotbl[key]=val:match'^%s*(.-)%s*$'endreturncontext_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 tolibrary.mapping_by_calling=function(ctx)localopts=ctx.pipelocaltnameifopts[1]~=nilthentname=opts[1]:match'^%s*(.*%S)'endiftname==nilthenerror(modulename..', ‘mapping_by_calling’: No template name was provided',0)endlocalmargs,argc,looptype,karg,varg=load_callback_opts(opts,1,mapping_styles.values_only)localmodel={title=tname,args=margs}value_maps[looptype](ctx.params,margs,karg,varg,function()returnctx.frame:expandTemplate(model)end)returncontext_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 tolibrary.mapping_by_invoking=function(ctx)localopts=ctx.pipelocalmnamelocalfnameifopts[1]~=nilthenmname=opts[1]:match'^%s*(.*%S)'endifmname==nilthenerror(modulename..', ‘mapping_by_invoking’: No module name was provided',0)endifopts[2]~=nilthenfname=opts[2]:match'^%s*(.*%S)'endiffname==nilthenerror(modulename..', ‘mapping_by_invoking’: No function name was provided',0)endlocalmargs,argc,looptype,karg,varg=load_callback_opts(opts,2,mapping_styles.values_only)localmodel={title='Module:'..mname,args=margs}localmfunc=require(model.title)[fname]ifmfunc==nilthenerror(modulename..', ‘mapping_by_invoking’: The function ‘'..fname..'’ does not exist',0)endvalue_maps[looptype](ctx.params,margs,karg,varg,function()returntostring(mfunc(ctx.frame:newChild(model)))end)returncontext_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 tolibrary.mapping_by_magic=function(ctx)localopts=ctx.pipelocalmagicifopts[1]~=nilthenmagic=opts[1]:match'^%s*(.*%S)'endifmagic==nilthenerror(modulename..', ‘mapping_by_magic’: No parser function was provided',0)endlocalmargs,argc,looptype,karg,varg=load_callback_opts(opts,1,mapping_styles.values_only)value_maps[looptype](ctx.params,margs,karg,varg,function()returnctx.frame:callParserFunction(magic,margs)end)returncontext_iterate(ctx,argc)end-- Syntax: #invoke:params|mapping_by_replacing|target|replace|[count]|[plain-- flag]|pipe tolibrary.mapping_by_replacing=function(ctx)localptn,repl,nmax,is_strict,argc,die=load_replace_args(ctx.pipe,'mapping_by_replacing')ifdiethenreturncontext_iterate(ctx,argc)endlocaltbl=ctx.paramsifis_strictthenforkey,valinpairs(tbl)doifval==ptnthentbl[key]=replendendelseifflg==2then-- Copied from Module:String's `str._escapePattern()`ptn=ptn:gsub('[%(%)%.%%%+%-%*%?%[%^%$%]]','%%%0')endforkey,valinpairs(tbl)dotbl[key]=val:gsub(ptn,repl,nmax)endendreturncontext_iterate(ctx,argc)end-- Syntax: #invoke:params|renaming_by_calling|template name|[call-- style]|[let]|[...][number of additional parameters]|[parameter-- 1]|[parameter 2]|[...]|[parameter N]|pipe tolibrary.renaming_by_calling=function(ctx)localopts=ctx.pipelocaltnameifopts[1]~=nilthentname=opts[1]:match'^%s*(.*%S)'endiftname==nilthenerror(modulename..', ‘renaming_by_calling’: No template name was provided',0)endlocalrargs,argc,looptype,karg,varg=load_callback_opts(opts,1,mapping_styles.names_only)localmodel={title=tname,args=rargs}map_names(ctx.params,rargs,karg,varg,looptype,function()returnctx.frame:expandTemplate(model)end)returncontext_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 tolibrary.renaming_by_invoking=function(ctx)localopts=ctx.pipelocalmnamelocalfnameifopts[1]~=nilthenmname=opts[1]:match'^%s*(.*%S)'endifmname==nilthenerror(modulename..', ‘renaming_by_invoking’: No module name was provided',0)endifopts[2]~=nilthenfname=opts[2]:match'^%s*(.*%S)'endiffname==nilthenerror(modulename..', ‘renaming_by_invoking’: No function name was provided',0)endlocalrargs,argc,looptype,karg,varg=load_callback_opts(opts,2,mapping_styles.names_only)localmodel={title='Module:'..mname,args=rargs}localmfunc=require(model.title)[fname]ifmfunc==nilthenerror(modulename..', ‘renaming_by_invoking’: The function ‘'..fname..'’ does not exist',0)endmap_names(ctx.params,rargs,karg,varg,looptype,function()localtmp=mfunc(ctx.frame:newChild(model))returntonumber(tmp)ortostring(tmp)end)returncontext_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 tolibrary.renaming_by_magic=function(ctx)localopts=ctx.pipelocalmagicifopts[1]~=nilthenmagic=opts[1]:match'^%s*(.*%S)'endifmagic==nilthenerror(modulename..', ‘renaming_by_magic’: No parser function was provided',0)endlocalrargs,argc,looptype,karg,varg=load_callback_opts(opts,1,mapping_styles.names_only)map_names(ctx.params,rargs,karg,varg,looptype,function()returnctx.frame:callParserFunction(magic,rargs)end)returncontext_iterate(ctx,argc)end-- Syntax: #invoke:params|renaming_by_replacing|target|replace|[count]|[plain-- flag]|pipe tolibrary.renaming_by_replacing=function(ctx)localptn,repl,nmax,is_strict,argc,die=load_replace_args(ctx.pipe,'renaming_by_replacing')ifdiethenreturncontext_iterate(ctx,argc)endlocaltbl=ctx.paramsifis_strictthenlocalkey=tonumber(ptn)orptn:match'^%s*(.-)%s*$'localval=tbl[key]tbl[key]=niltbl[tonumber(repl)orrepl:match'^%s*(.-)%s*$']=valelseifflg==2then-- Copied from Module:String's `str._escapePattern()`ptn=ptn:gsub('[%(%)%.%%%+%-%*%?%[%^%$%]]','%%%0')endlocalcache={}forkey,valinpairs(tbl)dosteal_if_renamed(val,tbl,key,cache,tostring(key):gsub(ptn,repl,nmax))endforkey,valinpairs(cache)dotbl[key]=valendendreturncontext_iterate(ctx,argc)end-- Syntax: #invoke:params|grouping_by_calling|template-- name|[let]|[...]|[number of additional arguments]|[argument-- 1]|[argument 2]|[...]|[argument N]|pipe tolibrary.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 returninglocalopts=ctx.pipelocaltmpifopts[1]~=nilthentmp=opts[1]:match'^%s*(.*%S)'endiftmp==nilthenerror(modulename..', ‘grouping_by_calling’: No template name was provided',0)endlocalmodel={title=tmp}localtmp,argc=load_child_opts(opts,2,0)localgargs={}forkey,valinpairs(tmp)doiftype(key)=='number'andkey<1thengargs[key-1]=valelsegargs[key]=valendendlocalgroups=make_groups(ctx.params)forgid,groupinpairs(groups)doforkey,valinpairs(gargs)dogroup[key]=valendgroup[0]=gidmodel.args=groupgroups[gid]=ctx.frame:expandTemplate(model)endctx.params=groupsreturncontext_iterate(ctx,argc)end-- Syntax: #invoke:params|parsing|string to parse|[trim flag]|[iteration-- delimiter setter]|[...]|[key-value delimiter setter]|[...]|pipe tolibrary.parsing=function(ctx)localopts=ctx.pipeifopts[1]==nilthenerror(modulename..', ‘parsing’: No string to parse was provided',0)endlocalisep,iplain,psep,pplain,trimnamed,trimunnamed,argc=load_parse_opts(opts,2)parse_parameter_string(ctx.params,opts[1],isep,iplain,psep,pplain,trimnamed,trimunnamed)returncontext_iterate(ctx,argc)end-- Syntax: #invoke:params|reinterpreting|parameter to reinterpret|[trim-- flag]|[iteration delimiter setter]|[...]|[key-value delimiter-- setter]|[...]|pipe tolibrary.reinterpreting=function(ctx)localopts=ctx.pipeifopts[1]==nilthenerror(modulename..', ‘reinterpreting’: No parameter to reinterpret was provided',0)endlocalisep,iplain,psep,pplain,trimnamed,trimunnamed,argc=load_parse_opts(opts,2)localtbl=ctx.paramslocaltmp=tonumber(opts[1])oropts[1]:match'^%s*(.-)%s*$'localstr=tbl[tmp]ifstr~=nilthentbl[tmp]=nilparse_parameter_string(tbl,str,isep,iplain,psep,pplain,trimnamed,trimunnamed)endreturncontext_iterate(ctx,argc)end-- Syntax: #invoke:params|combining_by_calling|template name|new parameter-- name|pipe tolibrary.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 returninglocaltname=ctx.pipe[1]iftname~=nilthentname=tname:match'^%s*(.*%S)'elseerror(modulename..', ‘combining_by_calling’: No template name was provided',0)endlocalmerge_into=ctx.pipe[2]ifmerge_into==nilthenerror(modulename..', ‘combining_by_calling’: No parameter name was provided',0)endmerge_into=tonumber(merge_into)ormerge_into:match'^%s*(.-)%s*$'ctx.params={[merge_into]=ctx.frame:expandTemplate{title=tname,args=ctx.params}}returncontext_iterate(ctx,3)end-- Syntax: #invoke:params|snapshotting|pipe tolibrary.snapshotting=function(ctx)push_cloned_stack(ctx,ctx.params)returncontext_iterate(ctx,1)end-- Syntax: #invoke:params|remembering|pipe tolibrary.remembering=function(ctx)push_cloned_stack(ctx,ctx.oparams)returncontext_iterate(ctx,1)end-- Syntax: #invoke:params|entering_substack|[new]|pipe tolibrary.entering_substack=function(ctx)localtbl=ctx.paramslocalncurrparent=ctx.n_parents+1ifctx.parents==nilthenctx.parents={tbl}elsectx.parents[ncurrparent]=tblendctx.n_parents=ncurrparentifctx.pipe[1]~=nilandctx.pipe[1]:match'^%s*new%s*$'thenctx.params={}returncontext_iterate(ctx,2)endlocalcurrsnap=ctx.n_childrenifcurrsnap>0thenctx.params=ctx.children[currsnap]ctx.children[currsnap]=nilctx.n_children=currsnap-1elselocalnewparams={}forkey,valinpairs(tbl)donewparams[key]=valendctx.params=newparamsendreturncontext_iterate(ctx,1)end-- Syntax: #invoke:params|pulling|parameter name|pipe tolibrary.pulling=function(ctx)localopts=ctx.pipeifopts[1]==nilthenerror(modulename..', ‘pulling’: No parameter to pull was provided',0)endlocalparentlocaltmp=ctx.n_parentsiftmp<1thenparent=ctx.oparamselseparent=ctx.parents[tmp]endtmp=tonumber(opts[1])oropts[1]:match'^%s*(.-)%s*$'ifparent[tmp]~=nilthenctx.params[tmp]=parent[tmp]endreturncontext_iterate(ctx,2)end-- Syntax: #invoke:params|detaching_substack|pipe tolibrary.detaching_substack=function(ctx)localncurrparent=ctx.n_parentsifncurrparent<1thenerror(modulename..', ‘detaching_substack’: No substack has been created',0)endlocalparent=ctx.parents[ncurrparent]forkeyinpairs(ctx.params)doparent[key]=nilendreturncontext_iterate(ctx,1)end-- Syntax: #invoke:params|leaving_substack|pipe tolibrary.leaving_substack=function(ctx)localncurrparent=ctx.n_parentsifncurrparent<1thenerror(modulename..', ‘leaving_substack’: No substack has been created',0)endlocalcurrsnap=ctx.n_children+1ifctx.children==nilthenctx.children={ctx.params}elsectx.children[currsnap]=ctx.paramsendctx.params=ctx.parents[ncurrparent]ctx.parents[ncurrparent]=nilctx.n_parents=ncurrparent-1ctx.n_children=currsnapreturncontext_iterate(ctx,1)end-- Syntax: #invoke:params|merging_substack|pipe tolibrary.merging_substack=function(ctx)localncurrparent=ctx.n_parentsifncurrparent<1thenerror(modulename..', ‘merging_substack’: No substack has been created',0)endlocalparent=ctx.parents[ncurrparent]localchild=ctx.paramsctx.params=parentctx.parents[ncurrparent]=nilctx.n_parents=ncurrparent-1forkey,valinpairs(child)doparent[key]=valendreturncontext_iterate(ctx,1)end-- Syntax: #invoke:params|flushing|pipe tolibrary.flushing=function(ctx)ifctx.n_children<1thenerror(modulename..', ‘flushing’: There are no substacks to flush',0)endlocalparent=ctx.paramslocalcurrsnap=ctx.n_childrenforkey,valinpairs(ctx.children[currsnap])doparent[key]=valendctx.children[currsnap]=nilctx.n_children=currsnap-1returncontext_iterate(ctx,1)end--[[ Functions ]]--------------------------------- Syntax: #invoke:params|countlibrary.count=function(ctx)-- NOTE: `ctx.pipe` and `ctx.params` might be the original metatables!localretval=0for_inctx.iterfunc(ctx.params)doretval=retval+1endifctx.subset==-1thenretval=retval-#ctx.paramsendctx.text=retvalreturnfalseend-- 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!localopts=ctx.pipelocaltnameifopts[1]~=nilthentname=opts[1]:match'^%s*(.*%S)'endiftname==nilthenerror(modulename..', ‘concat_and_call’: No template name was provided',0)endremove_numeric_keys(opts,1,1)ctx.text=ctx.frame:expandTemplate{title=tname,args=concat_params(ctx)}returnfalseend-- 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!localopts=ctx.pipelocalmnamelocalfnameifopts[1]~=nilthenmname=opts[1]:match'^%s*(.*%S)'endifmname==nilthenerror(modulename..', ‘concat_and_invoke’: No module name was provided',0)endifopts[2]~=nilthenfname=opts[2]:match'^%s*(.*%S)'endiffname==nilthenerror(modulename..', ‘concat_and_invoke’: No function name was provided',0)endremove_numeric_keys(opts,1,2)localmfunc=require('Module:'..mname)[fname]ifmfunc==nilthenerror(modulename..', ‘concat_and_invoke’: The function ‘'..fname..'’ does not exist',0)endctx.text=mfunc(ctx.frame:newChild{title='Module:'..fname,args=concat_params(ctx)})returnfalseend-- 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!localopts=ctx.pipelocalmagicifopts[1]~=nilthenmagic=opts[1]:match'^%s*(.*%S)'endifmagic==nilthenerror(modulename..', ‘concat_and_magic’: No parser function was provided',0)endremove_numeric_keys(opts,1,1)ctx.text=ctx.frame:callParserFunction(magic,concat_params(ctx))returnfalseend-- Syntax: #invoke:params|value_of|parameter namelibrary.value_of=function(ctx)-- NOTE: `ctx.pipe` and `ctx.params` might be the original metatables!localopts=ctx.pipelocalkstrifopts[1]~=nilthenkstr=opts[1]:match'^%s*(.*%S)'endifkstr==nilthenerror(modulename..', ‘value_of’: No parameter name was provided',0)endlocalknum=tonumber(kstr)locallen=#ctx.params-- No worries: unused when in first positionlocalval=ctx.params[knumorkstr]ifval~=niland(ctx.subset~=-1orknum==nilorknum>lenorknum<1)and(ctx.subset~=1or(knum~=nilandknum<=lenandknum>0))thenctx.text=(ctx.headeror'')..val..(ctx.footeror'')returnfalseendctx.text=ctx.ifngivenor''returnfalseend-- Syntax: #invoke:params|listlibrary.list=function(ctx)-- NOTE: `ctx.pipe` might be the original metatable!localkvs=ctx.pairsepor''localpps=ctx.itersepor''localret={}localnss=0flush_params(ctx,function(key,val)ret[nss+1]=ppsret[nss+2]=keyret[nss+3]=kvsret[nss+4]=valnss=nss+4end)ifnss>0thenifnss>4andctx.lastsep~=nilthenret[nss-3]=ctx.lastsependret[1]=ctx.headeror''ifctx.footer~=nilthenret[nss+1]=ctx.footerendctx.text=table.concat(ret)returnfalseendctx.text=ctx.ifngivenor''returnfalseend-- Syntax: #invoke:params|list_valueslibrary.list_values=function(ctx)-- NOTE: `ctx.pipe` might be the original metatable!-- NOTE: `library.coins()` and `library.unique_coins()` rely on uslocalpps=ctx.itersepor''localret={}localnss=0flush_params(ctx,function(key,val)ret[nss+1]=ppsret[nss+2]=valnss=nss+2end)ifnss>0thenifnss>2andctx.lastsep~=nilthenret[nss-1]=ctx.lastsependret[1]=ctx.headeror''ifctx.footer~=nilthenret[nss+1]=ctx.footerendctx.text=table.concat(ret)returnfalseendctx.text=ctx.ifngivenor''returnfalseend-- 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!localopts=ctx.pipelocaltbl=ctx.paramsforkey,valinpairs(tbl)dotbl[key]=opts[tonumber(val)orval]endreturnlibrary.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)localopts=ctx.pipelocaltbl=ctx.paramslocaltmpforkey,valinpairs(tbl)dotmp=tonumber(val)orvaltbl[key]=opts[tmp]opts[tmp]=nilendreturnlibrary.list_values(ctx)end-- Syntax: #invoke:params|for_each|wikitextlibrary.for_each=function(ctx)-- NOTE: `ctx.pipe` might be the original metatable!localtxt=ctx.pipe[1]or''localpps=ctx.itersepor''localret={}localnss=0flush_params(ctx,function(key,val)ret[nss+1]=ppsret[nss+2]=txt:gsub('%$#',key):gsub('%$@',val)nss=nss+2end)ifnss>0thenifnss>2andctx.lastsep~=nilthenret[nss-1]=ctx.lastsependret[1]=ctx.headeror''ifctx.footer~=nilthenret[nss+1]=ctx.footerendctx.text=table.concat(ret)returnfalseendctx.text=ctx.ifngivenor''returnfalseend-- 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)localopts=ctx.pipelocaltnameifopts[1]~=nilthentname=opts[1]:match'^%s*(.*%S)'endiftname==nilthenerror(modulename..', ‘call_for_each’: No template name was provided',0)endlocalmodel={title=tname,args=opts}localccs=ctx.itersepor''localret={}localnss=0table.insert(opts,1,true)flush_params(ctx,function(key,val)opts[1]=keyopts[2]=valret[nss+1]=ccsret[nss+2]=ctx.frame:expandTemplate(model)nss=nss+2end)ifnss>0thenifnss>2andctx.lastsep~=nilthenret[nss-1]=ctx.lastsependret[1]=ctx.headeror''ifctx.footer~=nilthenret[nss+1]=ctx.footerendctx.text=table.concat(ret)returnfalseendctx.text=ctx.ifngivenor''returnfalseend-- 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)localopts=ctx.pipelocalmnamelocalfnameifopts[1]~=nilthenmname=opts[1]:match'^%s*(.*%S)'endifmname==nilthenerror(modulename..', ‘invoke_for_each’: No module name was provided',0)endifopts[2]~=nilthenfname=opts[2]:match'^%s*(.*%S)'endiffname==nilthenerror(modulename..', ‘invoke_for_each’: No function name was provided',0)endlocalmodel={title='Module:'..mname,args=opts}localmfunc=require(model.title)[fname]localccs=ctx.itersepor''localret={}localnss=0flush_params(ctx,function(key,val)opts[1]=keyopts[2]=valret[nss+1]=ccsret[nss+2]=mfunc(ctx.frame:newChild(model))nss=nss+2end)ifnss>0thenifnss>2andctx.lastsep~=nilthenret[nss-1]=ctx.lastsependret[1]=ctx.headeror''ifctx.footer~=nilthenret[nss+1]=ctx.footerendctx.text=table.concat(ret)returnfalseendctx.text=ctx.ifngivenor''returnfalseend-- 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)localopts=ctx.pipelocalmagicifopts[1]~=nilthenmagic=opts[1]:match'^%s*(.*%S)'endifmagic==nilthenerror(modulename..', ‘magic_for_each’: No parser function was provided',0)endlocalccs=ctx.itersepor''localret={}localnss=0table.insert(opts,1,true)flush_params(ctx,function(key,val)opts[1]=keyopts[2]=valret[nss+1]=ccsret[nss+2]=ctx.frame:callParserFunction(magic,opts)nss=nss+2end)ifnss>0thenifnss>2andctx.lastsep~=nilthenret[nss-1]=ctx.lastsependret[1]=ctx.headeror''ifctx.footer~=nilthenret[nss+1]=ctx.footerendctx.text=table.concat(ret)returnfalseendctx.text=ctx.ifngivenor''returnfalseend-- 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)localopts=ctx.pipelocaltnameifopts[1]~=nilthentname=opts[1]:match'^%s*(.*%S)'endiftname==nilthenerror(modulename..', ‘call_for_each_value’: No template name was provided',0)endlocalmodel={title=tname,args=opts}localccs=ctx.itersepor''localret={}localnss=0flush_params(ctx,function(key,val)opts[1]=valret[nss+1]=ccsret[nss+2]=ctx.frame:expandTemplate(model)nss=nss+2end)ifnss>0thenifnss>2andctx.lastsep~=nilthenret[nss-1]=ctx.lastsependret[1]=ctx.headeror''ifctx.footer~=nilthenret[nss+1]=ctx.footerendctx.text=table.concat(ret)returnfalseendctx.text=ctx.ifngivenor''returnfalseend-- 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)localopts=ctx.pipelocalmnamelocalfnameifopts[1]~=nilthenmname=opts[1]:match'^%s*(.*%S)'endifmname==nilthenerror(modulename..', ‘invoke_for_each_value’: No module name was provided',0)endifopts[2]~=nilthenfname=opts[2]:match'^%s*(.*%S)'endiffname==nilthenerror(modulename..', ‘invoke_for_each_value’: No function name was provided',0)endlocalmodel={title='Module:'..mname,args=opts}localmfunc=require(model.title)[fname]localccs=ctx.itersepor''localret={}localnss=0remove_numeric_keys(opts,1,1)flush_params(ctx,function(key,val)opts[1]=valret[nss+1]=ccsret[nss+2]=mfunc(ctx.frame:newChild(model))nss=nss+2end)ifnss>0thenifnss>2andctx.lastsep~=nilthenret[nss-1]=ctx.lastsependret[1]=ctx.headeror''ifctx.footer~=nilthenret[nss+1]=ctx.footerendctx.text=table.concat(ret)returnfalseendctx.text=ctx.ifngivenor''returnfalseend-- 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)localopts=ctx.pipelocalmagicifopts[1]~=nilthenmagic=opts[1]:match'^%s*(.*%S)'endifmagic==nilthenerror(modulename..', ‘magic_for_each_value’: No parser function was provided',0)endlocalccs=ctx.itersepor''localret={}localnss=0flush_params(ctx,function(key,val)opts[1]=valret[nss+1]=ccsret[nss+2]=ctx.frame:callParserFunction(magic,opts)nss=nss+2end)ifnss>0thenifnss>2andctx.lastsep~=nilthenret[nss-1]=ctx.lastsependret[1]=ctx.headeror''ifctx.footer~=nilthenret[nss+1]=ctx.footerendctx.text=table.concat(ret)returnfalseendctx.text=ctx.ifngivenor''returnfalseend-- 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!localopts=ctx.pipelocaltmpifopts[1]~=nilthentmp=opts[1]:match'^%s*(.*%S)'endiftmp==nilthenerror(modulename..', ‘call_for_each_group’: No template name was provided',0)endlocalmodel={title=tmp}localccs=ctx.itersepor''localnss=0localret={}opts={}forkey,valinpairs(ctx.pipe)doiftype(key)=='number'thenopts[key-1]=valelseopts[key]=valendendctx.pipe=optsctx.params=make_groups(ctx.params)flush_params(ctx,function(gid,group)forkey,valinpairs(opts)dogroup[key]=valendgroup[0]=gidmodel.args=groupret[nss+1]=ccsret[nss+2]=ctx.frame:expandTemplate(model)nss=nss+2end)ifnss>0thenifnss>2andctx.lastsep~=nilthenret[nss-1]=ctx.lastsependret[1]=ctx.headeror''ifctx.footer~=nilthenret[nss+1]=ctx.footerendctx.text=table.concat(ret)returnfalseendctx.text=ctx.ifngivenor''returnfalseend--- ------ PUBLIC ENVIRONMENT ------ ________________________________ ------ -----[[ First-position-only modifiers ]]------------------------------------------- Syntax: #invoke:params|new|pipe tostatic_iface.new=function(frame)localctx=context_new(frame:getParent())ctx.pipe=copy_or_ref_table(frame.args,false)ctx.params={}main_loop(ctx,context_iterate(ctx,1))returnctx.textend--[[ First-position-only functions ]]------------------------------------------- Syntax: #invoke:params|selfstatic_iface.self=function(frame)returnframe:getParent():getTitle()end--[[ Public metatable of functions ]]-----------------------------------------returnsetmetatable({},{__index=function(_,query)localfname=query:match'^%s*(.*%S)'iffname==nilthenerror(modulename..': You must specify a function to call',0)endlocalfunc=static_iface[fname]iffunc~=nilthenreturnfuncendfunc=library[fname]iffunc==nilthenerror(modulename..': The function ‘'..fname..'’ does not exist',0)endreturnfunction(frame)localctx=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)returnctx.textendend})
close