From c9172879c19139ba8d262e615a535073caea2e54 Mon Sep 17 00:00:00 2001 From: Karl Berry Date: Fri, 12 Aug 2011 23:14:34 +0000 Subject: l3kernel (11aug11) git-svn-id: svn://tug.org/texlive/trunk@23524 c570f23f-e606-0410-a88d-b1316a301751 --- Master/texmf-dist/source/latex/l3kernel/l3tl.dtx | 234 ++++++++++++++++++----- 1 file changed, 181 insertions(+), 53 deletions(-) (limited to 'Master/texmf-dist/source/latex/l3kernel/l3tl.dtx') 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> @@ -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} -- cgit v1.2.3