summaryrefslogtreecommitdiff
path: root/Master/texmf-dist/source/latex/l3kernel/l3tl.dtx
diff options
context:
space:
mode:
Diffstat (limited to 'Master/texmf-dist/source/latex/l3kernel/l3tl.dtx')
-rw-r--r--Master/texmf-dist/source/latex/l3kernel/l3tl.dtx214
1 files changed, 213 insertions, 1 deletions
diff --git a/Master/texmf-dist/source/latex/l3kernel/l3tl.dtx b/Master/texmf-dist/source/latex/l3kernel/l3tl.dtx
index fab5c69b28a..b85b98a9222 100644
--- a/Master/texmf-dist/source/latex/l3kernel/l3tl.dtx
+++ b/Master/texmf-dist/source/latex/l3kernel/l3tl.dtx
@@ -41,7 +41,7 @@
% }^^A
% }
%
-% \date{Released 2018-12-11}
+% \date{Released 2018-12-12}
%
% \maketitle
%
@@ -1026,6 +1026,79 @@
% \end{texnote}
% \end{function}
%
+% \begin{function}[EXP, added = 2017-02-17, updated = 2017-07-15]
+% {\tl_range:Nnn, \tl_range:nnn}
+% \begin{syntax}
+% \cs{tl_range:Nnn} \meta{tl~var} \Arg{start index} \Arg{end index}
+% \cs{tl_range:nnn} \Arg{token list} \Arg{start index} \Arg{end index}
+% \end{syntax}
+% Leaves in the input stream the items from the \meta{start index} to the
+% \meta{end index} inclusive. Spaces and braces are preserved between
+% the items returned (but never at either end of the list).
+%
+% Here \meta{start index} and \meta{end index} should be integer denotations.
+% For describing in detail the functions' behavior, let $m$ and $n$ be the start
+% and end index respectively. If either is $0$, the result is empty. A positive
+% index means `start counting from the left end', a negative index means
+% `start counting from the right end'. Let $l$ be the count of the token list.
+%
+% The \emph{actual start point} is determined as $M=m$ if~$m>0$ and as $M=l+m+1$
+% if~$m<0$. Similarly the \emph{actual end point} is $N=n$ if~$n>0$ and $N=l+n+1$
+% if~$n<0$. If $M>N$, the result is empty. Otherwise it consists of all items from
+% position $M$ to position $N$ inclusive; for the purpose of this rule, we can
+% imagine that the token list extends at infinity on either side, with void items
+% at positions $s$ for $s\le0$ or $s>l$.
+%
+% Spaces in between items in the actual range are preserved. Spaces at either end
+% of the token list will be removed anyway (think to the token list being passed to
+% |\tl_trim_spaces:n| to begin with.
+%
+% Thus, with $l=7$ as in the examples below, all of the following are equivalent
+% and result in the whole token list
+% \begin{verbatim}
+% \tl_range:nnn { abcd~{e{}}fg } { 1 } { 7 }
+% \tl_range:nnn { abcd~{e{}}fg } { 1 } { 12 }
+% \tl_range:nnn { abcd~{e{}}fg } { -7 } { 7 }
+% \tl_range:nnn { abcd~{e{}}fg } { -12 } { 7 }
+% \end{verbatim}
+% Here are some more interesting examples. The calls
+% \begin{verbatim}
+% \iow_term:x { \tl_range:nnn { abcd{e{}}fg } { 2 } { 5 } }
+% \iow_term:x { \tl_range:nnn { abcd{e{}}fg } { 2 } { -3 } }
+% \iow_term:x { \tl_range:nnn { abcd{e{}}fg } { -6 } { 5 } }
+% \iow_term:x { \tl_range:nnn { abcd{e{}}fg } { -6 } { -3 } }
+% \end{verbatim}
+% are all equivalent and will print |bcd{e{}}| on the terminal; similarly
+% \begin{verbatim}
+% \iow_term:x { \tl_range:nnn { abcd~{e{}}fg } { 2 } { 5 } }
+% \iow_term:x { \tl_range:nnn { abcd~{e{}}fg } { 2 } { -3 } }
+% \iow_term:x { \tl_range:nnn { abcd~{e{}}fg } { -6 } { 5 } }
+% \iow_term:x { \tl_range:nnn { abcd~{e{}}fg } { -6 } { -3 } }
+% \end{verbatim}
+% are all equivalent and will print |bcd {e{}}| on the
+% terminal (note the space in the middle). To the contrary,
+% \begin{verbatim}
+% \tl_range:nnn { abcd~{e{}}f } { 2 } { 4 }
+% \end{verbatim}
+% will discard the space after `d`.
+%
+% If we want to get the items from the third to the last, the call
+% is |\tl_range:nnn { <tl> } { 3 } { -1 }|. Similarly, for discarding
+% the last item, we can do |\tl_range:nnn { <tl> } { 1 } { -2 }|.
+%
+% The behavior of \cs{tl_range:Nnn} is exactly the same, acting on the
+% contents of the tl variable.
+%
+% For improved performance, see \cs{tl_range_braced:nnn} and
+% \cs{tl_range_unbraced:nnn}.
+% \begin{texnote}
+% The result is returned within the \tn{unexpanded}
+% primitive (\cs{exp_not:n}), which means that the \meta{item}
+% does not expand further when appearing in an \texttt{x}-type
+% argument expansion.
+% \end{texnote}
+% \end{function}
+%
% \section{Viewing token lists}
%
% \begin{function}[updated = 2015-08-01]{\tl_show:N, \tl_show:c}
@@ -2994,6 +3067,145 @@
% \end{macrocode}
% \end{macro}
%
+% \begin{macro}{\tl_range:Nnn, \tl_range:cnn, \tl_range:nnn}
+% \begin{macro}
+% {
+% \@@_range:Nnnn, \@@_range:nnnNn, \@@_range:nnNn, \@@_range_skip:w,
+% \@@_range:w, \@@_range_skip_spaces:n, \@@_range_collect:nn,
+% \@@_range_collect:ff, \@@_range_collect_space:nw,
+% \@@_range_collect_N:nN, \@@_range_collect_group:nN,
+% }
+% To avoid checking for the end of the token list at every step, start
+% by counting the number $l$ of items and \enquote{normalizing} the
+% bounds, namely clamping them to the interval $[0,l]$ and dealing
+% with negative indices. More precisely, \cs{@@_range_items:nnNn}
+% receives the number of items to skip at the beginning of the token
+% list, the index of the last item to keep, a function which is either
+% \cs{@@_range:w} or the token list itself. If nothing should be kept,
+% leave |{}|: this stops the \texttt{f}-expansion of \cs{tl_head:f} and that
+% function produces an empty result. Otherwise, repeatedly call
+% \cs{@@_range_skip:w} to delete |#1| items from the input stream (the
+% extra brace group avoids an off-by-one shift). For the braced
+% version \cs{@@_range_braced:w} sets up
+% \cs{@@_range_collect_braced:w} which stores items one by one in an
+% argument after the semicolon. Depending on the first token of the tail,
+% either just move it (if it is a space) or also decrement the number of
+% items left to find. Eventually, the result is a brace group followed by
+% the rest of the token list, and \cs{tl_head:f} cleans up and gives the
+% result in \cs{exp_not:n}.
+% \begin{macrocode}
+\cs_new:Npn \tl_range:Nnn { \exp_args:No \tl_range:nnn }
+\cs_generate_variant:Nn \tl_range:Nnn { c }
+\cs_new:Npn \tl_range:nnn { \@@_range:Nnnn \@@_range:w }
+\cs_new:Npn \@@_range:Nnnn #1#2#3#4
+ {
+ \tl_head:f
+ {
+ \exp_args:Nf \@@_range:nnnNn
+ { \tl_count:n {#2} } {#3} {#4} #1 {#2}
+ }
+ }
+\cs_new:Npn \@@_range:nnnNn #1#2#3
+ {
+ \exp_args:Nff \@@_range:nnNn
+ {
+ \exp_args:Nf \@@_range_normalize:nn
+ { \int_eval:n { #2 - 1 } } {#1}
+ }
+ {
+ \exp_args:Nf \@@_range_normalize:nn
+ { \int_eval:n {#3} } {#1}
+ }
+ }
+\cs_new:Npn \@@_range:nnNn #1#2#3#4
+ {
+ \if_int_compare:w #2 > #1 \exp_stop_f: \else:
+ \exp_after:wN { \exp_after:wN }
+ \fi:
+ \exp_after:wN #3
+ \int_value:w \int_eval:n { #2 - #1 } \exp_after:wN ;
+ \exp_after:wN { \exp:w \@@_range_skip:w #1 ; { } #4 }
+ }
+\cs_new:Npn \@@_range_skip:w #1 ; #2
+ {
+ \if_int_compare:w #1 > 0 \exp_stop_f:
+ \exp_after:wN \@@_range_skip:w
+ \int_value:w \int_eval:n { #1 - 1 } \exp_after:wN ;
+ \else:
+ \exp_after:wN \exp_end:
+ \fi:
+ }
+\cs_new:Npn \@@_range:w #1 ; #2
+ {
+ \exp_args:Nf \@@_range_collect:nn
+ { \@@_range_skip_spaces:n {#2} } {#1}
+ }
+\cs_new:Npn \@@_range_skip_spaces:n #1
+ {
+ \tl_if_head_is_space:nTF {#1}
+ { \exp_args:Nf \@@_range_skip_spaces:n {#1} }
+ { { } #1 }
+ }
+\cs_new:Npn \@@_range_collect:nn #1#2
+ {
+ \int_compare:nNnTF {#2} = 0
+ {#1}
+ {
+ \exp_args:No \tl_if_head_is_space:nTF { \use_none:n #1 }
+ {
+ \exp_args:Nf \@@_range_collect:nn
+ { \@@_range_collect_space:nw #1 }
+ {#2}
+ }
+ {
+ \@@_range_collect:ff
+ {
+ \exp_args:No \tl_if_head_is_N_type:nTF { \use_none:n #1 }
+ { \@@_range_collect_N:nN }
+ { \@@_range_collect_group:nn }
+ #1
+ }
+ { \int_eval:n { #2 - 1 } }
+ }
+ }
+ }
+\cs_new:Npn \@@_range_collect_space:nw #1 ~ { { #1 ~ } }
+\cs_new:Npn \@@_range_collect_N:nN #1#2 { { #1 #2 } }
+\cs_new:Npn \@@_range_collect_group:nn #1#2 { { #1 {#2} } }
+\cs_generate_variant:Nn \@@_range_collect:nn { ff }
+% \end{macrocode}
+% \end{macro}
+% \end{macro}
+%
+% \begin{macro}[EXP]{\@@_range_normalize:nn}
+% This function converts an \meta{index} argument into an explicit
+% position in the token list (a result of $0$ denoting \enquote{out of
+% bounds}). Expects two explicit integer arguments: the \meta{index}
+% |#1| and the string count~|#2|. If |#1| is negative, replace it by
+% $|#1| + |#2| + 1$, then limit to the range $[0, |#2|]$.
+% \begin{macrocode}
+\cs_new:Npn \@@_range_normalize:nn #1#2
+ {
+ \int_eval:n
+ {
+ \if_int_compare:w #1 < 0 \exp_stop_f:
+ \if_int_compare:w #1 < -#2 \exp_stop_f:
+ 0
+ \else:
+ #1 + #2 + 1
+ \fi:
+ \else:
+ \if_int_compare:w #1 < #2 \exp_stop_f:
+ #1
+ \else:
+ #2
+ \fi:
+ \fi:
+ }
+ }
+% \end{macrocode}
+% \end{macro}
+%
% \subsection{Viewing token lists}
%
% \begin{macro}{\tl_show:N, \tl_show:c, \tl_log:N, \tl_log:c, \@@_show:NN}