summaryrefslogtreecommitdiff
path: root/Master/texmf-dist/source/latex/l3kernel/l3tl.dtx
diff options
context:
space:
mode:
authorKarl Berry <karl@freefriends.org>2011-08-12 23:14:34 +0000
committerKarl Berry <karl@freefriends.org>2011-08-12 23:14:34 +0000
commitc9172879c19139ba8d262e615a535073caea2e54 (patch)
tree3d907d4933b43fbc204a7069106fb6715601824f /Master/texmf-dist/source/latex/l3kernel/l3tl.dtx
parent3affad3394ee81c3f5ba136242d5d56949254515 (diff)
l3kernel (11aug11)
git-svn-id: svn://tug.org/texlive/trunk@23524 c570f23f-e606-0410-a88d-b1316a301751
Diffstat (limited to 'Master/texmf-dist/source/latex/l3kernel/l3tl.dtx')
-rw-r--r--Master/texmf-dist/source/latex/l3kernel/l3tl.dtx234
1 files changed, 181 insertions, 53 deletions
diff --git a/Master/texmf-dist/source/latex/l3kernel/l3tl.dtx b/Master/texmf-dist/source/latex/l3kernel/l3tl.dtx
index a7f292d14c7..149f4a487ba 100644
--- a/Master/texmf-dist/source/latex/l3kernel/l3tl.dtx
+++ b/Master/texmf-dist/source/latex/l3kernel/l3tl.dtx
@@ -35,7 +35,7 @@
%
%<*driver|package>
\RequirePackage{l3names}
-\GetIdInfo$Id: l3tl.dtx 2498 2011-07-09 17:51:47Z joseph $
+\GetIdInfo$Id: l3tl.dtx 2534 2011-08-10 18:21:44Z joseph $
{L3 Experimental token lists}
%</driver|package>
%<*driver>
@@ -768,44 +768,87 @@
% \begin{syntax}
% \cs{tl_head:n} \Arg{tokens}
% \end{syntax}
-% Leaves only the first \meta{token} in \meta{tokens} in the input
-% stream, discarding the remainder.
+% Leaves in the input stream the first non-space token from the
+% \meta{tokens}. Any leading space tokens will be discarded, and thus for
+% example
+% \begin{verbatim}
+% \tl_head:n { abc }
+% \end{verbatim}
+% and
+% \begin{verbatim}
+% \tl_head:n { ~ abc }
+% \end{verbatim}
+% will both leave |a| in the input stream.
+% An empty list of \meta{tokens} or one which consists
+% only of space (category code $10$) tokens will result in \cs{tl_head:n}
+% leaving nothing in the input stream.
% \end{function}
%
% \begin{function}[EXP]{\tl_head:w}
% \begin{syntax}
-% \cs{tl_head:w} \Arg{tokens} \cs{q_stop}
+% \cs{tl_head:w} \meta{tokens} \cs{q_stop}
% \end{syntax}
-% Leaves only the first \meta{token} in \meta{tokens} in the input
-% stream, discarding the remainder. This function requires only a
-% single expansion, and so is suitable for use inside an
-% \texttt{o}-type expansion. In general \cs{tl_head:n} should be
-% preferred.
+% Leaves in the input stream the first non-space token from the
+% \meta{tokens}. An empty list of \meta{tokens} or one which consists
+% only of space (category code $10$) tokens will result in an error, and
+% thus \meta{tokens} must \emph{not} be \enquote{blank} as determined by
+% \cs{tl_if_blank:n(TF)}. This function requires only a single expansion,
+% and thus is suitable for use within an \texttt{o}-type expansion. In
+% general, \cs{tl_head:n} should be preferred if the number of expansions
+% is not critical.
+% \end{function}
+%
+% \begin{function}[EXP]{\str_head:n}
+% \begin{syntax}
+% \cs{str_head:n} \Arg{tokens}
+% \end{syntax}
+% Converts the \meta{tokens} into a string, as described for
+% \cs{tl_to_str:n}, and then leaves the first character of this string
+% in the input stream; the first character may be a space. If the
+% \meta{tokens} argument is entirely empty, \cs{scan_stop:} will be left in
+% the input stream.
% \end{function}
%
% \begin{function}[EXP]{\tl_tail:n, \tl_tail:V, \tl_tail:v, \tl_tail:f}
% \begin{syntax}
% \cs{tl_tail:n} \Arg{tokens}
% \end{syntax}
-% Discards the first \meta{token} of the \meta{tokens} and leaves the
-% remainder in the input stream.
+% Discards the all leading space tokens and the first non-space token
+% in the \meta{tokens}, and leaves the remaining tokens in the
+% input stream. Thus for example
+% \begin{verbatim}
+% \tl_tail:n { abc }
+% \end{verbatim}
+% and
+% \begin{verbatim}
+% \tl_tail:n { ~ abc }
+% \end{verbatim}
+% will both leave |bc| in the input stream.
+% An empty list of \meta{tokens} or one which consists
+% only of space (category code $10$) tokens will result in \cs{tl_tail:n}
+% leaving nothing in the input stream.
% \end{function}
%
% \begin{function}[EXP]{\tl_tail:w}
% \begin{syntax}
% \cs{tl_tail:w} \Arg{tokens} \cs{q_stop}
% \end{syntax}
-% Discards the first \meta{token} of the \meta{tokens} and leaves the
-% remainder in the input stream. This function requires only a
-% single expansion, and so is suitable for use inside an
-% \texttt{o}-type expansion. In general \cs{tl_tail:n} should be
-% preferred.
+% Discards the all leading space tokens and the first non-space token
+% in the \meta{tokens}, and leaves the remaining tokens in the
+% input stream.
+% An empty list of \meta{tokens} or one which consists
+% only of space (category code $10$) tokens will result in an error, and
+% thus \meta{tokens} must \emph{not} be \enquote{blank} as determined by
+% \cs{tl_if_blank:n(TF)}. This function requires only a single expansion,
+% and thus is suitable for use within an \texttt{o}-type expansion. In
+% general, \cs{tl_tail:n} should be preferred if the number of expansions
+% is not critical.
% \end{function}
%
% \begin{function}[EXP,pTF]{\tl_if_head_eq_catcode:nN}
% \begin{syntax}
-% \cs{tl_if_head_eq_catcode_p:n} \Arg{token list} \meta{test token}
-% \cs{tl_if_head_eq_catcode:nTF} \Arg{token list} \meta{test token}
+% \cs{tl_if_head_eq_catcode_p:nN} \Arg{token list} \meta{test token}
+% \cs{tl_if_head_eq_catcode:nNTF} \Arg{token list} \meta{test token}
% ~~\Arg{true code} \Arg{false code}
% \end{syntax}
% Tests if the first \meta{token} in the \meta{token list} has the same
@@ -820,8 +863,8 @@
% \begin{function}[EXP,pTF]
% {\tl_if_head_eq_charcode:nN, \tl_if_head_eq_charcode:fN}
% \begin{syntax}
-% \cs{tl_if_head_eq_charcode_p:n} \Arg{token list} \meta{test token}
-% \cs{tl_if_head_eq_charcode:nTF} \Arg{token list} \meta{test token}
+% \cs{tl_if_head_eq_charcode_p:nN} \Arg{token list} \meta{test token}
+% \cs{tl_if_head_eq_charcode:nNTF} \Arg{token list} \meta{test token}
% ~~\Arg{true code} \Arg{false code}
% \end{syntax}
% Tests if the first \meta{token} in the \meta{token list} has the same
@@ -835,8 +878,8 @@
%
% \begin{function}[EXP,pTF]{\tl_if_head_eq_meaning:nN}
% \begin{syntax}
-% \cs{tl_if_head_eq_meaning_p:n} \Arg{token list} \meta{test token}
-% \cs{tl_if_head_eq_meaning:nTF} \Arg{token list} \meta{test token}
+% \cs{tl_if_head_eq_meaning_p:nN} \Arg{token list} \meta{test token}
+% \cs{tl_if_head_eq_meaning:nNTF} \Arg{token list} \meta{test token}
% ~~\Arg{true code} \Arg{false code}
% \end{syntax}
% Tests if the first \meta{token} in the \meta{token list} has the same
@@ -976,7 +1019,7 @@
% ~~\Arg{true code} \Arg{false code}
% \end{syntax}
% Tests if the token list consists of exactly one token, i.e.,
-% is either a single space character or a single ``normal'' token.
+% is either a single space character or a single \enquote{normal} token.
% Token groups are not single tokens. The branching
% versions leaves either \meta{true code} or \meta{false code}
% in the input stream, as appropriate to the truth of the test and
@@ -1922,12 +1965,16 @@
% \begin{macro}{\tl_head:w}
% \begin{macro}{\tl_tail:n, \tl_tail:V, \tl_tail:v, \tl_tail:f}
% \begin{macro}{\tl_tail:w}
-% These functions pick up either the head or the tail of a list.
+% These functions pick up either the head or the tail of a list. The
+% \texttt{n}-type implementation needs a test in order to avoid run-away
+% arguments occurring with blank input.
% \begin{macrocode}
-\cs_new:Npn \tl_head:n #1 { \tl_head:w #1 \q_stop }
-\cs_new:Npn \tl_tail:n #1 { \tl_tail:w #1 \q_stop }
\cs_new:Npn \tl_head:w #1#2 \q_stop {#1}
\cs_new:Npn \tl_tail:w #1#2 \q_stop {#2}
+\cs_new:Npn \tl_head:n #1
+ { \tl_if_blank:nF {#1} { \tl_head:w #1 \q_stop } }
+\cs_new:Npn \tl_tail:n #1
+ { \tl_if_blank:nF {#1} { \tl_tail:w #1 \q_stop } }
\cs_generate_variant:Nn \tl_head:n { V , v , f }
\cs_generate_variant:Nn \tl_tail:n { V , v , f }
% \end{macrocode}
@@ -1936,54 +1983,135 @@
% \end{macro}
% \end{macro}
%
+% \begin{macro}{\str_head:n}
+% \begin{macro}[aux]{\str_head_aux:w}
+% After \cs{tl_to_str:n}, we have a list of character tokens,
+% all with category code 12, except the space, which has category
+% code 10. Directly using \cs{tl_head:w} would thus lose leading spaces.
+% Instead, we take an argument delimited by an explicit space, and
+% then only use \cs{tl_head:w}. If the string started with a
+% space, then the argument of \cs{str_head_aux:w} is empty, and
+% the function correctly returns a space character. Otherwise,
+% it returns the first token of |#1|, which is the first token
+% of the string. If the string is empty, we return
+% \cs{scan_stop:}.
+% \begin{macrocode}
+\cs_new:Npn \str_head:n #1
+ {
+ \exp_after:wN \str_head_aux:w
+ \tl_to_str:n {#1}
+ { \scan_stop: } ~ \q_stop
+ }
+\cs_new_nopar:Npn \str_head_aux:w #1 ~ %
+ { \tl_head:w #1 { ~ } }
+% \end{macrocode}
+% \end{macro}
+% \end{macro}
+%
% \begin{macro}[pTF]{\tl_if_head_eq_meaning:nN}
% \begin{macro}[pTF]{\tl_if_head_eq_charcode:nN}
% \begin{macro}[pTF]{\tl_if_head_eq_charcode:fN}
% \begin{macro}[pTF]{\tl_if_head_eq_catcode:nN}
-% When we want to check if the first token of a list equals something
-% specific it is usually either to see if it is a control sequence or
-% a character. Hence we make two different functions as the internal
-% test is different.
-% \cs{tl_if_head_meaning_eq:nNTF} uses \cs{if_meaning:w} and will
-% consider the tokens |b|$\sb{11}$ and |b|$\sb{12}$ different.
-% \cs{tl_if_head_char_eq:nNTF} on the other hand only compares
-% character codes so would regard |b|$\sb{11}$ and |b|$\sb{12}$ as
-% equal but would also regard two primitives as equal.
+% Accessing the first token of a token list is tricky in two cases:
+% when it has category code 1 (begin-group token), or when it is
+% an explicit space, with category code 10 and character code 32.
+%
+% Forgetting temporarily about this issue we would use the
+% following test in \cs{tl_if_head_eq_charcode:nN}. Here,
+% an empty |#1| argument yields \cs{q_nil}, otherwise the
+% first token of the token list.
+% \begin{verbatim}
+% \if_charcode:w
+% \exp_after:wN \exp_not:N \tl_head:w #1 \q_nil \q_stop
+% \exp_not:N #2
+% \end{verbatim}
+% The special cases are detected by comparing |#1| with
+% \cs{use:n}~|#1| (the extra |?| takes care of empty arguments).
+% In those cases, the first token is a character, and
+% since we only care about its character code, we can
+% use \cs{str_head:n} to access it (this works even if
+% it is a space character).
% \begin{macrocode}
-\prg_new_conditional:Npnn \tl_if_head_eq_meaning:nN #1#2 { p , T , F , TF }
+\prg_new_conditional:Npnn \tl_if_head_eq_charcode:nN #1#2 { p , T , F , TF }
{
- \exp_after:wN \if_meaning:w \tl_head:w #1 \q_stop #2
+ \if_charcode:w
+ \exp_not:N #2
+ \str_if_eq:onTF { \use:n #1 ? } { #1 ? }
+ { \exp_after:wN \exp_not:N \tl_head:w #1 \q_nil \q_stop }
+ { \str_head:n {#1} }
\prg_return_true:
\else:
\prg_return_false:
\fi:
}
+\cs_generate_variant:Nn \tl_if_head_eq_charcode_p:nN { f }
+\cs_generate_variant:Nn \tl_if_head_eq_charcode:nNTF { f }
+\cs_generate_variant:Nn \tl_if_head_eq_charcode:nNT { f }
+\cs_generate_variant:Nn \tl_if_head_eq_charcode:nNF { f }
% \end{macrocode}
-% For the charcode and catcode versions we insert |\exp_not:N| in
-% front of both tokens. If you need them to expand fully as \TeX{}
-% does itself with these you can use an |f| type expansion.
+% For \cs{tl_if_head_eq_catcode:nN}, again we detect special
+% cases with a \cs{str_if_eq:onTF} test. Then we need to test
+% if the first token is a begin-group token or an explicit
+% space token, and produce the relevant token, either
+% \cs{c_group_begin_token} or \cs{c_space_token}.
% \begin{macrocode}
-\prg_new_conditional:Npnn \tl_if_head_eq_charcode:nN #1#2 { p , T , F , TF }
+\prg_new_conditional:Npnn \tl_if_head_eq_catcode:nN #1 #2 { p , T , F , TF }
{
- \exp_after:wN \if:w
- \exp_after:wN \exp_not:N \tl_head:w #1 \q_stop \exp_not:N #2
+ \if_catcode:w
+ \exp_not:N #2
+ \str_if_eq:onTF { \use:n #1 ? } { #1 ? }
+ { \exp_after:wN \exp_not:N \tl_head:w #1 \q_nil \q_stop }
+ {
+ \tl_if_head_begin_group:nTF {#1}
+ { \c_group_begin_token }
+ { \c_space_token }
+ }
\prg_return_true:
\else:
\prg_return_false:
\fi:
- }
-\cs_generate_variant:Nn \tl_if_head_eq_charcode_p:nN { f }
-\cs_generate_variant:Nn \tl_if_head_eq_charcode:nNTF { f }
-\cs_generate_variant:Nn \tl_if_head_eq_charcode:nNT { f }
-\cs_generate_variant:Nn \tl_if_head_eq_charcode:nNF { f }
+ }
% \end{macrocode}
-% And now catcodes:
+% For \cs{tl_if_head_eq_meaning:nN}, again, detect special cases.
+% In the normal case, use \cs{tl_head:w}, with no \cs{exp_not:N}
+% this time, since \cs{if_meaning:w} causes no expansion.
+% In the special cases, we know that the first token is a character,
+% hence \cs{if_charcode:w} and \cs{if_catcode:w} together are enough.
+% We combine them in some order, hopefully faster than the reverse.
% \begin{macrocode}
-\prg_new_conditional:Npnn \tl_if_head_eq_catcode:nN #1#2 { p , T , F , TF }
+\prg_new_conditional:Npnn \tl_if_head_eq_meaning:nN #1#2 { p , T , F , TF }
{
- \exp_after:wN \if_catcode:w \exp_after:wN \exp_not:N
- \tl_head:w #1 \q_stop \exp_not:N #2
- \prg_return_true: \else: \prg_return_false: \fi:
+ \str_if_eq:onTF { \use:n #1 ? } { #1 ? }
+ { \tl_if_head_eq_meaning_aux_normal:nN }
+ { \tl_if_head_eq_meaning_aux_special:nN }
+ {#1} #2
+ }
+\cs_new:Npn \tl_if_head_eq_meaning_aux_normal:nN #1 #2
+ {
+ \exp_after:wN \if_meaning:w \tl_head:w #1 \q_nil \q_stop #2
+ \prg_return_true:
+ \else:
+ \prg_return_false:
+ \fi:
+ }
+\cs_new:Npn \tl_if_head_eq_meaning_aux_special:nN #1 #2
+ {
+ \if_charcode:w \str_head:n {#1} \exp_not:N #2
+ \exp_after:wN \use:n
+ \else:
+ \prg_return_false:
+ \exp_after:wN \use_none:n
+ \fi:
+ {
+ \if_catcode:w \exp_not:N #2
+ \tl_if_head_begin_group:nTF {#1}
+ { \c_group_begin_token }
+ { \c_space_token }
+ \prg_return_true:
+ \else:
+ \prg_return_false:
+ \fi:
+ }
}
% \end{macrocode}
% \end{macro}