% \iffalse %% File: l3expan.dtx Copyright (C) 1990-2010 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 ``expl3 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 LaTeX Project Team. %% %% ----------------------------------------------------------------------- % %<*driver|package> \RequirePackage{l3names} % %\fi \GetIdInfo$Id: l3expan.dtx 2037 2010-09-20 21:22:45Z joseph $ {L3 Experimental Argument Expansion module} %\iffalse %<*driver> %\fi \ProvidesFile{\filename.\filenameext} [\filedate\space v\fileversion\space\filedescription] %\iffalse \documentclass[full]{l3doc} \begin{document} \DocInput{l3expan.dtx} \end{document} % % \fi % % % \title{The \pkg{l3expan} package\thanks{This file % has version number \fileversion, last % revised \filedate.}\\ % Controlling Expansion of Function Arguments} % \author{\Team} % \date{\filedate} % \maketitle % % \begin{documentation} % % \section{Brief overview} % % 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} % % 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 % "\exp_args:NNo". This function has three arguments, the first and the % second are a single tokens the third argument gets % expanded once. If "\seq_gpush:No" wouldn't be defined the example % above 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 "\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, 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_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_generate_variant:Nn", described next. % % \subsection{Methods for defining variants} % % %\begin{function}{ \cs_generate_variant:Nn } % \begin{syntax} % \cs{cs_generate_variant:Nn} \meta{parent control sequence} % ~~\Arg{variant argument specifier} % \end{syntax} % The \meta{parent control sequence} is first separated into the % \meta{base name} and \meta{original} argument specifier. The % \meta{variant} is then used to modify this by replacing the beginning % of the \meta{original} with the \meta{variant}. Thus the \meta{variant} % must be no longer than the \meta{original} argument specifier. This % new specifier is used to create a modified function which will expand % its arguments as required. 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 } % \cs_generate_variant:Nn \foo:Nn { cV } % \end{verbatim} % would generate the functions \cs{foo:NV} and \cs{foo:cV} in the % same way. \cs{cs_generate_variant:Nn} 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 variants are generated globally. %\end{function} % % \paragraph{Internal functions} \mbox{} % % \begin{function}{\cs_generate_internal_variant:n} % \begin{syntax} % "\cs_generate_internal_variant:n" \Arg{args} % \end{syntax} % Defines the appropriate "\exp_args:N" function, if necessary, % to perform the expansion control specified by . % \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 (i.e., are denoted with "x") % should be avoided if possible as they can not be processed very fast. % \item % In general "n", "x", and "o" (if not in the last position) will % need special processing which is not fast and not expandable, % i.e., functions of this type may not work correctly in arguments % that are itself subject to "x" expansion. Therefore it is best to % use the ``expandable'' functions (i.e., those that contain only % "c", "N", "o" or "f" in the last position) whenever possible. % \end{itemize} % % 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 "\aaa" equal to the control sequence % stemming from turning "b \l_tmpa_tl b" into a control % sequence. Furthermore we want to store the execution of it in a % \m{toks} register. In this example we assume "\l_tmpa_tl" contains % the text string "lur". The straight forward approach is % \begin{quote} % "\toks_set:No \l_tmpa_toks {\cs_set_eq:Nc \aaa {b \l_tmpa_tl b}}" % \end{quote} % Unfortunately this only puts % "\exp_args:NNc \cs_set_eq:NN \aaa {b \l_tmpa_tl b}" into "\l_tmpa_toks" % and not "\cs_set_eq:NwN \aaa = \blurb" as we probably wanted. Using % "\toks_set:Nx" is not an option as that will die horribly. Instead % we can do a % \begin{quote} % "\toks_set:Nf \l_tmpa_toks {\cs_set_eq:Nc \aaa {b \l_tmpa_tl b}}" % \end{quote} % which puts the desired result in "\l_tmpa_toks". It requires % "\toks_set:Nf" to be defined as % \begin{quote} % "\cs_set_nopar:Npn \toks_set:Nf {\exp_args:NNf \toks_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! % % % % % \section{Manipulating the first argument} % % \begin{function}{ \exp_args:No / (EXP) } % \begin{syntax} % " \exp_args:No" "..." % \end{syntax} % The first argument of (i.e., ) is expanded once, the % result is surrounded by braces and passed to . may have % more than one argument---all others are passed unchanged. % \end{function} % % \begin{function}{ \exp_args:Nc / (EXP) | \exp_args:cc / (EXP) } % \begin{syntax} % " \exp_args:Nc" "..." % \end{syntax} % The first argument of (i.e., ) is expanded until only % characters remain. (An internal error occurs if something else is the % result of this expansion.) Then the result is turned into a control % sequence and passed to as the first argument. may have % more than one argument---all others are passed unchanged. % % In the ":cc" variant, the control sequence itself is constructed % (with the same process as described above) before is turned into a % control sequence and passed as its argument. % \end{function} % % \begin{function}{ \exp_args:NV / (EXP) } % \begin{syntax} % " \exp_args:NV" % \end{syntax} % The first argument of (i.e., ) is expanded to its % value. By value we mean a number stored in an |int| or |num| % register, the length value of a |dim|, |skip| or |muskip| register, the % contents of a |toks| register or the unexpanded contents of a |tl var.| % register. The value is passed onto in braces. % \end{function} % % \begin{function}{ \exp_args:Nv / (EXP) } % \begin{syntax} % " \exp_args:Nv" \Arg{register} % \end{syntax} % Like the |V| type except the register is given by a list of % characters from which a control sequence name is generated. % \end{function} % % \begin{function}{ \exp_args:Nx } % \begin{syntax} % " \exp_args:Nx" "..." % \end{syntax} % The first argument of (i.e., ) is fully expanded until % only unexpandable tokens remain, the result is surrounded by braces % and passed to . may have more than one argument---all % others are passed unchanged. % As mentioned before, this type of function is relatively slow. % \end{function} % % \begin{function}{ \exp_args:Nf / (EXP) } % \begin{syntax} % " \exp_args:Nf" "..." % \end{syntax} % The first argument of (i.e., ) undergoes full % expansion until the first unexpandable token is encountered, the % result is surrounded by braces and passed to . may % have more than one argument---all others are passed unchanged. % Beware of its special behavior as explained above. % \end{function} % % \section{Manipulating two arguments} % % \begin{function}{% % \exp_args:NNx | % \exp_args:Nnx | % \exp_args:Ncx | % \exp_args:Nox | % \exp_args:Nxo | % \exp_args:Nxx | % } % \begin{syntax} % "\exp_args:Nnx" "..." % \end{syntax} % The above functions all manipulate the first two arguments of . % They are all slow and non-expandable. % \end{function} % % \begin{function}{% % \exp_args:NNo / (EXP) | % \exp_args:NNc / (EXP) | % \exp_args:NNv / (EXP) | % \exp_args:NNV / (EXP) | % \exp_args:NNf / (EXP) | % \exp_args:Nno / (EXP) | % \exp_args:NnV / (EXP) | % \exp_args:Nnf / (EXP) | % \exp_args:Noo / (EXP) | % \exp_args:Noc / (EXP) | % \exp_args:Nco / (EXP) | % \exp_args:Ncf / (EXP) | % \exp_args:Ncc / (EXP) | % \exp_args:Nff / (EXP) | % \exp_args:Nfo / (EXP) | % \exp_args:NVV / (EXP) | % } % \begin{syntax} % "\exp_args:NNo" "..." % \end{syntax} % These are the fast and expandable functions for the first two arguments. % \end{function} % % \section{Manipulating three arguments} % % So far not all possible functions are provided and even the selection % below may be reduced in the future as far as the non-expandable % functions are concerned. % % \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} % "\exp_args:Nnnx" "..." % \end{syntax} % All the above functions are non-expandable. % \end{function} % % \begin{function}{% % \exp_args:NNNo / (EXP) | % \exp_args:NNNV / (EXP) | % \exp_args:NNoo / (EXP) | % \exp_args:NNno / (EXP) | % \exp_args:Nnno / (EXP) | % \exp_args:Nnnc / (EXP) | % \exp_args:Nooo / (EXP) | % \exp_args:Nccc / (EXP) | % \exp_args:NcNc / (EXP) | % \exp_args:NcNo / (EXP) | % \exp_args:Ncco / (EXP) | % } % \begin{syntax} % "\exp_args:NNoo" "..." % \end{syntax} % These are the fast and expandable functions for the first three % arguments. % \end{function} % % \section{Preventing expansion} % % \begin{function}{\exp_not:N | % \exp_not:c | % \exp_not:n } % \begin{syntax} % "\exp_not:N" % "\exp_not:n" \Arg{token list} % \end{syntax} % This function will prohibit the expansion of in situation % where would otherwise be replaced by it definition, e.g., % inside an argument that is handled by the "x" convention. % \begin{texnote} % "\exp_not:N" is the primitive \tn{noexpand} renamed and "\exp_not:n" % is the \eTeX{} primitive \tn{unexpanded}. % \end{texnote} % \end{function} % % \begin{function}{\exp_not:o | % \exp_not:f } % \begin{syntax} % "\exp_not:o" \Arg{token list} % \end{syntax} % Same as "\exp_not:n" except is expanded once for the % "o" type and for the "f" type the token list is expanded until an % unexpandable token is found, and the result of these expansions is then % prohibited from being expanded further. % \end{function} % % \begin{function}{\exp_not:V | % \exp_not:v } % \begin{syntax} % "\exp_not:V" % "\exp_not:v" \Arg{token list} % \end{syntax} % The value of is retrieved and then passed on to % "\exp_not:n" which will prohibit further expansion. The |v| type % first creates a control sequence from but is otherwise % identical to |V|. % \end{function} % % \begin{function}{\exp_stop_f:} % \begin{syntax} % ... "\exp_stop_f:" % \end{syntax} % This function stops an "f" type expansion. An example use is one such as % \begin{verbatim} % \tl_set:Nf \l_tmpa_tl { % \if_case:w \l_tmpa_int % \or: \use_i_after_orelse:nw {\exp_stop_f: \textbullet} % \or: \use_i_after_orelse:nw {\exp_stop_f: \textendash} % \else: \use_i_after_fi:nw {\exp_stop_f: else-item} % \fi: % } % \end{verbatim} % This ensures the expansion in stopped right after finishing the % conditional but without expanding "\textbullet" etc. % \begin{texnote} % This function is a space token but it is better to distinguish % this expansion stopping token from a desired space token when % writing code. % \end{texnote} % \end{function} % % \section{Unbraced expansion} % % \begin{function}{ % \exp_last_unbraced:Nf| % \exp_last_unbraced:NV| % \exp_last_unbraced:No| % \exp_last_unbraced:Nv| % \exp_last_unbraced:NcV| % \exp_last_unbraced:NNV| % \exp_last_unbraced:NNo| % \exp_last_unbraced:NNNV| % \exp_last_unbraced:NNNo| % } % \begin{syntax} % "\exp_last_unbraced:NV" % \end{syntax} % There are a small number of occasions where the last argument % in an expansion run must be expanded unbraced. These functions % should only be used inside functions, \emph{not} for creating % variants. % \end{function} % % \end{documentation} % % \begin{implementation} % % \section{\pkg{l3expan} implementation} % % \subsection{Internal functions and variables} % % \begin{function}{\exp_after:wN} % \begin{syntax} % "\exp_after:wN" % \end{syntax} % This will expand once before processing . This is % similar to "\exp_args:No" except that no braces are put around the % result of expanding . % \begin{texnote} % This is the primitive \tn{expandafter} which was renamed to fit into % the naming conventions of \LaTeX3. % \end{texnote} % \end{function} % % \begin{variable}{\l_exp_tl} % \begin{syntax}\end{syntax} % 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}{ \exp_eval_register:N / (EXP) | % \exp_eval_register:c / (EXP) } % \begin{syntax} % "\exp_eval_register:N" % \end{syntax} % These functions evaluates a register as part of a "V" or "v" expansion % (respectively). A register might exist as % one of two things: A parameter-less non-long, non-protected macro % or a built-in \TeX\ register such as |\count|. % \end{function} % % \begin{function}{\exp_eval_error_msg:w} % \begin{syntax} % "\exp_eval_error_msg:w" % \end{syntax} % Used to generate an error message if a variable called as part of a % "v" or "V" expansion is defined as \cs{scan_stop:}. This typically % indicates that an incorrect cs name has been used. % \end{function} % % \begin{function}{\::n|\::N|\::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. % \end{function} % % \subsection{Module code} % % We start by ensuring that the required packages are loaded. % \begin{macrocode} %<*package> \ProvidesExplPackage {\filename}{\filedate}{\fileversion}{\filedescription} \package_check_loaded_expl: % %<*initex|package> % \end{macrocode} % % \begin{macro}{\exp_after:wN} % \begin{macro}{\exp_not:N} % \begin{macro}{\exp_not:n} % These are defined in \pkg{l3basics}. % \begin{macrocode} %<*bootstrap> \cs_set_eq:NwN \exp_after:wN \tex_expandafter:D \cs_set_eq:NwN \exp_not:N \tex_noexpand:D \cs_set_eq:NwN \exp_not:n \etex_unexpanded:D % % \end{macrocode} % \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_set_nopar:Npx| at some point, and % so is never going to be expandable.\footnote{However, some % primitives have certain characteristics that means that their % arguments undergo an \texttt{x} type expansion but the primitive % is in fact still expandable. We shall make it very clear when such % a function is expandable.}) % % The definition of expansion functions with this technique happens % in section~\ref{sec:gendef}. % In section~\ref{sec:handtune} some common cases are coded by a more direct % method for efficiency, typically using calls to |\exp_after:wN|. % % \begin{macro}{\l_exp_tl} % We need a scratch token list variable. % We don't use "tl" methods so that \pkg{l3expan} can be loaded earlier. % \begin{macrocode} \cs_new_nopar:Npn \l_exp_tl {} % \end{macrocode} % \end{macro} % % 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, % |\:::| 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. % % \begin{macro}[aux]{\exp_arg_next:nnn} % \begin{macro}[aux]{\exp_arg_next_nobrace: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 auxilliary 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\exp_arg_next:nnn#1#2#3{ #2\:::{#3{#1}} } \cs_new:Npn\exp_arg_next_nobrace: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}{\::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}{\::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}{\::c} % This function is used to skip an argument that is turned into % as control sequence without expansion. % \begin{macrocode} \cs_new:Npn\::c#1\:::#2#3{ \exp_after:wN\exp_arg_next_nobrace:nnn\cs:w #3\cs_end:{#1}{#2} } % \end{macrocode} % \end{macro} % % \begin{macro}{\::o} % This function is used to expand an argument once. % \begin{macrocode} \cs_new:Npn\::o#1\:::#2#3{ \exp_after:wN\exp_arg_next:nnn\exp_after:wN{#3}{#1}{#2} } % \end{macrocode} % \end{macro} % % % \begin{macro}{\::f} % \begin{macro}{\exp_stop_f:} % This function is used to expand a token list until the first % unexpandable token is found. The underlying "\tex_romannumeral:D -`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 "\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:NwN \aaa = \blurb" which then turned out to contain % the non-expandable token "\cs_set_eq:NwN". Since the expansion of % "\tex_romannumeral:D -`0" is \m{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\exp_arg_next:nnn \exp_after:wN{\tex_romannumeral:D -`0 #3} {#1}{#2} } \cs_new_nopar:Npn \exp_stop_f: {~} % \end{macrocode} % \end{macro} % \end{macro} % % \begin{macro}{\::x} % This function is used to expand an argument fully. % We could use the new expandable primitive "\expanded" here, but we % don't want to create incompatibilities between engines. % \begin{macrocode} \cs_new_protected:Npn \::x #1 \::: #2#3 { \cs_set_nopar:Npx \l_exp_tl {{#3}} \exp_after:wN \exp_arg_next:nnn \l_exp_tl {#1}{#2} } % \end{macrocode} % \end{macro} % % % \begin{macro}{\::v} % \begin{macro}{\::V} % These functions return the value of a register, i.e., one of % |tl|, |num|, |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 sequence |\tex_romannumeral:D -`0| sets off an |f| type % expansion. The argument is returned in braces. % \begin{macrocode} \cs_new:Npn \::V#1\:::#2#3{ \exp_after:wN\exp_arg_next:nnn \exp_after:wN{ \tex_romannumeral:D -`0 \exp_eval_register:N #3 } {#1}{#2} } \cs_new:Npn \::v#1\:::#2#3{ \exp_after:wN\exp_arg_next:nnn \exp_after:wN{ \tex_romannumeral:D -`0 \exp_eval_register:c {#3} } {#1}{#2} } % \end{macrocode} % \end{macro} % \end{macro} % % \begin{macro}{\exp_eval_register:N,\exp_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 |\tex_the:D| whereas for the macros we merely have to % expand them once. The trick is to find out when to use % |\tex_the:D| and when not to. What we do here is try to find out % whether the token will expand to something else when hit with % |\exp_after:wN|. The technique is to compare the meaning of the % register in question when it has been prefixed with |\exp_not:N| % and the register itself. If it is a macro, the prefixed % |\exp_not:N| will temporarily turn it into the primitive % |\tex_relax:D|. % \begin{macrocode} \cs_set_nopar:Npn \exp_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 % |\tex_relax:D|. 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 \tex_relax:D #1 \exp_eval_error_msg:w \fi: % \end{macrocode} % The next bit requires some explanation. The function must be % initiated by the sequence |\tex_romannumeral:D -`0| and we want to % terminate this expansion chain by inserting an |\exp_stop_f:| % 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_stop_f:\tex_the:D #1| and if it is a macro we % need to execute |\exp_after:wN\exp_stop_f: #1|. We therefore issue % the longer of the two sequences and if the register is a macro, we % remove the |\tex_the:D|. % \begin{macrocode} \else: \exp_after:wN \use_i_ii:nnn \fi: \exp_after:wN \exp_stop_f: \tex_the:D #1 } \cs_set_nopar:Npn \exp_eval_register:c #1{ \exp_after:wN\exp_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. % \exp_eval_error_msg:w ...erroneous variable used! % % l.55 \tl_set:Nv \l_tmpa_tl {undefined_tl} % \end{verbatim} % \begin{macrocode} \group_begin:% \tex_catcode:D`\!=11\tex_relax:D% \tex_catcode:D`\ =11\tex_relax:D% \cs_gset:Npn\exp_eval_error_msg:w#1\tex_the:D#2{% \fi:\fi:\erroneous variable used!}% \group_end:% % \end{macrocode} % \end{macro} % \end{macro} % % \subsection{Hand-tuned definitions} % \label{sec:handtune} % % One of the most important features of these functions is that they % are fully expandable and therefore allow to prefix them with % |\pref_global:D| for example. This together with the fact that the % `general' concept above is slower means that we should convert % whenever possible and perhaps remove all remaining occurences by % hand-encoding in the end. % % \begin{macro}{\exp_args:No} % \begin{macro}{\exp_args:NNo} % \begin{macro}{\exp_args:NNNo} % \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_args:Nc,\exp_args:cc,\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_set:Npn \exp_args:Nc #1#2{\exp_after:wN#1\cs:w#2\cs_end:} \cs_new:Npn \exp_args:cc #1#2{\cs:w #1\exp_after:wN\cs_end:\cs:w #2\cs_end:} \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_args:Nco} % If we force that the third argument % always has braces, we could implement this function % with less tokens and only two arguments. % \begin{macrocode} \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}} % \end{macrocode} % \end{macro} % % \subsection{Definitions with the `general' technique} % \label{sec:gendef} % % \begin{macro}{\exp_args:Nf,\exp_args:NV,\exp_args:Nv,\exp_args:Nx} % \begin{macrocode} \cs_set_nopar:Npn \exp_args:Nf {\::f\:::} \cs_set_nopar:Npn \exp_args:Nv {\::v\:::} \cs_set_nopar:Npn \exp_args:NV {\::V\:::} \cs_set_protected_nopar:Npn \exp_args:Nx {\::x\:::} % \end{macrocode} % \end{macro} % % \begin{macro}{\exp_args:NNV,\exp_args:NNv,\exp_args:NNf,\exp_args:NNx, % \exp_args:NVV, % \exp_args:Ncx, % \exp_args:Nfo,\exp_args:Nff, % \exp_args:Ncf,\exp_args:Nco, % \exp_args:Nnf,\exp_args:Nno,\exp_args:NnV,\exp_args:Nnx, % \exp_args:Noo,\exp_args:Noc,\exp_args:Nox, % \exp_args:Nxo,\exp_args:Nxx} % Here are the actual function definitions, using the helper functions % above. % \begin{macrocode} \cs_set_nopar:Npn \exp_args:NNf {\::N\::f\:::} \cs_set_nopar:Npn \exp_args:NNv {\::N\::v\:::} \cs_set_nopar:Npn \exp_args:NNV {\::N\::V\:::} \cs_set_protected_nopar:Npn \exp_args:NNx {\::N\::x\:::} \cs_set_protected_nopar:Npn \exp_args:Ncx {\::c\::x\:::} \cs_set_nopar:Npn \exp_args:Nfo {\::f\::o\:::} \cs_set_nopar:Npn \exp_args:Nff {\::f\::f\:::} \cs_set_nopar:Npn \exp_args:Ncf {\::c\::f\:::} \cs_set_nopar:Npn \exp_args:Nnf {\::n\::f\:::} \cs_set_nopar:Npn \exp_args:Nno {\::n\::o\:::} \cs_set_nopar:Npn \exp_args:NnV {\::n\::V\:::} \cs_set_protected_nopar:Npn \exp_args:Nnx {\::n\::x\:::} \cs_set_nopar:Npn \exp_args:Noc {\::o\::c\:::} \cs_set_nopar:Npn \exp_args:Noo {\::o\::o\:::} \cs_set_protected_nopar:Npn \exp_args:Nox {\::o\::x\:::} \cs_set_nopar:Npn \exp_args:NVV {\::V\::V\:::} \cs_set_protected_nopar:Npn \exp_args:Nxo {\::x\::o\:::} \cs_set_protected_nopar:Npn \exp_args:Nxx {\::x\::x\:::} % \end{macrocode} % \end{macro} % % \begin{macro}{\exp_args:Ncco, % \exp_args:Nccx, % \exp_args:Ncnx, % \exp_args:NcNc, % \exp_args:NcNo, % \exp_args:NNno, % \exp_args:NNNV, % \exp_args:Nnno, % \exp_args:Nnnx, % \exp_args:Nnox, % \exp_args:Nooo, % \exp_args:Noox, % \exp_args:Nnnc, % \exp_args:NNnx, % \exp_args:NNoo, % \exp_args:NNox} % \begin{macrocode} \cs_set_nopar:Npn \exp_args:NNNV {\::N\::N\::V\:::} \cs_set_nopar:Npn \exp_args:NNno {\::N\::n\::o\:::} \cs_set_protected_nopar:Npn \exp_args:NNnx {\::N\::n\::x\:::} \cs_set_nopar:Npn \exp_args:NNoo {\::N\::o\::o\:::} \cs_set_protected_nopar:Npn \exp_args:NNox {\::N\::o\::x\:::} \cs_set_nopar:Npn \exp_args:Nnnc {\::n\::n\::c\:::} \cs_set_nopar:Npn \exp_args:Nnno {\::n\::n\::o\:::} \cs_set_protected_nopar:Npn \exp_args:Nnnx {\::n\::n\::x\:::} \cs_set_protected_nopar:Npn \exp_args:Nnox {\::n\::o\::x\:::} \cs_set_nopar:Npn \exp_args:NcNc {\::c\::N\::c\:::} \cs_set_nopar:Npn \exp_args:NcNo {\::c\::N\::o\:::} \cs_set_nopar:Npn \exp_args:Ncco {\::c\::c\::o\:::} \cs_set_nopar:Npn \exp_args:Ncco {\::c\::c\::o\:::} \cs_set_protected_nopar:Npn \exp_args:Nccx {\::c\::c\::x\:::} \cs_set_protected_nopar:Npn \exp_args:Ncnx {\::c\::n\::x\:::} \cs_set_protected_nopar:Npn \exp_args:Noox {\::o\::o\::x\:::} \cs_set_nopar:Npn \exp_args:Nooo {\::o\::o\::o\:::} % \end{macrocode} % \end{macro} % % % \subsection{Preventing expansion} % % % \begin{macro}{\exp_not:o} % \begin{macro}{\exp_not:f} % \begin{macro}{\exp_not:v} % \begin{macro}{\exp_not:V} % \begin{macrocode} \cs_new:Npn\exp_not:o#1{\exp_not:n\exp_after:wN{#1}} \cs_new:Npn\exp_not:f#1{ \exp_not:n\exp_after:wN{\tex_romannumeral:D -`0 #1} } \cs_new:Npn\exp_not:v#1{ \exp_not:n\exp_after:wN{\tex_romannumeral:D -`0 \exp_eval_register:c {#1}} } \cs_new:Npn\exp_not:V#1{ \exp_not:n\exp_after:wN{\tex_romannumeral:D -`0 \exp_eval_register:N #1} } % \end{macrocode} % \end{macro} % \end{macro} % \end{macro} % \end{macro} % % \begin{macro}{\exp_not:c} % A helper function. % \begin{macrocode} \cs_new:Npn\exp_not:c#1{\exp_after:wN\exp_not:N\cs:w#1\cs_end:} % \end{macrocode} % \end{macro} % % % \subsection{Defining function variants} % % % \begin{macro}{\cs_generate_variant:Nn} % \begin{macro}[aux]{\cs_generate_variant_aux:nnNn} % \begin{macro}[aux]{\cs_generate_variant_aux:nnw} % \begin{macro}[aux]{\cs_generate_variant_aux:N} % \begin{arguments} % \item Base form of a function; e.g., "\tl_set:Nn" % \item One or more variant argument specifiers; e.g., "{Nx,c,cx}" % \end{arguments} % Split up the original base function to grab its name and signature % consisting of $k$ letters. Then we wish to iterate through the list % of variant argument specifiers, and for each one 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. For example, for a base function "\tl_set:Nn" which % needs a "c" variant form, we want the new signature to be "cn". % \begin{macrocode} \cs_new_protected:Npn \cs_generate_variant:Nn #1 { \chk_if_exist_cs:N #1 \cs_split_function:NN #1 \cs_generate_variant_aux:nnNn } % \end{macrocode} % We discard the boolean and then set off a loop through the desired % variant forms. % \begin{macrocode} \cs_set:Npn \cs_generate_variant_aux:nnNn #1#2#3#4{ \cs_generate_variant_aux:nnw {#1}{#2} #4,?,\q_recursion_stop } % \end{macrocode} % Next is the real work to be done. We now have 1: base name, 2: base % signature, 3: beginning of variant signature. To construct the new % csname and the "\exp_args:Ncc" form, we need the variant signature. % In our example, we wanted to discard the first two letters of the % base signature because the variant form started with "cc". This is % the same as putting first "cc" in the signature and then % "\use_none:nn" followed by the base signature "NNn". We therefore % call a small loop that outputs an "n" for each letter in the variant % signature and use this to call the correct "\use_none:" variant. % Firstly though, we check whether to terminate the loop. % \begin{macrocode} \cs_set:Npn \cs_generate_variant_aux:nnw #1 #2 #3, { \if:w ? #3 \exp_after:wN \use_none_delimit_by_q_recursion_stop:w \fi: % \end{macrocode} % Then check if the variant form has already been defined. % \begin{macrocode} \cs_if_free:cTF { #1:#3\use:c {use_none:\cs_generate_variant_aux:N #3 ?}#2 } { % \end{macrocode} % If not, then define it and then additionally check if % the |\exp_args:N| form needed is defined. % \begin{macrocode} \_cs_generate_variant_aux:ccpx { #1 : #2 } { #1:#3 \use:c{use_none:\cs_generate_variant_aux:N #3 ?}#2 } { \exp_not:c { exp_args:N #3} \exp_not:c {#1:#2} } \cs_generate_internal_variant:n {#3} } % \end{macrocode} % Otherwise tell that it was already defined. % \begin{macrocode} { \iow_log:x{ Variant~\token_to_str:c { #1:#3\use:c {use_none:\cs_generate_variant_aux:N #3 ?}#2 }~already~defined;~ not~ changing~ it~on~line~ \tex_the:D \tex_inputlineno:D } } % \end{macrocode} % Recurse. % \begin{macrocode} \cs_generate_variant_aux:nnw{#1}{#2} } % \end{macrocode} % The small loop for defining the required number of "n"s. Break when % seeing a "?". % \begin{macrocode} \cs_set:Npn \cs_generate_variant_aux:N #1{ \if:w ?#1 \exp_after:wN\use_none:nn \fi: n \cs_generate_variant_aux:N } % \end{macrocode} % \end{macro} % \end{macro} % \end{macro} % \end{macro} % %\begin{macro}[aux]{\_cs_generate_variant_aux:Ncpx} %\begin{macro}[aux]{\_cs_generate_variant_aux:ccpx} %\begin{macro}[aux]{\_cs_generate_variant_aux:w} % The idea here is to pick up protected parent functions, using the % nature of the meaning string that they generate. The test here is % almost the same as \cs{tl_if_empty:nTF}, but has to be hard-coded as % that function is not yet available and because it has to match both % long and short macros. % \begin{macrocode} \group_begin: \tex_lccode:D `\Z = `\d \scan_stop: \tex_lccode:D `\? =`\\ \scan_stop: \tex_catcode:D `\P = 12 \scan_stop: \tex_catcode:D `\R = 12 \scan_stop: \tex_catcode:D `\O = 12 \scan_stop: \tex_catcode:D `\T = 12 \scan_stop: \tex_catcode:D `\E = 12 \scan_stop: \tex_catcode:D `\C = 12 \scan_stop: \tex_catcode:D `\Z = 12 \scan_stop: \tex_lowercase:D { \group_end: \cs_new_nopar:Npn \_cs_generate_variant_aux:Ncpx #1 { \exp_after:wN \_cs_generate_variant_aux:w \tex_meaning:D #1 ? PROTECTEZ \q_stop } \cs_new_nopar:Npn \_cs_generate_variant_aux:ccpx { \exp_args:Nc \_cs_generate_variant_aux:Ncpx} \cs_new:Npn \_cs_generate_variant_aux:w #1 ? PROTECTEZ #2 \q_stop { \exp_after:wN \tex_ifx:D \exp_after:wN \q_no_value \etex_detokenize:D {#1} \q_no_value \exp_after:wN \cs_new_protected_nopar:cpx \tex_else:D \exp_after:wN \cs_new_nopar:cpx \tex_fi:D } } % \end{macrocode} %\end{macro} %\end{macro} %\end{macro} % % % \begin{macro}{\cs_generate_internal_variant:n} % Test if |exp_args:N #1| is already defined % and if not define it via the % |\::| commands using the chars in |#1| % \begin{macrocode} \cs_new_protected:Npn \cs_generate_internal_variant:n #1 { \cs_if_free:cT { exp_args:N #1 }{ % \end{macrocode} % We use "new" to log the definition if we have to make one. % \begin{macrocode} \cs_new:cpx { exp_args:N #1 } { \cs_generate_internal_variant_aux:n #1 : } } } % \end{macrocode} % \end{macro} % % \begin{macro}[aux]{\cs_generate_internal_variant_aux:n} % This command grabs char by char outputting |\::#1| (not expanded % further) until we see a |:|. That colon is in fact also turned into % |\:::| so that the required structure for |\exp_args...| commands % is correctly terminated. % \begin{macrocode} \cs_new:Npn \cs_generate_internal_variant_aux:n #1 { \exp_not:c{::#1} \if_meaning:w #1 : \exp_after:wN \use_none:n \fi: \cs_generate_internal_variant_aux:n } % \end{macrocode} % \end{macro} % % \subsection{Last-unbraced versions} % %\begin{macro}[aux]{\exp_arg_last_unbraced:nn} %\begin{macro}[aux]{\::f_unbraced} %\begin{macro}[aux]{\::o_unbraced} %\begin{macro}[aux]{\::V_unbraced} %\begin{macro}[aux]{\::v_unbraced} % There are a few places where the last argument needs to be available % unbraced. First some helper macros. % \begin{macrocode} \cs_new:Npn \exp_arg_last_unbraced:nn #1#2 { #2#1 } \cs_new:Npn \::f_unbraced \:::#1#2 { \exp_after:wN \exp_arg_last_unbraced:nn \exp_after:wN { \tex_romannumeral:D -`0 #2 } {#1} } \cs_new:Npn \::o_unbraced \:::#1#2 { \exp_after:wN \exp_arg_last_unbraced:nn \exp_after:wN {#2 }{#1} } \cs_new:Npn \::V_unbraced \:::#1#2 { \exp_after:wN \exp_arg_last_unbraced:nn \exp_after:wN { \tex_romannumeral:D -`0 \exp_eval_register:N #2 } {#1} } \cs_new:Npn \::v_unbraced \:::#1#2 { \exp_after:wN \exp_arg_last_unbraced:nn \exp_after:wN { \tex_romannumeral:D -`0 \exp_eval_register:c {#2} } {#1} } % \end{macrocode} %\end{macro} %\end{macro} %\end{macro} %\end{macro} %\end{macro} % %\begin{macro}{\exp_last_unbraced:NV} %\begin{macro}{\exp_last_unbraced:No} %\begin{macro}{\exp_last_unbraced:Nv} %\begin{macro}{\exp_last_unbraced:Nf} %\begin{macro}{\exp_last_unbraced:NcV} %\begin{macro}{\exp_last_unbraced:NNV} %\begin{macro}{\exp_last_unbraced:NNo} %\begin{macro}{\exp_last_unbraced:NNNV} %\begin{macro}{\exp_last_unbraced:NNNo} % Now the business end. % \begin{macrocode} \cs_new_nopar:Npn \exp_last_unbraced:Nf { \::f_unbraced \::: } \cs_new_nopar:Npn \exp_last_unbraced:NV { \::V_unbraced \::: } \cs_new_nopar:Npn \exp_last_unbraced:No { \::o_unbraced \::: } \cs_new_nopar:Npn \exp_last_unbraced:Nv { \::v_unbraced \::: } \cs_new_nopar:Npn \exp_last_unbraced:NcV { \::c \::V_unbraced \::: } \cs_new_nopar:Npn \exp_last_unbraced:NNV { \::N \::V_unbraced \::: } \cs_new:Npn \exp_last_unbraced:NNo #1#2#3 { \exp_after:wN #1 \exp_after:wN #2 #3 } \cs_new_nopar:Npn \exp_last_unbraced:NNNV { \::N \::N \::V_unbraced \::: } \cs_new:Npn \exp_last_unbraced:NNNo #1#2#3#4 { \exp_after:wN #1 \exp_after:wN #2 \exp_after:wN #3 #4 } % \end{macrocode} %\end{macro} %\end{macro} %\end{macro} %\end{macro} %\end{macro} %\end{macro} %\end{macro} %\end{macro} %\end{macro} % %\subsection{Items held from earlier} % %\begin{macro}{\str_if_eq_p:Vn} %\begin{macro}[TF]{\str_if_eq:Vn} %\begin{macro}{\str_if_eq_p:on} %\begin{macro}[TF]{\str_if_eq:on} %\begin{macro}{\str_if_eq_p:nV} %\begin{macro}[TF]{\str_if_eq:nV} %\begin{macro}{\str_if_eq_p:no} %\begin{macro}[TF]{\str_if_eq:no} %\begin{macro}{\str_if_eq_p:VV} %\begin{macro}[TF]{\str_if_eq:VV} % These cannot come earlier as they need \cs{cs_generate_variant:Nn}. % \begin{macrocode} \cs_generate_variant:Nn \str_if_eq_p:nn { V } \cs_generate_variant:Nn \str_if_eq_p:nn { o } \cs_generate_variant:Nn \str_if_eq_p:nn { nV } \cs_generate_variant:Nn \str_if_eq_p:nn { no } \cs_generate_variant:Nn \str_if_eq_p:nn { VV } \cs_generate_variant:Nn \str_if_eq:nnT { V } \cs_generate_variant:Nn \str_if_eq:nnT { o } \cs_generate_variant:Nn \str_if_eq:nnT { nV } \cs_generate_variant:Nn \str_if_eq:nnT { no } \cs_generate_variant:Nn \str_if_eq:nnT { VV } \cs_generate_variant:Nn \str_if_eq:nnF { V } \cs_generate_variant:Nn \str_if_eq:nnF { o } \cs_generate_variant:Nn \str_if_eq:nnF { nV } \cs_generate_variant:Nn \str_if_eq:nnF { no } \cs_generate_variant:Nn \str_if_eq:nnF { VV } \cs_generate_variant:Nn \str_if_eq:nnTF { V } \cs_generate_variant:Nn \str_if_eq:nnTF { o } \cs_generate_variant:Nn \str_if_eq:nnTF { nV } \cs_generate_variant:Nn \str_if_eq:nnTF { no } \cs_generate_variant:Nn \str_if_eq:nnTF { VV } % \end{macrocode} %\end{macro} %\end{macro} %\end{macro} %\end{macro} %\end{macro} %\end{macro} %\end{macro} %\end{macro} %\end{macro} %\end{macro} % % \begin{macrocode} % % \end{macrocode} % % Show token usage: % \begin{macrocode} %<*showmemory> \showMemUsage % % \end{macrocode} % % \end{implementation} % \PrintIndex % % \endinput