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