diff options
Diffstat (limited to 'Master/texmf-dist/source/latex/l3kernel/l3clist.dtx')
-rw-r--r-- | Master/texmf-dist/source/latex/l3kernel/l3clist.dtx | 342 |
1 files changed, 341 insertions, 1 deletions
diff --git a/Master/texmf-dist/source/latex/l3kernel/l3clist.dtx b/Master/texmf-dist/source/latex/l3kernel/l3clist.dtx index dcd332df4ae..d0389fc311c 100644 --- a/Master/texmf-dist/source/latex/l3kernel/l3clist.dtx +++ b/Master/texmf-dist/source/latex/l3kernel/l3clist.dtx @@ -39,7 +39,7 @@ \documentclass[full]{l3doc} %</driver> %<*driver|package> -\GetIdInfo$Id: l3clist.dtx 4728 2014-05-04 13:25:37Z joseph $ +\GetIdInfo$Id: l3clist.dtx 5237 2014-07-19 15:09:54Z bruno $ {L3 Comma separated lists} %</driver|package> %<*driver> @@ -104,6 +104,20 @@ % initially contain no items. % \end{function} % +% \begin{function}[added = 2014-07-05] +% { +% \clist_const:Nn, \clist_const:Nx, +% \clist_const:cn, \clist_const:cx +% } +% \begin{syntax} +% \cs{clist_const:Nn} \meta{clist~var} \Arg{comma list} +% \end{syntax} +% Creates a new constant \meta{clist~var} or raises an error +% if the name is already taken. The value of the +% \meta{clist~var} will be set globally to the +% \meta{comma list}. +% \end{function} +% % \begin{function} % {\clist_clear:N, \clist_clear:c, \clist_gclear:N, \clist_gclear:c} % \begin{syntax} @@ -139,6 +153,21 @@ % \meta{comma list_2}. % \end{function} % +% \begin{function}[added = 2014-07-17] +% { +% \clist_set_from_seq:NN, \clist_set_from_seq:cN, +% \clist_set_from_seq:Nc, \clist_set_from_seq:cc, +% \clist_gset_from_seq:NN, \clist_gset_from_seq:cN, +% \clist_gset_from_seq:Nc, \clist_gset_from_seq:cc +% } +% \begin{syntax} +% \cs{clist_set_from_seq:NN} \meta{comma list} \meta{sequence} +% \end{syntax} +% Converts the data in the \meta{sequence} into a \meta{comma list}: +% the original \meta{sequence} is unchanged. +% Items which contain either spaces or commas are surrounded by braces. +% \end{function} +% % \begin{function} % { % \clist_concat:NNN, \clist_concat:ccc, @@ -264,6 +293,30 @@ % \end{texnote} % \end{function} % +% \begin{function}[added = 2014-07-18] +% { +% \clist_reverse:N, \clist_reverse:c, +% \clist_greverse:N, \clist_greverse:c +% } +% \begin{syntax} +% \cs{clist_reverse:N} \meta{comma list} +% \end{syntax} +% Reverses the order of items stored in the \meta{comma list}. +% \end{function} +% +% \begin{function}[added = 2014-07-18]{\clist_reverse:n} +% \begin{syntax} +% \cs{clist_reverse:n} \Arg{comma list} +% \end{syntax} +% Leaves the items in the \meta{comma list} in the input stream in +% reverse order. Braces and spaces are preserved by this process. +% \begin{texnote} +% The result is returned within \tn{exp_not:n}, which means that the +% comma list will not expand further when appearing in an +% \texttt{x}-type argument expansion. +% \end{texnote} +% \end{function} +% % \section{Comma list conditionals} % % \begin{function}[EXP,pTF]{\clist_if_empty:N, \clist_if_empty:c} @@ -274,6 +327,19 @@ % Tests if the \meta{comma list} is empty (containing no items). % \end{function} % +% \begin{function}[EXP, pTF, added = 2014-07-05]{\clist_if_empty:n} +% \begin{syntax} +% \cs{clist_if_empty_p:n} \Arg{comma list} +% \cs{clist_if_empty:nTF} \Arg{comma list} \Arg{true code} \Arg{false code} +% \end{syntax} +% Tests if the \meta{comma list} is empty (containing no items). +% The rules for space trimming are as for other \texttt{n}-type +% comma-list functions, hence the comma list |{~,~,,~}| (without +% outer braces) is empty, while |{~,{},}| (without outer braces) +% contains one element, which happens to be empty: the comma-list +% is not empty. +% \end{function} +% % \begin{function}[updated = 2011-09-06, TF] % { % \clist_if_in:Nn, \clist_if_in:NV, \clist_if_in:No, @@ -573,6 +639,29 @@ % Spaces are removed from both sides of each item. % \end{function} % +% \section{Using a single item} +% +% \begin{function}[added = 2014-07-17, EXP] +% {\clist_item:Nn, \clist_item:cn, \clist_item:nn} +% \begin{syntax} +% \cs{clist_item:Nn} \meta{comma list} \Arg{integer expression} +% \end{syntax} +% Indexing items in the \meta{comma list} from~$1$ at the top (left), this +% function will evaluate the \meta{integer expression} and leave the +% appropriate item from the comma list in the input stream. If the +% \meta{integer expression} is negative, indexing occurs from the +% bottom (right) of the comma list. When the \meta{integer expression} +% is larger than the number of items in the \meta{comma list} (as +% calculated by \cs{clist_count:N}) then the function will expand to +% nothing. +% \begin{texnote} +% The result is returned within the \tn{unexpanded} +% primitive (\cs{exp_not:n}), which means that the \meta{item} +% will not expand further when appearing in an \texttt{x}-type +% argument expansion. +% \end{texnote} +% \end{function} +% % \section{Viewing comma lists} % % \begin{function}[updated = 2012-09-09]{\clist_show:N, \clist_show:c} @@ -658,6 +747,21 @@ % \end{macrocode} % \end{macro} % +% \begin{macro} +% { +% \clist_const:Nn, \clist_const:cn, +% \clist_const:Nx, \clist_const:cx +% } +% Creating and initializing a constant comma list is done in a way +% similar to \cs{clist_set:Nn} and \cs{clist_gset:Nn}, being careful +% to strip spaces. +% \begin{macrocode} +\cs_new_protected:Npn \clist_const:Nn #1#2 + { \tl_const:Nx #1 { \@@_trim_spaces:n {#2} } } +\cs_generate_variant:Nn \clist_const:Nn { c , Nx , cx } +% \end{macrocode} +% \end{macro} +% % \begin{macro}{\clist_clear:N, \clist_clear:c} % \UnitTested % \begin{macro}{\clist_gclear:N, \clist_gclear:c} @@ -709,6 +813,61 @@ % \end{macro} % \end{macro} % +% \begin{macro} +% { +% \clist_set_from_seq:NN, \clist_set_from_seq:cN, +% \clist_set_from_seq:Nc, \clist_set_from_seq:cc +% } +% \UnitTested +% \begin{macro} +% { +% \clist_gset_from_seq:NN, \clist_gset_from_seq:cN, +% \clist_gset_from_seq:Nc, \clist_gset_from_seq:cc +% } +% \UnitTested +% \begin{macro}[aux]{\@@_set_from_seq:NNNN} +% \begin{macro}[aux]{\@@_wrap_item:n} +% \begin{macro}[aux]{\@@_set_from_seq:w} +% Setting a comma list from a comma-separated list is done using a simple +% mapping. We wrap most items with \cs{exp_not:n}, and a comma. Items which +% contain a comma or a space are surrounded by an extra set of braces. The +% first comma must be removed, except in the case of an empty comma-list. +% \begin{macrocode} +\cs_new_protected:Npn \clist_set_from_seq:NN + { \@@_set_from_seq:NNNN \clist_clear:N \tl_set:Nx } +\cs_new_protected:Npn \clist_gset_from_seq:NN + { \@@_set_from_seq:NNNN \clist_gclear:N \tl_gset:Nx } +\cs_new_protected:Npn \@@_set_from_seq:NNNN #1#2#3#4 + { + \seq_if_empty:NTF #4 + { #1 #3 } + { + #2 #3 + { + \exp_last_unbraced:Nf \use_none:n + { \seq_map_function:NN #4 \@@_wrap_item:n } + } + } + } +\cs_new:Npn \@@_wrap_item:n #1 + { + , + \tl_if_empty:oTF { \@@_set_from_seq:w #1 ~ , #1 ~ } + { \exp_not:n {#1} } + { \exp_not:n { {#1} } } + } +\cs_new:Npn \@@_set_from_seq:w #1 , #2 ~ { } +\cs_generate_variant:Nn \clist_set_from_seq:NN { Nc } +\cs_generate_variant:Nn \clist_set_from_seq:NN { c , cc } +\cs_generate_variant:Nn \clist_gset_from_seq:NN { Nc } +\cs_generate_variant:Nn \clist_gset_from_seq:NN { c , cc } +% \end{macrocode} +% \end{macro} +% \end{macro} +% \end{macro} +% \end{macro} +% \end{macro} +% % \begin{macro}{\clist_concat:NNN, \clist_concat:ccc} % \UnitTested % \begin{macro}{\clist_gconcat:NNN, \clist_gconcat:ccc} @@ -1154,6 +1313,61 @@ % \end{macro} % \end{macro} % +% \begin{macro} +% { +% \clist_reverse:N, \clist_reverse:c, +% \clist_greverse:N, \clist_greverse:c +% } +% Use \cs{clist_reverse:n} in an \texttt{x}-expanding assignment. The +% extra work that \cs{clist_reverse:n} does to preserve braces and +% spaces would not be needed for the well-controlled case of +% \texttt{N}-type comma lists, but the slow-down is not too bad. +% \begin{macrocode} +\cs_new_protected:Npn \clist_reverse:N #1 + { \tl_set:Nx #1 { \exp_args:No \clist_reverse:n {#1} } } +\cs_new_protected:Npn \clist_greverse:N #1 + { \tl_gset:Nx #1 { \exp_args:No \clist_reverse:n {#1} } } +\cs_generate_variant:Nn \clist_reverse:N { c } +\cs_generate_variant:Nn \clist_greverse:N { c } +% \end{macrocode} +% \end{macro} +% +% \begin{macro}[EXP]{\clist_reverse:n} +% \begin{macro}[aux, EXP]{\@@_reverse:wwNww, \@@_reverse_end:ww} +% The reversed token list is built one item at a time, and stored +% between \cs{q_stop} and \cs{q_mark}, in the form of |?| followed by +% zero or more instances of ``\meta{item}|,|''. We start from a comma +% list ``\meta{item_1}|,|\ldots|,|\meta{item_n}''. During the loop, +% the auxiliary \cs{@@_reverse:wwNww} receives ``|?|\meta{item_i}'' as +% |#1|, ``\meta{item_{i+1}}|,|\ldots|,|\meta{item_n}'' as |#2|, +% \cs{@@_reverse:wwNww} as |#3|, what remains until \cs{q_stop} as +% |#4|, and ``\meta{item_{i-1}}|,|\ldots|,|\meta{item_1}|,|'' as |#5|. +% The auxiliary moves |#1| just before |#5|, with a comma, and calls +% itself (|#3|). After the last item is moved, \cs{@@_reverse:wwNww} +% receives ``\cs{q_mark} \cs{@@_reverse:wwNww} |!|'' as its argument +% |#1|, thus \cs{@@_reverse_end:ww} as its argument |#3|. This second +% auxiliary cleans up until the marker~|!|, removes the trailing comma +% (introduced when the first item was moved after \cs{q_stop}), and +% leaves its argument~|#1| within \cs{exp_not:n}. There is also a +% need to remove a leading comma, hence \cs{exp_not:o} and +% \cs{use_none:n}. +% \begin{macrocode} +\cs_new:Npn \clist_reverse:n #1 + { + \@@_reverse:wwNww ? #1 , + \q_mark \@@_reverse:wwNww ! , + \q_mark \@@_reverse_end:ww + \q_stop ? \q_mark + } +\cs_new:Npn \@@_reverse:wwNww + #1 , #2 \q_mark #3 #4 \q_stop ? #5 \q_mark + { #3 ? #2 \q_mark #3 #4 \q_stop #1 , #5 \q_mark } +\cs_new:Npn \@@_reverse_end:ww #1 ! #2 , \q_mark + { \exp_not:o { \use_none:n #2 } } +% \end{macrocode} +% \end{macro} +% \end{macro} +% % \subsection{Comma list conditionals} % % \begin{macro}[pTF]{\clist_if_empty:N, \clist_if_empty:c} @@ -1165,6 +1379,39 @@ % \end{macrocode} % \end{macro} % +% \begin{macro}[EXP, pTF]{\clist_if_empty:n} +% \begin{macro}[aux, EXP]{\@@_if_empty_n:w} +% \begin{macro}[aux, EXP]{\@@_if_empty_n:wNw} +% As usual, we insert a token (here |?|) before grabbing +% any argument: this avoids losing braces. The argument +% of \cs{tl_if_empty:oTF} is empty if |#1| is |?| followed +% by blank spaces (besides, this particular variant of +% the emptiness test is optimized). If the item of the +% comma list is blank, grab the next one. As soon as one +% item is non-blank, exit: the second auxiliary will grab +% \cs{prg_return_false:} as |#2|, unless every item in +% the comma list was blank and the loop actually got broken +% by the trailing |\q_mark \prg_return_false:| item. +% \begin{macrocode} +\prg_new_conditional:Npnn \clist_if_empty:n #1 { p , T , F , TF } + { + \@@_if_empty_n:w ? #1 + , \q_mark \prg_return_false: + , \q_mark \prg_return_true: + \q_stop + } +\cs_new:Npn \@@_if_empty_n:w #1 , + { + \tl_if_empty:oTF { \use_none:nn #1 ? } + { \@@_if_empty_n:w ? } + { \@@_if_empty_n:wNw } + } +\cs_new:Npn \@@_if_empty_n:wNw #1 \q_mark #2#3 \q_stop {#2} +% \end{macrocode} +% \end{macro} +% \end{macro} +% \end{macro} +% % \begin{macro}[TF] % { % \clist_if_in:Nn, \clist_if_in:NV, \clist_if_in:No, @@ -1462,6 +1709,99 @@ % \end{macro} % \end{macro} % +% \subsection{Using a single item} +% +% \begin{macro}{\clist_item:Nn, \clist_item:cn} +% \begin{macro}[aux]{\@@_item:nnNn} +% \begin{macro}[aux]{\@@_item_N_loop:nw} +% To avoid needing to test the end of the list at each step, +% we first compute the \meta{length} of the list. If the item number +% is~$0$, less than $-\meta{length}$, or more than $\meta{length}$, +% the result is empty. If it is negative, but not less than $-\meta{length}$, +% add $\meta{length}+1$ to the item number before performing the loop. +% The loop itself is very simple, return the item if the counter +% reached~$1$, otherwise, decrease the counter and repeat. +% \begin{macrocode} +\cs_new:Npn \clist_item:Nn #1#2 + { + \exp_args:Nfo \@@_item:nnNn + { \clist_count:N #1 } + #1 + \@@_item_N_loop:nw + {#2} + } +\cs_new:Npn \@@_item:nnNn #1#2#3#4 + { + \int_compare:nNnTF {#4} < \c_zero + { + \int_compare:nNnTF {#4} < { - #1 } + { \use_none_delimit_by_q_stop:w } + { \exp_args:Nf #3 { \int_eval:n { #4 + \c_one + #1 } } } + } + { + \int_compare:nNnTF {#4} > {#1} + { \use_none_delimit_by_q_stop:w } + { #3 {#4} } + } + { } , #2 , \q_stop + } +\cs_new:Npn \@@_item_N_loop:nw #1 #2, + { + \int_compare:nNnTF {#1} = \c_zero + { \use_i_delimit_by_q_stop:nw { \exp_not:n {#2} } } + { \exp_args:Nf \@@_item_N_loop:nw { \int_eval:n { #1 - 1 } } } + } +\cs_generate_variant:Nn \clist_item:Nn { c } +% \end{macrocode} +% \end{macro} +% \end{macro} +% \end{macro} +% +% \begin{macro}{\clist_item:nn} +% \begin{macro}[aux]{ +% \@@_item_n:nw, +% \@@_item_n_loop:nw, +% \@@_item_n_end:n, +% \@@_item_n_strip:w} +% This starts in the same way as \cs{clist_item:Nn} by counting the items +% of the comma list. The final item should be space-trimmed before being +% brace-stripped, hence we insert a couple of odd-looking +% \cs{prg_do_nothing:} to avoid losing braces. Blank items are ignored. +% \begin{macrocode} +\cs_new:Npn \clist_item:nn #1#2 + { + \exp_args:Nf \@@_item:nnNn + { \clist_count:n {#1} } + {#1} + \@@_item_n:nw + {#2} + } +\cs_new:Npn \@@_item_n:nw #1 + { \@@_item_n_loop:nw {#1} \prg_do_nothing: } +\cs_new:Npn \@@_item_n_loop:nw #1 #2, + { + \exp_args:No \tl_if_blank:nTF {#2} + { \@@_item_n_loop:nw {#1} \prg_do_nothing: } + { + \int_compare:nNnTF {#1} = \c_zero + { \exp_args:No \@@_item_n_end:n {#2} } + { + \exp_args:Nf \@@_item_n_loop:nw + { \int_eval:n { #1 - 1 } } + \prg_do_nothing: + } + } + } +\cs_new:Npn \@@_item_n_end:n #1 #2 \q_stop + { + \__tl_trim_spaces:nn { \q_mark #1 } + { \exp_last_unbraced:No \@@_item_n_strip:w } , + } +\cs_new:Npn \@@_item_n_strip:w #1 , { \exp_not:n {#1} } +% \end{macrocode} +% \end{macro} +% \end{macro} +% % \subsection{Viewing comma lists} % % \begin{macro}{\clist_show:N, \clist_show:c} |