diff options
Diffstat (limited to 'Master/texmf-dist/source/latex/l3kernel/l3expan.dtx')
-rw-r--r-- | Master/texmf-dist/source/latex/l3kernel/l3expan.dtx | 804 |
1 files changed, 455 insertions, 349 deletions
diff --git a/Master/texmf-dist/source/latex/l3kernel/l3expan.dtx b/Master/texmf-dist/source/latex/l3kernel/l3expan.dtx index 249309ab8cf..5479105b596 100644 --- a/Master/texmf-dist/source/latex/l3kernel/l3expan.dtx +++ b/Master/texmf-dist/source/latex/l3kernel/l3expan.dtx @@ -7,7 +7,7 @@ % license or (at your option) any later version. The latest version % of this license is in the file % -% http://www.latex-project.org/lppl.txt +% https://www.latex-project.org/lppl.txt % % This file is part of the "l3kernel bundle" (The Work in LPPL) % and all files in that bundle must be distributed together. @@ -21,7 +21,7 @@ % for those people who are interested. % %<*driver> -\documentclass[full]{l3doc} +\documentclass[full,kernel]{l3doc} \begin{document} \DocInput{\jobname.dtx} \end{document} @@ -41,7 +41,7 @@ % }^^A % } % -% \date{Released 2017/11/14} +% \date{Released 2017/12/05} % % \maketitle % @@ -74,7 +74,7 @@ % \begin{verbatim} % \exp_args:NNo \seq_gpush:Nn % \g_file_name_stack -% \l_tmpa_tl +% { \l_tmpa_tl } % \end{verbatim} % In other words, the first argument to \cs{exp_args:NNo} is the base % function and the other arguments are preprocessed and then passed to @@ -90,7 +90,7 @@ % \begin{quote} % |\cs_new:Npn \seq_gpush:No { \exp_args:NNo \seq_gpush:Nn }| % \end{quote} -% Providing variants in this way in style files is uncritical as the +% Providing variants in this way in style files is safe as the % \cs{cs_generate_variant:Nn} function will only create new definitions if % there is not already one available. Therefore adding % such definition to later releases of the kernel will not make such @@ -114,12 +114,13 @@ % once, |f|~expands fully the first token, |x|~expands fully all % tokens at the price of being non-expandable. % \item A few odd argument types remain: |T|~and |F|~for conditional -% processing, otherwise identical to~|n|, |p|~for the parameter text +% processing, otherwise identical to |n|-type arguments, +% |p|~for the parameter text % in definitions, |w|~for arguments with a specific syntax, and |D|~to % denote primitives that should not be used directly. % \end{itemize} % -% \begin{function}[updated = 2015-08-06]{\cs_generate_variant:Nn} +% \begin{function}[updated = 2017-11-28]{\cs_generate_variant:Nn} % \begin{syntax} % \cs{cs_generate_variant:Nn} \meta{parent control sequence} \Arg{variant argument specifiers} % \end{syntax} @@ -129,9 +130,9 @@ % \meta{base name} and \meta{original argument specifier}. The % comma-separated list of \meta{variant argument specifiers} is % then used to define variants of the -% \meta{original argument specifier} where these are not already +% \meta{original argument specifier} if these are not already % defined. For each \meta{variant} given, a function is created -% which expands its arguments as detailed and passes them +% that expands its arguments as detailed and passes them % to the \meta{parent control sequence}. So for example % \begin{verbatim} % \cs_set:Npn \foo:Nn #1#2 { code here } @@ -145,51 +146,71 @@ % \end{verbatim} % generates 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. Only |n|~and -% |N| arguments can be changed to other types. If the \meta{parent +% the \meta{parent control sequence} is already defined. If the \meta{parent % control sequence} is protected or if the \meta{variant} involves % |x|~arguments, then the \meta{variant control sequence} is also % protected. The \meta{variant} is created globally, as is any % \cs[no-index]{exp_args:N\meta{variant}} function needed to carry out the % expansion. % -% While \cs{cs_generate_variant:Nn} |\foo:N { o }| is currently -% allowed, one must know that it will break if the result of the -% expansion is more than one token or if |\foo:N| requires its -% argument not to be braced. +% Only |n|~and |N| arguments can be changed to other types. The only +% allowed changes are +% \begin{itemize} +% \item |c|~variant of an |N|~parent; +% \item |o|, |V|, |v|, |f|, or~|x| variant of an |n|~parent; +% \item |N|, |n|, |T|, |F|, or |p| argument unchanged. +% \end{itemize} +% This means the \meta{parent} of a \meta{variant} form is always +% unambiguous, even in cases where both an |n|-type parent and an +% |N|-type parent exist, such as for \cs{tl_count:n} and +% \cs{tl_count:N}. +% +% For backward compatibility it is currently possible to make |n|, +% |o|, |V|, |v|, |f|, or |x|-type variants of an |N|-type argument or +% |N| or |c|-type variants of an |n|-type argument. Both are +% deprecated. The first because passing more than one token to an +% |N|-type argument will typically break the parent function's code. +% The second because programmers who use that most often want to +% access the value of a variable given its name, hence should use a +% |V|-type or |v|-type variant instead of |c|-type. In those cases, +% using the lower-level \cs{exp_args:No} or \cs{exp_args:Nc} +% functions explicitly is preferred to defining confusing variants. % \end{function} % % \section{Introducing the variants} % -% The available internal functions for argument expansion come in two -% flavours, some of them are faster then others. Therefore -% (when speed is important) it is usually -% best to follow the following guidelines when defining new functions -% that are supposed to come with variant forms: +% It is usually best to follow the following guidelines when defining +% new functions that are supposed to come with variant forms. % \begin{itemize} % \item -% Arguments that might need expansion should come first in the list of -% arguments to make processing faster. -% \item -% Arguments that should consist of single tokens should come first. -% \item % Arguments that need full expansion (\emph{i.e.}, are denoted % with |x|) should be avoided if possible as they can not be % processed expandably, \emph{i.e.}, functions of this type % cannot work correctly in arguments that are themselves subject to |x| % expansion. +% \end{itemize} +% When speed is essential (for functions that do very little work and +% are used numerous times in a document) the following applies because +% internal functions for argument expansion come in two flavours, some +% faster than others. +% \begin{itemize} % \item -% In general, unless in the last position, multi-token arguments -% |n|, |f|, and |o| 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 -% not expanded. +% Arguments that might need expansion should come first in the list of +% arguments. +% \item +% Arguments that should consist of single tokens |N|, |c|, |V|, or +% |v| should come first among these. +% \item +% Arguments that appear after the first multi-token argument |n|, |f| +% or |o| require slightly slower special processing to be expanded. +% 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| or |T| +% or |F|, which are not expanded. % \end{itemize} % % The |V| type returns the value of a register, which can be one of -% |tl|, |int|, |skip|, |dim|, |toks|, or built-in \TeX{} +% |tl|, |clist|, |int|, |skip|, |dim|, |muskip|, or built-in \TeX{} % registers. The |v| type is the same except it first creates a % control sequence out of its argument before returning the % value. @@ -228,10 +249,10 @@ % 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! +% you should stick to using |TF| type functions only as the expansion +% does not finish any |\if... \fi:| itself! % -% If is important to note that both \texttt{f}- and \texttt{o}-type +% It 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 @@ -239,7 +260,7 @@ % \begin{verbatim} % \exp_after:wN <base function> \exp_after:wN { <argument> } % \end{verbatim} -% At the same time, \texttt{f}-type expansion stops at the emph{first} +% At the same time, \texttt{f}-type expansion stops at the \emph{first} % non-expandable token. This means for example that both % \begin{verbatim} % \tl_set:No \l_tmpa_tl { { \g_tmpb_tl } } @@ -256,17 +277,6 @@ % These functions are described in detail: expansion of multiple tokens follows % the same rules but is described in a shorter fashion. % -% \begin{function}[EXP]{\exp_args:No} -% \begin{syntax} -% \cs{exp_args:No} \meta{function} \Arg{tokens} ... -% \end{syntax} -% This function absorbs two arguments (the \meta{function} name and -% the \meta{tokens}). The \meta{tokens} are expanded once, and the result -% is inserted in braces into the input stream \emph{after} reinsertion -% of the \meta{function}. Thus the \meta{function} may take more than -% one argument: all others are left unchanged. -% \end{function} -% % \begin{function}[EXP]{\exp_args:Nc, \exp_args:cc} % \begin{syntax} % \cs{exp_args:Nc} \meta{function} \Arg{tokens} @@ -274,8 +284,8 @@ % This function absorbs two arguments (the \meta{function} name and % the \meta{tokens}). The \meta{tokens} are expanded until only characters % remain, and are then turned into a control sequence. (An internal error -% occurs if such a conversion is not possible). The result -% is inserted into the input stream \emph{after} reinsertion +% occurs if non-characters remain, as the conversion is not possible.) +% The result is inserted into the input stream \emph{after} reinsertion % of the \meta{function}. Thus the \meta{function} may take more than % one argument: all others are left unchanged. % @@ -283,6 +293,17 @@ % manner as described for the \meta{tokens}. % \end{function} % +% \begin{function}[EXP]{\exp_args:No} +% \begin{syntax} +% \cs{exp_args:No} \meta{function} \Arg{tokens} ... +% \end{syntax} +% This function absorbs two arguments (the \meta{function} name and +% the \meta{tokens}). The \meta{tokens} are expanded once, and the result +% is inserted in braces into the input stream \emph{after} reinsertion +% of the \meta{function}. Thus the \meta{function} may take more than +% one argument: all others are left unchanged. +% \end{function} +% % \begin{function}[EXP]{\exp_args:NV} % \begin{syntax} % \cs{exp_args:NV} \meta{function} \meta{variable} @@ -301,8 +322,8 @@ % This function absorbs two arguments (the \meta{function} name and % the \meta{tokens}). The \meta{tokens} are expanded until only characters % remain, and are then turned into a control sequence. (An internal error -% occurs if such a conversion is not possible). This control sequence -% should +% occurs if non-characters remain, as the conversion is not possible.) +% This control sequence should % be the name of a \meta{variable}. The content of the \meta{variable} are % recovered and placed inside braces into the input stream \emph{after} % reinsertion of the \meta{function}. Thus the \meta{function} may take more @@ -315,7 +336,8 @@ % \end{syntax} % This function absorbs two arguments (the \meta{function} name and % the \meta{tokens}). The \meta{tokens} are fully expanded until the -% first non-expandable token or space is found, and the result +% first non-expandable token is found (if that is a space it is +% removed), and the result % is inserted in braces into the input stream \emph{after} reinsertion % of the \meta{function}. Thus the \meta{function} may take more than % one argument: all others are left unchanged. @@ -326,8 +348,8 @@ % \cs{exp_args:Nx} \meta{function} \Arg{tokens} % \end{syntax} % This function absorbs two arguments (the \meta{function} name and -% the \meta{tokens}) and exhaustively expands the \meta{tokens} -% second. The result is inserted in braces into the input stream +% the \meta{tokens}) and exhaustively expands the \meta{tokens}. +% The result is inserted in braces into the input stream % \emph{after} reinsertion of the \meta{function}. % Thus the \meta{function} may take more % than one argument: all others are left unchanged. @@ -337,14 +359,16 @@ % % \begin{function}[EXP] % { -% \exp_args:NNo, % \exp_args:NNc, -% \exp_args:NNv, +% \exp_args:NNo, % \exp_args:NNV, +% \exp_args:NNv, % \exp_args:NNf, +% \exp_args:Ncc, % \exp_args:Nco, +% \exp_args:NcV, +% \exp_args:Ncv, % \exp_args:Ncf, -% \exp_args:Ncc, % \exp_args:NVV % } % \begin{syntax} @@ -358,15 +382,17 @@ % % \begin{function}[EXP, updated = 2012-01-14] % { +% \exp_args:Nnc, % \exp_args:Nno, % \exp_args:NnV, +% \exp_args:Nnv, % \exp_args:Nnf, +% \exp_args:Noc, % \exp_args:Noo, % \exp_args:Nof, -% \exp_args:Noc, -% \exp_args:Nff, +% \exp_args:NVo, % \exp_args:Nfo, -% \exp_args:Nnc +% \exp_args:Nff, % } % \begin{syntax} % \cs{exp_args:Noo} \meta{token} \Arg{tokens_1} \Arg{tokens_2} @@ -375,14 +401,14 @@ % third as detailed by their argument specifier. The first argument % of the function is then the next item on the input stream, followed % by the expansion of the second and third arguments. -% These functions need special (slower) processing. +% These functions need slower processing. % \end{function} % % \begin{function} % { % \exp_args:NNx, -% \exp_args:Nnx, % \exp_args:Ncx, +% \exp_args:Nnx, % \exp_args:Nox, % \exp_args:Nxo, % \exp_args:Nxx @@ -394,7 +420,7 @@ % third as detailed by their argument specifier. The first argument % of the function is then the next item on the input stream, followed % by the expansion of the second and third arguments. These functions -% are not expandable. +% are not expandable due to their |x|-type argument. % \end{function} % % \section{Manipulating three arguments} @@ -419,11 +445,22 @@ % % \begin{function}[EXP] % { -% \exp_args:NNoo, +% \exp_args:NNcf, % \exp_args:NNno, -% \exp_args:Nnno, +% \exp_args:NNnV, +% \exp_args:NNoo, +% \exp_args:NNVV, +% \exp_args:Ncno, +% \exp_args:NcnV, +% \exp_args:Ncoo, +% \exp_args:NcVV, % \exp_args:Nnnc, +% \exp_args:Nnno, +% \exp_args:Nnnf, +% \exp_args:Nnff, % \exp_args:Nooo, +% \exp_args:Noof, +% \exp_args:Nffo, % } % \begin{syntax} % \cs{exp_args:NNoo} \meta{token_1} \meta{token_2} \Arg{token_3} \Arg{tokens} @@ -432,7 +469,7 @@ % and fourth as detailed by their argument specifier. The first % argument of the function is then the next item on the input stream, % followed by the expansion of the second argument, \emph{etc}. -% These functions need special (slower) processing. +% These functions need slower processing. % \end{function} % % \begin{function}[added = 2015-08-12] @@ -440,11 +477,11 @@ % \exp_args:NNNx, % \exp_args:NNnx, % \exp_args:NNox, +% \exp_args:Nccx, +% \exp_args:Ncnx, % \exp_args:Nnnx, % \exp_args:Nnox, % \exp_args:Noox, -% \exp_args:Ncnx, -% \exp_args:Nccx % } % \begin{syntax} % \cs{exp_args:NNnx} \meta{token_1} \meta{token_2} \Arg{tokens_1} \Arg{tokens_2} @@ -459,21 +496,22 @@ % % \begin{function}[EXP, updated = 2012-02-12] % { -% \exp_last_unbraced:NV, -% \exp_last_unbraced:Nf, % \exp_last_unbraced:No, +% \exp_last_unbraced:NV, % \exp_last_unbraced:Nv, +% \exp_last_unbraced:Nf, +% \exp_last_unbraced:NNo, +% \exp_last_unbraced:NNV, % \exp_last_unbraced:Nco, % \exp_last_unbraced:NcV, -% \exp_last_unbraced:NNV, -% \exp_last_unbraced:NNo, % \exp_last_unbraced:Nno, % \exp_last_unbraced:Noo, % \exp_last_unbraced:Nfo, -% \exp_last_unbraced:NNNV, % \exp_last_unbraced:NNNo, -% \exp_last_unbraced:NnNo -% } +% \exp_last_unbraced:NNNV, +% \exp_last_unbraced:NnNo, +% \exp_last_unbraced:NNNNo, +% } % \begin{syntax} % \cs{exp_last_unbraced:Nno} \meta{token} \Arg{tokens_1} \Arg{tokens_2} % \end{syntax} @@ -481,8 +519,8 @@ % specification, carry out the expansion % indicated and leave the results in the input stream, with the % last argument not surrounded by the usual braces. -% Of these, the \texttt{:Nno}, \texttt{:Noo}, and \texttt{:Nfo} -% variants need special (slower) processing. +% Of these, the |:Nno|, |:Noo|, |:Nfo| and |:NnNo| +% variants need slower processing. % \begin{texnote} % As an optimization, the last argument is unbraced by some % of those functions before expansion. This can cause problems @@ -496,8 +534,8 @@ % \begin{syntax} % \cs{exp_last_unbraced:Nx} \meta{function} \Arg{tokens} % \end{syntax} -% This functions fully expands the \meta{tokens} and leaves -% the result in the input stream after reinsertion of \meta{function}. +% This function fully expands the \meta{tokens} and leaves the result +% in the input stream after reinsertion of the \meta{function}. % This function is not expandable. % \end{function} % @@ -505,7 +543,7 @@ % \begin{syntax} % \cs{exp_last_two_unbraced:Noo} \meta{token} \Arg{tokens_1} \Arg{tokens_2} % \end{syntax} -% This function absorbs three arguments and expand the second and third +% This function absorbs three arguments and expands the second and third % once. The first argument of the function is then the next item on the % input stream, followed by the expansion of the second and third arguments, % which are not wrapped in braces. @@ -522,9 +560,9 @@ % unchanged. It is important to notice that \meta{token_1} may be % \emph{any} single token, including group-opening and -closing % tokens (|{| or |}| assuming normal \TeX{} category codes). Unless -% specifically required, expansion should be carried out using an +% specifically required this should be avoided: expansion should be carried out using an % appropriate argument specifier variant or the appropriate -% \cs{exp_arg:N} function. +% \cs[no-index]{exp_arg:N} function. % \begin{texnote} % This is the \TeX{} primitive \tn{expandafter} renamed. % \end{texnote} @@ -542,10 +580,16 @@ % \begin{syntax} % \cs{exp_not:N} \meta{token} % \end{syntax} -% Prevents expansion of the \meta{token} in a context where it would otherwise -% be expanded, for example an |x|-type argument. +% Prevents expansion of the \meta{token} in a context where it would +% otherwise be expanded, for example an |x|-type argument or the first +% token in an |o| or |f| argument. % \begin{texnote} -% This is the \TeX{} \tn{noexpand} primitive. +% This is the \TeX{} \tn{noexpand} primitive. It only prevents +% expansion. At the beginning of an |f|-type argument, a space +% \meta{token} is removed despite \cs{exp_not:N}. In an +% |x|-expanding definition (\cs{cs_new:Npx}) a macro parameter +% \meta{token} (normally~|#|) denotes an argument despite +% \cs{exp_not:N} (see \cs{exp_not:n}). % \end{texnote} % \end{function} % @@ -553,60 +597,65 @@ % \begin{syntax} % \cs{exp_not:c} \Arg{tokens} % \end{syntax} -% Expands the \meta{tokens} until only unexpandable content remains, and then -% converts this into a control sequence. Further expansion of this control -% sequence is then inhibited. +% Expands the \meta{tokens} until only characters remain, and then +% converts this into a control sequence. (An internal error occurs if +% non-characters remain, as the conversion is not possible.) +% Further expansion of this control sequence is then inhibited using +% \cs{exp_not:N}. % \end{function} % % \begin{function}[EXP]{\exp_not:n} % \begin{syntax} % \cs{exp_not:n} \Arg{tokens} % \end{syntax} -% Prevents expansion of the \meta{tokens} in a context where they -% would otherwise be expanded, for example an |x|-type argument. +% Prevents expansion of the \meta{tokens} in an |x|-type argument. In +% other cases (input stream or |o| or |f| arguments) the \meta{tokens} +% continue being expanded. % \begin{texnote} % This is the \eTeX{} \tn{unexpanded} primitive. Hence its argument -% \emph{must} be surrounded by braces. +% \emph{must} be surrounded by braces. In an |x|-expanding +% definition (\cs{cs_new:Npx}), \cs{exp_not:n}~|{#}| inserts a macro +% parameter character in the replacement text. % \end{texnote} % \end{function} % +% \begin{function}[EXP]{\exp_not:o} +% \begin{syntax} +% \cs{exp_not:o} \Arg{tokens} +% \end{syntax} +% Expands the \meta{tokens} once, then prevents any further expansion +% in |x|-type arguments using \cs{exp_not:n}. +% \end{function} +% % \begin{function}[EXP]{\exp_not:V} % \begin{syntax} % \cs{exp_not:V} \meta{variable} % \end{syntax} % Recovers the content of the \meta{variable}, then prevents expansion -% of this material in a context where it would otherwise -% be expanded, for example an |x|-type argument. +% of this material in |x|-type arguments using \cs{exp_not:n}. % \end{function} % % \begin{function}[EXP]{\exp_not:v} % \begin{syntax} % \cs{exp_not:v} \Arg{tokens} % \end{syntax} -% Expands the \meta{tokens} until only unexpandable content remains, and then -% converts this into a control sequence (which should be a \meta{variable} -% name). The content of the \meta{variable} is recovered, and further -% expansion is prevented in a context where it would otherwise -% be expanded, for example an |x|-type argument. -% \end{function} -% -% \begin{function}[EXP]{\exp_not:o} -% \begin{syntax} -% \cs{exp_not:o} \Arg{tokens} -% \end{syntax} -% Expands the \meta{tokens} once, then prevents any further expansion in a -% context where they would otherwise -% be expanded, for example an |x|-type argument. +% Expands the \meta{tokens} until only characters remains, and then +% converts this into a control sequence which should be a \meta{variable} +% name. (An internal error occurs if +% non-characters remain, as the conversion is not possible.) +% The content of the \meta{variable} is recovered, and further +% expansion in |x|-type arguments is prevented using \cs{exp_not:n}. % \end{function} % % \begin{function}[EXP]{\exp_not:f} % \begin{syntax} % \cs{exp_not:f} \Arg{tokens} % \end{syntax} -% Expands \meta{tokens} fully until the first unexpandable token -% is found. Expansion then stops, and the result of the expansion -% (including any tokens which were not expanded) is protected from -% further expansion. +% Expands \meta{tokens} fully until the first unexpandable token is +% found (if it is a space it is removed). Expansion then stops, and +% the result of the expansion (including any tokens which were not +% expanded) is protected from further expansion in |x|-type arguments +% using \cs{exp_not:n}. % \end{function} % % \begin{function}[updated = 2011-06-03, EXP]{\exp_stop_f:} @@ -710,7 +759,7 @@ % 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). +% |f|-expansion). % % You might wonder why there are two different approaches available, % after all the effect of @@ -740,18 +789,18 @@ % \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 \texttt{f}-type expansion. +% up an argument which is then returned to the input stream. If +% \meta{further-tokens} starts with space tokens then these space +% tokens are removed while searching for the argument. If it starts +% with a brace group then the braces are removed. Thus such spaces or +% braces will not terminate the \texttt{f}-type expansion. % \end{function} % % \section{Internal functions and variables} % % \begin{variable}{\l__exp_internal_tl} -% The |\exp_| module has its private variables to temporarily store -% results of the argument expansion. This is done to avoid interference +% The |\exp_| module has its private variable to temporarily store the +% result of |x|-type argument expansion. This is done to avoid interference % with other functions using temporary variables. % \end{variable} % @@ -781,15 +830,16 @@ % \begin{macro}{\exp_after:wN} % \begin{macro}{\exp_not:N} % \begin{macro}{\exp_not:n} -% These are defined in \pkg{l3basics}. +% These are defined in \pkg{l3basics}, as they are needed +% \enquote{early}. This is just a reminder of that fact! % \end{macro} % \end{macro} % \end{macro} % % \subsection{General expansion} % -% In this section a general mechanism for defining functions to handle -% argument handling is defined. These general expansion functions are +% In this section a general mechanism for defining functions that handle +% arguments is defined. These general expansion functions are % expandable unless |x| is used. (Any version of |x| is going to have % to use one of the \LaTeX3 names for \cs{cs_set:Npx} at some % point, and so is never going to be expandable.) @@ -800,15 +850,12 @@ % method for efficiency, typically using calls to \cs{exp_after:wN}. % % \begin{variable}{\l_@@_internal_tl} -% This scratch token list variable is defined in \pkg{l3basics}, as it -% is needed \enquote{early}. This is just a reminder that is the -% case! +% This scratch token list variable is defined in \pkg{l3basics}. % \end{variable} % -% This code uses internal functions with names that start with |\::| -% to perform the expansions. All macros are |long| as this turned out -% to be desirable since the tokens undergoing expansion may be -% arbitrary user input. +% This code uses internal functions with names that start with |\::| to +% perform the expansions. All macros are |long| since the tokens +% undergoing expansion may be arbitrary user input. % % An argument manipulator |\::|\meta{Z} always has signature |#1\:::#2#3| % where |#1| holds the remaining argument manipulations to be performed, @@ -818,8 +865,8 @@ % One exception to this rule is \cs{::p}, which has to grab an argument % delimited by a left brace. % -% \begin{macro}[aux, EXP]{\@@_arg_next:nnn} -% \begin{macro}[aux, EXP]{\@@_arg_next:Nnn} +% \begin{macro}[EXP]{\@@_arg_next:nnn} +% \begin{macro}[EXP]{\@@_arg_next:Nnn} % |#1| is the result of an expansion step, |#2| is the remaining % argument manipulations and |#3| is the current result of the % expansion chain. This auxiliary function moves |#1| back after @@ -836,14 +883,14 @@ % \end{macro} % \end{macro} % -% \begin{macro}[int]{\:::} +% \begin{macro}{\:::} % The end marker is just another name for the identity function. % \begin{macrocode} \cs_new:Npn \::: #1 {#1} % \end{macrocode} % \end{macro} % -% \begin{macro}[int, EXP]{\::n} +% \begin{macro}[EXP]{\::n} % This function is used to skip an argument that doesn't need to % be expanded. % \begin{macrocode} @@ -851,7 +898,7 @@ % \end{macrocode} % \end{macro} % -% \begin{macro}[int, EXP]{\::N} +% \begin{macro}[EXP]{\::N} % This function is used to skip an argument that consists of a % single token and doesn't need to be expanded. % \begin{macrocode} @@ -859,16 +906,16 @@ % \end{macrocode} % \end{macro} % -% \begin{macro}[int, EXP]{\::p} +% \begin{macro}[EXP]{\::p} % This function is used to skip an argument that is delimited by a -% left brace and doesn't need to be expanded. It should not be +% left brace and doesn't need to be expanded. It is not % wrapped in braces in the result. % \begin{macrocode} \cs_new:Npn \::p #1 \::: #2#3# { #1 \::: {#2#3} } % \end{macrocode} % \end{macro} % -% \begin{macro}[int, EXP]{\::c} +% \begin{macro}[EXP]{\::c} % This function is used to skip an argument that is turned into % a control sequence without expansion. % \begin{macrocode} @@ -877,7 +924,7 @@ % \end{macrocode} % \end{macro} % -% \begin{macro}[int, EXP]{\::o} +% \begin{macro}[EXP]{\::o} % This function is used to expand an argument once. % \begin{macrocode} \cs_new:Npn \::o #1 \::: #2#3 @@ -885,23 +932,22 @@ % \end{macrocode} % \end{macro} % -% \begin{macro}[int, EXP]{\::f} +% \begin{macro}[EXP]{\::f} % \begin{macro}{\exp_stop_f:} % This function is used to expand a token list until the first % 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 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 -% \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. +% \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 (if that is a space it is +% removed). We introduce \cs{exp_stop_f:} to mark such an +% end-of-expansion marker. For example, |f|-expanding +% |\cs_set_eq:Nc \aaa { b \l_tmpa_tl b }| where |\l_tmpa_tl| contains +% the characters |lur| gives |\tex_let:D \aaa = \blurb| which then +% turns out to start with the non-expandable token |\tex_let:D|. +% Since the expansion of \cs{exp:w} \cs{exp_end_continue_f:w} is +% empty, 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. % \begin{macrocode} \cs_new:Npn \::f #1 \::: #2#3 { @@ -914,7 +960,7 @@ % \end{macro} % \end{macro} % -% \begin{macro}[int]{\::x} +% \begin{macro}{\::x} % This function is used to expand an argument fully. % \begin{macrocode} \cs_new_protected:Npn \::x #1 \::: #2#3 @@ -925,10 +971,11 @@ % \end{macrocode} % \end{macro} % -% \begin{macro}[int, EXP]{\::v} -% \begin{macro}[int, EXP]{\::V} +% \begin{macro}[EXP]{\::v} +% \begin{macro}[EXP]{\::V} % These functions return the value of a register, i.e., one of -% |tl|, |clist|, |int|, |skip|, |dim| and |muskip|. The |V| version +% |tl|, |clist|, |int|, |skip|, |dim|, |muskip|, or built-in +% \TeX{} register. 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 \cs{exp:w} sets off an expansion @@ -951,8 +998,8 @@ % \end{macro} % \end{macro} % -% \begin{macro}[int, EXP]{\@@_eval_register:N, \@@_eval_register:c} -% \begin{macro}[aux, EXP]{\@@_eval_error_msg:w} +% \begin{macro}[EXP]{\@@_eval_register:N, \@@_eval_register:c} +% \begin{macro}[EXP]{\@@_eval_error_msg:w} % This function evaluates a register. Now a register might exist as % one of two things: A parameter-less macro or a built-in \TeX{} % register such as |\count|. For the \TeX{} registers we have to @@ -1027,23 +1074,7 @@ % \label{sec:l3expan:handtune} % % One of the most important features of these functions is that they -% are fully expandable and therefore allow to prefix them with -% \cs{tex_global:D} for example. -% -% \begin{macro}[EXP]{\exp_args:No} -% \begin{macro}[EXP]{\exp_args:NNo} -% \begin{macro}[EXP]{\exp_args:NNNo} -% Those lovely runs of expansion! -% \begin{macrocode} -\cs_new:Npn \exp_args:No #1#2 { \exp_after:wN #1 \exp_after:wN {#2} } -\cs_new:Npn \exp_args:NNo #1#2#3 - { \exp_after:wN #1 \exp_after:wN #2 \exp_after:wN {#3} } -\cs_new:Npn \exp_args:NNNo #1#2#3#4 - { \exp_after:wN #1 \exp_after:wN#2 \exp_after:wN #3 \exp_after:wN {#4} } -% \end{macrocode} -% \end{macro} -% \end{macro} -% \end{macro} +% are fully expandable. % % \begin{macro}[EXP]{\exp_args:Nc, \exp_args:cc} % In \pkg{l3basics}. @@ -1067,6 +1098,21 @@ % \end{macrocode} % \end{macro} % +% \begin{macro}[EXP]{\exp_args:No} +% \begin{macro}[EXP]{\exp_args:NNo} +% \begin{macro}[EXP]{\exp_args:NNNo} +% Those lovely runs of expansion! +% \begin{macrocode} +\cs_new:Npn \exp_args:No #1#2 { \exp_after:wN #1 \exp_after:wN {#2} } +\cs_new:Npn \exp_args:NNo #1#2#3 + { \exp_after:wN #1 \exp_after:wN #2 \exp_after:wN {#3} } +\cs_new:Npn \exp_args:NNNo #1#2#3#4 + { \exp_after:wN #1 \exp_after:wN#2 \exp_after:wN #3 \exp_after:wN {#4} } +% \end{macrocode} +% \end{macro} +% \end{macro} +% \end{macro} +% % \begin{macro}[EXP]{\exp_args:Nf, \exp_args:NV, \exp_args:Nv} % \begin{macrocode} \cs_new:Npn \exp_args:Nf #1#2 @@ -1087,19 +1133,19 @@ % \begin{macro}[EXP] % { % \exp_args:NNV, \exp_args:NNv, \exp_args:NNf, +% \exp_args:Nco, \exp_args:NcV, \exp_args:Ncv, \exp_args:Ncf, % \exp_args:NVV, -% \exp_args:Ncf, \exp_args:Nco % } % Some more hand-tuned function with three arguments. % If we forced that an |o| argument always has braces, % we could implement \cs{exp_args:Nco} with less tokens % and only two arguments. % \begin{macrocode} -\cs_new:Npn \exp_args:NNf #1#2#3 +\cs_new:Npn \exp_args:NNV #1#2#3 { \exp_after:wN #1 \exp_after:wN #2 - \exp_after:wN { \exp:w \exp_end_continue_f:w #3 } + \exp_after:wN { \exp:w \@@_eval_register:N #3 } } \cs_new:Npn \exp_args:NNv #1#2#3 { @@ -1107,11 +1153,11 @@ \exp_after:wN #2 \exp_after:wN { \exp:w \@@_eval_register:c {#3} } } -\cs_new:Npn \exp_args:NNV #1#2#3 +\cs_new:Npn \exp_args:NNf #1#2#3 { \exp_after:wN #1 \exp_after:wN #2 - \exp_after:wN { \exp:w \@@_eval_register:N #3 } + \exp_after:wN { \exp:w \exp_end_continue_f:w #3 } } \cs_new:Npn \exp_args:Nco #1#2#3 { @@ -1119,6 +1165,18 @@ \cs:w #2 \exp_after:wN \cs_end: \exp_after:wN {#3} } +\cs_new:Npn \exp_args:NcV #1#2#3 + { + \exp_after:wN #1 + \cs:w #2 \exp_after:wN \cs_end: + \exp_after:wN { \exp:w \@@_eval_register:N #3 } + } +\cs_new:Npn \exp_args:Ncv #1#2#3 + { + \exp_after:wN #1 + \cs:w #2 \exp_after:wN \cs_end: + \exp_after:wN { \exp:w \@@_eval_register:c {#3} } + } \cs_new:Npn \exp_args:Ncf #1#2#3 { \exp_after:wN #1 @@ -1137,8 +1195,8 @@ % % \begin{macro}[EXP] % { -% \exp_args:Ncco, \exp_args:NcNc, \exp_args:NcNo, -% \exp_args:NNNV +% \exp_args:NNNV, \exp_args:NcNc, \exp_args:NcNo, +% \exp_args:Ncco, % } % A few more that we can hand-tune. % \begin{macrocode} @@ -1178,7 +1236,7 @@ % % Some of these could be done more efficiently, but the complexity of % coding then becomes an issue. Notice that the auto-generated functions -% are all not long: they don't actually take any arguments themselves. +% actually take no arguments themselves. % % \begin{macro}{\exp_args:Nx} % \begin{macrocode} @@ -1188,9 +1246,9 @@ % % \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:Noc +% \exp_args:Nnc, \exp_args:Nno, \exp_args:NnV, \exp_args:Nnv, \exp_args:Nnf, +% \exp_args:Noc, \exp_args:Noo, \exp_args:Nof, +% \exp_args:NVo, \exp_args:Nfo, \exp_args:Nff, % } % \begin{macro} % { @@ -1201,14 +1259,16 @@ % above. % \begin{macrocode} \cs_new:Npn \exp_args:Nnc { \::n \::c \::: } -\cs_new:Npn \exp_args:Nfo { \::f \::o \::: } -\cs_new:Npn \exp_args:Nff { \::f \::f \::: } -\cs_new:Npn \exp_args:Nnf { \::n \::f \::: } \cs_new:Npn \exp_args:Nno { \::n \::o \::: } \cs_new:Npn \exp_args:NnV { \::n \::V \::: } +\cs_new:Npn \exp_args:Nnv { \::n \::v \::: } +\cs_new:Npn \exp_args:Nnf { \::n \::f \::: } +\cs_new:Npn \exp_args:Noc { \::o \::c \::: } \cs_new:Npn \exp_args:Noo { \::o \::o \::: } \cs_new:Npn \exp_args:Nof { \::o \::f \::: } -\cs_new:Npn \exp_args:Noc { \::o \::c \::: } +\cs_new:Npn \exp_args:NVo { \::V \::o \::: } +\cs_new:Npn \exp_args:Nfo { \::f \::o \::: } +\cs_new:Npn \exp_args:Nff { \::f \::f \::: } \cs_new_protected:Npn \exp_args:NNx { \::N \::x \::: } \cs_new_protected:Npn \exp_args:Ncx { \::c \::x \::: } \cs_new_protected:Npn \exp_args:Nnx { \::n \::x \::: } @@ -1221,21 +1281,35 @@ % % \begin{macro}[EXP] % { -% \exp_args:NNno, \exp_args:NNoo, -% \exp_args:Nnnc, \exp_args:Nnno, \exp_args:Nooo, +% \exp_args:NNcf, +% \exp_args:NNno, \exp_args:NNnV, \exp_args:NNoo, \exp_args:NNVV, +% \exp_args:Ncno, \exp_args:NcnV, \exp_args:Ncoo, \exp_args:NcVV, +% \exp_args:Nnnc, \exp_args:Nnno, \exp_args:Nnnf, \exp_args:Nnff, +% \exp_args:Nooo, \exp_args:Noof, \exp_args:Nffo, % } % \begin{macro} % { -% \exp_args:NNNx, -% \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:Nccx, \exp_args:Ncnx, +% \exp_args:Nnnx, \exp_args:Nnox, \exp_args:Noox, % } % \begin{macrocode} +\cs_new:Npn \exp_args:NNcf { \::N \::c \::f \::: } \cs_new:Npn \exp_args:NNno { \::N \::n \::o \::: } +\cs_new:Npn \exp_args:NNnV { \::N \::n \::V \::: } \cs_new:Npn \exp_args:NNoo { \::N \::o \::o \::: } +\cs_new:Npn \exp_args:NNVV { \::N \::V \::V \::: } +\cs_new:Npn \exp_args:Ncno { \::c \::n \::o \::: } +\cs_new:Npn \exp_args:NcnV { \::c \::n \::V \::: } +\cs_new:Npn \exp_args:Ncoo { \::c \::o \::o \::: } +\cs_new:Npn \exp_args:NcVV { \::c \::V \::V \::: } \cs_new:Npn \exp_args:Nnnc { \::n \::n \::c \::: } \cs_new:Npn \exp_args:Nnno { \::n \::n \::o \::: } +\cs_new:Npn \exp_args:Nnnf { \::n \::n \::f \::: } +\cs_new:Npn \exp_args:Nnff { \::n \::f \::f \::: } \cs_new:Npn \exp_args:Nooo { \::o \::o \::o \::: } +\cs_new:Npn \exp_args:Noof { \::o \::o \::f \::: } +\cs_new:Npn \exp_args:Nffo { \::f \::f \::o \::: } \cs_new_protected:Npn \exp_args:NNNx { \::N \::N \::x \::: } \cs_new_protected:Npn \exp_args:NNnx { \::N \::n \::x \::: } \cs_new_protected:Npn \exp_args:NNox { \::N \::o \::x \::: } @@ -1250,21 +1324,16 @@ % % \subsection{Last-unbraced versions} % -% \begin{macro}[aux, EXP]{\@@_arg_last_unbraced:nn} -% \begin{macro}[aux, EXP]{\::f_unbraced} -% \begin{macro}[aux, EXP]{\::o_unbraced} -% \begin{macro}[aux, EXP]{\::V_unbraced} -% \begin{macro}[aux, EXP]{\::v_unbraced} -% \begin{macro}[aux, EXP]{\::x_unbraced} +% \begin{macro}[EXP]{\@@_arg_last_unbraced:nn} +% \begin{macro}[EXP]{\::o_unbraced} +% \begin{macro}[EXP]{\::V_unbraced} +% \begin{macro}[EXP]{\::v_unbraced} +% \begin{macro}[EXP]{\::f_unbraced} +% \begin{macro}[EXP]{\::x_unbraced} % There are a few places where the last argument needs to be available % unbraced. First some helper macros. % \begin{macrocode} \cs_new:Npn \@@_arg_last_unbraced:nn #1#2 { #2#1 } -\cs_new:Npn \::f_unbraced \::: #1#2 - { - \exp_after:wN \@@_arg_last_unbraced:nn - \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 @@ -1277,6 +1346,11 @@ \exp_after:wN \@@_arg_last_unbraced:nn \exp_after:wN { \exp:w \@@_eval_register:c {#2} } {#1} } +\cs_new:Npn \::f_unbraced \::: #1#2 + { + \exp_after:wN \@@_arg_last_unbraced:nn + \exp_after:wN { \exp:w \exp_end_continue_f:w #2 } {#1} + } \cs_new_protected:Npn \::x_unbraced \::: #1#2 { \cs_set_nopar:Npx \l_@@_internal_tl { \exp_not:n {#1} #2 } @@ -1290,47 +1364,53 @@ % \end{macro} % \end{macro} % -% \begin{macro}[EXP]{\exp_last_unbraced:NV} -% \begin{macro}[EXP]{\exp_last_unbraced:Nv} -% \begin{macro}[EXP]{\exp_last_unbraced:Nf} -% \begin{macro}[EXP]{\exp_last_unbraced:No} -% \begin{macro}[EXP]{\exp_last_unbraced:Nco} -% \begin{macro}[EXP]{\exp_last_unbraced:NcV} -% \begin{macro}[EXP]{\exp_last_unbraced:NNV} -% \begin{macro}[EXP]{\exp_last_unbraced:NNo} -% \begin{macro}[EXP]{\exp_last_unbraced:NNNV} -% \begin{macro}[EXP]{\exp_last_unbraced:NNNo} -% \begin{macro}[EXP]{\exp_last_unbraced:Nno} -% \begin{macro}[EXP]{\exp_last_unbraced:Noo} -% \begin{macro}[EXP]{\exp_last_unbraced:Nfo} -% \begin{macro}[EXP]{\exp_last_unbraced:NnNo} +% \begin{macro}[EXP] +% { +% \exp_last_unbraced:No, +% \exp_last_unbraced:NV, +% \exp_last_unbraced:Nv, +% \exp_last_unbraced:Nf, +% \exp_last_unbraced:NNo, +% \exp_last_unbraced:NNV, +% \exp_last_unbraced:Nco, +% \exp_last_unbraced:NcV, +% \exp_last_unbraced:NNNo, +% \exp_last_unbraced:NNNV, +% \exp_last_unbraced:Nno, +% \exp_last_unbraced:Noo, +% \exp_last_unbraced:Nfo, +% \exp_last_unbraced:NnNo, +% \exp_last_unbraced:NNNNo, +% } % \begin{macro}{\exp_last_unbraced:Nx} % Now the business end: most of these are hand-tuned for speed, but the % general system is in place. % \begin{macrocode} +\cs_new:Npn \exp_last_unbraced:No #1#2 { \exp_after:wN #1 #2 } \cs_new:Npn \exp_last_unbraced:NV #1#2 { \exp_after:wN #1 \exp:w \@@_eval_register:N #2 } \cs_new:Npn \exp_last_unbraced:Nv #1#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 \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 +\cs_new:Npn \exp_last_unbraced:NNo #1#2#3 + { \exp_after:wN #1 \exp_after:wN #2 #3 } +\cs_new:Npn \exp_last_unbraced:NNV #1#2#3 { \exp_after:wN #1 - \cs:w #2 \exp_after:wN \cs_end: + \exp_after:wN #2 \exp:w \@@_eval_register:N #3 } -\cs_new:Npn \exp_last_unbraced:NNV #1#2#3 +\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 - \exp_after:wN #2 + \cs:w #2 \exp_after:wN \cs_end: \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 } +\cs_new:Npn \exp_last_unbraced:NNNo #1#2#3#4 + { \exp_after:wN #1 \exp_after:wN #2 \exp_after:wN #3 #4 } \cs_new:Npn \exp_last_unbraced:NNNV #1#2#3#4 { \exp_after:wN #1 @@ -1338,32 +1418,19 @@ \exp_after:wN #3 \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 } \cs_new:Npn \exp_last_unbraced:Nno { \::n \::o_unbraced \::: } \cs_new:Npn \exp_last_unbraced:Noo { \::o \::o_unbraced \::: } \cs_new:Npn \exp_last_unbraced:Nfo { \::f \::o_unbraced \::: } \cs_new:Npn \exp_last_unbraced:NnNo { \::n \::N \::o_unbraced \::: } +\cs_new:Npn \exp_last_unbraced:NNNNo #1#2#3#4#5 + { \exp_after:wN #1 \exp_after:wN #2 \exp_after:wN #3 \exp_after:wN #4 #5 } \cs_new_protected:Npn \exp_last_unbraced:Nx { \::x_unbraced \::: } % \end{macrocode} % \end{macro} % \end{macro} -% \end{macro} -% \end{macro} -% \end{macro} -% \end{macro} -% \end{macro} -% \end{macro} -% \end{macro} -% \end{macro} -% \end{macro} -% \end{macro} -% \end{macro} -% \end{macro} -% \end{macro} % % \begin{macro}[EXP]{\exp_last_two_unbraced:Noo} -% \begin{macro}[EXP, aux]{\@@_last_two_unbraced:noN} +% \begin{macro}[EXP]{\@@_last_two_unbraced:noN} % If |#2| is a single token then this can be implemented as % \begin{verbatim} % \cs_new:Npn \exp_last_two_unbraced:Noo #1 #2 #3 @@ -1382,14 +1449,16 @@ % % \subsection{Preventing expansion} % -% \begin{macro}[EXP]{\exp_not:o} % \begin{macro}[EXP]{\exp_not:c} +% \begin{macro}[EXP]{\exp_not:o} % \begin{macro}[EXP]{\exp_not:f} % \begin{macro}[EXP]{\exp_not:V} % \begin{macro}[EXP]{\exp_not:v} +% All these except \cs{exp_not:c} call the primitive +% \cs{etex_unexpanded:D} namely \cs{exp_not:n}. % \begin{macrocode} -\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:o #1 { \etex_unexpanded:D \exp_after:wN {#1} } \cs_new:Npn \exp_not:f #1 { \etex_unexpanded:D \exp_after:wN { \exp:w \exp_end_continue_f:w #1 } } \cs_new:Npn \exp_not:V #1 @@ -1415,57 +1484,54 @@ % \begin{macro}{\exp_end:} % \begin{macro}{\exp_end_continue_f:w} % \begin{macro}{\exp_end_continue_f:nw} -% -% To trigger a sequence of \enquote{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. +% To trigger a sequence of \enquote{arbitrarily} 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) 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: \cs{exp:w} is set equal to \cs{tex_romannumeral:D} in +% \pkg{l3basics}. To stop the expansion sequence in a controlled way +% all we need to provide is a constant integer zero as part of +% expanded tokens. As this is an integer constant it immediately stops +% \cs{tex_romannumeral:D}'s search for a number. Again, the +% definition of \cs{exp_end:} as the integer constant zero is in +% \pkg{l3basics}. (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 \enquote{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 \texttt{f}-type expansion we provide the +% alphabetic constant |`^^@| that also represents |0| but this time +% \TeX's syntax for a \meta{number} continues searching for an +% optional space (and it continues expansion doing that) --- see +% \TeX{}book page~269 for details. % \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 a constant integer zero as part of expanded tokens. As this is -% an integer constant it immediately stops -% \cs{tex_romannumerl:D}'s search for a number. -% \begin{macrocode} -%\int_const:Nn \exp_end: { 0 } -% \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 \enquote{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 \texttt{f}-type expansion we provide the -% alphabetic constant |`^^@| that also represents |0| but this time -% \TeX's syntax for a \meta{number} continues searching for an -% optional space (and it continues 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 {`^^@} +\group_begin: + \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.} +% error. % \begin{macrocode} -\cs_new:Npn ^^@{\expansionERROR} + \cs_new:Npn ^^@ + { \__msg_kernel_expandable_error:nn { kernel } { bad-exp-end-f } } % \end{macrocode} -% +% The same but grabbing an argument to remove spaces and braces. % \begin{macrocode} -\cs_new:Npn \exp_end_continue_f:nw #1 { `^^@ #1 } -\tex_catcode:D `\^^@=15 + \cs_new:Npn \exp_end_continue_f:nw #1 { `^^@ #1 } +\group_end: % \end{macrocode} % \end{macro} % \end{macro} @@ -1507,13 +1573,13 @@ % \end{macrocode} % \end{macro} % -% \begin{macro}[aux]{\@@_generate_variant:N} -% \begin{macro}[aux]{\@@_generate_variant:ww, \@@_generate_variant:wwNw} +% \begin{macro}{\@@_generate_variant:N} +% \begin{macro}{\@@_generate_variant:ww, \@@_generate_variant:wwNw} % The goal here is to pick up protected parent functions. There are % four cases: the parent function can be a primitive or a macro, and % can be expandable or not. For non-expandable primitives, all % variants should be protected; skipping the \cs{else:} branch is safe -% because all primitive \TeX{} conditionals are expandable. +% because non-expandable primitives cannot be \TeX{} conditionals. % % The other case where variants should be protected is when the parent % function is a protected macro: then |protected| appears in the @@ -1546,24 +1612,19 @@ \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 } +\exp_last_unbraced:NNNNo + \cs_new_protected:Npn \@@_generate_variant:ww + #1 { \tl_to_str:n { ma } } #2 \q_mark + { \@@_generate_variant:wwNw #1 } +\exp_last_unbraced:NNNNo + \cs_new_protected:Npn \@@_generate_variant:wwNw + #1 { \tl_to_str:n { pr } } #2 \q_mark #3 #4 \q_stop + { \cs_set_eq:NN \@@_tmp:w #3 } % \end{macrocode} % \end{macro} % \end{macro} % -% \begin{macro}[aux]{\@@_generate_variant:nnNN} +% \begin{macro}{\@@_generate_variant:nnNN} % \begin{arguments} % \item Base name. % \item Base signature. @@ -1587,7 +1648,7 @@ % \end{macrocode} % \end{macro} % -% \begin{macro}[aux]{\@@_generate_variant:Nnnw} +% \begin{macro}{\@@_generate_variant:Nnnw} % \begin{arguments} % \item Base function. % \item Base name. @@ -1603,32 +1664,34 @@ % % There are further subtleties: % \begin{itemize} -% \item In \cs{cs_generate_variant:Nn} |\foo:nnTF| |{xxTF}|, it -% would be better to define |\foo:xxTF| using |\exp_args:Nxx|, +% \item In \cs{cs_generate_variant:Nn} |\foo:nnTF| |{xxTF}|, we must define +% |\foo:xxTF| using |\exp_args:Nxx|, % rather than a hypothetical |\exp_args:NxxTF|. Thus, we wish to % trim a common trailing part from the base signature and the % variant signature. % \item In \cs{cs_generate_variant:Nn} |\foo:on| |{ox}|, the -% function |\foo:ox| should be defined using |\exp_args:Nnx|, not +% function |\foo:ox| must be defined using |\exp_args:Nnx|, not % |\exp_args:Nox|, to avoid double |o| expansion. -% \item Lastly, \cs{cs_generate_variant:Nn} |\foo:on| |{xn}| should +% \item Lastly, \cs{cs_generate_variant:Nn} |\foo:on| |{xn}| must % trigger an error, because we do not have a means to replace % |o|-expansion by |x|-expansion. +% More generally, we can only convert |N| to |c|, or convert |n| +% to |V|, |v|, |o|, |f|, |x|. % \end{itemize} % All this boils down to a few rules. Only |n| and |N|-type % arguments can be replaced by \cs{cs_generate_variant:Nn}. Other % argument types are allowed to be passed unchanged from the base % form to the variant: in the process they are changed to |n| -% (except for two cases: |N| and |p|-type arguments). A common -% trailing part is ignored. +% except for |N| and |p|-type arguments. A common trailing +% part is ignored. % % We compare the base and variant signatures one character at a time % within |x|-expansion. The result is given to -% \cs{@@_generate_variant:wwNN} in the form \meta{processed variant -% signature} \cs{q_mark} \meta{errors} \cs{q_stop} \meta{base -% function} \meta{new function}. If all went well, \meta{errors} -% is empty; otherwise, it is a kernel error message, followed by -% some clean-up code (\cs{use_none:nnn}). +% \cs{@@_generate_variant:wwNN} (defined later) in the form +% \meta{processed variant signature} \cs{q_mark} \meta{errors} +% \cs{q_stop} \meta{base function} \meta{new function}. If all went +% well, \meta{errors} is empty; otherwise, it is a kernel error +% message and some clean-up code. % % Note the space after |#3| and after the following brace group. % Those are ignored by \TeX{} when fetching the last argument for @@ -1658,17 +1721,20 @@ % \end{macrocode} % \end{macro} % -% \begin{macro}[aux, EXP] +% \begin{macro}[rEXP] % { % \@@_generate_variant_loop:nNwN, +% \@@_generate_variant_loop_base:N, % \@@_generate_variant_loop_same:w, % \@@_generate_variant_loop_end:nwwwNNnn, % \@@_generate_variant_loop_long:wNNnn, % \@@_generate_variant_loop_invalid:NNwNNnn, +% \@@_generate_variant_loop_special:NNwNNnn, +% \@@_generate_variant_loop_warning:nnxxxx % } % \begin{arguments} -% \item Last few (consecutive) letters common between the base -% and variant (in fact, \cs{@@_generate_variant_same:N} +% \item Last few consecutive letters common between the base and +% variant (more precisely, \cs{@@_generate_variant_same:N} % \meta{letter} for each letter). % \item Next variant letter. % \item Remainder of variant form. @@ -1680,15 +1746,16 @@ % two letters are different: if the loop ends before, the argument is % dropped, which means that trailing common letters are ignored. % -% The case where the two letters are different is only allowed with a -% base letter of |N| or |n|. Otherwise, call +% The case where the two letters are different is only allowed if the +% base is |N| and the variant is |c|, or when the base is |n| and the +% variant is |o|, |V|, |v|, |f| or |x|. Otherwise, call % \cs{@@_generate_variant_loop_invalid:NNwNNnn} to remove the end of % the loop, get arguments at the end of the loop, and place an % appropriate error message as a second argument of -% \cs{@@_generate_variant:wwNN}. If the letters are distinct and -% the base letter is indeed |n| or |N|, leave in the input stream -% whatever argument was collected, and the next variant letter |#2|, -% then loop by calling \cs{@@_generate_variant_loop:nNwN}. +% \cs{@@_generate_variant:wwNN}. If the letters are distinct and the +% base letter is indeed |n| or |N|, leave in the input stream whatever +% argument |#1| was collected, and the next variant letter |#2|, then +% loop by calling \cs{@@_generate_variant_loop:nNwN}. % % The loop can stop in three ways. % \begin{itemize} @@ -1706,8 +1773,9 @@ % \cs{@@_generate_variant:wwNN}. % \item The loop can be interrupted early if the requested expansion % is unavailable, namely when the variant and base letters differ -% and the base is neither |n| nor |N|. Again, an error is placed -% as the second argument of \cs{@@_generate_variant:wwNN}. +% and the base is not the right one (|n| or |N| to support the +% variant). In that case too an error is placed as the second +% argument of \cs{@@_generate_variant:wwNN}. % \end{itemize} % Note that if the variant form has the same length as the base form, % |#2| is as described in the first point, and |#4| as described in @@ -1715,14 +1783,23 @@ % breaking function takes the empty brace group in |#4| as its first % argument: this empty brace group produces the correct signature for % the full variant. +% +% Since people seem to have tried generating |N| or |c|-type variants +% of |n|-type arguments, and |n|, |o|, |V|, |v|, |f|, |x| variants of +% |N|-type arguments, in those cases we only produce a warning. % \begin{macrocode} \cs_new:Npn \@@_generate_variant_loop:nNwN #1#2#3 \q_mark #4 { \if:w #2 #4 \exp_after:wN \@@_generate_variant_loop_same:w \else: - \if:w N #4 \else: - \if:w n #4 \else: + \if:w #4 \@@_generate_variant_loop_base:N #2 \else: + \if:w 0 + \if:w N #4 \else: \if:w n #4 \else: 1 \fi: \fi: + \if:w \scan_stop: \@@_generate_variant_loop_base:N #2 1 \fi: + 0 + \@@_generate_variant_loop_special:NNwNNnn #4#2 + \else: \@@_generate_variant_loop_invalid:NNwNNnn #4#2 \fi: \fi: @@ -1732,11 +1809,29 @@ #2 \@@_generate_variant_loop:nNwN { } #3 \q_mark } -\cs_new:Npn \@@_generate_variant_loop_same:w - #1 \prg_do_nothing: #2#3#4 +\cs_new:Npn \@@_generate_variant_loop_base:N #1 { - #3 { #1 \@@_generate_variant_same:N #2 } + \if:w c #1 N \else: + \if:w o #1 n \else: + \if:w V #1 n \else: + \if:w v #1 n \else: + \if:w f #1 n \else: + \if:w x #1 n \else: + \if:w n #1 n \else: + \if:w N #1 N \else: + \scan_stop: + \fi: + \fi: + \fi: + \fi: + \fi: + \fi: + \fi: + \fi: } +\cs_new:Npn \@@_generate_variant_loop_same:w + #1 \prg_do_nothing: #2#3#4 + { #3 { #1 \@@_generate_variant_same:N #2 } } \cs_new:Npn \@@_generate_variant_loop_end:nwwwNNnn #1#2 \q_mark #3 ~ #4 \q_stop #5#6#7#8 { @@ -1774,31 +1869,42 @@ #5 } } +\cs_new:Npn \@@_generate_variant_loop_special:NNwNNnn #1#2#3 \q_stop #4#5#6#7 + { + #3 \q_stop #4 #5 {#6} {#7} + \exp_not:n + { + \@@_generate_variant_loop_warning:nnxxxx { kernel } { invalid-variant } + {#7} { \token_to_str:N #5 } {#1} {#2} + } + } +\cs_new_protected:Npn \@@_generate_variant_loop_warning:nnxxxx + { \__msg_kernel_warning:nnxxxx } % \end{macrocode} % \end{macro} % -% \begin{macro}[aux, rEXP]{\@@_generate_variant_same:N} +% \begin{macro}[rEXP]{\@@_generate_variant_same:N} % When the base and variant letters are identical, don't do any % expansion. For most argument types, we can use the |n|-type % no-expansion, but the |N| and |p| types require a slightly different -% behaviour with respect to braces. +% behaviour with respect to braces. For |V|-type this function could +% output |N| to avoid adding useless braces but that is not a problem. % \begin{macrocode} \cs_new:Npn \@@_generate_variant_same:N #1 { - \if:w N #1 - N - \else: - \if:w p #1 - p - \else: + \if:w N #1 N \else: + \if:w p #1 p \else: n + \if:w n #1 \else: + \@@_generate_variant_loop_special:NNwNNnn #1#1 + \fi: \fi: \fi: } % \end{macrocode} % \end{macro} % -% \begin{macro}[aux]{\@@_generate_variant:wwNN} +% \begin{macro}{\@@_generate_variant:wwNN} % If the variant form has already been defined, log its existence % (provided \texttt{log-functions} is active). % Otherwise, make sure that the |\exp_args:N #3| form is defined, and @@ -1833,9 +1939,9 @@ % \end{macrocode} % \end{macro} % -% \begin{macro}[int]{\@@_generate_internal_variant:n} -% \begin{macro}[aux]{\@@_generate_internal_variant:wwnw} -% \begin{macro}[aux, rEXP]{\@@_generate_internal_variant_loop:n} +% \begin{macro}{\@@_generate_internal_variant:n} +% \begin{macro}{\@@_generate_internal_variant:wwnw} +% \begin{macro}[rEXP]{\@@_generate_internal_variant_loop:n} % Test if |\exp_args:N #1| is already defined and if not define it via % the |\::| commands using the chars in |#1|. If |#1| contains an |x| % (this is the place where having converted the original comma-list |