Anda dapat membuat halaman dokumentasi untuk buat pada modul Scribunto ini.
Penyunting dapat melakukan uji coba pada halaman bak pasir (buat | cermin) dan kasus uji (buat) modul ini.
Subhalaman modul ini.
Penyunting dapat melakukan uji coba pada halaman bak pasir (buat | cermin) dan kasus uji (buat) modul ini.
Subhalaman modul ini.
require[[strict]] --- --- --- PRIVATE 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) returnvar1:gsub('%d+',zero_padded)<var2:gsub('%d+',zero_padded) end -- Return a copy or a reference to a table localfunctioncopy_or_ref_table(src,refonly) ifrefonlythenreturnsrcend localnewtab={} forkey,valinpairs(src)donewtab[key]=valend returnnewtab end -- Copy at most N items (of all kinds) from `src` to `dest` and return `dest` localfunctioncopy_table_maxn(dest,src,len) localidx=1 forkey,valinpairs(src)do dest[key],idx=val,idx+1 ifidx>lenthenbreakend end returndest end -- Remove some numeric elements from a table, shifting everything to the left localfunctionremove_numeric_keys(tbl,idx,len) localcache,tmp={},idx+len-1 forkey,valinpairs(tbl)do iftype(key)=='number'andkey>=idxthen ifkey>tmpthencache[key-len]=valend tbl[key]=nil end end forkey,valinpairs(cache)dotbl[key]=valend end -- Make a reduced copy of a table (shifting in both directions if necessary) localfunctioncopy_table_reduced(tbl,idx,len) localret,tmp={},idx+len-1 ifidx>0then forkey,valinpairs(tbl)do iftype(key)~='number'orkey<idxthen ret[key]=val elseifkey>tmpthenret[key-len]=valend end elseiftmp>0then localnshift=1-idx forkey,valinpairs(tbl)do iftype(key)~='number'thenret[key]=val elseifkey>tmpthenret[key-tmp]=val elseifkey<idxthenret[key+nshift]=valend end else forkey,valinpairs(tbl)do iftype(key)~='number'orkey>tmpthen ret[key]=val elseifkey<idxthenret[key+len]=valend end end returnret end -- Make an expanded copy of a table (shifting in both directions if necessary) localfunctioncopy_table_expanded(tbl,idx,len) localret,tmp={},idx+len-1 ifidx>0then forkey,valinpairs(tbl)do iftype(key)~='number'orkey<idxthen ret[key]=val elseret[key+len]=valend end elseiftmp>0then localnshift=idx-1 forkey,valinpairs(tbl)do iftype(key)~='number'thenret[key]=val elseifkey>0thenret[key+tmp]=val elseifkey<1thenret[key+nshift]=valend end else forkey,valinpairs(tbl)do iftype(key)~='number'orkey>tmpthen ret[key]=val elseret[key-len]=valend end end returnret end -- Given a table, create two new tables containing the sorted list of keys localfunctionget_key_list_sorted(tbl,sort_fn) localnums,words,nn,nw={},{},0,0 forkey,valinpairs(tbl)do iftype(key)=='number'then nn=nn+1 nums[nn]=key else nw=nw+1 words[nw]=key end end table.sort(nums) table.sort(words,sort_fn) returnnums,words,nn,nw end -- Parse a parameter name string and return it as a string or a number localfunctionget_parameter_name(par_str) localret=par_str:match'^%s*(.-)%s*$' ifret~='0'andret:find'^%-?[1-9]%d*$'==nilthenreturnretend returntonumber(ret) end -- Move a key from a table to another, but only if under a different name and -- always parsing numeric strings as numbers localfunctionsteal_if_renamed(val,src,skey,dest,dkey) localrealkey=get_parameter_name(dkey) ifskey~=realkeythendest[realkey],src[skey]=val,nilend end --[[ 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, 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`) ]]-- 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={ h='header', f='footer', i='itersep', l='lastsep', n='ifngiven', p='pairsep', s='oxfordsep' } -- Possible trimming modes for the `parsing` modifier localtrim_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 localisep_parse_opts={ splitter_pattern=false, splitter_string=true } -- Possible string modes for the key-value separator in the `parsing` and -- `reinterpreting` modifiers localpsep_parse_opts={ setter_pattern=false, setter_string=true } -- Possible position references for the `splicing` modifier localposition_references={ add_nothing=0, add_smallest_number=1, add_last_of_sequence=2, add_largest_number=3 } -- Possible modes for the `reassigning` modifier locala_modes={ transfer=0, clone=1, rename=2, copy=3, sacrifice=4, provide=5, spare=7 } -- Functions and modifiers MUST avoid these names too: `here`, `in_substack`, -- `let`, `expose`, `use`, `with_flushed_glue`, `without_flushed_glue` -- `without_sorting` --[[ Private constants ]]-- --------------------------- -- 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 available localrefpipe={ call_for_each_group=true, --coins = true, count=true, evaluating=true, for_each=true, list=true, list_values=true, list_maybe_with_names=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 localrefparams={ call_for_each_group=true, combining=true, combining_by_calling=true, combining_values=true, concat_and_call=true, concat_and_invoke=true, concat_and_magic=true, count=true, grouping_by_calling=true, mixing_names_and_values=true, keeping_at_most=true, renaming_by_mixing=true, renaming_to_sequence=true, renaming_to_uppercase=true, renaming_to_lowercase=true, --renaming_to_values = true, shifting=true, splicing=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) localmaxfill=1024 -- The private table of functions locallibrary={} -- Functions and modifiers that can only be invoked in first position localstatic_iface={} --[[ Private functions ]]-- --------------------------- -- Create a new context localfunctioncontext_new(child_frame) localmain_frame=child_frame:getParent() return{ frame=main_frame, opipe=child_frame.args, oparams=main_frame.args, firstposonly=static_iface, iterfunc=pairs, sorttype=0, n_parents=0, n_children=0, n_available=maxfill } end -- Move to the next action within the user-given list localfunctioncontext_iterate(ctx,n_forward) localnextfn ifctx.pipe[n_forward]~=nilthen nextfn=ctx.pipe[n_forward]:match'^%s*(.*%S)' end ifnextfn==nilthenerror(modulename.. ': You must specify a function to call',0)end iflibrary[nextfn]==nilthen ifctx.firstposonly[nextfn]==nilthenerror(modulename.. ': The function ‘'..nextfn..'’ does not exist',0) elseerror(modulename..': The ‘'..nextfn.. '’ directive can only appear in first position',0) end end remove_numeric_keys(ctx.pipe,1,n_forward) returnlibrary[nextfn] end -- Main loop localfunctionmain_loop(ctx,start_with) localfn=start_with repeatfn=fn(ctx)untilnotfn ifctx.n_parents>0thenerror(modulename.. ': One or more ‘merging_substack’ directives are missing',0)end ifctx.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)end end -- Load a `setting`-like directive string into the `dest` table localfunctionset_strings_from_opts(dest,opts,start_from) localcmd ifopts[start_from]==nilthenreturnstart_from-1end cmd=opts[start_from]:gsub('%s+',''):gsub('/+','/') :match'^/*(.*[^/])' ifcmd==nilthenreturnstart_fromend localvname,chr localamap,sep,argc={},string.byte('/'),start_from+1 foridx=1,#cmddo chr=cmd:byte(idx) ifchr==septhen forkey,valinipairs(amap)do dest[val],amap[key]=opts[argc],nil end argc=argc+1 else vname=memoryslots[string.char(chr)] ifvname==nilthenerror(modulename.. ', ‘setting’: Unknown slot ‘'.. string.char(chr)..'’',0)end table.insert(amap,vname) end end forkey,valinipairs(amap)dodest[val]=opts[argc]end returnargc end -- Add a new stack of parameters to `ctx.children` localfunctionnew_substack(ctx) localcurrsnap,newparams=ctx.n_children+1,{} ifctx.children==nilthenctx.children={newparams} elsectx.children[currsnap]=newparamsend ctx.n_children=currsnap returnnewparams end -- Parse a raw argument containing a `sortfunctions` directive, or -- `'without_sorting'`, or `nil` localfunctionload_sort_opt(raw_arg) ifraw_arg==nilthenreturnnil,1,falseend localtrarg=raw_arg:match'^%s*(.-)%s*$' iftrarg=='without_sorting'thenreturnnil,2,false,trargend localtmp=sortfunctions[trarg] iftmp==nilthenreturnnil,1,false,trargend returntmpornil,2,true,trarg end -- Parse optional user arguments of type `...|[let/use]|[...]|[let/use]|[...]| -- [number of additional parameters]|[parameter 1]|[parameter 2]|[...]` localfunctionload_child_opts(src,start_from,append_after,params) localtnamed,tmp1,tmp2 localpin,tbl,mem=start_from,{},{} whilesrc[pin]~=nilandsrc[pin+1]~=nildo tmp1=src[pin]:match'^%s*(.*%S)' iftmp1=='let'andsrc[pin+2]~=nilthen tmp1=get_parameter_name(src[pin+1]) mem[tmp1],tbl[tmp1],pin=nil,src[pin+2],pin+3 --[[ elseif tmp1 == 'expose' then tmp1 = get_parameter_name(src[pin + 1]) tmp2 = params[tmp1] mem[tmp1], tbl[tmp1], pin = tmp2, tmp2, pin + 2 ]]-- elseiftmp1=='use'andsrc[pin+2]~=nilthen tmp1=get_parameter_name(src[pin+2]) tmp2=params[tmp1] mem[tmp1],tbl[get_parameter_name(src[pin+1])],pin= tmp2,tmp2,pin+3 elsebreakend end localtnew=copy_or_ref_table(params,next(mem)==nil) forkeyinpairs(mem)dotnew[key]=nilend ifpin~=start_fromthentnamed,tbl=tbl,{}end tmp1=tonumber(src[pin]) iftmp1~=nilandmath.floor(tmp1)==tmp1then iftmp1<0thentmp1=-1end tmp2=append_after-pin foridx=pin+1,pin+tmp1dotbl[idx+tmp2]=src[idx]end pin=pin+tmp1+1 end iftnamed~=nilthen forkey,valinpairs(tnamed)dotbl[key]=valend end returntbl,pin,tnew,mem end -- Load the optional arguments of some of the `mapping_*` and `renaming_*` -- class of modifiers localfunctionload_callback_opts(src,n_skip,default_style,params) localstyle,shf localtmp=src[n_skip+1] iftmp~=nilthenstyle=mapping_styles[tmp:match'^%s*(.-)%s*$']end ifstyle==nilthenstyle,shf=default_style,n_skip-1 elseshf=n_skipend localn_exist,karg,varg=style[3],style[4],style[5] tmp=style[6] iftmp>-1then karg=src[tmp+shf]:match'^%s*(.-)%s*$' ifkarg=='0'orkarg:find'^%-?[1-9]%d*$'~=nilthen karg=tonumber(karg) n_exist=math.max(n_exist,karg) end end tmp=style[7] iftmp>-1then varg=src[tmp+shf]:match'^%s*(.-)%s*$' ifvarg=='0'orvarg:find'^%-?[1-9]%d*$'~=nilthen varg=tonumber(varg) n_exist=math.max(n_exist,varg) end end localdest,argc,tnew,mem=load_child_opts(src,style[2]+shf, n_exist,params) tmp=style[1] if(tmp==3ortmp==2)anddest[karg]~=nilthen tmp=tmp-2end if(tmp==3ortmp==1)anddest[varg]~=nilthen tmp=tmp-1end returndest,argc,tmp,karg,varg,tnew,mem end -- Parse the arguments of some of the `mapping_*` and `renaming_*` class of -- modifiers localfunctionload_replace_args(opts,whoami) ifopts[1]==nilthenerror(modulename.. ', ‘'..whoami..'’: No pattern string was given',0)end ifopts[2]==nilthenerror(modulename.. ', ‘'..whoami..'’: No replacement string was given',0)end localptn,repl,nmax,argc=opts[1],opts[2],tonumber(opts[3]),3 ifnmax~=nilor(opts[3]or''):match'^%s*$'~=nilthenargc=4end localflg=opts[argc] ifflg~=nilthenflg=mkeywords[flg:match'^%s*(.-)%s*$']end ifflg==0thenflg=nilelseifflg~=nilthenargc=argc+1end returnptn,repl,nmax,flg,argc,(nmax~=nilandnmax<1)or (flg==3andptn==repl) end -- Parse the arguments of the `with_*_matching` class of modifiers localfunctionload_pattern_args(opts,whoami) localkeyw localptns,state,nptns,cnt={},0,0,1 for_,valinipairs(opts)do ifstate==0then nptns,state=nptns+1,-1 ptns[nptns]={val,false,false} else keyw=val:match'^%s*(.*%S)' ifkeyw==nilormkeywords[keyw]==nilor( state>0andmkeywords[keyw]>0 )thenbreak else state=mkeywords[keyw] ifstate>1thenptns[nptns][2]=trueend ifstate==3thenptns[nptns][3]=trueend end end cnt=cnt+1 end ifstate==0thenerror(modulename..', ‘'..whoami.. '’: No pattern was given',0)end returnptns,nptns,cnt end -- Load the optional arguments of the `parsing`, `reinterpreting` and -- `evaluating` modifiers localfunctionload_parse_opts(opts,start_from,isp,psp) localtmp localoptslots,noptslots,argc,trimn,trimu,iplain,pplain= {true,true,true},3,start_from,true,false,true,true repeat noptslots,tmp=noptslots-1,opts[argc] iftmp==nilthenbreakend tmp=tmp:match'^%s*(.-)%s*$' ifoptslots[1]~=nilandtrim_parse_opts[tmp]~=nilthen tmp=trim_parse_opts[tmp] trimn,trimu,optslots[1]=tmp[1],tmp[2],nil elseifoptslots[2]~=nilandisep_parse_opts[tmp]~=nilthen argc=argc+1 iplain,isp,optslots[2]=isep_parse_opts[tmp], opts[argc],nil elseifoptslots[3]~=nilandpsep_parse_opts[tmp]~=nilthen argc=argc+1 pplain,psp,optslots[3]=psep_parse_opts[tmp], opts[argc],nil elsebreakend argc=argc+1 untilnoptslots<1 returnisp,iplain,psp,pplain,trimn,trimu,argc end -- Map parameters' values using a custom callback and a referenced table localvalue_maps={ [0]=function(tbl,margs,karg,varg,fn) forkeyinpairs(tbl)dotbl[key]=fn()end end, [1]=function(tbl,margs,karg,varg,fn) forkey,valinpairs(tbl)do margs[varg]=val tbl[key]=fn() end end, [2]=function(tbl,margs,karg,varg,fn) forkeyinpairs(tbl)do margs[karg]=key tbl[key]=fn() end end, [3]=function(tbl,margs,karg,varg,fn) forkey,valinpairs(tbl)do margs[karg],margs[varg]=key,val tbl[key]=fn() end end } -- Private table for `map_names()` localname_thieves={ [0]=function(cache,tbl,rargs,karg,varg,fn) forkey,valinpairs(tbl)do steal_if_renamed(val,tbl,key,cache,fn()) end end, [1]=function(cache,tbl,rargs,karg,varg,fn) forkey,valinpairs(tbl)do rargs[varg]=val steal_if_renamed(val,tbl,key,cache,fn()) end end, [2]=function(cache,tbl,rargs,karg,varg,fn) forkey,valinpairs(tbl)do rargs[karg]=key steal_if_renamed(val,tbl,key,cache,fn()) end end, [3]=function(cache,tbl,rargs,karg,varg,fn) forkey,valinpairs(tbl)do rargs[karg],rargs[varg]=key,val steal_if_renamed(val,tbl,key,cache,fn()) end end } -- Map parameters' names using a custom callback and a referenced table localfunctionmap_names(tbl,rargs,karg,varg,looptype,fn) localcache={} name_thieves[looptype](cache,tbl,rargs,karg,varg,fn) forkey,valinpairs(cache)dotbl[key]=valend end -- Return a new table that contains `src` regrouped according to the numeric -- suffixes in its keys localfunctionmake_groups(src) -- NOTE: `src` might be the original metatable! localprefix,gid localgroups={} forkey,valinpairs(src)do -- `key` must only be a string or a number... iftype(key)=='string'then prefix,gid=key:match'^%s*(.-)%s*(%-?%d*)%s*$' gid=tonumber(gid)or'' else prefix,gid='',key end ifgroups[gid]==nilthengroups[gid]={}end ifprefix=='0'orprefix:find'^%-?[1-9]%d*$'~=nilthen prefix=tonumber(prefix) ifprefix<1thenprefix=prefix-1end end groups[gid][prefix]=val end returngroups end -- Split into parts a string containing the `$#` and `$@` placeholders and -- return the information as a skeleton table, a canvas table and a length localfunctionparse_placeholder_string(target) localidx,s_pos,skel,canvas=1,1,{},{} locale_pos=string.find(target,'%$[@#]',1,false) whilee_pos~=nildo 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())thenidx=idx-1 elsecanvas[idx]=target:sub(s_pos)end returnskel,canvas,idx end -- Populate a table by parsing a parameter string (heavy lifting for `parsing`, -- `reinterpreting` and `evaluating`) localfunctionparse_parameter_string(tbl,str,isp,ipl,psp,ppl,trn,tru) localkey,val,spos1,spos2,pos1,pos2 localpos3,idx,lenplone=0,1,#str+1 ifisp==nilorisp==''then ifpsp==nilorpsp==''then iftruthentbl[idx]=str:match'^%s*(.-)%s*$' elsetbl[idx]=strend returnidx end spos1,spos2=str:find(psp,1,ppl) ifspos1==nilthen key=idx iftruthenval=str:match'^%s*(.-)%s*$' elseval=strend idx=idx+1 else key=get_parameter_name(str:sub(1,spos1-1)) val=str:sub(spos2+1) iftrnthenval=val:match'^%s*(.-)%s*$'end end tbl[key]=val returnidx end ifpsp==nilorpsp==''then repeat pos1=pos3+1 pos2,pos3=str:find(isp,pos1,ipl) val=str:sub(pos1,(pos2orlenplone)-1) iftruthenval=val:match'^%s*(.-)%s*$'end tbl[idx],idx=val,idx+1 untilpos2==nil returnidx end repeat pos1=pos3+1 pos2,pos3=str:find(isp,pos1,ipl) val=str:sub(pos1,(pos2orlenplone)-1) spos1,spos2=val:find(psp,1,ppl) ifspos1==nilthen key=idx iftruthenval=val:match'^%s*(.-)%s*$'end idx=idx+1 else key=get_parameter_name(val:sub(1,spos1-1)) val=val:sub(spos2+1) iftrnthenval=val:match'^%s*(.-)%s*$'end end tbl[key]=val untilpos2==nil returnidx end -- Heavy lifting for `snapshotting` and `remembering` localfunctionmake_child(ctx,src,whoami) locallen=tonumber(ctx.pipe[1]) iflen==nilorlen==0then localstack=new_substack(ctx) forkey,valinpairs(src)dostack[key]=valend returnlen==niland1or2 end iflen<0ormath.floor(len)~=lenthenerror(modulename.. ', ‘'..whoami..'’: The number of parameters to copy must be an integer greater than zero',0)end copy_table_maxn(new_substack(ctx),src,len) return2 end -- Heavy lifting for `setting_by_flushing`, `combining` and `combining_values` localfunctionset_strings_from_substack(ctx,dest,whoami) ifctx.n_children<1thenerror(modulename.. ', ‘'..whoami..'’: There are no substacks to flush',0)end localcurrsnap=ctx.n_children localstack=ctx.children[currsnap] forkey,valinpairs(memoryslots)do ifstack[key]~=nilthendest[val]=stack[key]end end ctx.children[currsnap],ctx.n_children=nil,currsnap-1 end -- Heavy lifting for `combining` and `combining_values` localfunctioncombine_parameters(ctx,keyval_fn,whoami) -- NOTE: `ctx.params` might be the original metatable! This function -- MUST create a copy of it before returning localopts=ctx.pipe ifctx.pipe[1]==nilthenerror(modulename.. ', ‘'..whoami..'’: No parameter name was provided',0)end localargc localtbl,vars=ctx.params,{} localsortfn,varsarg0,do_sort,tmp=load_sort_opt(opts[2]) ifvarsarg0==2thentmp=opts[3]andopts[3]:match'^%s*(.-)%s*$'end iftmp=='with_flushed_glue'then varsarg0=varsarg0+1 argc=set_strings_from_opts(vars,opts,varsarg0+1) set_strings_from_substack(ctx,vars,whoami) else iftmp=='without_flushed_glue'thenvarsarg0=varsarg0+1end argc=set_strings_from_opts(vars,opts,varsarg0+1) end ifargc<varsarg0thenerror(modulename.. ', ‘'..whoami..'’: No setting directive was given',0)end ifnext(tbl)==nilthen ifvars.ifngiven~=nilthenctx.params= {[get_parameter_name(ctx.pipe[1])]=vars.ifngiven} elseiftbl==ctx.oparamsthenctx.params={}end returnargc end localcache,len ifdo_sortthen localwords cache,words,len,tmp=get_key_list_sorted(tbl,sortfn) foridx=1,tmpdocache[len+idx]=words[idx]end len=len+tmp else len,cache=0,{} forkeyinpairs(tbl)do len=len+1 cache[len]=key end end localpmap,nss,kvs,pps={},0,vars.pairsepor'',vars.itersepor'' foridx=1,lendo tmp,pmap[nss+1]=cache[idx],pps pmap[nss+2]=keyval_fn(tmp,tbl[tmp],kvs) nss=nss+2 end tmp=vars.oxfordseporvars.lastsep iftmp~=nilandnss>4thenpmap[nss-1]=tmp elseifnss>2andvars.lastsep~=nilthen pmap[nss-1]=vars.lastsep end pmap[1]=vars.headeror'' ifvars.footer~=nilthenpmap[nss+1]=vars.footerend ctx.params={[get_parameter_name(ctx.pipe[1])]=table.concat(pmap)} returnargc 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 localfunctionconcat_params(ctx) localretval,tbl,nmax={},ctx.params,table.maxn(ctx.pipe) ifctx.subset==1then -- We need only the sequence forkey,valinipairs(tbl)doretval[key+nmax]=valend else ifctx.subset==-1then forkeyinipairs(tbl)dotbl[key]=nilend end forkey,valinpairs(tbl)do iftype(key)=='number'andkey>0then retval[key+nmax]=val elseretval[key]=valend end end forkey,valinpairs(ctx.pipe)doretval[key]=valend returnretval 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) localfunctionflush_params(ctx,fn) localtbl=ctx.params ifctx.subset==1then forkey,valinipairs(tbl)dofn(key,val)end return end ifctx.subset==-1then forkey,valinipairs(tbl)dotbl[key]=nilend end ifctx.sorttype>0then localnums,words,nn,nw=get_key_list_sorted(tbl,natural_sort) ifctx.sorttype==2then foridx=1,nwdofn(words[idx],tbl[words[idx]])end foridx=1,nndofn(nums[idx],tbl[nums[idx]])end return end foridx=1,nndofn(nums[idx],tbl[nums[idx]])end foridx=1,nwdofn(words[idx],tbl[words[idx]])end return end ifctx.subset~=-1then forkey,valinipairs(tbl)do fn(key,val) tbl[key]=nil end end forkey,valinpairs(tbl)dofn(key,val)end end -- Flush the parameters by calling one of two custom functions for each value -- (after this function has been invoked `ctx.params` will be no longer usable) localfunctionmixed_flush_params(ctx,fn_seq,fn_oth) ifctx.subset==1then forkey,valinipairs(ctx.params)dofn_seq(key,val)end return end ifctx.subset==-1then flush_params(ctx,fn_oth) return end localtbl=ctx.params ifctx.sorttype>0then localnums,words,nn,nw=get_key_list_sorted(tbl,natural_sort) localsequence={} forkey,valinipairs(tbl)dosequence[key]=valend ifctx.sorttype==2then foridx=1,nwdofn_oth(words[idx],tbl[words[idx]])end end foridx=1,nndo ifsequence[nums[idx]]thenfn_seq(nums[idx],sequence[nums[idx]]) elsefn_oth(nums[idx],tbl[nums[idx]])end end ifctx.sorttype~=2then foridx=1,nwdofn_oth(words[idx],tbl[words[idx]])end end return end forkey,valinipairs(tbl)do fn_seq(key,val) tbl[key]=nil end forkey,valinpairs(tbl)dofn_oth(key,val)end end -- Finalize and return a concatenated list localfunctionfinalize_and_return_concatenated_list(ctx,lst,len,modsize) iflen>0then localtmp=ctx.oxfordseporctx.lastsep iftmp~=nilandlen>modsize*2then lst[len-modsize+1]=tmp elseiflen>modsizeandctx.lastsep~=nilthen lst[len-modsize+1]=ctx.lastsep end lst[1]=ctx.headeror'' ifctx.footer~=nilthenlst[len+1]=ctx.footerend ctx.text=table.concat(lst) elsectx.text=ctx.ifngivenor''end end --- --- --- PUBLIC ENVIRONMENT --- --- ________________________________ --- --- --- --[[ Modifiers ]]-- ------------------- -- Syntax: #invoke:params|sequential|pipe to library.sequential=function(ctx) ifctx.subset==1thenerror(modulename.. ': The ‘sequential’ directive has been provided more than once',0)end ifctx.subset==-1thenerror(modulename.. ': The two directives ‘non-sequential’ and ‘sequential’ are in contradiction with each other',0)end ifctx.sorttype>0thenerror(modulename.. ': The ‘all_sorted’ and ‘reassorted’ directives are redundant when followed by ‘sequential’',0)end ctx.iterfunc,ctx.subset=ipairs,1 returncontext_iterate(ctx,1) end -- Syntax: #invoke:params|non-sequential|pipe to library['non-sequential']=function(ctx) ifctx.subset==-1thenerror(modulename.. ': The ‘non-sequential’ directive has been provided more than once',0)end ifctx.subset==1thenerror(modulename.. ': The two directives ‘sequential’ and ‘non-sequential’ are in contradiction with each other',0)end ctx.iterfunc,ctx.subset=pairs,-1 returncontext_iterate(ctx,1) end -- Syntax: #invoke:params|all_sorted|pipe to library.all_sorted=function(ctx) ifctx.sorttype==1thenerror(modulename.. ': The ‘all_sorted’ directive has been provided more than once',0)end ifctx.subset==1thenerror(modulename.. ': The ‘all_sorted’ directive is redundant after ‘sequential’',0)end ifctx.sorttype==2thenerror(modulename.. ': The two directives ‘reassorted’ and ‘sequential’ are in contradiction with each other',0)end ctx.sorttype=1 returncontext_iterate(ctx,1) end -- Syntax: #invoke:params|reassorted|pipe to library.reassorted=function(ctx) ifctx.sorttype==2thenerror(modulename.. ': The ‘reassorted’ directive has been provided more than once',0)end ifctx.subset==1thenerror(modulename.. ': The ‘reassorted’ directive is redundant after ‘sequential’',0)end ifctx.sorttype==1thenerror(modulename.. ': The two directives ‘sequential’ and ‘reassorted’ are in contradiction with each other',0)end ctx.sorttype=2 returncontext_iterate(ctx,1) end -- Syntax: #invoke:params|setting|directives|...|pipe to library.setting=function(ctx) localargc=set_strings_from_opts(ctx,ctx.pipe,1) ifargc<2thenerror(modulename.. ', ‘setting’: No directive was given',0)end returncontext_iterate(ctx,argc+1) end -- Syntax: #invoke:params|scoring|new parameter name|[container]|pipe to library.scoring=function(ctx) ifctx.pipe[1]==nilthenerror(modulename.. ', ‘scoring’: No parameter name was provided',0)end localtmp localretval,opts=0,ctx.pipe for_inpairs(ctx.params)doretval=retval+1end ifopts[2]~=nilthentmp=opts[2]:match'^%s*(.*%S)'end iftmp=='in_substack'then new_substack(ctx)[get_parameter_name(opts[1])]=tostring(retval) returncontext_iterate(ctx,3) end ctx.params[get_parameter_name(opts[1])]=tostring(retval) returncontext_iterate(ctx,tmp=='here'and3or2) end -- Syntax: #invoke:params|squeezing|pipe to library.squeezing=function(ctx) localstore,indices,tbl,newlen={},{},ctx.params,0 forkey,valinpairs(tbl)do iftype(key)=='number'then newlen=newlen+1 indices[newlen],store[key],tbl[key]=key,val,nil end end table.sort(indices) foridx=1,newlendotbl[idx]=store[indices[idx]]end returncontext_iterate(ctx,1) end -- Syntax: #invoke:params|filling_the_gaps|pipe to library.filling_the_gaps=function(ctx) localnewval,tbl,tmp,nmin,nmax,nnums= ctx.pipe[1],ctx.params,{},1,nil,-1 ifnewval==nilthenerror(modulename.. ', ‘filling_the_gaps’: No value was provided',0)end forkey,valinpairs(tbl)do iftype(key)=='number'then ifnmax==nilthen ifkey<nminthennmin=keyend nmax=key elseifkey>nmaxthennmax=key elseifkey<nminthennmin=keyend tmp[key],nnums=val,nnums+1 end end ifnmax~=nilandnmax-nmin>nnumsthen ctx.n_available=ctx.n_available+nmin+nnums-nmax ifctx.n_available<0thenerror(modulename.. ', ‘filling_the_gaps’: It is possible to fill at most '.. tostring(maxfill)..' parameters',0)end foridx=nmin,nmax,1dotbl[idx]=newvalend forkey,valinpairs(tmp)dotbl[key]=valend end returncontext_iterate(ctx,2) end -- Syntax: #invoke:params|clearing|pipe to library.clearing=function(ctx) localtbl,numerics=ctx.params,{} forkey,valinpairs(tbl)do iftype(key)=='number'then numerics[key],tbl[key]=val,nil end end forkey,valinipairs(numerics)dotbl[key]=valend returncontext_iterate(ctx,1) end -- Syntax: #invoke:params|cutting|left cut|right cut|pipe to library.cutting=function(ctx) locallcut=tonumber(ctx.pipe[1]) iflcut==nilormath.floor(lcut)~=lcutthenerror(modulename.. ', ‘cutting’: Left cut must be an integer number',0)end localrcut=tonumber(ctx.pipe[2]) ifrcut==nilormath.floor(rcut)~=rcutthenerror(modulename.. ', ‘cutting’: Right cut must be an integer number',0)end localtbl=ctx.params locallen=#tbl iflcut<0thenlcut=len+lcutend ifrcut<0thenrcut=len+rcutend localtot=lcut+rcut iftot>0then localcache={} iftot>=lenthen forkeyinipairs(tbl)dotbl[key]=nilend tot=len else foridx=len-rcut+1,len,1dotbl[idx]=nilend foridx=1,lcut,1dotbl[idx]=nilend end forkey,valinpairs(tbl)do iftype(key)=='number'andkey>0then ifkey>lenthencache[key-tot]=val elsecache[key-lcut]=valend tbl[key]=nil end end forkey,valinpairs(cache)dotbl[key]=valend end returncontext_iterate(ctx,3) end -- Syntax: #invoke:params|cropping|left crop|right crop|pipe to library.cropping=function(ctx) locallcut=tonumber(ctx.pipe[1]) iflcut==nilormath.floor(lcut)~=lcutthenerror(modulename.. ', ‘cropping’: Left crop must be an integer number',0)end localrcut=tonumber(ctx.pipe[2]) ifrcut==nilormath.floor(rcut)~=rcutthenerror(modulename.. ', ‘cropping’: Right crop must be an integer number',0)end localtbl=ctx.params localnmin,nmax forkeyinpairs(tbl)do iftype(key)=='number'then ifnmin==nilthennmin,nmax=key,key elseifkey>nmaxthennmax=key elseifkey<nminthennmin=keyend end end ifnmin~=nilthen locallen=nmax-nmin+1 iflcut<0thenlcut=len+lcutend ifrcut<0thenrcut=len+rcutend iflcut+rcut-len>-1then forkeyinpairs(tbl)do iftype(key)=='number'thentbl[key]=nilend end elseiflcut+rcut>0then foridx=nmax-rcut+1,nmaxdotbl[idx]=nilend foridx=nmin,nmin+lcut-1dotbl[idx]=nilend locallshift=nmin+lcut-1 iflshift>0then foridx=lshift+1,nmax,1do tbl[idx-lshift],tbl[idx]= tbl[idx],nil end end end end returncontext_iterate(ctx,3) end -- Syntax: #invoke:params|purging|start offset|length|pipe to library.purging=function(ctx) localidx=tonumber(ctx.pipe[1]) ifidx==nilormath.floor(idx)~=idxthenerror(modulename.. ', ‘purging’: Start offset must be an integer number',0)end locallen=tonumber(ctx.pipe[2]) iflen==nilormath.floor(len)~=lenthenerror(modulename.. ', ‘purging’: Length must be an integer number',0)end localtbl=ctx.params iflen<1then len=len+table.maxn(tbl) ifidx>lenthenreturncontext_iterate(ctx,3)end len=len-idx+1 end ctx.params=copy_table_reduced(tbl,idx,len) returncontext_iterate(ctx,3) end -- Syntax: #invoke:params|backpurging|start offset|length|pipe to library.backpurging=function(ctx) locallast=tonumber(ctx.pipe[1]) iflast==nilormath.floor(last)~=lastthenerror(modulename.. ', ‘backpurging’: Start offset must be an integer number',0)end locallen=tonumber(ctx.pipe[2]) iflen==nilormath.floor(len)~=lenthenerror(modulename.. ', ‘backpurging’: Length must be an integer number',0)end localidx localtbl=ctx.params iflen>0then idx=last-len+1 else forkeyinpairs(tbl)do iftype(key)=='number'and(idx==nilor key<idx)thenidx=keyend end ifidx==nilthenreturncontext_iterate(ctx,3)end idx=idx-len iflast<idxthenreturncontext_iterate(ctx,3)end len=last-idx+1 end ctx.params=copy_table_reduced(ctx.params,idx,len) returncontext_iterate(ctx,3) end -- Syntax: #invoke:params|shifting|addend|pipe to library.shifting=function(ctx) -- NOTE: `ctx.params` might be the original metatable! As a modifier, -- this function MUST create a copy of it before returning localnshift=tonumber(ctx.pipe[1]) ifnshift==nilornshift==0ormath.floor(nshift)~=nshiftthen error(modulename..', ‘shifting’: A non-zero integer number must be provided',0)end localtbl={} forkey,valinpairs(ctx.params)do iftype(key)=='number'thentbl[key+nshift]=val elsetbl[key]=valend end ctx.params=tbl returncontext_iterate(ctx,2) end -- Syntax: #invoke:params|reversing_numeric_names|pipe to library.reversing_numeric_names=function(ctx) localtbl,numerics,nmax=ctx.params,{},0 forkey,valinpairs(tbl)do iftype(key)=='number'then numerics[key],tbl[key]=val,nil ifkey>nmaxthennmax=keyend end end forkey,valinpairs(numerics)dotbl[nmax-key+1]=valend returncontext_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 nmax, nmin local tbl, numerics = ctx.params, {} for key, val in pairs(tbl) do if type(key) == 'number' then numerics[key] = val tbl[key] = nil if nmax == nil then nmin, nmax = key, 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 tmp local tbl, cache, nsize = ctx.params, {}, 0 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) localsortfn ifctx.pipe[1]~=nilthen sortfn=sortfunctions[ctx.pipe[1]:match'^%s*(.-)%s*$'] end ifsortfnthentable.sort(ctx.params,sortfn) elsetable.sort(ctx.params)end-- i.e. either `false` or `nil` ifsortfn==nilthenreturncontext_iterate(ctx,1)end returncontext_iterate(ctx,2) end -- Syntax: #invoke:params|splicing|[add to position]|position|increment| -- [number of elements to write]|...|pipe to library.splicing=function(ctx) -- NOTE: `ctx.params` might be the original metatable! As a modifier, -- this function MUST create a copy of it before returning localtmp2,argc,pos,refp localopts,tbl=ctx.pipe,ctx.params localtmp1=opts[1] iftmp1~=nilthen tmp2=tonumber(tmp1) iftmp2==nilormath.floor(tmp2)~=tmp2then pos,argc,tmp2=tonumber(opts[2]),4, tmp1:match'^%s*(.*%S)' iftmp2~=nilthen refp=position_references[tmp2] ifrefp==nilthenerror(modulename.. ', ‘splicing’: ‘'..tostring(tmp2).. '’ is not a valid first argument',0)end elserefp=0end elsepos,argc,refp=tmp2,3,0end elsepos,argc,refp=tonumber(opts[2]),4,0end ifpos==nilormath.floor(pos)~=posthenerror(modulename.. ', ‘splicing’: The position must be an integer number',0)end locallen=tonumber(opts[argc-1]) iflen==nilormath.floor(len)~=lenthenerror(modulename.. ', ‘splicing’: The increment must be an integer number',0)end localinsn=tonumber(opts[argc]) iflen==0and(insn==nilorinsn<1)thenerror(modulename.. ', ‘splicing’: When the increment is zero the number of elements to write cannot be zero',0)end ifrefp==2then for_inipairs(tbl)dopos=pos+1end refp=0 end tmp1,tmp2=nil,nil ifrefp~=0orlen~=0then forkey,valinpairs(tbl)do iftype(key)=='number'then iftmp1==nilthentmp1,tmp2=key,key elseifkey<tmp1thentmp1=key elseifkey>tmp2thentmp2=keyend end end end iftmp2==nilthenlen=0 elseifrefp==3thenpos=pos+tmp2 elseifrefp==1thenpos=pos+tmp1end iflen>0andpos+len>tmp1andpos<=tmp2then tbl=copy_table_expanded(tbl,pos,len) elseiflen<0andpos-len>tmp1andpos<=tmp2then tbl=copy_table_reduced(tbl,pos,-len) elsetbl=copy_or_ref_table(tbl,tbl~=ctx.oparams)end ctx.params=tbl ifinsn==nilorinsn<0ormath.floor(insn)~=insnthen returncontext_iterate(ctx,argc) end tmp1=argc-pos+1 forkey=pos,pos+insn-1dotbl[key]=opts[key+tmp1]end returncontext_iterate(ctx,argc+insn+1) end -- Syntax: #invoke:params|imposing|name|value|pipe to library.imposing=function(ctx) ifctx.pipe[1]==nilthenerror(modulename.. ', ‘imposing’: Missing parameter name to impose',0)end ctx.params[get_parameter_name(ctx.pipe[1])]=ctx.pipe[2] returncontext_iterate(ctx,3) end -- Syntax: #invoke:params|providing|name|value|pipe to library.providing=function(ctx) ifctx.pipe[1]==nilthenerror(modulename.. ', ‘providing’: Missing parameter name to provide',0)end localkey=get_parameter_name(ctx.pipe[1]) ifctx.params[key]==nilthenctx.params[key]=ctx.pipe[2]end returncontext_iterate(ctx,3) end -- Syntax: #invoke:params|reassigning|source|destination|[mode]|pipe to library.reassigning=function(ctx) localopts,tbl=ctx.pipe,ctx.params ifopts[1]==nilthenerror(modulename.. ', ‘reassigning’: Missing source parameter',0)end ifopts[2]==nilthenerror(modulename.. ', ‘reassigning’: Missing destination parameter',0)end localmode,argc localsrc=get_parameter_name(opts[1]) localval=tbl[src] ifopts[3]~=nilthenmode=a_modes[opts[3]:match'^%s*(.-)%s*$']end ifmode==nilthenmode,argc=0,3elseargc=4end ifval==nilandmode>1thenreturncontext_iterate(ctx,argc)end localdest=get_parameter_name(opts[2]) localtmp=tbl[dest]==nil ifmode%2==0or(mode==7andtmp)thentbl[src]=nilend iftmpormode<4thentbl[dest]=valend returncontext_iterate(ctx,argc) end -- Syntax: #invoke:params|discarding|name|[how many]|pipe to library.discarding=function(ctx) ifctx.pipe[1]==nilthenerror(modulename.. ', ‘discarding’: Missing parameter name to discard',0)end locallen=tonumber(ctx.pipe[2]) iflen==nilthen ctx.params[get_parameter_name(ctx.pipe[1])]=nil returncontext_iterate(ctx,2) end localkey=tonumber(ctx.pipe[1]) ifkey==nilormath.floor(key)~=keythenerror(modulename.. ', ‘discarding’: A range was provided, but the initial parameter name is not an integer number',0)end iflen<1ormath.floor(len)~=lenthenerror(modulename.. ', ‘discarding’: A range can only be an integer number greater than zero',0)end foridx=key,key+len-1doctx.params[idx]=nilend returncontext_iterate(ctx,3) end -- Syntax: #invoke:params|excluding_non-numeric_names|pipe to library['excluding_non-numeric_names']=function(ctx) localtmp=ctx.params forkey,valinpairs(tmp)do iftype(key)~='number'thentmp[key]=nilend end returncontext_iterate(ctx,1) end -- Syntax: #invoke:params|excluding_numeric_names|pipe to library.excluding_numeric_names=function(ctx) localtmp=ctx.params forkey,valinpairs(tmp)do iftype(key)=='number'thentmp[key]=nilend end returncontext_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 localtmp,ptn localtargets,nptns,argc=load_pattern_args(ctx.pipe, 'with_name_matching') localtbl,newparams=ctx.params,{} foridx=1,nptnsdo ptn=targets[idx] ifptn[3]then tmp=ptn[1] iftmp=='0'ortmp:find'^%-?[1-9]%d*$'~=nilthen tmp=tonumber(tmp) end newparams[tmp]=tbl[tmp] else forkey,valinpairs(tbl)do iftostring(key):find(ptn[1],1,ptn[2])then newparams[key]=val end end end end ctx.params=newparams returncontext_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) localtargets,nptns,argc=load_pattern_args(ctx.pipe, 'with_name_not_matching') localtbl=ctx.params ifnptns==1andtargets[1][3]then localtmp=targets[1][1] iftmp=='0'ortmp:find'^%-?[1-9]%d*$'~=nilthen tbl[tonumber(tmp)]=nil elsetbl[tmp]=nilend returncontext_iterate(ctx,argc) end localyesmatch,ptn forkeyinpairs(tbl)do yesmatch=true foridx=1,nptnsdo ptn=targets[idx] ifptn[3]then iftostring(key)~=ptn[1]then yesmatch=false break end elseifnottostring(key):find(ptn[1],1,ptn[2])then yesmatch=false break end end ifyesmatchthentbl[key]=nilend end returncontext_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) localnomatch,ptn localtbl=ctx.params localtargets,nptns,argc=load_pattern_args(ctx.pipe, 'with_value_matching') forkey,valinpairs(tbl)do nomatch=true foridx=1,nptnsdo ptn=targets[idx] ifptn[3]then ifval==ptn[1]then nomatch=false break end elseifval:find(ptn[1],1,ptn[2])then nomatch=false break end end ifnomatchthentbl[key]=nilend end returncontext_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) localyesmatch,ptn localtbl=ctx.params localtargets,nptns,argc=load_pattern_args(ctx.pipe, 'with_value_not_matching') forkey,valinpairs(tbl)do yesmatch=true foridx=1,nptnsdo ptn=targets[idx] ifptn[3]then ifval~=ptn[1]then yesmatch=false break end elseifnotval:find(ptn[1],1,ptn[2])then yesmatch=false break end end ifyesmatchthentbl[key]=nilend end returncontext_iterate(ctx,argc) end -- Syntax: #invoke:params|keeping_at_most|number of parameters to pick|pipe to library.keeping_at_most=function(ctx) -- NOTE: `ctx.params` might be the original metatable! As a modifier, -- this function MUST create a copy of it before returning locallen=tonumber(ctx.pipe[1]) iflen==nilorlen<1ormath.floor(len)~=lenthenerror(modulename.. ', ‘keeping_at_most’: The number of parameters to keep must be an integer greater than zero',0)end ctx.params=copy_table_maxn({},ctx.params,len) returncontext_iterate(ctx,2) end -- Syntax: #invoke:params|trimming_values|pipe to library.trimming_values=function(ctx) localtbl=ctx.params forkey,valinpairs(tbl)dotbl[key]=val:match'^%s*(.-)%s*$'end returncontext_iterate(ctx,1) end -- Syntax: #invoke:params|mapping_to_lowercase|pipe to library.mapping_to_lowercase=function(ctx) localtbl=ctx.params forkey,valinpairs(tbl)dotbl[key]=val:lower()end returncontext_iterate(ctx,1) end -- Syntax: #invoke:params|mapping_to_uppercase|pipe to library.mapping_to_uppercase=function(ctx) localtbl=ctx.params forkey,valinpairs(tbl)dotbl[key]=val:upper()end returncontext_iterate(ctx,1) end -- Syntax: #invoke:params|mapping_by_calling|template name|[call -- style]|[let/use]|[...]|[let/use]|[...]|[number of additional -- parameters]|[parameter 1]|[parameter 2]|[...]|[parameter N]|pipe to library.mapping_by_calling=function(ctx) localtname localopts=ctx.pipe ifopts[1]~=nilthentname=opts[1]:match'^%s*(.*%S)'end iftname==nilthenerror(modulename.. ', ‘mapping_by_calling’: No template name was provided',0)end localmargs,argc,looptype,karg,varg,tbl,mem= load_callback_opts(opts,1,mapping_styles.values_only,ctx.params) localmodel={title=tname,args=margs} value_maps[looptype](tbl,margs,karg,varg,function() returnctx.frame:expandTemplate(model) end) forkey,valinpairs(mem)dotbl[key]=valend ctx.params=tbl returncontext_iterate(ctx,argc) end -- Syntax: #invoke:params|mapping_by_invoking|module name|function name|[call -- style]|[let/use]|[...]|[let/use]|[...]|[number of additional -- arguments]|[argument 1]|[argument 2]|[...]|[argument N]|pipe to library.mapping_by_invoking=function(ctx) localmname,fname localopts=ctx.pipe ifopts[1]~=nilthenmname=opts[1]:match'^%s*(.*%S)'end ifmname==nilthenerror(modulename.. ', ‘mapping_by_invoking’: No module name was provided',0)end ifopts[2]~=nilthenfname=opts[2]:match'^%s*(.*%S)'end iffname==nilthenerror(modulename.. ', ‘mapping_by_invoking’: No function name was provided',0)end localmargs,argc,looptype,karg,varg,tbl,mem= load_callback_opts(opts,2,mapping_styles.values_only,ctx.params) localmodel={title='Module:'..mname,args=margs} localmfunc=require(model.title)[fname] ifmfunc==nilthenerror(modulename.. ', ‘mapping_by_invoking’: The function ‘'..fname.. '’ does not exist',0)end value_maps[looptype](tbl,margs,karg,varg,function() returntostring(mfunc(ctx.frame:newChild(model))) end) forkey,valinpairs(mem)dotbl[key]=valend ctx.params=tbl returncontext_iterate(ctx,argc) end -- Syntax: #invoke:params|mapping_by_magic|parser function|[call -- style]|[let/use]|[...]|[let/use]|[...]|[number of additional -- arguments]|[argument 1]|[argument 2]|[...]|[argument N]|pipe to library.mapping_by_magic=function(ctx) localmagic localopts=ctx.pipe ifopts[1]~=nilthenmagic=opts[1]:match'^%s*(.*%S)'end ifmagic==nilthenerror(modulename.. ', ‘mapping_by_magic’: No parser function was provided',0)end localmargs,argc,looptype,karg,varg,tbl,mem= load_callback_opts(opts,1,mapping_styles.values_only,ctx.params) value_maps[looptype](tbl,margs,karg,varg,function() returnctx.frame:callParserFunction(magic,margs) end) forkey,valinpairs(mem)dotbl[key]=valend ctx.params=tbl returncontext_iterate(ctx,argc) end -- Syntax: #invoke:params|mapping_by_replacing|target|replace|[count]|[plain -- flag]|pipe to library.mapping_by_replacing=function(ctx) localptn,repl,nmax,flg,argc,die= load_replace_args(ctx.pipe,'mapping_by_replacing') ifdiethenreturncontext_iterate(ctx,argc)end localtbl=ctx.params ifflg==3then forkey,valinpairs(tbl)do ifval==ptnthentbl[key]=replend end else ifflg==2then -- Copied from Module:String's `str._escapePattern()` ptn=ptn:gsub('[%(%)%.%%%+%-%*%?%[%^%$%]]','%%%0') end forkey,valinpairs(tbl)do tbl[key]=val:gsub(ptn,repl,nmax) end end returncontext_iterate(ctx,argc) end -- Syntax: #invoke:params|mapping_by_mixing|mixing string|pipe to library.mapping_by_mixing=function(ctx) ifctx.pipe[1]==nilthenerror(modulename.. ', ‘mapping_by_mixing’: No mixing string was provided',0)end localtbl,mix=ctx.params,ctx.pipe[1] ifmix=='$#'then forkeyinpairs(tbl)dotbl[key]=tostring(key)end returncontext_iterate(ctx,2) end localskel,cnv,n_parts=parse_placeholder_string(mix) forkey,valinpairs(tbl)do foridx=2,n_parts,2do ifskel[idx]thencnv[idx]=val elsecnv[idx]=tostring(key)end end tbl[key]=table.concat(cnv) end returncontext_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] = tostring(key) end return context_iterate(ctx, 1) end ]]-- -- Syntax: #invoke:params|renaming_to_lowercase|pipe to library.renaming_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 localcache={} forkey,valinpairs(ctx.params)do iftype(key)=='string'thencache[key:lower()]=valelse cache[key]=valend end ctx.params=cache returncontext_iterate(ctx,1) end -- Syntax: #invoke:params|renaming_to_uppercase|pipe to library.renaming_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 localcache={} forkey,valinpairs(ctx.params)do iftype(key)=='string'thencache[key:upper()]=valelse cache[key]=valend end ctx.params=cache returncontext_iterate(ctx,1) end -- Syntax: #invoke:params|renaming_to_sequence|[sort order]|pipe to library.renaming_to_sequence=function(ctx) -- NOTE: `ctx.params` might be the original metatable! As a modifier, -- this function MUST create a copy of it before returning localcache,len localtbl=ctx.params localsortfn,argc,do_sort=load_sort_opt(ctx.pipe[1]) ifdo_sortthen localwords,wl cache,words,len,wl=get_key_list_sorted(tbl,sortfn) foridx=1,lendocache[idx]=tbl[cache[idx]]end foridx=1,wldocache[len+idx]=tbl[words[idx]]end else len,cache=0,{} for_,valinpairs(tbl)do len=len+1 cache[len]=val end end ctx.params=cache returncontext_iterate(ctx,argc) end -- Syntax: #invoke:params|renaming_by_calling|template name|[call -- style]|[let/use]|[...]|[let/use]|[...]|[number of additional -- parameters]|[parameter 1]|[parameter 2]|[...]|[parameter N]|pipe to library.renaming_by_calling=function(ctx) localtname localopts=ctx.pipe ifopts[1]~=nilthentname=opts[1]:match'^%s*(.*%S)'end iftname==nilthenerror(modulename.. ', ‘renaming_by_calling’: No template name was provided',0)end localrargs,argc,looptype,karg,varg,tbl,mem= load_callback_opts(opts,1,mapping_styles.names_only,ctx.params) localmodel={title=tname,args=rargs} map_names(tbl,rargs,karg,varg,looptype,function() returnctx.frame:expandTemplate(model) end) forkey,valinpairs(mem)dotbl[key]=valend ctx.params=tbl returncontext_iterate(ctx,argc) end -- Syntax: #invoke:params|renaming_by_invoking|module name|function -- name|[call style]|[let/use]|[...]|[let/use]|[...]|[number of -- additional arguments]|[argument 1]|[argument 2]|[...]|[argument -- N]|pipe to library.renaming_by_invoking=function(ctx) localmname,fname localopts=ctx.pipe ifopts[1]~=nilthenmname=opts[1]:match'^%s*(.*%S)'end ifmname==nilthenerror(modulename.. ', ‘renaming_by_invoking’: No module name was provided',0)end ifopts[2]~=nilthenfname=opts[2]:match'^%s*(.*%S)'end iffname==nilthenerror(modulename.. ', ‘renaming_by_invoking’: No function name was provided',0)end localrargs,argc,looptype,karg,varg,tbl,mem= load_callback_opts(opts,2,mapping_styles.names_only,ctx.params) localmodel={title='Module:'..mname,args=rargs} localmfunc=require(model.title)[fname] ifmfunc==nilthenerror(modulename.. ', ‘renaming_by_invoking’: The function ‘'..fname.. '’ does not exist',0)end map_names(tbl,rargs,karg,varg,looptype,function() returntostring(mfunc(ctx.frame:newChild(model))) end) forkey,valinpairs(mem)dotbl[key]=valend ctx.params=tbl returncontext_iterate(ctx,argc) end -- Syntax: #invoke:params|renaming_by_magic|parser function|[call -- style]|[let/use]|[...]|[let/use]|[...]|[number of additional -- arguments]|[argument 1]|[argument 2]|[...]|[argument N]|pipe to library.renaming_by_magic=function(ctx) localopts=ctx.pipe localmagic ifopts[1]~=nilthenmagic=opts[1]:match'^%s*(.*%S)'end ifmagic==nilthenerror(modulename.. ', ‘renaming_by_magic’: No parser function was provided',0)end localrargs,argc,looptype,karg,varg,tbl,mem= load_callback_opts(opts,1,mapping_styles.names_only,ctx.params) map_names(tbl,rargs,karg,varg,looptype,function() returnctx.frame:callParserFunction(magic,rargs) end) forkey,valinpairs(mem)dotbl[key]=valend ctx.params=tbl returncontext_iterate(ctx,argc) end -- Syntax: #invoke:params|renaming_by_replacing|target|replace|[count]|[plain -- flag]|pipe to library.renaming_by_replacing=function(ctx) localptn,repl,nmax,flg,argc,die= load_replace_args(ctx.pipe,'renaming_by_replacing') ifdiethenreturncontext_iterate(ctx,argc)end localtbl=ctx.params ifflg==3then ptn=get_parameter_name(ptn) localval=tbl[ptn] ifval~=nilthen tbl[ptn],tbl[get_parameter_name(repl)]=nil,val end else ifflg==2then -- Copied from Module:String's `str._escapePattern()` ptn=ptn:gsub('[%(%)%.%%%+%-%*%?%[%^%$%]]','%%%0') end localcache={} forkey,valinpairs(tbl)do steal_if_renamed(val,tbl,key,cache, tostring(key):gsub(ptn,repl,nmax)) end forkey,valinpairs(cache)dotbl[key]=valend end returncontext_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 ifctx.pipe[1]==nilthenerror(modulename.. ', ‘renaming_by_mixing’: No mixing string was provided',0)end localmix=ctx.pipe[1]:match'^%s*(.-)%s*$' localcache={} ifmix=='$@'then for_,valinpairs(ctx.params)do cache[get_parameter_name(val)]=val end else localskel,canvas,n_parts=parse_placeholder_string(mix) forkey,valinpairs(ctx.params)do foridx=2,n_parts,2do ifskel[idx]thencanvas[idx]=val elsecanvas[idx]=tostring(key)end end cache[get_parameter_name(table.concat(canvas))]=val end end ctx.params=cache returncontext_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/use]|[...]|[let/use]|[...]|[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 localtmp,argc,tbl,mem=load_child_opts(ctx.pipe,2,0,ctx.params) localgargs={} forkey,valinpairs(tmp)do iftype(key)=='number'andkey<1thengargs[key-1]=val elsegargs[key]=valend end tmp=ctx.pipe[1] iftmp~=nilthentmp=tmp:match'^%s*(.*%S)'end iftmp==nilthenerror(modulename.. ', ‘grouping_by_calling’: No template name was provided',0)end localmodel={title=tmp} localgroups=make_groups(tbl) forgid,groupinpairs(groups)do forkey,valinpairs(gargs)dogroup[key]=valend group[0],model.args=gid,group groups[gid]=ctx.frame:expandTemplate(model) end forkey,valinpairs(mem)dogroups[key]=valend ctx.params=groups returncontext_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) localopts=ctx.pipe ifopts[1]==nilthenerror(modulename.. ', ‘parsing’: No string to parse was provided',0)end localisep,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 to library.reinterpreting=function(ctx) localopts=ctx.pipe ifopts[1]==nilthenerror(modulename.. ', ‘reinterpreting’: No parameter to reinterpret was provided',0)end localisep,iplain,psep,pplain,trimnamed,trimunnamed,argc= load_parse_opts(opts,2,'|','=') localtbl,tmp=ctx.params,get_parameter_name(opts[1]) localstr=tbl[tmp] ifstr~=nilthen tbl[tmp]=nil parse_parameter_string(tbl,str,isep,iplain,psep,pplain, trimnamed,trimunnamed) end returncontext_iterate(ctx,argc) end -- Syntax: #invoke:params|evaluating|string to parse|[trim flag]|[iteration -- delimiter setter]|[...]|[key-value delimiter setter]|[...]|pipe to library.evaluating=function(ctx) -- NOTE: `ctx.pipe` might be the original metatable! As a modifier, -- this function MUST create a copy of it before returning localopts=ctx.pipe ifopts[1]==nilthenerror(modulename.. ', ‘evaluating’: No string to parse was provided',0)end localisep,iplain,psep,pplain,trimnamed,trimunnamed,argc= load_parse_opts(opts,2,'!',':') ifopts[1]:match'^%s*(.*%S)'==nilthen ctx.pipe=copy_or_ref_table(opts,opts~=ctx.opipe) returncontext_iterate(ctx,argc) end localnew_opts,cache={},{} localshift=parse_parameter_string(cache,opts[1],isep,iplain, psep,pplain,trimnamed,trimunnamed)-argc forkey,valinpairs(opts)do iftype(key)~='number'orkey<1thennew_opts[key]=val elseifkey>=argcthennew_opts[key+shift]=valend end forkey,valinpairs(cache)donew_opts[key]=valend ctx.pipe=new_opts returncontext_iterate(ctx,1) 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 ifctx.pipe[1]==nilthenerror(modulename.. ', ‘mixing_names_and_values’: No mixing string was provided for parameter names',0)end ifctx.pipe[2]==nilthenerror(modulename.. ', ‘mixing_names_and_values’: No mixing string was provided for parameter values',0)end localtmp localmix_k=ctx.pipe[1]:match'^%s*(.-)%s*$' localcache,mix_v={},ctx.pipe[2] ifmix_k=='$@'andmix_v=='$@'then for_,valinpairs(ctx.params)do cache[get_parameter_name(val)]=val end elseifmix_k=='$@'andmix_v=='$#'then forkey,valinpairs(ctx.params)do cache[get_parameter_name(val)]=tostring(key) end elseifmix_k=='$#'andmix_v=='$#'then forkeyinpairs(ctx.params)docache[key]=tostring(key)end else localskel_k,cnv_k,n_parts_k=parse_placeholder_string(mix_k) localskel_v,cnv_v,n_parts_v=parse_placeholder_string(mix_v) forkey,valinpairs(ctx.params)do tmp=tostring(key) foridx=2,n_parts_k,2do ifskel_k[idx]thencnv_k[idx]=valelsecnv_k[idx]=tmpend end foridx=2,n_parts_v,2do ifskel_v[idx]thencnv_v[idx]=valelsecnv_v[idx]=tmpend end cache[get_parameter_name(table.concat(cnv_k))]= table.concat(cnv_v) end end ctx.params=cache returncontext_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|new parameter name|[sort -- order]|[with/without flushed glue]|setting directives|...|pipe to library.combining=function(ctx) -- NOTE: `ctx.params` might be the original metatable! As a modifier, -- this function MUST create a copy of it before returning returncontext_iterate(ctx,combine_parameters( ctx, function(key,val,kvs)returnkey..kvs..valend, 'combining' )+1) end -- Syntax: #invoke:params|combining_values|new parameter name|[sort -- order]|[with/without flushed glue]|setting directives|...|pipe to library.combining_values=function(ctx) -- NOTE: `ctx.params` might be the original metatable! As a modifier, -- this function MUST create a copy of it before returning returncontext_iterate(ctx,combine_parameters( ctx, function(key,val,kvs)returnvalend, 'combining_values' )+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 localtname=ctx.pipe[1] iftname~=nilthentname=tname:match'^%s*(.*%S)' elseerror(modulename.. ', ‘combining_by_calling’: No template name was provided',0)end ifctx.pipe[2]==nilthenerror(modulename.. ', ‘combining_by_calling’: No parameter name was provided',0)end ctx.params={ [get_parameter_name(ctx.pipe[2])]=ctx.frame:expandTemplate{ title=tname, args=ctx.params } } returncontext_iterate(ctx,3) end -- Syntax: #invoke:params|combining_by_invoking|module name|function name|new -- parameter name|pipe to library.combining_by_invoking=function(ctx) -- NOTE: `ctx.params` might be the original metatable! As a modifier, -- this function MUST create a copy of it before returning localmname=ctx.pipe[1] ifmname~=nilthenmname=mname:match'^%s*(.*%S)' elseerror(modulename.. ', ‘combining_by_invoking’: No module name was provided',0)end localfname=ctx.pipe[2] iffname~=nilthenfname=fname:match'^%s*(.*%S)' elseerror(modulename.. ', ‘combining_by_invoking’: No function name was provided',0)end ifctx.pipe[3]==nilthenerror(modulename.. ', ‘combining_by_invoking’: No parameter name was provided',0)end localmodel={title='Module:'..mname,args=ctx.params} localmfunc=require(model.title)[fname] ifmfunc==nilthenerror(modulename.. ', ‘mapping_by_invoking’: The function ‘'..fname.. '’ does not exist',0)end ctx.params={ [get_parameter_name(ctx.pipe[3])]= tostring(mfunc(ctx.frame:newChild(model))) } returncontext_iterate(ctx,4) end -- Syntax: #invoke:params|combining_by_magic|parser function|new parameter -- name|pipe to library.combining_by_magic=function(ctx) -- NOTE: `ctx.params` might be the original metatable! As a modifier, -- this function MUST create a copy of it before returning localmagic=ctx.pipe[1] ifmagic~=nilthenmagic=magic:match'^%s*(.*%S)' elseerror(modulename.. ', ‘combining_by_magic’: No parser function was provided',0)end ifctx.pipe[2]==nilthenerror(modulename.. ', ‘combining_by_magic’: No parameter name was provided',0)end ctx.params={ [get_parameter_name(ctx.pipe[2])]= ctx.frame:callParserFunction(magic,ctx.params) } returncontext_iterate(ctx,3) end -- Syntax: #invoke:params|snapshotting|[maximum number]|pipe to library.snapshotting=function(ctx) returncontext_iterate(ctx,make_child(ctx,ctx.params,'snapshotting')) end -- Syntax: #invoke:params|remembering|[maximum number]|pipe to library.remembering=function(ctx) returncontext_iterate(ctx,make_child(ctx,ctx.oparams,'remembering')) end -- Syntax: #invoke:params|entering_substack|[new]|pipe to library.entering_substack=function(ctx) localtbl,ncurrparent=ctx.params,ctx.n_parents+1 ifctx.parents==nilthenctx.parents={tbl} elsectx.parents[ncurrparent]=tblend ctx.n_parents=ncurrparent ifctx.pipe[1]~=nilandctx.pipe[1]:match'^%s*new%s*$'then ctx.params={} returncontext_iterate(ctx,2) end localcurrsnap=ctx.n_children ifcurrsnap>0then ctx.params,ctx.children[currsnap],ctx.n_children= ctx.children[currsnap],nil,currsnap-1 else localnewparams={} forkey,valinpairs(tbl)donewparams[key]=valend ctx.params=newparams end returncontext_iterate(ctx,1) end -- Syntax: #invoke:params|pulling|parameter name|pipe to library.pulling=function(ctx) localopts=ctx.pipe ifopts[1]==nilthenerror(modulename.. ', ‘pulling’: No parameter to pull was provided',0)end localtmp=ctx.n_parents localparent=tmp<1andctx.oparamsorctx.parents[tmp] tmp=get_parameter_name(opts[1]) ifparent[tmp]~=nilthenctx.params[tmp]=parent[tmp]end returncontext_iterate(ctx,2) end -- Syntax: #invoke:params|recalling|parameter name|pipe to library.recalling=function(ctx) localopts=ctx.pipe ifopts[1]==nilthenerror(modulename.. ', ‘recalling’: No parameter to recall was provided',0)end localarg=get_parameter_name(opts[1]) ifctx.oparams[arg]~=nilthenctx.params[arg]=ctx.oparams[arg]end returncontext_iterate(ctx,2) end -- Syntax: #invoke:params|finding|parameter name|pipe to --[[ library.finding = function (ctx) local opts = ctx.pipe if opts[1] == nil then error(modulename .. ', ‘finding’: No parameter to find was provided', 0) end local arg = get_parameter_name(opts[1]) local parent for idx = ctx.n_parents, 1, -1 do parent = ctx.parents[idx] if parent[arg] ~= nil then ctx.params[arg] = parent[arg] return context_iterate(ctx, 2) end end if ctx.oparams[arg] ~= nil then ctx.params[arg] = ctx.oparams[arg] end return context_iterate(ctx, 2) end ]]-- -- Syntax: #invoke:params|picking|number of parameters to pick|pipe to --[[ library.picking = function (ctx) local len = tonumber(ctx.pipe[1]) if len == nil or len < 1 or math.floor(len) ~= len then error(modulename .. ', ‘picking’: The number of parameters to pick must be an integer greater than zero', 0) end if ctx.n_parents < 1 then copy_table_maxn(ctx.params, ctx.oparams, len) else copy_table_maxn(ctx.params, ctx.parents[ctx.n_parents], len) end return context_iterate(ctx, 2) end ]]-- -- Syntax: #invoke:params|detaching_substack|pipe to library.detaching_substack=function(ctx) localncurrparent=ctx.n_parents ifncurrparent<1thenerror(modulename.. ', ‘detaching_substack’: No substack has been created',0)end localparent=ctx.parents[ncurrparent] forkeyinpairs(ctx.params)doparent[key]=nilend returncontext_iterate(ctx,1) end -- Syntax: #invoke:params|dropping_substack|pipe to library.dropping_substack=function(ctx) localncurrparent=ctx.n_parents ifncurrparent<1thenerror(modulename.. ', ‘dropping_substack’: No substack has been created',0)end ctx.params,ctx.parents[ncurrparent],ctx.n_parents= ctx.parents[ncurrparent],nil,ncurrparent-1 returncontext_iterate(ctx,1) end -- Syntax: #invoke:params|leaving_substack|pipe to library.leaving_substack=function(ctx) localncurrparent=ctx.n_parents ifncurrparent<1thenerror(modulename.. ', ‘leaving_substack’: No substack has been created',0)end localcurrsnap=ctx.n_children+1 ifctx.children==nilthenctx.children={ctx.params} elsectx.children[currsnap]=ctx.paramsend ctx.params,ctx.parents[ncurrparent],ctx.n_parents,ctx.n_children= ctx.parents[ncurrparent],nil,ncurrparent-1,currsnap returncontext_iterate(ctx,1) end -- Syntax: #invoke:params|merging_substack|pipe to library.merging_substack=function(ctx) localncurrparent=ctx.n_parents ifncurrparent<1thenerror(modulename.. ', ‘merging_substack’: No substack has been created',0)end localparent,child=ctx.parents[ncurrparent],ctx.params ctx.params,ctx.parents[ncurrparent],ctx.n_parents=parent,nil, ncurrparent-1 forkey,valinpairs(child)doparent[key]=valend returncontext_iterate(ctx,1) end -- Syntax: #invoke:params|flushing|pipe to library.flushing=function(ctx) ifctx.n_children<1thenerror(modulename.. ', ‘flushing’: There are no substacks to flush',0)end localparent,currsnap=ctx.params,ctx.n_children forkey,valinpairs(ctx.children[currsnap])doparent[key]=valend ctx.children[currsnap],ctx.n_children=nil,currsnap-1 returncontext_iterate(ctx,1) end -- Syntax: #invoke:params|setting_by_flushing|pipe to library.setting_by_flushing=function(ctx) set_strings_from_substack(ctx,ctx,'setting_by_flushing') returncontext_iterate(ctx,1) end --[[ Functions ]]-- ----------------------------- -- Syntax: #invoke:params|count library.count=function(ctx) -- NOTE: `ctx.pipe` and `ctx.params` might be the original metatables! localretval=0 for_inctx.iterfunc(ctx.params)doretval=retval+1end ifctx.subset==-1thenretval=retval-#ctx.paramsend ctx.text=retval returnfalse 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! localtname localopts=ctx.pipe ifopts[1]~=nilthentname=opts[1]:match'^%s*(.*%S)'end iftname==nilthenerror(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) } returnfalse 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! localmname,fname localopts=ctx.pipe ifopts[1]~=nilthenmname=opts[1]:match'^%s*(.*%S)'end ifmname==nilthenerror(modulename.. ', ‘concat_and_invoke’: No module name was provided',0)end ifopts[2]~=nilthenfname=opts[2]:match'^%s*(.*%S)'end iffname==nilthenerror(modulename.. ', ‘concat_and_invoke’: No function name was provided',0)end remove_numeric_keys(opts,1,2) localmfunc=require('Module:'..mname)[fname] ifmfunc==nilthenerror(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) }) returnfalse 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! localmagic localopts=ctx.pipe ifopts[1]~=nilthenmagic=opts[1]:match'^%s*(.*%S)'end ifmagic==nilthenerror(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)) returnfalse end -- Syntax: #invoke:params|value_of|parameter name library.value_of=function(ctx) -- NOTE: `ctx.pipe` and `ctx.params` might be the original metatables! localopts=ctx.pipe ifopts[1]==nilthenerror(modulename.. ', ‘value_of’: No parameter name was provided',0)end localval localkey=opts[1]:match'^%s*(.-)%s*$' ifkey=='0'orkey:find'^%-?[1-9]%d*$'~=nilthen key=tonumber(key) val=ctx.params[key] -- No worries: #ctx.params is unused when the modifier is in -- first position (and therefore `ctx.params` is a metatable) ifval~=niland( ctx.subset~=-1orkey>#ctx.paramsorkey<1 )and( ctx.subset~=1or(key<=#ctx.paramsandkey>0) )then ctx.text=(ctx.headeror'')..val..(ctx.footeror'') elsectx.text=ctx.ifngivenor''end else val=ctx.params[key] ifctx.subset~=1andval~=nilthenctx.text=(ctx.header or'')..val..(ctx.footeror'') elsectx.text=ctx.ifngivenor''end end returnfalse end -- Syntax: #invoke:params|list library.list=function(ctx) -- NOTE: `ctx.pipe` might be the original metatable! localret,nss,kvs,pps={},0,ctx.pairsepor'',ctx.itersepor'' flush_params(ctx,function(key,val) ret[nss+1],ret[nss+2],ret[nss+3],ret[nss+4],nss= pps,key,kvs,val,nss+4 end) finalize_and_return_concatenated_list(ctx,ret,nss,4) returnfalse 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 localret,nss,pps={},0,ctx.itersepor'' flush_params(ctx,function(key,val) ret[nss+1],ret[nss+2],nss=pps,val,nss+2 end) finalize_and_return_concatenated_list(ctx,ret,nss,2) returnfalse end -- Syntax: #invoke:params|list_maybe_with_names library.list_maybe_with_names=function(ctx) -- NOTE: `ctx.pipe` might be the original metatable! localret,nss,kvs,pps={},0,ctx.pairsepor'',ctx.itersepor'' mixed_flush_params( ctx, function(key,val) ret[nss+1],ret[nss+2],ret[nss+3], ret[nss+4],nss=pps,'','',val,nss+4 end, function(key,val) ret[nss+1],ret[nss+2],ret[nss+3], ret[nss+4],nss=pps,key,kvs,val,nss+4 end ) finalize_and_return_concatenated_list(ctx,ret,nss,4) returnfalse 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, tbl = ctx.pipe, ctx.params for key, val in pairs(tbl) do tbl[key] = opts[get_parameter_name(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 tmp local opts, tbl = ctx.pipe, ctx.params for key, val in pairs(tbl) do tmp = get_parameter_name(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! localret,nss,pps,txt={},0,ctx.itersepor'',ctx.pipe[1]or'' localskel,cnv,n_parts=parse_placeholder_string(txt) flush_params(ctx,function(key,val) foridx=2,n_parts,2do ifskel[idx]thencnv[idx]=val elsecnv[idx]=tostring(key)end end ret[nss+1],nss=pps,nss+2 ret[nss]=table.concat(cnv) end) finalize_and_return_concatenated_list(ctx,ret,nss,2) returnfalse 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) localtname localopts=ctx.pipe ifopts[1]~=nilthentname=opts[1]:match'^%s*(.*%S)'end iftname==nilthenerror(modulename.. ', ‘call_for_each’: No template name was provided',0)end localmodel={title=tname,args=opts} localret,nss,ccs={},0,ctx.itersepor'' table.insert(opts,1,true) flush_params(ctx,function(key,val) opts[1],opts[2],ret[nss+1],nss=key,val,ccs,nss+2 ret[nss]=ctx.frame:expandTemplate(model) end) finalize_and_return_concatenated_list(ctx,ret,nss,2) returnfalse 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) localmname,fname localopts=ctx.pipe ifopts[1]~=nilthenmname=opts[1]:match'^%s*(.*%S)'end ifmname==nilthenerror(modulename.. ', ‘invoke_for_each’: No module name was provided',0)end ifopts[2]~=nilthenfname=opts[2]:match'^%s*(.*%S)'end iffname==nilthenerror(modulename.. ', ‘invoke_for_each’: No function name was provided',0)end localmodel={title='Module:'..mname,args=opts} localmfunc=require(model.title)[fname] localret,nss,ccs={},0,ctx.itersepor'' flush_params(ctx,function(key,val) opts[1],opts[2],ret[nss+1],nss=key,val,ccs,nss+2 ret[nss]=mfunc(ctx.frame:newChild(model)) end) finalize_and_return_concatenated_list(ctx,ret,nss,2) returnfalse 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) localmagic localopts=ctx.pipe ifopts[1]~=nilthenmagic=opts[1]:match'^%s*(.*%S)'end ifmagic==nilthenerror(modulename.. ', ‘magic_for_each’: No parser function was provided',0)end localret,nss,ccs={},0,ctx.itersepor'' table.insert(opts,1,true) flush_params(ctx,function(key,val) opts[1],opts[2],ret[nss+1],nss=key,val,ccs,nss+2 ret[nss]=ctx.frame:callParserFunction(magic,opts) end) finalize_and_return_concatenated_list(ctx,ret,nss,2) returnfalse 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) localtname localopts=ctx.pipe ifopts[1]~=nilthentname=opts[1]:match'^%s*(.*%S)'end iftname==nilthenerror(modulename.. ', ‘call_for_each_value’: No template name was provided',0)end localmodel={title=tname,args=opts} localret,nss,ccs={},0,ctx.itersepor'' flush_params(ctx,function(key,val) opts[1],ret[nss+1],nss=val,ccs,nss+2 ret[nss]=ctx.frame:expandTemplate(model) end) finalize_and_return_concatenated_list(ctx,ret,nss,2) returnfalse 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) localopts=ctx.pipe localmname,fname ifopts[1]~=nilthenmname=opts[1]:match'^%s*(.*%S)'end ifmname==nilthenerror(modulename.. ', ‘invoke_for_each_value’: No module name was provided',0)end ifopts[2]~=nilthenfname=opts[2]:match'^%s*(.*%S)'end iffname==nilthenerror(modulename.. ', ‘invoke_for_each_value’: No function name was provided',0)end localmodel={title='Module:'..mname,args=opts} localmfunc=require(model.title)[fname] localret,nss,ccs={},0,ctx.itersepor'' remove_numeric_keys(opts,1,1) flush_params(ctx,function(key,val) opts[1],ret[nss+1],nss=val,ccs,nss+2 ret[nss]=mfunc(ctx.frame:newChild(model)) end) finalize_and_return_concatenated_list(ctx,ret,nss,2) returnfalse 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) localopts=ctx.pipe localmagic ifopts[1]~=nilthenmagic=opts[1]:match'^%s*(.*%S)'end ifmagic==nilthenerror(modulename.. ', ‘magic_for_each_value’: No parser function was provided',0)end localret,nss,ccs={},0,ctx.itersepor'' flush_params(ctx,function(key,val) opts[1],ret[nss+1],nss=val,ccs,nss+2 ret[nss]=ctx.frame:callParserFunction(magic,opts) end) finalize_and_return_concatenated_list(ctx,ret,nss,2) returnfalse 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! localtmp ifctx.pipe[1]~=nilthentmp=ctx.pipe[1]:match'^%s*(.*%S)'end iftmp==nilthenerror(modulename.. ', ‘call_for_each_group’: No template name was provided',0)end localmodel={title=tmp} localopts,ret,nss,ccs={},{},0,ctx.itersepor'' forkey,valinpairs(ctx.pipe)do iftype(key)=='number'thenopts[key-1]=val elseopts[key]=valend end ctx.pipe=opts ctx.params=make_groups(ctx.params) flush_params(ctx,function(gid,group) forkey,valinpairs(opts)dogroup[key]=valend group[0],model.args,ret[nss+1],nss=gid,group,ccs, nss+2 ret[nss]=ctx.frame:expandTemplate(model) end) finalize_and_return_concatenated_list(ctx,ret,nss,2) returnfalse end --[[ First-position-only modifiers ]]-- --------------------------------------- -- Syntax: #invoke:params|new|pipe to static_iface.new=function(child_frame) localctx=context_new(child_frame) ctx.pipe=copy_or_ref_table(ctx.opipe,false) ctx.params={} main_loop(ctx,context_iterate(ctx,1)) returnctx.text end --[[ First-position-only functions ]]-- --------------------------------------- -- Syntax: #invoke:params|self static_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)end localfunc=static_iface[fname] iffunc~=nilthenreturnfuncend func=library[fname] iffunc==nilthenerror(modulename.. ': The function ‘'..fname..'’ does not exist',0)end returnfunction(child_frame) localctx=context_new(child_frame) ctx.pipe=copy_or_ref_table(ctx.opipe,refpipe[fname]) ctx.params=copy_or_ref_table(ctx.oparams,refparams[fname]) main_loop(ctx,func) returnctx.text end end })