% \iffalse meta-comment
%
%% File: l3expan.dtx
%
% Copyright (C) 1990-2025 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 2025-01-18}
%
% \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
%   ignored. 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,
%     \@@_generate_variant_check:nn
%   }
%    \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
  { \@@_generate_variant_check:nn { #1 _p : #2 } }
\cs_new_protected:Npn \@@_generate_variant_T_form:nnn #1#2
  { \@@_generate_variant_check:nn { #1 : #2 T } }
\cs_new_protected:Npn \@@_generate_variant_F_form:nnn #1#2
  { \@@_generate_variant_check:nn { #1 : #2 F } }
\cs_new_protected:Npn \@@_generate_variant_TF_form:nnn #1#2
  { \@@_generate_variant_check:nn { #1 : #2 TF } }
\cs_new_protected:Npn \@@_generate_variant_check:nn #1#2
  {
    \cs_if_exist:cTF {#1}
      { \cs_generate_variant:cn {#1} {#2} }
      {
        \msg_error:nne
          { kernel } { conditional-base-undefined }
            { \token_to_str:c {#1} }
      }
  }
%    \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