summaryrefslogtreecommitdiff
path: root/macros/latex/required/l3kernel/l3expan.dtx
diff options
context:
space:
mode:
Diffstat (limited to 'macros/latex/required/l3kernel/l3expan.dtx')
-rw-r--r--macros/latex/required/l3kernel/l3expan.dtx2398
1 files changed, 2398 insertions, 0 deletions
diff --git a/macros/latex/required/l3kernel/l3expan.dtx b/macros/latex/required/l3kernel/l3expan.dtx
new file mode 100644
index 0000000000..e79b5f32b9
--- /dev/null
+++ b/macros/latex/required/l3kernel/l3expan.dtx
@@ -0,0 +1,2398 @@
+% \iffalse meta-comment
+%
+%% File: l3expan.dtx
+%
+% Copyright (C) 1990-2024 The LaTeX Project
+%
+% It may be distributed and/or modified under the conditions of the
+% LaTeX Project Public License (LPPL), either version 1.3c of this
+% license or (at your option) any later version. The latest version
+% of this license is in the file
+%
+% 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.
+%
+% -----------------------------------------------------------------------
+%
+% The development version of the bundle can be found at
+%
+% https://github.com/latex3/latex3
+%
+% for those people who are interested.
+%
+%<*driver>
+\documentclass[full,kernel]{l3doc}
+\begin{document}
+ \DocInput{\jobname.dtx}
+\end{document}
+%</driver>
+% \fi
+%
+% \title{^^A
+% The \pkg{l3expan} module\\ Argument expansion^^A
+% }
+%
+% \author{^^A
+% The \LaTeX{} Project\thanks
+% {^^A
+% E-mail:
+% \href{mailto:latex-team@latex-project.org}
+% {latex-team@latex-project.org}^^A
+% }^^A
+% }
+%
+% \date{Released 2024-04-11}
+%
+% \maketitle
+%
+% \begin{documentation}
+%
+% This module provides generic methods for expanding \TeX{} arguments in a
+% systematic manner. The functions in this module all have prefix |exp|.
+%
+% Not all possible variations are implemented for every base
+% function. Instead only those that are used within the \LaTeX3 kernel
+% or otherwise seem to be of general interest are implemented.
+% Consult the module description to find out which functions are
+% actually defined. The next section explains how to define missing
+% variants.
+%
+% \section{Defining new variants}
+% \label{sec:l3expan:defining-variants}
+%
+% The definition of variant forms for base functions may be necessary
+% when writing new functions or when applying a kernel function in a
+% situation that we haven't thought of before.
+%
+% Internally preprocessing of arguments is done with functions of the form
+% \cs[no-index]{exp_\ldots{}}. They all look alike, an example would be
+% \cs{exp_args:NNo}. This function has three arguments, the first and the
+% second are a single tokens, while the third argument should be given
+% in braces. Applying \cs{exp_args:NNo} expands the content of third
+% argument once before any expansion of the first and second arguments.
+% If \cs{seq_gpush:No} was not defined it could be coded in the following way:
+% \begin{verbatim}
+% \exp_args:NNo \seq_gpush:Nn
+% \g_file_name_stack
+% { \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
+% this base function. In the example the first argument to the base
+% function should be a single token which is left unchanged while the
+% second argument is expanded once. From this example we can also see
+% how the variants are defined. They just expand into the appropriate
+% |\exp_| function followed by the desired base function, \emph{e.g.}
+% \begin{quote}
+% |\cs_generate_variant:Nn \seq_gpush:Nn { No } |
+% \end{quote}
+% results in the definition of |\seq_gpush:No|
+% \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 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
+% style files obsolete.
+%
+% The steps above may be automated by using the function
+% \cs{cs_generate_variant:Nn}, described next.
+%
+% \section{Methods for defining variants}
+% \label{sec:l3expan:variants-method}
+%
+% We recall the set of available argument specifiers.
+% \begin{itemize}
+% \item |N|~is used for single-token arguments while |c|~constructs a
+% control sequence from its name and passes it to a parent function as
+% an |N|-type argument.
+% \item Many argument types extract or expand some tokens and provide it
+% as an |n|-type argument, namely a braced multiple-token argument:
+% |V|~extracts the value of a variable, |v|~extracts the value from
+% the name of a variable, |n|~uses the argument as it is, |o|~expands
+% once, |f|~expands fully the front of the token list, |e| and
+% |x|~expand fully all tokens (differences are explained later).
+% \item A few odd argument types remain: |T|~and |F|~for conditional
+% 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 = 2017-11-28]
+% {\cs_generate_variant:Nn, \cs_generate_variant:cn}
+% \begin{syntax}
+% \cs{cs_generate_variant:Nn} \meta{parent control sequence} \Arg{variant argument specifiers}
+% \end{syntax}
+% This function is used to define argument-specifier variants of the
+% \meta{parent control sequence} for \LaTeX3 code-level macros. The
+% \meta{parent control sequence} is first separated into the
+% \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} if these are not already
+% defined; entries which correspond to existing functions are silently
+% ingored. For each \meta{variant} given, a function is created
+% 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 }
+% \cs_generate_variant:Nn \foo:Nn { c }
+% \end{verbatim}
+% creates a new function |\foo:cn| which expands its first
+% argument into a control sequence name and passes the result to
+% |\foo:Nn|. Similarly
+% \begin{verbatim}
+% \cs_generate_variant:Nn \foo:Nn { NV , cV }
+% \end{verbatim}
+% generates the functions |\foo:NV| and |\foo:cV| in the same
+% way. The \cs{cs_generate_variant:Nn} function should only be applied if
+% the \meta{parent control sequence} is already defined. (This is only
+% enforced if debugging support \texttt{check-declarations} is enabled.)
+% If the \meta{parent
+% control sequence} is protected or if the \meta{variant} involves any
+% |x|~argument, 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. There is no need to re-apply \cs{cs_generate_variant:Nn} after
+% changing the definition of the parent function: the variant will always
+% use the current definition of the parent. Providing variants repeatedly is
+% safe as \cs{cs_generate_variant:Nn} will only create new definitions if
+% there is not already one available.
+%
+% 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|, |e|, 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}.
+%
+% When creating variants for conditional functions,
+% \cs{prg_generate_conditional_variant:Nnn} provides a convenient way
+% of handling the related function set.
+%
+% For backward compatibility it is currently possible to make |n|,
+% |o|, |V|, |v|, |f|, |e|, 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}
+%
+% \begin{function}[added = 2018-04-04, updated = 2019-02-08]
+% {\exp_args_generate:n}
+% \begin{syntax}
+% \cs{exp_args_generate:n} \Arg{variant argument specifiers}
+% \end{syntax}
+% Defines \cs[no-index]{exp_args:N\meta{variant}} functions for each
+% \meta{variant} given in the comma list \Arg{variant argument
+% specifiers}. Each \meta{variant} should consist of the letters |N|,
+% |c|, |n|, |V|, |v|, |o|, |f|, |e|, |x|, |p| and the resulting function is
+% protected if the letter |x| appears in the \meta{variant}. This is
+% only useful for cases where \cs{cs_generate_variant:Nn} is not
+% applicable.
+% \end{function}
+%
+% \section{Introducing the variants}
+%
+% The |V| type returns the value of a register, which can be one of
+% |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.
+%
+% In general, the programmer should not need to be concerned with
+% expansion control. When simply using the content of a variable,
+% functions with a |V| specifier should be used. For those referred to by
+% (cs)name, the |v| specifier is available for the same purpose. Only when
+% specific expansion steps are needed, such as when using delimited
+% arguments, should the lower-level functions with |o| specifiers be employed.
+%
+% The |e| type expands all tokens fully, starting from the first. More
+% precisely the expansion is identical to that of \TeX{}'s \tn{message}
+% (in particular |#| needs not be doubled). It relies on the
+% primitive \tn{expanded} hence is fast.
+%
+% The |x| type expands all tokens fully, starting from the first. In
+% contrast to |e|, all macro parameter characters |#| must be doubled,
+% and omitting this leads to low-level errors. In addition this type of
+% expansion is not expandable, namely functions that have |x| in their
+% signature do not themselves expand when appearing inside |e| or |x|
+% expansion.
+%
+% 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 the front of the token list
+% 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}
+% |\example:f { \int_eval:n { 3 + 4 } }|
+% \end{quote}
+% 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}
+% |\example:f { \int_eval:n { 1 + 2 } , \int_eval:n { 3 + 4 } }|
+% \end{quote}
+% results in the call
+% \begin{quote}
+% |\example:n { 3 , \int_eval:n { 3 + 4 } }|
+% \end{quote}
+% while using |\example:x| or |\example:e| instead results in
+% \begin{quote}
+% |\example:n { 3 , 7 }|
+% \end{quote}
+% at the cost of being protected for |x|-type.
+% If you use |f| type expansion in conditional processing then
+% you should stick to using |TF| type functions only as the expansion
+% does not finish any |\if... \fi:| itself!
+%
+% 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
+% is conceptually similar to
+% \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}
+% non-expandable token. This means for example that both
+% \begin{verbatim}
+% \tl_set:No \l_tmpa_tl { { \g_tmpb_tl } }
+% \end{verbatim}
+% and
+% \begin{verbatim}
+% \tl_set:Nf \l_tmpa_tl { { \g_tmpb_tl } }
+% \end{verbatim}
+% leave |\g_tmpb_tl| unchanged: |{| is the first token in the
+% argument and is non-expandable.
+%
+% It is usually best to keep the following in mind when using variant
+% forms.
+% \begin{itemize}
+% \item
+% Variants with |x|-type arguments (that are fully expanded before
+% being passed to the |n|-type base function) are never expandable
+% even when the base function is. Such variants cannot work
+% correctly in arguments that are themselves subject to expansion.
+% Consider using |f| or |e| expansion.
+% \item
+% In contrast, |e|~expansion (full expansion, almost like~|x| except
+% for the treatment of~|#|) does not prevent variants from being
+% expandable (if the base function is).
+% \item
+% Finally |f|~expansion only expands the front of the token list,
+% stopping at the first non-expandable token. This may fail to
+% fully expand the argument.
+% \end{itemize}
+%
+% When speed is essential (for functions that do very little work and
+% whose variants are used numerous times in a document) the following
+% considerations apply because the speed of internal functions that
+% expand the arguments of a base function depend on what needs doing
+% with each argument and where this happens in the list of arguments:
+% \begin{itemize}
+% \item for fastest processing any |c|-type arguments should come first
+% followed by all other modified arguments;
+% \item unchanged |N|-type args that appear before modified ones have
+% a small performance hit;
+% \item unchanged |n|-type args that appear before modified ones have
+% a relative larger performance hit.
+% \end{itemize}
+%
+% \section{Manipulating the first argument}
+%
+% 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:Nc, \exp_args:cc}
+% \begin{syntax}
+% \cs{exp_args:Nc} \meta{function} \Arg{tokens}
+% \end{syntax}
+% 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.
+% 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.
+%
+% The |:cc| variant constructs the \meta{function} name in the same
+% 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}
+% \end{syntax}
+% This function absorbs two arguments (the names of the \meta{function} and
+% the \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 than
+% one argument: all others are left unchanged.
+% \end{function}
+%
+% \begin{function}[EXP]{\exp_args:Nv}
+% \begin{syntax}
+% \cs{exp_args:Nv} \meta{function} \Arg{tokens}
+% \end{syntax}
+% 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.
+% 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
+% than one argument: all others are left unchanged.
+% \end{function}
+%
+% \begin{function}[EXP, added = 2018-05-15]{\exp_args:Ne}
+% \begin{syntax}
+% \cs{exp_args:Ne} \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}.
+% 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:Nf}
+% \begin{syntax}
+% \cs{exp_args:Nf} \meta{function} \Arg{tokens}
+% \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 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.
+% \end{function}
+%
+% \begin{function}{\exp_args:Nx}
+% \begin{syntax}
+% \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}.
+% 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}
+%
+% \section{Manipulating two arguments}
+%
+% \begin{function}[EXP, updated = 2018-05-15]
+% {
+% \exp_args:NNc,
+% \exp_args:NNo,
+% \exp_args:NNV,
+% \exp_args:NNv,
+% \exp_args:NNe,
+% \exp_args:NNf,
+% \exp_args:Ncc,
+% \exp_args:Nco,
+% \exp_args:NcV,
+% \exp_args:Ncv,
+% \exp_args:Ncf,
+% \exp_args:NVV
+% }
+% \begin{syntax}
+% \cs{exp_args:NNc} \meta{token_1} \meta{token_2} \Arg{tokens}
+% \end{syntax}
+% These optimized functions absorb three arguments and expand the second and
+% 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.
+% \end{function}
+%
+% \begin{function}[EXP, updated = 2018-05-15]
+% {
+% \exp_args:Nnc,
+% \exp_args:Nno,
+% \exp_args:NnV,
+% \exp_args:Nnv,
+% \exp_args:Nne,
+% \exp_args:Nnf,
+% \exp_args:Noc,
+% \exp_args:Noo,
+% \exp_args:Nof,
+% \exp_args:NVo,
+% \exp_args:Nfo,
+% \exp_args:Nff,
+% \exp_args:Nee,
+% }
+% \begin{syntax}
+% \cs{exp_args:Noo} \meta{token} \Arg{tokens_1} \Arg{tokens_2}
+% \end{syntax}
+% These functions absorb three arguments and expand the second and
+% 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.
+% \end{function}
+%
+% \begin{function}
+% {
+% \exp_args:NNx,
+% \exp_args:Ncx,
+% \exp_args:Nnx,
+% \exp_args:Nox,
+% \exp_args:Nxo,
+% \exp_args:Nxx
+% }
+% \begin{syntax}
+% \cs{exp_args:NNx} \meta{token_1} \meta{token_2} \Arg{tokens}
+% \end{syntax}
+% These functions absorb three arguments and expand the second and
+% 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 due to their |x|-type argument.
+% \end{function}
+%
+% \section{Manipulating three arguments}
+%
+% \begin{function}[EXP]
+% {
+% \exp_args:NNNo,
+% \exp_args:NNNV,
+% \exp_args:NNNv,
+% \exp_args:NNNe,
+% \exp_args:Nccc,
+% \exp_args:NcNc,
+% \exp_args:NcNo,
+% \exp_args:Ncco
+% }
+% \begin{syntax}
+% \cs{exp_args:NNNo} \meta{token_1} \meta{token_2} \meta{token_3} \Arg{tokens}
+% \end{syntax}
+% These optimized functions absorb four arguments and expand the second, third
+% 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}.
+% \end{function}
+%
+% \begin{function}[EXP]
+% {
+% \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,
+% \exp_args:Neee
+% }
+% \begin{syntax}
+% \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
+% argument of the function is then the next item on the input stream,
+% followed by the expansion of the second argument, \emph{etc}.
+% \end{function}
+%
+% \begin{function}[added = 2015-08-12]
+% {
+% \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{syntax}
+% \cs{exp_args:NNnx} \meta{token_1} \meta{token_2} \Arg{tokens_1} \Arg{tokens_2}
+% \end{syntax}
+% These functions absorb four arguments and expand the second, third
+% 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.}
+% \end{function}
+%
+% \section{Unbraced expansion}
+%
+% \begin{function}[EXP, updated = 2018-05-15]
+% {
+% \exp_last_unbraced:No,
+% \exp_last_unbraced:NV,
+% \exp_last_unbraced:Nv,
+% \exp_last_unbraced:Ne,
+% \exp_last_unbraced:Nf,
+% \exp_last_unbraced:NNo,
+% \exp_last_unbraced:NNV,
+% \exp_last_unbraced:NNf,
+% \exp_last_unbraced:Nco,
+% \exp_last_unbraced:NcV,
+% \exp_last_unbraced:Nno,
+% \exp_last_unbraced:Nnf,
+% \exp_last_unbraced:Noo,
+% \exp_last_unbraced:Nfo,
+% \exp_last_unbraced:NNNo,
+% \exp_last_unbraced:NNNV,
+% \exp_last_unbraced:NNNf,
+% \exp_last_unbraced:NnNo,
+% \exp_last_unbraced:NNNNo,
+% \exp_last_unbraced:NNNNf,
+% }
+% \begin{syntax}
+% \cs{exp_last_unbraced:Nno} \meta{token} \Arg{tokens_1} \Arg{tokens_2}
+% \end{syntax}
+% These functions absorb the number of arguments given by their
+% 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 |: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
+% if the argument is empty: for instance,
+% \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}
+%
+% \begin{function}{\exp_last_unbraced:Nx}
+% \begin{syntax}
+% \cs{exp_last_unbraced:Nx} \meta{function} \Arg{tokens}
+% \end{syntax}
+% 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}
+%
+% \begin{function}[EXP]{\exp_last_two_unbraced:Noo}
+% \begin{syntax}
+% \cs{exp_last_two_unbraced:Noo} \meta{token} \Arg{tokens_1} \Arg{tokens_2}
+% \end{syntax}
+% 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.
+% This function needs special (slower) processing.
+% \end{function}
+%
+% \begin{function}[EXP]{\exp_after:wN}
+% \begin{syntax}
+% \cs{exp_after:wN} \meta{token_1} \meta{token_2}
+% \end{syntax}
+% Carries out a single expansion of \meta{token_2} (which may consume
+% arguments) prior to the expansion of \meta{token_1}. If \meta{token_2} has
+% no expansion (for example, if it is a character) then it is left
+% 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 this should be avoided: expansion should be carried out using an
+% appropriate argument specifier variant or the appropriate
+% \cs[no-index]{exp_args:N\meta{variant}} function.
+% \begin{texnote}
+% This is the \TeX{} primitive \tn{expandafter}.
+% \end{texnote}
+% \end{function}
+%
+%
+% \section{Preventing expansion}
+%
+% Despite the fact that the following functions are all about preventing
+% expansion, they're designed to be used in an expandable context and hence
+% are all marked as being `expandable' since they themselves disappear
+% after the expansion has completed.
+%
+% \begin{function}[EXP]{\exp_not:N}
+% \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 |e|-type or |x|-type argument or
+% the first token in an |o|-type or |f|-type argument.
+% \begin{texnote}
+% This is the \TeX{} primitive \tn{noexpand}. It only prevents
+% expansion. At the beginning of an |f|-type argument, a space
+% \meta{token} is removed even if it appears as \cs{exp_not:N}
+% \cs{c_space_token}. In an |e|-expanding definition
+% (\cs{cs_new:Npe}), a macro parameter introduces an argument even
+% if it appears as \cs{exp_not:N} |#| |1|. This differs from
+% \cs{exp_not:n}.
+% \end{texnote}
+% \end{function}
+%
+% \begin{function}[EXP]{\exp_not:c}
+% \begin{syntax}
+% \cs{exp_not:c} \Arg{tokens}
+% \end{syntax}
+% Expands the \meta{tokens} until only characters remain, and then
+% converts this into a control sequence.
+% 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 an |e|-type or |x|-type argument.
+% In all other cases the \meta{tokens} continue to be expanded, for
+% example in the input stream or in other types of arguments such as
+% \texttt{c}, \texttt{f}, \texttt{v}. The argument of \cs{exp_not:n}
+% \emph{must} be surrounded by braces.
+% \begin{texnote}
+% This is the \eTeX{} primitive \tn{unexpanded}. In an
+% |e|-expanding definition (\cs{cs_new:Npe}), \cs{exp_not:n}~|{#1}|
+% is equivalent to |##1| rather than to~|#1|, namely it inserts the
+% two characters |#| and~|1|, and
+% \cs{exp_not:n}~|{#}| is equivalent to |#|, namely it inserts the
+% character~|#|.
+% \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 |e|-type or |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 |e|-type or |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 characters 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 in |e|-type or |x|-type arguments is prevented using \cs{exp_not:n}.
+% \end{function}
+%
+% \begin{function}[EXP]{\exp_not:e}
+% \begin{syntax}
+% \cs{exp_not:e} \Arg{tokens}
+% \end{syntax}
+% Expands \meta{tokens} exhaustively, then protects the result of the
+% expansion (including any tokens which were not expanded) from
+% further expansion in |e|-type or |x|-type arguments using \cs{exp_not:n}.
+% This is very rarely useful but is provided for consistency.
+% \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 (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 |e|-type or |x|-type arguments
+% using \cs{exp_not:n}.
+% \end{function}
+%
+% \begin{function}[updated = 2011-06-03, EXP]{\exp_stop_f:}
+% \begin{syntax}
+% |\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 |\foo_bar:f| starts an \texttt{f}-type expansion
+% and all of \meta{tokens} are expandable \cs{exp_stop_f:}
+% terminates the expansion of tokens even if \meta{more tokens}
+% are also expandable. The function itself is an implicit space
+% token. Inside an \texttt{e}-type or \texttt{x}-type expansion, it retains its
+% 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 \enquote{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. These
+% commands are 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:} is 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.
+% \begin{texnote}
+% The current implementation uses \tn{romannumeral} hence ignores
+% space tokens and explicit signs |+| and |-| in the expansion of the
+% \meta{expandable tokens}, but this should not be relied upon.
+% \end{texnote}
+% \end{function}
+% \footnotetext{Due to the implementation you might get the character
+% in position 0 in the current font (typically \enquote{\texttt{`}})
+% in the output without any error message!}
+%
+% \begin{function}[added=2015-08-23, EXP, label = \exp_end_continue_f:w]
+% {
+% \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 \texttt{f}-type expansion expanding
+% \meta{further-tokens} until an unexpandable token is encountered (or
+% the \texttt{f}-type expansion is explicitly terminated by
+% \cs{exp_stop_f:}). As with all \texttt{f}-type expansions a space ending
+% the expansion gets 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 \texttt{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 \texttt{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, label = \exp_end_continue_f:nw]
+% {
+% \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 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}
+%
+% \begin{function}{\::n, \::N, \::p, \::c, \::o, \::e, \::f, \::x, \::v, \::V, \:::}
+% \begin{syntax}
+% |\cs_new:Npn \exp_args:Ncof { \::c \::o \::f \::: }|
+% \end{syntax}
+% Internal forms for the base expansion types. These names do \emph{not}
+% conform to the general \LaTeX3 approach as this makes them more readily
+% visible in the log and so forth. They should not be used outside this module.
+% \end{function}
+%
+% \begin{function}
+% {\::o_unbraced, \::e_unbraced, \::f_unbraced, \::x_unbraced, \::v_unbraced, \::V_unbraced}
+% \begin{syntax}
+% |\cs_new:Npn \exp_last_unbraced:Nno { \::n \::o_unbraced \::: }|
+% \end{syntax}
+% Internal forms for the expansion types which leave the terminal argument
+% unbraced. These names do \emph{not}
+% conform to the general \LaTeX3 approach as this makes them more readily
+% visible in the log and so forth. They should not be used outside this module.
+% \end{function}
+%
+% \end{documentation}
+%
+% \begin{implementation}
+%
+% \section{\pkg{l3expan} implementation}
+%
+% \begin{macrocode}
+%<*package>
+% \end{macrocode}
+%
+% \begin{macrocode}
+%<@@=exp>
+% \end{macrocode}
+%
+% \begin{variable}{\l_@@_internal_tl}
+% 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}
+%
+% \begin{macro}{\exp_after:wN}
+% \begin{macro}{\exp_not:N}
+% \begin{macro}{\exp_not:n}
+% 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 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.)
+%
+% The definition of expansion functions with this technique happens
+% in section~\ref{sec:l3expan:gendef}.
+% In section~\ref{sec:l3expan:handtune} some common cases are coded by a more direct
+% 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}.
+% \end{variable}
+%
+% 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,
+% \cs{:::} serves as an end marker for the list of manipulations, |#2|
+% is the carried over result of the previous expansion steps and |#3| is
+% the argument about to be processed.
+% One exception to this rule is \cs{::p}, which has to grab an argument
+% delimited by a left brace.
+%
+% \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
+% |#3| in the input stream and checks if any expansion is left to
+% be done by calling |#2|. In by far the most cases we need
+% to add a set of braces to the result of an argument manipulation
+% so it is more effective to do it directly here. Actually, so far
+% only the |c| of the final argument manipulation variants does not
+% require a set of braces.
+% \begin{macrocode}
+\cs_new:Npn \@@_arg_next:nnn #1#2#3 { #2 \::: { #3 {#1} } }
+\cs_new:Npn \@@_arg_next:Nnn #1#2#3 { #2 \::: { #3 #1 } }
+% \end{macrocode}
+% \end{macro}
+% \end{macro}
+%
+% \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}[EXP]{\::n}
+% This function is used to skip an argument that doesn't need to
+% be expanded.
+% \begin{macrocode}
+\cs_new:Npn \::n #1 \::: #2#3 { #1 \::: { #2 {#3} } }
+% \end{macrocode}
+% \end{macro}
+%
+% \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}
+\cs_new:Npn \::N #1 \::: #2#3 { #1 \::: {#2#3} }
+% \end{macrocode}
+% \end{macro}
+%
+% \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 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}[EXP]{\::c}
+% This function is used to skip an argument that is turned into
+% a control sequence without expansion.
+% \begin{macrocode}
+\cs_new:Npn \::c #1 \::: #2#3
+ { \exp_after:wN \@@_arg_next:Nnn \cs:w #3 \cs_end: {#1} {#2} }
+% \end{macrocode}
+% \end{macro}
+%
+% \begin{macro}[EXP]{\::o}
+% This function is used to expand an argument once.
+% \begin{macrocode}
+\cs_new:Npn \::o #1 \::: #2#3
+ { \exp_after:wN \@@_arg_next:nnn \exp_after:wN {#3} {#1} {#2} }
+% \end{macrocode}
+% \end{macro}
+%
+% \begin{macro}[EXP]{\::e}
+% With the \tn{expanded} primitive available, just expand.
+% \begin{macrocode}
+\cs_new:Npn \::e #1 \::: #2#3
+ { \tex_expanded:D { \exp_not:n { #1 \::: } { \exp_not:n {#2} {#3} } } }
+% \end{macrocode}
+% \end{macro}
+%
+% \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 (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 |e| and |x| argument type.
+% \begin{macrocode}
+\cs_new:Npn \::f #1 \::: #2#3
+ {
+ \exp_after:wN \@@_arg_next:nnn
+ \exp_after:wN { \exp:w \exp_end_continue_f:w #3 }
+ {#1} {#2}
+ }
+\use:nn { \cs_new_eq:NN \exp_stop_f: } { ~ }
+% \end{macrocode}
+% \end{macro}
+% \end{macro}
+%
+% \begin{macro}{\::x}
+% This function is used to expand an argument fully.
+% We build in the expansion of \cs{@@_arg_next:nnn}.
+% \begin{macrocode}
+\cs_new_protected:Npn \::x #1 \::: #2#3
+ {
+ \cs_set_nopar:Npe \l_@@_internal_tl
+ { \exp_not:n { #1 \::: } { \exp_not:n {#2} {#3} } }
+ \l_@@_internal_tl
+ }
+% \end{macrocode}
+% \end{macro}
+%
+% \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|, |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
+% similar to an |f|-type expansion, which we terminate using
+% \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 { \exp:w \@@_eval_register:N #3 }
+ {#1} {#2}
+}
+\cs_new:Npn \::v #1 \::: #2#3
+ {
+ \exp_after:wN \@@_arg_next:nnn
+ \exp_after:wN { \exp:w \@@_eval_register:c {#3} }
+ {#1} {#2}
+ }
+% \end{macrocode}
+% \end{macro}
+% \end{macro}
+%
+% \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
+% utilize a \tn{the} whereas for the macros we merely have to
+% expand them once. The trick is to find out when to use
+% \tn{the} and when not to. What we want here is to find out
+% whether the token expands to something else when hit with
+% \cs{exp_after:wN}. The technique is to compare the meaning of the
+% token in question when it has been prefixed with \cs{exp_not:N}
+% and the token itself. If it is a macro, the prefixed
+% \cs{exp_not:N} temporarily turns it into the primitive
+% \cs{scan_stop:}.
+% \begin{macrocode}
+\cs_new:Npn \@@_eval_register:N #1
+ {
+ \exp_after:wN \if_meaning:w \exp_not:N #1 #1
+% \end{macrocode}
+% If the token was not a macro it may be a malformed variable from a
+% |c| expansion in which case it is equal to the primitive
+% \cs{scan_stop:}. In that case we throw an error. We could let \TeX{}
+% do it for us but that would result in the rather obscure
+% \begin{quote}
+% |! You can't use `\relax' after \the.|
+% \end{quote}
+% which while quite true doesn't give many hints as to what actually
+% went wrong. We provide something more sensible.
+% \begin{macrocode}
+ \if_meaning:w \scan_stop: #1
+ \@@_eval_error_msg:w
+ \fi:
+% \end{macrocode}
+% The next bit requires some explanation. The function must be
+% 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 \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 \exp_end: \tex_the:D #1
+ }
+\cs_new:Npn \@@_eval_register:c #1
+ { \exp_after:wN \@@_eval_register:N \cs:w #1 \cs_end: }
+% \end{macrocode}
+% Clean up nicely, then call the undefined control sequence. The
+% result is an error message looking like this:
+% \begin{verbatim}
+% ! Undefined control sequence.
+% <argument> \LaTeX3 error:
+% Erroneous variable used!
+% l.55 \tl_set:Nv \l_tmpa_tl {undefined_tl}
+% \end{verbatim}
+% \begin{macrocode}
+\cs_new:Npn \@@_eval_error_msg:w #1 \tex_the:D #2
+ {
+ \fi:
+ \fi:
+ \msg_expandable_error:nnn { kernel } { bad-variable } {#2}
+ \exp_end:
+ }
+% \end{macrocode}
+% \end{macro}
+% \end{macro}
+%
+% \subsection{Hand-tuned definitions}
+% \label{sec:l3expan:handtune}
+%
+% One of the most important features of these functions is that they
+% are fully expandable.
+%
+% \begin{macro}[EXP]{\exp_args:Nc, \exp_args:cc}
+% In \pkg{l3basics}.
+% \end{macro}
+%
+% \begin{macro}[EXP]{\exp_args:NNc, \exp_args:Ncc, \exp_args:Nccc}
+% Here are the functions that turn their argument into csnames but are
+% expandable.
+% \begin{macrocode}
+\cs_new:Npn \exp_args:NNc #1#2#3
+ { \exp_after:wN #1 \exp_after:wN #2 \cs:w # 3\cs_end: }
+\cs_new:Npn \exp_args:Ncc #1#2#3
+ { \exp_after:wN #1 \cs:w #2 \exp_after:wN \cs_end: \cs:w #3 \cs_end: }
+\cs_new:Npn \exp_args:Nccc #1#2#3#4
+ {
+ \exp_after:wN #1
+ \cs:w #2 \exp_after:wN \cs_end:
+ \cs:w #3 \exp_after:wN \cs_end:
+ \cs:w #4 \cs_end:
+ }
+% \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:Ne}
+% When the \tn{expanded} primitive is available, use it.
+% \begin{macrocode}
+\cs_new:Npn \exp_args:Ne #1#2
+ { \exp_after:wN #1 \tex_expanded:D { {#2} } }
+% \end{macrocode}
+% \end{macro}
+%
+% \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 { \exp:w \exp_end_continue_f:w #2 } }
+\cs_new:Npn \exp_args:Nv #1#2
+ {
+ \exp_after:wN #1 \exp_after:wN
+ { \exp:w \@@_eval_register:c {#2} }
+ }
+\cs_new:Npn \exp_args:NV #1#2
+ {
+ \exp_after:wN #1 \exp_after:wN
+ { \exp:w \@@_eval_register:N #2 }
+ }
+% \end{macrocode}
+% \end{macro}
+%
+% \begin{macro}[EXP]
+% {
+% \exp_args:NNV, \exp_args:NNv, \exp_args:NNe, \exp_args:NNf,
+% \exp_args:Nco, \exp_args:NcV, \exp_args:Ncv, \exp_args:Ncf,
+% \exp_args:NVV,
+% }
+% 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:NNV #1#2#3
+ {
+ \exp_after:wN #1
+ \exp_after:wN #2
+ \exp_after:wN { \exp:w \@@_eval_register:N #3 }
+ }
+\cs_new:Npn \exp_args:NNv #1#2#3
+ {
+ \exp_after:wN #1
+ \exp_after:wN #2
+ \exp_after:wN { \exp:w \@@_eval_register:c {#3} }
+ }
+\cs_new:Npn \exp_args:NNe #1#2#3
+ {
+ \exp_after:wN #1
+ \exp_after:wN #2
+ \tex_expanded:D { {#3} }
+ }
+\cs_new:Npn \exp_args:NNf #1#2#3
+ {
+ \exp_after:wN #1
+ \exp_after:wN #2
+ \exp_after:wN { \exp:w \exp_end_continue_f:w #3 }
+ }
+\cs_new:Npn \exp_args:Nco #1#2#3
+ {
+ \exp_after:wN #1
+ \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
+ \cs:w #2 \exp_after:wN \cs_end:
+ \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 { \exp:w \exp_after:wN
+ \@@_eval_register:N \exp_after:wN #2 \exp_after:wN }
+ \exp_after:wN { \exp:w \@@_eval_register:N #3 }
+ }
+% \end{macrocode}
+% \end{macro}
+%
+% \begin{macro}[EXP]
+% {
+% \exp_args:NNNV, \exp_args:NNNv, \exp_args:NNNe,
+% \exp_args:NcNc, \exp_args:NcNo,
+% \exp_args:Ncco,
+% }
+% A few more that we can hand-tune.
+% \begin{macrocode}
+\cs_new:Npn \exp_args:NNNV #1#2#3#4
+ {
+ \exp_after:wN #1
+ \exp_after:wN #2
+ \exp_after:wN #3
+ \exp_after:wN { \exp:w \@@_eval_register:N #4 }
+ }
+\cs_new:Npn \exp_args:NNNv #1#2#3#4
+ {
+ \exp_after:wN #1
+ \exp_after:wN #2
+ \exp_after:wN #3
+ \exp_after:wN { \exp:w \@@_eval_register:c {#4} }
+ }
+\cs_new:Npn \exp_args:NNNe #1#2#3#4
+ {
+ \exp_after:wN #1
+ \exp_after:wN #2
+ \exp_after:wN #3
+ \tex_expanded:D { {#4} }
+ }
+\cs_new:Npn \exp_args:NcNc #1#2#3#4
+ {
+ \exp_after:wN #1
+ \cs:w #2 \exp_after:wN \cs_end:
+ \exp_after:wN #3
+ \cs:w #4 \cs_end:
+ }
+\cs_new:Npn \exp_args:NcNo #1#2#3#4
+ {
+ \exp_after:wN #1
+ \cs:w #2 \exp_after:wN \cs_end:
+ \exp_after:wN #3
+ \exp_after:wN {#4}
+ }
+\cs_new:Npn \exp_args:Ncco #1#2#3#4
+ {
+ \exp_after:wN #1
+ \cs:w #2 \exp_after:wN \cs_end:
+ \cs:w #3 \exp_after:wN \cs_end:
+ \exp_after:wN {#4}
+ }
+% \end{macrocode}
+% \end{macro}
+%
+% \begin{macro}{\exp_args:Nx}
+% \begin{macrocode}
+\cs_new_protected:Npn \exp_args:Nx #1#2
+ { \use:x { \exp_not:N #1 {#2} } }
+% \end{macrocode}
+% \end{macro}
+%
+% \subsection{Last-unbraced versions}
+%
+% \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]{\::e_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 \::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 { \exp:w \@@_eval_register:N #2 } {#1}
+ }
+\cs_new:Npn \::v_unbraced \::: #1#2
+ {
+ \exp_after:wN \@@_arg_last_unbraced:nn
+ \exp_after:wN { \exp:w \@@_eval_register:c {#2} } {#1}
+ }
+\cs_new:Npn \::e_unbraced \::: #1#2
+ { \tex_expanded:D { \exp_not:n {#1} #2 } }
+\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:Npe \l_@@_internal_tl { \exp_not:n {#1} #2 }
+ \l_@@_internal_tl
+ }
+% \end{macrocode}
+% \end{macro}
+% \end{macro}
+% \end{macro}
+% \end{macro}
+% \end{macro}
+% \end{macro}
+% \end{macro}
+%
+% \begin{macro}[EXP]
+% {
+% \exp_last_unbraced:No,
+% \exp_last_unbraced:NV,
+% \exp_last_unbraced:Nv,
+% \exp_last_unbraced:Ne,
+% \exp_last_unbraced:Nf,
+% \exp_last_unbraced:NNo,
+% \exp_last_unbraced:NNV,
+% \exp_last_unbraced:NNf,
+% \exp_last_unbraced:Nco,
+% \exp_last_unbraced:NcV,
+% \exp_last_unbraced:NNNo,
+% \exp_last_unbraced:NNNV,
+% \exp_last_unbraced:NNNf,
+% \exp_last_unbraced:Nno,
+% \exp_last_unbraced:Nnf,
+% \exp_last_unbraced:Noo,
+% \exp_last_unbraced:Nfo,
+% \exp_last_unbraced:NnNo,
+% \exp_last_unbraced:NNNNo,
+% \exp_last_unbraced:NNNNf,
+% }
+% \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:Ne #1#2
+ { \exp_after:wN #1 \tex_expanded:D {#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: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
+ \exp_after:wN #2
+ \exp:w \@@_eval_register:N #3
+ }
+\cs_new:Npn \exp_last_unbraced:NNf #1#2#3
+ {
+ \exp_after:wN #1
+ \exp_after:wN #2
+ \exp:w \exp_end_continue_f:w #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
+ \cs:w #2 \exp_after:wN \cs_end:
+ \exp:w \@@_eval_register:N #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
+ \exp_after:wN #2
+ \exp_after:wN #3
+ \exp:w \@@_eval_register:N #4
+ }
+\cs_new:Npn \exp_last_unbraced:NNNf #1#2#3#4
+ {
+ \exp_after:wN #1
+ \exp_after:wN #2
+ \exp_after:wN #3
+ \exp:w \exp_end_continue_f:w #4
+ }
+\cs_new:Npn \exp_last_unbraced:Nno { \::n \::o_unbraced \::: }
+\cs_new:Npn \exp_last_unbraced:Nnf { \::n \::f_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:Npn \exp_last_unbraced:NNNNf #1#2#3#4#5
+ {
+ \exp_after:wN #1
+ \exp_after:wN #2
+ \exp_after:wN #3
+ \exp_after:wN #4
+ \exp:w \exp_end_continue_f:w #5
+ }
+\cs_new_protected:Npn \exp_last_unbraced:Nx { \::x_unbraced \::: }
+% \end{macrocode}
+% \end{macro}
+% \end{macro}
+%
+% \begin{macro}[EXP]{\exp_last_two_unbraced:Noo}
+% \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
+% { \exp_after:wN \exp_after:wN \exp_after:wN #1 \exp_after:wN #2 #3 }
+% \end{verbatim}
+% However, for robustness this is not suitable. Instead, a bit of a
+% shuffle is used to ensure that |#2| can be multiple tokens.
+% \begin{macrocode}
+\cs_new:Npn \exp_last_two_unbraced:Noo #1#2#3
+ { \exp_after:wN \@@_last_two_unbraced:noN \exp_after:wN {#3} {#2} #1 }
+\cs_new:Npn \@@_last_two_unbraced:noN #1#2#3
+ { \exp_after:wN #3 #2 #1 }
+% \end{macrocode}
+% \end{macro}
+% \end{macro}
+%
+% \subsection{Preventing expansion}
+%
+% \begin{macro}{\__kernel_exp_not:w}
+% At the kernel level, we need the primitive behaviour to allow expansion
+% \emph{before} the brace group.
+% \begin{macrocode}
+\cs_new_eq:NN \__kernel_exp_not:w \tex_unexpanded:D
+% \end{macrocode}
+% \end{macro}
+%
+% \begin{macro}[EXP]{\exp_not:c}
+% \begin{macro}[EXP]{\exp_not:o}
+% \begin{macro}[EXP]{\exp_not:e}
+% \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 kernel-internal
+% \cs{__kernel_exp_not:w} namely \cs{tex_unexpanded:D}.
+% \begin{macrocode}
+\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 { \__kernel_exp_not:w \exp_after:wN {#1} }
+\cs_new:Npn \exp_not:e #1
+ { \__kernel_exp_not:w \tex_expanded:D { {#1} } }
+\cs_new:Npn \exp_not:f #1
+ { \__kernel_exp_not:w \exp_after:wN { \exp:w \exp_end_continue_f:w #1 } }
+\cs_new:Npn \exp_not:V #1
+ {
+ \__kernel_exp_not:w \exp_after:wN
+ { \exp:w \@@_eval_register:N #1 }
+ }
+\cs_new:Npn \exp_not:v #1
+ {
+ \__kernel_exp_not:w \exp_after:wN
+ { \exp:w \@@_eval_register:c {#1} }
+ }
+% \end{macrocode}
+% \end{macro}
+% \end{macro}
+% \end{macro}
+% \end{macro}
+% \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 \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}
+\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. The test for existence covers the (unlikely) case that some
+% other code has already defined |^^@|: this is true for example for
+% \texttt{xmltex.tex}.
+% \begin{macrocode}
+ \if_cs_exist:N ^^@
+ \else:
+ \cs_new:Npn ^^@
+ { \msg_expandable_error:nn { kernel } { bad-exp-end-f } }
+ \fi:
+% \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 }
+\group_end:
+% \end{macrocode}
+% \end{macro}
+% \end{macro}
+% \end{macro}
+% \end{macro}
+%
+% \subsection{Defining function variants}
+%
+% \begin{macrocode}
+%<@@=cs>
+% \end{macrocode}
+%
+% \begin{variable}{\s_@@_mark,\s_@@_stop}
+% Internal scan marks. No \pkg{l3quark} yet, so do things by hand.
+% \begin{macrocode}
+\cs_new_eq:NN \s_@@_mark \scan_stop:
+\cs_new_eq:NN \s_@@_stop \scan_stop:
+% \end{macrocode}
+% \end{variable}
+%
+% \begin{variable}{\q_@@_recursion_stop}
+% Internal recursion quarks. No \pkg{l3quark} yet, so do things by hand.
+% \begin{macrocode}
+\cs_new:Npn \q_@@_recursion_stop { \q_@@_recursion_stop }
+% \end{macrocode}
+% \end{variable}
+%
+% \begin{macro}[EXP]{
+% \@@_use_none_delimit_by_s_stop:w,
+% \@@_use_i_delimit_by_s_stop:nw,
+% \@@_use_none_delimit_by_q_recursion_stop:w
+% }
+% Internal scan marks.
+% \begin{macrocode}
+\cs_new:Npn \@@_use_none_delimit_by_s_stop:w #1 \s_@@_stop { }
+\cs_new:Npn \@@_use_i_delimit_by_s_stop:nw #1 #2 \s_@@_stop {#1}
+\cs_new:Npn \@@_use_none_delimit_by_q_recursion_stop:w
+ #1 \q_@@_recursion_stop { }
+% \end{macrocode}
+% \end{macro}
+%
+% \begin{macro}{\cs_generate_variant:Nn, \cs_generate_variant:cn}
+% \begin{arguments}
+% \item Base form of a function; \emph{e.g.},~\cs{tl_set:Nn}
+% \item One or more variant argument specifiers; e.g., |{Nx,c,cx}|
+% \end{arguments}
+% After making sure that the base form exists, test whether it is
+% protected or not and define \cs{@@_tmp:w} as either
+% \cs{cs_new:Npe} or \cs{cs_new_protected:Npe}, which is
+% then used to define all the variants (except those involving
+% \texttt{x}-expansion, always protected). Split up the original base
+% function only once, to grab its name and signature. Then we wish to
+% iterate through the comma list of variant argument specifiers, which
+% we first convert to a string: the reason is explained later.
+% \begin{macrocode}
+\cs_new_protected:Npn \cs_generate_variant:Nn #1#2
+ {
+ \@@_generate_variant:N #1
+ \use:e
+ {
+ \@@_generate_variant:nnNN
+ \cs_split_function:N #1
+ \exp_not:N #1
+ \tl_to_str:n {#2} ,
+ \exp_not:N \scan_stop: ,
+ \exp_not:N \q_@@_recursion_stop
+ }
+ }
+\cs_new_protected:Npn \cs_generate_variant:cn
+ { \exp_args:Nc \cs_generate_variant:Nn }
+% \end{macrocode}
+% \end{macro}
+%
+% \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 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
+% meaning before the first occurrence of |macro|. The |ww| auxiliary
+% removes everything in the meaning string after the first |ma|. We
+% use |ma| rather than the full |macro| because the meaning of the
+% \tn{firstmark} primitive (and four others) can contain an arbitrary
+% string after a leading |firstmark:|. Then, look for |pr| in the
+% part we extracted: no need to look for anything longer: the only
+% strings we can have are an empty string, \verb*|\long |,
+% \verb*|\protected |, \verb*|\protected\long |, |\first|, |\top|,
+% |\bot|, |\splittop|, or |\splitbot|, with |\| replaced by the
+% appropriate escape character. If |pr| appears in the part before
+% |ma|, the first \cs{s_@@_mark} is taken as an argument of the |wwNw|
+% auxiliary, and |#3| is \cs{cs_new_protected:Npe}, otherwise it
+% is \cs{cs_new:Npe}.
+% \begin{macrocode}
+\cs_new_protected:Npe \@@_generate_variant:N #1
+ {
+ \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:Npe
+ \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 }
+ \s_@@_mark
+ \s_@@_mark \cs_new_protected:Npe
+ \tl_to_str:n { pr }
+ \s_@@_mark \cs_new:Npe
+ \s_@@_stop
+ \exp_not:N \fi:
+ }
+\exp_last_unbraced:NNNNo
+ \cs_new_protected:Npn \@@_generate_variant:ww
+ #1 { \tl_to_str:n { ma } } #2 \s_@@_mark
+ { \@@_generate_variant:wwNw #1 }
+\exp_last_unbraced:NNNNo
+ \cs_new_protected:Npn \@@_generate_variant:wwNw
+ #1 { \tl_to_str:n { pr } } #2 \s_@@_mark #3 #4 \s_@@_stop
+ { \cs_set_eq:NN \@@_tmp:w #3 }
+% \end{macrocode}
+% \end{macro}
+% \end{macro}
+%
+% \begin{macro}{\@@_generate_variant:nnNN}
+% \begin{arguments}
+% \item Base name.
+% \item Base signature.
+% \item Boolean.
+% \item Base function.
+% \end{arguments}
+% If the boolean is \cs{c_false_bool}, the base function has no colon
+% and we abort with an error; otherwise, set off a loop through the
+% desired variant forms. The original function is retained as |#4| for
+% efficiency.
+% \begin{macrocode}
+\cs_new_protected:Npn \@@_generate_variant:nnNN #1#2#3#4
+ {
+ \if_meaning:w \c_false_bool #3
+ \msg_error:nne { kernel } { missing-colon }
+ { \token_to_str:c {#1} }
+ \exp_after:wN \@@_use_none_delimit_by_q_recursion_stop:w
+ \fi:
+ \@@_generate_variant:Nnnw #4 {#1}{#2}
+ }
+% \end{macrocode}
+% \end{macro}
+%
+% \begin{macro}{\@@_generate_variant:Nnnw}
+% \begin{arguments}
+% \item Base function.
+% \item Base name.
+% \item Base signature.
+% \item Beginning of variant signature.
+% \end{arguments}
+% First check whether to terminate the loop over variant forms. Then,
+% for each variant form, construct a new function name using the
+% original base name, the variant signature consisting of $l$ letters
+% and the last $k-l$ letters of the base signature (of length $k$).
+% For example, for a base function \cs{prop_put:Nnn} which needs a
+% |cV| variant form, we want the new signature to be |cVn|.
+%
+% There are further subtleties:
+% \begin{itemize}
+% \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| 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}| 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|, |e|, |f|, or |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 |N| and |p|-type arguments. A common trailing
+% part is ignored.
+%
+% We compare the base and variant signatures one character at a time
+% within |e|-expansion. The result is given to
+% \cs{@@_generate_variant:wwNN} (defined later) in the form
+% \meta{processed variant signature} \cs{s_@@_mark} \meta{errors}
+% \cs{s_@@_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
+% \cs{@@_generate_variant_loop:nNwN}, but can be used as a delimiter
+% for \cs{@@_generate_variant_loop_end:nwwwNNnn}.
+% \begin{macrocode}
+\cs_new_protected:Npn \@@_generate_variant:Nnnw #1#2#3#4 ,
+ {
+ \if_meaning:w \scan_stop: #4
+ \exp_after:wN \@@_use_none_delimit_by_q_recursion_stop:w
+ \fi:
+ \use:e
+ {
+ \exp_not:N \@@_generate_variant:wwNN
+ \@@_generate_variant_loop:nNwN { }
+ #4
+ \@@_generate_variant_loop_end:nwwwNNnn
+ \s_@@_mark
+ #3 ~
+ { ~ { } \fi: \@@_generate_variant_loop_long:wNNnn } ~
+ { }
+ \s_@@_stop
+ \exp_not:N #1 {#2} {#4}
+ }
+ \@@_generate_variant:Nnnw #1 {#2} {#3}
+ }
+% \end{macrocode}
+% \end{macro}
+%
+% \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
+% }
+% \begin{arguments}
+% \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.
+% \item Next base letter.
+% \end{arguments}
+% The first argument is populated by
+% \cs{@@_generate_variant_loop_same:w} when a variant letter and a
+% base letter match. It is flushed into the input stream whenever the
+% 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 if the
+% base is |N| and the variant is |c|, or when the base is |n| and the
+% variant is |V|, |v|, |o|, |e|, |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 |#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}
+% \item If the end of the variant form is encountered first, |#2| is
+% \cs{@@_generate_variant_loop_end:nwwwNNnn} (expanded by the
+% conditional \cs{if:w}), which inserts some tokens to end the
+% conditional; grabs the \meta{base name} as |#7|, the
+% \meta{variant signature} |#8|, the \meta{next base letter} |#1|
+% and the part |#3| of the base signature that wasn't read yet;
+% and combines those into the \meta{new function} to be defined.
+% \item If the end of the base form is encountered first, |#4| is
+% |~{}\fi:| which ends the conditional (with an empty expansion),
+% followed by \cs{@@_generate_variant_loop_long:wNNnn}, which
+% places an error as the second argument of
+% \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 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
+% the second point above. The \cs{@@_generate_variant_loop_end:nwwwNNnn}
+% 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.
+% \begin{macrocode}
+\cs_new:Npn \@@_generate_variant_loop:nNwN #1#2#3 \s_@@_mark #4
+ {
+ \if:w #2 #4
+ \exp_after:wN \@@_generate_variant_loop_same:w
+ \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:
+ \fi:
+ #1
+ \prg_do_nothing:
+ #2
+ \@@_generate_variant_loop:nNwN { } #3 \s_@@_mark
+ }
+\cs_new:Npn \@@_generate_variant_loop_base:N #1
+ {
+ \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 e #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:
+ \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 \s_@@_mark #3 ~ #4 \s_@@_stop #5#6#7#8
+ {
+ \scan_stop: \scan_stop: \fi:
+ \s_@@_mark \s_@@_stop
+ \exp_not:N #6
+ \exp_not:c { #7 : #8 #1 #3 }
+ }
+\cs_new:Npn \@@_generate_variant_loop_long:wNNnn #1 \s_@@_stop #2#3#4#5
+ {
+ \exp_not:n
+ {
+ \s_@@_mark
+ \msg_error:nnee { kernel } { variant-too-long }
+ {#5} { \token_to_str:N #3 }
+ \use_none:nnn
+ \s_@@_stop
+ #3
+ #3
+ }
+ }
+\cs_new:Npn \@@_generate_variant_loop_invalid:NNwNNnn
+ #1#2 \fi: \fi: \fi: #3 \s_@@_stop #4#5#6#7
+ {
+ \fi: \fi: \fi:
+ \exp_not:n
+ {
+ \s_@@_mark
+ \msg_error:nneeee { kernel } { invalid-variant }
+ {#7} { \token_to_str:N #5 } {#1} {#2}
+ \use_none:nnn
+ \s_@@_stop
+ #5
+ #5
+ }
+ }
+\cs_new:Npn \@@_generate_variant_loop_special:NNwNNnn
+ #1#2#3 \s_@@_stop #4#5#6#7
+ {
+ #3 \s_@@_stop #4 #5 {#6} {#7}
+ \exp_not:n
+ {
+ \msg_error:nneeee
+ { kernel } { deprecated-variant }
+ {#7} { \token_to_str:N #5 } {#1} {#2}
+ }
+ }
+% \end{macrocode}
+% \end{macro}
+%
+% \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. 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 #1 \else:
+ \if:w p #1 #1 \else:
+ \token_to_str:N n
+ \if:w n #1 \else:
+ \@@_generate_variant_loop_special:NNwNNnn #1#1
+ \fi:
+ \fi:
+ \fi:
+ }
+% \end{macrocode}
+% \end{macro}
+%
+% \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
+% if it contains |x|, change \cs{@@_tmp:w} locally to
+% \cs{cs_new_protected:Npe}. Then define the variant by
+% combining the |\exp_args:N #3| variant and the base function.
+% \begin{macrocode}
+\cs_new_protected:Npn \@@_generate_variant:wwNN
+ #1 \s_@@_mark #2 \s_@@_stop #3#4
+ {
+ #2
+ \cs_if_free:NT #4
+ {
+ \group_begin:
+ \@@_generate_internal_variant:n {#1}
+ \@@_tmp:w #4 { \exp_not:c { exp_args:N #1 } \exp_not:N #3 }
+ \group_end:
+ }
+ }
+% \end{macrocode}
+% \end{macro}
+%
+% \begin{macro}{\@@_generate_internal_variant:n}
+% \begin{macro}[rEXP]{\@@_generate_internal_variant_loop:n}
+% First test for the presence of |x| (this is where working with
+% strings makes our lives easier), as the result should be protected,
+% and the next variant to be defined using that internal variant
+% should be protected (done by setting \cs{@@_tmp:w}). Then call
+% \cs{@@_generate_internal_variant:NNn} with arguments
+% \cs{cs_new_protected:cpn} \cs{use:x} (for protected) or
+% \cs{cs_new:cpn} \cs{tex_expanded:D} (expandable) and the signature. If |p|
+% appears in the signature, or if the function to be defined is
+% expandable and the primitive \tn{expanded} is not available, or if there
+% are more than $8$ arguments, call
+% some fall-back code that just puts the appropriate |\::| commands.
+% Otherwise, call \cs{@@_generate_internal_one_go:NNn} to construct
+% the \cs[no-index]{exp_args:N\dots} function as a macro taking up to
+% $9$~arguments and expanding them using \cs{use:x} or \cs{tex_expanded:D}.
+% \begin{macrocode}
+\cs_new_protected:Npe \@@_generate_internal_variant:n #1
+ {
+ \exp_not:N \@@_generate_internal_variant:wwnNwn
+ #1 \s_@@_mark
+ { \cs_set_eq:NN \exp_not:N \@@_tmp:w \cs_new_protected:Npe }
+ \cs_new_protected:cpn
+ \use:x
+ \token_to_str:N x \s_@@_mark
+ { }
+ \cs_new:cpn
+ \exp_not:N \tex_expanded:D
+ \s_@@_stop
+ {#1}
+ }
+\exp_last_unbraced:NNNNo
+ \cs_new_protected:Npn \@@_generate_internal_variant:wwnNwn #1
+ { \token_to_str:N x } #2 \s_@@_mark #3#4#5#6 \s_@@_stop #7
+ {
+ #3
+ \cs_if_free:cT { exp_args:N #7 }
+ { \@@_generate_internal_variant:NNn #4 #5 {#7} }
+ }
+\cs_set_protected:Npn \@@_tmp:w #1
+ {
+ \cs_new_protected:Npn \@@_generate_internal_variant:NNn ##1##2##3
+ {
+ \if_catcode:w X \use_none:nnnnnnnn ##3
+ \prg_do_nothing: \prg_do_nothing: \prg_do_nothing:
+ \prg_do_nothing: \prg_do_nothing: \prg_do_nothing:
+ \prg_do_nothing: \prg_do_nothing: X
+ \exp_after:wN \@@_generate_internal_test:Nw \exp_after:wN ##2
+ \else:
+ \exp_after:wN \@@_generate_internal_test_aux:w \exp_after:wN #1
+ \fi:
+ ##3
+ \s_@@_mark
+ {
+ \use:e
+ {
+ ##1 { exp_args:N ##3 }
+ { \@@_generate_internal_variant_loop:n ##3 { : \use_i:nn } }
+ }
+ }
+ #1
+ \s_@@_mark
+ { \exp_not:n { \@@_generate_internal_one_go:NNn ##1 ##2 {##3} } }
+ \s_@@_stop
+ }
+ \cs_new_protected:Npn \@@_generate_internal_test_aux:w
+ ##1 #1 ##2 \s_@@_mark ##3 ##4 \s_@@_stop {##3}
+ \cs_new_eq:NN \@@_generate_internal_test:Nw
+ \@@_generate_internal_test_aux:w
+ }
+\exp_args:No \@@_tmp:w { \token_to_str:N p }
+\cs_new_protected:Npn \@@_generate_internal_one_go:NNn #1#2#3
+ {
+ \@@_generate_internal_loop:nwnnw
+ { \exp_not:N ##1 } 1 . { } { }
+ #3 { ? \@@_generate_internal_end:w } X ;
+ 23456789 { ? \@@_generate_internal_long:w } ;
+ #1 #2 {#3}
+ }
+\cs_new_protected:Npn \@@_generate_internal_loop:nwnnw #1#2 . #3#4#5#6 ; #7
+ {
+ \use_none:n #5
+ \use_none:n #7
+ \cs_if_exist_use:cF { @@_generate_internal_#5:NN }
+ { \@@_generate_internal_other:NN }
+ #5 #7
+ #7 .
+ { #3 #1 } { #4 ## #2 }
+ #6 ;
+ }
+\cs_new_protected:Npn \@@_generate_internal_N:NN #1#2
+ { \@@_generate_internal_loop:nwnnw { \exp_not:N ###2 } }
+\cs_new_protected:Npn \@@_generate_internal_c:NN #1#2
+ { \exp_args:No \@@_generate_internal_loop:nwnnw { \exp_not:c {###2} } }
+\cs_new_protected:Npn \@@_generate_internal_n:NN #1#2
+ { \@@_generate_internal_loop:nwnnw { { \exp_not:n {###2} } } }
+\cs_new_protected:Npn \@@_generate_internal_x:NN #1#2
+ { \@@_generate_internal_loop:nwnnw { {###2} } }
+\cs_new_protected:Npn \@@_generate_internal_other:NN #1#2
+ {
+ \exp_args:No \@@_generate_internal_loop:nwnnw
+ {
+ \exp_after:wN
+ {
+ \exp:w \exp_args:NNc \exp_after:wN \exp_end:
+ { exp_not:#1 } {###2}
+ }
+ }
+ }
+\cs_new_protected:Npn \@@_generate_internal_end:w #1 . #2#3#4 ; #5 ; #6#7#8
+ { #6 { exp_args:N #8 } #3 { #7 {#2} } }
+\cs_new_protected:Npn \@@_generate_internal_long:w #1 N #2#3 . #4#5#6#
+ {
+ \exp_args:Nx \@@_generate_internal_long:nnnNNn
+ { \@@_generate_internal_variant_loop:n #2 #6 { : \use_i:nn } }
+ {#4} {#5}
+ }
+\cs_new:Npn \@@_generate_internal_long:nnnNNn #1#2#3#4 ; ; #5#6#7
+ { #5 { exp_args:N #7 } #3 { #6 { \exp_not:n {#1} {#2} } } }
+% \end{macrocode}
+% This command grabs char by char outputting |\::#1| (not expanded
+% further). We avoid tests by putting a trailing |: \use_i:nn|, which
+% leaves \cs{cs_end:} and removes the looping macro. The colon is in
+% fact also turned into \cs{:::} so that the required structure for
+% |\exp_args:N...| commands is correctly terminated.
+% \begin{macrocode}
+\cs_new:Npn \@@_generate_internal_variant_loop:n #1
+ {
+ \exp_after:wN \exp_not:N \cs:w :: #1 \cs_end:
+ \@@_generate_internal_variant_loop:n
+ }
+% \end{macrocode}
+% \end{macro}
+% \end{macro}
+%
+% \begin{macro}
+% {
+% \prg_generate_conditional_variant:Nnn,
+% \@@_generate_variant:nnNnn,
+% \@@_generate_variant:w,
+% \@@_generate_variant:n,
+% \@@_generate_variant_p_form:nnn,
+% \@@_generate_variant_T_form:nnn,
+% \@@_generate_variant_F_form:nnn,
+% \@@_generate_variant_TF_form:nnn,
+% }
+% \begin{macrocode}
+\cs_new_protected:Npn \prg_generate_conditional_variant:Nnn #1
+ {
+ \use:e
+ {
+ \@@_generate_variant:nnNnn
+ \cs_split_function:N #1
+ }
+ }
+\cs_new_protected:Npn \@@_generate_variant:nnNnn #1#2#3#4#5
+ {
+ \if_meaning:w \c_false_bool #3
+ \msg_error:nne { kernel } { missing-colon }
+ { \token_to_str:c {#1} }
+ \@@_use_i_delimit_by_s_stop:nw
+ \fi:
+ \exp_after:wN \@@_generate_variant:w
+ \tl_to_str:n {#5} , \scan_stop: , \q_@@_recursion_stop
+ \@@_use_none_delimit_by_s_stop:w \s_@@_mark {#1} {#2} {#4} \s_@@_stop
+ }
+\cs_new_protected:Npn \@@_generate_variant:w
+ #1 , #2 \s_@@_mark #3#4#5
+ {
+ \if_meaning:w \scan_stop: #1 \scan_stop:
+ \if_meaning:w \q_@@_nil #1 \q_@@_nil
+ \use_i:nnn
+ \fi:
+ \exp_after:wN \@@_use_none_delimit_by_q_recursion_stop:w
+ \else:
+ \cs_if_exist_use:cTF { @@_generate_variant_#1_form:nnn }
+ { {#3} {#4} {#5} }
+ {
+ \msg_error:nnee
+ { kernel } { conditional-form-unknown }
+ {#1} { \token_to_str:c { #3 : #4 } }
+ }
+ \fi:
+ \@@_generate_variant:w #2 \s_@@_mark {#3} {#4} {#5}
+ }
+\cs_new_protected:Npn \@@_generate_variant_p_form:nnn #1#2
+ { \cs_generate_variant:cn { #1 _p : #2 } }
+\cs_new_protected:Npn \@@_generate_variant_T_form:nnn #1#2
+ { \cs_generate_variant:cn { #1 : #2 T } }
+\cs_new_protected:Npn \@@_generate_variant_F_form:nnn #1#2
+ { \cs_generate_variant:cn { #1 : #2 F } }
+\cs_new_protected:Npn \@@_generate_variant_TF_form:nnn #1#2
+ { \cs_generate_variant:cn { #1 : #2 TF } }
+% \end{macrocode}
+% \end{macro}
+%
+% \begin{macro}{\exp_args_generate:n}
+% This function is not used in the kernel hence we can use functions
+% that are defined in later modules. It also does not need to be fast
+% so use inline mappings. For each requested variant we check that
+% there are no characters besides |NnpcofVvx|, in particular that
+% there are no spaces. Then we just call the internal function.
+% \begin{macrocode}
+\cs_new_protected:Npn \exp_args_generate:n #1
+ {
+ \exp_args:No \clist_map_inline:nn { \tl_to_str:n {#1} }
+ {
+ \str_map_inline:nn {##1}
+ {
+ \str_if_in:nnF { NnpcofeVvx } {####1}
+ {
+ \msg_error:nnnn { kernel } { invalid-exp-args }
+ {####1} {##1}
+ \str_map_break:n { \use_none:nn }
+ }
+ }
+ \@@_generate_internal_variant:n {##1}
+ }
+ }
+% \end{macrocode}
+% \end{macro}
+%
+% \subsection{Definitions with the automated technique}
+% \label{sec:l3expan:gendef}
+%
+% Some of these could be done more efficiently, but the complexity of
+% coding then becomes an issue. Notice that the auto-generated functions
+% actually take no arguments themselves.
+%
+% \begin{macro}[EXP]
+% {
+% \exp_args:Nnc, \exp_args:Nno, \exp_args:NnV, \exp_args:Nnv, \exp_args:Nne, \exp_args:Nnf,
+% \exp_args:Noc, \exp_args:Noo, \exp_args:Nof,
+% \exp_args:NVo, \exp_args:Nfo, \exp_args:Nff, \exp_args:Nee
+% }
+% \begin{macro}
+% {
+% \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. The group is used because
+% \cs{@@_generate_internal_variant:n} redefines \cs{@@_tmp:w} locally.
+% \begin{macrocode}
+\cs_set_protected:Npn \@@_tmp:w #1
+ {
+ \group_begin:
+ \exp_args:No \@@_generate_internal_variant:n
+ { \tl_to_str:n {#1} }
+ \group_end:
+ }
+\@@_tmp:w { nc }
+\@@_tmp:w { no }
+\@@_tmp:w { nV }
+\@@_tmp:w { nv }
+\@@_tmp:w { ne }
+\@@_tmp:w { nf }
+\@@_tmp:w { oc }
+\@@_tmp:w { oo }
+\@@_tmp:w { of }
+\@@_tmp:w { Vo }
+\@@_tmp:w { fo }
+\@@_tmp:w { ff }
+\@@_tmp:w { ee }
+\@@_tmp:w { Nx }
+\@@_tmp:w { cx }
+\@@_tmp:w { nx }
+\@@_tmp:w { ox }
+\@@_tmp:w { xo }
+\@@_tmp:w { xx }
+% \end{macrocode}
+% \end{macro}
+% \end{macro}
+%
+% \begin{macro}[EXP]
+% {
+% \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, \exp_args:Neee
+% }
+% \begin{macro}
+% {
+% \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}
+\@@_tmp:w { Ncf }
+\@@_tmp:w { Nno }
+\@@_tmp:w { NnV }
+\@@_tmp:w { Noo }
+\@@_tmp:w { NVV }
+\@@_tmp:w { cno }
+\@@_tmp:w { cnV }
+\@@_tmp:w { coo }
+\@@_tmp:w { cVV }
+\@@_tmp:w { nnc }
+\@@_tmp:w { nno }
+\@@_tmp:w { nnf }
+\@@_tmp:w { nff }
+\@@_tmp:w { ooo }
+\@@_tmp:w { oof }
+\@@_tmp:w { ffo }
+\@@_tmp:w { eee }
+\@@_tmp:w { NNx }
+\@@_tmp:w { Nnx }
+\@@_tmp:w { Nox }
+\@@_tmp:w { nnx }
+\@@_tmp:w { nox }
+\@@_tmp:w { ccx }
+\@@_tmp:w { cnx }
+\@@_tmp:w { oox }
+% \end{macrocode}
+% \end{macro}
+% \end{macro}
+%
+% \subsection{Held-over variant generation}
+%
+% \begin{macro}[documented-as = \cs_generate_from_arg_count:NNnn]
+% {\cs_generate_from_arg_count:NNno}
+% \begin{macro}[documented-as = \cs_replacement_spec:N]{\cs_replacement_spec:c}
+% A couple of variants that are from early functions.
+% \begin{macrocode}
+\cs_generate_variant:Nn \cs_generate_from_arg_count:NNnn { NNno }
+\cs_generate_variant:Nn \cs_replacement_spec:N { c }
+% \end{macrocode}
+% \end{macro}
+% \end{macro}
+%
+% \begin{macrocode}
+%</package>
+% \end{macrocode}
+%
+% \end{implementation}
+%
+% \PrintIndex