diff options
author | Karl Berry <karl@freefriends.org> | 2021-05-25 20:48:22 +0000 |
---|---|---|
committer | Karl Berry <karl@freefriends.org> | 2021-05-25 20:48:22 +0000 |
commit | 1764edc3b60a2c9fb210ca74b758f3e8e8a53692 (patch) | |
tree | da1842e54bdea33c2b8d434860131cfa08c9444d /Master/texmf-dist/source/latex/l3kernel/l3clist.dtx | |
parent | 4bf5956529386575d89874638bfd567040b9475c (diff) |
l3kernel (25may21)
git-svn-id: svn://tug.org/texlive/trunk@59345 c570f23f-e606-0410-a88d-b1316a301751
Diffstat (limited to 'Master/texmf-dist/source/latex/l3kernel/l3clist.dtx')
-rw-r--r-- | Master/texmf-dist/source/latex/l3kernel/l3clist.dtx | 210 |
1 files changed, 113 insertions, 97 deletions
diff --git a/Master/texmf-dist/source/latex/l3kernel/l3clist.dtx b/Master/texmf-dist/source/latex/l3kernel/l3clist.dtx index f61fedb4837..147fb466751 100644 --- a/Master/texmf-dist/source/latex/l3kernel/l3clist.dtx +++ b/Master/texmf-dist/source/latex/l3kernel/l3clist.dtx @@ -44,21 +44,22 @@ % }^^A % } % -% \date{Released 2021-05-11} +% \date{Released 2021-05-25} % % \maketitle % % \begin{documentation} % -% Comma lists contain ordered data where items can be added to the left -% or right end of the list. This data type allows basic list +% Comma lists (in short, |clist|) contain ordered data where items can +% be added to the left or right end of the list. This data type allows +% basic list % manipulations such as adding/removing items, applying a function to % every item, removing duplicate items, extracting a given item, using % the comma list with specified separators, and so on. Sequences % (defined in \pkg{l3seq}) are safer, faster, and provide more features, % so they should often be preferred to comma lists. Comma lists are % mostly useful when interfacing with \LaTeXe{} or other code that -% expects or provides comma list data. +% expects or provides items separated by commas. % % Several items can be added at once. To ease input of comma lists from % data provided by a user outside an \cs{ExplSyntaxOn} \ldots{} @@ -75,10 +76,10 @@ % \end{verbatim} % results in |\l_my_clist| containing |a,b,c~\d,{e~},{{f}}| namely the % five items |a|, |b|, |c~\d|, |e~| and~|{f}|. Comma lists normally do -% not contain empty items so the following gives an empty comma list: +% not contain empty or blank items so the following gives an empty comma list: % \begin{verbatim} % \clist_clear_new:N \l_my_clist -% \clist_put_right:Nn \l_my_clist { , ~ , , } +% \clist_set:Nn \l_my_clist { , ~ , , } % \clist_if_empty:NTF \l_my_clist { true } { false } % \end{verbatim} % and it leaves \texttt{true} in the input stream. To include an @@ -86,6 +87,17 @@ % or ends with a space, or is a single brace group), surround it with % braces. % +% Any |n|-type token list is a valid comma list input for \pkg{l3clist} +% functions, which will split the token list at every comma and process +% the items as described above. On the other hand, |N|-type functions +% expect comma list variables, which are particular token list variables +% in which this processing of items (and removal of blank items) has +% already occurred. Because comma list variables are token list +% variables, expanding them once yields their items separated by commas, +% and \pkg{l3tl} functions such as \cs{tl_show:N} can be applied to +% them. (These functions often have \pkg{l3clist} analogues, which +% should be preferred.) +% % Almost all operations on comma lists are % noticeably slower than those on sequences so converting the data to % sequences using \cs{seq_set_from_clist:Nn} (see \pkg{l3seq}) may be @@ -156,7 +168,10 @@ % \cs{clist_set_eq:NN} \meta{comma list_1} \meta{comma list_2} % \end{syntax} % Sets the content of \meta{comma list_1} equal to that of -% \meta{comma list_2}. +% \meta{comma list_2}. To set a token list variable equal to a comma +% list variable, use \cs{tl_set_eq:NN}. Conversely, setting a comma +% list variable to a token list is unadvisable unless one checks +% space-trimming and related issues. % \end{function} % % \begin{function}[added = 2014-07-17] @@ -831,22 +846,6 @@ % \end{macrocode} % \end{macro} % -% \begin{variable}{\q_@@_recursion_tail,\q_@@_recursion_stop} -% Internal recursion quarks. -% \begin{macrocode} -\quark_new:N \q_@@_recursion_tail -\quark_new:N \q_@@_recursion_stop -% \end{macrocode} -% \end{variable} -% -% \begin{macro}[EXP]{\@@_if_recursion_tail_break:nN,\@@_if_recursion_tail_stop:n} -% Functions to query recursion quarks. -% \begin{macrocode} -\__kernel_quark_new_test:N \@@_if_recursion_tail_break:nN -\__kernel_quark_new_test:N \@@_if_recursion_tail_stop:n -% \end{macrocode} -% \end{macro} -% % \begin{macro}{\@@_tmp:w} % A temporary function for various purposes. % \begin{macrocode} @@ -888,11 +887,11 @@ { \exp_after:wN \@@_sanitize:Nn \exp_after:wN \c_empty_tl \exp:w \@@_trim_next:w \prg_do_nothing: - #1 , \q_@@_recursion_tail , \q_@@_recursion_stop + #1 , \s_@@_stop \prg_break: , \prg_break_point: } \cs_new:Npn \@@_sanitize:Nn #1#2 { - \@@_if_recursion_tail_stop:n {#2} + \@@_use_none_delimit_by_s_stop:w #2 \s_@@_stop #1 \@@_wrap_item:w #2 , \exp_after:wN \@@_sanitize:Nn \exp_after:wN , \exp:w \@@_trim_next:w \prg_do_nothing: @@ -910,10 +909,7 @@ % \item is empty, or % \item consists of a single braced group. % \end{itemize} -% All \pkg{l3clist} functions go through the same test when they need -% to determine whether to brace an item, so it is not a problem that -% this test has false positives such as \enquote{\cs{s_@@_mark} -% \texttt{?}}. If the argument starts or end with a space or contains +% If the argument starts or ends with a space or contains % a comma then one of the three arguments of \cs{@@_if_wrap:w} will % have its end delimiter (partly) in one of the three copies of |#1| % in \cs{@@_if_wrap:nTF}; this has a knock-on effect meaning that the @@ -1394,7 +1390,13 @@ \clist_map_inline:Nn #2 { \clist_if_in:NnF \l_@@_internal_remove_clist {##1} - { \clist_put_right:Nn \l_@@_internal_remove_clist {##1} } + { + \tl_put_right:Nx \l_@@_internal_remove_clist + { + \clist_if_empty:NF \l_@@_internal_remove_clist { , } + \@@_if_wrap:nTF {##1} { \exp_not:n { {##1} } } { \exp_not:n {##1} } + } + } } #1 #2 \l_@@_internal_remove_clist } @@ -1654,28 +1656,38 @@ % % \begin{macro}{\clist_map_function:NN, \clist_map_function:cN} % \UnitTested -% \begin{macro}{\@@_map_function:nw} +% \begin{macro}{\@@_map_function:Nw, \@@_map_function_end:w} % If the variable is empty, the mapping is skipped (otherwise, % that comma-list would be seen as consisting of one empty item). -% Then loop over the comma-list, grabbing one comma-delimited -% item at a time. The end is marked by \cs{q_@@_recursion_tail}. -% The auxiliary function \cs{@@_map_function:nw} is also used -% in \cs{clist_map_inline:Nn}. +% Then loop over the comma-list, grabbing eight comma-delimited items +% at a time. The end is marked by \cs{s_@@_stop}, which may not appear +% in any of the items. Once the last group of eight items has been +% reached, we go through them more slowly using +% \cs{@@_map_function_end:w}. The auxiliary function +% \cs{@@_map_function:Nw} is also used in some other clist mappings. % \begin{macrocode} \cs_new:Npn \clist_map_function:NN #1#2 { \clist_if_empty:NF #1 { - \exp_last_unbraced:NNo \@@_map_function:nw #2 #1 - , \q_@@_recursion_tail , + \exp_after:wN \@@_map_function:Nw \exp_after:wN #2 #1 , + \s_@@_stop , \s_@@_stop , \s_@@_stop , \s_@@_stop , + \s_@@_stop , \s_@@_stop , \s_@@_stop , \s_@@_stop , \prg_break_point:Nn \clist_map_break: { } } } -\cs_new:Npn \@@_map_function:nw #1#2 , +\cs_new:Npn \@@_map_function:Nw #1 #2, #3, #4, #5, #6, #7, #8, #9, + { + \@@_use_none_delimit_by_s_stop:w + #9 \@@_map_function_end:w \s_@@_stop + #1 {#2} #1 {#3} #1 {#4} #1 {#5} #1 {#6} #1 {#7} #1 {#8} #1 {#9} + \@@_map_function:Nw #1 + } +\cs_new:Npn \@@_map_function_end:w \s_@@_stop #1#2 { - \@@_if_recursion_tail_break:nN {#2} \clist_map_break: + \@@_use_none_delimit_by_s_stop:w #2 \clist_map_break: \s_@@_stop #1 {#2} - \@@_map_function:nw {#1} + \@@_map_function_end:w \s_@@_stop } \cs_generate_variant:Nn \clist_map_function:NN { c } % \end{macrocode} @@ -1697,12 +1709,13 @@ \cs_new:Npn \clist_map_function:nN #1#2 { \exp_after:wN \@@_map_function_n:Nn \exp_after:wN #2 - \exp:w \@@_trim_next:w \prg_do_nothing: #1 , \q_@@_recursion_tail , + \exp:w \@@_trim_next:w \prg_do_nothing: #1 , + \s_@@_stop \clist_map_break: , \prg_break_point:Nn \clist_map_break: { } } \cs_new:Npn \@@_map_function_n:Nn #1 #2 { - \@@_if_recursion_tail_break:nN {#2} \clist_map_break: + \@@_use_none_delimit_by_s_stop:w #2 \s_@@_stop \@@_map_unbrace:wn #2 , #1 \exp_after:wN \@@_map_function_n:Nn \exp_after:wN #1 \exp:w \@@_trim_next:w \prg_do_nothing: @@ -1736,9 +1749,11 @@ \int_gincr:N \g__kernel_prg_map_int \cs_gset_protected:cpn { @@_map_ \int_use:N \g__kernel_prg_map_int :w } ##1 {#2} - \exp_last_unbraced:Nco \@@_map_function:nw + \exp_last_unbraced:Nco \@@_map_function:Nw { @@_map_ \int_use:N \g__kernel_prg_map_int :w } - #1 , \q_@@_recursion_tail , + #1 , + \s_@@_stop , \s_@@_stop , \s_@@_stop , \s_@@_stop , + \s_@@_stop , \s_@@_stop , \s_@@_stop , \s_@@_stop , \prg_break_point:Nn \clist_map_break: { \int_gdecr:N \g__kernel_prg_map_int } } @@ -1756,65 +1771,63 @@ % \begin{macro}{\clist_map_variable:NNn, \clist_map_variable:cNn} % \UnitTested % \begin{macro}{\clist_map_variable:nNn} -% \begin{macro}{\@@_map_variable:Nnw} -% As for other comma-list mappings, filter out the case of -% an empty list. Same approach as \cs{clist_map_function:Nn}, -% additionally we store each item in the given variable. -% As for inline mappings, space trimming for the \texttt{n} -% variant is done by storing the comma list in a variable. -% The quark test is done before assigning the item to the variable: -% this avoids storing a quark which the user wouldn't expect. -% The strange \cs{use:n} avoids unlikely problems when |#2| would -% contain \cs{q_@@_recursion_stop}. +% \begin{macro}{\@@_map_variable:Nnn} +% The |N|-type version is a straightforward application of +% \cs{clist_map_tokens:Nn}, calling \cs{@@_map_variable:Nnn} for each +% item to assign the variable and run the user's code. The |n|-type +% version is \emph{not} implemented in terms of the |n|-type function +% \cs{clist_map_tokens:Nn}, because here we are allowed to clean up +% the |n|-type comma list non-expandably. % \begin{macrocode} \cs_new_protected:Npn \clist_map_variable:NNn #1#2#3 - { - \clist_if_empty:NF #1 - { - \exp_args:Nno \use:nn - { \@@_map_variable:Nnw #2 {#3} } - #1 - , \q_@@_recursion_tail , \q_@@_recursion_stop - \prg_break_point:Nn \clist_map_break: { } - } - } + { \clist_map_tokens:Nn #1 { \@@_map_variable:Nnn #2 {#3} } } +\cs_generate_variant:Nn \clist_map_variable:NNn { c } +\cs_new_protected:Npn \@@_map_variable:Nnn #1#2#3 + { \tl_set:Nn #1 {#3} #2 } \cs_new_protected:Npn \clist_map_variable:nNn #1 { \clist_set:Nn \l_@@_internal_clist {#1} \clist_map_variable:NNn \l_@@_internal_clist } -\cs_new_protected:Npn \@@_map_variable:Nnw #1#2#3, - { - \@@_if_recursion_tail_stop:n {#3} - \tl_set:Nn #1 {#3} - \use:n {#2} - \@@_map_variable:Nnw #1 {#2} - } -\cs_generate_variant:Nn \clist_map_variable:NNn { c } % \end{macrocode} % \end{macro} % \end{macro} % \end{macro} % % \begin{macro}{\clist_map_tokens:Nn, \clist_map_tokens:cn} -% \begin{macro}{\@@_map_tokens:nw} +% \begin{macro}{\@@_map_tokens:nw, \@@_map_tokens_end:w} % Essentially a copy of \cs{clist_map_function:NN} with braces added. % \begin{macrocode} \cs_new:Npn \clist_map_tokens:Nn #1#2 { \clist_if_empty:NF #1 { - \exp_last_unbraced:Nno \@@_map_function:nw {#2} #1 - , \q_@@_recursion_tail , + \exp_last_unbraced:Nno \@@_map_tokens:nw {#2} #1 , + \s_@@_stop , \s_@@_stop , \s_@@_stop , \s_@@_stop , + \s_@@_stop , \s_@@_stop , \s_@@_stop , \s_@@_stop , \prg_break_point:Nn \clist_map_break: { } } } +\cs_new:Npn \@@_map_tokens:nw #1 #2, #3, #4, #5, #6, #7, #8, #9, + { + \@@_use_none_delimit_by_s_stop:w + #9 \@@_map_tokens_end:w \s_@@_stop + \use:n {#1} {#2} \use:n {#1} {#3} \use:n {#1} {#4} \use:n {#1} {#5} + \use:n {#1} {#6} \use:n {#1} {#7} \use:n {#1} {#8} \use:n {#1} {#9} + \@@_map_tokens:nw {#1} + } +\cs_new:Npn \@@_map_tokens_end:w \s_@@_stop \use:n #1#2 + { + \@@_use_none_delimit_by_s_stop:w #2 \clist_map_break: \s_@@_stop + #1 {#2} + \@@_map_tokens_end:w \s_@@_stop + } \cs_generate_variant:Nn \clist_map_tokens:Nn { c } % \end{macrocode} % \end{macro} % \end{macro} % -% \begin{macro}{\clist_map_tokens:nn, \@@_map_tokens_n:nw, \@@_use_ii_i:nn} +% \begin{macro}{\clist_map_tokens:nn, \@@_map_tokens_n:nw} % Similar to \cs{clist_map_function:nN} but with a different way of % grabbing items because we cannot use \cs{exp_after:wN} to pass the % \meta{code}. @@ -1822,20 +1835,19 @@ \cs_new:Npn \clist_map_tokens:nn #1#2 { \@@_map_tokens_n:nw {#2} - \prg_do_nothing: #1 , \q_@@_recursion_tail , + \prg_do_nothing: #1 , \s_@@_stop \clist_map_break: , \prg_break_point:Nn \clist_map_break: { } } \cs_new:Npn \@@_map_tokens_n:nw #1#2 , { \tl_if_empty:oF { \use_none:nn #2 ? } { - \exp_args:No \@@_if_recursion_tail_break:nN {#2} \clist_map_break: - \tl_trim_spaces_apply:oN {#2} \@@_use_ii_i:nn + \@@_use_none_delimit_by_s_stop:w #2 \s_@@_stop + \tl_trim_spaces_apply:oN {#2} \use_ii_i:nn \@@_map_unbrace:wn , {#1} } \@@_map_tokens_n:nw {#1} \prg_do_nothing: } -\cs_new:Npn \@@_use_ii_i:nn #1#2 { #2 #1 } % \end{macrocode} % \end{macro} % @@ -1869,22 +1881,26 @@ } } \cs_generate_variant:Nn \clist_count:N { c } -\cs_new:Npx \clist_count:n #1 +\cs_new:Npn \@@_count:n #1 { + 1 } +\cs_set_protected:Npn \@@_tmp:w #1 { - \exp_not:N \int_eval:n + \cs_new:Npn \clist_count:n ##1 { - 0 - \exp_not:N \@@_count:w \c_space_tl - #1 \exp_not:n { , \q_@@_recursion_tail , \q_@@_recursion_stop } + \int_eval:n + { + 0 + \@@_count:w #1 + ##1 , \s_@@_stop \prg_break: , \prg_break_point: + } + } + \cs_new:Npn \@@_count:w ##1 , + { + \@@_use_none_delimit_by_s_stop:w ##1 \s_@@_stop + \tl_if_blank:nF {##1} { + 1 } + \@@_count:w #1 } } -\cs_new:Npn \@@_count:n #1 { + 1 } -\cs_new:Npx \@@_count:w #1 , - { - \exp_not:n { \exp_args:Nf \@@_if_recursion_tail_stop:n } {#1} - \exp_not:N \tl_if_blank:nF {#1} { + 1 } - \exp_not:N \@@_count:w \c_space_tl - } +\exp_args:No \@@_tmp:w \c_space_tl % \end{macrocode} % \end{macro} % \end{macro} @@ -1907,15 +1923,15 @@ % quarks), 5: the rest of the comma list, 6: a \meta{continuation} % function (\texttt{use_ii} or \texttt{use_iii} with its % \meta{separator} argument), 7: junk, and 8: the temporary result, -% which is built in a brace group following \cs{q_@@_stop}. The +% which is built in a brace group following \cs{s_@@_stop}. The % \meta{separator} and the first of the three items are placed in the % result, then we use the \meta{continuation}, placing the remaining % two items after it. When we begin this loop, the three items really -% belong to the comma list, the first \cs{q_@@_mark} is taken as a +% belong to the comma list, the first \cs{s_@@_mark} is taken as a % delimiter to the \texttt{use_ii} function, and the continuation is % \texttt{use_ii} itself. When we reach the last two items of the -% original token list, \cs{q_@@_mark} is taken as a third item, and now -% the second \cs{q_@@_mark} serves as a delimiter to \texttt{use_ii}, +% original token list, \cs{s_@@_mark} is taken as a third item, and now +% the second \cs{s_@@_mark} serves as a delimiter to \texttt{use_ii}, % switching to the other \meta{continuation}, \texttt{use_iii}, which % uses the \meta{separator between final two}. % \begin{macrocode} @@ -1993,7 +2009,7 @@ { \@@_use:Nw #1#2 ; } { \@@_use_none_delimit_by_s_mark:w #4 #1 \s_@@_mark - \tl_trim_spaces_apply:oN {#4} \@@_use_ii_i:nn + \tl_trim_spaces_apply:oN {#4} \use_ii_i:nn \@@_map_unbrace:wn , { #2 ; } } #3 ; \prg_do_nothing: |