% \iffalse %% File: l3expan.dtx Copyright (C) 1990-1998 LaTeX3 project % %<*dtx> \ProvidesFile{l3expan.dtx} % %\NeedsTeXFormat{LaTeX2e} %\ProvidesPackage{l3expan} % \ProvidesFile{l3expan.drv} % \fi % \ProvidesFile{l3expan.dtx} [1998/04/20 v1.0e L3 Experimental Argument Expansion module] % % \iffalse %<*driver> \documentclass{l3doc} \begin{document} \DocInput{l3expan.dtx} \end{document} % % \fi % % % \GetFileInfo{l3expan.dtx} % \title{The \textsf{l3expan} package\thanks{This file % has version number \fileversion, last % revised \filedate.}\\ % Controlling Expansion of Command Arguments} % \author{\Team} % \date{\filedate} % \maketitle % % % \section{\LaTeX3 functions} % % All \LaTeX3 functions contain a colon in their % name. Characters following the colon are used to denote the number and % the ``type'' of arguments that the function takes. An uppercase "N" is % used to denote an argument that consists of a single token and a % lowercase "n" is used when the argument can consist of several tokens % surrounded by braces. In case of "n" arguments that consist of a % single token the surrounding braces can be omitted in nearly all % situations---functions that force the use of braces even for single % token arguments are explicitly mentioned. For example, "\seq_gpush:Nn" % is a function that takes two arguments, the first is a single token % (the sequence) and the second may consist of several tokens surrounded % by braces. % % This concept of argument specification makes it easy to read the code % and should be followed when defining new functions. % % \subsection{Expanding arguments of functions} % % Within code it is often necessary to expand or partially expand % arguments before passing it on to some function. For example, if the % token list pointer "\l_tmpa_tlp" contains the current file % that should be pushed onto some stack, we can not write % \begin{quote} % "\seq_gpush:Nn" \\ % " \g_file_name_stack" \\ % " \l_tmpa_tlp" % \end{quote} % since this would put the token "\l_tmpa_tlp" and not its % contents on the stack. Instead a suitable number of "\exp_after:NN" % would be necessary (together with extra braces) to change the order of % execution, i.e. % \begin{quote} % "\exp_after:NN" \\ % " \seq_gpush:Nn" \\ % "\exp_after:NN" \\ % " \g_file_name_stack" \\ % "\exp_after:NN" \\ % " {\l_tmpa_tlp}" % \end{quote} % % The above example is probably the simplest case but is already shows % how the code changes to something difficult to understand. Therefore % \LaTeX3 provides the programmer with a general scheme that keeps the % code compact and easy to understand. % To denote that some argument to a function needs special treatment one % just uses different letters in the argument part of the function to % mark the desired behavior. In the above example one would write % \begin{quote} % "\seq_gpush:No" \\ % " \g_file_name_stack" \\ % " \l_tmpa_tlp" % \end{quote} % to achieve the desired effect. Here the "o" stands for expand this % (the second) argument once before passing it to the function. % % The following letters can be used to denote special treatment of % arguments before passing it to the basic function: % \begin{description} % \item[o] One time expanded token or token-list. In the latter case, % effectively only the first token in the list gets expanded. Since % the expansion might result in more than one token, the result is % surrounded for further processing with braces. % % \item[x] Fully expanded token or token-list. Like "o" but the % argument is expanded using "\def:Npx" before it is passed on. This means % that expansion takes place until only unexpandable tokens are left. % % \item[N,O,X] Like "n", "o", "x" but the argument must be a single % token without any braces around it. % % \item[c] A character string or a token-list that ultimately expands % to characters. This string (after expansion) is used to construct a % command name that is eventually passed on. % % \item[C] A character string or a token-list that ultimately expands % to characters. From this string (after expansion) a command name is % constructed and then this command name is expanded once (like "o"). % The result of this is eventually passed on. In other words % \begin{quote} % "\seq_gpush:NC" \\ % " \g_file_name_stack" \\ % " {l_tmpa_tlp}" % \end{quote} % Has the same effect as the example above. % % % % \end{description} % % Due to memory constraints not all possible variations are implemented % for every base function. Instead only those that are used within the % \LaTeX3 kernel or otherwise seem 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. % % \subsection{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{quote} % "\exp_args:NNo\seq_gpush:Nn" \\ % " \g_file_name_stack" \\ % " \l_tmpa_tlp" % \end{quote} % 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} % "\def_new:Npn\seq_gpush:No{\exp_args:NNo\seq_gpush:Nn}" % \end{quote} % Providing variants in this way in style files is uncritical as the % "\def_new: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 available internal functions for argument expansion come in to % 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 "o" in the last position) whenever possible. % \end{itemize} % % \subsection{Manipulating the first argument} % % \begin{function}{% % \exp_args:No % } % \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 % } % \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. % \end{function} % % \begin{function}{% % \exp_args:NC % } % \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 which is then expanded once more. The result of this is then % passed to as the first argument. may have more than % one argument---all others are passed unchanged. % \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} % % \subsection{Manipulating two arguments} % % \begin{function}{% % \exp_args:Nno | % \exp_args:NNx | % \exp_args:Nnx | % \exp_args:Noo | % \exp_args:Nox | % \exp_args:Nxo | % \exp_args:Nxx | % } % \begin{syntax} % "\exp_args:Nno" "..." % \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_args:NNc | % \exp_args:NOo | % \exp_args:NOc | % \exp_args:Nco | % \exp_args:Ncc | % } % \begin{syntax} % "\exp_args:NNo" "..." % \end{syntax} % These are the fast and expandable functions for the first two arguments. % \end{function} % % \subsection{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:Nnno | % \exp_args:Nnnx | % \exp_args:Noox | % \exp_args:Nnox | % \exp_args:Ncnx | % } % \begin{syntax} % "\exp_args:Nnno" "..." % \end{syntax} % All the above functions are non-expandable. % \end{function} % % \begin{function}{% % \exp_args:NNOo | % \exp_args:NOOo | % \exp_args:Nccc | % } % \begin{syntax} % "\exp_args:NNOo" "..." % \end{syntax} % These are the fast and expandable functions for the first three % arguments. % \end{function} % % \subsection{Internal functions and variables} % % \begin{function}{\exp_after:NN} % \begin{syntax} % "\exp_after:NN" % \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{function}{\exp_not:N | % \exp_not:c } % \begin{syntax} % "\exp_not:N" % \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. % \end{texnote} % \end{function} % % % \begin{function}{\exp_not:o} % \begin{syntax} % "\exp_not:o" % \end{syntax} % % The name of this command is a lie. Perhaps it should be called % ``"exp_perhaps_once"''. What it actually does is, it expands and % then issues an "\exp_not:N" to prohibit further expansion of the % first token in the replacement text of . This means that if the % replacement text of consists of more than one token all % further tokens are still subject to full expansion. The command is, for % example, useful when generating a new cs name inside a "x" situation % that shouldn't be expanded further, e.g., "\exp_not:o" "\cs:w" "foo" % "\cs_end:". % \begin{texnote} % This command has no equivalent. % \end{texnote} % \end{function} % % \begin{variable}{\l_exp_tlp | \l_exp_toks} % 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} % % \StopEventually{} % % \section {Argument Expansion} % % We start by ensuring that the required packages are loaded. % \begin{macrocode} %\RequirePackage{l3basics} %\RequirePackage{l3tlp} %<*package> % \end{macrocode} % % \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 |\def:Npx| at some point, and so is never % going to be expandable.) % % In a later section some common cases are coded by a more direct % method, typically using calls to |\exp_after:NN|. % % \begin{macro}{\l_exp_tlp} % We need a scratch token list pointer. % \begin{macrocode} \tlp_new:Nn\l_exp_tlp{} % \end{macrocode} % \end{macro} % % This code uses internal functions with names that start with |\::| % to perform the expansions. % \begin{macro}{\exp_arg_next:nnn} % This is basically the same function as |\Dexp_arg_next:nnn|. % \begin{macrocode} \def_new:Npn\exp_arg_next:nnn#1#2#3{% #2\:::{#3#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} \def_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. %^^A was \let_new:NN\::N\::n (changed to match \;N above. % \begin{macrocode} \def_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} \def_new:Npn\::c#1\:::#2#3{% \exp_after:NN\exp_arg_next: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} \def_new:Npn\::o#1\:::#2#3{% \exp_after:NN\exp_arg_next:nnn\exp_after:NN{\exp_after:NN{#3}}{#1}{#2}} % \end{macrocode} % \end{macro} % % \begin{macro}{\::x} % This function is used to expand an argument fully. % % \begin{macrocode} \def_new:Npn\::x#1\:::#2#3{% \tlp_set:Nx\l_exp_tlp{{{#3}}}% \exp_after:NN\exp_arg_next:nnn\l_exp_tlp{#1}{#2}} % \end{macrocode} % \end{macro} % % \begin{macro}{\:::} % Just another name for the identity function. % \begin{macrocode} \def_new:Npn\:::#1{#1} % \end{macrocode} % \end{macro} % % \begin{macro}{\::C} % This function creates a control sequence out of |#3| and expands % that once before passing it on to |\exp_arg_next:nnn|. % \begin{macrocode} \def_new:Npn\::C#1\:::#2#3{% \exp_after:NN\exp_C_aux:nnn\cs:w #3\cs_end:{#1}{#2}} % \end{macrocode} % \end{macro} % % \begin{macro}{\exp_C_aux:nnn} % A helper function for |\::C| wich expands its argument before % passing it on to |\exp_arg_next:nnn|. % \begin{macrocode} \def_new:Npn\exp_C_aux:nnn #1 { \exp_after:NN \exp_arg_next:nnn \exp_after:NN { \exp_after:NN {#1} } } % \end{macrocode} % \end{macro} % % \begin{macro}{\exp_args:NC} % \begin{macro}{\exp_args:Nccx} % \begin{macro}{\exp_args:Ncnx} % \begin{macro}{\exp_args:NNno} % \begin{macro}{\exp_args:Nnno} % \begin{macro}{\exp_args:Nnnx} % \begin{macro}{\exp_args:Nno} % \begin{macro}{\exp_args:Nnox} % \begin{macro}{\exp_args:NNx} % \begin{macro}{\exp_args:Nnx} % \begin{macro}{\exp_args:Noo} % \begin{macro}{\exp_args:Noox} % \begin{macro}{\exp_args:Nox} % \begin{macro}{\exp_args:Nx} % \begin{macro}{\exp_args:Nxx} % \begin{macro}{\exp_args:Nxx} % Here are the actual function definitions, using the helper functions % above. % \begin{macrocode} \def:Npn \exp_args:NC {\::C\:::} %\def:Npn \exp_args:Nc {\::c\:::} %\def:Npn \exp_args:Ncc {\::c\::c\:::} %\def:Npn \exp_args:Nccc {\::c\::c\::c\:::} \def:Npn \exp_args:Nccx {\::c\::c\::x\:::} \def:Npn \exp_args:Ncnx {\::c\::n\::x\:::} %\def:Npn \exp_args:Nco {\::c\::o\:::} %\def:Npn \exp_args:NNc {\::N\::c\:::} %\def:Npn \exp_args:NNNo {\::N\::N\::o\:::} \def:Npn \exp_args:NNno {\::N\::n\::o\:::} \def:Npn \exp_args:Nnno {\::n\::n\::o\:::} \def:Npn \exp_args:Nnnx {\::n\::n\::x\:::} %\def:Npn \exp_args:NNo {\::N\::o\::\:::} \def:Npn \exp_args:Nno {\::n\::o\:::} %\def:Npn \exp_args:NNOo {\::N\::O\::o\:::} \def:Npn \exp_args:Nnox {\::n\::o\::x\:::} \def:Npn \exp_args:NNx {\::N\::x\:::} \def:Npn \exp_args:Nnx {\::n\::x\:::} %\def:Npn \exp_args:No {\::o\:::} %\def:Npn \exp_args:NOc {\::O\::c\:::} %\def:Npn \exp_args:NOo {\::O\::o\:::} \def:Npn \exp_args:Noo {\::o\::o\:::} %\def:Npn \exp_args:NOOo {\::O\::O\::o\:::} \def:Npn \exp_args:Noox {\::o\::o\::x\:::} \def:Npn \exp_args:Nox {\::o\::x\:::} \def:Npn \exp_args:Nx {\::x\:::} \def:Npn \exp_args:Nxo {\::x\::o\:::} \def:Npn \exp_args:Nxx {\::x\::x\:::} % \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} % \end{macro} % % % \subsection{Preventing expansion} % % \begin{macro}{\exp_not:N} % This is the \TeX\ primitive that was defined earlier. % \end{macro} % % \begin{macro}{\exp_not:o} % \begin{macro}{\exp_not:c} % Two helper functions, which we can probably live without it. % \begin{macrocode} \def_new:Npn\exp_not:o{\exp_after:NN\exp_not:N} \def_new:Npn\exp_not:c#1{\exp_after:NN\exp_not:N\cs:w#1\cs_end:} % \end{macrocode} % \end{macro} % \end{macro} % % \subsection{Single token expansion} % % Expansion for arguments that are single tokens is done with the % functions below. I first thought of using a different module name % but then I saw that this wouldn't do since I could then never % determine for, say, |\seq_put:no| whether this means single, or % general expansion. Therefore I decided to use uppercase `O' for % single expansion. % % 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 % above concept is much slower in general 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:NOo} % \begin{macro}{\exp_args:NNo} % \begin{macro}{\exp_args:NOOo} % \begin{macro}{\exp_args:NNOo} % \begin{macro}{\exp_args:NNNo} % This looks somewhat horrible but it runs well with the other % syntax. It is important to see that these functions really need % single tokens as arguments whenever capital letters are used. % \begin{macrocode} \def_new:Npn \exp_args:No #1#2{\exp_after:NN#1\exp_after:NN{#2}} \def_new:Npn \exp_args:NOo #1#2#3{\exp_after:NN\exp_args:No \exp_after:NN#1 \exp_after:NN#2\exp_after:NN{#3}} \def_new:Npn \exp_args:NOOo #1#2#3#4{\exp_after:NN\exp_args:NOo \exp_after:NN#1\exp_after:NN#2\exp_after:NN#3\exp_after:NN{#4}} \def_new:Npn \exp_args:NNo #1#2#3{\exp_after:NN#1\exp_after:NN#2 \exp_after:NN{#3}} \def_new:Npn \exp_args:NNOo #1#2#3#4{\exp_after:NN\exp_args:NNo \exp_after:NN#1\exp_after:NN#2\exp_after:NN#3\exp_after:NN{#4}} \def_new:Npn \exp_args:NNNo #1#2#3#4{\exp_after:NN#1\exp_after:NN#2 \exp_after:NN#3\exp_after:NN{#4}} % \end{macrocode} % \end{macro} % \end{macro} % \end{macro} % \end{macro} % \end{macro} % \end{macro} % % % \begin{macro}{\exp_args:Nc} % \begin{macro}{\exp_args:NNc} % \begin{macro}{\exp_args:NOc} % \begin{macro}{\exp_args:Ncc} % \begin{macro}{\exp_args:Nccc} % Here are the functions that turn their argument into csnames but % are expandable. % \begin{macrocode} \def_new:Npn \exp_args:Nc #1#2{\exp_after:NN#1\cs:w#2\cs_end:} \def_new:Npn \exp_args:NNc #1#2#3{\exp_after:NN#1\exp_after:NN#2 \cs:w#3\cs_end:} \def_new:Npn \exp_args:NOc#1#2#3{\exp_after:NN\exp_args:No\exp_after:NN #1\exp_after:NN#2\cs:w#3\cs_end:} \def_new:Npn \exp_args:Ncc #1#2#3{\exp_after:NN#1 \cs:w#2\exp_after:NN\cs_end:\cs:w#3\cs_end:} \def_new:Npn \exp_args:Nccc #1#2#3#4{\exp_after:NN#1 \cs:w#2\exp_after:NN\cs_end:\cs:w#3\exp_after:NN \cs_end:\cs:w #4\cs_end:} % \end{macrocode} % \end{macro} % \end{macro} % \end{macro} % \end{macro} % \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} \def_new:Npn \exp_args:Nco #1#2#3{\exp_after:NN#1\cs:w#2\exp_after:NN \cs_end:\exp_after:NN{#3}} % \end{macrocode} % \end{macro} % % % \begin{macro}{\exp_def_form:nnn} % This command is a recent addition which was actually added % when we wrote the article for TUGboat (while most of the other % code goes way back to 1993). % \begin{macrocode} \def:Npn\exp_def_form:nnn#1#2#3{ \exp_after:NN \def:Npn \cs:w #1:#3 \exp_after:NN \cs_end: \exp_after:NN { \cs:w exp_args:N#3 \exp_after:NN \cs_end: \cs:w #1:#2 \cs_end: } % \end{macrocode} % We also have to test if |exp_arg:N#3| is already defined % and if not define it via the % |\::| commands using the chars in |#3| % \begin{macrocode} \cs_free:cT {exp_args:N#3} {\def:cpx {exp_args:N#3} {\exp_args_form_x:w #3 :} } } % \end{macrocode} % \end{macro} % % % \begin{macro}{\exp_args_form_x:w} % This command graps 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} \def_new:Npn\exp_args_form_x:w #1 { \exp_after:NN \exp_not:N \cs:w ::#1 \cs_end: \if_meaning:NN #1 : \else: \exp_after:NN\exp_args_form_x:w \fi:} % \end{macrocode} % \end{macro} % Show token usage: % \begin{macrocode} % %<*showmemory> \showMemUsage % % \end{macrocode} % %