diff options
Diffstat (limited to 'Master/texmf-dist/source/latex/l3kernel/l3clist.dtx')
-rw-r--r-- | Master/texmf-dist/source/latex/l3kernel/l3clist.dtx | 606 |
1 files changed, 380 insertions, 226 deletions
diff --git a/Master/texmf-dist/source/latex/l3kernel/l3clist.dtx b/Master/texmf-dist/source/latex/l3kernel/l3clist.dtx index b2c09e72e15..53823cde267 100644 --- a/Master/texmf-dist/source/latex/l3kernel/l3clist.dtx +++ b/Master/texmf-dist/source/latex/l3kernel/l3clist.dtx @@ -10,7 +10,7 @@ %% %% http://www.latex-project.org/lppl.txt %% -%% This file is part of the "expl3 bundle" (The Work in LPPL) +%% This file is part of the "l3kernel bundle" (The Work in LPPL) %% and all files in that bundle must be distributed together. %% %% The released version of this bundle is available from CTAN. @@ -36,7 +36,7 @@ % %<*driver|package> \RequirePackage{l3names} -\GetIdInfo$Id: l3clist.dtx 2725 2011-09-05 18:53:03Z bruno $ +\GetIdInfo$Id: l3clist.dtx 2798 2011-09-10 15:42:13Z will $ {L3 Experimental comma separated lists} %</driver|package> %<*driver> @@ -162,8 +162,7 @@ % % \begin{function}{\clist_concat:NNN, \clist_concat:ccc} % \begin{syntax} -% \cs{clist_concat:NNN} \meta{comma list1} \meta{comma list2} -% ~~\meta{comma list3} +% \cs{clist_concat:NNN} \meta{comma list1} \meta{comma list2} \meta{comma list3} % \end{syntax} % Concatenates the content of \meta{comma list2} and \meta{comma list3} % together and saves the result in \meta{comma list1}. The items in @@ -174,8 +173,7 @@ % % \begin{function}{\clist_gconcat:NNN, \clist_gconcat:ccc} % \begin{syntax} -% \cs{clist_gconcat:NNN} \meta{comma list1} \meta{comma list2} -% ~~\meta{comma list3} +% \cs{clist_gconcat:NNN} \meta{comma list1} \meta{comma list2} \meta{comma list3} % \end{syntax} % Concatenates the content of \meta{comma list2} and \meta{comma list3} % together and saves the result in \meta{comma list1}. The items in @@ -184,14 +182,47 @@ % \meta{comma list1}. % \end{function} % -% \section{Appending items to comma lists} +% \section{Adding data to comma lists} % -% \begin{function}{ -% \clist_put_left:Nn, \clist_put_left:NV, -% \clist_put_left:No, \clist_put_left:Nx, -% \clist_put_left:cn, \clist_put_left:cV, -% \clist_put_left:co, \clist_put_left:cx -% } +% \begin{function}[added = 2011-09-06] +% { +% \clist_set:Nn, \clist_set:NV, +% \clist_set:No, \clist_set:Nx, +% \clist_set:cn, \clist_set:cV, +% \clist_set:co, \clist_set:cx +% } +% \begin{syntax} +% \cs{clist_set:Nn} \meta{comma list} |{|\meta{item1},\ldots{},\meta{item$_n$}|}| +% \end{syntax} +% Sets \meta{comma list} to contain the \meta{items}, +% removing any previous content from the variable. +% Spaces are removed from both sides of each item. +% The assignment is restricted to the current \TeX{} group. +% \end{function} +% +% \begin{function}[added = 2011-09-06] +% { +% \clist_gset:Nn, \clist_gset:NV, +% \clist_gset:No, \clist_gset:Nx, +% \clist_gset:cn, \clist_gset:cV, +% \clist_gset:co, \clist_gset:cx +% } +% \begin{syntax} +% \cs{clist_gset:Nn} \meta{comma list} |{|\meta{item1},\ldots{},\meta{item$_n$}|}| +% \end{syntax} +% Sets \meta{comma list} to contain the \meta{items}, +% removing any previous content from the variable. +% Spaces are removed from both sides of each item. +% The assignment is global. +% \end{function} +% +% \begin{function}[updated = 2011-09-05] +% { +% \clist_put_left:Nn, \clist_put_left:NV, +% \clist_put_left:No, \clist_put_left:Nx, +% \clist_put_left:cn, \clist_put_left:cV, +% \clist_put_left:co, \clist_put_left:cx +% } % \begin{syntax} % \cs{clist_put_left:Nn} \meta{comma list} |{|\meta{item1},\ldots{},\meta{item$_n$}|}| % \end{syntax} @@ -200,12 +231,13 @@ % The assignment is restricted to the current \TeX{} group. % \end{function} % -% \begin{function}{ -% \clist_gput_left:Nn, \clist_gput_left:NV, -% \clist_gput_left:No, \clist_gput_left:Nx, -% \clist_gput_left:cn, \clist_gput_left:cV, -% \clist_gput_left:co, \clist_gput_left:cx -% } +% \begin{function}[updated = 2011-09-05] +% { +% \clist_gput_left:Nn, \clist_gput_left:NV, +% \clist_gput_left:No, \clist_gput_left:Nx, +% \clist_gput_left:cn, \clist_gput_left:cV, +% \clist_gput_left:co, \clist_gput_left:cx +% } % \begin{syntax} % \cs{clist_gput_left:Nn} \meta{comma list} |{|\meta{item1},\ldots{},\meta{item$_n$}|}| % \end{syntax} @@ -214,12 +246,13 @@ % The assignment is global. % \end{function} % -% \begin{function}{ -% \clist_put_right:Nn, \clist_put_right:NV, -% \clist_put_right:No, \clist_put_right:Nx, -% \clist_put_right:cn, \clist_put_right:cV, -% \clist_put_right:co, \clist_put_right:cx -% } +% \begin{function}[updated = 2011-09-05] +% { +% \clist_put_right:Nn, \clist_put_right:NV, +% \clist_put_right:No, \clist_put_right:Nx, +% \clist_put_right:cn, \clist_put_right:cV, +% \clist_put_right:co, \clist_put_right:cx +% } % \begin{syntax} % \cs{clist_put_right:Nn} \meta{comma list} |{|\meta{item1},\ldots{},\meta{item$_n$}|}| % \end{syntax} @@ -228,12 +261,13 @@ % The assignment is restricted to the current \TeX{} group. % \end{function} % -% \begin{function}{ -% \clist_gput_right:Nn, \clist_gput_right:NV, -% \clist_gput_right:No, \clist_gput_right:Nx, -% \clist_gput_right:cn, \clist_gput_right:cV, -% \clist_gput_right:co, \clist_gput_right:cx -% } +% \begin{function}[updated = 2011-09-05] +% { +% \clist_gput_right:Nn, \clist_gput_right:NV, +% \clist_gput_right:No, \clist_gput_right:Nx, +% \clist_gput_right:cn, \clist_gput_right:cV, +% \clist_gput_right:co, \clist_gput_right:cx +% } % \begin{syntax} % \cs{clist_gput_right:Nn} \meta{comma list} |{|\meta{item1},\ldots{},\meta{item$_n$}|}| % \end{syntax} @@ -254,10 +288,10 @@ % % \section{Modifying comma lists} % -% While comma lists are normally used as ordered lists, it may be -% necessary to modify the content. The functions here may be used -% to update comma lists, while retaining the order of the unaffected -% entries. +% While comma lists are normally used as ordered lists, it may be +% necessary to modify the content. The functions here may be used +% to update comma lists, while retaining the order of the unaffected +% entries. % % \begin{function}{\clist_remove_duplicates:N, \clist_remove_duplicates:c} % \begin{syntax} @@ -295,7 +329,7 @@ % \end{texnote} % \end{function} % -% \begin{function}{\clist_remove_all:Nn, \clist_remove_all:cn} +% \begin{function}[updated = 2011-09-06]{\clist_remove_all:Nn, \clist_remove_all:cn} % \begin{syntax} % \cs{clist_remove_all:Nn} \meta{comma list} \Arg{item} % \end{syntax} @@ -308,7 +342,7 @@ % \end{texnote} % \end{function} % -% \begin{function}{\clist_gremove_all:Nn, \clist_gremove_all:cn} +% \begin{function}[updated = 2011-09-06]{\clist_gremove_all:Nn, \clist_gremove_all:cn} % \begin{syntax} % \cs{clist_gremove_all:Nn} \meta{comma list} \Arg{item} % \end{syntax} @@ -326,8 +360,7 @@ % \begin{function}[EXP,pTF]{\clist_if_empty:N, \clist_if_empty:c} % \begin{syntax} % \cs{clist_if_empty_p:N} \meta{comma list} -% \cs{clist_if_empty:NTF} \meta{comma list} -% ~~\Arg{true code} \Arg{false code} +% \cs{clist_if_empty:NTF} \meta{comma list} \Arg{true code} \Arg{false code} % \end{syntax} % Tests if the \meta{comma list} is empty (containing no items). % \end{function} @@ -336,27 +369,34 @@ % {\clist_if_eq:NN, \clist_if_eq:Nc, \clist_if_eq:cN, \clist_if_eq:cc} % \begin{syntax} % \cs{clist_if_eq_p:NN} \Arg{clist1} \Arg{clist2} -% \cs{clist_if_eq:NNTF} \Arg{clist1} \Arg{clist2} \Arg{true code} -% ~~\Arg{false code} +% \cs{clist_if_eq:NNTF} \Arg{clist1} \Arg{clist2} \Arg{true code} \Arg{false code} % \end{syntax} % Compares the content of two \meta{comma lists} and % is logically \texttt{true} if the two contain the same list of % entries in the same order. % \end{function} % -% \begin{function}[TF]{ -% \clist_if_in:Nn, \clist_if_in:NV, \clist_if_in:No, -% \clist_if_in:cn, \clist_if_in:cV, \clist_if_in:co, -% \clist_if_in:nn, \clist_if_in:nV, \clist_if_in:no -% } +% \begin{function}[updated = 2011-09-06, TF] +% { +% \clist_if_in:Nn, \clist_if_in:NV, \clist_if_in:No, +% \clist_if_in:cn, \clist_if_in:cV, \clist_if_in:co, +% \clist_if_in:nn, \clist_if_in:nV, \clist_if_in:no +% } % \begin{syntax} -% \cs{clist_if_in:NnTF} \meta{comma list} \Arg{item} -% ~~\Arg{true code} \Arg{false code} +% \cs{clist_if_in:NnTF} \meta{comma list} \Arg{item} \Arg{true code} \Arg{false code} % \end{syntax} % Tests if the \meta{item} is present in the \meta{comma list}. +% In the case of an \texttt{n}-type \meta{comma list}, +% spaces are stripped from each item, but braces are not removed. +% Hence, +% \begin{verbatim} +% \clist_if_in:nnTF { a , {b}~ , {b} , c } { b } {true} {false} +% \end{verbatim} +% yields \texttt{false}. % \begin{texnote} % The \meta{item} may not contain |{|, |}|, or |#| -% (assuming the usual \TeX{} category codes apply). +% (assuming the usual \TeX{} category codes apply), +% and should not contain |,| nor start or end with a space. % \end{texnote} % \end{function} % @@ -407,8 +447,7 @@ % \begin{function} % {\clist_map_variable:NNn, \clist_map_variable:cNn, \clist_map_variable:nNn} % \begin{syntax} -% \cs{clist_map_variable:NNn} \meta{comma list} -% ~~\meta{tl~var.} \Arg{function using tl~var.} +% \cs{clist_map_variable:NNn} \meta{comma list} \meta{tl~var.} \Arg{function using tl~var.} % \end{syntax} % Stores each entry in the \meta{comma list} in turn in the % \meta{tl~var.}\ and applies the \meta{function using tl~var.} @@ -437,7 +476,7 @@ % \end{verbatim} % Use outside of a \cs{clist_map_\ldots} scenario will lead to low % level \TeX{} errors. -% \begin{texnote}^^A temporarily untrue, fixed next week. +% \begin{texnote} % When the mapping is broken, additional tokens may be inserted by the % internal macro \cs{clist_break_point:n} before further items are taken % from the input stream. This will depend on the design of the mapping @@ -482,8 +521,6 @@ % in the previous section: a comma list should either be used as an % ordered data type or as a stack, but not in both ways. % -% \section{Comma lists as stacks} -% % \begin{function}{\clist_get:NN, \clist_get:cN} % \begin{syntax} % \cs{clist_get:NN} \meta{comma list} \meta{token list variable} @@ -502,7 +539,7 @@ % \meta{comma list}. The \meta{token list variable} is assigned locally. % \end{function} % -% \begin{function}{\clist_pop:NN, \clist_pop:cN} +% \begin{function}[updated = 2011-09-06]{\clist_pop:NN, \clist_pop:cN} % \begin{syntax} % \cs{clist_pop:NN} \meta{comma list} \meta{token list variable} % \end{syntax} @@ -529,9 +566,10 @@ % \clist_push:cn, \clist_push:cV, \clist_push:co, \clist_push:cx % } % \begin{syntax} -% \cs{clist_push:Nn} \meta{comma list} \Arg{item} +% \cs{clist_push:Nn} \meta{comma list} \Arg{items} % \end{syntax} -% Adds the \Arg{item} to the top of the \meta{comma list}. +% Adds the \Arg{items} to the top of the \meta{comma list}. +% Spaces are removed from both sides of each item. % The assignment is restricted to the current \TeX{} group. % \end{function} % @@ -541,10 +579,12 @@ % \clist_gpush:cn, \clist_gpush:cV, \clist_gpush:co, \clist_gpush:cx % } % \begin{syntax} -% \cs{clist_gpush:Nn} \meta{comma list} \Arg{item} +% \cs{clist_gpush:Nn} \meta{comma list} \Arg{items} % \end{syntax} -% Pushes the \meta{item} onto the end of the top of the -% \meta{comma list}. The assignment is global. +% Pushes the \meta{items} onto the end of the top of the +% \meta{comma list}. +% Spaces are removed from both sides of each item. +% The assignment is global. % \end{function} % % \section{Viewing comma lists} @@ -556,12 +596,29 @@ % Displays the entries in the \meta{comma list} in the terminal. % \end{function} % +% \section{Scratch comma lists} +% +% \begin{variable}[added = 2011-09-06]{\l_tmpa_clist, \l_tmpb_clist} +% Scratch comma lists for local assignment. These are never used by +% the kernel code, and so are safe for use with any \LaTeX3-defined +% function. However, they may be overwritten by other non-kernel +% code and so should only be used for short-term storage. +% \end{variable} +% +% \begin{variable}[added = 2011-09-06]{\g_tmpa_clist, \g_tmpb_clist} +% Scratch comma lists for global assignment. These are never used by +% the kernel code, and so are safe for use with any \LaTeX3-defined +% function. However, they may be overwritten by other non-kernel +% code and so should only be used for short-term storage. +% \end{variable} +% % \section{Experimental comma list functions} % % This section contains functions which may or may not be retained, depending % on how useful they are found to be. % -% \begin{function}[EXP]{\clist_length:N, \clist_length:c,\clist_length:n} +% \begin{function}[added = 2011-06-25, updated = 2011-09-06, EXP] +% {\clist_length:N, \clist_length:c,\clist_length:n} % \begin{syntax} % \cs{clist_length:N} \meta{comma list} % \end{syntax} @@ -571,7 +628,8 @@ % \emph{i.e.}~every item in a \meta{comma list} is unique. % \end{function} % -% \begin{function}[EXP]{\clist_item:Nn, \clist_item:cn, \clist_item:nn} +% \begin{function}[updated = 2011-09-06, EXP] +% {\clist_item:Nn, \clist_item:cn, \clist_item:nn} % \begin{syntax} % \cs{clist_item:Nn} \meta{comma list} \Arg{integer expression} % \end{syntax} @@ -585,7 +643,7 @@ % nothing. % \end{function} % -% \begin{function} +% \begin{function}[updated = 2011-08-31] % { % \clist_set_from_seq:NN, \clist_set_from_seq:cN, % \clist_set_from_seq:Nc, \clist_set_from_seq:cc @@ -595,9 +653,10 @@ % \end{syntax} % Sets the \meta{comma list} within the current \TeX{} group to be equal % to the content of the \meta{sequence}. +% Items which contain either spaces or commas are surrounded by braces. % \end{function} % -% \begin{function} +% \begin{function}[updated = 2011-08-31] % { % \clist_gset_from_seq:NN, \clist_gset_from_seq:cN, % \clist_gset_from_seq:Nc, \clist_gset_from_seq:cc @@ -607,38 +666,21 @@ % \end{syntax} % Sets the \meta{comma list} globally to equal to the content of the % \meta{sequence}. +% Items which contain either spaces or commas are surrounded by braces. % \end{function} % -% \section{Deprecated comma-list functions} +% \section{Internal comma-list functions} % -% \begin{function}{\clist_trim_spaces:N, \clist_trim_spaces:c} +% \begin{function}[added = 2011-07-09, rEXP]{\clist_trim_spaces:n} % \begin{syntax} -% \cs{clist_trim_spaces:N} \meta{comma list} -% \end{syntax} -% Removes leading and trailing spaces from each \meta{item} in the -% \meta{comma list} within the current \TeX{} group. This space-removal -% process takes place as described for \cs{tl_trim_spaces:n}. -% \end{function} -% -% \begin{function}{\clist_gtrim_spaces:N, \clist_gtrim_spaces:c} -% \begin{syntax} -% \cs{clist_gtrim_spaces:N} \meta{comma list} -% \end{syntax} -% Removes leading and trailing spaces from each \meta{item} in the -% \meta{comma list} globally. This space-removal -% process takes place as described for \cs{tl_trim_spaces:n}. -% \end{function} -% -% \begin{function}[rEXP]{\clist_trim_spaces:n} -% \begin{syntax} -% \cs{clist_trim_spaces:N} \meta{comma list} +% \cs{clist_trim_spaces:n} \Arg{comma list} % \end{syntax} % Removes leading and trailing spaces from each \meta{item} in the % \meta{comma list}, leaving the resulting modified list in the -% input stream. +% input stream. This is used by the functions which add data +% into a comma list. % \end{function} % -% % \end{documentation} % % \begin{implementation} @@ -659,16 +701,20 @@ %</package> % \end{macrocode} % -%^^A todo: provide users with \l_tmpa_clist and friends? -% -% \begin{variable}{\l_clist_tmpa_tl, \l_clist_tmpb_tl} +% \begin{variable}{\l_clist_tmpa_tl} % Scratch space for various internal uses. % \begin{macrocode} \tl_new:N \l_clist_tmpa_tl -\tl_new:N \l_clist_tmpb_tl % \end{macrocode} % \end{variable} % +% \begin{macro}[aux]{\clist_tmp:w} +% A temporary function for various purposes. +% \begin{macrocode} +\cs_new_protected:Npn \clist_tmp:w { } +% \end{macrocode} +% \end{macro} +% % \subsection{Allocation and initialisation} % % \begin{macro}{\clist_new:N,\clist_new:c} @@ -736,8 +782,7 @@ % \begin{macro}{\clist_gconcat:NNN, \clist_gconcat:ccc} % \UnitTested % \begin{macro}[aux]{\clist_concat_aux:NNNN} -% Concatenating sequences is not quite as easy as it seems, as there is -% the danger that |#1| may be the same as either |#2| or |#3|. Also, +% Concatenating sequences is not quite as easy as it seems, as % there needs to be the correct addition of a comma to the output. So % a little work to do. % \begin{macrocode} @@ -749,16 +794,9 @@ { #1 #2 { - \clist_if_empty:NTF #3 - { \exp_not:o #4 } - { - \exp_not:o #3 - \clist_if_empty:NF #4 - { - , - \exp_not:o #4 - } - } + \exp_not:o #3 + \clist_if_empty:NF #3 { \clist_if_empty:NF #4 { , } } + \exp_not:o #4 } } \cs_generate_variant:Nn \clist_concat:NNN { ccc } @@ -770,13 +808,6 @@ % % \subsection{Removing spaces around items} % -% \begin{macro}[aux]{\clist_tmp:w} -% A temporary function for various purposes. -% \begin{macrocode} -\cs_new_protected:Npn \clist_tmp:w { } -% \end{macrocode} -% \end{macro} -% % \begin{macro}[int,EXP]{\clist_trim_spaces_generic:nw} % \begin{macro}[aux]{\clist_trim_spaces_generic_aux:w} % \begin{macro}[aux]{\clist_trim_spaces_generic_aux_ii:nn} @@ -851,9 +882,32 @@ % \end{macro} % \end{macro} % +% \subsection{Adding data to comma lists} % -% -% \subsection{Appending items to comma lists} +% \begin{macro} +% { +% \clist_set:Nn, \clist_set:NV, +% \clist_set:No, \clist_set:Nx, +% \clist_set:cn, \clist_set:cV, +% \clist_set:co, \clist_set:cx +% } +% \begin{macro} +% { +% \clist_gset:Nn, \clist_gset:NV, +% \clist_gset:No, \clist_gset:Nx, +% \clist_gset:cn, \clist_gset:cV, +% \clist_gset:co, \clist_gset:cx +% } +% \begin{macrocode} +\cs_new_protected:Npn \clist_set:Nn #1#2 + { \tl_set:Nx #1 { \clist_trim_spaces:n {#2} } } +\cs_new_protected:Npn \clist_gset:Nn #1#2 + { \tl_gset:Nx #1 { \clist_trim_spaces:n {#2} } } +\cs_generate_variant:Nn \clist_set:Nn { NV , No , Nx , c , cV , co , cx } +\cs_generate_variant:Nn \clist_gset:Nn { NV , No , Nx , c , cV , co , cx } +% \end{macrocode} +% \end{macro} +% \end{macro} % % \begin{macro} % { @@ -862,7 +916,7 @@ % \clist_put_left:cn, \clist_put_left:cV, % \clist_put_left:co, \clist_put_left:cx % } -%^^A \UnitTested +% \UnitTested % \begin{macro} % { % \clist_gput_left:Nn, \clist_gput_left:NV, @@ -870,7 +924,7 @@ % \clist_gput_left:cn, \clist_gput_left:cV, % \clist_gput_left:co, \clist_gput_left:cx % } -%^^A \UnitTested +% \UnitTested % Comma lists cannot hold empty values: there are therefore a couple % of sanity checks to avoid accumulating commas. % \begin{macrocode} @@ -946,34 +1000,35 @@ % \UnitTested % \begin{macro}{\clist_gpop:NN, \clist_gpop:cN} % \UnitTested -% \begin{macro}[aux]{\clist_pop_aux:NNN} -% \begin{macro}[aux]{\clist_pop_aux:wNNN} +% \begin{macro}[aux] +% {\clist_pop_aux:NNN, \clist_pop_aux:NwNNN, \clist_pop_aux:wNN} % The aim here is to get the popped item as |#1| in the auxiliary, with % |#2| containing either the remainder of the list \emph{or} \cs{q_nil} % if there were insufficient items. That keeps the number of auxiliary % functions down. -%^^A broken for {a,{b,c}}, which unbraces {b,c}. % \begin{macrocode} \cs_new_protected_nopar:Npn \clist_pop:NN - { \clist_pop_aux:NNN \tl_set:Nn } + { \clist_pop_aux:NNN \tl_set:Nf } \cs_new_protected_nopar:Npn \clist_gpop:NN - { \clist_pop_aux:NNN \tl_gset:Nn } + { \clist_pop_aux:NNN \tl_gset:Nf } \cs_new_protected_nopar:Npn \clist_pop_aux:NNN #1#2#3 - { \exp_after:wN \clist_pop_aux:wNNN #2 , \q_nil , \q_nil , \q_stop #1#2#3 } -\cs_new_protected:Npn \clist_pop_aux:wNNN #1 , #2 , \q_nil , #3 \q_stop #4#5#6 { + \exp_after:wN \clist_pop_aux:wNNN #2 , \q_nil \q_stop #1#2#3 + } +\cs_new_protected:Npn \clist_pop_aux:wNNN #1 , #2 \q_stop #3#4#5 + { + \tl_set:Nn #5 {#1} \quark_if_nil:nTF {#2} - { #4 #5 { } } - { #4 #5 {#2} } - \tl_set:Nn #6 {#1} + { #3 #4 { } } + { #3 #4 { \clist_pop_aux:w \exp_stop_f: #2 } } } +\cs_new_protected:Npn \clist_pop_aux:w #1 , \q_nil {#1} \cs_generate_variant:Nn \clist_pop:NN { c } \cs_generate_variant:Nn \clist_gpop:NN { c } % \end{macrocode} % \end{macro} % \end{macro} % \end{macro} -% \end{macro} % % \begin{macro}{ % \clist_push:Nn, \clist_push:NV, \clist_push:No, \clist_push:Nx, @@ -1061,42 +1116,58 @@ % \UnitTested % \begin{macro}[aux]{\clist_remove_all_aux:NNn} % \begin{macro}[aux]{\clist_remove_all_aux:w} -% Removing an item from a comma list is done without looping over -% the entire list, as the performance of that approach is very bad for -% long lists. Instead, a delimited function is needed. For this to work -% correctly, there is a need to add an additional comma at the start of -% the list, and to remove it again once the removal is complete. Of -% course, the list can end up empty, which is the reason for the test -% before copying back to the parent. +% \begin{macro}[aux]{\clist_remove_all_aux:} +% The method used here is very similar to \cs{tl_replace_all:Nnn}. +% Build a function delimited by the \meta{item} that should be removed, +% surrounded with commas, and call that function followed by +% the expanded comma list, and another copy of the \meta{item}. +% The loop is controlled by the argument grabbed by +% \cs{clist_remove_all_aux:w}: when the item was found, +% the \cs{q_mark} delimiter used is the one inserted by +% \cs{clist_tmp:w}, and \cs{use_none_delimit_by_q_stop:w} +% is deleted. At the end, the final \meta{item} is +% grabbed, and the argument of \cs{clist_tmp:w} contains +% \cs{q_mark}: in that case, \cs{clist_remove_all_aux:w} +% removes the second \cs{q_mark} (inserted by \cs{clist_tmp:w}), +% and lets \cs{use_none_delimit_by_q_stop:w} act. +% +% No brace is lost because items are always grabbed with a leading comma. +% The result of the first assignment has an extra leading comma, +% which we remove in a second assignment. +% Two exceptions: if the clist lost all of its elements, the result +% is empty, and we shouldn't remove anything; if the clist started up +% empty, the first step happens to turn it into a single comma, and +% the second step removes it. % \begin{macrocode} \cs_new_protected:Npn \clist_remove_all:Nn - { \clist_remove_all_aux:NNn \clist_set_eq:NN } + { \clist_remove_all_aux:NNn \tl_set:Nx } \cs_new_protected:Npn \clist_gremove_all:Nn - { \clist_remove_all_aux:NNn \clist_gset_eq:NN } + { \clist_remove_all_aux:NNn \tl_gset:Nx } \cs_new_protected:Npn \clist_remove_all_aux:NNn #1#2#3 { + \cs_set:Npn \clist_tmp:w ##1 , #3 , + { + ##1 + , \q_mark , \use_none_delimit_by_q_stop:w , + \clist_remove_all_aux: + } + #1 #2 + { + \exp_after:wN \clist_remove_all_aux: + #2 , \q_mark , #3 , \q_stop + } \clist_if_empty:NF #2 { - \clist_clear:N \l_clist_remove_clist - \cs_set_protected:Npn \clist_remove_all_aux:w - ##1 , #3 , ##2 \q_stop + #1 #2 { - \tl_put_right:Nn \l_clist_remove_clist {##1} - \quark_if_no_value:nF {##2} - { \clist_remove_all_aux:w , ##2 \q_stop } + \exp_args:No \exp_not:o + { \exp_after:wN \use_none:n #2 } } - \exp_after:wN \clist_remove_all_aux:w - \exp_after:wN , #2 , #3 , \q_no_value \q_stop - \tl_if_empty:NF \l_clist_remove_clist - { - \exp_after:wN \tl_set:No \exp_after:wN - \l_clist_remove_clist \exp_after:wN - { \exp_after:wN \use_none:n \l_clist_remove_clist } - } - #1 #2 \l_clist_remove_clist } } -\cs_new_protected:Npn \clist_remove_all_aux:w { } +\cs_new:Npn \clist_remove_all_aux: + { \exp_after:wN \clist_remove_all_aux:w \clist_tmp:w , } +\cs_new:Npn \clist_remove_all_aux:w #1 , \q_mark , #2 , { \exp_not:n {#1} } \cs_generate_variant:Nn \clist_remove_all:Nn { c } \cs_generate_variant:Nn \clist_gremove_all:Nn { c } % \end{macrocode} @@ -1104,10 +1175,17 @@ % \end{macro} % \end{macro} % \end{macro} -% +% \end{macro} % % \subsection{Comma list conditionals} % +% \begin{variable}{\l_clist_if_in_clist} +% An internal comma list for \cs{clist_if_in:nn} conditionals. +% \begin{macrocode} +\clist_new:N \l_clist_if_in_clist +% \end{macrocode} +% \end{variable} +% % \begin{macro}[pTF]{\clist_if_empty:N, \clist_if_empty:c} % \UnitTested % Simple copies from the token list variable material. @@ -1132,35 +1210,29 @@ % \begin{macro}[TF] % { % \clist_if_in:Nn, \clist_if_in:NV, \clist_if_in:No, -% \clist_if_in:cn, \clist_if_in:cV, \clist_if_in:co +% \clist_if_in:cn, \clist_if_in:cV, \clist_if_in:co, +% \clist_if_in:nn, \clist_if_in:nV, \clist_if_in:no % } +% \begin{macro}[aux]{\clist_if_in_return:nn} % \UnitTested +% See description of the \cs{tl_if_in:Nn} function for details. +% We simply surround the comma list, and the item, with commas. % \begin{macrocode} -\prg_new_protected_conditional:Npnn \clist_if_in:Nn #1#2 - { T , F , TF } +\prg_new_protected_conditional:Npnn \clist_if_in:Nn #1#2 { T , F , TF } { - \cs_set_protected:Npn \clist_tmp:w ##1 , #2 , ##2##3 \q_stop - { - \if_meaning:w \q_no_value ##2 - \prg_return_false: - \else: - \prg_return_true: - \fi: - } - \exp_last_unbraced:NNo \clist_tmp:w , #1 , #2 , \q_no_value \q_stop + \exp_args:No \clist_if_in_return:nn #1 {#2} } -\prg_new_protected_conditional:Npnn \clist_if_in:nn #1#2 - { T , F , TF } +\prg_new_protected_conditional:Npnn \clist_if_in:nn #1#2 { T , F , TF } { - \cs_set_protected:Npn \clist_tmp:w ##1 , #2 , ##2##3 \q_stop - { - \if_meaning:w \q_no_value ##2 - \prg_return_false: - \else: - \prg_return_true: - \fi: - } - \clist_tmp:w , #1 , #2 , \q_no_value \q_stop + \clist_set:Nn \l_clist_if_in_clist {#1} + \exp_args:No \clist_if_in_return:nn \l_clist_if_in_clist {#2} + } +\cs_new_protected:Npn \clist_if_in_return:nn #1#2 + { + \cs_set:Npn \clist_tmp:w ##1 ,#2, { } + \tl_if_empty:oTF + { \clist_tmp:w ,#1, {} {} ,#2, } + { \prg_return_false: } { \prg_return_true: } } \cs_generate_variant:Nn \clist_if_in:NnT { NV , No } \cs_generate_variant:Nn \clist_if_in:NnT { c , cV , co } @@ -1173,6 +1245,7 @@ \cs_generate_variant:Nn \clist_if_in:nnTF { nV , no } % \end{macrocode} % \end{macro} +% \end{macro} % % \subsection{Mapping to comma lists} % @@ -1182,6 +1255,8 @@ % \UnitTested % \begin{macro}[aux]{\clist_map_function_aux:Nw} % Mapping to comma lists is pretty simple, if not massively efficient. +% The auxiliary function \cs{clist_map_function_aux:Nw} is used +% directly in \cs{clist_length:n}. Change with care. % \begin{macrocode} \cs_new_nopar:Npn \clist_map_function:NN #1#2 { @@ -1316,7 +1391,7 @@ % \begin{macro}{\clist_map_break:} % \UnitTested % \begin{macro}{\clist_map_break:n} -% Both are simple renaming.^^A todo: fix \clist_map_break:n (cf. seq). +% Both are simple renaming. % \begin{macrocode} \cs_new_eq:NN \clist_map_break: \use_none_delimit_by_q_recursion_stop:w \cs_new_eq:NN \clist_map_break:n \use_i_delimit_by_q_recursion_stop:nw @@ -1367,6 +1442,20 @@ % \end{macro} % \end{macro} % +% \subsection{Scratch comma lists} +% +% \begin{variable}{\l_tmpa_clist, \l_tmpb_clist} +% \begin{variable}{\g_tmpa_tl, \g_tmpb_tl} +% Temporary comma list variables. +% \begin{macrocode} +\clist_new:N \l_tmpa_clist +\clist_new:N \l_tmpb_clist +\clist_new:N \g_tmpa_clist +\clist_new:N \g_tmpb_clist +% \end{macrocode} +% \end{variable} +% \end{variable} +% % \subsection{Experimental functions} % % \begin{macro}{\clist_length:N, \clist_length:c} @@ -1375,7 +1464,11 @@ % Counting the items in a comma list is done using the same approach as for % other length functions: turn each entry into a \texttt{+1} then use % integer evaluation to actually do the mathematics. -%^^A todo: make a faster version avoiding \clist_map_function:nN? +% In the case of an \texttt{n}-type comma-list, we could of course use +% \cs{clist_map_function:nN}, but that is very slow, because it carefully +% removes spaces. Instead, we call \cs{clist_map_function_aux:Nw} +% directly, and test for each item whether it is blank (hence should +% be ignored). % \begin{macrocode} \cs_new:Npn \clist_length:N #1 { @@ -1385,15 +1478,17 @@ \clist_map_function:NN #1 \clist_length_aux:n } } +\cs_new:Npn \clist_length_aux:n #1 { +1 } \cs_new:Npn \clist_length:n #1 { \int_eval:n { 0 - \clist_map_function:nN {#1} \clist_length_aux:n + \clist_map_function_aux:Nw \clist_length_n_aux:n #1 + , \q_recursion_tail , \q_recursion_stop } } -\cs_new:Npn \clist_length_aux:n #1 { +1 } +\cs_new:Npn \clist_length_n_aux:n #1 { \tl_if_blank:nF {#1} {+1} } \cs_generate_variant:Nn \clist_length:N { c } % \end{macrocode} % \end{macro} @@ -1401,35 +1496,44 @@ % \end{macro} % % \begin{macro}{\clist_item:Nn, \clist_item:cn} -% \begin{macro}{\clist_item:nn} -% \begin{macro}[aux]{\clist_item_aux:nnn} -% The idea here is to find the offset of the item from the left, then use -% a loop to grab the correct item. If the resulting offset is too large, -% then \cs{quark_if_recursion_stop:n} will be true, -% terminating the loop and returning nothing at all. +% \begin{macro}[aux]{\clist_item_aux:nnNn} +% \begin{macro}[aux]{\clist_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 less than $-\meta{length}$ or more than $\meta{length}-1$, +% the result is empty. If it is negative, but not less than $-\meta{length}$, +% add the \meta{length} to the item number before performing the loop. +% The loop itself is very simple, return the item if the counter +% reached zero, otherwise, decrease the counter and repeat. % \begin{macrocode} -\cs_set_nopar:Npn \clist_item:Nn #1#2 - { \exp_args:No \clist_item:nn #1 {#2} } -\cs_set:Npn \clist_item:nn #1#2 +\cs_new:Npn \clist_item:Nn #1#2 { - \int_compare:nNnTF {#2} < \c_zero + \exp_args:Nfo \clist_item_aux:nnNn + { \clist_length:N #1 } + #1 + \clist_item_N_loop:nw + {#2} + } +\cs_new:Npn \clist_item_aux: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 + #1 } } } + } { - \exp_args:Nf \clist_item_aux:nw - { \int_eval:n { \clist_length:n {#1} + #2 } } - #1 , \q_recursion_tail \q_recursion_stop + \int_compare:nNnTF {#4} < {#1} + { #3 {#4} } + { \use_none_delimit_by_q_stop:w } } - { \clist_item_aux:nw {#2} #1 , \q_recursion_tail \q_recursion_stop } + #2, \q_stop } -\cs_set:Npn \clist_item_aux:nw #1#2 , #3 +\cs_new:Npn \clist_item_N_loop:nw #1 #2, { \int_compare:nNnTF {#1} = \c_zero - { \use_i_delimit_by_q_recursion_stop:nw {#2} } - { - \quark_if_recursion_tail_stop:n {#3} - \exp_args:Nf \clist_item_aux:nw - { \int_eval:n { #1 - 1 } } - #3 - } + { \use_i_delimit_by_q_stop:nw {#2} } + { \exp_args:Nf \clist_item_N_loop:nw { \int_eval:n { #1 - 1 } } } } \cs_generate_variant:Nn \clist_item:Nn { c } % \end{macrocode} @@ -1437,6 +1541,51 @@ % \end{macro} % \end{macro} % +% \begin{macro}{\clist_item:nn} +% \begin{macro}[aux]{ +% \clist_item_n_aux:nw, +% \clist_item_n_loop:nw, +% \clist_item_n_end:n, +% \clist_item_n_strip:w} +% This starts in the same way as \cs{clist_item:Nn} by checking the length +% 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 \clist_item_aux:nnNn + { \clist_length:n {#1} } + {#1} + \clist_item_n_aux:nw + {#2} + } +\cs_new:Npn \clist_item_n_aux:nw #1 + { \clist_item_n_loop:nw {#1} \prg_do_nothing: } +\cs_new:Npn \clist_item_n_loop:nw #1 #2, + { + \exp_args:No \tl_if_blank:nTF {#2} + { \clist_item_n_loop:nw {#1} \prg_do_nothing: } + { + \int_compare:nNnTF {#1} = \c_zero + { \exp_args:No \clist_item_n_end:n {#2} } + { + \exp_args:Nf \clist_item_n_loop:nw + { \int_eval:n { #1 - 1 } } + \prg_do_nothing: + } + } + } +\cs_new:Npn \clist_item_n_end:n #1 #2 \q_stop + { + \exp_after:wN \exp_after:wN \exp_after:wN \clist_item_n_strip:w + \tl_trim_spaces:n {#1} , + } +\cs_new:Npn \clist_item_n_strip:w #1 , {#1} +% \end{macrocode} +% \end{macro} +% \end{macro} +% % \begin{macro} % { % \clist_set_from_seq:NN, \clist_set_from_seq:cN, @@ -1450,31 +1599,31 @@ % } % \UnitTested % Setting a comma list from a comma-separated list is done using a simple -% mapping. We wrap each item with braces, \cs{exp_not:n}, and a comma. The +% 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 #1#2 - { - \seq_if_empty:NTF #2 - { \clist_clear:N #1 } - { - \seq_push_item_def:n { , \exp_not:n {{##1}} } - \tl_set:Nx #1 - { \exp_after:wN \use_none:n \tex_romannumeral:D -`\0 #2 } - \seq_pop_item_def: - } - } -\cs_new_protected:Npn \clist_gset_from_seq:NN #1#2 +\cs_new_protected:Npn \clist_set_from_seq:NN + { \clist_set_from_seq_aux:NNNN \clist_clear:N \tl_set:Nx } +\cs_new_protected:Npn \clist_gset_from_seq:NN + { \clist_set_from_seq_aux:NNNN \clist_gclear:N \tl_gset:Nx } +\cs_new_protected:Npn \clist_set_from_seq_aux:NNNN #1#2#3#4 { - \seq_if_empty:NTF #2 - { \clist_gclear:N #1 } + \seq_if_empty:NTF #4 + { #1 #3 } { - \seq_push_item_def:n { , \exp_not:n {{##1}} } - \tl_gset:Nx #1 - { \exp_after:wN \use_none:n \tex_romannumeral:D -`\0 #2 } + \seq_push_item_def:n + { + , + \tl_if_empty:oTF { \clist_set_from_seq_aux:w ##1 ~ , ##1 ~ } + { \exp_not:n {##1} } + { \exp_not:n { {##1} } } + } + #2 #3 { \exp_last_unbraced:Nf \use_none:n #4 } \seq_pop_item_def: } } +\cs_new:Npn \clist_set_from_seq_aux: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 } @@ -1491,8 +1640,10 @@ % \UnitTested % These are old stack functions. % \begin{macrocode} +%<*deprecated> \cs_new_eq:NN \clist_top:NN \clist_get:NN \cs_new_eq:NN \clist_top:cN \clist_get:cN +%</deprecated> % \end{macrocode} % \end{macro} % @@ -1500,20 +1651,24 @@ % \UnitTested % An older name for \cs{clist_remove_all:Nn}. % \begin{macrocode} +%<*deprecated> \cs_new_eq:NN \clist_remove_element:Nn \clist_remove_all:Nn \cs_new_eq:NN \clist_gremove_element:Nn \clist_gremove_all:Nn +%</deprecated> % \end{macrocode} % \end{macro} % % \begin{macro}{\clist_display:N, \clist_display:c} % An older name for \cs{clist_show:N}. % \begin{macrocode} +%<*deprecated> \cs_new_eq:NN \clist_display:N \clist_show:N \cs_new_eq:NN \clist_display:c \clist_show:c +%</deprecated> % \end{macrocode} % \end{macro} -% -% Deprecated on 2011-09-05, for removal by 2012-09-04. +% +% Deprecated on 2011-09-05, for removal by 2011-12-32. % % \begin{macro} % { @@ -1522,21 +1677,20 @@ % } % Since clist items are now always stripped from their surrounding % spaces, it is redundant to provide these functions. +% The \cs{clist_trim_spaces:n} function is now internal, +% deprecated for use outside the kernel. % \begin{macrocode} -\cs_new_protected:Npn \clist_trim_spaces:N #1 - { \tl_set:Nx #1 { \exp_args:No \clist_trim_spaces:n #1 } } -\cs_new_protected:Npn \clist_gtrim_spaces:N #1 - { \tl_gset:Nx #1 { \exp_args:No \clist_trim_spaces:n #1 } } +\cs_new_protected:Npn \clist_trim_spaces:N #1 { \clist_set:No #1 {#1} } +\cs_new_protected:Npn \clist_gtrim_spaces:N #1 { \clist_gset:No #1 {#1} } \cs_generate_variant:Nn \clist_trim_spaces:N { c } \cs_generate_variant:Nn \clist_gtrim_spaces:N { c } % \end{macrocode} % \end{macro} % -% % \begin{macrocode} %</initex|package> % \end{macrocode} % % \end{implementation} % -% \PrintIndex
\ No newline at end of file +% \PrintIndex |