% \iffalse meta-comment % %% File: l3expan.dtx Copyright (C) 1990-2014 The LaTeX3 project %% %% It may be distributed and/or modified under the conditions of the %% LaTeX Project Public License (LPPL), either version 1.3c of this %% license or (at your option) any later version. The latest version %% of this license is in the file %% %% http://www.latex-project.org/lppl.txt %% %% This file is part of the "l3kernel bundle" (The Work in LPPL) %% and all files in that bundle must be distributed together. %% %% The released version of this bundle is available from CTAN. %% %% ----------------------------------------------------------------------- %% %% The development version of the bundle can be found at %% %% http://www.latex-project.org/svnroot/experimental/trunk/ %% %% for those people who are interested. %% %%%%%%%%%%% %% NOTE: %% %%%%%%%%%%% %% %% Snapshots taken from the repository represent work in progress and may %% not work or may contain conflicting material! We therefore ask %% people _not_ to put them into distributions, archives, etc. without %% prior consultation with the LaTeX3 Project. %% %% ----------------------------------------------------------------------- % %<*driver> \documentclass[full]{l3doc} % %<*driver|package> \GetIdInfo$Id: l3expan.dtx 5472 2014-11-27 09:10:40Z joseph $ {L3 Argument expansion} % %<*driver> \begin{document} \DocInput{\jobname.dtx} \end{document} % % \fi % % \title{^^A % The \pkg{l3expan} package\\ Argument expansion^^A % \thanks{This file describes v\ExplFileVersion, % last revised \ExplFileDate.}^^A % } % % \author{^^A % The \LaTeX3 Project\thanks % {^^A % E-mail: % \href{mailto:latex-team@latex-project.org} % {latex-team@latex-project.org}^^A % }^^A % } % % \date{Released \ExplFileDate} % % \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 from the % |\exp_| module. 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} will expand 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_new_nopar:Npn \seq_gpush:No { \exp_args:NNo \seq_gpush:Nn }| % \end{quote} % Providing variants in this way in style files is uncritical as the % \cs{cs_new_nopar:Npn} function will silently accept definitions whenever the % new definition is identical to an already given one. 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} % % \begin{function}[updated = 2013-07-09]{\cs_generate_variant:Nn} % \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} where these are not already % defined. For each \meta{variant} given, a function is created % which will expand its arguments as detailed and pass 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} % will create a new function \cs{foo:cn} which will expand its first % argument into a control sequence name and pass the result to % \cs{foo:Nn}. Similarly % \begin{verbatim} % \cs_generate_variant:Nn \foo:Nn { NV , cV } % \end{verbatim} % would generate the functions \cs{foo:NV} and \cs{foo:cV} in the % same way. The \cs{cs_generate_variant:Nn} function can only be % applied if the \meta{parent control sequence} is already defined. If % the \meta{parent control sequence} is protected then the new sequence % will also be protected. The \meta{variant} is created globally, as % is any \cs{exp_args:N\meta{variant}} function needed to carry out % the expansion. % \end{function} % % \section{Introducing the variants} % % The available internal functions for argument expansion come in two % flavours, some of them are faster then others. Therefore it is usually % best to follow the following guidelines when defining new functions % that are supposed to come with variant forms: % \begin{itemize} % \item % Arguments that might need expansion should come first in the list of % arguments to make processing faster. % \item % Arguments that should consist of single tokens should come first. % \item % Arguments that need full expansion (\emph{i.e.}, are denoted % with |x|) should be avoided if possible as they can not be % processed expandably, \emph{i.e.}, functions of this type will % not work correctly in arguments that are themselves subject to |x| % expansion. % \item % In general, unless in the last position, multi-token arguments % |n|, |f|, and |o| will need special processing which is not fast. % Therefore it is best to use the optimized functions, namely % those that contain only |N|, |c|, |V|, and |v|, and, in the last % position, |o|, |f|, with possible trailing |N| or |n|, which are % not expanded. % \end{itemize} % % ^^A Bruno: We should drop part of that paragraph eventually. % The |V| type returns the value of a register, which can be one of % |tl|, |num|, |int|, |skip|, |dim|, |toks|, 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. This recent addition to the argument specifiers may shake % things up a bit as most places where |o| is used will be replaced by % |V|. The documentation you are currently reading will therefore % require a fair bit of re-writing. % % 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 |f| type is so special that it deserves an example. Let's pretend % we want to set the control sequence whose name is given by % |b \l_tmpa_tl b| equal to the list of tokens |\aaa a|. Furthermore we % want to store the execution of it in a % \meta{tl~var}. In this example we assume |\l_tmpa_tl| contains % the text string |lur|. The straightforward approach is % \begin{quote} % |\tl_set:No \l_tmpb_tl { \tl_set:cn { b \l_tmpa_tl b } { \aaa a } }| % \end{quote} % Unfortunately this only puts % |\exp_args:Nc \tl_set:Nn {b \l_tmpa_tl b} { \aaa a }| into % |\l_tmpb_tl| and not |\tl_set:Nn \blurb { \aaa a }| as we probably % wanted. Using \cs{tl_set:Nx} is not an option as that will die % horribly. Instead we can do a % \begin{quote} % |\tl_set:Nf \l_tmpb_tl { \tl_set:cn { b \l_tmpa_tl b } { \aaa a } }| % \end{quote} % which puts the desired result in |\l_tmpb_tl|. It requires % \cs{tl_set:Nf} to be defined as % \begin{quote} % |\cs_set_nopar:Npn \tl_set:Nf { \exp_args:NNf \tl_set:Nn }| % \end{quote} % If you use this type of expansion in conditional processing then % you should stick to using |TF| type functions only as it does not % try to finish any |\if... \fi:| itself! % % If is important to not that both \texttt{f}- and \texttt{o}-type % 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 \exp_after:wN { } % \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 { { \l_tmpa_tl } } % \end{verbatim} % and % \begin{verbatim} % \tl_set:Nf \l_tmpa_tl { { \l_tmpa_tl } } % \end{verbatim} % leave |\l_tmpa_tl| unchanged: |{| is the first token in the % argument and is non-expandable. % % \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: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 will be left unchanged. % \end{function} % % \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. (An internal error % will occur if such a conversion is not possible). The result % is inserted into the input stream \emph{after} reinsertion % of the \meta{function}. Thus the \meta{function} may take more than % one argument: all others will be 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: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 will be 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. (An internal error % will occur if such a conversion is not possible). This control sequence % should % be the name of a \meta{variable}. The content of the \meta{variable} are % recovered and placed inside braces into the input stream \emph{after} % reinsertion of the \meta{function}. Thus the \meta{function} may take more % than one argument: all others will be 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 or space is found, 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 will be 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} % second. 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 will be left unchanged. % \end{function} % % \section{Manipulating two arguments} % % \begin{function}[EXP] % { % \exp_args:NNo, % \exp_args:NNc, % \exp_args:NNv, % \exp_args:NNV, % \exp_args:NNf, % \exp_args:Nco, % \exp_args:Ncf, % \exp_args:Ncc, % \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 = 2012-01-14] % { % \exp_args:Nno, % \exp_args:NnV, % \exp_args:Nnf, % \exp_args:Noo, % \exp_args:Nof, % \exp_args:Noc, % \exp_args:Nff, % \exp_args:Nfo, % \exp_args:Nnc % } % \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. % These functions need special (slower) processing. % \end{function} % % \begin{function} % { % \exp_args:NNx, % \exp_args:Nnx, % \exp_args:Ncx, % \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. % \end{function} % % \section{Manipulating three arguments} % % \begin{function}[EXP] % { % \exp_args:NNNo, % \exp_args:NNNV, % \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:NNoo, % \exp_args:NNno, % \exp_args:Nnno, % \exp_args:Nnnc, % \exp_args:Nooo, % } % \begin{syntax} % \cs{exp_args:NNNo} \meta{token_1} \meta{token_2} \meta{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}. % These functions need special (slower) processing. % \end{function} % % \begin{function} % { % \exp_args:NNnx, % \exp_args:NNox, % \exp_args:Nnnx, % \exp_args:Nnox, % \exp_args:Noox, % \exp_args:Ncnx, % \exp_args:Nccx % } % \begin{syntax} % \cs{exp_args:NNnx} \meta{token_1} \meta{token_2} \Arg{tokens_1} \Arg{tokens_2} % \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 = 2012-02-12] % { % \exp_last_unbraced:Nf, % \exp_last_unbraced:NV, % \exp_last_unbraced:No, % \exp_last_unbraced:Nv, % \exp_last_unbraced:Nco, % \exp_last_unbraced:NcV, % \exp_last_unbraced:NNV, % \exp_last_unbraced:NNo, % \exp_last_unbraced:Nno, % \exp_last_unbraced:Noo, % \exp_last_unbraced:Nfo, % \exp_last_unbraced:NNNV, % \exp_last_unbraced:NNNo, % \exp_last_unbraced:NnNo % } % \begin{syntax} % \cs{exp_last_unbraced:Nno} \meta{token} \meta{tokens_1} \meta{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 \texttt{:Nno}, \texttt{:Noo}, and \texttt{:Nfo} % variants need special (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} \cs{mypkg_foo: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 functions fully expands the \meta{tokens} and leaves % the result in the input stream after reinsertion of \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} \meta{tokens_1} \Arg{tokens_2} % \end{syntax} % This function absorbs three arguments and expand 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} is a \TeX{} primitive, it will % be executed rather than expanded, while if \meta{token_2} has not % expansion (for example, if it is a character) then it will be 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, expansion should be carried out using an % appropriate argument specifier variant or the appropriate % \cs{exp_arg:N} function. % \begin{texnote} % This is the \TeX{} primitive \tn{expandafter} renamed. % \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 will not appear % 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 |x|-type argument. % \begin{texnote} % This is the \TeX{} \tn{noexpand} primitive. % \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 unexpandable content remains, and then % converts this into a control sequence. Further expansion of this control % sequence is then inhibited. % \end{function} % % \begin{function}[EXP]{\exp_not:n} % \begin{syntax} % \cs{exp_not:n} \Arg{tokens} % \end{syntax} % Prevents expansion of the \meta{tokens} in a context where they % would otherwise be expanded, for example an |x|-type argument. % \begin{texnote} % This is the \eTeX{} \tn{unexpanded} primitive. Hence its argument % \emph{must} be surrounded by braces. % \end{texnote} % \end{function} % % \begin{function}[EXP]{\exp_not:V} % \begin{syntax} % \cs{exp_not:V} \meta{variable} % \end{syntax} % Recovers the content of the \meta{variable}, then prevents expansion % of this material in a context where it would otherwise % be expanded, for example an |x|-type argument. % \end{function} % % \begin{function}[EXP]{\exp_not:v} % \begin{syntax} % \cs{exp_not:v} \Arg{tokens} % \end{syntax} % Expands the \meta{tokens} until only unexpandable content remains, and then % converts this into a control sequence (which should be a \meta{variable} % name). The content of the \meta{variable} is recovered, and further % expansion is prevented in a context where it would otherwise % be expanded, for example an |x|-type argument. % \end{function} % % \begin{function}[EXP]{\exp_not:o} % \begin{syntax} % \cs{exp_not:o} \Arg{tokens} % \end{syntax} % Expands the \meta{tokens} once, then prevents any further expansion in a % context where they would otherwise % be expanded, for example an |x|-type argument. % \end{function} % % \begin{function}[EXP]{\exp_not:f} % \begin{syntax} % \cs{exp_not:f} \Arg{tokens} % \end{syntax} % Expands \meta{tokens} fully until the first unexpandable token % is found. Expansion then stops, and the result of the expansion % (including any tokens which were not expanded) is protected from % further expansion. % \end{function} % % \begin{function}[updated = 2011-06-03, EXP]{\exp_stop_f:} % \begin{syntax} % \cs{function:f} \meta{tokens} \cs{exp_stop_f:} \meta{more tokens} % \end{syntax} % This function terminates an \texttt{f}-type expansion. Thus if % a function |\function:f| starts an \texttt{f}-type expansion % and all of \meta{tokens} are expandable \cs{exp_stop_f:} will % terminate the expansion of tokens even if \meta{more tokens} % are also expandable. The function itself is an implicit space % token. Inside an \texttt{x}-type expansion, it will retain its % form, but when typeset it produces the underlying space (\verb*| |). % \end{function} % % \section{Internal functions and variables} % % \begin{variable}{\l__exp_internal_tl} % The |\exp_| module has its private variables to temporarily store % results of the argument expansion. This is done to avoid interference % with other functions using temporary variables. % \end{variable} % % \begin{function}{\::n, \::N, \::p, \::c, \::o, \::f, \::x, \::v, \::V, \:::} % \begin{syntax} % |\cs_set_nopar: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. % \end{function} % % \end{documentation} % % \begin{implementation} % % \section{\pkg{l3expan} implementation} % % \begin{macrocode} %<*initex|package> % \end{macrocode} % % \begin{macrocode} %<@@=exp> % \end{macrocode} % % \begin{macro}{\exp_after:wN} % \begin{macro}{\exp_not:N} % \begin{macro}{\exp_not:n} % These are defined in \pkg{l3basics}. % \end{macro} % \end{macro} % \end{macro} % % \subsection{General expansion} % % In this section a general mechanism for defining functions to handle % argument handling is defined. These general expansion functions are % expandable unless |x| is used. (Any version of |x| is going to have % to use one of the \LaTeX3 names for \cs{cs_set_nopar: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}, as it % is needed \enquote{early}. This is just a reminder that is the % case! % \end{variable} % % This code uses internal functions with names that start with |\::| % to perform the expansions. All macros are |long| as this turned out % to be desirable since the tokens undergoing expansion may be % arbitrary user input. % % 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}[aux, EXP]{\@@_arg_next:nnn} % \begin{macro}[aux, 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 will require % 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}[int]{\:::} % The end marker is just another name for the identity function. % \begin{macrocode} \cs_new:Npn \::: #1 {#1} % \end{macrocode} % \end{macro} % % \begin{macro}[int, EXP]{\::n} % 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}[int, 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}[int, EXP]{\::p} % This function is used to skip an argument that is delimited by a % left brace and doesn't need to be expanded. It should not be % wrapped in braces in the result. % \begin{macrocode} \cs_new:Npn \::p #1 \::: #2#3# { #1 \::: {#2#3} } % \end{macrocode} % \end{macro} % % \begin{macro}[int, EXP]{\::c} % 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}[int, 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}[int, EXP]{\::f} % \begin{macro}{\exp_stop_f:} % This function is used to expand a token list until the first % unexpandable token is found. The underlying \tn{romannumeral} |-`0| % expands everything in its way to find something terminating the % number and thereby expands the function in front of it. This % scanning procedure is terminated once the expansion hits % something non-expandable or a space. We introduce \cs{exp_stop_f:} % to mark such an end of expansion marker; in case the scanner hits % a number, this number also terminates the scanning and is left % untouched. In the example shown earlier the scanning was stopped % once \TeX{} had fully expanded |\cs_set_eq:Nc \aaa { b \l_tmpa_tl b }| % into |\cs_set_eq:NN \aaa = \blurb| which then turned out to contain % the non-expandable token \cs{cs_set_eq:NN}. Since the expansion of % \tn{romannumeral} |-`0| is \meta{null}, we wind up with a fully % expanded list, only \TeX{} has not tried to execute any of the % non-expandable tokens. This is what differentiates this function % from the |x| argument type. % \begin{macrocode} \cs_new:Npn \::f #1 \::: #2#3 { \exp_after:wN \@@_arg_next:nnn \exp_after:wN { \tex_romannumeral:D -`0 #3 } {#1} {#2} } \use:nn { \cs_new_eq:NN \exp_stop_f: } { ~ } % \end{macrocode} % \end{macro} % \end{macro} % % \begin{macro}[int]{\::x} % This function is used to expand an argument fully. % \begin{macrocode} \cs_new_protected:Npn \::x #1 \::: #2#3 { \cs_set_nopar:Npx \l_@@_internal_tl { {#3} } \exp_after:wN \@@_arg_next:nnn \l_@@_internal_tl {#1} {#2} } % \end{macrocode} % \end{macro} % % \begin{macro}[int, EXP]{\::v} % \begin{macro}[int, EXP]{\::V} % These functions return the value of a register, i.e., one of % |tl|, |clist|, |int|, |skip|, |dim| and |muskip|. The |V| version % expects a single token whereas |v| like |c| creates a csname from % its argument given in braces and then evaluates it as if it was a % |V|. The primitive \tn{romannumeral} sets off an expansion % similar to an |f| type expansion, which we will terminate using % \cs{c_zero}. The argument is returned in braces. % \begin{macrocode} \cs_new:Npn \::V #1 \::: #2#3 { \exp_after:wN \@@_arg_next:nnn \exp_after:wN { \tex_romannumeral:D \@@_eval_register:N #3 } {#1} {#2} } \cs_new:Npn \::v # 1\::: #2#3 { \exp_after:wN \@@_arg_next:nnn \exp_after:wN { \tex_romannumeral:D \@@_eval_register:c {#3} } {#1} {#2} } % \end{macrocode} % \end{macro} % \end{macro} % % \begin{macro}[int, EXP]{\@@_eval_register:N, \@@_eval_register:c} % \begin{macro}[aux, 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 do here is try to find out % whether the token will expand to something else when hit with % \cs{exp_after:wN}. The technique is to compare the meaning of the % register in question when it has been prefixed with \cs{exp_not:N} % and the register itself. If it is a macro, the prefixed % \cs{exp_not:N} will temporarily turn 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 the primitive \tn{romannumeral} and we want to % terminate this expansion chain by inserting the \cs{c_zero} integer % constant. However, we have to expand the register |#1| before we do % that. If it is a \TeX{} register, we need to execute the sequence % |\exp_after:wN \c_zero \tex_the:D #1| and if it is a macro we % need to execute |\exp_after:wN \c_zero #1|. We therefore issue % the longer of the two sequences and if the register is a macro, we % remove the \cs{tex_the:D}. % \begin{macrocode} \else: \exp_after:wN \use_i_ii:nnn \fi: \exp_after:wN \c_zero \tex_the:D #1 } \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. % \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_kernel_expandable_error:nnn { kernel } { bad-variable } {#2} \c_zero } % \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 and therefore allow to prefix them with % \cs{tex_global:D} for example. % % \begin{macro}[EXP]{\exp_args:No} % \begin{macro}[EXP]{\exp_args:NNo} % \begin{macro}[EXP]{\exp_args:NNNo} % Those lovely runs of expansion! % \begin{macrocode} \cs_new:Npn \exp_args:No #1#2 { \exp_after:wN #1 \exp_after:wN {#2} } \cs_new:Npn \exp_args:NNo #1#2#3 { \exp_after:wN #1 \exp_after:wN #2 \exp_after:wN {#3} } \cs_new:Npn \exp_args:NNNo #1#2#3#4 { \exp_after:wN #1 \exp_after:wN#2 \exp_after:wN #3 \exp_after:wN {#4} } % \end{macrocode} % \end{macro} % \end{macro} % \end{macro} % % \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:Nf, \exp_args:NV, \exp_args:Nv} % \begin{macrocode} \cs_new:Npn \exp_args:Nf #1#2 { \exp_after:wN #1 \exp_after:wN { \tex_romannumeral:D -`0 #2 } } \cs_new:Npn \exp_args:Nv #1#2 { \exp_after:wN #1 \exp_after:wN { \tex_romannumeral:D \@@_eval_register:c {#2} } } \cs_new:Npn \exp_args:NV #1#2 { \exp_after:wN #1 \exp_after:wN { \tex_romannumeral:D \@@_eval_register:N #2 } } % \end{macrocode} % \end{macro} % % \begin{macro}[EXP] % { % \exp_args:NNV,\exp_args:NNv,\exp_args:NNf, % \exp_args:NVV, % \exp_args:Ncf,\exp_args:Nco % } % Some more hand-tuned function with three arguments. % If we forced that an |o| argument always has braces, % we could implement \cs{exp_args:Nco} with less tokens % and only two arguments. % \begin{macrocode} \cs_new:Npn \exp_args:NNf #1#2#3 { \exp_after:wN #1 \exp_after:wN #2 \exp_after:wN { \tex_romannumeral:D -`0 #3 } } \cs_new:Npn \exp_args:NNv #1#2#3 { \exp_after:wN #1 \exp_after:wN #2 \exp_after:wN { \tex_romannumeral:D \@@_eval_register:c {#3} } } \cs_new:Npn \exp_args:NNV #1#2#3 { \exp_after:wN #1 \exp_after:wN #2 \exp_after:wN { \tex_romannumeral:D \@@_eval_register:N #3 } } \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:Ncf #1#2#3 { \exp_after:wN #1 \cs:w #2 \exp_after:wN \cs_end: \exp_after:wN { \tex_romannumeral:D -`0 #3 } } \cs_new:Npn \exp_args:NVV #1#2#3 { \exp_after:wN #1 \exp_after:wN { \tex_romannumeral:D \exp_after:wN \@@_eval_register:N \exp_after:wN #2 \exp_after:wN } \exp_after:wN { \tex_romannumeral:D \@@_eval_register:N #3 } } % \end{macrocode} % \end{macro} % % \begin{macro}[EXP] % { % \exp_args:Ncco, \exp_args:NcNc, \exp_args:NcNo, % \exp_args:NNNV % } % 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 { \tex_romannumeral:D \@@_eval_register:N #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} % % \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 % are all not long: they don't actually take any arguments themselves. % % \begin{macro}{\exp_args:Nx} % \begin{macrocode} \cs_new_protected_nopar:Npn \exp_args:Nx { \::x \::: } % \end{macrocode} % \end{macro} % % \begin{macro}[EXP] % { % \exp_args:Nnc,\exp_args:Nfo,\exp_args:Nff,\exp_args:Nnf, % \exp_args:Nno,\exp_args:NnV,\exp_args:Noo,\exp_args:Nof, % \exp_args:Noc % } % \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. % \begin{macrocode} \cs_new_nopar:Npn \exp_args:Nnc { \::n \::c \::: } \cs_new_nopar:Npn \exp_args:Nfo { \::f \::o \::: } \cs_new_nopar:Npn \exp_args:Nff { \::f \::f \::: } \cs_new_nopar:Npn \exp_args:Nnf { \::n \::f \::: } \cs_new_nopar:Npn \exp_args:Nno { \::n \::o \::: } \cs_new_nopar:Npn \exp_args:NnV { \::n \::V \::: } \cs_new_nopar:Npn \exp_args:Noo { \::o \::o \::: } \cs_new_nopar:Npn \exp_args:Nof { \::o \::f \::: } \cs_new_nopar:Npn \exp_args:Noc { \::o \::c \::: } \cs_new_protected_nopar:Npn \exp_args:NNx { \::N \::x \::: } \cs_new_protected_nopar:Npn \exp_args:Ncx { \::c \::x \::: } \cs_new_protected_nopar:Npn \exp_args:Nnx { \::n \::x \::: } \cs_new_protected_nopar:Npn \exp_args:Nox { \::o \::x \::: } \cs_new_protected_nopar:Npn \exp_args:Nxo { \::x \::o \::: } \cs_new_protected_nopar:Npn \exp_args:Nxx { \::x \::x \::: } % \end{macrocode} % \end{macro} % \end{macro} % % \begin{macro}[EXP] % { % \exp_args:NNno,\exp_args:NNoo, % \exp_args:Nnnc,\exp_args:Nnno,\exp_args:Nooo, % } % \begin{macro} % { % \exp_args:NNnx,\exp_args:NNox,\exp_args:Nnnx,\exp_args:Nnox, % \exp_args:Nccx,\exp_args:Ncnx,\exp_args:Noox, % } % \begin{macrocode} \cs_new_nopar:Npn \exp_args:NNno { \::N \::n \::o \::: } \cs_new_nopar:Npn \exp_args:NNoo { \::N \::o \::o \::: } \cs_new_nopar:Npn \exp_args:Nnnc { \::n \::n \::c \::: } \cs_new_nopar:Npn \exp_args:Nnno { \::n \::n \::o \::: } \cs_new_nopar:Npn \exp_args:Nooo { \::o \::o \::o \::: } \cs_new_protected_nopar:Npn \exp_args:NNnx { \::N \::n \::x \::: } \cs_new_protected_nopar:Npn \exp_args:NNox { \::N \::o \::x \::: } \cs_new_protected_nopar:Npn \exp_args:Nnnx { \::n \::n \::x \::: } \cs_new_protected_nopar:Npn \exp_args:Nnox { \::n \::o \::x \::: } \cs_new_protected_nopar:Npn \exp_args:Nccx { \::c \::c \::x \::: } \cs_new_protected_nopar:Npn \exp_args:Ncnx { \::c \::n \::x \::: } \cs_new_protected_nopar:Npn \exp_args:Noox { \::o \::o \::x \::: } % \end{macrocode} % \end{macro} % \end{macro} % % \subsection{Last-unbraced versions} % % \begin{macro}[aux, EXP]{\@@_arg_last_unbraced:nn} % \begin{macro}[aux, EXP]{\::f_unbraced} % \begin{macro}[aux, EXP]{\::o_unbraced} % \begin{macro}[aux, EXP]{\::V_unbraced} % \begin{macro}[aux, EXP]{\::v_unbraced} % \begin{macro}[aux, EXP]{\::x_unbraced} % There are a few places where the last argument needs to be available % unbraced. First some helper macros. % \begin{macrocode} \cs_new:Npn \@@_arg_last_unbraced:nn #1#2 { #2#1 } \cs_new:Npn \::f_unbraced \::: #1#2 { \exp_after:wN \@@_arg_last_unbraced:nn \exp_after:wN { \tex_romannumeral:D -`0 #2 } {#1} } \cs_new:Npn \::o_unbraced \::: #1#2 { \exp_after:wN \@@_arg_last_unbraced:nn \exp_after:wN {#2} {#1} } \cs_new:Npn \::V_unbraced \::: #1#2 { \exp_after:wN \@@_arg_last_unbraced:nn \exp_after:wN { \tex_romannumeral:D \@@_eval_register:N #2 } {#1} } \cs_new:Npn \::v_unbraced \::: #1#2 { \exp_after:wN \@@_arg_last_unbraced:nn \exp_after:wN { \tex_romannumeral:D \@@_eval_register:c {#2} } {#1} } \cs_new_protected:Npn \::x_unbraced \::: #1#2 { \cs_set_nopar:Npx \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} % % \begin{macro}[EXP]{\exp_last_unbraced:NV} % \begin{macro}[EXP]{\exp_last_unbraced:Nv} % \begin{macro}[EXP]{\exp_last_unbraced:Nf} % \begin{macro}[EXP]{\exp_last_unbraced:No} % \begin{macro}[EXP]{\exp_last_unbraced:Nco} % \begin{macro}[EXP]{\exp_last_unbraced:NcV} % \begin{macro}[EXP]{\exp_last_unbraced:NNV} % \begin{macro}[EXP]{\exp_last_unbraced:NNo} % \begin{macro}[EXP]{\exp_last_unbraced:NNNV} % \begin{macro}[EXP]{\exp_last_unbraced:NNNo} % \begin{macro}[EXP]{\exp_last_unbraced:Nno} % \begin{macro}[EXP]{\exp_last_unbraced:Noo} % \begin{macro}[EXP]{\exp_last_unbraced:Nfo} % \begin{macro}[EXP]{\exp_last_unbraced:NnNo} % \begin{macro}{\exp_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:NV #1#2 { \exp_after:wN #1 \tex_romannumeral:D \@@_eval_register:N #2 } \cs_new:Npn \exp_last_unbraced:Nv #1#2 { \exp_after:wN #1 \tex_romannumeral:D \@@_eval_register:c {#2} } \cs_new:Npn \exp_last_unbraced:No #1#2 { \exp_after:wN #1 #2 } \cs_new:Npn \exp_last_unbraced:Nf #1#2 { \exp_after:wN #1 \tex_romannumeral:D -`0 #2 } \cs_new:Npn \exp_last_unbraced:Nco #1#2#3 { \exp_after:wN #1 \cs:w #2 \exp_after:wN \cs_end: #3 } \cs_new:Npn \exp_last_unbraced:NcV #1#2#3 { \exp_after:wN #1 \cs:w #2 \exp_after:wN \cs_end: \tex_romannumeral:D \@@_eval_register:N #3 } \cs_new:Npn \exp_last_unbraced:NNV #1#2#3 { \exp_after:wN #1 \exp_after:wN #2 \tex_romannumeral:D \@@_eval_register:N #3 } \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:NNNV #1#2#3#4 { \exp_after:wN #1 \exp_after:wN #2 \exp_after:wN #3 \tex_romannumeral:D \@@_eval_register:N #4 } \cs_new:Npn \exp_last_unbraced:NNNo #1#2#3#4 { \exp_after:wN #1 \exp_after:wN #2 \exp_after:wN #3 #4 } \cs_new_nopar:Npn \exp_last_unbraced:Nno { \::n \::o_unbraced \::: } \cs_new_nopar:Npn \exp_last_unbraced:Noo { \::o \::o_unbraced \::: } \cs_new_nopar:Npn \exp_last_unbraced:Nfo { \::f \::o_unbraced \::: } \cs_new_nopar:Npn \exp_last_unbraced:NnNo { \::n \::N \::o_unbraced \::: } \cs_new_protected_nopar:Npn \exp_last_unbraced:Nx { \::x_unbraced \::: } % \end{macrocode} % \end{macro} % \end{macro} % \end{macro} % \end{macro} % \end{macro} % \end{macro} % \end{macro} % \end{macro} % \end{macro} % \end{macro} % \end{macro} % \end{macro} % \end{macro} % \end{macro} % \end{macro} % % \begin{macro}[EXP]{\exp_last_two_unbraced:Noo} % \begin{macro}[EXP, aux]{\@@_last_two_unbraced:noN} % 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}[EXP]{\exp_not:o} % \begin{macro}[EXP]{\exp_not:c} % \begin{macro}[EXP]{\exp_not:f} % \begin{macro}[EXP]{\exp_not:V} % \begin{macro}[EXP]{\exp_not:v} % \begin{macrocode} \cs_new:Npn \exp_not:o #1 { \etex_unexpanded:D \exp_after:wN {#1} } \cs_new:Npn \exp_not:c #1 { \exp_after:wN \exp_not:N \cs:w #1 \cs_end: } \cs_new:Npn \exp_not:f #1 { \etex_unexpanded:D \exp_after:wN { \tex_romannumeral:D -`0 #1 } } \cs_new:Npn \exp_not:V #1 { \etex_unexpanded:D \exp_after:wN { \tex_romannumeral:D \@@_eval_register:N #1 } } \cs_new:Npn \exp_not:v #1 { \etex_unexpanded:D \exp_after:wN { \tex_romannumeral:D \@@_eval_register:c {#1} } } % \end{macrocode} % \end{macro} % \end{macro} % \end{macro} % \end{macro} % \end{macro} % % \subsection{Defining function variants} % % \begin{macrocode} %<@@=cs> % \end{macrocode} % % \begin{macro}{\cs_generate_variant:Nn} % \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_nopar:Npx} or \cs{cs_new_protected_nopar:Npx}, 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 { \__chk_if_exist_cs:N #1 \@@_generate_variant:N #1 \exp_after:wN \@@_split_function:NN \exp_after:wN #1 \exp_after:wN \@@_generate_variant:nnNN \exp_after:wN #1 \etex_detokenize:D {#2} , \scan_stop: , \q_recursion_stop } % \end{macrocode} % \end{macro} % % \begin{macro}[aux]{\@@_generate_variant:N} % \begin{macro}[aux]{\@@_generate_variant:ww, \@@_generate_variant:wwNw} % The goal here is to pick up protected parent functions. There are % four cases: the parent function can be a primitive or a macro, and % can be expandable or not. For non-expandable primitives, all % variants should be protected; skipping the \cs{else:} branch is safe % because all primitive \TeX{} conditionals are expandable. % % 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 fist 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{q_mark} is taken as an argument of the |wwNw| % auxiliary, and |#3| is \cs{cs_new_protected_nopar:Npx}, otherwise it % is \cs{cs_new_nopar:Npx}. % \begin{macrocode} \group_begin: \tex_catcode:D `\M = 12 \scan_stop: \tex_catcode:D `\A = 12 \scan_stop: \tex_catcode:D `\P = 12 \scan_stop: \tex_catcode:D `\R = 12 \scan_stop: \tex_lowercase:D { \group_end: \cs_new_protected:Npn \@@_generate_variant:N #1 { \exp_after:wN \if_meaning:w \exp_not:N #1 #1 \cs_set_eq:NN \@@_tmp:w \cs_new_protected_nopar:Npx \else: \exp_after:wN \@@_generate_variant:ww \token_to_meaning:N #1 MA \q_mark \q_mark \cs_new_protected_nopar:Npx PR \q_mark \cs_new_nopar:Npx \q_stop \fi: } \cs_new_protected:Npn \@@_generate_variant:ww #1 MA #2 \q_mark { \@@_generate_variant:wwNw #1 } \cs_new_protected:Npn \@@_generate_variant:wwNw #1 PR #2 \q_mark #3 #4 \q_stop { \cs_set_eq:NN \@@_tmp:w #3 } } % \end{macrocode} % \end{macro} % \end{macro} % % \begin{macro}[aux]{\@@_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_kernel_error:nnx { 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}[aux]{\@@_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}|, it % would be better to define |\foo:xxTF| using |\exp_args:Nxx|, % rather than a hypothetical |\exp_args:NxxTF|. Thus, we wish to % trim a common trailing part from the base signature and the % variant signature. % \item In \cs{cs_generate_variant:Nn} |\foo:on| |{ox}|, the % function |\foo:ox| should be defined using |\exp_args:Nnx|, not % |\exp_args:Nox|, to avoid double |o| expansion. % \item Lastly, \cs{cs_generate_variant:Nn} |\foo:on| |{xn}| should % trigger an error, because we do not have a means to replace % |o|-expansion by |x|-expansion. % \end{itemize} % All this boils down to a few rules. Only |n| and |N|-type % arguments can be replaced by \cs{cs_generate_variant:Nn}. Other % argument types are allowed to be passed unchanged from the base % form to the variant: in the process they are changed to |n| % (except for two cases: |N| and |p|-type arguments). A common % trailing part is ignored. % % We compare the base and variant signatures one character at a time % within |x|-expansion. The result is given to % \cs{@@_generate_variant:wwNN} in the form \meta{processed variant % signature} \cs{q_mark} \meta{errors} \cs{q_stop} \meta{base % function} \meta{new function}. If all went well, \meta{errors} % is empty; otherwise, it is a kernel error message, followed by % some clean-up code (\cs{use_none:nnnn}). % % 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:x { \exp_not:N \@@_generate_variant:wwNN \@@_generate_variant_loop:nNwN { } #4 \@@_generate_variant_loop_end:nwwwNNnn \q_mark #3 ~ { ~ { } \fi: \@@_generate_variant_loop_long:wNNnn } ~ { } \q_stop \exp_not:N #1 {#2} {#4} } \@@_generate_variant:Nnnw #1 {#2} {#3} } % \end{macrocode} % \end{macro} % % \begin{macro}[aux, EXP] % { % \@@_generate_variant_loop:nNwN, % \@@_generate_variant_loop_same:w, % \@@_generate_variant_loop_end:nwwwNNnn, % \@@_generate_variant_loop_long:wNNnn, % \@@_generate_variant_loop_invalid:NNwNNnn, % } % \begin{arguments} % \item Last few (consecutive) letters common between the base % and variant (in fact, \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 with a % base letter of |N| or |n|. Otherwise, call % \cs{@@_generate_variant_loop_invalid:NNwNNnn} to remove the end of % the loop, get arguments at the end of the loop, and place an % appropriate error message as a second argument of % \cs{@@_generate_variant:wwNN}. If the letters are distinct and % the base letter is indeed |n| or |N|, leave in the input stream % whatever argument was collected, and the next variant letter |#2|, % then loop by calling \cs{@@_generate_variant_loop:nNwN}. % % 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 neither |n| nor |N|. Again, 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 \q_mark #4 { \if:w #2 #4 \exp_after:wN \@@_generate_variant_loop_same:w \else: \if:w N #4 \else: \if:w n #4 \else: \@@_generate_variant_loop_invalid:NNwNNnn #4#2 \fi: \fi: \fi: #1 \prg_do_nothing: #2 \@@_generate_variant_loop:nNwN { } #3 \q_mark } \cs_new:Npn \@@_generate_variant_loop_same:w #1 \prg_do_nothing: #2#3#4 { #3 { #1 \@@_generate_variant_same:N #2 } } \cs_new:Npn \@@_generate_variant_loop_end:nwwwNNnn #1#2 \q_mark #3 ~ #4 \q_stop #5#6#7#8 { \scan_stop: \scan_stop: \fi: \exp_not:N \q_mark \exp_not:N \q_stop \exp_not:N #6 \exp_not:c { #7 : #8 #1 #3 } } \cs_new:Npn \@@_generate_variant_loop_long:wNNnn #1 \q_stop #2#3#4#5 { \exp_not:n { \q_mark \__msg_kernel_error:nnxx { kernel } { variant-too-long } {#5} { \token_to_str:N #3 } \use_none:nnnn \q_stop #3 #3 } } \cs_new:Npn \@@_generate_variant_loop_invalid:NNwNNnn #1#2 \fi: \fi: \fi: #3 \q_stop #4#5#6#7 { \fi: \fi: \fi: \exp_not:n { \q_mark \__msg_kernel_error:nnxxxx { kernel } { invalid-variant } {#7} { \token_to_str:N #5 } {#1} {#2} \use_none:nnnn \q_stop #5 #5 } } % \end{macrocode} % \end{macro} % % \begin{macro}[aux, 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. % \begin{macrocode} \cs_new:Npn \@@_generate_variant_same:N #1 { \if:w N #1 N \else: \if:w p #1 p \else: n \fi: \fi: } % \end{macrocode} % \end{macro} % % \begin{macro}[aux]{\@@_generate_variant:wwNN} % If the variant form has already been defined, log its existence. % 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_nopar:Npx}. 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 \q_mark #2 \q_stop #3#4 { #2 \cs_if_free:NTF #4 { \group_begin: \@@_generate_internal_variant:n {#1} \@@_tmp:w #4 { \exp_not:c { exp_args:N #1 } \exp_not:N #3 } \group_end: } { \iow_log:x { Variant~\token_to_str:N #4~% already~defined;~ not~ changing~ it~on~line~% \tex_the:D \tex_inputlineno:D } } } % \end{macrocode} % \end{macro} % % \begin{macro}[int]{\@@_generate_internal_variant:n} % \begin{macro}[aux]{\@@_generate_internal_variant:wwnw} % \begin{macro}[aux, rEXP]{\@@_generate_internal_variant_loop:n} % Test if |\exp_args:N #1| is already defined and if not define it via % the |\::| commands using the chars in |#1|. If |#1| contains an |x| % (this is the place where having converted the original comma-list % argument to a string is very important), the result should be % protected, and the next variant to be defined using that internal % variant should be protected. % \begin{macrocode} \group_begin: \tex_catcode:D `\X = 12 \scan_stop: \tex_lccode:D `\N = `\N \scan_stop: \tex_lowercase:D { \group_end: \cs_new_protected:Npn \@@_generate_internal_variant:n #1 { \@@_generate_internal_variant:wwnNwnn #1 \q_mark { \cs_set_eq:NN \@@_tmp:w \cs_new_protected_nopar:Npx } \cs_new_protected_nopar:cpx X \q_mark { } \cs_new_nopar:cpx \q_stop { exp_args:N #1 } { \@@_generate_internal_variant_loop:n #1 { : \use_i:nn } } } \cs_new_protected:Npn \@@_generate_internal_variant:wwnNwnn #1 X #2 \q_mark #3 #4 #5 \q_stop #6 #7 { #3 \cs_if_free:cT {#6} { #4 {#6} {#7} } } } % \end{macrocode} % This command grabs char by char outputting |\::#1| (not expanded % further). We avoid tests by putting a trailing |: \use_i:nn|, which % 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} % \end{macro} % % \begin{macrocode} % % \end{macrocode} % % \end{implementation} % % \PrintIndex