diff options
Diffstat (limited to 'Master/texmf-dist/source/latex/l3kernel/l3expan.dtx')
-rw-r--r-- | Master/texmf-dist/source/latex/l3kernel/l3expan.dtx | 467 |
1 files changed, 332 insertions, 135 deletions
diff --git a/Master/texmf-dist/source/latex/l3kernel/l3expan.dtx b/Master/texmf-dist/source/latex/l3kernel/l3expan.dtx index 7d708c411ac..65105c61736 100644 --- a/Master/texmf-dist/source/latex/l3kernel/l3expan.dtx +++ b/Master/texmf-dist/source/latex/l3kernel/l3expan.dtx @@ -1,6 +1,6 @@ % \iffalse meta-comment % -%% File: l3expan.dtx Copyright (C) 1990-2014 The LaTeX3 project +%% File: l3expan.dtx Copyright (C) 1990-2015 The LaTeX3 project %% %% It may be distributed and/or modified under the conditions of the %% LaTeX Project Public License (LPPL), either version 1.3c of this @@ -37,7 +37,7 @@ \documentclass[full]{l3doc} %</driver> %<*driver|package> -\GetIdInfo$Id: l3expan.dtx 5472 2014-11-27 09:10:40Z joseph $ +\GetIdInfo$Id: l3expan.dtx 5897 2015-08-28 09:06:29Z joseph $ {L3 Argument expansion} %</driver|package> %<*driver> @@ -119,7 +119,7 @@ % \section{Methods for defining variants} % \label{sec:l3expan:variants-method} % -% \begin{function}[updated = 2013-07-09]{\cs_generate_variant:Nn} +% \begin{function}[updated = 2015-08-06]{\cs_generate_variant:Nn} % \begin{syntax} % \cs{cs_generate_variant:Nn} \meta{parent control sequence} \Arg{variant argument specifiers} % \end{syntax} @@ -137,13 +137,13 @@ % \cs_set:Npn \foo:Nn #1#2 { code here } % \cs_generate_variant:Nn \foo:Nn { c } % \end{verbatim} -% will create a new function \cs{foo:cn} which will expand its first +% will create a new function |\foo:cn| which will expand its first % argument into a control sequence name and pass the result to -% \cs{foo:Nn}. Similarly +% |\foo:Nn|. Similarly % \begin{verbatim} % \cs_generate_variant:Nn \foo:Nn { NV , cV } % \end{verbatim} -% would generate the functions \cs{foo:NV} and \cs{foo:cV} in the +% would generate the functions |\foo:NV| and |\foo:cV| in the % same way. The \cs{cs_generate_variant:Nn} function can only be % applied if the \meta{parent control sequence} is already defined. If % the \meta{parent control sequence} is protected then the new sequence @@ -172,7 +172,8 @@ % expansion. % \item % In general, unless in the last position, multi-token arguments -% |n|, |f|, and |o| will need special processing which is not fast. +% |n|, |f|, and |o| will need special processing when more than +% one argument is being expanded. This special processing is not fast. % Therefore it is best to use the optimized functions, namely % those that contain only |N|, |c|, |V|, and |v|, and, in the last % position, |o|, |f|, with possible trailing |N| or |n|, which are @@ -196,33 +197,37 @@ % specific expansion steps are needed, such as when using delimited % arguments, should the lower-level functions with |o| specifiers be employed. % -% The |f| type is so special that it deserves an example. Let's pretend -% we want to set the control sequence whose name is given by -% |b \l_tmpa_tl b| equal to the list of tokens |\aaa a|. Furthermore we -% want to store the execution of it in a -% \meta{tl~var}. In this example we assume |\l_tmpa_tl| contains -% the text string |lur|. The straightforward approach is +% The |f| type is so special that it deserves an example. It is +% typically used in contexts where only expandable commands are allowed. +% Then |x|-expansion cannot be used, and |f|-expansion provides an +% alternative that expands as much as can be done in such contexts. For +% instance, say that we want to evaluate the integer expression $3 + 4$ +% and pass the result $7$ as an argument to an expandable function +% |\example:n|. For this, one should define a variant using +% \cs{cs_generate_variant:Nn} |\example:n| |{| |f| |}|, then do % \begin{quote} -% |\tl_set:No \l_tmpb_tl { \tl_set:cn { b \l_tmpa_tl b } { \aaa a } }| +% |\example:f { \int_eval:n { 3 + 4 } }| % \end{quote} -% Unfortunately this only puts -% |\exp_args:Nc \tl_set:Nn {b \l_tmpa_tl b} { \aaa a }| into -% |\l_tmpb_tl| and not |\tl_set:Nn \blurb { \aaa a }| as we probably -% wanted. Using \cs{tl_set:Nx} is not an option as that will die -% horribly. Instead we can do a +% Note that |x|-expansion would also expand \cs{int_eval:n} fully to its +% result~$7$, but the variant |\example:x| cannot be expandable. Note +% also that |o|-expansion would not expand \cs{int_eval:n} fully to its +% result since that function requires several expansions. Besides the +% fact that |x|-expansion is protected rather than expandable, another +% difference between |f|-expansion and |x|-expansion is that +% |f|-expansion expands tokens from the beginning and stops as soon as a +% non-expandable token is encountered, while |x|-expansion continues +% expanding further tokens. Thus, for instance % \begin{quote} -% |\tl_set:Nf \l_tmpb_tl { \tl_set:cn { b \l_tmpa_tl b } { \aaa a } }| -% \end{quote} -% which puts the desired result in |\l_tmpb_tl|. It requires -% \cs{tl_set:Nf} to be defined as -% \begin{quote} -% |\cs_set_nopar:Npn \tl_set:Nf { \exp_args:NNf \tl_set:Nn }| +% |\example:f { \int_eval:n { 1 + 2 } , \int_eval:n { 3 + 4 } }| % \end{quote} +% will result in the call |\example:n { 3 , \int_eval:n { 3 + 4 } }| +% while using |\example:x| instead results in |\example:n { 3 , 7 }| +% at the cost of being protected. % If you use this type of expansion in conditional processing then % you should stick to using |TF| type functions only as it does not % try to finish any |\if... \fi:| itself! % -% If is important to not that both \texttt{f}- and \texttt{o}-type +% If is important to note that both \texttt{f}- and \texttt{o}-type % expansion are concerned with the expansion of tokens from left to % right in their arguments. In particular, \texttt{o}-type expansion % applies to the first \emph{token} in the argument it receives: it @@ -417,7 +422,7 @@ % \exp_args:Nooo, % } % \begin{syntax} -% \cs{exp_args:NNNo} \meta{token_1} \meta{token_2} \meta{token_3} \Arg{tokens} +% \cs{exp_args:NNoo} \meta{token_1} \meta{token_2} \Arg{token_3} \Arg{tokens} % \end{syntax} % These functions absorb four arguments and expand the second, third % and fourth as detailed by their argument specifier. The first @@ -426,8 +431,9 @@ % These functions need special (slower) processing. % \end{function} % -% \begin{function} +% \begin{function}[added = 2015-08-12] % { +% \exp_args:NNNx, % \exp_args:NNnx, % \exp_args:NNox, % \exp_args:Nnnx, @@ -477,7 +483,7 @@ % As an optimization, the last argument is unbraced by some % of those functions before expansion. This can cause problems % if the argument is empty: for instance, -% \cs{exp_last_unbraced:Nf} \cs{mypkg_foo:w} |{ }| \cs{q_stop} +% \cs{exp_last_unbraced:Nf} |\foo_bar:w| |{ }| \cs{q_stop} % leads to an infinite loop, as the quark is \texttt{f}-expanded. % \end{texnote} % \end{function} @@ -522,6 +528,7 @@ % \end{texnote} % \end{function} % +% % \section{Preventing expansion} % % Despite the fact that the following functions are all about preventing @@ -602,10 +609,10 @@ % % \begin{function}[updated = 2011-06-03, EXP]{\exp_stop_f:} % \begin{syntax} -% \cs{function:f} \meta{tokens} \cs{exp_stop_f:} \meta{more tokens} +% |\foo_bar:f| \{ \meta{tokens} \cs{exp_stop_f:} \meta{more tokens} \} % \end{syntax} % This function terminates an \texttt{f}-type expansion. Thus if -% a function |\function:f| starts an \texttt{f}-type expansion +% a function |\foo_bar:f| starts an \texttt{f}-type expansion % and all of \meta{tokens} are expandable \cs{exp_stop_f:} will % terminate the expansion of tokens even if \meta{more tokens} % are also expandable. The function itself is an implicit space @@ -613,6 +620,131 @@ % form, but when typeset it produces the underlying space (\verb*| |). % \end{function} % +% +% \section{Controlled expansion} +% +% The \pkg{expl3} language makes all efforts to hide the complexity of +% \TeX{} expansion from the programmer by providing concepts that +% evaluate/expand arguments of functions prior to calling the ``base'' +% functions. Thus, instead of using many \tn{expandafter} calls and +% other trickery it is usually a matter of choosing the right variant +% of a function to achieve a desired result. +% +% Of course, deep down \TeX{} is using expansion as always and there +% are cases where a programmer needs to control that expansion +% directly; typical situations are basic data manipulation tools. This +% section documents the functions for that level. You will find these +% commands used throughout the kernel code, but we hope that outside +% the kernel there will be little need to resort to them. Instead the +% argument manipulation methods document above should usually be sufficient. +% +% While \cs{exp_after:wN} expands one token (out of order) it is +% sometimes necessary to expand several tokens in one go. The next set +% of commands provide this functionality. Be aware that it is +% absolutely required that the programmer has full control over the +% tokens to be expanded, i.e., it is not possible to use these +% functions to expand unknown input as part of +% \meta{expandable-tokens} as that will break badly if unexpandable +% tokens are encountered in that place! +% +% \begin{function}[added=2015-08-23,EXP] +% { +% \exp:w , +% \exp_end: +% } +% \begin{syntax} +% \cs{exp:w} \meta{expandable-tokens} \cs{exp_end:} \\ +% \end{syntax} +% Expands \meta{expandable-tokens} until reaching \cs{exp_end:} at +% which point expansion stops. +% The full expansion of \meta{expandable-tokens} has to be empty. +% If any token in \meta{expandable-tokens} or any token generated by +% expanding the tokens therein is not expandable the expansion will end +% prematurely and as a result \cs{exp_end:} will be misinterpreted +% later on.\footnotemark +% +% In typical use cases the \cs{exp_end:} will be hidden somewhere +% in the replacement text of \meta{expandable-tokens} rather than +% being on the same expansion level than \cs{exp:w}, e.g., you may +% see code such as +%\begin{verbatim} +% \exp:w \@@_case:NnTF #1 {#2} { } { } +%\end{verbatim} +% where somewhere during the expansion of |\@@_case:NnTF| the +% \cs{exp_end:} gets generated. +% \end{function} +% \footnotetext{Due to the implementation you might get the character +% in position 0 in the current font (typically ``\texttt`'') +% in the output without any error message!} +% +% \begin{function}[added=2015-08-23,EXP] +% { +% \exp:w , +% \exp_end_continue_f:w +% } +% \begin{syntax} +% \cs{exp:w} \meta{expandable-tokens} \cs{exp_end_continue_f:w} \meta{further-tokens} +% \end{syntax} +% Expands \meta{expandable-tokens} until reaching \cs{exp_end_continue_f:w} at +% which point expansion continues as an f-type expansion expanding +% \meta{further-tokens} until an unexpandable token is encountered (or +% the f-type expansion is explicitly terminated by +% \cs{exp_stop_f:}). As with all f-type expansions a space ending +% the expansion will get removed. +% +% The full expansion of \meta{expandable-tokens} has to be empty. +% If any token in \meta{expandable-tokens} or any token generated by +% expanding the tokens therein is not expandable the expansion will end +% prematurely and as a result \cs{exp_end_continue_f:w} will be misinterpreted +% later on.\footnotemark +% +% +% In typical use cases \meta{expandable-tokens} contains no tokens at all, +% e.g., you will see code such as +%\begin{verbatim} +% \exp_after:wN { \exp:w \exp_end_continue_f:w #2 } +%\end{verbatim} +% where the \cs{exp_after:wN} triggers an f-expansion of the tokens +% in |#2|. For technical reasons this has to happen using two tokens +% (if they would be hidden inside another command \cs{exp_after:wN} +% would only expand the command but not trigger any additional +% f-expansion). +% +% You might wonder why there are two different approaches available, +% after all the effect of +% \begin{quote} +% \cs{exp:w} \meta{expandable-tokens} \cs{exp_end:} +% \end{quote} +% can be alternatively achieved through an f-type expansion by using +% \cs{exp_stop_f:}, i.e. +% \begin{quote} +% \cs{exp:w} \cs{exp_end_continue_f:w} \meta{expandable-tokens} \cs{exp_stop_f:} +% \end{quote} +% The reason is simply that the first approach is slightly faster +% (one less token to parse and less expansion internally) +% so in places where such performance really matters and where we +% want to explicitly stop the expansion at a defined point the first +% form is preferable. +% \end{function} +% \footnotetext{In this particular case you may get a character into +% the output as well as an error message.} +% +% \begin{function}[added=2015-08-23,EXP] +% { +% \exp:w , +% \exp_end_continue_f:nw +% } +% \begin{syntax} +% \cs{exp:w} \meta{expandable-tokens} \cs{exp_end_continue_f:nw} \meta{further-tokens} +% \end{syntax} +% The difference to \cs{exp_end_continue_f:w} is that we first we pick +% up an argument which is then returned to the input stream. If +% \meta{further-tokens} starts with a brace group then the braces +% are removed. If on the other hand it starts with space tokens then +% these space tokens are removed while searching for the +% argument. Thus such space tokens will not terminate the f-type expansion. +% \end{function} +% % \section{Internal functions and variables} % % \begin{variable}{\l__exp_internal_tl} @@ -754,18 +886,17 @@ % \begin{macro}[int, EXP]{\::f} % \begin{macro}{\exp_stop_f:} % This function is used to expand a token list until the first -% unexpandable token is found. The underlying \tn{romannumeral} |-`0| -% expands everything in its way to find something terminating the -% number and thereby expands the function in front of it. This +% unexpandable token is found. This is achieved through \cs{exp:w} +% \cs{exp_end_continue_f:w} that +% expands everything in its way following it. This % scanning procedure is terminated once the expansion hits % something non-expandable or a space. We introduce \cs{exp_stop_f:} -% to mark such an end of expansion marker; in case the scanner hits -% a number, this number also terminates the scanning and is left -% untouched. In the example shown earlier the scanning was stopped +% to mark such an end of expansion marker. +% In the example shown earlier the scanning was stopped % once \TeX{} had fully expanded |\cs_set_eq:Nc \aaa { b \l_tmpa_tl b }| % into |\cs_set_eq:NN \aaa = \blurb| which then turned out to contain % the non-expandable token \cs{cs_set_eq:NN}. Since the expansion of -% \tn{romannumeral} |-`0| is \meta{null}, we wind up with a fully +% \cs{exp:w} \cs{exp_end_continue_f:w} is \meta{null}, we wind up with a fully % expanded list, only \TeX{} has not tried to execute any of the % non-expandable tokens. This is what differentiates this function % from the |x| argument type. @@ -773,7 +904,7 @@ \cs_new:Npn \::f #1 \::: #2#3 { \exp_after:wN \@@_arg_next:nnn - \exp_after:wN { \tex_romannumeral:D -`0 #3 } + \exp_after:wN { \exp:w \exp_end_continue_f:w #3 } {#1} {#2} } \use:nn { \cs_new_eq:NN \exp_stop_f: } { ~ } @@ -798,20 +929,20 @@ % |tl|, |clist|, |int|, |skip|, |dim| and |muskip|. The |V| version % expects a single token whereas |v| like |c| creates a csname from % its argument given in braces and then evaluates it as if it was a -% |V|. The primitive \tn{romannumeral} sets off an expansion +% |V|. The \cs{exp:w} sets off an expansion % similar to an |f| type expansion, which we will terminate using -% \cs{c_zero}. The argument is returned in braces. +% \cs{exp_end:}. The argument is returned in braces. % \begin{macrocode} \cs_new:Npn \::V #1 \::: #2#3 { \exp_after:wN \@@_arg_next:nnn - \exp_after:wN { \tex_romannumeral:D \@@_eval_register:N #3 } + \exp_after:wN { \exp:w \@@_eval_register:N #3 } {#1} {#2} } \cs_new:Npn \::v # 1\::: #2#3 { \exp_after:wN \@@_arg_next:nnn - \exp_after:wN { \tex_romannumeral:D \@@_eval_register:c {#3} } + \exp_after:wN { \exp:w \@@_eval_register:c {#3} } {#1} {#2} } % \end{macrocode} @@ -852,19 +983,20 @@ \fi: % \end{macrocode} % The next bit requires some explanation. The function must be -% initiated by the primitive \tn{romannumeral} and we want to -% terminate this expansion chain by inserting the \cs{c_zero} integer -% constant. However, we have to expand the register |#1| before we do +% initiated by \cs{exp:w} and we want to +% terminate this expansion chain by inserting the \cs{exp_end:} +% token. +% However, we have to expand the register |#1| before we do % that. If it is a \TeX{} register, we need to execute the sequence -% |\exp_after:wN \c_zero \tex_the:D #1| and if it is a macro we -% need to execute |\exp_after:wN \c_zero #1|. We therefore issue +% |\exp_after:wN \exp_end: \tex_the:D #1| and if it is a macro we +% need to execute |\exp_after:wN \exp_end: #1|. We therefore issue % the longer of the two sequences and if the register is a macro, we % remove the \cs{tex_the:D}. % \begin{macrocode} \else: \exp_after:wN \use_i_ii:nnn \fi: - \exp_after:wN \c_zero \tex_the:D #1 + \exp_after:wN \exp_end: \tex_the:D #1 } \cs_new:Npn \@@_eval_register:c #1 { \exp_after:wN \@@_eval_register:N \cs:w #1 \cs_end: } @@ -883,7 +1015,7 @@ \fi: \fi: \__msg_kernel_expandable_error:nnn { kernel } { bad-variable } {#2} - \c_zero + \exp_end: } % \end{macrocode} % \end{macro} @@ -936,25 +1068,25 @@ % \begin{macro}[EXP]{\exp_args:Nf, \exp_args:NV, \exp_args:Nv} % \begin{macrocode} \cs_new:Npn \exp_args:Nf #1#2 - { \exp_after:wN #1 \exp_after:wN { \tex_romannumeral:D -`0 #2 } } + { \exp_after:wN #1 \exp_after:wN { \exp:w \exp_end_continue_f:w #2 } } \cs_new:Npn \exp_args:Nv #1#2 { \exp_after:wN #1 \exp_after:wN - { \tex_romannumeral:D \@@_eval_register:c {#2} } + { \exp:w \@@_eval_register:c {#2} } } \cs_new:Npn \exp_args:NV #1#2 { \exp_after:wN #1 \exp_after:wN - { \tex_romannumeral:D \@@_eval_register:N #2 } + { \exp:w \@@_eval_register:N #2 } } % \end{macrocode} % \end{macro} % % \begin{macro}[EXP] % { -% \exp_args:NNV,\exp_args:NNv,\exp_args:NNf, +% \exp_args:NNV, \exp_args:NNv, \exp_args:NNf, % \exp_args:NVV, -% \exp_args:Ncf,\exp_args:Nco +% \exp_args:Ncf, \exp_args:Nco % } % Some more hand-tuned function with three arguments. % If we forced that an |o| argument always has braces, @@ -965,19 +1097,19 @@ { \exp_after:wN #1 \exp_after:wN #2 - \exp_after:wN { \tex_romannumeral:D -`0 #3 } + \exp_after:wN { \exp:w \exp_end_continue_f:w #3 } } \cs_new:Npn \exp_args:NNv #1#2#3 { \exp_after:wN #1 \exp_after:wN #2 - \exp_after:wN { \tex_romannumeral:D \@@_eval_register:c {#3} } + \exp_after:wN { \exp:w \@@_eval_register:c {#3} } } \cs_new:Npn \exp_args:NNV #1#2#3 { \exp_after:wN #1 \exp_after:wN #2 - \exp_after:wN { \tex_romannumeral:D \@@_eval_register:N #3 } + \exp_after:wN { \exp:w \@@_eval_register:N #3 } } \cs_new:Npn \exp_args:Nco #1#2#3 { @@ -989,14 +1121,14 @@ { \exp_after:wN #1 \cs:w #2 \exp_after:wN \cs_end: - \exp_after:wN { \tex_romannumeral:D -`0 #3 } + \exp_after:wN { \exp:w \exp_end_continue_f:w #3 } } \cs_new:Npn \exp_args:NVV #1#2#3 { \exp_after:wN #1 - \exp_after:wN { \tex_romannumeral:D \exp_after:wN + \exp_after:wN { \exp:w \exp_after:wN \@@_eval_register:N \exp_after:wN #2 \exp_after:wN } - \exp_after:wN { \tex_romannumeral:D \@@_eval_register:N #3 } + \exp_after:wN { \exp:w \@@_eval_register:N #3 } } % \end{macrocode} % \end{macro} @@ -1013,7 +1145,7 @@ \exp_after:wN #1 \exp_after:wN #2 \exp_after:wN #3 - \exp_after:wN { \tex_romannumeral:D \@@_eval_register:N #4 } + \exp_after:wN { \exp:w \@@_eval_register:N #4 } } \cs_new:Npn \exp_args:NcNc #1#2#3#4 { @@ -1054,14 +1186,14 @@ % % \begin{macro}[EXP] % { -% \exp_args:Nnc,\exp_args:Nfo,\exp_args:Nff,\exp_args:Nnf, -% \exp_args:Nno,\exp_args:NnV,\exp_args:Noo,\exp_args:Nof, +% \exp_args:Nnc, \exp_args:Nfo, \exp_args:Nff, \exp_args:Nnf, +% \exp_args:Nno, \exp_args:NnV, \exp_args:Noo, \exp_args:Nof, % \exp_args:Noc % } % \begin{macro} % { -% \exp_args:NNx,\exp_args:Ncx,\exp_args:Nnx, -% \exp_args:Nox,\exp_args:Nxo,\exp_args:Nxx, +% \exp_args:NNx, \exp_args:Ncx, \exp_args:Nnx, +% \exp_args:Nox, \exp_args:Nxo, \exp_args:Nxx, % } % Here are the actual function definitions, using the helper functions % above. @@ -1087,13 +1219,14 @@ % % \begin{macro}[EXP] % { -% \exp_args:NNno,\exp_args:NNoo, -% \exp_args:Nnnc,\exp_args:Nnno,\exp_args:Nooo, +% \exp_args:NNno, \exp_args:NNoo, +% \exp_args:Nnnc, \exp_args:Nnno, \exp_args:Nooo, % } % \begin{macro} % { -% \exp_args:NNnx,\exp_args:NNox,\exp_args:Nnnx,\exp_args:Nnox, -% \exp_args:Nccx,\exp_args:Ncnx,\exp_args:Noox, +% \exp_args:NNNx, +% \exp_args:NNnx, \exp_args:NNox, \exp_args:Nnnx, \exp_args:Nnox, +% \exp_args:Nccx, \exp_args:Ncnx, \exp_args:Noox, % } % \begin{macrocode} \cs_new_nopar:Npn \exp_args:NNno { \::N \::n \::o \::: } @@ -1101,6 +1234,7 @@ \cs_new_nopar:Npn \exp_args:Nnnc { \::n \::n \::c \::: } \cs_new_nopar:Npn \exp_args:Nnno { \::n \::n \::o \::: } \cs_new_nopar:Npn \exp_args:Nooo { \::o \::o \::o \::: } +\cs_new_protected_nopar:Npn \exp_args:NNNx { \::N \::N \::x \::: } \cs_new_protected_nopar:Npn \exp_args:NNnx { \::N \::n \::x \::: } \cs_new_protected_nopar:Npn \exp_args:NNox { \::N \::o \::x \::: } \cs_new_protected_nopar:Npn \exp_args:Nnnx { \::n \::n \::x \::: } @@ -1127,19 +1261,19 @@ \cs_new:Npn \::f_unbraced \::: #1#2 { \exp_after:wN \@@_arg_last_unbraced:nn - \exp_after:wN { \tex_romannumeral:D -`0 #2 } {#1} + \exp_after:wN { \exp:w \exp_end_continue_f:w #2 } {#1} } \cs_new:Npn \::o_unbraced \::: #1#2 { \exp_after:wN \@@_arg_last_unbraced:nn \exp_after:wN {#2} {#1} } \cs_new:Npn \::V_unbraced \::: #1#2 { \exp_after:wN \@@_arg_last_unbraced:nn - \exp_after:wN { \tex_romannumeral:D \@@_eval_register:N #2 } {#1} + \exp_after:wN { \exp:w \@@_eval_register:N #2 } {#1} } \cs_new:Npn \::v_unbraced \::: #1#2 { \exp_after:wN \@@_arg_last_unbraced:nn - \exp_after:wN { \tex_romannumeral:D \@@_eval_register:c {#2} } {#1} + \exp_after:wN { \exp:w \@@_eval_register:c {#2} } {#1} } \cs_new_protected:Npn \::x_unbraced \::: #1#2 { @@ -1173,25 +1307,25 @@ % general system is in place. % \begin{macrocode} \cs_new:Npn \exp_last_unbraced:NV #1#2 - { \exp_after:wN #1 \tex_romannumeral:D \@@_eval_register:N #2 } + { \exp_after:wN #1 \exp:w \@@_eval_register:N #2 } \cs_new:Npn \exp_last_unbraced:Nv #1#2 - { \exp_after:wN #1 \tex_romannumeral:D \@@_eval_register:c {#2} } + { \exp_after:wN #1 \exp:w \@@_eval_register:c {#2} } \cs_new:Npn \exp_last_unbraced:No #1#2 { \exp_after:wN #1 #2 } \cs_new:Npn \exp_last_unbraced:Nf #1#2 - { \exp_after:wN #1 \tex_romannumeral:D -`0 #2 } + { \exp_after:wN #1 \exp:w \exp_end_continue_f:w #2 } \cs_new:Npn \exp_last_unbraced:Nco #1#2#3 { \exp_after:wN #1 \cs:w #2 \exp_after:wN \cs_end: #3 } \cs_new:Npn \exp_last_unbraced:NcV #1#2#3 { \exp_after:wN #1 \cs:w #2 \exp_after:wN \cs_end: - \tex_romannumeral:D \@@_eval_register:N #3 + \exp:w \@@_eval_register:N #3 } \cs_new:Npn \exp_last_unbraced:NNV #1#2#3 { \exp_after:wN #1 \exp_after:wN #2 - \tex_romannumeral:D \@@_eval_register:N #3 + \exp:w \@@_eval_register:N #3 } \cs_new:Npn \exp_last_unbraced:NNo #1#2#3 { \exp_after:wN #1 \exp_after:wN #2 #3 } @@ -1200,7 +1334,7 @@ \exp_after:wN #1 \exp_after:wN #2 \exp_after:wN #3 - \tex_romannumeral:D \@@_eval_register:N #4 + \exp:w \@@_eval_register:N #4 } \cs_new:Npn \exp_last_unbraced:NNNo #1#2#3#4 { \exp_after:wN #1 \exp_after:wN #2 \exp_after:wN #3 #4 } @@ -1255,16 +1389,16 @@ \cs_new:Npn \exp_not:o #1 { \etex_unexpanded:D \exp_after:wN {#1} } \cs_new:Npn \exp_not:c #1 { \exp_after:wN \exp_not:N \cs:w #1 \cs_end: } \cs_new:Npn \exp_not:f #1 - { \etex_unexpanded:D \exp_after:wN { \tex_romannumeral:D -`0 #1 } } + { \etex_unexpanded:D \exp_after:wN { \exp:w \exp_end_continue_f:w #1 } } \cs_new:Npn \exp_not:V #1 { \etex_unexpanded:D \exp_after:wN - { \tex_romannumeral:D \@@_eval_register:N #1 } + { \exp:w \@@_eval_register:N #1 } } \cs_new:Npn \exp_not:v #1 { \etex_unexpanded:D \exp_after:wN - { \tex_romannumeral:D \@@_eval_register:c {#1} } + { \exp:w \@@_eval_register:c {#1} } } % \end{macrocode} % \end{macro} @@ -1273,6 +1407,71 @@ % \end{macro} % \end{macro} % +% \subsection{Controlled expansion} +% +% \begin{macro}{\exp:w} +% \begin{macro}{\exp_end:} +% \begin{macro}{\exp_end_continue_f:w} +% \begin{macro}{\exp_end_continue_f:nw} +% +% To trigger a sequence of ``arbitrary'' many expansions we need a +% method to invoke \TeX's expansion mechanism in such a way that a) +% we are able to stop it in a controlled manner and b) that the +% result of what triggered the expansion in the first place is +% null, i.e., that we do not get any unwanted side effects. There +% aren't that many possibilities in \TeX{}; in fact the one +% explained below might well be the only one (as normally the +% result of expansion is not null). +% +% The trick here is to make use of the fact that +% \cs{tex_romannumeral:D} expands the tokens following it when +% looking for a number and that its expansion is null if that +% number turns out to be zero or negative. So we use that to start +% the expansion sequence. +% \begin{macrocode} +%\cs_new_eq:NN \exp:w \tex_romannumeral:D +% \end{macrocode} +% So to stop the expansion sequence in a controlled way all we need +% to provide is \cs{c_zero} as part of expanded tokens. As this is +% an integer constant it will immediately stop +% \cs{tex_romannumerl:D}'s search for a number. +% \begin{macrocode} +%\cs_new_eq:NN \exp_end: \c_zero +% \end{macrocode} +% (Note that according to our specification all tokens we expand +% initiated by \cs{exp:w} are supposed to be expandable (as well as +% their replacement text in the expansion) so we will not encounter +% a ``number'' that actually result in a roman numeral being +% generated. Or if we do then the programmer made a mistake.) +% +% If on the other hand we want to stop the initial expansion +% sequence but continue with an f-type expansion we provide the +% alphabetic constant |`^^@| that also represents |0| but this time +% \TeX's syntax for a \meta{number} will continue searching for an +% optional space (and it will continue expansion doing that) --- +% see \TeX{}book page~269 for details. +% \begin{macrocode} +\tex_catcode:D `\^^@=13 +\cs_new_protected:Npn \exp_end_continue_f:w {`^^@} +% \end{macrocode} +% If the above definition ever appears outside its proper context +% the active character |^^@| will be executed so we turn this into an +% error.\footnote{Need to get a real error message.} +% \begin{macrocode} +\cs_new:Npn ^^@{\expansionERROR} +% \end{macrocode} +% +% \begin{macrocode} +\cs_new:Npn \exp_end_continue_f:nw #1 { `^^@ #1 } +\tex_catcode:D `\^^@=15 +% \end{macrocode} +% \end{macro} +% \end{macro} +% \end{macro} +% \end{macro} +% +% +% % \subsection{Defining function variants} % % \begin{macrocode} @@ -1301,7 +1500,7 @@ \exp_after:wN #1 \exp_after:wN \@@_generate_variant:nnNN \exp_after:wN #1 - \etex_detokenize:D {#2} , \scan_stop: , \q_recursion_stop + \tl_to_str:n {#2} , \scan_stop: , \q_recursion_stop } % \end{macrocode} % \end{macro} @@ -1330,35 +1529,34 @@ % auxiliary, and |#3| is \cs{cs_new_protected_nopar:Npx}, otherwise it % is \cs{cs_new_nopar:Npx}. % \begin{macrocode} -\group_begin: - \tex_catcode:D `\M = 12 \scan_stop: - \tex_catcode:D `\A = 12 \scan_stop: - \tex_catcode:D `\P = 12 \scan_stop: - \tex_catcode:D `\R = 12 \scan_stop: -\tex_lowercase:D +\cs_new_protected:Npx \@@_generate_variant:N #1 { - \group_end: - \cs_new_protected:Npn \@@_generate_variant:N #1 - { - \exp_after:wN \if_meaning:w \exp_not:N #1 #1 - \cs_set_eq:NN \@@_tmp:w \cs_new_protected_nopar:Npx - \else: - \exp_after:wN \@@_generate_variant:ww - \token_to_meaning:N #1 MA \q_mark - \q_mark \cs_new_protected_nopar:Npx - PR - \q_mark \cs_new_nopar:Npx - \q_stop - \fi: - } - \cs_new_protected:Npn \@@_generate_variant:ww #1 MA #2 \q_mark - { \@@_generate_variant:wwNw #1 } - \cs_new_protected:Npn \@@_generate_variant:wwNw - #1 PR #2 \q_mark #3 #4 \q_stop - { - \cs_set_eq:NN \@@_tmp:w #3 - } + \exp_not:N \exp_after:wN \exp_not:N \if_meaning:w + \exp_not:N \exp_not:N #1 #1 + \cs_set_eq:NN \exp_not:N \@@_tmp:w \cs_new_protected_nopar:Npx + \exp_not:N \else: + \exp_not:N \exp_after:wN \exp_not:N \@@_generate_variant:ww + \exp_not:N \token_to_meaning:N #1 \tl_to_str:n { ma } + \exp_not:N \q_mark + \exp_not:N \q_mark \cs_new_protected_nopar:Npx + \tl_to_str:n { pr } + \exp_not:N \q_mark \cs_new_nopar:Npx + \exp_not:N \q_stop + \exp_not:N \fi: + } +\use:x + { + \cs_new_protected:Npn \exp_not:N \@@_generate_variant:ww + ##1 \tl_to_str:n { ma } ##2 \exp_not:N \q_mark } + { \@@_generate_variant:wwNw #1 } +\use:x + { + \cs_new_protected:Npn \exp_not:N \@@_generate_variant:wwNw + ##1 \tl_to_str:n { pr } ##2 \exp_not:N \q_mark + ##3 ##4 \exp_not:N \q_stop + } + { \cs_set_eq:NN \@@_tmp:w #3 } % \end{macrocode} % \end{macro} % \end{macro} @@ -1617,11 +1815,10 @@ \group_end: } { - \iow_log:x + \__chk_log:x { Variant~\token_to_str:N #4~% - already~defined;~ not~ changing~ it~on~line~% - \tex_the:D \tex_inputlineno:D + already~defined;~ not~ changing~ it~ \msg_line_context: } } } @@ -1638,32 +1835,32 @@ % protected, and the next variant to be defined using that internal % variant should be protected. % \begin{macrocode} -\group_begin: - \tex_catcode:D `\X = 12 \scan_stop: - \tex_lccode:D `\N = `\N \scan_stop: -\tex_lowercase:D +\cs_new_protected:Npx \@@_generate_internal_variant:n #1 { - \group_end: - \cs_new_protected:Npn \@@_generate_internal_variant:n #1 - { - \@@_generate_internal_variant:wwnNwnn - #1 \q_mark - { \cs_set_eq:NN \@@_tmp:w \cs_new_protected_nopar:Npx } - \cs_new_protected_nopar:cpx - X \q_mark - { } - \cs_new_nopar:cpx - \q_stop - { exp_args:N #1 } - { \@@_generate_internal_variant_loop:n #1 { : \use_i:nn } } - } - \cs_new_protected:Npn \@@_generate_internal_variant:wwnNwnn - #1 X #2 \q_mark #3 #4 #5 \q_stop #6 #7 + \exp_not:N \@@_generate_internal_variant:wwnNwnn + #1 \exp_not:N \q_mark + { \cs_set_eq:NN \exp_not:N \@@_tmp:w \cs_new_protected_nopar:Npx } + \cs_new_protected_nopar:cpx + \token_to_str:N x \exp_not:N \q_mark + { } + \cs_new_nopar:cpx + \exp_not:N \q_stop + { exp_args:N #1 } { - #3 - \cs_if_free:cT {#6} { #4 {#6} {#7} } + \exp_not:N \@@_generate_internal_variant_loop:n #1 + { : \exp_not:N \use_i:nn } } } +\use:x + { + \cs_new_protected:Npn \exp_not:N \@@_generate_internal_variant:wwnNwnn + ##1 \token_to_str:N x ##2 \exp_not:N \q_mark + ##3 ##4 ##5 \exp_not:N \q_stop ##6 ##7 + } + { + #3 + \cs_if_free:cT {#6} { #4 {#6} {#7} } + } % \end{macrocode} % This command grabs char by char outputting |\::#1| (not expanded % further). We avoid tests by putting a trailing |: \use_i:nn|, which |