% \iffalse meta-comment % %% File: l3basics.dtx Copyright (C) 1990-2011 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|package> \RequirePackage{l3names} \GetIdInfo$Id: l3basics.dtx 2896 2011-10-09 20:36:50Z joseph $ {L3 Experimental basic definitions} % %<*driver> \documentclass[full]{l3doc} \begin{document} \DocInput{\jobname.dtx} \end{document} % % \fi % % \title{^^A % The \pkg{l3basics} package\\ Basic definitions^^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} % % As the name suggest this package holds some basic definitions which % are needed by most or all other packages in this set. % % Here we describe those functions that are used all over the place. With % that we mean functions dealing with the construction and testing of % control sequences. Furthermore the basic parts of conditional % processing are covered; conditional processing dealing with specific % data types is described in the modules specific for the respective % data types. % % \section{No operation functions} % % \begin{function}[EXP]{\prg_do_nothing:} % \begin{syntax} % \cs{prg_do_nothing:} % \end{syntax} % An expandable function which does nothing at all: leaves nothing % in the input stream after a single expansion. % \end{function} % % \begin{function}{\scan_stop:} % \begin{syntax} % \cs{scan_stop:} % \end{syntax} % A non-expandable function which does nothing. Does not vanish on % expansion but produces no typeset output. % \end{function} % % \section{Grouping material} % % \begin{function}{\group_begin:, \group_end:} % \begin{syntax} % \cs{group_begin:} % \cs{group_end:} % \end{syntax} % These functions begin and end a group for definition purposes. % Assignments are local to groups unless carried out in a global % manner. (A small number of exceptions to this rule will be noted % as necessary elsewhere in this document.) Each \cs{group_begin:} % must be matched by a \cs{group_end:}, although this does not have % to occur within the same function. Indeed, it is often necessary % to start a group within one function and finish it within another, % for example when seeking to use non-standard category codes. % \end{function} % % \begin{function}{\group_insert_after:N} % \begin{syntax} % \cs{group_insert_after:N} \meta{token} % \end{syntax} % Adds \meta{token} to the list of \meta{tokens} to be inserted % when the current group level ends. The list of \meta{tokens} to be % inserted will be empty at the beginning of a group: multiple % applications of \cs{group_insert_after:N} may be used to build % the inserted list one \meta{token} at a time. The current group % level may be closed by a \cs{group_end:} function or by a token % with category code $2$ (close-group). The later will be a ^^A{ % |}| if standard category codes apply. % \end{function} % % \section{Control sequences and functions} % % As \TeX{} is a macro language, creating new functions means % creating macros. At point of use, a function is replaced by % the replacement text (\enquote{code}) in which each parameter % in the code (|#1|, |#2|, \emph{etc.}) is replaced the appropriate % arguments absorbed by the function. In the following, \meta{code} % is therefore used as a shorthand for \enquote{replacement text}. % % Functions which are not \enquote{protected} will be fully expanded % inside an \texttt{x} expansion. In contrast, \enquote{protected} % functions are not expanded within \texttt{x} expansions. % % \subsection{Defining functions} % % Functions can be created with no requirement that they are declared % first (in contrast to variables, which must always be declared). % Declaring a function before setting up the code means that the name % chosen will be checked and an error raised if it is already in use. % The name of a function can be checked at the point of definition using % the \cs{cs_new\ldots} functions: this is recommended for all % functions which are defined for the first time. % % \subsection{Defining new functions using primitive parameter text} % % \begin{function}{\cs_new:Npn, \cs_new:cpn, \cs_new:Npx, \cs_new:cpx} % \begin{syntax} % \cs{cs_new:Npn} \meta{function} \meta{parameters} \Arg{code} % \end{syntax} % Creates \meta{function} to expand to \meta{code} as replacement text. % Within the \meta{code}, the \meta{parameters} (|#1|, |#2|, % \emph{etc.}) will be replaced by those absorbed by the function. % The definition is global and an error will result if the % \meta{function} is already defined. % \end{function} % % \begin{function} % { % \cs_new_nopar:Npn, \cs_new_nopar:cpn, % \cs_new_nopar:Npx, \cs_new_nopar:cpx % } % \begin{syntax} % \cs{cs_new_nopar:Npn} \meta{function} \meta{parameters} \Arg{code} % \end{syntax} % Creates \meta{function} to expand to \meta{code} as replacement text. % Within the \meta{code}, the \meta{parameters} (|#1|, |#2|, % \emph{etc.}) will be replaced by those absorbed by the function. % When the \meta{function} is used the \meta{parameters} absorbed % cannot contain \cs{par} tokens. The definition is global and % an error will result if the \meta{function} is already defined. % \end{function} % % \begin{function} % { % \cs_new_protected:Npn, \cs_new_protected:cpn, % \cs_new_protected:Npx, \cs_new_protected:cpx % } % \begin{syntax} % \cs{cs_new_protected:Npn} \meta{function} \meta{parameters} % ~~\Arg{code} % \end{syntax} % Creates \meta{function} to expand to \meta{code} as replacement text. % Within the \meta{code}, the \meta{parameters} (|#1|, |#2|, % \emph{etc.}) will be replaced by those absorbed by the function. % The \meta{function} will not expand within an \texttt{x}-type % argument. The definition is global and an error will result if the % \meta{function} is already defined. % \end{function} % % \begin{function} % { % \cs_new_protected_nopar:Npn, \cs_new_protected_nopar:cpn , % \cs_new_protected_nopar:Npx, \cs_new_protected_nopar:cpx % } % \begin{syntax} % \cs{cs_new_protected_nopar:Npn} \meta{function} \meta{parameters} \Arg{code} % \end{syntax} % Creates \meta{function} to expand to \meta{code} as replacement text. % Within the \meta{code}, the \meta{parameters} (|#1|, |#2|, % \emph{etc.}) will be replaced by those absorbed by the function. % When the \meta{function} is used the \meta{parameters} absorbed % cannot contain \cs{par} tokens. The \meta{function} will not % expand within an \texttt{x}-type argument. The definition is global % and an error will result if the \meta{function} is already defined. % \end{function} % % \begin{function}{\cs_set:Npn, \cs_set:cpn, \cs_set:Npx, \cs_set:cpx} % \begin{syntax} % \cs{cs_set:Npn} \meta{function} \meta{parameters} \Arg{code} % \end{syntax} % Sets \meta{function} to expand to \meta{code} as replacement text. % Within the \meta{code}, the \meta{parameters} (|#1|, |#2|, % \emph{etc.}) will be replaced by those absorbed by the function. % The assignment of a meaning to \meta{function} is restricted to % the current \TeX{} group level. % \end{function} % % \begin{function} % { % \cs_set_nopar:Npn, \cs_set_nopar:cpn, % \cs_set_nopar:Npx, \cs_set_nopar:cpx % } % \begin{syntax} % \cs{cs_set_nopar:Npn} \meta{function} \meta{parameters} \Arg{code} % \end{syntax} % Sets \meta{function} to expand to \meta{code} as replacement text. % Within the \meta{code}, the \meta{parameters} (|#1|, |#2|, % \emph{etc.}) will be replaced by those absorbed by the function. % When the \meta{function} is used the \meta{parameters} absorbed % cannot contain \cs{par} tokens. The assignment of a meaning % to \meta{function} is restricted to the current \TeX{} group % level. % \end{function} % % \begin{function} % { % \cs_set_protected:Npn, \cs_set_protected:cpn, % \cs_set_protected:Npx, \cs_set_protected:cpx % } % \begin{syntax} % \cs{cs_set_protected:Npn} \meta{function} \meta{parameters} \Arg{code} % \end{syntax} % Sets \meta{function} to expand to \meta{code} as replacement text. % Within the \meta{code}, the \meta{parameters} (|#1|, |#2|, % \emph{etc.}) will be replaced by those absorbed by the function. % The assignment of a meaning to \meta{function} is restricted to % the current \TeX{} group level. The \meta{function} will % not expand within an \texttt{x}-type argument. % \end{function} % % \begin{function} % { % \cs_set_protected_nopar:Npn, \cs_set_protected_nopar:cpn , % \cs_set_protected_nopar:Npx, \cs_set_protected_nopar:cpx , % } % \begin{syntax} % \cs{cs_set_protected_nopar:Npn} \meta{function} \meta{parameters} \Arg{code} % \end{syntax} % Sets \meta{function} to expand to \meta{code} as replacement text. % Within the \meta{code}, the \meta{parameters} (|#1|, |#2|, % \emph{etc.}) will be replaced by those absorbed by the function. % When the \meta{function} is used the \meta{parameters} absorbed % cannot contain \cs{par} tokens. The assignment of a meaning % to \meta{function} is restricted to the current \TeX{} group % level. The \meta{function} will not expand within an % \texttt{x}-type argument. % \end{function} % % \begin{function}{\cs_gset:Npn, \cs_gset:cpn, \cs_gset:Npx, \cs_gset:cpx} % \begin{syntax} % \cs{cs_gset:Npn} \meta{function} \meta{parameters} \Arg{code} % \end{syntax} % Globally sets \meta{function} to expand to \meta{code} as replacement % text. Within the \meta{code}, the \meta{parameters} (|#1|, |#2|, % \emph{etc.}) will be replaced by those absorbed by the function. % The assignment of a meaning to \meta{function} is \emph{not} % restricted to the current \TeX{} group level: the assignment is % global. % \end{function} % % \begin{function} % { % \cs_gset_nopar:Npn, \cs_gset_nopar:cpn, % \cs_gset_nopar:Npx, \cs_gset_nopar:cpx % } % \begin{syntax} % \cs{cs_gset_nopar:Npn} \meta{function} \meta{parameters} \Arg{code} % \end{syntax} % Globally sets \meta{function} to expand to \meta{code} as replacement % text. Within the \meta{code}, the \meta{parameters} (|#1|, |#2|, % \emph{etc.}) will be replaced by those absorbed by the function. % When the \meta{function} is used the \meta{parameters} absorbed % cannot contain \cs{par} tokens. The assignment of a meaning to % \meta{function} is \emph{not} restricted to the current \TeX{} % group level: the assignment is global. % \end{function} % % \begin{function} % { % \cs_gset_protected:Npn, \cs_gset_protected:cpn, % \cs_gset_protected:Npx, \cs_gset_protected:cpx % } % \begin{syntax} % \cs{cs_gset_protected:Npn} \meta{function} \meta{parameters} \Arg{code} % \end{syntax} % Globally sets \meta{function} to expand to \meta{code} as replacement % text. Within the \meta{code}, the \meta{parameters} (|#1|, |#2|, % \emph{etc.}) will be replaced by those absorbed by the function. % The assignment of a meaning to \meta{function} is \emph{not} % restricted to the current \TeX{} group level: the assignment is % global. The \meta{function} will not expand within an % \texttt{x}-type argument. % \end{function} % % \begin{function} % { % \cs_gset_protected_nopar:Npn, \cs_gset_protected_nopar:cpn, % \cs_gset_protected_nopar:Npx, \cs_gset_protected_nopar:cpx % } % \begin{syntax} % \cs{cs_gset_protected_nopar:Npn} \meta{function} \meta{parameters} \Arg{code} % \end{syntax} % Globally sets \meta{function} to expand to \meta{code} as replacement % text. Within the \meta{code}, the \meta{parameters} (|#1|, |#2|, % \emph{etc.}) will be replaced by those absorbed by the function. % When the \meta{function} is used the \meta{parameters} absorbed % cannot contain \cs{par} tokens. The assignment of a meaning to % \meta{function} is \emph{not} restricted to the current \TeX{} % group level: the assignment is global. The \meta{function} will % not expand within an \texttt{x}-type argument. % \end{function} % % \subsection{Defining new functions using the signature} % % \begin{function} % { % \cs_new:Nn, \cs_new:cn, % \cs_new:Nx, \cs_new:cx % } % \begin{syntax} % \cs{cs_new:Nn} \meta{function} \Arg{code} % \end{syntax} % Creates \meta{function} to expand to \meta{code} as replacement text. % Within the \meta{code}, the number of \meta{parameters} is detected % automatically from the function signature. These \meta{parameters} % (|#1|, |#2|, \emph{etc.}) will be replaced by those absorbed by the % function. The definition is global and % an error will result if the \meta{function} is already defined. % \end{function} % % \begin{function} % { % \cs_new_nopar:Nn, \cs_new_nopar:cn, % \cs_new_nopar:Nx, \cs_new_nopar:cx % } % \begin{syntax} % \cs{cs_new_nopar:Nn} \meta{function} \Arg{code} % \end{syntax} % Creates \meta{function} to expand to \meta{code} as replacement text. % Within the \meta{code}, the number of \meta{parameters} is detected % automatically from the function signature. These \meta{parameters} % (|#1|, |#2|, \emph{etc.}) will be replaced by those absorbed by the % function. When the \meta{function} is used the \meta{parameters} % absorbed cannot contain \cs{par} tokens. The definition is global and % an error will result if the \meta{function} is already defined. % \end{function} % % \begin{function} % { % \cs_new_protected:Nn, \cs_new_protected:cn, % \cs_new_protected:Nx, \cs_new_protected:cx % } % \begin{syntax} % \cs{cs_new_protected:Nn} \meta{function} \Arg{code} % \end{syntax} % Creates \meta{function} to expand to \meta{code} as replacement text. % Within the \meta{code}, the number of \meta{parameters} is detected % automatically from the function signature. These \meta{parameters} % (|#1|, |#2|, \emph{etc.}) will be replaced by those absorbed by the % function. The \meta{function} will not expand within an \texttt{x}-type % argument. The definition is global and % an error will result if the \meta{function} is already defined. % \end{function} % % \begin{function} % { % \cs_new_protected_nopar:Nn, \cs_new_protected_nopar:cn, % \cs_new_protected_nopar:Nx, \cs_new_protected_nopar:cx % } % \begin{syntax} % \cs{cs_new_protected_nopar:Nn} \meta{function} \Arg{code} % \end{syntax} % Creates \meta{function} to expand to \meta{code} as replacement text. % Within the \meta{code}, the number of \meta{parameters} is detected % automatically from the function signature. These \meta{parameters} % (|#1|, |#2|, \emph{etc.}) will be replaced by those absorbed by the % function. When the \meta{function} is used the \meta{parameters} % absorbed cannot contain \cs{par} tokens. The \meta{function} will not % expand within an \texttt{x}-type argument. The definition is global and % an error will result if the \meta{function} is already defined. % \end{function} % % \begin{function} % { % \cs_set:Nn, \cs_set:cn, % \cs_set:Nx, \cs_set:cx % } % \begin{syntax} % \cs{cs_set:Nn} \meta{function} \Arg{code} % \end{syntax} % Sets \meta{function} to expand to \meta{code} as replacement text. % Within the \meta{code}, the number of \meta{parameters} is detected % automatically from the function signature. These \meta{parameters} % (|#1|, |#2|, \emph{etc.}) will be replaced by those absorbed by the % function. % The assignment of a meaning to \meta{function} is restricted to % the current \TeX{} group level. % \end{function} % % \begin{function} % { % \cs_set_nopar:Nn, \cs_set_nopar:cn, % \cs_set_nopar:Nx, \cs_set_nopar:cx % } % \begin{syntax} % \cs{cs_set_nopar:Nn} \meta{function} \Arg{code} % \end{syntax} % Sets \meta{function} to expand to \meta{code} as replacement text. % Within the \meta{code}, the number of \meta{parameters} is detected % automatically from the function signature. These \meta{parameters} % (|#1|, |#2|, \emph{etc.}) will be replaced by those absorbed by the % function. When the \meta{function} is used the \meta{parameters} % absorbed cannot contain \cs{par} tokens. % The assignment of a meaning to \meta{function} is restricted to % the current \TeX{} group level. % \end{function} % % \begin{function} % { % \cs_set_protected:Nn, \cs_set_protected:cn, % \cs_set_protected:Nx, \cs_set_protected:cx % } % \begin{syntax} % \cs{cs_set_protected:Nn} \meta{function} \Arg{code} % \end{syntax} % Sets \meta{function} to expand to \meta{code} as replacement text. % Within the \meta{code}, the number of \meta{parameters} is detected % automatically from the function signature. These \meta{parameters} % (|#1|, |#2|, \emph{etc.}) will be replaced by those absorbed by the % function. The \meta{function} will not expand within an \texttt{x}-type % argument. % The assignment of a meaning to \meta{function} is restricted to % the current \TeX{} group level. % \end{function} % % \begin{function} % { % \cs_set_protected_nopar:Nn, \cs_set_protected_nopar:cn, % \cs_set_protected_nopar:Nx, \cs_set_protected_nopar:cx % } % \begin{syntax} % \cs{cs_set_protected_nopar:Nn} \meta{function} \Arg{code} % \end{syntax} % Sets \meta{function} to expand to \meta{code} as replacement text. % Within the \meta{code}, the number of \meta{parameters} is detected % automatically from the function signature. These \meta{parameters} % (|#1|, |#2|, \emph{etc.}) will be replaced by those absorbed by the % function. When the \meta{function} is used the \meta{parameters} % absorbed cannot contain \cs{par} tokens. The \meta{function} will not % expand within an \texttt{x}-type argument. % The assignment of a meaning to \meta{function} is restricted to % the current \TeX{} group level. % \end{function} % % \begin{function} % { % \cs_gset:Nn, \cs_gset:cn, % \cs_gset:Nx, \cs_gset:cx % } % \begin{syntax} % \cs{cs_gset:Nn} \meta{function} \Arg{code} % \end{syntax} % Sets \meta{function} to expand to \meta{code} as replacement text. % Within the \meta{code}, the number of \meta{parameters} is detected % automatically from the function signature. These \meta{parameters} % (|#1|, |#2|, \emph{etc.}) will be replaced by those absorbed by the % function. % The assignment of a meaning to \meta{function} is global. % \end{function} % % \begin{function} % { % \cs_gset_nopar:Nn, \cs_gset_nopar:cn, % \cs_gset_nopar:Nx, \cs_gset_nopar:cx % } % \begin{syntax} % \cs{cs_gset_nopar:Nn} \meta{function} \Arg{code} % \end{syntax} % Sets \meta{function} to expand to \meta{code} as replacement text. % Within the \meta{code}, the number of \meta{parameters} is detected % automatically from the function signature. These \meta{parameters} % (|#1|, |#2|, \emph{etc.}) will be replaced by those absorbed by the % function. When the \meta{function} is used the \meta{parameters} % absorbed cannot contain \cs{par} tokens. % The assignment of a meaning to \meta{function} is global. % \end{function} % % \begin{function} % { % \cs_gset_protected:Nn, \cs_gset_protected:cn, % \cs_gset_protected:Nx, \cs_gset_protected:cx % } % \begin{syntax} % \cs{cs_gset_protected:Nn} \meta{function} \Arg{code} % \end{syntax} % Sets \meta{function} to expand to \meta{code} as replacement text. % Within the \meta{code}, the number of \meta{parameters} is detected % automatically from the function signature. These \meta{parameters} % (|#1|, |#2|, \emph{etc.}) will be replaced by those absorbed by the % function. The \meta{function} will not expand within an \texttt{x}-type % argument. % The assignment of a meaning to \meta{function} is global. % \end{function} % % \begin{function} % { % \cs_gset_protected_nopar:Nn, \cs_gset_protected_nopar:cn, % \cs_gset_protected_nopar:Nx, \cs_gset_protected_nopar:cx % } % \begin{syntax} % \cs{cs_gset_protected_nopar:Nn} \meta{function} \Arg{code} % \end{syntax} % Sets \meta{function} to expand to \meta{code} as replacement text. % Within the \meta{code}, the number of \meta{parameters} is detected % automatically from the function signature. These \meta{parameters} % (|#1|, |#2|, \emph{etc.}) will be replaced by those absorbed by the % function. When the \meta{function} is used the \meta{parameters} % absorbed cannot contain \cs{par} tokens. The \meta{function} will not % expand within an \texttt{x}-type argument. % The assignment of a meaning to \meta{function} is global. % \end{function} % % \begin{function}[updated = 2011-09-05] % {\cs_generate_from_arg_count:NNnn, \cs_generate_from_arg_count:cNnn} % \begin{syntax} % \cs{cs_generate_from_arg_count:NNnn} \meta{function} \meta{creator} \meta{number} \meta{code} % \end{syntax} % Uses the \meta{creator} function (which should have signature % |Npn|, for example \cs{cs_new:Npn}) to define a \meta{function} % which takes \meta{number} arguments and has \meta{code} as % replacement text. The \meta{number} of arguments is an integer expression, % evaluated as detailed for \cs{int_eval:n}. % \end{function} % % \subsection{Copying control sequences} % % Control sequences (not just functions as defined above) can % be set to have the same meaning using the functions described % here. Making two control sequences equivalent means that the % second control sequence is a \emph{copy} of the first (rather than % a pointer to it). Thus the old and new control sequence are not % tided together: changes to one are not reflected in the other. % % In the following text \enquote{cs} is used as an abbreviation for % \enquote{control sequence}. % % \begin{function} % {\cs_new_eq:NN, \cs_new_eq:Nc, \cs_new_eq:cN, \cs_new_eq:cc} % \begin{syntax} % \cs{cs_new_eq:NN} \meta{cs 1} \meta{cs 2} % \cs{cs_new_eq:NN} \meta{cs 1} \meta{token} % \end{syntax} % Globally creates \meta{control sequence 1} and sets it to have the same % meaning as \meta{control sequence 2} or . % The second control sequence may % subsequently be altered without affecting the copy. % \end{function} % % \begin{function} % {\cs_set_eq:NN, \cs_set_eq:Nc, \cs_set_eq:cN, \cs_set_eq:cc} % \begin{syntax} % \cs{cs_set_eq:NN} \meta{cs 1} \meta{cs 2} % \cs{cs_set_eq:NN} \meta{cs 1} \meta{token} % \end{syntax} % Sets \meta{control sequence 1} to have the same meaning as % \meta{control sequence 2} (or ). % The second control sequence may subsequently be % altered without affecting the copy. The assignment of a meaning % to \meta{control sequence 1} is restricted to the current % \TeX{} group level. % \end{function} % % \begin{function} % {\cs_gset_eq:NN, \cs_gset_eq:Nc, \cs_gset_eq:cN, \cs_gset_eq:cc} % \begin{syntax} % \cs{cs_gset_eq:NN} \meta{cs 1} \meta{cs 2} % \cs{cs_gset_eq:NN} \meta{cs 1} \meta{token} % \end{syntax} % Globally sets \meta{control sequence 1} to have the same meaning as % \meta{control sequence 2} (or ). % The second control sequence may subsequently be % altered without affecting the copy. The assignment of a meaning to % \meta{control sequence 1} is \emph{not} restricted to the current % \TeX{} group level: the assignment is global. % \end{function} % % \subsection{Deleting control sequences} % % There are occasions where control sequences need to be deleted. % This is handled in a very simple manner. % % \begin{function}[updated = 2011-09-15]{\cs_undefine:N, \cs_undefine:c} % \begin{syntax} % \cs{cs_undefine:N} \meta{control sequence} % \end{syntax} % Sets \meta{control sequence} to be globally undefined. % \end{function} % % \subsection{Showing control sequences} % % \begin{function}[EXP]{\cs_meaning:N, \cs_meaning:c} % \begin{syntax} % \cs{cs_meaning:N} \meta{control sequence} % \end{syntax} % This function expands to the \emph{meaning} of the \meta{control sequence} % control sequence. This will show the \meta{replacement text} for a % macro. % \begin{texnote} % This is \TeX{}'s \tn{meaning} primitive. % \end{texnote} % \end{function} % % \begin{function}{\cs_show:N, \cs_show:c} % \begin{syntax} % \cs{cs_show:N} \meta{control sequence} % \end{syntax} % Displays the definition of the \meta{control sequence} on the % terminal. % \begin{texnote} % This is the \TeX{} primitive \tn{show}. % \end{texnote} % \end{function} % % \subsection{Converting to and from control sequences} % % \begin{function}[EXP]{\use:c} % \begin{syntax} % \cs{use:c} \Arg{control sequence name} % \end{syntax} % Converts the given \meta{control sequence name} into a single % control sequence token. This process requires two expansions. % The content for \meta{control sequence name} may be literal % material or from other expandable functions. The % \meta{control sequence name} must, when fully expanded, consist % of character tokens which are not active: typically, they will % be of category code $10$ (space), $11$ (letter) % or $12$ (other), or a mixture of these. % \end{function} % % As an example of the \cs{use:c} function, both % \begin{verbatim} % \use:c { a b c } % \end{verbatim} % and % \begin{verbatim} % \tl_new:N \l_my_tl % \tl_set:Nn \l_my_tl { a b c } % \use:c { \tl_use:N \l_my_tl } % \end{verbatim} % would be equivalent to % \begin{verbatim} % \abc % \end{verbatim} % after two expansions of \cs{use:c}. % % \begin{function}[EXP]{\cs:w, \cs_end:} % \begin{syntax} % \cs{cs:w} \meta{control sequence name} \cs{cs_end:} % \end{syntax} % Converts the given \meta{control sequence name} into a single % control sequence token. This process requires one expansion. % The content for \meta{control sequence name} may be literal % material or from other expandable functions. The % \meta{control sequence name} must, when fully expanded, consist % of character tokens which are not active: typically, they will % be of category code $10$ (space), $11$ (letter) % or $12$ (other), or a mixture of these. % \begin{texnote} % These are the \TeX{} primitives \tn{csname} and \tn{endcsname}. % \end{texnote} % \end{function} % % As an example of the \cs{cs:w} and \cs{cs_end:} functions, both % \begin{verbatim} % \cs:w a b c \cs_end: % \end{verbatim} % and % \begin{verbatim} % \tl_new:N \l_my_tl % \tl_set:Nn \l_my_tl { a b c } % \cs:w \tl_use:N \l_my_tl \cs_end: % \end{verbatim} % would be equivalent to % \begin{verbatim} % \abc % \end{verbatim} % after one expansion of \cs{cs:w}. % % \begin{function}[EXP]{\cs_to_str:N} % \begin{syntax} % \cs{cs_to_str:N} \Arg{control sequence} % \end{syntax} % Converts the given \meta{control sequence} into a series of % characters with category code $12$ (other), except spaces, % of category code $10$. The sequence will \emph{not} include % the current escape token, \emph{cf.}~\cs{token_to_str:N}. % Full expansion of this function requires a variable number % of expansion steps (either 3 or 4), and so an % \texttt{f}- or \texttt{x}-type expansion will be required to % convert the \meta{control sequence} to a sequence of characters % in the input stream. % \end{function} % % \section{Using or removing tokens and arguments} % % Tokens in the input can be read and used or read and discarded. % If one or more tokens are wrapped in braces then in absorbing them % the outer set will be removed. At the same time, the category code % of each token is set when the token is read by a function (if it % is read more than once, the category code is determined by the % the situation in force when first function absorbs the token). % % \begin{function}[EXP]{\use:n, \use:nn, \use:nnn, \use:nnnn} % \begin{syntax} % \cs{use:n} \Arg{group1} % \cs{use:nn} \Arg{group1} \Arg{group2} % \cs{use:nnn} \Arg{group1} \Arg{group2} \Arg{group3} % \cs{use:nnnn} \Arg{group1} \Arg{group2} \Arg{group3} \Arg{group4} % \end{syntax} % As illustrated, these functions will absorb between one and four % arguments, as indicated by the argument specifier. The braces % surrounding each argument will be removed leaving the remaining % tokens in the input stream. The category code of these tokens will % also be fixed by this process (if it has not already been by some % other absorption). All of these functions require only a single % expansion to operate, so that one expansion of % \begin{verbatim} % \use:nn { abc } { { def } } % \end{verbatim} % will result in the input stream containing % \begin{verbatim} % abc { def } % \end{verbatim} % \emph{i.e.} only the outer braces will be removed. % \end{function} % % \begin{function}[EXP]{\use_i:nn, \use_ii:nn} % \begin{syntax} % \cs{use_i:nn} \Arg{group1} \Arg{group2} % \end{syntax} % These functions will absorb two groups and leave only the % first or the second in the input stream. The braces surrounding the % arguments will be removed as part of this process. The category code % of these tokens will also be fixed (if it has not already been by % some other absorption). A single expansion is needed for the % functions to take effect. % \end{function} % % \begin{function}[EXP]{\use_i:nnn, \use_ii:nnn, \use_iii:nnn} % \begin{syntax} % \cs{use_i:nnn} \Arg{group1} \Arg{group2} \Arg{group3} % \end{syntax} % These functions will absorb three groups and leave only of these % in the input stream. The braces surrounding the arguments will be % removed as part of this process. The category code of these tokens % will also be fixed (if it has not already been by some other % absorption). A single expansion is needed for the functions to take % effect. % \end{function} % % \begin{function}[EXP] % {\use_i:nnnn, \use_ii:nnnn, \use_iii:nnnn, \use_iv:nnnn} % \begin{syntax} % \cs{use_i:nnnn} \Arg{group1} \Arg{group2} \Arg{group3} \Arg{group4} % \end{syntax} % These functions will absorb four groups and leave only of these % in the input stream. The braces surrounding the arguments will be % removed as part of this process. The category code of these tokens % will also be fixed (if it has not already been by some other % absorption). A single expansion is needed for the functions to take % effect. % \end{function} % % \begin{function}[EXP]{\use_i_ii:nnn} % \begin{syntax} % \cs{use_i_ii:nnn} \Arg{group1} \Arg{group2} \Arg{group3} % \end{syntax} % This functions will absorb three groups and leave the first and % second in the input stream. The braces surrounding the arguments % will be removed as part of this process. The category code of % these tokens will also be fixed (if it has not already been by % some other absorption). A single expansion is needed for the % functions to take effect. An example: % \begin{verbatim} % \use_i_ii:nnn { abc } { { def } } { ghi } % \end{verbatim} % will result in the input stream containing % \begin{verbatim} % abc { def } % \end{verbatim} % \emph{i.e.} the outer braces will be removed and the third group % will be removed. % \end{function} % % \begin{function}[EXP] % { % \use_none:n , % \use_none:nn , % \use_none:nnn , % \use_none:nnnn , % \use_none:nnnnn , % \use_none:nnnnnn , % \use_none:nnnnnnn , % \use_none:nnnnnnnn , % \use_none:nnnnnnnnn % } % \begin{syntax} % \cs{use_none:n} \Arg{group1} % \end{syntax} % These functions absorb between one and nine groups from the % input stream, leaving nothing on the resulting input stream. % These functions work after a single expansion. One or more of the % \texttt{n} arguments may be an unbraced single token % (\emph{i.e.}~an \texttt{N} argument). % \end{function} % % \begin{function}{\use:x} % \begin{syntax} % \cs{use:x} \Arg{expandable tokens} % \end{syntax} % Fully expands the \meta{expandable tokens} and inserts the % result into the input stream at the current location. % Any hash characters ("#") in the argument must be doubled. % \end{function} % % \subsection{Selecting tokens from delimited arguments} % % A different kind of function for selecting tokens from the token % stream are those that use delimited arguments. % % \begin{function}[EXP] % { % \use_none_delimit_by_q_nil:w, % \use_none_delimit_by_q_stop:w, % \use_none_delimit_by_q_recursion_stop:w % } % \begin{syntax} % \cs{use_none_delimit_by_q_nil:w} \meta{balanced text} \cs{q_nil} % \end{syntax} % Absorb the \meta{balanced} text form the input stream delimited by % the marker given in the function name, leaving nothing in the % input stream. % \end{function} % % \begin{function}[EXP] % { % \use_i_delimit_by_q_nil:nw, % \use_i_delimit_by_q_stop:nw, % \use_i_delimit_by_q_recursion_stop:nw % } % \begin{syntax} % \cs{use_i_delimit_by_q_nil:nw} \Arg{inserted tokens} % ~~\meta{balanced text} \cs{q_nil} % \end{syntax} % Absorb the \meta{balanced} text form the input stream delimited by % the marker given in the function name, leaving \meta{inserted tokens} % in the input stream for further processing. % \end{function} % % \subsection{Decomposing control sequences} % % \begin{function}[EXP]{\cs_get_arg_count_from_signature:N} % \begin{syntax} % \cs{cs_get_arg_count_from_signature:N} \meta{function} % \end{syntax} % Splits the \meta{function} into the name (\emph{i.e.}~the part % before the colon) and the signature (\emph{i.e.}~after the colon). % The \meta{number} of tokens in the \meta{signature} is then left in % the input stream. If there was no \meta{signature} then the result is % the marker value $-1$. % \end{function} % % \begin{function}[EXP]{\cs_get_function_name:N} % \begin{syntax} % \cs{cs_get_function_name:N} \meta{function} % \end{syntax} % Splits the \meta{function} into the name (\emph{i.e.}~the part % before the colon) and the signature (\emph{i.e.}~after the colon). % The \meta{name} is then left in the input stream without the escape % character present made up of tokens with category code $12$ % (other). % \end{function} % % \begin{function}[EXP]{\cs_get_function_signature:N} % \begin{syntax} % \cs{cs_get_function_signature:N} \meta{function} % \end{syntax} % Splits the \meta{function} into the name (\emph{i.e.}~the part % before the colon) and the signature (\emph{i.e.}~after the colon). % The \meta{signature} is then left in the input stream made up of % tokens with category code $12$ (other). % \end{function} % % \begin{function}[EXP]{\cs_split_function:NN} % \begin{syntax} % \cs{cs_split_function:NN} \meta{function} \meta{processor} % \end{syntax} % Splits the \meta{function} into the name (\emph{i.e.}~the part % before the colon) and the signature (\emph{i.e.}~after the colon). % This information is then placed in the input stream after the % \meta{processor} function in three parts: the \meta{name}, the % \meta{signature} and a logic token indicating if a colon was found % (to differentiate variables from function names). The \meta{name} % will not include the escape character, and both the \meta{name} and % \meta{signature} are made up of tokens with category code $12$ % (other). The \meta{processor} should be a function with argument % specification \texttt{:nnN} (plus any trailing arguments needed). % \end{function} % % \section{Predicates and conditionals} % \label{sec:predicates} % % \LaTeX3 has three concepts for conditional flow processing: % \begin{description} % \item[Branching conditionals] % Functions that carry out a test and then execute, depending on its % result, either the code supplied in the \meta{true arg} or the % \meta{false arg}. % These arguments are denoted with |T| and |F|, respectively. An % example would be % \begin{quote} % |\cs_if_free:cTF{abc}| \Arg{true code} \Arg{false code} % \end{quote} % a function that will turn the first argument into a control sequence % (since it's marked as |c|) then checks whether this control sequence % is still free and then depending on the result carry out the code in % the second argument (true case) or in the third argument (false % case). % % These type of functions are known as \enquote{conditionals}; % whenever a |TF| function is defined it will usually be accompanied by % |T| and |F| functions as well. These are provided for convenience when % the branch only needs to go a single way. Package writers are free to % choose which types to define but the kernel definitions will always % provide all three versions. % % Important to note is that these branching conditionals with \meta{true % code} and/or \meta{false code} are always defined in a way that the % code of the chosen alternative can operate on following tokens in % the input stream. % % These conditional functions may or may not be fully expandable, but if % they are expandable they will be accompanied by a \enquote{predicate} % for the same test as described below. % % \item[Predicates] % \enquote{Predicates} are functions that return a special type of % boolean value which can be tested by the boolean expression parser. % All functions of this type % are expandable and have names that end with |_p| in the % description part. For example, % \begin{quote} % |\cs_if_free_p:N| % \end{quote} % would be a predicate function for the same type of test as the % conditional described above. It would return \enquote{true} if its % argument (a single token denoted by |N|) is still free for definition. % It would be used in constructions like % \begin{quote} % |\bool_if:nTF {| \\ % \verb" \cs_if_free_p:N \l_tmpz_tl || \cs_if_free_p:N \g_tmpz_tl " \\ % |}| % \Arg{true code} \Arg{false code} % \end{quote} % % For each predicate defined, a \enquote{branching conditional} will % also exist that behaves like a conditional described above. % % \item[Primitive conditionals] % There is a third variety of conditional, which is the original % concept used in plain \TeX{} and \LaTeXe{}. Their use is discouraged % in \pkg{expl3} (although still used in low-level definitions) % because they are more fragile and in many cases require more % expansion control (hence more code) than the two types of % conditionals described above. % \end{description} % % \begin{variable}{\c_true_bool, \c_false_bool} % Constants that represent |true| and |false|, respectively. Used to % implement predicates. % \end{variable} % % \subsection{Tests on control sequences} % % \begin{function}[EXP,pTF]{\cs_if_eq:NN} % \begin{syntax} % \cs{cs_if_eq_p:NN} \Arg{cs1} \Arg{cs2} % \cs{cs_if_eq:NNTF} \Arg{cs1} \Arg{cs2} \Arg{true code} \Arg{false code} % \end{syntax} % Compares the definition of two \meta{control sequences} and % is logically \texttt{true} if the two are the same. % \end{function} % % \begin{function}[EXP,pTF]{\cs_if_exist:N, \cs_if_exist:c} % \begin{syntax} % \cs{cs_if_exist_p:N} \meta{control sequence} % \cs{cs_if_exist:NTF} \meta{control sequence} \Arg{true code} \Arg{false code} % \end{syntax} % Tests whether the \meta{control sequence} is currently defined % (whether as a function or another control sequence type). Any % valid definition of \meta{control sequence} will evaluate as % \texttt{true}. % \end{function} % % \begin{function}[EXP,pTF]{\cs_if_free:N, \cs_if_free:c} % \begin{syntax} % \cs{cs_if_free_p:N} \meta{control sequence} % \cs{cs_if_free:NTF} \meta{control sequence} \Arg{true code} \Arg{false code} % \end{syntax} % Tests whether the \meta{control sequence} is currently free to % be defined. This test will be \texttt{false} if the % \meta{control sequence} currently exists (as defined by % \cs{cs_if_exist:N}). % \end{function} % % \subsection{Testing string equality} % % \begin{function}[EXP,pTF] % { % \str_if_eq:nn, \str_if_eq:Vn, \str_if_eq:on, \str_if_eq:no, % \str_if_eq:nV, \str_if_eq:VV, \str_if_eq:xx % } % \begin{syntax} % \cs{str_if_eq_p:nn} \Arg{tl1} \Arg{tl2} % \cs{str_if_eq:nnTF} \Arg{tl1} \Arg{tl2} \Arg{true code} \Arg{false code} % \end{syntax} % Compares the two \meta{token lists} on a character by character % basis, and is \texttt{true} if the two lists contain the same % characters in the same order. Thus for example % \begin{verbatim} % \str_if_eq_p:xx { abc } { \tl_to_str:n { abc } } % \end{verbatim} % is logically \texttt{true}. All versions of these functions are fully % expandable (including those involving an \texttt{x}-type % expansion). % \end{function} % % \subsection{Engine-specific conditionals} % % \begin{function}[updated = 2011-09-06,EXP,pTF]{\luatex_if_engine:} % \begin{syntax} % \cs{luatex_if_luatex:TF} \Arg{true code} \Arg{false code} % \end{syntax} % Detects is the document is being compiled using \LuaTeX{}. % \end{function} % % \begin{function}[updated = 2011-09-06,EXP,pTF]{\pdftex_if_engine:} % \begin{syntax} % \cs{pdftex_if_engine:TF} \Arg{true code} \Arg{false code} % \end{syntax} % Detects is the document is being compiled using \pdfTeX{}. % \end{function} % % \begin{function}[updated = 2011-09-06,EXP,pTF]{\xetex_if_engine:} % \begin{syntax} % \cs{xetex_if_engine:TF} \Arg{true code} \Arg{false code} % \end{syntax} % Detects is the document is being compiled using \XeTeX{}. % \end{function} % % \subsection{Primitive conditionals} % % The \eTeX{} engine itself provides many different conditionals. Some % expand whatever comes after them and others don't. Hence the names % for these underlying functions will often contain a |:w| part but % higher level functions are often available. See for instance % |\int_compare_p:nNn| which is a wrapper for |\if_num:w|. % % Certain conditionals deal with specific data types like boxes and % fonts and are described there. The ones described below are either % the universal conditionals or deal with control sequences. We will % prefix primitive conditionals with |\if_|. % % \begin{function}[EXP] % {\if_true:, \if_false:, \or:, \else:, \fi:, \reverse_if:N} % \begin{syntax} % "\if_true:" "\else:" "\fi:" \\ % "\if_false:" "\else:" "\fi:" \\ % "\reverse_if:N" % \end{syntax} % "\if_true:" always executes , while "\if_false:" always % executes . "\reverse_if:N" reverses any two-way primitive % conditional. "\else:" and "\fi:" delimit the branches of the % conditional. "\or:" is used in case switches, see \pkg{l3int} % for more. % \begin{texnote} % These are equivalent to their corresponding \TeX\ primitive % conditionals; |\reverse_if:N| is \eTeX's |\unless|. % \end{texnote} % \end{function} % % \begin{function}[EXP]{\if_meaning:w} % \begin{syntax} % "\if_meaning:w" "\else:" "\fi:" % \end{syntax} % "\if_meaning:w" executes when and are the same, % otherwise it executes . % and could be functions, variables, tokens; in all cases the % \emph{unexpanded} definitions are compared. % \begin{texnote} % This is \TeX's |\ifx|. % \end{texnote} % \end{function} % % \begin{function}[EXP]{\if:w, \if_charcode:w,\if_catcode:w} % \begin{syntax} % "\if:w" "\else:" "\fi:" \\ % "\if_catcode:w" "\else:" "\fi:" % \end{syntax} % These conditionals will expand any following tokens until two % unexpandable tokens are left. If you wish to prevent this expansion, % prefix the token in question with "\exp_not:N". "\if_catcode:w" % tests if the category codes of the two tokens are the same whereas % "\if:w" tests if the character codes are % identical. "\if_charcode:w" is an alternative name for "\if:w". % \end{function} % % \begin{function}[EXP]{\if_predicate:w} % \begin{syntax} % "\if_predicate:w" "\else:" "\fi:" % \end{syntax} % This function takes a predicate function and % branches according to the result. (In practice this function would also % accept a single boolean variable in place of the but to make the % coding clearer this should be done through "\if_bool:N".) % \end{function} % % \begin{function}[EXP]{\if_bool:N} % \begin{syntax} % "\if_bool:N" "\else:" "\fi:" % \end{syntax} % This function takes a boolean variable and % branches according to the result. % \end{function} % % \begin{function}[EXP]{\if_cs_exist:N, \if_cs_exist:w} % \begin{syntax} % "\if_cs_exist:N" "\else:" "\fi:" \\ % "\if_cs_exist:w" "\cs_end:" "\else:" "\fi:" % \end{syntax} % Check if appears in the hash table or if the control sequence % that can be formed from appears in the hash table. The % latter function does not turn the control sequence in question into % "\scan_stop:"! This can be useful when dealing with control % sequences which cannot be entered as a single token. % \end{function} % % \begin{function}[EXP] % { % \if_mode_horizontal:, \if_mode_vertical:, % \if_mode_math:, \if_mode_inner: % } % \begin{syntax} % "\if_mode_horizontal:" "\else:" "\fi:" % \end{syntax} % Execute if currently in horizontal mode, otherwise % execute . Similar for the other functions. % \end{function} % % \section{Internal kernel functions} % % \begin{function}{\chk_if_exist_cs:N, \chk_if_exist_cs:c} % \begin{syntax} % \cs{chk_if_exist_cs:N} \meta{cs} % \end{syntax} % This function checks that \meta{cs} exists according to the % criteria for \cs{cs_if_exist_p:N}, and if not raises a kernel-level % error. % \end{function} % % \begin{function}{\chk_if_free_cs:N, \chk_if_free_cs:c} % \begin{syntax} % \cs{chk_if_free_cs:N} \meta{cs} % \end{syntax} % This function checks that \meta{cs} is free according to the % criteria for \cs{cs_if_free_p:N}, and if not raises a kernel-level % error. % \end{function} % % \end{documentation} % % \begin{implementation} % % \section{\pkg{l3basics} implementation} % % \begin{macrocode} %<*initex|package> % \end{macrocode} % % \begin{macrocode} %<*package> \ProvidesExplPackage {\ExplFileName}{\ExplFileDate}{\ExplFileVersion}{\ExplFileDescription} \package_check_loaded_expl: % % \end{macrocode} % % \subsection{Renaming some \TeX{} primitives (again)} % % Having given all the \TeX{} primitives a consistent name, we need to % give sensible names to the ones we actually want to use. % These will be defined as needed in the appropriate modules, but % do a few now, just to get started.\footnote{This renaming gets expensive % in terms of csname usage, an alternative scheme would be to just use % the \cs{tex\ldots:D} name in the cases where no good alternative exists.} % % \begin{macro}{\if_true:} % \begin{macro}{\if_false:} % \begin{macro}{\or:} % \begin{macro}{\else:} % \begin{macro}{\fi:} % \begin{macro}{\reverse_if:N} % \begin{macro}{\if:w} % \begin{macro}{\if_bool:N} % \begin{macro}{\if_predicate:w} % \begin{macro}{\if_charcode:w} % \begin{macro}{\if_catcode:w} % \begin{macro}{\if_meaning:w} % Then some conditionals. % \begin{macrocode} \tex_let:D \if_true: \tex_iftrue:D \tex_let:D \if_false: \tex_iffalse:D \tex_let:D \or: \tex_or:D \tex_let:D \else: \tex_else:D \tex_let:D \fi: \tex_fi:D \tex_let:D \reverse_if:N \etex_unless:D \tex_let:D \if:w \tex_if:D \tex_let:D \if_bool:N \tex_ifodd:D \tex_let:D \if_predicate:w \tex_ifodd:D \tex_let:D \if_charcode:w \tex_if:D \tex_let:D \if_catcode:w \tex_ifcat:D \tex_let:D \if_meaning:w \tex_ifx:D % \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} % % \begin{macro}{\if_mode_math:} % \begin{macro}{\if_mode_horizontal:} % \begin{macro}{\if_mode_vertical:} % \begin{macro}{\if_mode_inner:} % \TeX{} lets us detect some if its modes. % \begin{macrocode} \tex_let:D \if_mode_math: \tex_ifmmode:D \tex_let:D \if_mode_horizontal: \tex_ifhmode:D \tex_let:D \if_mode_vertical: \tex_ifvmode:D \tex_let:D \if_mode_inner: \tex_ifinner:D % \end{macrocode} % \end{macro} % \end{macro} % \end{macro} % \end{macro} % % \begin{macro}{\if_cs_exist:N} % \begin{macro}{\if_cs_exist:w} % \begin{macrocode} \tex_let:D \if_cs_exist:N \etex_ifdefined:D \tex_let:D \if_cs_exist:w \etex_ifcsname:D % \end{macrocode} % \end{macro} % \end{macro} % % \begin{macro}{\exp_after:wN} % \begin{macro}{\exp_not:N} % \begin{macro}{\exp_not:n} % The three |\exp_| functions are used in the \textsf{l3expan} module % where they are described. % \begin{macrocode} \tex_let:D \exp_after:wN \tex_expandafter:D \tex_let:D \exp_not:N \tex_noexpand:D \tex_let:D \exp_not:n \etex_unexpanded:D % \end{macrocode} % \end{macro} % \end{macro} % \end{macro} % % \begin{macro}{\token_to_meaning:N} % \begin{macro}{\token_to_str:N} % \begin{macro}{\cs:w} % \begin{macro}{\cs_end:} % \begin{macro}{\cs_meaning:N} % \begin{macro}{\cs_show:N} % \begin{macrocode} \tex_let:D \token_to_meaning:N \tex_meaning:D \tex_let:D \token_to_str:N \tex_string:D \tex_let:D \cs:w \tex_csname:D \tex_let:D \cs_end: \tex_endcsname:D \tex_let:D \cs_meaning:N \tex_meaning:D \tex_let:D \cs_show:N \tex_show:D % \end{macrocode} % \end{macro} % \end{macro} % \end{macro} % \end{macro} % \end{macro} % \end{macro} % % \begin{macro}{\scan_stop:} % \begin{macro}{\group_begin:} % \begin{macro}{\group_end:} % The next three are basic functions for which there also exist % versions that are safe inside alignments. These safe versions are % defined in the \textsf{l3prg} module. % \begin{macrocode} \tex_let:D \scan_stop: \tex_relax:D \tex_let:D \group_begin: \tex_begingroup:D \tex_let:D \group_end: \tex_endgroup:D % \end{macrocode} % \end{macro} % \end{macro} % \end{macro} % % \begin{macro}{\if_int_compare:w} % \begin{macro}{\int_to_roman:w} % \begin{macrocode} \tex_let:D \if_int_compare:w \tex_ifnum:D \tex_let:D \int_to_roman:w \tex_romannumeral:D % \end{macrocode} % \end{macro} % \end{macro} % % \begin{macro}{\group_insert_after:N} % \begin{macrocode} \tex_let:D \group_insert_after:N \tex_aftergroup:D % \end{macrocode} % \end{macro} % % \begin{macro}{\tex_global:D} % \begin{macro}{\tex_long:D} % \begin{macro}{\tex_protected:D} % \begin{macrocode} \tex_let:D \tex_global:D \tex_global:D \tex_let:D \tex_long:D \tex_long:D \tex_let:D \tex_protected:D \etex_protected:D % \end{macrocode} % \end{macro} % \end{macro} % \end{macro} % % \begin{macro}{\exp_args:Nc} % Discussed in \pkg{l3expan}, but needed much earlier. % \begin{macrocode} \tex_long:D \tex_def:D \exp_args:Nc #1#2 { \exp_after:wN #1 \cs:w #2 \cs_end: } % \end{macrocode} % \end{macro} % % \begin{macro}{\token_to_str:c} % \begin{macro}{\cs_meaning:c} % \begin{macro}{\cs_show:c} %% A small number of variants by hand. % \begin{macrocode} \tex_def:D \cs_meaning:c { \exp_args:Nc \cs_meaning:N } \tex_def:D \token_to_str:c { \exp_args:Nc \token_to_str:N } \tex_def:D \cs_show:c { \exp_args:Nc \cs_show:N } % \end{macrocode} % \end{macro} % \end{macro} % \end{macro} % % \subsection {Defining functions} % % We start by providing functions for the typical definition % functions. First the local ones. % % \begin{macro}{\cs_set_nopar:Npn} % \begin{macro}{\cs_set_nopar:Npx} % \begin{macro}{\cs_set:Npn} % \begin{macro}{\cs_set:Npx} % \begin{macro}{\cs_set_protected_nopar:Npn} % \begin{macro}{\cs_set_protected_nopar:Npx} % \begin{macro}{\cs_set_protected:Npn} % \begin{macro}{\cs_set_protected:Npx} % All assignment functions in \LaTeX3 should be naturally robust; % after all, the \TeX{} primitives for assignments are and it can be % a cause of problems if others aren't. % \begin{macrocode} \tex_let:D \cs_set_nopar:Npn \tex_def:D \tex_let:D \cs_set_nopar:Npx \tex_edef:D \tex_protected:D \cs_set_nopar:Npn \cs_set:Npn { \tex_long:D \cs_set_nopar:Npn } \tex_protected:D \cs_set_nopar:Npn \cs_set:Npx { \tex_long:D \cs_set_nopar:Npx } \tex_protected:D \cs_set_nopar:Npn \cs_set_protected_nopar:Npn { \tex_protected:D \cs_set_nopar:Npn } \tex_protected:D \cs_set_nopar:Npn \cs_set_protected_nopar:Npx { \tex_protected:D \cs_set_nopar:Npx } \cs_set_protected_nopar:Npn \cs_set_protected:Npn { \tex_protected:D \tex_long:D \cs_set_nopar:Npn } \cs_set_protected_nopar:Npn \cs_set_protected:Npx { \tex_protected:D \tex_long:D \cs_set_nopar:Npx } % \end{macrocode} % \end{macro} % \end{macro} % \end{macro} % \end{macro} % \end{macro} % \end{macro} % \end{macro} % \end{macro} % % \begin{macro}{\cs_gset_nopar:Npn} % \begin{macro}{\cs_gset_nopar:Npx} % \begin{macro}{\cs_gset:Npn} % \begin{macro}{\cs_gset:Npx} % \begin{macro}{\cs_gset_protected_nopar:Npn} % \begin{macro}{\cs_gset_protected_nopar:Npx} % \begin{macro}{\cs_gset_protected:Npn} % \begin{macro}{\cs_gset_protected:Npx} % Global versions of the above functions. % \begin{macrocode} \tex_let:D \cs_gset_nopar:Npn \tex_gdef:D \tex_let:D \cs_gset_nopar:Npx \tex_xdef:D \cs_set_protected_nopar:Npn \cs_gset:Npn { \tex_long:D \cs_gset_nopar:Npn } \cs_set_protected_nopar:Npn \cs_gset:Npx { \tex_long:D \cs_gset_nopar:Npx } \cs_set_protected_nopar:Npn \cs_gset_protected_nopar:Npn { \tex_protected:D \cs_gset_nopar:Npn } \cs_set_protected_nopar:Npn \cs_gset_protected_nopar:Npx { \tex_protected:D \cs_gset_nopar:Npx } \cs_set_protected_nopar:Npn \cs_gset_protected:Npn { \tex_protected:D \tex_long:D \cs_gset_nopar:Npn } \cs_set_protected_nopar:Npn \cs_gset_protected:Npx { \tex_protected:D \tex_long:D \cs_gset_nopar:Npx } % \end{macrocode} % \end{macro} % \end{macro} % \end{macro} % \end{macro} % \end{macro} % \end{macro} % \end{macro} % \end{macro} % % \subsection{Selecting tokens} % % \begin{macro}{\use:c} % This macro grabs its argument and returns a csname from it. % \begin{macrocode} \cs_set:Npn \use:c #1 { \cs:w #1 \cs_end: } % \end{macrocode} % \end{macro} % % \begin{macro}{\use:x} % \begin{macro}[aux]{\cs_tmp:w} % Fully expands its argument and passes it to the input stream. % Uses |\cs_tmp:| as a scratch register but does not affect it. % \begin{macrocode} \cs_set_protected:Npn \use:x #1 { \group_begin: \cs_set:Npx \cs_tmp:w {#1} \exp_after:wN \group_end: \cs_tmp:w } \cs_set:Npn \cs_tmp:w { } % \end{macrocode} % \end{macro} % % \begin{macro}{\use:n} % \begin{macro}{\use:nn} % \begin{macro}{\use:nnn} % \begin{macro}{\use:nnnn} % These macro grabs its arguments and returns it back to the input % (with outer braces removed). % \begin{macrocode} \cs_set:Npn \use:n #1 {#1} \cs_set:Npn \use:nn #1#2 {#1#2} \cs_set:Npn \use:nnn #1#2#3 {#1#2#3} \cs_set:Npn \use:nnnn #1#2#3#4 {#1#2#3#4} % \end{macrocode} % \end{macro} % \end{macro} % \end{macro} % \end{macro} % % \begin{macro}{\use_i:nn} % \begin{macro}{\use_ii:nn} % The equivalent to \LaTeXe{}'s \tn{@firstoftwo} and \tn{@secondoftwo}. % \begin{macrocode} \cs_set:Npn \use_i:nn #1#2 {#1} \cs_set:Npn \use_ii:nn #1#2 {#2} % \end{macrocode} % \end{macro} % \end{macro} % % \begin{macro}{\use_i:nnn} % \begin{macro}{\use_ii:nnn} % \begin{macro}{\use_iii:nnn} % \begin{macro}{\use_i_ii:nnn} % \begin{macro}{\use_i:nnnn} % \begin{macro}{\use_ii:nnnn} % \begin{macro}{\use_iii:nnnn} % \begin{macro}{\use_iv:nnnn} % We also need something for picking up arguments from a longer % list. % \begin{macrocode} \cs_set:Npn \use_i:nnn #1#2#3 {#1} \cs_set:Npn \use_ii:nnn #1#2#3 {#2} \cs_set:Npn \use_iii:nnn #1#2#3 {#3} \cs_set:Npn \use_i_ii:nnn #1#2#3 {#1#2} \cs_set:Npn \use_i:nnnn #1#2#3#4 {#1} \cs_set:Npn \use_ii:nnnn #1#2#3#4 {#2} \cs_set:Npn \use_iii:nnnn #1#2#3#4 {#3} \cs_set:Npn \use_iv:nnnn #1#2#3#4 {#4} % \end{macrocode} % \end{macro} % \end{macro} % \end{macro} % \end{macro} % \end{macro} % \end{macro} % \end{macro} % \end{macro} % % \begin{macro}{\use_none_delimit_by_q_nil:w} % \begin{macro}{\use_none_delimit_by_q_stop:w} % \begin{macro}{\use_none_delimit_by_q_recursion_stop:w} % Functions that gobble everything until they see either \cs{q_nil} or % \cs{q_stop}, respectively. % \begin{macrocode} \cs_set:Npn \use_none_delimit_by_q_nil:w #1 \q_nil { } \cs_set:Npn \use_none_delimit_by_q_stop:w #1 \q_stop { } \cs_set:Npn \use_none_delimit_by_q_recursion_stop:w #1 \q_recursion_stop { } % \end{macrocode} % \end{macro} % \end{macro} % \end{macro} % % \begin{macro}{\use_i_delimit_by_q_nil:nw} % \begin{macro}{\use_i_delimit_by_q_stop:nw} % \begin{macro}{\use_i_delimit_by_q_recursion_stop:nw} % Same as above but execute first argument after gobbling. Very % useful when you need to skip the rest of a mapping sequence but % want an easy way to control what should be expanded next. % \begin{macrocode} \cs_set:Npn \use_i_delimit_by_q_nil:nw #1#2 \q_nil {#1} \cs_set:Npn \use_i_delimit_by_q_stop:nw #1#2 \q_stop {#1} \cs_set:Npn \use_i_delimit_by_q_recursion_stop:nw #1#2 \q_recursion_stop {#1} % \end{macrocode} % \end{macro} % \end{macro} % \end{macro} % % \subsection{Gobbling tokens from input} % % \begin{macro}{\use_none:n} % \begin{macro}{\use_none:nn} % \begin{macro}{\use_none:nnn} % \begin{macro}{\use_none:nnnn} % \begin{macro}{\use_none:nnnnn} % \begin{macro}{\use_none:nnnnnn} % \begin{macro}{\use_none:nnnnnnn} % \begin{macro}{\use_none:nnnnnnnn} % \begin{macro}{\use_none:nnnnnnnnn} % To gobble tokens from the input we use a standard naming % convention: the number of tokens gobbled is given by the number of % |n|'s following the |:| in the name. Although defining % |\use_none:nnn| and above as separate calls of |\use_none:n| and % |\use_none:nn| is slightly faster, this is very non-intuitive to % the programmer who will assume that expanding such a function once % will take care of gobbling all the tokens in one go. % \begin{macrocode} \cs_set:Npn \use_none:n #1 { } \cs_set:Npn \use_none:nn #1#2 { } \cs_set:Npn \use_none:nnn #1#2#3 { } \cs_set:Npn \use_none:nnnn #1#2#3#4 { } \cs_set:Npn \use_none:nnnnn #1#2#3#4#5 { } \cs_set:Npn \use_none:nnnnnn #1#2#3#4#5#6 { } \cs_set:Npn \use_none:nnnnnnn #1#2#3#4#5#6#7 { } \cs_set:Npn \use_none:nnnnnnnn #1#2#3#4#5#6#7#8 { } \cs_set:Npn \use_none:nnnnnnnnn #1#2#3#4#5#6#7#8#9 { } % \end{macrocode} % \end{macro} % \end{macro} % \end{macro} % \end{macro} % \end{macro} % \end{macro} % \end{macro} % \end{macro} % \end{macro} % % \subsection{Conditional processing and definitions} % % Underneath any predicate function (|_p|) or other conditional forms % (|TF|, etc.) is a built-in logic saying that it after all of the % testing and processing must return the \meta{state} this leaves % \TeX{} in. Therefore, a simple user interface could be something like % \begin{verbatim} % \if_meaning:w #1#2 \prg_return_true: \else: % \if_meaning:w #1#3 \prg_return_true: \else: % \prg_return_false: % \fi: \fi: % \end{verbatim} % Usually, a \TeX{} programmer would have to insert a number of % |\exp_after:wN|s to ensure the state value is returned at exactly % the point where the last conditional is finished. However, that % obscures the code and forces the \TeX{} programmer to prove that % he/she knows the $2^{n}-1$ table. We therefore provide the simpler % interface. % % \begin{macro}{\prg_return_true:} % \begin{macro}{\prg_return_false:} % The idea here is that \cs{int_to_roman:w} will expand fully any % \cs{else:} and the \cs{fi:} that are waiting to be discarded, % before reaching the \cs{c_zero} which will leave the expansion null. % The code can then leave either the first or second argument in the % input stream. This means that all of the branching code has to contain % at least two tokens: see how the logical tests are actually implemented % to see this. % \begin{macrocode} \cs_set_nopar:Npn \prg_return_true: { \exp_after:wN \use_i:nn \int_to_roman:w } \cs_set_nopar:Npn \prg_return_false: { \exp_after:wN \use_ii:nn \int_to_roman:w} % \end{macrocode} % An extended state space could be implemented by including a more % elaborate function in place of \cs{use_i:nn}/\cs{use_ii:nn}. Provided % two arguments are absorbed then the code will work. % \end{macro} % \end{macro} % % \begin{macro}{\prg_set_conditional:Npnn,\prg_new_conditional:Npnn, % \prg_set_protected_conditional:Npnn,\prg_new_protected_conditional:Npnn} % The user functions for the types using parameter text from the % programmer. Call aux function to grab parameters, split the base % function into name and signature and then use, \emph{e.g.}, |\cs_set:Npn| % to define it with. % \begin{macrocode} \cs_set_protected:Npn \prg_set_conditional:Npnn #1 { \prg_get_parm_aux:nw { \cs_split_function:NN #1 \prg_generate_conditional_aux:nnNNnnnn \cs_set:Npn { parm } } } \cs_set_protected:Npn \prg_new_conditional:Npnn #1 { \prg_get_parm_aux:nw { \cs_split_function:NN #1 \prg_generate_conditional_aux:nnNNnnnn \cs_new:Npn { parm } } } \cs_set_protected:Npn \prg_set_protected_conditional:Npnn #1 { \prg_get_parm_aux:nw{ \cs_split_function:NN #1 \prg_generate_conditional_aux:nnNNnnnn \cs_set_protected:Npn { parm } } } \cs_set_protected:Npn \prg_new_protected_conditional:Npnn #1 { \prg_get_parm_aux:nw { \cs_split_function:NN #1 \prg_generate_conditional_aux:nnNNnnnn \cs_new_protected:Npn { parm } } } % \end{macrocode} % \end{macro} % % \begin{macro}{\prg_set_conditional:Nnn,\prg_new_conditional:Nnn, % \prg_set_protected_conditional:Nnn,\prg_new_protected_conditional:Nnn} % The user functions for the types automatically inserting the % correct parameter text based on the signature. Call aux function % after calculating number of arguments, split the base function % into name and signature and then use, \emph{e.g.}, |\cs_set:Npn| to % define it with. % \begin{macrocode} \cs_set_protected:Npn \prg_set_conditional:Nnn #1 { \exp_args:Nnf \prg_get_count_aux:nn { \cs_split_function:NN #1 \prg_generate_conditional_aux:nnNNnnnn \cs_set:Npn { count } } { \cs_get_arg_count_from_signature:N #1 } } \cs_set_protected:Npn \prg_new_conditional:Nnn #1 { \exp_args:Nnf \prg_get_count_aux:nn { \cs_split_function:NN #1 \prg_generate_conditional_aux:nnNNnnnn \cs_new:Npn { count} } { \cs_get_arg_count_from_signature:N #1 } } \cs_set_protected:Npn \prg_set_protected_conditional:Nnn #1{ \exp_args:Nnf \prg_get_count_aux:nn{ \cs_split_function:NN #1 \prg_generate_conditional_aux:nnNNnnnn \cs_set_protected:Npn {count} }{\cs_get_arg_count_from_signature:N #1} } \cs_set_protected:Npn \prg_new_protected_conditional:Nnn #1 { \exp_args:Nnf \prg_get_count_aux:nn { \cs_split_function:NN #1 \prg_generate_conditional_aux:nnNNnnnn \cs_new_protected:Npn {count} } { \cs_get_arg_count_from_signature:N #1 } } % \end{macrocode} % \end{macro} % % \begin{macro}{\prg_set_eq_conditional:NNn,\prg_new_eq_conditional:NNn} % The obvious setting-equal functions. % \begin{macrocode} \cs_set_protected:Npn \prg_set_eq_conditional:NNn #1#2#3 { \prg_set_eq_conditional_aux:NNNn \cs_set_eq:cc #1#2 {#3} } \cs_set_protected:Npn \prg_new_eq_conditional:NNn #1#2#3 { \prg_set_eq_conditional_aux:NNNn \cs_new_eq:cc #1#2 {#3} } % \end{macrocode} % \end{macro} % % \begin{macro}[aux]{\prg_get_parm_aux:nw,\prg_get_count_aux:nn} % For the |Npnn| type we must grab the parameter text before % continuing. We make this a very generic function that takes one % argument before reading everything up to a left brace. Something % similar for the |Nnn| type. % \begin{macrocode} \cs_set:Npn \prg_get_count_aux:nn #1#2 { #1 {#2} } \cs_set:Npn \prg_get_parm_aux:nw #1#2# { #1 {#2} } % \end{macrocode} % \end{macro} % % \begin{macro}[aux]{\prg_generate_conditional_parm_aux:nnNNnnnn, % \prg_generate_conditional_parm_aux:nw} % The workhorse here is going through a list of desired forms, \emph{i.e.}, % |p|, |TF|, |T| and |F|. The first three arguments come from splitting up % the base form of the conditional, which gives the name, signature % and a boolean to signal whether or not there was a colon in the % name. For the time being, we do not use this piece of information % but could well throw an error. The fourth argument is how to % define this function, the fifth is the text |parm| or |count| for % which version to use to define the functions, the sixth is the % parameters to use (possibly empty) or number of arguments, the % seventh is the list of forms to define, the eight is the % replacement text which we will augment when defining the forms. % \begin{macrocode} \cs_set_protected:Npn \prg_generate_conditional_aux:nnNNnnnn #1#2#3#4#5#6#7#8 { \prg_generate_conditional_aux:nnw {#5} { #4 {#1} {#2} {#6} {#8} } #7 , ? , \q_recursion_stop } % \end{macrocode} % Looping through the list of desired forms. First is the text |parm| % or |count|, second is five arguments packed together and third is % the form. Use text and form to call the correct type. % \begin{macrocode} \cs_set_protected:Npn \prg_generate_conditional_aux:nnw #1#2#3 , { \if:w ?#3 \exp_after:wN \use_none_delimit_by_q_recursion_stop:w \fi: \use:c { prg_generate_#3_form_#1:Nnnnn } #2 \prg_generate_conditional_aux:nnw {#1} {#2} } % \end{macrocode} % \end{macro} % % \begin{macro}[aux] % { % \prg_generate_p_form_parm:Nnnnn, % \prg_generate_TF_form_parm:Nnnnn, % \prg_generate_T_form_parm:Nnnnn, % \prg_generate_F_form_parm:Nnnnn % } % How to generate the various forms. The |parm| types here takes the % following arguments: 1: how to define (an N-type), 2: name, 3: % signature, 4: parameter text (or empty), 5: replacement. Remember that % the logic-returning functions expect two arguments to be present after % \cs{c_zero}: notice the construction of the different variants % relies on this, and that the |TF| variant will be slightly faster % than the |T| version. % \begin{macrocode} \cs_set_protected:Npn \prg_generate_p_form_parm:Nnnnn #1#2#3#4#5 { \exp_args:Nc #1 { #2 _p: #3 } #4 { #5 \c_zero \c_true_bool \c_false_bool } } \cs_set_protected:Npn \prg_generate_T_form_parm:Nnnnn #1#2#3#4#5 { \exp_args:Nc #1 { #2 : #3 T } #4 { #5 \c_zero \use:n \use_none:n } } \cs_set_protected:Npn \prg_generate_F_form_parm:Nnnnn #1#2#3#4#5 { \exp_args:Nc #1 { #2 : #3 F } #4 { #5 \c_zero { } } } \cs_set_protected:Npn \prg_generate_TF_form_parm:Nnnnn #1#2#3#4#5 { \exp_args:Nc #1 { #2 : #3 TF } #4 { #5 \c_zero } } % \end{macrocode} % \end{macro} % % \begin{macro}[aux] % { % \prg_generate_p_form_count:Nnnnn, % \prg_generate_TF_form_count:Nnnnn, % \prg_generate_T_form_count:Nnnnn, % \prg_generate_F_form_count:Nnnnn % } % The |count| form is similar, but of course requires a number rather % than a primitive argument specification. % \begin{macrocode} \cs_set_protected:Npn \prg_generate_p_form_count:Nnnnn #1#2#3#4#5 { \cs_generate_from_arg_count:cNnn { #2 _p: #3 } #1 {#4} { #5 \c_zero \c_true_bool \c_false_bool } } \cs_set_protected:Npn \prg_generate_T_form_count:Nnnnn #1#2#3#4#5 { \cs_generate_from_arg_count:cNnn { #2 : #3 T } #1 {#4} { #5 \c_zero \use:n \use_none:n } } \cs_set_protected:Npn \prg_generate_F_form_count:Nnnnn #1#2#3#4#5 { \cs_generate_from_arg_count:cNnn { #2 : #3 F } #1 {#4} { #5 \c_zero { } } } \cs_set_protected:Npn \prg_generate_TF_form_count:Nnnnn #1#2#3#4#5 { \cs_generate_from_arg_count:cNnn { #2 : #3 TF } #1 {#4} { #5 \c_zero } } % \end{macrocode} % \end{macro} % % \begin{macro}[aux]{\prg_set_eq_conditional_aux:NNNn, % \prg_set_eq_conditional_aux:NNNw} % \begin{macrocode} \cs_set_protected:Npn \prg_set_eq_conditional_aux:NNNn #1#2#3#4 { \prg_set_eq_conditional_aux:NNNw #1#2#3#4 , ? , \q_recursion_stop } % \end{macrocode} % Manual clist loop over argument |#4|. % \begin{macrocode} \cs_set_protected:Npn \prg_set_eq_conditional_aux:NNNw #1#2#3#4 , { \if:w ? #4 \scan_stop: \exp_after:wN \use_none_delimit_by_q_recursion_stop:w \fi: #1 { \exp_args:NNc \cs_split_function:NN #2 { prg_conditional_form_#4:nnn } } { \exp_args:NNc \cs_split_function:NN #3 { prg_conditional_form_#4:nnn } } \prg_set_eq_conditional_aux:NNNw #1 {#2} {#3} } % \end{macrocode} % \begin{macrocode} \cs_set:Npn \prg_conditional_form_p:nnn #1#2#3 { #1 _p : #2 } \cs_set:Npn \prg_conditional_form_TF:nnn #1#2#3 { #1 : #2 TF } \cs_set:Npn \prg_conditional_form_T:nnn #1#2#3 { #1 : #2 T } \cs_set:Npn \prg_conditional_form_F:nnn #1#2#3 { #1 : #2 F } % \end{macrocode} % \end{macro} % % All that is left is to define the canonical boolean true and false. % I think Michael originated the idea of expandable boolean tests. At % first these were supposed to expand into either \texttt{TT} or % \texttt{TF} to be tested using |\if:w| but this was later changed to % |00| and |01|, so they could be used in logical % operations. Later again they were changed to being numerical % constants with values of $1$ for true and $0$ for false. We need % this from the get-go. % % \begin{macro}{\c_true_bool} % \begin{macro}{\c_false_bool} % Here are the canonical boolean values. % \begin{macrocode} \tex_chardef:D \c_true_bool = 1~ \tex_chardef:D \c_false_bool = 0~ % \end{macrocode} % \end{macro} % \end{macro} % % \subsection{Dissecting a control sequence} % % \begin{macro}{\cs_to_str:N} % \begin{macro}[aux]{\cs_to_str_aux:w} % This converts a control sequence into the character string of its % name, removing the leading escape character. This turns out to be % a non-trivial matter as there a different cases: % \begin{itemize} % \item The usual case of a printable escape character; % \item the case of a non-printable escape characters, e.g., when % the value of |\tex_escapechar:D| is negative; % \item when the escape character is a space. % \end{itemize} % One approach to solve this is to test how many tokens result from % |\token_to_str:N \a|. If there are two tokens, then the escape % character is printable, while if it is non-printable then only % one is present. % % However, there is an additional complication: the control % sequence itself may start with a space. Clearly that should \emph{not} be % lost in the process of converting to a string. So the approach adopted is % a little more intricate still. When the escape character is printable, % \verb*|\token_to_str:N \ | yields the escape character itself and a space. % The escape sequence will terminate the expansion started by % \cs{int_to_roman:w}, which is a negative number and so will not % gobble the escape character even if it's a number. The \cs{if:w} % test will then be \texttt{false}, and the na\"ive approach of gobbling % the first character of the \cs{token_to_str:N} version of the control % sequence will work, even if the first character is a space. % The second case is that the escape character is itself a space. In this % case, the escape character space is consumed terminating the first % \cs{int_to_roman:w}, and \cs{cs_to_str_aux:w} is expanded. This % inserts a space, making the \cs{if:w} test \texttt{true}. The % second \cs{int_to_roman:w} will then execute the \cs{token_to_str:N}, % with the escape-character space being consumed by the % \cs{int_to_roman:w}, and thus leaving the control sequence name in the % input stream. The final case is where the escape character is not % printable. % The flow here starts with the \verb*|\token_to_str:N \ | giving just a % space, which terminates the first \cs{int_to_roman:w} but leaves no % token for the \cs{if:w} test. This means that the \cs{int_to_roman:w} % is executed before the test is finished. The result is that the % \cs{fi:}, expanded before the \cs{if:w} is finished, becomes % \cs{scan_stop:} \cs{fi:}, and the \cs{scan_stop:} is then used in % the \cs{if:w} test. % In this case, \cs{token_to_str:N} is therefore used with no gobbling at % all, which is exactly what is needed in this case. % \begin{macrocode} \cs_set_nopar:Npn \cs_to_str:N { \if:w \int_to_roman:w - `0 \token_to_str:N \ % \cs_to_str_aux:w \fi: \exp_after:wN \use_none:n \token_to_str:N } \cs_set_nopar:Npn \cs_to_str_aux:w #1 \use_none:n { ~ \int_to_roman:w - `0 \fi: } % \end{macrocode} % \end{macro} % \end{macro} % % \begin{macro}{\cs_split_function:NN} % \begin{macro}[aux]{\cs_split_function_aux:w} % \begin{macro}[aux]{\cs_split_function_auxii:w} % This function takes a function name and splits it into name with % the escape char removed and argument specification. In addition to % this, a third argument, a boolean \meta{true} or \meta{false} is % returned with \meta{true} for when there is a colon in the function % and \meta{false} if there is not. Lastly, the second argument of % |\cs_split_function:NN| is supposed to be a function % taking three variables, one for name, one for signature, and one % for the boolean. For example, % |\cs_split_function:NN\foo_bar:cnx\use_i:nnn| as input % becomes |\use_i:nnn {foo_bar}{cnx}\c_true_bool|. % % Can't use a literal |:| because it has the wrong catcode here, so % it's transformed from |@| with |\tex_lowercase:D|. % \begin{macrocode} \group_begin: \tex_lccode:D `\@ = `\: \scan_stop: \tex_catcode:D `\@ = 12~ \tex_lowercase:D { \group_end: % \end{macrocode} % First ensure that we actually get a properly evaluated str as we % don't know how many expansions |\cs_to_str:N| requires. Insert % extra colon to catch the error cases. % \begin{macrocode} \cs_set:Npn \cs_split_function:NN #1#2 { \exp_after:wN \cs_split_function_aux:w \int_to_roman:w - `\q \cs_to_str:N #1 @ a \q_stop #2 } % \end{macrocode} % If no colon in the name, |#2| is |a| with catcode 11 and |#3| is % empty. If colon in the name, then either |#2| is a colon or the % first letter of the signature. The letters here have catcode 12. % If a colon was given we need to a) split off the colon and quark at % the end and b) ensure we return the name, signature and boolean true % We can't use |\quark_if_no_value:NTF| yet but this is very safe % anyway as all tokens have catcode~12. % \begin{macrocode} \cs_set:Npn \cs_split_function_aux:w #1 @ #2#3 \q_stop #4 { \if_meaning:w a #2 \exp_after:wN \use_i:nn \else: \exp_after:wN\use_ii:nn \fi: { #4 {#1} { } \c_false_bool } { \cs_split_function_auxii:w #2#3 \q_stop #4 {#1} } } \cs_set:Npn \cs_split_function_auxii:w #1 @a \q_stop #2#3 { #2{#3}{#1}\c_true_bool } % \end{macrocode} % End of lowercase % \begin{macrocode} } % \end{macrocode} % \end{macro} % \end{macro} % \end{macro} % % \begin{macro}{\cs_get_function_name:N, \cs_get_function_signature:N} % Now returning the name is trivial: just discard the last two % arguments. Similar for signature. % \begin{macrocode} \cs_set:Npn \cs_get_function_name:N #1 { \cs_split_function:NN #1 \use_i:nnn } \cs_set:Npn \cs_get_function_signature:N #1 { \cs_split_function:NN #1 \use_ii:nnn } % \end{macrocode} % \end{macro} % % \subsection{Exist or free} % % A control sequence is said to \emph{exist} (to be used) if has an entry in % the hash table and its meaning is different from the primitive % |\tex_relax:D| token. A control sequence is said to be \emph{free} % (to be defined) if it does not already exist. % % \begin{macro}[pTF]{\cs_if_exist:N,\cs_if_exist:c} % Two versions for checking existence. For the |N| form we firstly % check for |\scan_stop:| and then if it is in the hash % table. There is no problem when inputting something like |\else:| % or |\fi:| as \TeX{} will only ever skip input in case the token % tested against is |\scan_stop:|. % \begin{macrocode} \prg_set_conditional:Npnn \cs_if_exist:N #1 { p , T , F , TF } { \if_meaning:w #1 \scan_stop: \prg_return_false: \else: \if_cs_exist:N #1 \prg_return_true: \else: \prg_return_false: \fi: \fi: } % \end{macrocode} % For the |c| form we firstly check if it is in the hash table and % then for |\scan_stop:| so that we do not add it to the hash table % unless it was already there. Here we have to be careful as the text % to be skipped if the first test is false may contain tokens that % disturb the scanner. Therefore, we ensure that the second test is % performed after the first one has concluded completely. % \begin{macrocode} \prg_set_conditional:Npnn \cs_if_exist:c #1 { p , T , F , TF } { \if_cs_exist:w #1 \cs_end: \exp_after:wN \use_i:nn \else: \exp_after:wN \use_ii:nn \fi: { \exp_after:wN \if_meaning:w \cs:w #1 \cs_end: \scan_stop: \prg_return_false: \else: \prg_return_true: \fi: } \prg_return_false: } % \end{macrocode} % \end{macro} % \end{macro} % % \begin{macro}[pTF]{\cs_if_free:N,\cs_if_free:c} % The logical reversal of the above. % \begin{macrocode} \prg_set_conditional:Npnn \cs_if_free:N #1 { p , T , F , TF } { \if_meaning:w #1 \scan_stop: \prg_return_true: \else: \if_cs_exist:N #1 \prg_return_false: \else: \prg_return_true: \fi: \fi: } \prg_set_conditional:Npnn \cs_if_free:c #1 { p , T , F , TF } { \if_cs_exist:w #1 \cs_end: \exp_after:wN \use_i:nn \else: \exp_after:wN \use_ii:nn \fi: { \exp_after:wN \if_meaning:w \cs:w #1 \cs_end: \scan_stop: \prg_return_true: \else: \prg_return_false: \fi: } { \prg_return_true: } } % \end{macrocode} % \end{macro} % % \subsection{Defining and checking (new) functions} % % \begin{macro}{\c_minus_one, \c_zero, \c_sixteen} % \begin{macro}{\c_six, \c_seven, \c_twelve} % We need the constants |\c_minus_one| and |\c_sixteen| now for % writing information to the log and the terminal and |\c_zero| % which is used by some functions in the \textsf{l3alloc} module. The % rest are defined in the \textsf{l3int} module -- at least for the % ones that can be defined with |\tex_chardef:D| or % |\tex_mathchardef:D|. For other constants the \textsf{l3int} module is % required but it can't be used until the allocation has been set % up properly! The actual allocation mechanism is in % \textsf{l3alloc} and as \TeX{} wants to reserve count registers % 0--9, the first available one is~10 so we use that for % |\c_minus_one|. % \begin{macrocode} %<*package> \tex_let:D \c_minus_one \m@ne % %<*initex> \tex_countdef:D \c_minus_one = 10 ~ \c_minus_one = -1 ~ % \tex_chardef:D \c_sixteen = 16~ \tex_chardef:D \c_zero = 0~ \tex_chardef:D \c_six = 6~ \tex_chardef:D \c_seven = 7~ \tex_chardef:D \c_twelve = 12~ % \end{macrocode} % \end{macro} % \end{macro} % % \begin{macro}{\c_max_register_int} % This is here as this particular integer is needed both in package % mode and to bootstrap \pkg{l3alloc} % \begin{macrocode} \tex_mathchardef:D \c_max_register_int = 32 767 \scan_stop: % \end{macrocode} % \end{macro} % % We provide two kinds of functions that can be used to define % control sequences. On the one hand we have functions that check % if their argument doesn't already exist, they are called % |\..._new|. The second type of defining functions doesn't check % if the argument is already defined. % % Before we can define them, we need some auxiliary macros that % allow us to generate error messages. The definitions here are % only temporary, they will be redefined later on. % % \begin{macro}{\iow_log:x} % \begin{macro}{\iow_term:x} % We define a routine to write only to the log file. And a % similar one for writing to both the log file and the terminal. % These will be redefined later by \pkg{l3io}. % \begin{macrocode} \cs_set_protected_nopar:Npn \iow_log:x { \tex_immediate:D \tex_write:D \c_minus_one } \cs_set_protected_nopar:Npn \iow_term:x { \tex_immediate:D \tex_write:D \c_sixteen } % \end{macrocode} % \end{macro} % \end{macro} % % \begin{macro}{\msg_kernel_error:nnxx} % \begin{macro}{\msg_kernel_error:nnx} % \begin{macro}{\msg_kernel_error:nn} % If an internal error occurs before \LaTeX3 has loaded \pkg{l3msg} then % the code should issue a usable if terse error message and halt. This % can only happen if a coding error is made by the team, so this is % a reasonable response. % \begin{macrocode} \cs_set_protected_nopar:Npn \msg_kernel_error:nnxx #1#2#3#4 { \tex_errmessage:D { !!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!~! ^^J Argh,~internal~LaTeX3~error! ^^J ^^J Module ~ #1 , ~ message~name~"#2": ^^J Arguments~'#3'~and~'#4' ^^J ^^J This~is~one~for~The~LaTeX3~Project:~bailing~out } \tex_end:D } \cs_set_protected_nopar:Npn \msg_kernel_error:nnx #1#2#3 { \msg_kernel_error:nnxx {#1} {#2} {#3} { } } \cs_set_protected_nopar:Npn \msg_kernel_error:nn #1#2 { \msg_kernel_error:nnxx {#1} {#2} { } { } } % \end{macrocode} % \end{macro} % \end{macro} % \end{macro} % % \begin{macro}{\msg_line_context:} % Another one from \pkg{l3msg} which will be altered later. % \begin{macrocode} \cs_set_nopar:Npn \msg_line_context: { on~line~\tex_the:D \tex_inputlineno:D } % \end{macrocode} % \end{macro} % % \begin{macro}{\chk_if_free_cs:N, \chk_if_free_cs:c} % This command is called by |\cs_new_nopar:Npn| and |\cs_new_eq:NN| % \emph{etc.}\ % to make sure that the argument sequence is not already in use. If % it is, an error is signalled. It checks if \meta{csname} is % undefined or |\scan_stop:|. Otherwise an error message is % issued. We have to make sure we don't put the argument into the % conditional processing since it may be an |\if...| type function! % \begin{macrocode} \cs_set_protected_nopar:Npn \chk_if_free_cs:N #1 { \cs_if_free:NF #1 { \msg_kernel_error:nnxx { kernel } { command-already-defined } { \token_to_str:N #1 } { \token_to_meaning:N #1 } } } %<*package> \tex_ifodd:D \l@expl@log@functions@bool \cs_set_protected_nopar:Npn \chk_if_free_cs:N #1 { \cs_if_free:NF #1 { \msg_kernel_error:nnxx { kernel } { command-already-defined } { \token_to_str:N #1 } { \token_to_meaning:N #1 } } \iow_log:x { Defining~\token_to_str:N #1~ \msg_line_context: } } \fi: % \cs_set_protected_nopar:Npn \chk_if_free_cs:c { \exp_args:Nc \chk_if_free_cs:N } % \end{macrocode} % \end{macro} % % \begin{macro}{\chk_if_exist_cs:N, \chk_if_exist_cs:c} % This function issues a warning message when the control sequence % in its argument does not exist. % \begin{macrocode} \cs_set_protected_nopar:Npn \chk_if_exist_cs:N #1 { \cs_if_exist:NF #1 { \msg_kernel_error:nnxx { kernel } { command-not-defined } { \token_to_str:N #1 } { \token_to_meaning:N #1 } } } \cs_set_protected_nopar:Npn \chk_if_exist_cs:c { \exp_args:Nc \chk_if_exist_cs:N } % \end{macrocode} % \end{macro} % % \subsection{More new definitions} % % \begin{macro}{\cs_new_nopar:Npn} % \begin{macro}{\cs_new_nopar:Npx} % \begin{macro}{\cs_new:Npn} % \begin{macro}{\cs_new:Npx} % \begin{macro}{\cs_new_protected_nopar:Npn} % \begin{macro}{\cs_new_protected_nopar:Npx} % \begin{macro}{\cs_new_protected:Npn} % \begin{macro}{\cs_new_protected:Npx} % Global versions of the above functions. % \begin{macrocode} \cs_set:Npn \cs_tmp:w #1#2 { \cs_set_protected_nopar:Npn #1 ##1 { \chk_if_free_cs:N ##1 #2 ##1 } } \cs_tmp:w \cs_new_nopar:Npn \cs_gset_nopar:Npn \cs_tmp:w \cs_new_nopar:Npx \cs_gset_nopar:Npx \cs_tmp:w \cs_new:Npn \cs_gset:Npn \cs_tmp:w \cs_new:Npx \cs_gset:Npx \cs_tmp:w \cs_new_protected_nopar:Npn \cs_gset_protected_nopar:Npn \cs_tmp:w \cs_new_protected_nopar:Npx \cs_gset_protected_nopar:Npx \cs_tmp:w \cs_new_protected:Npn \cs_gset_protected:Npn \cs_tmp:w \cs_new_protected:Npx \cs_gset_protected:Npx % \end{macrocode} % \end{macro} % \end{macro} % \end{macro} % \end{macro} % \end{macro} % \end{macro} % \end{macro} % \end{macro} % % \begin{macro}{\cs_set_nopar:cpn} % \begin{macro}{\cs_set_nopar:cpx} % \begin{macro}{\cs_gset_nopar:cpn} % \begin{macro}{\cs_gset_nopar:cpx} % \begin{macro}{\cs_new_nopar:cpn} % \begin{macro}{\cs_new_nopar:cpx} % Like |\cs_set_nopar:Npn| and |\cs_new_nopar:Npn|, except that the % first argument consists of the sequence of characters that should % be used to form the name of the desired control sequence (the |c| % stands for csname argument, see the expansion module). Global % versions are also provided. % % |\cs_set_nopar:cpn|\meta{string}\meta{rep-text} will turn \meta{string} % into a csname and then assign \meta{rep-text} to it by using % |\cs_set_nopar:Npn|. This means that there might be a parameter % string between the two arguments. % \begin{macrocode} \cs_set:Npn \cs_tmp:w #1#2 { \cs_new_protected_nopar:Npn #1 { \exp_args:Nc #2 } } \cs_tmp:w \cs_set_nopar:cpn \cs_set_nopar:Npn \cs_tmp:w \cs_set_nopar:cpx \cs_set_nopar:Npx \cs_tmp:w \cs_gset_nopar:cpn \cs_gset_nopar:Npn \cs_tmp:w \cs_gset_nopar:cpx \cs_gset_nopar:Npx \cs_tmp:w \cs_new_nopar:cpn \cs_new_nopar:Npn \cs_tmp:w \cs_new_nopar:cpx \cs_new_nopar:Npx % \end{macrocode} % \end{macro} % \end{macro} % \end{macro} % \end{macro} % \end{macro} % \end{macro} % % \begin{macro}{\cs_set:cpn} % \begin{macro}{\cs_set:cpx} % \begin{macro}{\cs_gset:cpn} % \begin{macro}{\cs_gset:cpx} % \begin{macro}{\cs_new:cpn} % \begin{macro}{\cs_new:cpx} % Variants of the |\cs_set:Npn| versions which make a csname out % of the first arguments. We may also do this globally. % \begin{macrocode} \cs_tmp:w \cs_set:cpn \cs_set:Npn \cs_tmp:w \cs_set:cpx \cs_set:Npx \cs_tmp:w \cs_gset:cpn \cs_gset:Npn \cs_tmp:w \cs_gset:cpx \cs_gset:Npx \cs_tmp:w \cs_new:cpn \cs_new:Npn \cs_tmp:w \cs_new:cpx \cs_new:Npx % \end{macrocode} % \end{macro} % \end{macro} % \end{macro} % \end{macro} % \end{macro} % \end{macro} % % \begin{macro}{\cs_set_protected_nopar:cpn} % \begin{macro}{\cs_set_protected_nopar:cpx} % \begin{macro}{\cs_gset_protected_nopar:cpn} % \begin{macro}{\cs_gset_protected_nopar:cpx} % \begin{macro}{\cs_new_protected_nopar:cpn} % \begin{macro}{\cs_new_protected_nopar:cpx} % Variants of the |\cs_set_protected_nopar:Npn| versions which make a csname % out of the first arguments. We may also do this globally. % \begin{macrocode} \cs_tmp:w \cs_set_protected_nopar:cpn \cs_set_protected_nopar:Npn \cs_tmp:w \cs_set_protected_nopar:cpx \cs_set_protected_nopar:Npx \cs_tmp:w \cs_gset_protected_nopar:cpn \cs_gset_protected_nopar:Npn \cs_tmp:w \cs_gset_protected_nopar:cpx \cs_gset_protected_nopar:Npx \cs_tmp:w \cs_new_protected_nopar:cpn \cs_new_protected_nopar:Npn \cs_tmp:w \cs_new_protected_nopar:cpx \cs_new_protected_nopar:Npx % \end{macrocode} % \end{macro} % \end{macro} % \end{macro} % \end{macro} % \end{macro} % \end{macro} % % \begin{macro}{\cs_set_protected:cpn} % \begin{macro}{\cs_set_protected:cpx} % \begin{macro}{\cs_gset_protected:cpn} % \begin{macro}{\cs_gset_protected:cpx} % \begin{macro}{\cs_new_protected:cpn} % \begin{macro}{\cs_new_protected:cpx} % Variants of the |\cs_set_protected:Npn| versions which make a csname % out of the first arguments. We may also do this globally. % \begin{macrocode} \cs_tmp:w \cs_set_protected:cpn \cs_set_protected:Npn \cs_tmp:w \cs_set_protected:cpx \cs_set_protected:Npx \cs_tmp:w \cs_gset_protected:cpn \cs_gset_protected:Npn \cs_tmp:w \cs_gset_protected:cpx \cs_gset_protected:Npx \cs_tmp:w \cs_new_protected:cpn \cs_new_protected:Npn \cs_tmp:w \cs_new_protected:cpx \cs_new_protected:Npx % \end{macrocode} % \end{macro} % \end{macro} % \end{macro} % \end{macro} % \end{macro} % \end{macro} % % \subsection{Copying definitions} % % \begin{macro}{\cs_set_eq:NN} % \begin{macro}{\cs_set_eq:cN} % \begin{macro}{\cs_set_eq:Nc} % \begin{macro}{\cs_set_eq:cc} % These macros allow us to copy the definition of a control sequence % to another control sequence. % % The |=| sign allows us to define funny char tokens like |=| % itself or \verb*| | with this function. For the definition of % |\c_space_char{~}| to work we need the |~| after the |=|. % % |\cs_set_eq:NN| is long to avoid problems with a literal argument % of |\par|. While |\cs_new_eq:NN| will probably never be correct % with a first argument of |\par|, define it long in order to throw % an \enquote{already defined} error rather than % \enquote{runaway argument}. % \begin{macrocode} \cs_new_protected:Npn \cs_set_eq:NN #1 { \tex_let:D #1 =~ } \cs_new_protected_nopar:Npn \cs_set_eq:cN { \exp_args:Nc \cs_set_eq:NN } \cs_new_protected_nopar:Npn \cs_set_eq:Nc { \exp_args:NNc \cs_set_eq:NN } \cs_new_protected_nopar:Npn \cs_set_eq:cc { \exp_args:Ncc \cs_set_eq:NN } % \end{macrocode} % \end{macro} % \end{macro} % \end{macro} % \end{macro} % % \begin{macro}{\cs_new_eq:NN} % \begin{macro}{\cs_new_eq:cN} % \begin{macro}{\cs_new_eq:Nc} % \begin{macro}{\cs_new_eq:cc} % \begin{macrocode} \cs_new_protected:Npn \cs_new_eq:NN #1 { \chk_if_free_cs:N #1 \tex_global:D \cs_set_eq:NN #1 } \cs_new_protected_nopar:Npn \cs_new_eq:cN { \exp_args:Nc \cs_new_eq:NN } \cs_new_protected_nopar:Npn \cs_new_eq:Nc { \exp_args:NNc \cs_new_eq:NN } \cs_new_protected_nopar:Npn \cs_new_eq:cc { \exp_args:Ncc \cs_new_eq:NN } % \end{macrocode} % \end{macro} % \end{macro} % \end{macro} % \end{macro} % % \begin{macro}{\cs_gset_eq:NN} % \begin{macro}{\cs_gset_eq:cN} % \begin{macro}{\cs_gset_eq:Nc} % \begin{macro}{\cs_gset_eq:cc} % \begin{macrocode} \cs_new_protected_nopar:Npn \cs_gset_eq:NN { \tex_global:D \cs_set_eq:NN } \cs_new_protected_nopar:Npn \cs_gset_eq:Nc { \exp_args:NNc \cs_gset_eq:NN } \cs_new_protected_nopar:Npn \cs_gset_eq:cN { \exp_args:Nc \cs_gset_eq:NN } \cs_new_protected_nopar:Npn \cs_gset_eq:cc { \exp_args:Ncc \cs_gset_eq:NN } % \end{macrocode} % \end{macro} % \end{macro} % \end{macro} % \end{macro} % % \subsection{Undefining functions} % % \begin{macro}{\cs_undefine:N, \cs_undefine:c} % The following function is used to free the main memory from the % definition of some function that isn't in use any longer. % The \texttt{c} variant is careful not to add the control sequence % to the hash table if it isn't there yet, and it also avoids nesting % \TeX{} conditionals in case |#1| is unbalanced in this matter. % \begin{macrocode} \cs_new_protected_nopar:Npn \cs_undefine:N #1 { \cs_gset_eq:NN #1 \c_undefined:D } \cs_new_protected_nopar:Npn \cs_undefine:c #1 { \if_cs_exist:w #1 \cs_end: \exp_after:wN \use:n \else: \exp_after:wN \use_none:n \fi: { \cs_gset_eq:cN {#1} \c_undefined:D } } % \end{macrocode} % \end{macro} % % \subsection{Defining functions from a given number of arguments} % % \begin{macro}{\cs_get_arg_count_from_signature:N} % \begin{macro}[aux]{\cs_get_arg_count_from_signature_aux:nnN} % \begin{macro}[aux]{\cs_get_arg_count_from_signature_auxii:w} % Counting the number of tokens in the signature, i.e., the number % of arguments the function should take. If there is no signature, % we return that there is $-1$ arguments to signal an error. % Otherwise we insert the string |9876543210| after the signature. % If the signature is empty, the number we want is $0$ so we remove % the first nine tokens and return the tenth. Similarly, if the % signature is |nnn| we want to remove the nine tokens |nnn987654| % and return $3$. Therefore, we simply remove the first nine tokens % and then return the tenth. % \begin{macrocode} \cs_new:Npn \cs_get_arg_count_from_signature:N #1 { \cs_split_function:NN #1 \cs_get_arg_count_from_signature_aux:nnN } \cs_new:Npn \cs_get_arg_count_from_signature_aux:nnN #1#2#3 { \if_predicate:w #3 \exp_after:wN \use_i:nn \else: \exp_after:wN\use_ii:nn \fi: { \exp_after:wN \cs_get_arg_count_from_signature_auxii:w \use_none:nnnnnnnnn #2 9876543210 \q_stop } { -1 } } \cs_new:Npn \cs_get_arg_count_from_signature_auxii:w #1#2 \q_stop {#1} % \end{macrocode} % A variant form we need right away. % \begin{macrocode} \cs_new_nopar:Npn \cs_get_arg_count_from_signature:c { \exp_args:Nc \cs_get_arg_count_from_signature:N } % \end{macrocode} % \end{macro} % \end{macro} % \end{macro} % % \begin{macro}[aux]{\cs_generate_from_arg_count:NNnn} % \begin{macro}[aux]{\cs_generate_from_arg_count_error_msg:Nn} % \begin{macro}[aux]{\cs_generate_from_arg_count_aux:nwn} % We provide a constructor function for defining functions with a % given number of arguments. For this we need to choose the correct % parameter text and then use that when defining. Since \TeX{} % supports from zero to nine arguments, we use a simple switch to % choose the correct parameter text, ensuring the result is returned % after finishing the conditional. If it is not between zero and % nine, we throw an error. % % 1: function to define, 2: with what to define it, 3: the number of % args it requires and 4: the replacement text % \begin{macrocode} \cs_new_protected:Npn \cs_generate_from_arg_count:NNnn #1#2#3#4 { \if_case:w \int_eval:w #3 \int_eval_end: \cs_generate_from_arg_count_aux:nwn {} \or: \cs_generate_from_arg_count_aux:nwn {##1} \or: \cs_generate_from_arg_count_aux:nwn {##1##2} \or: \cs_generate_from_arg_count_aux:nwn {##1##2##3} \or: \cs_generate_from_arg_count_aux:nwn {##1##2##3##4} \or: \cs_generate_from_arg_count_aux:nwn {##1##2##3##4##5} \or: \cs_generate_from_arg_count_aux:nwn {##1##2##3##4##5##6} \or: \cs_generate_from_arg_count_aux:nwn {##1##2##3##4##5##6##7} \or: \cs_generate_from_arg_count_aux:nwn {##1##2##3##4##5##6##7##8} \or: \cs_generate_from_arg_count_aux:nwn {##1##2##3##4##5##6##7##8##9} \else: \cs_generate_from_arg_count_error_msg:Nn #1 {#3} \use_i:nnn \fi: {#2#1} {#4} } \cs_new_protected_nopar:Npn \cs_generate_from_arg_count_aux:nwn #1 #2 \fi: #3 { \fi: #3 #1 } % \end{macrocode} % A variant form we need right away. % \begin{macrocode} \cs_new_nopar:Npn \cs_generate_from_arg_count:cNnn { \exp_args:Nc \cs_generate_from_arg_count:NNnn } % \end{macrocode} % The error message. Elsewhere we use the value of $-1$ to signal a % missing colon in a function, so provide a hint for help on this. % \begin{macrocode} \cs_new:Npn \cs_generate_from_arg_count_error_msg:Nn #1#2 { \msg_kernel_error:nnxx { kernel } { bad-number-of-arguments } { \token_to_str:N #1 } { \int_eval:n {#2} } } % \end{macrocode} % \end{macro} % \end{macro} % \end{macro} % % \subsection{Using the signature to define functions} % % We can now combine some of the tools we have to provide a simple % interface for defining functions. We define some simpler functions % with user interface |\cs_set:Nn \foo_bar:nn {#1,#2}|, \emph{i.e.}, the % number of arguments is read from the signature. % % \begin{macro}{\cs_set:Nn} % \begin{macro}{\cs_set:Nx} % \begin{macro}{\cs_set_nopar:Nn} % \begin{macro}{\cs_set_nopar:Nx} % \begin{macro}{\cs_set_protected:Nn} % \begin{macro}{\cs_set_protected:Nx} % \begin{macro}{\cs_set_protected_nopar:Nn} % \begin{macro}{\cs_set_protected_nopar:Nx} % \begin{macro}{\cs_gset:Nn} % \begin{macro}{\cs_gset:Nx} % \begin{macro}{\cs_gset_nopar:Nn} % \begin{macro}{\cs_gset_nopar:Nx} % \begin{macro}{\cs_gset_protected:Nn} % \begin{macro}{\cs_gset_protected:Nx} % \begin{macro}{\cs_gset_protected_nopar:Nn} % \begin{macro}{\cs_gset_protected_nopar:Nx} % We want to define |\cs_set:Nn| as % \begin{verbatim} % \cs_set_protected:Npn \cs_set:Nn #1#2 % { % \cs_generate_from_arg_count:NNnn #1 \cs_set:Npn % { \cs_get_arg_count_from_signature:N #1 } {#2} % } % \end{verbatim} % In short, to define |\cs_set:Nn| we need just use |\cs_set:Npn|, % everything else is the same for each variant. Therefore, we can % make it simpler by temporarily defining a function to do this for % us. % \begin{macrocode} \cs_set:Npn \cs_tmp:w #1#2#3 { \cs_set_protected:cpx { cs_ #1 : #2 } ##1##2 { \exp_not:N \cs_generate_from_arg_count:NNnn ##1 \exp_after:wN \exp_not:N \cs:w cs_#1 : #3 \cs_end: { \exp_not:N\cs_get_arg_count_from_signature:N ##1 }{##2} } } % \end{macrocode} % Then we define the 32 variants beginning with |N|. % \begin{macrocode} \cs_tmp:w { set } { Nn } { Npn } \cs_tmp:w { set } { Nx } { Npx } \cs_tmp:w { set_nopar } { Nn } { Npn } \cs_tmp:w { set_nopar } { Nx } { Npx } \cs_tmp:w { set_protected } { Nn } { Npn } \cs_tmp:w { set_protected } { Nx } { Npx } \cs_tmp:w { set_protected_nopar } { Nn } { Npn } \cs_tmp:w { set_protected_nopar } { Nx } { Npx } \cs_tmp:w { gset } { Nn } { Npn } \cs_tmp:w { gset } { Nx } { Npx } \cs_tmp:w { gset_nopar } { Nn } { Npn } \cs_tmp:w { gset_nopar } { Nx } { Npx } \cs_tmp:w { gset_protected } { Nn } { Npn } \cs_tmp:w { gset_protected } { Nx } { Npx } \cs_tmp:w { gset_protected_nopar } { Nn } { Npn } \cs_tmp:w { gset_protected_nopar } { Nx } { Npx } % \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} % % \begin{macro}{\cs_new:Nn} % \begin{macro}{\cs_new:Nx} % \begin{macro}{\cs_new_nopar:Nn} % \begin{macro}{\cs_new_nopar:Nx} % \begin{macro}{\cs_new_protected:Nn} % \begin{macro}{\cs_new_protected:Nx} % \begin{macro}{\cs_new_protected_nopar:Nn} % \begin{macro}{\cs_new_protected_nopar:Nx} % \begin{macrocode} \cs_tmp:w { new } { Nn } { Npn } \cs_tmp:w { new } { Nx } { Npx } \cs_tmp:w { new_nopar } { Nn } { Npn } \cs_tmp:w { new_nopar } { Nx } { Npx } \cs_tmp:w { new_protected } { Nn } { Npn } \cs_tmp:w { new_protected } { Nx } { Npx } \cs_tmp:w { new_protected_nopar } { Nn } { Npn } \cs_tmp:w { new_protected_nopar } { Nx } { Npx } % \end{macrocode} % \end{macro} % \end{macro} % \end{macro} % \end{macro} % \end{macro} % \end{macro} % \end{macro} % \end{macro} % % Then something similar for the |c| variants. % \begin{verbatim} % \cs_set_protected:Npn \cs_set:cn #1#2 % { % \cs_generate_from_arg_count:cNnn {#1} \cs_set:Npn % { \cs_get_arg_count_from_signature:c {#1} } {#2} % } % \end{verbatim} % \begin{macrocode} \cs_set:Npn \cs_tmp:w #1#2#3 { \cs_set_protected:cpx {cs_#1:#2}##1##2{ \exp_not:N\cs_generate_from_arg_count:cNnn {##1} \exp_after:wN \exp_not:N \cs:w cs_#1:#3 \cs_end: { \exp_not:N \cs_get_arg_count_from_signature:c {##1} } {##2} } } % \end{macrocode} % \begin{macro}{\cs_set:cn} % \begin{macro}{\cs_set:cx} % \begin{macro}{\cs_set_nopar:cn} % \begin{macro}{\cs_set_nopar:cx} % \begin{macro}{\cs_set_protected:cn} % \begin{macro}{\cs_set_protected:cx} % \begin{macro}{\cs_set_protected_nopar:cn} % \begin{macro}{\cs_set_protected_nopar:cx} % \begin{macro}{\cs_gset:cn} % \begin{macro}{\cs_gset:cx} % \begin{macro}{\cs_gset_nopar:cn} % \begin{macro}{\cs_gset_nopar:cx} % \begin{macro}{\cs_gset_protected:cn} % \begin{macro}{\cs_gset_protected:cx} % \begin{macro}{\cs_gset_protected_nopar:cn} % \begin{macro}{\cs_gset_protected_nopar:cx} % The 32 |c| variants. % \begin{macrocode} \cs_tmp:w { set } { cn } { Npn } \cs_tmp:w { set } { cx } { Npx } \cs_tmp:w { set_nopar } { cn } { Npn } \cs_tmp:w { set_nopar } { cx } { Npx } \cs_tmp:w { set_protected } { cn } { Npn } \cs_tmp:w { set_protected } { cx } { Npx } \cs_tmp:w { set_protected_nopar } { cn } { Npn } \cs_tmp:w { set_protected_nopar } { cx } { Npx } \cs_tmp:w { gset } { cn } { Npn } \cs_tmp:w { gset } { cx } { Npx } \cs_tmp:w { gset_nopar } { cn } { Npn } \cs_tmp:w { gset_nopar } { cx } { Npx } \cs_tmp:w { gset_protected } { cn } { Npn } \cs_tmp:w { gset_protected } { cx } { Npx } \cs_tmp:w { gset_protected_nopar } { cn } { Npn } \cs_tmp:w { gset_protected_nopar } { cx } { Npx } % \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} % % \begin{macro}{\cs_new:cn} % \begin{macro}{\cs_new:cx} % \begin{macro}{\cs_new_nopar:cn} % \begin{macro}{\cs_new_nopar:cx} % \begin{macro}{\cs_new_protected:cn} % \begin{macro}{\cs_new_protected:cx} % \begin{macro}{\cs_new_protected_nopar:cn} % \begin{macro}{\cs_new_protected_nopar:cx} % \begin{macrocode} \cs_tmp:w { new } { cn } { Npn } \cs_tmp:w { new } { cx } { Npx } \cs_tmp:w { new_nopar } { cn } { Npn } \cs_tmp:w { new_nopar } { cx } { Npx } \cs_tmp:w { new_protected } { cn } { Npn } \cs_tmp:w { new_protected } { cx } { Npx } \cs_tmp:w { new_protected_nopar } { cn } { Npn } \cs_tmp:w { new_protected_nopar } { cx } { Npx } % \end{macrocode} % \end{macro} % \end{macro} % \end{macro} % \end{macro} % \end{macro} % \end{macro} % \end{macro} % \end{macro} % % \subsection{Checking control sequence equality} % % \begin{macro}[pTF]{\cs_if_eq:NN,\cs_if_eq:cN,\cs_if_eq:Nc,\cs_if_eq:cc} % Check if two control sequences are identical. % \begin{macrocode} \prg_new_conditional:Npnn \cs_if_eq:NN #1#2 { p , T , F , TF } { \if_meaning:w #1#2 \prg_return_true: \else: \prg_return_false: \fi: } \cs_new_nopar:Npn \cs_if_eq_p:cN { \exp_args:Nc \cs_if_eq_p:NN } \cs_new_nopar:Npn \cs_if_eq:cNTF { \exp_args:Nc \cs_if_eq:NNTF } \cs_new_nopar:Npn \cs_if_eq:cNT { \exp_args:Nc \cs_if_eq:NNT } \cs_new_nopar:Npn \cs_if_eq:cNF { \exp_args:Nc \cs_if_eq:NNF } \cs_new_nopar:Npn \cs_if_eq_p:Nc { \exp_args:NNc \cs_if_eq_p:NN } \cs_new_nopar:Npn \cs_if_eq:NcTF { \exp_args:NNc \cs_if_eq:NNTF } \cs_new_nopar:Npn \cs_if_eq:NcT { \exp_args:NNc \cs_if_eq:NNT } \cs_new_nopar:Npn \cs_if_eq:NcF { \exp_args:NNc \cs_if_eq:NNF } \cs_new_nopar:Npn \cs_if_eq_p:cc { \exp_args:Ncc \cs_if_eq_p:NN } \cs_new_nopar:Npn \cs_if_eq:ccTF { \exp_args:Ncc \cs_if_eq:NNTF } \cs_new_nopar:Npn \cs_if_eq:ccT { \exp_args:Ncc \cs_if_eq:NNT } \cs_new_nopar:Npn \cs_if_eq:ccF { \exp_args:Ncc \cs_if_eq:NNF } % \end{macrocode} % \end{macro} % % \subsection{Diagnostic wrapper functions} % % \begin{macro}{\kernel_register_show:N, \kernel_register_show:c} % \begin{macrocode} \cs_new_nopar:Npn \kernel_register_show:N #1 { \cs_if_exist:NTF #1 { \tex_showthe:D #1 } { \msg_kernel_error:nnx { kernel } { variable-not-defined } { \token_to_str:N #1 } } } \cs_new_nopar:Npn \kernel_register_show:c { \exp_args:Nc \int_show:N } % \end{macrocode} % \end{macro} % % \subsection{Engine specific definitions} % % \begin{macro}[pTF]{\xetex_if_engine:, \luatex_if_engine:, \pdftex_if_engine:} % In some cases it will be useful to know which engine we're running. % This can all be hard-coded for speed. % \begin{macrocode} \cs_new_eq:NN \luatex_if_engine:T \use_none:n \cs_new_eq:NN \luatex_if_engine:F \use:n \cs_new_eq:NN \luatex_if_engine:TF \use_ii:nn \cs_new_eq:NN \pdftex_if_engine:T \use:n \cs_new_eq:NN \pdftex_if_engine:F \use_none:n \cs_new_eq:NN \pdftex_if_engine:TF \use_i:nn \cs_new_eq:NN \xetex_if_engine:T \use_none:n \cs_new_eq:NN \xetex_if_engine:F \use:n \cs_new_eq:NN \xetex_if_engine:TF \use_ii:nn \cs_new_eq:NN \luatex_if_engine_p: \c_false_bool \cs_new_eq:NN \pdftex_if_engine_p: \c_true_bool \cs_new_eq:NN \xetex_if_engine_p: \c_false_bool \cs_if_exist:NT \xetex_XeTeXversion:D { \cs_set_eq:NN \pdftex_if_engine:T \use_none:n \cs_set_eq:NN \pdftex_if_engine:F \use:n \cs_set_eq:NN \pdftex_if_engine:TF \use_ii:nn \cs_set_eq:NN \xetex_if_engine:T \use:n \cs_set_eq:NN \xetex_if_engine:F \use_none:n \cs_set_eq:NN \xetex_if_engine:TF \use_i:nn \cs_set_eq:NN \pdftex_if_engine_p: \c_false_bool \cs_set_eq:NN \xetex_if_engine_p: \c_true_bool } \cs_if_exist:NT \luatex_directlua:D { \cs_set_eq:NN \luatex_if_engine:T \use:n \cs_set_eq:NN \luatex_if_engine:F \use_none:n \cs_set_eq:NN \luatex_if_engine:TF \use_i:nn \cs_set_eq:NN \pdftex_if_engine:T \use_none:n \cs_set_eq:NN \pdftex_if_engine:F \use:n \cs_set_eq:NN \pdftex_if_engine:TF \use_ii:nn \cs_set_eq:NN \luatex_if_engine_p: \c_true_bool \cs_set_eq:NN \pdftex_if_engine_p: \c_false_bool } % \end{macrocode} % \end{macro} % % \subsection{Doing nothing functions} % % \begin{macro}{\prg_do_nothing:} % This does not fit anywhere else! % \begin{macrocode} \cs_new_nopar:Npn \prg_do_nothing: { } % \end{macrocode} % \end{macro} % % \subsection{String comparisons} % % \begin{macro}[pTF]{\str_if_eq:nn} % \begin{macro}[pTF]{\str_if_eq:xx} % Modern engines provide a direct way of comparing two token lists, % but returning a number. This set of conditionals therefore make life % a bit clearer. The \texttt{nn} and \texttt{xx} versions are created % directly as this is most efficient. These should eventually % move somewhere else. % \begin{macrocode} \prg_new_conditional:Npnn \str_if_eq:nn #1#2 { p , T , F , TF } { \if_int_compare:w \pdftex_strcmp:D { \exp_not:n {#1} } { \exp_not:n {#2} } = \c_zero \prg_return_true: \else: \prg_return_false: \fi: } \prg_new_conditional:Npnn \str_if_eq:xx #1#2 { p , T , F , TF } { \if_int_compare:w \pdftex_strcmp:D {#1} {#2} = \c_zero \prg_return_true: \else: \prg_return_false: \fi: } % \end{macrocode} % \end{macro} % \end{macro} % % \subsection{Deprecated functions} % % Deprecated on 2011-05-27, for removal by 2011-08-31. % % \begin{macrocode} %<*deprecated> \cs_new_eq:NN \cs_gnew_nopar:Npn \cs_new_nopar:Npn \cs_new_eq:NN \cs_gnew:Npn \cs_new:Npn \cs_new_eq:NN \cs_gnew_protected_nopar:Npn \cs_new_protected_nopar:Npn \cs_new_eq:NN \cs_gnew_protected:Npn \cs_new_protected:Npn \cs_new_eq:NN \cs_gnew_nopar:Npx \cs_new_nopar:Npx \cs_new_eq:NN \cs_gnew:Npx \cs_new:Npx \cs_new_eq:NN \cs_gnew_protected_nopar:Npx \cs_new_protected_nopar:Npx \cs_new_eq:NN \cs_gnew_protected:Npx \cs_new_protected:Npx \cs_new_eq:NN \cs_gnew_nopar:cpn \cs_new_nopar:cpn \cs_new_eq:NN \cs_gnew:cpn \cs_new:cpn \cs_new_eq:NN \cs_gnew_protected_nopar:cpn \cs_new_protected_nopar:cpn \cs_new_eq:NN \cs_gnew_protected:cpn \cs_new_protected:cpn \cs_new_eq:NN \cs_gnew_nopar:cpx \cs_new_nopar:cpx \cs_new_eq:NN \cs_gnew:cpx \cs_new:cpx \cs_new_eq:NN \cs_gnew_protected_nopar:cpx \cs_new_protected_nopar:cpx \cs_new_eq:NN \cs_gnew_protected:cpx \cs_new_protected:cpx % % \end{macrocode} % % \begin{macrocode} %<*deprecated> \cs_new_eq:NN \cs_gnew_eq:NN \cs_new_eq:NN \cs_new_eq:NN \cs_gnew_eq:cN \cs_new_eq:cN \cs_new_eq:NN \cs_gnew_eq:Nc \cs_new_eq:Nc \cs_new_eq:NN \cs_gnew_eq:cc \cs_new_eq:cc % % \end{macrocode} % % \begin{macrocode} %<*deprecated> \cs_new_eq:NN \cs_gundefine:N \cs_undefine:N \cs_new_eq:NN \cs_gundefine:c \cs_undefine:c % % \end{macrocode} % % \begin{macrocode} %<*deprecated> \cs_new_eq:NN \group_execute_after:N \group_insert_after:N % % \end{macrocode} % % Deprecated 2011-09-06, for removal by 2012-09-05. % % \begin{macro} % { % \c_pdftex_is_engine_bool, \c_luatex_is_engine_bool, % \c_xetex_is_engine_bool % } % Predicates are better % \begin{macrocode} \cs_new_eq:NN \c_luatex_is_engine_bool \luatex_if_engine_p: \cs_new_eq:NN \c_pdftex_is_engine_bool \pdftex_if_engine_p: \cs_new_eq:NN \c_xetex_is_engine_bool \xetex_if_engine_p: % \end{macrocode} % \end{macro} % % Deprecated 2011-09-06, for removal by 2012-10-06. % % \begin{macro}{\use_i_after_fi:nw} % \begin{macro}{\use_i_after_else:nw} % \begin{macro}{\use_i_after_or:nw} % \begin{macro}{\use_i_after_orelse:nw} % These functions return the first argument after ending the conditional. % This is rather specialized, and we want to de-emphasize the use of % primitive \TeX{} conditionals. % \begin{macrocode} \cs_set:Npn \use_i_after_fi:nw #1 \fi: { \fi: #1 } \cs_set:Npn \use_i_after_else:nw #1 \else: #2 \fi: { \fi: #1 } \cs_set:Npn \use_i_after_or:nw #1 \or: #2 \fi: { \fi: #1 } \cs_set:Npn \use_i_after_orelse:nw #1#2#3 \fi: { \fi: #1 } % \end{macrocode} % \end{macro} % \end{macro} % \end{macro} % \end{macro} % % Deprecated 2011-09-07, for removal by 2011-10-07. % % \begin{macro}{\cs_set_eq:NwN} % \begin{macrocode} \tex_let:D \cs_set_eq:NwN \tex_let:D % \end{macrocode} % \end{macro} % % \begin{macrocode} % % \end{macrocode} % % \end{implementation} % % \PrintIndex