summaryrefslogtreecommitdiff
path: root/Master/texmf-dist/source/latex/l3kernel/l3clist.dtx
diff options
context:
space:
mode:
Diffstat (limited to 'Master/texmf-dist/source/latex/l3kernel/l3clist.dtx')
-rw-r--r--Master/texmf-dist/source/latex/l3kernel/l3clist.dtx342
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}