% \iffalse meta-comment % %% File: l3basics.dtx % % Copyright (C) 1990-2024 The LaTeX Project % % It may be distributed and/or modified under the conditions of the % LaTeX Project Public License (LPPL), either version 1.3c of this % license or (at your option) any later version. The latest version % of this license is in the file % % https://www.latex-project.org/lppl.txt % % This file is part of the "l3kernel bundle" (The Work in LPPL) % and all files in that bundle must be distributed together. % % ----------------------------------------------------------------------- % % The development version of the bundle can be found at % % https://github.com/latex3/latex3 % % for those people who are interested. % %<*driver> \documentclass[full,kernel]{l3doc} \begin{document} \DocInput{\jobname.dtx} \end{document} % % \fi % % \title{^^A % The \pkg{l3basics} module\\ Basic definitions^^A % } % % \author{^^A % The \LaTeX{} Project\thanks % {^^A % E-mail: % \href{mailto:latex-team@latex-project.org} % {latex-team@latex-project.org}^^A % }^^A % } % % \date{Released 2024-12-25} % % \maketitle % % \begin{documentation} % % As the name suggests, this module holds some basic definitions which % are needed by most or all other modules in this set. % % Here we describe those functions that are used all over the place. % By 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. % \begin{texnote} % These are the \TeX{} primitives \tn{begingroup} and \tn{endgroup}. % \end{texnote} % \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 is 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), namely a ^^A{ % |}| if standard category codes apply. % \begin{texnote} % This is the \TeX{} primitive \tn{aftergroup}. % \end{texnote} % \end{function} % % \begin{function}[added = 2021-05-11]{\group_show_list:, \group_log_list:} % \begin{syntax} % \cs{group_show_list:} % \cs{group_log_list:} % \end{syntax} % Display (to the terminal or log file) a list of the groups that are % currently opened. This is intended for tracking down problems. % \begin{texnote} % This is a wrapper around the \eTeX{} primitive \tn{showgroups}. % \end{texnote} % \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} are fully expanded % inside an \texttt{e}-type or \texttt{x}-type expansion. % In contrast, \enquote{protected} functions are not expanded within % \texttt{e} and \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 is 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[no-index]{cs_new\ldots} functions: this is recommended for all % functions which are defined for the first time. % % There are three ways to define new functions. % All classes define a function to expand to the substitution text. % Within the substitution text the actual parameters are substituted % for the formal parameters (|#1|, |#2|, \ldots). % \begin{description} % \item[\texttt{new}] % Create a new function with the \texttt{new} scope, % such as \cs{cs_new:Npn}. The definition is global and results in % an error if it is already defined. % \item[\texttt{set}] % Create a new function with the \texttt{set} scope, % such as \cs{cs_set:Npn}. The definition is restricted to the current % \TeX{} group and does not result in an error if the function is already % defined. % \item[\texttt{gset}] % Create a new function with the \texttt{gset} scope, % such as \cs{cs_gset:Npn}. The definition is global and % does not result in an error if the function is already defined. % \end{description} % % Within each set of scope there are different ways to define a function. % The differences depend on restrictions on the actual parameters and % the expandability of the resulting function. % \begin{description} % \item[\texttt{nopar}] % Create a new function with the \texttt{nopar} restriction, % such as \cs{cs_set_nopar:Npn}. The parameter may not contain % \cs{par} tokens. % \item[\texttt{protected}] % Create a new function with the \texttt{protected} restriction, % such as \cs{cs_set_protected:Npn}. The parameter may contain % \cs{par} tokens but the function will not expand within an % \texttt{e}-type or \texttt{x}-type expansion. % \end{description} % % Finally, the functions in % Subsections~\ref{sec:l3basics:defining-new-function-1}~and % \ref{sec:l3basics:defining-new-function-2} are primarily meant to define % \emph{base functions} only. Base functions can only have the following % argument specifiers: % \begin{description} % \item[|N| and |n|] No manipulation. % \item[|T| and |F|] Functionally equivalent to |n| (you are actually % encouraged to use the family of |\prg_new_conditional:| functions % described in Section~\ref{sec:l3prg:new-conditional-functions}). % \item[|p| and |w|] These are special cases. % \end{description} % % The |\cs_new:| functions below (and friends) do not stop you from using % other argument specifiers in your function names, but they do not handle % expansion for you. You should define the base function and then use % \cs{cs_generate_variant:Nn} to generate custom variants as described in % Section~\ref{sec:l3expan:variants-method}. % % \subsection{Defining new functions using parameter text} % \label{sec:l3basics:defining-new-function-1} % % \begin{function} % { % \cs_new:Npn, \cs_new:cpn, % \cs_new:Npe, \cs_new:cpe, % \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 results if the % \meta{function} is already defined. % \end{function} % % \begin{function} % { % \cs_new_nopar:Npn, \cs_new_nopar:cpn, % \cs_new_nopar:Npe, \cs_new_nopar:cpe, % \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 results if the \meta{function} is already defined. % \end{function} % % \begin{function} % { % \cs_new_protected:Npn, \cs_new_protected:cpn, % \cs_new_protected:Npe, \cs_new_protected:cpe, % \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{e}-type or % or \texttt{x}-type % argument. The definition is global and an error results 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:Npe, \cs_new_protected_nopar:cpe , % \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{e}-type or \texttt{x}-type argument. The definition is global % and an error results if the \meta{function} is already defined. % \end{function} % % \begin{function} % { % \cs_set:Npn, \cs_set:cpn, % \cs_set:Npe, \cs_set:cpe, % \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 the \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:Npe, \cs_set_nopar:cpe, % \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 the \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:Npe, \cs_set_protected:cpe, % \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 the \meta{function} is restricted to % the current \TeX{} group level. The \meta{function} will % not expand within an \texttt{e}-type or \texttt{x}-type argument. % \end{function} % % \begin{function} % { % \cs_set_protected_nopar:Npn, \cs_set_protected_nopar:cpn , % \cs_set_protected_nopar:Npe, \cs_set_protected_nopar:cpe , % \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 the \meta{function} is restricted to the current \TeX{} group % level. The \meta{function} will not expand within an % \texttt{e}-type or \texttt{x}-type argument. % \end{function} % % \begin{function} % { % \cs_gset:Npn, \cs_gset:cpn, % \cs_gset:Npe, \cs_gset:cpe, % \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 the \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:Npe, \cs_gset_nopar:cpe, % \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 the % \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:Npe, \cs_gset_protected:cpe, % \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 the \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{e}-type or \texttt{x}-type argument. % \end{function} % % \begin{function} % { % \cs_gset_protected_nopar:Npn, \cs_gset_protected_nopar:cpn, % \cs_gset_protected_nopar:Npe, \cs_gset_protected_nopar:cpe, % \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 the % \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{e}-type or \texttt{x}-type argument. % \end{function} % % \subsection{Defining new functions using the signature} % \label{sec:l3basics:defining-new-function-2} % % \begin{function} % { % \cs_new:Nn, \cs_new:cn, % \cs_new:Ne, \cs_new:ce % } % \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 results if the \meta{function} is already defined. % \end{function} % % \begin{function} % { % \cs_new_nopar:Nn, \cs_new_nopar:cn, % \cs_new_nopar:Ne, \cs_new_nopar:ce % } % \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 results if the \meta{function} is already defined. % \end{function} % % \begin{function} % { % \cs_new_protected:Nn, \cs_new_protected:cn, % \cs_new_protected:Ne, \cs_new_protected:ce % } % \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{e}-type % or \texttt{x}-type argument. The definition is global and % an error results 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:Ne, \cs_new_protected_nopar:ce % } % \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{e}-type or \texttt{x}-type argument. The definition is global and % an error results if the \meta{function} is already defined. % \end{function} % % \begin{function} % { % \cs_set:Nn, \cs_set:cn, % \cs_set:Ne, \cs_set:ce % } % \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 the \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:Ne, \cs_set_nopar:ce % } % \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 the \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:Ne, \cs_set_protected:ce % } % \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{e}-type % or \texttt{x}-type argument. % The assignment of a meaning to the \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:Ne, \cs_set_protected_nopar:ce % } % \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{e}-type or \texttt{x}-type argument. % The assignment of a meaning to the \meta{function} is restricted to % the current \TeX{} group level. % \end{function} % % \begin{function} % { % \cs_gset:Nn, \cs_gset:cn, % \cs_gset:Ne, \cs_gset:ce % } % \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 the \meta{function} is global. % \end{function} % % \begin{function} % { % \cs_gset_nopar:Nn, \cs_gset_nopar:cn, % \cs_gset_nopar:Ne, \cs_gset_nopar:ce % } % \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 the \meta{function} is global. % \end{function} % % \begin{function} % { % \cs_gset_protected:Nn, \cs_gset_protected:cn, % \cs_gset_protected:Ne, \cs_gset_protected:ce % } % \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{e}-type % or \texttt{x}-type argument. % The assignment of a meaning to the \meta{function} is global. % \end{function} % % \begin{function} % { % \cs_gset_protected_nopar:Nn, \cs_gset_protected_nopar:cn, % \cs_gset_protected_nopar:Ne, \cs_gset_protected_nopar:ce % } % \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{e}-type or \texttt{x}-type argument. % The assignment of a meaning to the \meta{function} is global. % \end{function} % % \begin{function}[updated = 2012-01-14] % { % \cs_generate_from_arg_count:NNnn, % \cs_generate_from_arg_count:NNno, % \cs_generate_from_arg_count:cNnn, % \cs_generate_from_arg_count:Ncnn % } % \begin{syntax} % \cs{cs_generate_from_arg_count:NNnn} \meta{function} \meta{creator} \Arg{number} \Arg{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 % tied 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 the \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 % the \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, updated = 2011-12-22]{\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. For a macro, this includes the \meta{replacement text}. % \begin{texnote} % This is the \TeX{} primitive \tn{meaning}. % For tokens that are not control sequences, it is more logical to % use \cs{token_to_meaning:N}. % The \texttt{c} variant correctly reports undefined arguments. % \end{texnote} % \end{function} % % \begin{function}[updated = 2017-02-14]{\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 similar to the \TeX{} primitive \tn{show}, wrapped to a % fixed number of characters per line. % \end{texnote} % \end{function} % % \begin{function}[added = 2014-08-22, updated = 2017-02-14]{\cs_log:N, \cs_log:c} % \begin{syntax} % \cs{cs_log:N} \meta{control sequence} % \end{syntax} % Writes the definition of the \meta{control sequence} in the log % file. See also \cs{cs_show:N} which displays the result in the % terminal. % \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} % Expands the \meta{control sequence name} until only characters % remain, and then converts this into a control sequence. This process % requires two expansions. As in other \texttt{c}-type arguments the % \meta{control sequence name} must, when fully expanded, consist of % character tokens, typically a mixture of category code $10$ (space), % $11$ (letter) and $12$ (other). % \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}[noTF, EXP, added = 2012-11-10] % {\cs_if_exist_use:N, \cs_if_exist_use:c} % \begin{syntax} % \cs{cs_if_exist_use:N} \meta{control sequence} % \cs{cs_if_exist_use:NTF} \meta{control sequence} \Arg{true code} \Arg{false code} % \end{syntax} % Tests whether the \meta{control sequence} is currently defined % according to the conditional \cs{cs_if_exist:NTF} % (whether as a function or another control sequence type), and if it % is inserts the \meta{control sequence} into the input stream followed % by the \meta{true code}. Otherwise the \meta{false code} is used. % \end{function} % % \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 % 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} \meta{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 result does \emph{not} include % the current escape token, contrarily to \cs{token_to_str:N}. % Full expansion of this function requires exactly $2$ expansion % steps, and so an \texttt{e}-type or \texttt{x}-type expansion, or two % \texttt{o}-type expansions are required to % convert the \meta{control sequence} to a sequence of characters % in the input stream. In most cases, an \texttt{f}-expansion % is correct as well, but this loses a space at the start % of the result. % \end{function} % % \section{Analysing control sequences} % % \begin{function}[EXP, added = 2018-04-06]{\cs_split_function:N} % \begin{syntax} % \cs{cs_split_function:N} \meta{function} % \end{syntax} % Splits the \meta{function} into the \meta{name} (\emph{i.e.}~the part % before the colon) and the \meta{signature} (\emph{i.e.}~after the colon). % This information is then placed in the input stream % 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} % does not include the escape character, and both the \meta{name} and % \meta{signature} are made up of tokens with category code $12$ % (other). % \end{function} % % The next three functions decompose \TeX{} macros into their % constituent parts: if the \meta{token} passed is not a macro then no % decomposition can occur. In the latter case, all three functions leave % \cs{scan_stop:} in the input stream. % % \begin{function}[EXP, added = 2019-02-27]{\cs_prefix_spec:N} % \begin{syntax} % \cs{cs_prefix_spec:N} \meta{token} % \end{syntax} % If the \meta{token} is a macro, this function leaves the applicable % \TeX{} prefixes in input stream as a string of tokens of category % code $12$ (with spaces having category code $10$). Thus for example % \begin{verbatim} % \cs_set:Npn \next:nn #1#2 { x #1~y #2 } % \cs_prefix_spec:N \next:nn % \end{verbatim} % leaves |\long| in the input stream. If the \meta{token} is % not a macro then \cs{scan_stop:} is left in the input stream. % \begin{texnote} % The prefix can be empty, |\long|, |\protected| or % |\protected\long| with backslash replaced by the current escape % character. % \end{texnote} % \end{function} % % \begin{function}[EXP, added = 2022-06-24]{\cs_parameter_spec:N} % \begin{syntax} % \cs{cs_parameter_spec:N} \meta{token} % \end{syntax} % If the \meta{token} is a macro, this function leaves the primitive % \TeX{} parameter specification in input stream as a string of % character tokens of category code $12$ (with spaces having category % code $10$). Thus for example % \begin{verbatim} % \cs_set:Npn \next:nn #1#2 { x #1 y #2 } % \cs_parameter_spec:N \next:nn % \end{verbatim} % leaves |#1#2| in the input stream. If the \meta{token} is % not a macro then \cs{scan_stop:} is left in the input stream. % \begin{texnote} % If the parameter specification contains the string |->|, then the % function produces incorrect results. % \end{texnote} % \end{function} % % \begin{function}[EXP, added = 2019-02-27]{\cs_replacement_spec:N, \cs_replacement_spec:c} % \begin{syntax} % \cs{cs_replacement_spec:N} \meta{token} % \end{syntax} % If the \meta{token} is a macro, this function leaves the replacement % text in input stream as a string of character tokens of category % code $12$ (with spaces having category code $10$). Thus for example % \begin{verbatim} % \cs_set:Npn \next:nn #1#2 { x #1~y #2 } % \cs_replacement_spec:N \next:nn % \end{verbatim} % leaves \verb*|x#1 y#2| in the input stream. If the \meta{token} is % not a macro then \cs{scan_stop:} is left in the input stream. % \begin{texnote} % If the parameter specification contains the string |->|, then the % function produces incorrect results. % \end{texnote} % \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 when absorbing them % the outer set is 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 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{group_1} % \cs{use:nn} \Arg{group_1} \Arg{group_2} % \cs{use:nnn} \Arg{group_1} \Arg{group_2} \Arg{group_3} % \cs{use:nnnn} \Arg{group_1} \Arg{group_2} \Arg{group_3} \Arg{group_4} % \end{syntax} % As illustrated, these functions absorb between one and four % arguments, as indicated by the argument specifier. The braces % surrounding each argument are removed and the remaining tokens are % left in the input stream. The category code of these tokens is % also 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} % results in the input stream containing % \begin{verbatim} % abc { def } % \end{verbatim} % \emph{i.e.} only the outer braces are removed. % \begin{texnote} % The \cs{use:n} function is equivalent to \LaTeXe{}'s \tn{@firstofone}. % \end{texnote} % \end{function} % % \begin{function}[EXP] % { % \use_i:nn, \use_ii:nn , % \use_i:nnn , \use_ii:nnn , \use_iii:nnn , % \use_i:nnnn, \use_ii:nnnn, \use_iii:nnnn, \use_iv:nnnn , % \use_i:nnnnn, \use_ii:nnnnn, \use_iii:nnnnn, \use_iv:nnnnn , % \use_v:nnnnn , % \use_i:nnnnnn, \use_ii:nnnnnn, \use_iii:nnnnnn, \use_iv:nnnnnn , % \use_v:nnnnnn , \use_vi:nnnnnn , % \use_i:nnnnnnn, \use_ii:nnnnnnn, \use_iii:nnnnnnn, \use_iv:nnnnnnn , % \use_v:nnnnnnn , \use_vi:nnnnnnn , \use_vii:nnnnnnn , % \use_i:nnnnnnnn, \use_ii:nnnnnnnn, \use_iii:nnnnnnnn, \use_iv:nnnnnnnn , % \use_v:nnnnnnnn , \use_vi:nnnnnnnn , \use_vii:nnnnnnnn , \use_viii:nnnnnnnn , % \use_i:nnnnnnnnn, \use_ii:nnnnnnnnn, \use_iii:nnnnnnnnn, \use_iv:nnnnnnnnn , % \use_v:nnnnnnnnn , \use_vi:nnnnnnnnn , \use_vii:nnnnnnnnn , \use_viii:nnnnnnnnn , % \use_ix:nnnnnnnnn % } % \begin{syntax} % \cs{use_i:nn} \Arg{arg_1} \Arg{arg_2} % \cs{use_i:nnn} \Arg{arg_1} \Arg{arg_2} \Arg{arg_3} % \cs{use_i:nnnn} \Arg{arg_1} \Arg{arg_2} \Arg{arg_3} \Arg{arg_4} % \cs{use_i:nnnnn} \Arg{arg_1} \Arg{arg_2} \Arg{arg_3} \Arg{arg_4} \Arg{arg_5} % \cs{use_i:nnnnnn} \Arg{arg_1} \Arg{arg_2} \Arg{arg_3} \Arg{arg_4} \Arg{arg_5} \Arg{arg_6} % \cs{use_i:nnnnnnn} \Arg{arg_1} \Arg{arg_2} \Arg{arg_3} \Arg{arg_4} \Arg{arg_5} \Arg{arg_6} \Arg{arg_7} % \cs{use_i:nnnnnnnn} \Arg{arg_1} \Arg{arg_2} \Arg{arg_3} \Arg{arg_4} \Arg{arg_5} \Arg{arg_6} \Arg{arg_7} \Arg{arg_8} % \cs{use_i:nnnnnnnnn} \Arg{arg_1} \Arg{arg_2} \Arg{arg_3} \Arg{arg_4} \Arg{arg_5} \Arg{arg_6} \Arg{arg_7} \Arg{arg_8} \Arg{arg_9} % \end{syntax} % These functions absorb a number ($n$) arguments from the input stream. % They then discard all arguments other than that indicated by the roman % numeral, which is left in the input stream. For example, \cs{use_i:nn} % discards the second argument, and leaves the content of the first % argument in the input stream. % The category code % of these tokens is also 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{arg_1} \Arg{arg_2} \Arg{arg_3} % \end{syntax} % This function absorbs three arguments and leaves the content of the % first and second in the input stream. The category code of % these tokens is also fixed (if it has not already been by % some other absorption). A single expansion is needed for the % function to take effect. An example: % \begin{verbatim} % \use_i_ii:nnn { abc } { { def } } { ghi } % \end{verbatim} % results in the input stream containing % \begin{verbatim} % abc { def } % \end{verbatim} % \emph{i.e.} the outer braces are removed and the third group % is removed. % \end{function} % % \begin{function}[EXP, added = 2019-06-02]{\use_ii_i:nn} % \begin{syntax} % \cs{use_ii_i:nn} \Arg{arg_1} \Arg{arg_2} % \end{syntax} % This function absorbs two arguments and leaves the content of the % second and first in the input stream. The category code of % these tokens is also fixed (if it has not already been by % some other absorption). A single expansion is needed for the % function to take effect. % \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{group_1} % \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). % \begin{texnote} % These are equivalent to \LaTeXe{}'s \tn{@gobble}, \tn{@gobbletwo}, % \emph{etc.} % \end{texnote} % \end{function} % % \begin{function}[EXP, added = 2018-06-18, updated = 2023-07-05]{\use:e} % \begin{syntax} % \cs{use:e} \Arg{expandable tokens} % \end{syntax} % Fully expands the \meta{token list} in an \texttt{e}-type manner, % in which parameter character (usually~|#|) need not be doubled, \emph{and} % the function remains fully expandable. % \begin{texnote} % \cs{use:e} is a wrapper around the primitive \tn{expanded}. % It requires two expansions to complete its action. % \end{texnote} % \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} % \cs{use_none_delimit_by_q_stop:w} \meta{balanced text} \cs{q_stop} % \cs{use_none_delimit_by_q_recursion_stop:w} \meta{balanced text} \cs{q_recursion_stop} % \end{syntax} % Absorb the \meta{balanced text} from 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} % \cs{use_i_delimit_by_q_stop:nw} \Arg{inserted tokens} \meta{balanced text} \cs{q_stop} % \cs{use_i_delimit_by_q_recursion_stop:nw} \Arg{inserted tokens} \meta{balanced text} \cs{q_recursion_stop} % \end{syntax} % Absorb the \meta{balanced text} from 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} % % \section{Predicates and conditionals} % % \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 as the \meta{true code} or the % \meta{false code}. % 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 turns 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 carries 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 is usually 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 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 are 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{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" \\ % " { \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} % also exists 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} % % \subsection{Tests on control sequences} % % \begin{function}[EXP,pTF]{\cs_if_eq:NN, \cs_if_eq:Nc, \cs_if_eq:cN, \cs_if_eq:cc} % \begin{syntax} % \cs{cs_if_eq_p:NN} \meta{cs_1} \meta{cs_2} % \cs{cs_if_eq:NNTF} \meta{cs_1} \meta{cs_2} \Arg{true code} \Arg{false code} % \end{syntax} % Compares the definition of two \meta{control sequences} and % is logically \texttt{true} if they are the same, \emph{i.e.}~if they have exactly % the same definition when examined with \cs{cs_show:N}. % \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 % definition of \meta{control sequence} other than \tn{relax} % evaluates 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 is \texttt{false} if the % \meta{control sequence} currently exists (as defined by % \cs{cs_if_exist:NTF}). % \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 often contains a |:w| part but % higher level functions are often available. See for instance % \cs{int_compare_p:nNn} which is a wrapper for \cs{if_int_compare: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 % prefix primitive conditionals with |\if_|, except for \cs{if:w}. % % \begin{function}[EXP] % {\if_true:, \if_false:, \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. The function "\or:" is documented in \pkg{l3int} and % used in case switches. % \begin{texnote} % \cs{if_true:} and \cs{if_false:} are equivalent to their corresponding % \TeX{} primitive conditionals \tn{iftrue} and \tn{iffalse}; % \cs{else:} and \cs{fi:} are the \TeX{} primitives \tn{else} and \tn{fi}; % \cs{reverse_if:N} is the \eTeX{} primitive \tn{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 the \TeX{} primitive \tn{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} % "\if_charcode:w" is an alternative name for "\if:w". % These conditionals expand \meta{token(s)} until two % unexpandable tokens \meta{token_1} and \meta{token_2} are found; % any further tokens up to the next unbalanced "\else:" are the true branch, % ending with \meta{true code}. It is executed if the condition is fulfilled, % otherwise \meta{false code} is executed. % You can omit "\else:" when just in front of "\fi:" and % you can nest "\if...\else:...\fi:" constructs inside the true branch or the % \meta{false code}. % With "\exp_not:N", you can prevent the expansion of a token. % % "\if_catcode:w" % tests if \meta{token_1} and \meta{token_2} have the same category code whereas % "\if:w" and \cs{if_charcode:w} test if they have the same character code. % \begin{texnote} % \cs{if:w} and \cs{if_charcode:w} are both the \TeX{} primitive \tn{if}. % \cs{if_catcode:w} is the \TeX{} primitive \tn{ifcat}. % \end{texnote} % \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. % \begin{texnote} % These are the \TeX{} primitives \tn{ifdefined} and \tn{ifcsname}. % \end{texnote} % \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. % \begin{texnote} % These are the \TeX{} primitives \tn{ifhmode}, \tn{ifvmode}, \tn{ifmmode}, % and~\tn{ifinner}. % \end{texnote} % \end{function} % % \section{Starting a paragraph} % % \begin{function}[added = 2017-07-04]{\mode_leave_vertical:} % \begin{syntax} % \cs{mode_leave_vertical:} % \end{syntax} % Ensures that \TeX{} is not in vertical (inter-paragraph) mode. In % horizontal or math mode this command has no effect, in vertical mode it % switches to horizontal mode, and inserts a box of width % \tn{parindent}, followed by the \tn{everypar} token list. % \begin{texnote} % This results in the contents of the \tn{everypar} token register being % inserted, after \cs{mode_leave_vertical:} is complete. Notice that in % contrast to the \LaTeXe{} \tn{leavevmode} approach, no box is used % by the method implemented here. % \end{texnote} % \end{function} % % \section{Debugging support} % % \begin{function}[added = 2017-07-16, updated = 2023-05-23]{\debug_on:n, \debug_off:n} % \begin{syntax} % \cs{debug_on:n} \Arg{comma-separated list} % \cs{debug_off:n} \Arg{comma-separated list} % \end{syntax} % Turn on and off within a group various debugging code, some of which % is also available as \pkg{expl3} load-time options. The items that % can be used in the \meta{list} are % \begin{itemize} % \item \texttt{check-declarations} that checks all \pkg{expl3} % variables used were previously declared and that local/global % variables (based on their name or on their first assignment) are % only locally/globally assigned; % \item \texttt{check-expressions} that checks integer, dimension, % skip, and muskip expressions are not terminated prematurely; % \item \texttt{deprecation} that makes deprecated commands produce errors; % \item \texttt{log-functions} that logs function definitions and % variable declarations; % \item \texttt{all} that does all of the above. % \end{itemize} % Providing these as switches rather than options allows testing code % even if it relies on other packages: load all other packages, call % \cs{debug_on:n}, and load the code that one is interested in % testing. % \end{function} % % \begin{function}[added = 2017-11-28]{\debug_suspend:, \debug_resume:} % \begin{syntax} % \cs{debug_suspend:} \ldots{} \cs{debug_resume:} % \end{syntax} % Suppress (locally) errors and logging from \texttt{debug} commands, % except for the \texttt{deprecation} errors. These pairs % of commands can be nested. This can be used around pieces of code % that are known to fail checks, if such failures should be ignored. % See for instance \pkg{l3cctab} and \pkg{l3coffins}. % \end{function} % % \end{documentation} % % \begin{implementation} % % \section{\pkg{l3basics} implementation} % % \begin{macrocode} %<*package> % \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 we % 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[no-index]{tex_\ldots:D} name in the cases where no good alternative exists.} % % \begin{macro}[EXP] % { % \if_true:, \if_false:, \or:, \else:, \fi:, \reverse_if:N, % \if:w, \if_charcode:w, \if_catcode:w, \if_meaning:w % } % Then some conditionals. % \begin{macrocode} \tex_global:D \tex_let:D \if_true: \tex_iftrue:D \tex_global:D \tex_let:D \if_false: \tex_iffalse:D \tex_global:D \tex_let:D \or: \tex_or:D \tex_global:D \tex_let:D \else: \tex_else:D \tex_global:D \tex_let:D \fi: \tex_fi:D \tex_global:D \tex_let:D \reverse_if:N \tex_unless:D \tex_global:D \tex_let:D \if:w \tex_if:D \tex_global:D \tex_let:D \if_charcode:w \tex_if:D \tex_global:D \tex_let:D \if_catcode:w \tex_ifcat:D \tex_global:D \tex_let:D \if_meaning:w \tex_ifx:D \tex_global:D \tex_let:D \if_bool:N \tex_ifodd:D % \end{macrocode} % \end{macro} % % \begin{macro}[EXP] % { % \if_mode_math:, % \if_mode_horizontal:, % \if_mode_vertical:, % \if_mode_inner: % } % \TeX{} lets us detect some if its modes. % \begin{macrocode} \tex_global:D \tex_let:D \if_mode_math: \tex_ifmmode:D \tex_global:D \tex_let:D \if_mode_horizontal: \tex_ifhmode:D \tex_global:D \tex_let:D \if_mode_vertical: \tex_ifvmode:D \tex_global:D \tex_let:D \if_mode_inner: \tex_ifinner:D % \end{macrocode} % \end{macro} % % \begin{macro}[EXP]{\if_cs_exist:N, \if_cs_exist:w, \cs:w, \cs_end:} % Building csnames and testing if control sequences exist. % \begin{macrocode} \tex_global:D \tex_let:D \if_cs_exist:N \tex_ifdefined:D \tex_global:D \tex_let:D \if_cs_exist:w \tex_ifcsname:D \tex_global:D \tex_let:D \cs:w \tex_csname:D \tex_global:D \tex_let:D \cs_end: \tex_endcsname:D % \end{macrocode} % \end{macro} % % \begin{macro}[EXP]{\exp_after:wN, \exp_not:N, \exp_not:n} % The five |\exp_| functions are used in the \pkg{l3expan} module % where they are described. % \begin{macrocode} \tex_global:D \tex_let:D \exp_after:wN \tex_expandafter:D \tex_global:D \tex_let:D \exp_not:N \tex_noexpand:D \tex_global:D \tex_let:D \exp_not:n \tex_unexpanded:D \tex_global:D \tex_let:D \exp:w \tex_romannumeral:D \tex_global:D \tex_chardef:D \exp_end: = 0 ~ % \end{macrocode} % \end{macro} % % \begin{macro}[EXP]{\token_to_meaning:N, \cs_meaning:N} % Examining a control sequence or token. % \begin{macrocode} \tex_global:D \tex_let:D \token_to_meaning:N \tex_meaning:D \tex_global:D \tex_let:D \cs_meaning:N \tex_meaning:D % \end{macrocode} % \end{macro} % % \begin{macro}[EXP]{\tl_to_str:n, \token_to_str:N, \__kernel_tl_to_str:w} % Making strings. % \begin{macrocode} \tex_global:D \tex_let:D \tl_to_str:n \tex_detokenize:D \tex_global:D \tex_let:D \token_to_str:N \tex_string:D \tex_global:D \tex_let:D \__kernel_tl_to_str:w \tex_detokenize:D % \end{macrocode} % \end{macro} % % \begin{macro}{\scan_stop:, \group_begin:, \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 \pkg{l3prg} module. % \begin{macrocode} \tex_global:D \tex_let:D \scan_stop: \tex_relax:D \tex_global:D \tex_let:D \group_begin: \tex_begingroup:D \tex_global:D \tex_let:D \group_end: \tex_endgroup:D % \end{macrocode} % \end{macro} % % \begin{macrocode} %<@@=int> % \end{macrocode} % % \begin{macro}[EXP]{\if_int_compare:w, \@@_to_roman:w} % For integers. % \begin{macrocode} \tex_global:D \tex_let:D \if_int_compare:w \tex_ifnum:D \tex_global:D \tex_let:D \@@_to_roman:w \tex_romannumeral:D % \end{macrocode} % \end{macro} % % \begin{macro}{\group_insert_after:N} % Adding material after the end of a group. % \begin{macrocode} \tex_global:D \tex_let:D \group_insert_after:N \tex_aftergroup:D % \end{macrocode} % \end{macro} % % \begin{macro}[EXP]{\exp_args:Nc, \exp_args:cc} % Discussed in \pkg{l3expan}, but needed much earlier. % \begin{macrocode} \tex_long:D \tex_gdef:D \exp_args:Nc #1#2 { \exp_after:wN #1 \cs:w #2 \cs_end: } \tex_long:D \tex_gdef:D \exp_args:cc #1#2 { \cs:w #1 \exp_after:wN \cs_end: \cs:w #2 \cs_end: } % \end{macrocode} % \end{macro} % % \begin{macro}[EXP, documented-as=\token_to_meaning:N] % {\token_to_meaning:c, \token_to_str:c, \cs_meaning:c} % A small number of variants defined by hand. % Some of the necessary functions % (\cs{use_i:nn}, \cs{use_ii:nn}, and \cs{exp_args:NNc}) are not % defined at that point yet, but will be defined before those variants % are used. The \cs{cs_meaning:c} command must check for an undefined % control sequence to avoid defining it mistakenly. % \begin{macrocode} \tex_gdef:D \token_to_str:c { \exp_args:Nc \token_to_str:N } \tex_long:D \tex_gdef:D \cs_meaning:c #1 { \if_cs_exist:w #1 \cs_end: \exp_after:wN \use_i:nn \else: \exp_after:wN \use_ii:nn \fi: { \exp_args:Nc \cs_meaning:N {#1} } { \tl_to_str:n {undefined} } } \tex_global:D \tex_let:D \token_to_meaning:c = \cs_meaning:c % \end{macrocode} % \end{macro} % % \subsection{Defining some constants} % % \begin{variable}{\c_zero_int} % We need the constant \cs{c_zero_int} % which is used by some functions in current module. The % rest are defined in the \pkg{l3int} module -- at least for the % ones that can be defined with \cs{tex_chardef:D} or % \cs{tex_mathchardef:D}. For other constants the \pkg{l3int} module is % required but it can't be used until the allocation has been set % up properly! % \begin{macrocode} \tex_global:D \tex_chardef:D \c_zero_int = 0 ~ % \end{macrocode} % \end{variable} % % \begin{variable}{\c_max_register_int} % This is here as this particular integer is needed in modules % loaded before \pkg{l3int}, and is documented in \pkg{l3int}. % \LuaTeX{} and those which contain parts of the Omega extensions have % more registers available than \eTeX{}. % \begin{macrocode} \tex_ifdefined:D \tex_luatexversion:D \tex_global:D \tex_chardef:D \c_max_register_int = 65 535 ~ \tex_else:D \tex_ifdefined:D \tex_omathchardef:D \tex_global:D \tex_omathchardef:D \c_max_register_int = 65535 ~ \tex_else:D \tex_global:D \tex_mathchardef:D \c_max_register_int = 32767 ~ \tex_fi:D \tex_fi:D % \end{macrocode} % \end{variable} % % \subsection{Defining functions} % % We start by providing functions for the typical definition % functions. First the global ones. % % \begin{macro} % { % \cs_gset_nopar:Npn , \cs_gset_nopar:Npe , \cs_gset_nopar:Npx , % \cs_gset:Npn , \cs_gset:Npe , \cs_gset:Npx , % \cs_gset_protected_nopar:Npn , \cs_gset_protected_nopar:Npe , \cs_gset_protected_nopar:Npx , % \cs_gset_protected:Npn , \cs_gset_protected:Npe , \cs_gset_protected:Npx % } % All assignment functions in \LaTeX3 should be naturally protected; % after all, the \TeX{} primitives for assignments are and it can be % a cause of problems if others aren't. % \begin{macrocode} \tex_global:D \tex_let:D \cs_gset_nopar:Npn \tex_gdef:D \tex_global:D \tex_let:D \cs_gset_nopar:Npe \tex_xdef:D \tex_global:D \tex_let:D \cs_gset_nopar:Npx \tex_xdef:D \tex_protected:D \tex_long:D \tex_gdef:D \cs_gset:Npn { \tex_long:D \tex_gdef:D } \tex_protected:D \tex_long:D \tex_gdef:D \cs_gset:Npe { \tex_long:D \tex_xdef:D } \tex_global:D \tex_let:D \cs_gset:Npx \cs_gset:Npe \tex_protected:D \tex_long:D \tex_gdef:D \cs_gset_protected_nopar:Npn { \tex_protected:D \tex_gdef:D } \tex_protected:D \tex_long:D \tex_gdef:D \cs_gset_protected_nopar:Npe { \tex_protected:D \tex_xdef:D } \tex_global:D \tex_let:D \cs_gset_protected_nopar:Npx \cs_gset_protected_nopar:Npe \tex_protected:D \tex_long:D \tex_gdef:D \cs_gset_protected:Npn { \tex_protected:D \tex_long:D \tex_gdef:D } \tex_protected:D \tex_long:D \tex_gdef:D \cs_gset_protected:Npe { \tex_protected:D \tex_long:D \tex_xdef:D } \tex_global:D \tex_let:D \cs_gset_protected:Npx \cs_gset_protected:Npe % \end{macrocode} % \end{macro} % % \begin{macro} % { % \cs_set_nopar:Npn , \cs_set_nopar:Npe , \cs_set_nopar:Npx , % \cs_set:Npn , \cs_set:Npe , \cs_set:Npx , % \cs_set_protected_nopar:Npn , \cs_set_protected_nopar:Npe , \cs_set_protected_nopar:Npx , % \cs_set_protected:Npn , \cs_set_protected:Npe , \cs_set_protected:Npx % } % Local versions of the above functions. % \begin{macrocode} \tex_global:D \tex_let:D \cs_set_nopar:Npn \tex_def:D \tex_global:D \tex_let:D \cs_set_nopar:Npe \tex_edef:D \tex_global:D \tex_let:D \cs_set_nopar:Npx \tex_edef:D \cs_gset_protected:Npn \cs_set:Npn { \tex_long:D \tex_def:D } \cs_gset_protected:Npn \cs_set:Npe { \tex_long:D \tex_edef:D } \tex_global:D \tex_let:D \cs_set:Npx \cs_set:Npe \cs_gset_protected:Npn \cs_set_protected_nopar:Npn { \tex_protected:D \tex_def:D } \cs_gset_protected:Npn \cs_set_protected_nopar:Npe { \tex_protected:D \tex_edef:D } \tex_global:D \tex_let:D \cs_set_protected_nopar:Npx \cs_set_protected_nopar:Npe \cs_gset_protected:Npn \cs_set_protected:Npn { \tex_protected:D \tex_long:D \tex_def:D } \cs_gset_protected:Npn \cs_set_protected:Npe { \tex_protected:D \tex_long:D \tex_edef:D } \tex_global:D \tex_let:D \cs_set_protected:Npx \cs_set_protected:Npe % \end{macrocode} % \end{macro} % % \subsection{Selecting tokens} % % \begin{macrocode} %<@@=exp> % \end{macrocode} % % \begin{variable}{\l_@@_internal_tl} % Scratch token list variable for \pkg{l3expan}, used by \cs{use:x}, % used in defining conditionals. We don't use |tl| methods because % \pkg{l3basics} is loaded earlier. % \begin{macrocode} \cs_gset_nopar:Npn \l_@@_internal_tl { } % \end{macrocode} % \end{variable} % % \begin{macro}[EXP]{\use:c} % This macro grabs its argument and returns a csname from it. % \begin{macrocode} \cs_gset:Npn \use:c #1 { \cs:w #1 \cs_end: } % \end{macrocode} % \end{macro} % % \begin{macro}[deprecated]{\use:x} % Fully expands its argument and passes it to the input stream. Uses % the reserved \cs{l_@@_internal_tl} which we've set up above. % \begin{macrocode} \cs_gset_protected:Npn \use:x #1 { \cs_set_nopar:Npx \l_@@_internal_tl {#1} \l_@@_internal_tl } % \end{macrocode} % \end{macro} % % \begin{macrocode} %<@@=use> % \end{macrocode} % % \begin{macro}[EXP]{\use:e} % \begin{macrocode} \cs_gset:Npn \use:e #1 { \tex_expanded:D {#1} } % \end{macrocode} % \end{macro} % % \begin{macrocode} %<@@=exp> % \end{macrocode} % % \begin{macro}[EXP]{\use:n, \use:nn, \use:nnn, \use:nnnn} % These macros grab their arguments and return them back to the input % (with outer braces removed). % \begin{macrocode} \cs_gset:Npn \use:n #1 {#1} \cs_gset:Npn \use:nn #1#2 {#1#2} \cs_gset:Npn \use:nnn #1#2#3 {#1#2#3} \cs_gset:Npn \use:nnnn #1#2#3#4 {#1#2#3#4} % \end{macrocode} % \end{macro} % % \begin{macro}[EXP]{\use_i:nn, \use_ii:nn} % The equivalent to \LaTeXe{}'s \tn{@firstoftwo} and \tn{@secondoftwo}. % \begin{macrocode} \cs_gset:Npn \use_i:nn #1#2 {#1} \cs_gset:Npn \use_ii:nn #1#2 {#2} % \end{macrocode} % \end{macro} % % \begin{macro}[EXP] % { % \use_i:nnn , \use_ii:nnn , \use_iii:nnn , % \use_i:nnnn, \use_ii:nnnn, \use_iii:nnnn, \use_iv:nnnn , % \use_i:nnnnn, \use_ii:nnnnn, \use_iii:nnnnn, \use_iv:nnnnn , % \use_v:nnnnn , % \use_i:nnnnnn, \use_ii:nnnnnn, \use_iii:nnnnnn, \use_iv:nnnnnn , % \use_v:nnnnnn , \use_vi:nnnnnn , % \use_i:nnnnnnn, \use_ii:nnnnnnn, \use_iii:nnnnnnn, \use_iv:nnnnnnn , % \use_v:nnnnnnn , \use_vi:nnnnnnn , \use_vii:nnnnnnn , % \use_i:nnnnnnnn, \use_ii:nnnnnnnn, \use_iii:nnnnnnnn, \use_iv:nnnnnnnn , % \use_v:nnnnnnnn , \use_vi:nnnnnnnn , \use_vii:nnnnnnnn , \use_viii:nnnnnnnn , % \use_i:nnnnnnnnn, \use_ii:nnnnnnnnn, \use_iii:nnnnnnnnn, \use_iv:nnnnnnnnn , % \use_v:nnnnnnnnn , \use_vi:nnnnnnnnn , \use_vii:nnnnnnnnn , \use_viii:nnnnnnnnn , % \use_ix:nnnnnnnnn % } % We also need something for picking up arguments from a longer list. % \begin{macrocode} \cs_gset:Npn \use_i:nnn #1#2#3 {#1} \cs_gset:Npn \use_ii:nnn #1#2#3 {#2} \cs_gset:Npn \use_iii:nnn #1#2#3 {#3} \cs_gset:Npn \use_i:nnnn #1#2#3#4 {#1} \cs_gset:Npn \use_ii:nnnn #1#2#3#4 {#2} \cs_gset:Npn \use_iii:nnnn #1#2#3#4 {#3} \cs_gset:Npn \use_iv:nnnn #1#2#3#4 {#4} \cs_gset:Npn \use_i:nnnnn #1#2#3#4#5 {#1} \cs_gset:Npn \use_ii:nnnnn #1#2#3#4#5 {#2} \cs_gset:Npn \use_iii:nnnnn #1#2#3#4#5 {#3} \cs_gset:Npn \use_iv:nnnnn #1#2#3#4#5 {#4} \cs_gset:Npn \use_v:nnnnn #1#2#3#4#5 {#5} \cs_gset:Npn \use_i:nnnnnn #1#2#3#4#5#6 {#1} \cs_gset:Npn \use_ii:nnnnnn #1#2#3#4#5#6 {#2} \cs_gset:Npn \use_iii:nnnnnn #1#2#3#4#5#6 {#3} \cs_gset:Npn \use_iv:nnnnnn #1#2#3#4#5#6 {#4} \cs_gset:Npn \use_v:nnnnnn #1#2#3#4#5#6 {#5} \cs_gset:Npn \use_vi:nnnnnn #1#2#3#4#5#6 {#6} \cs_gset:Npn \use_i:nnnnnnn #1#2#3#4#5#6#7 {#1} \cs_gset:Npn \use_ii:nnnnnnn #1#2#3#4#5#6#7 {#2} \cs_gset:Npn \use_iii:nnnnnnn #1#2#3#4#5#6#7 {#3} \cs_gset:Npn \use_iv:nnnnnnn #1#2#3#4#5#6#7 {#4} \cs_gset:Npn \use_v:nnnnnnn #1#2#3#4#5#6#7 {#5} \cs_gset:Npn \use_vi:nnnnnnn #1#2#3#4#5#6#7 {#6} \cs_gset:Npn \use_vii:nnnnnnn #1#2#3#4#5#6#7 {#7} \cs_gset:Npn \use_i:nnnnnnnn #1#2#3#4#5#6#7#8 {#1} \cs_gset:Npn \use_ii:nnnnnnnn #1#2#3#4#5#6#7#8 {#2} \cs_gset:Npn \use_iii:nnnnnnnn #1#2#3#4#5#6#7#8 {#3} \cs_gset:Npn \use_iv:nnnnnnnn #1#2#3#4#5#6#7#8 {#4} \cs_gset:Npn \use_v:nnnnnnnn #1#2#3#4#5#6#7#8 {#5} \cs_gset:Npn \use_vi:nnnnnnnn #1#2#3#4#5#6#7#8 {#6} \cs_gset:Npn \use_vii:nnnnnnnn #1#2#3#4#5#6#7#8 {#7} \cs_gset:Npn \use_viii:nnnnnnnn #1#2#3#4#5#6#7#8 {#8} \cs_gset:Npn \use_i:nnnnnnnnn #1#2#3#4#5#6#7#8#9 {#1} \cs_gset:Npn \use_ii:nnnnnnnnn #1#2#3#4#5#6#7#8#9 {#2} \cs_gset:Npn \use_iii:nnnnnnnnn #1#2#3#4#5#6#7#8#9 {#3} \cs_gset:Npn \use_iv:nnnnnnnnn #1#2#3#4#5#6#7#8#9 {#4} \cs_gset:Npn \use_v:nnnnnnnnn #1#2#3#4#5#6#7#8#9 {#5} \cs_gset:Npn \use_vi:nnnnnnnnn #1#2#3#4#5#6#7#8#9 {#6} \cs_gset:Npn \use_vii:nnnnnnnnn #1#2#3#4#5#6#7#8#9 {#7} \cs_gset:Npn \use_viii:nnnnnnnnn #1#2#3#4#5#6#7#8#9 {#8} \cs_gset:Npn \use_ix:nnnnnnnnn #1#2#3#4#5#6#7#8#9 {#9} % \end{macrocode} % \end{macro} % % \begin{macro}[EXP]{\use_i_ii:nnn} % \begin{macrocode} \cs_gset:Npn \use_i_ii:nnn #1#2#3 {#1#2} % \end{macrocode} % \end{macro} % % \begin{macro}[EXP]{\use_ii_i:nn} % \begin{macrocode} \cs_gset:Npn \use_ii_i:nn #1#2 { #2 #1 } % \end{macrocode} % \end{macro} % % % \begin{macro}[EXP] % { % \use_none_delimit_by_q_nil:w , % \use_none_delimit_by_q_stop:w , % \use_none_delimit_by_q_recursion_stop:w % } % Functions that gobble everything until they see either \cs{q_nil}, % \cs{q_stop}, or \cs{q_recursion_stop}, respectively. % \begin{macrocode} \cs_gset:Npn \use_none_delimit_by_q_nil:w #1 \q_nil { } \cs_gset:Npn \use_none_delimit_by_q_stop:w #1 \q_stop { } \cs_gset:Npn \use_none_delimit_by_q_recursion_stop:w #1 \q_recursion_stop { } % \end{macrocode} % \end{macro} % % \begin{macro}[EXP] % { % \use_i_delimit_by_q_nil:nw , % \use_i_delimit_by_q_stop:nw , % \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_gset:Npn \use_i_delimit_by_q_nil:nw #1#2 \q_nil {#1} \cs_gset:Npn \use_i_delimit_by_q_stop:nw #1#2 \q_stop {#1} \cs_gset:Npn \use_i_delimit_by_q_recursion_stop:nw #1#2 \q_recursion_stop {#1} % \end{macrocode} % \end{macro} % % \subsection{Gobbling tokens from input} % % \begin{macro}[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 % } % 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 we could define functions to % remove ten arguments or more using separate calls of % \cs{use_none:nnnnn}, this is very non-intuitive to the programmer % who will assume that expanding such a function once takes care % of gobbling all the tokens in one go. % \begin{macrocode} \cs_gset:Npn \use_none:n #1 { } \cs_gset:Npn \use_none:nn #1#2 { } \cs_gset:Npn \use_none:nnn #1#2#3 { } \cs_gset:Npn \use_none:nnnn #1#2#3#4 { } \cs_gset:Npn \use_none:nnnnn #1#2#3#4#5 { } \cs_gset:Npn \use_none:nnnnnn #1#2#3#4#5#6 { } \cs_gset:Npn \use_none:nnnnnnn #1#2#3#4#5#6#7 { } \cs_gset:Npn \use_none:nnnnnnnn #1#2#3#4#5#6#7#8 { } \cs_gset:Npn \use_none:nnnnnnnnn #1#2#3#4#5#6#7#8#9 { } % \end{macrocode} % \end{macro} % % \subsection{Debugging and patching later definitions} % % \begin{macrocode} %<@@=debug> % \end{macrocode} % % \begin{macro}{\__kernel_if_debug:TF} % A more meaningful test of whether debugging is enabled than messing % up with guards. We can also more easily change the logic in one % place then. This is needed primarily for deprecations. % \begin{macrocode} \cs_gset_protected:Npn \__kernel_if_debug:TF #1#2 {#2} % \end{macrocode} % \end{macro} % % \begin{macro}{\debug_on:n, \debug_off:n} % Stubs. % \begin{macrocode} \cs_gset_protected:Npn \debug_on:n #1 { \sys_load_debug: \cs_if_exist:NT \@@_all_on: { \debug_on:n {#1} } } \cs_gset_protected:Npn \debug_off:n #1 { \sys_load_debug: \cs_if_exist:NT \@@_all_on: { \debug_off:n {#1} } } % \end{macrocode} % \end{macro} % % \begin{macro}{\debug_suspend:, \debug_resume:} % \begin{macrocode} \cs_gset_protected:Npn \debug_suspend: { } \cs_gset_protected:Npn \debug_resume: { } % \end{macrocode} % \end{macro} % % \begin{macro}{\__kernel_deprecation_code:nn} % \begin{variable}{\g_@@_deprecation_on_tl, \g_@@_deprecation_off_tl} % Make deprecated commands throw errors if the user requests it. % This relies on two token lists, filled up in \pkg{l3deprecation}. % \begin{macrocode} \cs_gset_nopar:Npn \g_@@_deprecation_on_tl { } \cs_gset_nopar:Npn \g_@@_deprecation_off_tl { } \cs_gset_protected:Npn \__kernel_deprecation_code:nn #1#2 { \tl_gput_right:Nn \g_@@_deprecation_on_tl {#1} \tl_gput_right:Nn \g_@@_deprecation_off_tl {#2} } % \end{macrocode} % \end{variable} % \end{macro} % % \subsection{Conditional processing and definitions} % % \begin{macrocode} %<@@=prg> % \end{macrocode} % % 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 % \cs{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}[EXP]{\prg_return_true:, \prg_return_false:} % The idea here is that \cs{exp:w} expands fully any % \cs{else:} and \cs{fi:} that are waiting to be discarded, % before reaching the \cs{exp_end:} which leaves an empty expansion. % 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_gset:Npn \prg_return_true: { \exp_after:wN \use_i:nn \exp:w } \cs_gset:Npn \prg_return_false: { \exp_after:wN \use_ii:nn \exp: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 would work. % \end{macro} % % \begin{macro}[EXP]{\@@_use_none_delimit_by_q_recursion_stop:w} % Private version of \cs{use_none_delimit_by_q_recursion_stop:w}. % \begin{macrocode} \cs_gset:Npn \@@_use_none_delimit_by_q_recursion_stop:w #1 \q_@@_recursion_stop { } % \end{macrocode} % \end{macro} % % \begin{macro} % { % \prg_set_conditional:Npnn , % \prg_gset_conditional:Npnn , % \prg_new_conditional:Npnn , % \prg_set_protected_conditional:Npnn , % \prg_gset_protected_conditional:Npnn, % \prg_new_protected_conditional:Npnn % } % \begin{macro}{\@@_generate_conditional_parm:NNNpnn} % The user functions for the types using parameter text from the % programmer. The various functions only differ by which function is % used for the assignment. For those |Npnn| type functions, we must % grab the parameter text, reading everything up to a left brace % before continuing. Then split the base function into name and % signature, and feed \Arg{name} \Arg{signature} \meta{boolean} % \Arg{set~or~new} \Arg{maybe~protected} \Arg{parameters} |{TF,...}| % \Arg{code} to the auxiliary function responsible for defining all % conditionals. % Note that |e| stands for expandable and |p| for protected. % \begin{macrocode} \cs_gset_protected:Npn \prg_set_conditional:Npnn { \@@_generate_conditional_parm:NNNpnn \cs_set:Npn e } \cs_gset_protected:Npn \prg_gset_conditional:Npnn { \@@_generate_conditional_parm:NNNpnn \cs_gset:Npn e } \cs_gset_protected:Npn \prg_new_conditional:Npnn { \@@_generate_conditional_parm:NNNpnn \cs_new:Npn e } \cs_gset_protected:Npn \prg_set_protected_conditional:Npnn { \@@_generate_conditional_parm:NNNpnn \cs_set_protected:Npn p } \cs_gset_protected:Npn \prg_gset_protected_conditional:Npnn { \@@_generate_conditional_parm:NNNpnn \cs_gset_protected:Npn p } \cs_gset_protected:Npn \prg_new_protected_conditional:Npnn { \@@_generate_conditional_parm:NNNpnn \cs_new_protected:Npn p } \cs_gset_protected:Npn \@@_generate_conditional_parm:NNNpnn #1#2#3#4# { \use:e { \@@_generate_conditional:nnNNNnnn \cs_split_function:N #3 } #1 #2 {#4} } % \end{macrocode} % \end{macro} % \end{macro} % % \begin{macro} % { % \prg_set_conditional:Nnn , % \prg_gset_conditional:Nnn , % \prg_new_conditional:Nnn , % \prg_set_protected_conditional:Nnn , % \prg_gset_protected_conditional:Nnn, % \prg_new_protected_conditional:Nnn % } % \begin{macro} % { % \@@_generate_conditional_count:NNNnn , % \@@_generate_conditional_count:nnNNNnn % } % The user functions for the types automatically inserting the correct % parameter text based on the signature. The various functions only % differ by which function is used for the assignment. Split the base % function into name and signature. The second auxiliary generates % the parameter text from the number of letters in the signature. % Then feed \Arg{name} \Arg{signature} \meta{boolean} \Arg{set~or~new} % \Arg{maybe~protected} \Arg{parameters} |{TF,...}| \Arg{code} to the % auxiliary function responsible for defining all conditionals. If % the \meta{signature} has more than $9$ letters, the definition is % aborted since \TeX{} macros have at most $9$ arguments. The % erroneous case where the function name contains no colon is captured % later. % \begin{macrocode} \cs_gset_protected:Npn \prg_set_conditional:Nnn { \@@_generate_conditional_count:NNNnn \cs_set:Npn e } \cs_gset_protected:Npn \prg_gset_conditional:Nnn { \@@_generate_conditional_count:NNNnn \cs_set:Npn e } \cs_gset_protected:Npn \prg_new_conditional:Nnn { \@@_generate_conditional_count:NNNnn \cs_new:Npn e } \cs_gset_protected:Npn \prg_set_protected_conditional:Nnn { \@@_generate_conditional_count:NNNnn \cs_set_protected:Npn p } \cs_gset_protected:Npn \prg_gset_protected_conditional:Nnn { \@@_generate_conditional_count:NNNnn \cs_gset_protected:Npn p } \cs_gset_protected:Npn \prg_new_protected_conditional:Nnn { \@@_generate_conditional_count:NNNnn \cs_new_protected:Npn p } \cs_gset_protected:Npn \@@_generate_conditional_count:NNNnn #1#2#3 { \use:e { \@@_generate_conditional_count:nnNNNnn \cs_split_function:N #3 } #1 #2 } \cs_gset_protected:Npn \@@_generate_conditional_count:nnNNNnn #1#2#3#4#5 { \__kernel_cs_parm_from_arg_count:nnF { \@@_generate_conditional:nnNNNnnn {#1} {#2} #3 #4 #5 } { \tl_count:n {#2} } { \msg_error:nnee { kernel } { bad-number-of-arguments } { \token_to_str:c { #1 : #2 } } { \tl_count:n {#2} } \use_none:nn } } % \end{macrocode} % \end{macro} % \end{macro} % % \begin{macro} % { % \@@_generate_conditional:nnNNNnnn, % \@@_generate_conditional:NNnnnnNw, % \@@_generate_conditional_test:w, % \@@_generate_conditional_fast: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. In the absence of a colon, we throw an error and don't define % any conditional. The fourth and fifth arguments build up the % defining function. The sixth is the parameters to use (possibly % empty), the seventh is the list of forms to define, the eighth is the % replacement text which we will augment when defining the forms. % The use of \cs{tl_to_str:n} makes the later loop more robust. % % A large number of our low-level conditionals look like \meta{code} % \cs{prg_return_true:} \cs{else:} \cs{prg_return_false:} \cs{fi:} so % we optimize this special case by calling % \cs{@@_generate_conditional_fast:nw} \Arg{code}. This passes % \cs{use_i:nn} instead of \cs{use_i_ii:nnn} to functions such as % \cs{@@_generate_p_form:wNNnnnnN}. % \begin{macrocode} \cs_gset_protected:Npn \@@_generate_conditional:nnNNNnnn #1#2#3#4#5#6#7#8 { \if_meaning:w \c_false_bool #3 \msg_error:nne { kernel } { missing-colon } { \token_to_str:c {#1} } \exp_after:wN \use_none:nn \fi: \use:e { \exp_not:N \@@_generate_conditional:NNnnnnNw \exp_not:n { #4 #5 {#1} {#2} {#6} } \@@_generate_conditional_test:w #8 \s_@@_mark \@@_generate_conditional_fast:nw \prg_return_true: \else: \prg_return_false: \fi: \s_@@_mark \use_none:n \exp_not:n { {#8} \use_i_ii:nnn } \tl_to_str:n {#7} \exp_not:n { , \q_@@_recursion_tail , \q_@@_recursion_stop } } } \cs_gset:Npn \@@_generate_conditional_test:w #1 \prg_return_true: \else: \prg_return_false: \fi: \s_@@_mark #2 { #2 {#1} } \cs_gset:Npn \@@_generate_conditional_fast:nw #1#2 \exp_not:n #3 { \exp_not:n { {#1} \use_i:nn } } % \end{macrocode} % Looping through the list of desired forms. First are six arguments % and seventh is the form. Use the form to call the % correct type. If the form does not exist, the \cs{use:c} % construction results in \tn{relax}, and the error message is % displayed (unless the form is empty, to allow for |{T, , F}|), % then \cs{use_none:nnnnnnnn} cleans up. Otherwise, the % error message is removed by the variant form. % \begin{macrocode} \cs_gset_protected:Npn \@@_generate_conditional:NNnnnnNw #1#2#3#4#5#6#7#8 , { \if_meaning:w \q_@@_recursion_tail #8 \exp_after:wN \@@_use_none_delimit_by_q_recursion_stop:w \fi: \use:c { @@_generate_ #8 _form:wNNnnnnN } \tl_if_empty:nF {#8} { \msg_error:nnee { kernel } { conditional-form-unknown } {#8} { \token_to_str:c { #3 : #4 } } } \use_none:nnnnnnnn \s_@@_stop #1 #2 {#3} {#4} {#5} {#6} #7 \@@_generate_conditional:NNnnnnNw #1 #2 {#3} {#4} {#5} {#6} #7 } % \end{macrocode} % \end{macro} % % \begin{macro} % { % \@@_generate_p_form:wNNnnnnN, % \@@_generate_TF_form:wNNnnnnN, % \@@_generate_T_form:wNNnnnnN, % \@@_generate_F_form:wNNnnnnN % } % \begin{macro}[EXP]{\@@_p_true:w, \@@_T_true:w, \@@_F_true:w, \@@_TF_true:w} % How to generate the various forms. Those functions take the % following arguments: 1: junk, 2: \cs{cs_set:Npn} or similar, 3: |p| % (for protected conditionals) or |e|, 4: function name, 5: signature, % 6: parameter text, 7: replacement (possibly trimmed by % \cs{@@_generate_conditional_fast:nw}), 8: \cs{use_i_ii:nnn} or % \cs{use_i:nn} (for \enquote{fast} conditionals). Remember that the % logic-returning functions expect two arguments to be present after % \cs{exp_end:}: notice the construction of the different variants % relies on this, and that the |TF| and |F| variants will be slightly % faster than the |T| version. The |p| form is only valid for % expandable tests, we check for that by making sure that the second % argument is empty. For \enquote{fast} conditionals, |#7| has an % extra \cs[no-index]{if_\ldots{}}. To optimize a bit further we % don't use \cs{exp_after:wN} \cs{use_ii:nnn} and similar but instead use % \cs{@@_TF_true:w} and similar to swap out the macro after \cs{fi:}. It would % be a tiny bit faster if we directly grabbed the |T| and |F| arguments there, % but if those are actually missing, the recovery from the runaway argument % would not insert \cs{fi:} back, messing up nesting of conditionals. % \begin{macrocode} \cs_gset_protected:Npn \@@_generate_p_form:wNNnnnnN #1 \s_@@_stop #2#3#4#5#6#7#8 { \if_meaning:w e #3 \exp_after:wN \use_i:nn \else: \exp_after:wN \use_ii:nn \fi: { #8 { \exp_args:Nc #2 { #4 _p: #5 } #6 } { { #7 \exp_end: \c_true_bool \c_false_bool } } { #7 \@@_p_true:w \fi: \c_false_bool } } { \msg_error:nne { kernel } { protected-predicate } { \token_to_str:c { #4 _p: #5 } } } } \cs_gset_protected:Npn \@@_generate_T_form:wNNnnnnN #1 \s_@@_stop #2#3#4#5#6#7#8 { #8 { \exp_args:Nc #2 { #4 : #5 T } #6 } { { #7 \exp_end: \use:n \use_none:n } } { #7 \@@_T_true:w \fi: \use_none:n } } \cs_gset_protected:Npn \@@_generate_F_form:wNNnnnnN #1 \s_@@_stop #2#3#4#5#6#7#8 { #8 { \exp_args:Nc #2 { #4 : #5 F } #6 } { { #7 \exp_end: { } } } { #7 \@@_F_true:w \fi: \use:n } } \cs_gset_protected:Npn \@@_generate_TF_form:wNNnnnnN #1 \s_@@_stop #2#3#4#5#6#7#8 { #8 { \exp_args:Nc #2 { #4 : #5 TF } #6 } { { #7 \exp_end: } } { #7 \@@_TF_true:w \fi: \use_ii:nn } } \cs_gset:Npn \@@_p_true:w \fi: \c_false_bool { \fi: \c_true_bool } \cs_gset:Npn \@@_T_true:w \fi: \use_none:n { \fi: \use:n } \cs_gset:Npn \@@_F_true:w \fi: \use:n { \fi: \use_none:n } \cs_gset:Npn \@@_TF_true:w \fi: \use_ii:nn { \fi: \use_i:nn } % \end{macrocode} % \end{macro} % \end{macro} % % \begin{macro} % { % \prg_set_eq_conditional:NNn , % \prg_gset_eq_conditional:NNn, % \prg_new_eq_conditional:NNn % } % \begin{macro}{\@@_set_eq_conditional:NNNn} % The setting-equal functions. Split both functions and feed % \Arg{name_1} \Arg{signature_1} \meta{boolean_1} % \Arg{name_2} \Arg{signature_2} \meta{boolean_2} % \meta{copying~function} \meta{conditions} |,| \cs{q_@@_recursion_tail} % |,| \cs{q_@@_recursion_stop} % to a first auxiliary. % \begin{macrocode} \cs_gset_protected:Npn \prg_set_eq_conditional:NNn { \@@_set_eq_conditional:NNNn \cs_set_eq:cc } \cs_gset_protected:Npn \prg_gset_eq_conditional:NNn { \@@_set_eq_conditional:NNNn \cs_gset_eq:cc } \cs_gset_protected:Npn \prg_new_eq_conditional:NNn { \@@_set_eq_conditional:NNNn \cs_new_eq:cc } \cs_gset_protected:Npn \@@_set_eq_conditional:NNNn #1#2#3#4 { \use:e { \exp_not:N \@@_set_eq_conditional:nnNnnNNw \cs_split_function:N #2 \cs_split_function:N #3 \exp_not:N #1 \tl_to_str:n {#4} \exp_not:n { , \q_@@_recursion_tail , \q_@@_recursion_stop } } } % \end{macrocode} % \end{macro} % \end{macro} % % \begin{macro} % { % \@@_set_eq_conditional:nnNnnNNw , % \@@_set_eq_conditional_loop:nnnnNw % } % \begin{macro}[EXP] % { % \@@_set_eq_conditional_p_form:nnn , % \@@_set_eq_conditional_TF_form:nnn , % \@@_set_eq_conditional_T_form:nnn , % \@@_set_eq_conditional_F_form:nnn , % } % Split the function to be defined, and setup a manual clist loop over % argument |#6| of the first auxiliary. The second auxiliary receives % twice three arguments coming from splitting the function to be % defined and the function to copy. Make sure that both functions % contained a colon, otherwise we don't know how to build % conditionals, hence abort. Call the looping macro, with arguments % \Arg{name_1} \Arg{signature_1} \Arg{name_2} \Arg{signature_2} % \meta{copying~function} and followed by the comma list. At each % step in the loop, make sure that the conditional form we copy is % defined, and copy it, otherwise abort. % \begin{macrocode} \cs_gset_protected:Npn \@@_set_eq_conditional:nnNnnNNw #1#2#3#4#5#6 { \if_meaning:w \c_false_bool #3 \msg_error:nne { kernel } { missing-colon } { \token_to_str:c {#1} } \exp_after:wN \@@_use_none_delimit_by_q_recursion_stop:w \fi: \if_meaning:w \c_false_bool #6 \msg_error:nne { kernel } { missing-colon } { \token_to_str:c {#4} } \exp_after:wN \@@_use_none_delimit_by_q_recursion_stop:w \fi: \@@_set_eq_conditional_loop:nnnnNw {#1} {#2} {#4} {#5} } \cs_gset_protected:Npn \@@_set_eq_conditional_loop:nnnnNw #1#2#3#4#5#6 , { \if_meaning:w \q_@@_recursion_tail #6 \exp_after:wN \@@_use_none_delimit_by_q_recursion_stop:w \fi: \use:c { @@_set_eq_conditional_ #6 _form:wNnnnn } \tl_if_empty:nF {#6} { \msg_error:nnee { kernel } { conditional-form-unknown } {#6} { \token_to_str:c { #1 : #2 } } } \use_none:nnnnnn \s_@@_stop #5 {#1} {#2} {#3} {#4} \@@_set_eq_conditional_loop:nnnnNw {#1} {#2} {#3} {#4} #5 } \cs_gset:Npn \@@_set_eq_conditional_p_form:wNnnnn #1 \s_@@_stop #2#3#4#5#6 { #2 { #3 _p : #4 } { #5 _p : #6 } } \cs_gset:Npn \@@_set_eq_conditional_TF_form:wNnnnn #1 \s_@@_stop #2#3#4#5#6 { #2 { #3 : #4 TF } { #5 : #6 TF } } \cs_gset:Npn \@@_set_eq_conditional_T_form:wNnnnn #1 \s_@@_stop #2#3#4#5#6 { #2 { #3 : #4 T } { #5 : #6 T } } \cs_gset:Npn \@@_set_eq_conditional_F_form:wNnnnn #1 \s_@@_stop #2#3#4#5#6 { #2 { #3 : #4 F } { #5 : #6 F } } % \end{macrocode} % \end{macro} % \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 \cs{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{variable}{\c_true_bool, \c_false_bool} % Here are the canonical boolean values. % \begin{macrocode} \tex_global:D \tex_chardef:D \c_true_bool = 1 ~ \tex_global:D \tex_chardef:D \c_false_bool = 0 ~ % \end{macrocode} % \end{variable} % % \subsection{Dissecting a control sequence} % % \begin{macrocode} %<@@=cs> % \end{macrocode} % % \begin{function}[EXP]{\@@_count_signature:N} % \begin{syntax} % \cs{@@_count_signature:N} \meta{function} % \end{syntax} % Splits the \meta{function} into the \meta{name} (\emph{i.e.}~the part % before the colon) and the \meta{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}{\@@_tmp:w} % Function used for various short-term usages, for instance defining % functions whose definition involves tokens which are hard to insert % normally (spaces, characters with category other). % \end{function} % % \begin{macro}[EXP]{\cs_to_str:N} % \begin{macro}[EXP]{\@@_to_str:N, \@@_to_str: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 the \tn{escapechar} 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 character codes are different, thus the \cs{if:w} test is false, % and \TeX{} reads \cs{@@_to_str:N} after turning the following % control sequence into a string; this auxiliary removes the escape % character, and stops the expansion of the initial \cs{tex_romannumeral:D}. % The second case is that the escape character is not printable. Then % the \cs{if:w} test is unfinished after reading a the space from % \verb*|\token_to_str:N \ |, and the auxiliary \cs{@@_to_str:w} % is expanded, feeding |-| as a second character for the test; % the test is false, and \TeX{} skips to \cs{fi:}, then performs % \cs{token_to_str:N}, and stops the \cs{tex_romannumeral:D} with \cs{c_zero_int}. % The last case is that the escape character is itself a space. In this % case, the \cs{if:w} test is true, and the auxiliary \cs{@@_to_str:w} % comes into play, inserting |-\int_value:w|, which expands \cs{c_zero_int} % to the character |0|. The initial \cs{tex_romannumeral:D} then sees % |0|, which is not a terminated number, followed by the escape character, % a space, which is removed, terminating the expansion of % \cs{tex_romannumeral:D}. % In all three cases, \cs{cs_to_str:N} takes two expansion steps % to be fully expanded. % \begin{macrocode} \cs_gset:Npn \cs_to_str:N { % \end{macrocode} % We implement the expansion scheme using \cs{tex_romannumeral:D} % terminating it with \cs{c_zero_int} rather than using \cs{exp:w} and % \cs{exp_end:} as we normally do. The reason is that the code % heavily depends on terminating the expansion with \cs{c_zero_int} so % we make this dependency explicit. % \begin{macrocode} \tex_romannumeral:D \if:w \token_to_str:N \ \@@_to_str:w \fi: \exp_after:wN \@@_to_str:N \token_to_str:N } \cs_gset:Npn \@@_to_str:N #1 { \c_zero_int } \cs_gset:Npn \@@_to_str:w #1 \@@_to_str:N { - \int_value:w \fi: \exp_after:wN \c_zero_int } % \end{macrocode} % If speed is a concern we could use \tn{csstring} in \LuaTeX{}. For % the empty csname that primitive gives an empty result while the % current \cs{cs_to_str:N} gives incorrect results in all engines % (this is impossible to fix without huge performance hit). % \end{macro} % \end{macro} % % \begin{macro}[EXP]{\cs_split_function:N} % \begin{macro}[EXP] % {\@@_split_function_auxi:w, \@@_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. % % First ensure that we actually get a properly evaluated string by % expanding \cs{cs_to_str:N} twice. If the function contained a % colon, the auxiliary takes as |#1| the function name, delimited by % the first colon, then the signature |#2|, delimited by \cs{s_@@_mark}, % then \cs{c_true_bool} as |#3|, and |#4| cleans up until \cs{s_@@_stop}. % Otherwise, the |#1| contains the function name and \cs{s_@@_mark} % \cs{c_true_bool}, |#2| is empty, |#3| is \cs{c_false_bool}, and |#4| % cleans up. The second % auxiliary trims the trailing \cs{s_@@_mark} from the function name if % present (that is, if the original function had no colon). % \begin{macrocode} \cs_gset_protected:Npn \@@_tmp:w #1 { \cs_gset:Npn \cs_split_function:N ##1 { \exp_after:wN \exp_after:wN \exp_after:wN \@@_split_function_auxi:w \cs_to_str:N ##1 \s_@@_mark \c_true_bool #1 \s_@@_mark \c_false_bool \s_@@_stop } \cs_gset:Npn \@@_split_function_auxi:w ##1 #1 ##2 \s_@@_mark ##3##4 \s_@@_stop { \@@_split_function_auxii:w ##1 \s_@@_mark \s_@@_stop {##2} ##3 } \cs_gset:Npn \@@_split_function_auxii:w ##1 \s_@@_mark ##2 \s_@@_stop { {##1} } } \exp_after:wN \@@_tmp:w \token_to_str:N : % \end{macrocode} % \end{macro} % \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 % \tn{relax} token. A control sequence is said to be \emph{free} % (to be defined) if it does not already exist. % % \begin{macro}[pTF, EXP]{\cs_if_exist:N, \cs_if_exist:c} % \begin{macro}{\@@_if_exist_c_aux:,\@@_if_exist_c_aux:w} % Two versions for checking existence. For the |N| form we firstly % check for \cs{scan_stop:} and then if it is in the hash % table. There is no problem when inputting something like \cs{else:} % or \cs{fi:} as \TeX{} will only ever skip input in case the token % tested against is \cs{scan_stop:}. % % In both the |N| and |c| form we use the way \cs{prg_set_conditional:Npnn} % optimizes the conditionals to negate the tests using \cs{else:} (the % \cs{else:} in the top level functions will be removed by the optimization, % and this usage of \cs{else:} will be fine). % \begin{macrocode} \prg_gset_conditional:Npnn \cs_if_exist:N #1 { p , T , F , TF } { \if_meaning:w #1 \scan_stop: \use_i:nnnn \else: \fi: \if_cs_exist:N #1 \prg_return_true: \else: \prg_return_false: \fi: } % \end{macrocode} % For the |c| form we firstly check if it is in the hash table and % then for \cs{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} \cs_if_exist:NTF \tex_lastnamedcs:D { \prg_gset_conditional:Npnn \cs_if_exist:c #1 { p , T , F , TF } { \if_cs_exist:w #1 \cs_end: \@@_if_exist_c_aux: \prg_return_true: \else: \prg_return_false: \fi: } \cs_gset:Npn \@@_if_exist_c_aux: { \fi: \exp_after:wN \if_meaning:w \tex_lastnamedcs:D \scan_stop: \else: } } { \prg_gset_conditional:Npnn \cs_if_exist:c #1 { p , T , F , TF } { \if_cs_exist:w #1 \cs_end: \@@_if_exist_c_aux:w \fi: \use_none:n {#1} \if_false: \prg_return_true: \else: \prg_return_false: \fi: } \cs_gset:Npn \@@_if_exist_c_aux:w \fi: \use_none:n #1 \if_false: { \fi: \exp_after:wN \if_meaning:w \cs:w #1 \cs_end: \scan_stop: \else: } } % \end{macrocode} % \end{macro} % \end{macro} % % \begin{macro}[pTF, EXP]{\cs_if_free:N, \cs_if_free:c} % The logical reversal of the above. % \begin{macrocode} \prg_gset_conditional:Npnn \cs_if_free:N #1 { p , T , F , TF } { \if_cs_exist:N #1 \else: \use_none:nnnn \fi: \if_meaning:w #1 \scan_stop: \prg_return_true: \else: \prg_return_false: \fi: } \cs_if_exist:NTF \tex_lastnamedcs:D { \prg_gset_conditional:Npnn \cs_if_free:c #1 { p , T , F , TF } { \if_cs_exist:w #1 \cs_end: \@@_if_free_c_aux:w \fi: \if_true: \prg_return_true: \else: \prg_return_false: \fi: } \cs_gset:Npn \@@_if_free_c_aux:w \fi: \if_true: { \fi: \exp_after:wN \if_meaning:w \tex_lastnamedcs:D \scan_stop: } } { \prg_gset_conditional:Npnn \cs_if_free:c #1 { p , T , F , TF } { \if_cs_exist:w #1 \cs_end: \@@_if_free_c_aux:w \fi: \use_none:n {#1} \if_true: \prg_return_true: \else: \prg_return_false: \fi: } \cs_gset:Npn \@@_if_free_c_aux:w \fi: \use_none:n #1 \if_true: { \fi: \exp_after:wN \if_meaning:w \cs:w #1 \cs_end: \scan_stop: } } % \end{macrocode} % \end{macro} % % \begin{macro}[EXP,noTF,added=2011-10-10] % {\cs_if_exist_use:N, \cs_if_exist_use:c} % \begin{macro}{\@@_if_exist_use_aux:w, \@@_if_exist_use_aux:Nnn} % The \cs[index=cs_if_exist_use:N]{cs_if_exist_use:\ldots{}} % functions cannot be implemented % as conditionals because the true branch must leave both the control % sequence itself and the true code in the input stream. % For the \texttt{c} variants, we are careful not to put the control % sequence in the hash table if it does not exist. % If available we use the \tn{lastnamedcs} primitive. % \begin{macrocode} \cs_gset:Npn \cs_if_exist_use:NTF #1#2 { \cs_if_exist:NTF #1 { #1 #2 } } \cs_gset:Npn \cs_if_exist_use:NF #1 { \cs_if_exist:NTF #1 #1 } \cs_gset:Npn \cs_if_exist_use:NT #1 #2 { \cs_if_exist:NT #1 { #1 #2 } } \cs_gset:Npn \cs_if_exist_use:N #1 { \cs_if_exist:NT #1 #1 } \cs_if_exist:NTF \tex_lastnamedcs:D { \cs_gset:Npn \cs_if_exist_use:cTF #1 { \if_cs_exist:w #1 \cs_end: \@@_if_exist_use_aux:w \fi: \use_ii:nn } \cs_gset:Npn \@@_if_exist_use_aux:w \fi: \use_ii:nn { \fi: \exp_after:wN \@@_if_exist_use_aux:Nnn \tex_lastnamedcs:D } } { \cs_gset:Npn \cs_if_exist_use:cTF #1 { \if_cs_exist:w #1 \cs_end: \@@_if_exist_use_aux:w \fi: \use_iii:nnn {#1} } \cs_gset:Npn \@@_if_exist_use_aux:w \fi: \use_iii:nnn #1 { \fi: \exp_after:wN \@@_if_exist_use_aux:Nnn \cs:w #1 \cs_end: } } \cs_gset:Npn \@@_if_exist_use_aux:Nnn #1#2 { \if_meaning:w #1 \scan_stop: \exp_after:wN \use_iii:nnn \fi: \use_i:nn { #1 #2 } } \cs_gset:Npn \cs_if_exist_use:cF #1 { \cs_if_exist_use:cTF {#1} {} } \cs_gset:Npn \cs_if_exist_use:cT #1#2 { \cs_if_exist_use:cTF {#1} {#2} {} } \cs_gset:Npn \cs_if_exist_use:c #1 { \cs_if_exist_use:cTF {#1} {} {} } % \end{macrocode} % \end{macro} % \end{macro} % % \subsection{Preliminaries for new functions} % % 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 next few definitions here are % only temporary, they will be redefined later on. % % \begin{macro}[documented-as = \msg_error:nnnn] % {\msg_error:nnee, \msg_error:nne, \msg_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. Setting the \tn{newlinechar} is needed, to % turn |^^J| into a proper line break in plain \TeX{}. % \begin{macrocode} \cs_gset_protected:Npn \msg_error:nnee #1#2#3#4 { \tex_newlinechar:D = `\^^J \scan_stop: \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_gset_protected:Npn \msg_error:nne #1#2#3 { \msg_error:nnee {#1} {#2} {#3} { } } \cs_gset_protected:Npn \msg_error:nn #1#2 { \msg_error:nnee {#1} {#2} { } { } } % \end{macrocode} % \end{macro} % % \begin{macro}[rEXP]{\msg_line_context:} % Another one from \pkg{l3msg} which will be altered later. % \begin{macrocode} \cs_gset:Npn \msg_line_context: { on~line~ \tex_the:D \tex_inputlineno:D } % \end{macrocode} % \end{macro} % % \begin{macro}[documented-as=\iow_log:n]{\iow_log:e, \iow_term:e} % 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{l3file}. % \begin{macrocode} \cs_gset_protected:Npn \iow_log:e { \tex_immediate:D \tex_write:D -1 } \cs_gset_protected:Npn \iow_term:e { \tex_immediate:D \tex_write:D 16 } % \end{macrocode} % \end{macro} % % \begin{macro}{\__kernel_chk_if_free_cs:N, \__kernel_chk_if_free_cs:c} % This command is called by \cs{cs_new_nopar:Npn} and \cs{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 \cs{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_gset_protected:Npn \__kernel_chk_if_free_cs:N #1 { \cs_if_free:NF #1 { \msg_error:nnee { kernel } { command-already-defined } { \token_to_str:N #1 } { \token_to_meaning:N #1 } } } \cs_gset_protected:Npn \__kernel_chk_if_free_cs:c { \exp_args:Nc \__kernel_chk_if_free_cs:N } % \end{macrocode} % \end{macro} % % \subsection{Defining new functions} % % \begin{macrocode} %<@@=cs> % \end{macrocode} % % \begin{macro} % { % \cs_new_nopar:Npn , \cs_new_nopar:Npe , \cs_new_nopar:Npx , % \cs_new:Npn , \cs_new:Npe , \cs_new:Npx , % \cs_new_protected_nopar:Npn , \cs_new_protected_nopar:Npe , \cs_new_protected_nopar:Npx , % \cs_new_protected:Npn , \cs_new_protected:Npe , \cs_new_protected:Npx % } % \begin{macro}{\@@_tmp:w} % Function which check that the control sequence is free before % defining it. % \begin{macrocode} \cs_set:Npn \@@_tmp:w #1#2 { \cs_gset_protected:Npn #1 ##1 { \__kernel_chk_if_free_cs:N ##1 #2 ##1 } } \@@_tmp:w \cs_new_nopar:Npn \cs_gset_nopar:Npn \@@_tmp:w \cs_new_nopar:Npe \cs_gset_nopar:Npe \@@_tmp:w \cs_new_nopar:Npx \cs_gset_nopar:Npx \@@_tmp:w \cs_new:Npn \cs_gset:Npn \@@_tmp:w \cs_new:Npe \cs_gset:Npe \@@_tmp:w \cs_new:Npx \cs_gset:Npx \@@_tmp:w \cs_new_protected_nopar:Npn \cs_gset_protected_nopar:Npn \@@_tmp:w \cs_new_protected_nopar:Npe \cs_gset_protected_nopar:Npe \@@_tmp:w \cs_new_protected_nopar:Npx \cs_gset_protected_nopar:Npx \@@_tmp:w \cs_new_protected:Npn \cs_gset_protected:Npn \@@_tmp:w \cs_new_protected:Npe \cs_gset_protected:Npe \@@_tmp:w \cs_new_protected:Npx \cs_gset_protected:Npx % \end{macrocode} % \end{macro} % \end{macro} % % \begin{macro}[documented-as=\cs_set_nopar:Npn] % { % \cs_set_nopar:cpn , \cs_set_nopar:cpe , \cs_set_nopar:cpx , % \cs_gset_nopar:cpn , \cs_gset_nopar:cpe , \cs_gset_nopar:cpx , % \cs_new_nopar:cpn , \cs_new_nopar:cpe , \cs_new_nopar:cpx % } % Like \cs{cs_set_nopar:Npn} and \cs{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{cs_set_nopar:cpn}\meta{string}\meta{rep-text} turns \meta{string} % into a csname and then assigns \meta{rep-text} to it by using % \cs{cs_set_nopar:Npn}. This means that there might be a parameter % string between the two arguments. % \begin{macrocode} \cs_set:Npn \@@_tmp:w #1#2 { \cs_new_protected_nopar:Npn #1 { \exp_args:Nc #2 } } \@@_tmp:w \cs_set_nopar:cpn \cs_set_nopar:Npn \@@_tmp:w \cs_set_nopar:cpe \cs_set_nopar:Npe \@@_tmp:w \cs_set_nopar:cpx \cs_set_nopar:Npx \@@_tmp:w \cs_gset_nopar:cpn \cs_gset_nopar:Npn \@@_tmp:w \cs_gset_nopar:cpe \cs_gset_nopar:Npe \@@_tmp:w \cs_gset_nopar:cpx \cs_gset_nopar:Npx \@@_tmp:w \cs_new_nopar:cpn \cs_new_nopar:Npn \@@_tmp:w \cs_new_nopar:cpe \cs_new_nopar:Npe \@@_tmp:w \cs_new_nopar:cpx \cs_new_nopar:Npx % \end{macrocode} % \end{macro} % % \begin{macro}[documented-as=\cs_set:Npn] % { % \cs_set:cpn , \cs_set:cpe , \cs_set:cpx , % \cs_gset:cpn , \cs_gset:cpe , \cs_gset:cpx , % \cs_new:cpn , \cs_new:cpe , \cs_new:cpx % } % Variants of the \cs{cs_set:Npn} versions which make a csname out % of the first arguments. We may also do this globally. % \begin{macrocode} \@@_tmp:w \cs_set:cpn \cs_set:Npn \@@_tmp:w \cs_set:cpe \cs_set:Npe \@@_tmp:w \cs_set:cpx \cs_set:Npx \@@_tmp:w \cs_gset:cpn \cs_gset:Npn \@@_tmp:w \cs_gset:cpe \cs_gset:Npe \@@_tmp:w \cs_gset:cpx \cs_gset:Npx \@@_tmp:w \cs_new:cpn \cs_new:Npn \@@_tmp:w \cs_new:cpe \cs_new:Npe \@@_tmp:w \cs_new:cpx \cs_new:Npx % \end{macrocode} % \end{macro} % % \begin{macro}[documented-as=\cs_set_protected_nopar:Npn] % { % \cs_set_protected_nopar:cpn , \cs_set_protected_nopar:cpe , \cs_set_protected_nopar:cpx , % \cs_gset_protected_nopar:cpn , \cs_gset_protected_nopar:cpe , \cs_gset_protected_nopar:cpx , % \cs_new_protected_nopar:cpn , \cs_new_protected_nopar:cpe , \cs_new_protected_nopar:cpx % } % Variants of the \cs{cs_set_protected_nopar:Npn} versions which make % a csname out of the first arguments. We may also do this globally. % \begin{macrocode} \@@_tmp:w \cs_set_protected_nopar:cpn \cs_set_protected_nopar:Npn \@@_tmp:w \cs_set_protected_nopar:cpe \cs_set_protected_nopar:Npe \@@_tmp:w \cs_set_protected_nopar:cpx \cs_set_protected_nopar:Npx \@@_tmp:w \cs_gset_protected_nopar:cpn \cs_gset_protected_nopar:Npn \@@_tmp:w \cs_gset_protected_nopar:cpe \cs_gset_protected_nopar:Npe \@@_tmp:w \cs_gset_protected_nopar:cpx \cs_gset_protected_nopar:Npx \@@_tmp:w \cs_new_protected_nopar:cpn \cs_new_protected_nopar:Npn \@@_tmp:w \cs_new_protected_nopar:cpe \cs_new_protected_nopar:Npe \@@_tmp:w \cs_new_protected_nopar:cpx \cs_new_protected_nopar:Npx % \end{macrocode} % \end{macro} % % \begin{macro}[documented-as=\cs_set_protected:Npn] % { % \cs_set_protected:cpn , \cs_set_protected:cpe , \cs_set_protected:cpx , % \cs_gset_protected:cpn , \cs_gset_protected:cpe , \cs_gset_protected:cpx , % \cs_new_protected:cpn , \cs_new_protected:cpe , \cs_new_protected:cpx % } % Variants of the \cs{cs_set_protected:Npn} versions which make a csname % out of the first arguments. We may also do this globally. % \begin{macrocode} \@@_tmp:w \cs_set_protected:cpn \cs_set_protected:Npn \@@_tmp:w \cs_set_protected:cpe \cs_set_protected:Npe \@@_tmp:w \cs_set_protected:cpx \cs_set_protected:Npx \@@_tmp:w \cs_gset_protected:cpn \cs_gset_protected:Npn \@@_tmp:w \cs_gset_protected:cpe \cs_gset_protected:Npe \@@_tmp:w \cs_gset_protected:cpx \cs_gset_protected:Npx \@@_tmp:w \cs_new_protected:cpn \cs_new_protected:Npn \@@_tmp:w \cs_new_protected:cpe \cs_new_protected:Npe \@@_tmp:w \cs_new_protected:cpx \cs_new_protected:Npx % \end{macrocode} % \end{macro} % % \subsection{Copying definitions} % % \begin{macro} % { % \cs_set_eq:NN , \cs_set_eq:cN , \cs_set_eq:Nc , \cs_set_eq:cc , % \cs_gset_eq:NN , \cs_gset_eq:cN , \cs_gset_eq:Nc , \cs_gset_eq:cc , % \cs_new_eq:NN , \cs_new_eq:cN , \cs_new_eq:Nc , \cs_new_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{cs_set_eq:NN} is long to avoid problems with a literal argument % of \cs{par}. While \cs{cs_new_eq:NN} will probably never be correct % with a first argument of \cs{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:Npn \cs_set_eq:cN { \exp_args:Nc \cs_set_eq:NN } \cs_new_protected:Npn \cs_set_eq:Nc { \exp_args:NNc \cs_set_eq:NN } \cs_new_protected:Npn \cs_set_eq:cc { \exp_args:Ncc \cs_set_eq:NN } \cs_new_protected:Npn \cs_gset_eq:NN { \tex_global:D \cs_set_eq:NN } \cs_new_protected:Npn \cs_gset_eq:Nc { \exp_args:NNc \cs_gset_eq:NN } \cs_new_protected:Npn \cs_gset_eq:cN { \exp_args:Nc \cs_gset_eq:NN } \cs_new_protected:Npn \cs_gset_eq:cc { \exp_args:Ncc \cs_gset_eq:NN } \cs_new_protected:Npn \cs_new_eq:NN #1 { \__kernel_chk_if_free_cs:N #1 \tex_global:D \cs_set_eq:NN #1 } \cs_new_protected:Npn \cs_new_eq:cN { \exp_args:Nc \cs_new_eq:NN } \cs_new_protected:Npn \cs_new_eq:Nc { \exp_args:NNc \cs_new_eq:NN } \cs_new_protected:Npn \cs_new_eq:cc { \exp_args:Ncc \cs_new_eq:NN } % \end{macrocode} % \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. % We optimize the case where the command exists by reducing as much as % possible the tokens in the conditional. % \begin{macrocode} \cs_new_protected:Npn \cs_undefine:N #1 { \cs_gset_eq:NN #1 \tex_undefined:D } \cs_new_protected:Npn \cs_undefine:c #1 { \if_cs_exist:w #1 \cs_end: \else: \use_i:nnnn \fi: \exp_args:Nc \cs_undefine:N {#1} } % \end{macrocode} % \end{macro} % % \subsection{Generating parameter text from argument count} % % \begin{macrocode} %<@@=cs> % \end{macrocode} % % \begin{macro}{\__kernel_cs_parm_from_arg_count:nnF} % \begin{macro}{\@@_parm_from_arg_count_test:nnF} % \LaTeX3 provides shorthands to define control sequences and % conditionals with a simple parameter text, derived directly from the % signature, or more generally from knowing the number of arguments, % between~$0$ and~$9$. This function expands to its first argument, % untouched, followed by a brace group containing the parameter text % |{#|$1$\ldots{}|#|$n$|}|, where $n$ is the result of evaluating the % second argument (as described in \cs{int_eval:n}). If the second % argument gives a result outside the range $[0,9]$, the third % argument is returned instead, normally an error message. Some of % the functions use here are not defined yet, but will be defined % before this function is called. % \begin{macrocode} \cs_new_protected:Npn \__kernel_cs_parm_from_arg_count:nnF #1#2 { \exp_args:Ne \@@_parm_from_arg_count_test:nnF { \exp_after:wN \exp_not:n \if_case:w \int_eval:n {#2} { } \or: { ##1 } \or: { ##1##2 } \or: { ##1##2##3 } \or: { ##1##2##3##4 } \or: { ##1##2##3##4##5 } \or: { ##1##2##3##4##5##6 } \or: { ##1##2##3##4##5##6##7 } \or: { ##1##2##3##4##5##6##7##8 } \or: { ##1##2##3##4##5##6##7##8##9 } \else: { \c_false_bool } \fi: } {#1} } \cs_new_protected:Npn \@@_parm_from_arg_count_test:nnF #1#2 { \if_meaning:w \c_false_bool #1 \exp_after:wN \use_ii:nn \else: \exp_after:wN \use_i:nn \fi: { #2 {#1} } } % \end{macrocode} % \end{macro} % \end{macro} % % \subsection{Defining functions from a given number of arguments} % % \begin{macrocode} %<@@=cs> % \end{macrocode} % % \begin{macro}[EXP]{\@@_count_signature:N, \@@_count_signature:c} % \begin{macro}[EXP]{\@@_count_signature:n} % \begin{macro}[EXP]{\@@_count_signature:nnN} % Counting the number of tokens in the signature, \emph{i.e.}, the % number of arguments the function should take. Since this is not % used in any time-critical function, we simply use \cs{tl_count:n} if % there is a signature, otherwise $-1$ arguments to signal an error. % We need a variant form right away. % \begin{macrocode} \cs_new:Npn \@@_count_signature:N #1 { \exp_args:Nf \@@_count_signature:n { \cs_split_function:N #1 } } \cs_new:Npn \@@_count_signature:n #1 { \int_eval:n { \@@_count_signature:nnN #1 } } \cs_new:Npn \@@_count_signature:nnN #1#2#3 { \if_meaning:w \c_true_bool #3 \tl_count:n {#2} \else: -1 \fi: } \cs_new:Npn \@@_count_signature:c { \exp_args:Nc \@@_count_signature:N } % \end{macrocode} % \end{macro} % \end{macro} % \end{macro} % % \begin{macro} % { % \cs_generate_from_arg_count:NNnn, % \cs_generate_from_arg_count:cNnn, % \cs_generate_from_arg_count:Ncnn % } % 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 { \__kernel_cs_parm_from_arg_count:nnF { \use:nnn #2 #1 } {#3} { \msg_error:nnee { kernel } { bad-number-of-arguments } { \token_to_str:N #1 } { \int_eval:n {#3} } \use_none:n } {#4} } % \end{macrocode} % A variant form we need right away, plus one which is used elsewhere but % which is most logically created here. % \begin{macrocode} \cs_new_protected:Npn \cs_generate_from_arg_count:cNnn { \exp_args:Nc \cs_generate_from_arg_count:NNnn } \cs_new_protected:Npn \cs_generate_from_arg_count:Ncnn { \exp_args:NNc \cs_generate_from_arg_count:NNnn } % \end{macrocode} % \end{macro} % % \subsection{Using the signature to define functions} % % \begin{macrocode} %<@@=cs> % \end{macrocode} % % We can now combine some of the tools we have to provide a simple % interface for defining functions, where the number of arguments is % read from the signature. For instance, % |\cs_set:Nn \foo_bar:nn {#1,#2}|. % % \begin{macro} % { % \cs_set:Nn , \cs_set:Ne , \cs_set:Nx , % \cs_set_nopar:Nn , \cs_set_nopar:Ne , \cs_set_nopar:Nx , % \cs_set_protected:Nn , \cs_set_protected:Ne , \cs_set_protected:Nx , % \cs_set_protected_nopar:Nn , \cs_set_protected_nopar:Ne , \cs_set_protected_nopar:Nx , % \cs_gset:Nn , \cs_gset:Ne , \cs_gset:Nx , % \cs_gset_nopar:Nn , \cs_gset_nopar:Ne , \cs_gset_nopar:Nx , % \cs_gset_protected:Nn , \cs_gset_protected:Ne , \cs_gset_protected:Nx , % \cs_gset_protected_nopar:Nn , \cs_gset_protected_nopar:Ne , \cs_gset_protected_nopar:Nx , % \cs_new:Nn , \cs_new:Ne , \cs_new:Nx , % \cs_new_nopar:Nn , \cs_new_nopar:Ne , \cs_new_nopar:Nx , % \cs_new_protected:Nn , \cs_new_protected:Ne , \cs_new_protected:Nx , % \cs_new_protected_nopar:Nn , \cs_new_protected_nopar:Ne , \cs_new_protected_nopar:Nx , % } % We want to define \cs{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 % { \@@_count_signature:N #1 } {#2} % } % \end{verbatim} % In short, to define \cs{cs_set:Nn} we need just use \cs{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 \@@_tmp:w #1#2#3 { \cs_new_protected:cpx { cs_ #1 : #2 } { \exp_not:N \@@_generate_from_signature:NNn \exp_after:wN \exp_not:N \cs:w cs_ #1 : #3 \cs_end: } } \cs_new_protected:Npn \@@_generate_from_signature:NNn #1#2 { \use:e { \@@_generate_from_signature:nnNNNn \cs_split_function:N #2 } #1 #2 } \cs_new_protected:Npn \@@_generate_from_signature:nnNNNn #1#2#3#4#5#6 { \bool_if:NTF #3 { \cs_set_nopar:Npx \@@_tmp:w { \tl_map_function:nN {#2} \@@_generate_from_signature:n } \tl_if_empty:oF \@@_tmp:w { \msg_error:nneee { kernel } { non-base-function } { \token_to_str:N #5 } {#2} { \@@_tmp:w } } \cs_generate_from_arg_count:NNnn #5 #4 { \tl_count:n {#2} } {#6} } { \msg_error:nne { kernel } { missing-colon } { \token_to_str:N #5 } } } \cs_new:Npn \@@_generate_from_signature:n #1 { \if:w n #1 \else: \if:w N #1 \else: \if:w T #1 \else: \if:w F #1 \else: #1 \fi: \fi: \fi: \fi: } % \end{macrocode} % Then we define the 24 variants beginning with |N|. % \begin{macrocode} \@@_tmp:w { set } { Nn } { Npn } \@@_tmp:w { set } { Ne } { Npe } \@@_tmp:w { set } { Nx } { Npx } \@@_tmp:w { set_nopar } { Nn } { Npn } \@@_tmp:w { set_nopar } { Ne } { Npe } \@@_tmp:w { set_nopar } { Nx } { Npx } \@@_tmp:w { set_protected } { Nn } { Npn } \@@_tmp:w { set_protected } { Ne } { Npe } \@@_tmp:w { set_protected } { Nx } { Npx } \@@_tmp:w { set_protected_nopar } { Nn } { Npn } \@@_tmp:w { set_protected_nopar } { Ne } { Npe } \@@_tmp:w { set_protected_nopar } { Nx } { Npx } \@@_tmp:w { gset } { Nn } { Npn } \@@_tmp:w { gset } { Ne } { Npe } \@@_tmp:w { gset } { Nx } { Npx } \@@_tmp:w { gset_nopar } { Nn } { Npn } \@@_tmp:w { gset_nopar } { Ne } { Npe } \@@_tmp:w { gset_nopar } { Nx } { Npx } \@@_tmp:w { gset_protected } { Nn } { Npn } \@@_tmp:w { gset_protected } { Ne } { Npe } \@@_tmp:w { gset_protected } { Nx } { Npx } \@@_tmp:w { gset_protected_nopar } { Nn } { Npn } \@@_tmp:w { gset_protected_nopar } { Ne } { Npe } \@@_tmp:w { gset_protected_nopar } { Nx } { Npx } \@@_tmp:w { new } { Nn } { Npn } \@@_tmp:w { new } { Ne } { Npe } \@@_tmp:w { new } { Nx } { Npx } \@@_tmp:w { new_nopar } { Nn } { Npn } \@@_tmp:w { new_nopar } { Ne } { Npe } \@@_tmp:w { new_nopar } { Nx } { Npx } \@@_tmp:w { new_protected } { Nn } { Npn } \@@_tmp:w { new_protected } { Ne } { Npe } \@@_tmp:w { new_protected } { Nx } { Npx } \@@_tmp:w { new_protected_nopar } { Nn } { Npn } \@@_tmp:w { new_protected_nopar } { Ne } { Npe } \@@_tmp:w { new_protected_nopar } { Nx } { Npx } % \end{macrocode} % \end{macro} % % \begin{macro}[documented-as=\cs_set:Nn] % { % \cs_set:cn , \cs_set:ce , \cs_set:cx , % \cs_set_nopar:cn , \cs_set_nopar:ce , \cs_set_nopar:cx , % \cs_set_protected:cn , \cs_set_protected:ce , \cs_set_protected:cx , % \cs_set_protected_nopar:cn , \cs_set_protected_nopar:ce , \cs_set_protected_nopar:cx , % \cs_gset:cn , \cs_gset:ce , \cs_gset:cx , % \cs_gset_nopar:cn , \cs_gset_nopar:ce , \cs_gset_nopar:cx , % \cs_gset_protected:cn , \cs_gset_protected:ce , \cs_gset_protected:cx , % \cs_gset_protected_nopar:cn , \cs_gset_protected_nopar:ce , \cs_gset_protected_nopar:cx , % \cs_new:cn , \cs_new:ce , \cs_new:cx , % \cs_new_nopar:cn , \cs_new_nopar:ce , \cs_new_nopar:cx , % \cs_new_protected:cn , \cs_new_protected:ce , \cs_new_protected:cx , % \cs_new_protected_nopar:cn , \cs_new_protected_nopar:ce , \cs_new_protected_nopar:cx , % } % The 24 |c| variants simply use \cs{exp_args:Nc}. % \begin{macrocode} \cs_set:Npn \@@_tmp:w #1#2 { \cs_new_protected:cpx { cs_ #1 : c #2 } { \exp_not:N \exp_args:Nc \exp_after:wN \exp_not:N \cs:w cs_ #1 : N #2 \cs_end: } } \@@_tmp:w { set } { n } \@@_tmp:w { set } { e } \@@_tmp:w { set } { x } \@@_tmp:w { set_nopar } { n } \@@_tmp:w { set_nopar } { e } \@@_tmp:w { set_nopar } { x } \@@_tmp:w { set_protected } { n } \@@_tmp:w { set_protected } { e } \@@_tmp:w { set_protected } { x } \@@_tmp:w { set_protected_nopar } { n } \@@_tmp:w { set_protected_nopar } { e } \@@_tmp:w { set_protected_nopar } { x } \@@_tmp:w { gset } { n } \@@_tmp:w { gset } { e } \@@_tmp:w { gset } { x } \@@_tmp:w { gset_nopar } { n } \@@_tmp:w { gset_nopar } { e } \@@_tmp:w { gset_nopar } { x } \@@_tmp:w { gset_protected } { n } \@@_tmp:w { gset_protected } { e } \@@_tmp:w { gset_protected } { x } \@@_tmp:w { gset_protected_nopar } { n } \@@_tmp:w { gset_protected_nopar } { e } \@@_tmp:w { gset_protected_nopar } { x } \@@_tmp:w { new } { n } \@@_tmp:w { new } { e } \@@_tmp:w { new } { x } \@@_tmp:w { new_nopar } { n } \@@_tmp:w { new_nopar } { e } \@@_tmp:w { new_nopar } { x } \@@_tmp:w { new_protected } { n } \@@_tmp:w { new_protected } { e } \@@_tmp:w { new_protected } { x } \@@_tmp:w { new_protected_nopar } { n } \@@_tmp:w { new_protected_nopar } { e } \@@_tmp:w { new_protected_nopar } { x } % \end{macrocode} % \end{macro} % % \subsection{Checking control sequence equality} % % \begin{macro}[pTF, EXP] % {\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:Npn \cs_if_eq_p:cN { \exp_args:Nc \cs_if_eq_p:NN } \cs_new:Npn \cs_if_eq:cNTF { \exp_args:Nc \cs_if_eq:NNTF } \cs_new:Npn \cs_if_eq:cNT { \exp_args:Nc \cs_if_eq:NNT } \cs_new:Npn \cs_if_eq:cNF { \exp_args:Nc \cs_if_eq:NNF } \cs_new:Npn \cs_if_eq_p:Nc { \exp_args:NNc \cs_if_eq_p:NN } \cs_new:Npn \cs_if_eq:NcTF { \exp_args:NNc \cs_if_eq:NNTF } \cs_new:Npn \cs_if_eq:NcT { \exp_args:NNc \cs_if_eq:NNT } \cs_new:Npn \cs_if_eq:NcF { \exp_args:NNc \cs_if_eq:NNF } \cs_new:Npn \cs_if_eq_p:cc { \exp_args:Ncc \cs_if_eq_p:NN } \cs_new:Npn \cs_if_eq:ccTF { \exp_args:Ncc \cs_if_eq:NNTF } \cs_new:Npn \cs_if_eq:ccT { \exp_args:Ncc \cs_if_eq:NNT } \cs_new:Npn \cs_if_eq:ccF { \exp_args:Ncc \cs_if_eq:NNF } % \end{macrocode} % \end{macro} % % \subsection{Diagnostic functions} % % \begin{macrocode} %<@@=kernel> % \end{macrocode} % % \begin{macro}{\@@_chk_defined:NT} % Error if the variable |#1| is not defined. % \begin{macrocode} \cs_new_protected:Npn \@@_chk_defined:NT #1#2 { \cs_if_exist:NTF #1 {#2} { \msg_error:nne { kernel } { variable-not-defined } { \token_to_str:N #1 } } } % \end{macrocode} % \end{macro} % % \begin{macro} % {\@@_register_show:N, \@@_register_show:c, \@@_register_log:N, \@@_register_log:c} % \begin{macro}{\@@_register_show_aux:NN, \@@_register_show_aux:nNN} % Simply using the \tn{showthe} primitive does not allow for % line-wrapping, so instead use \cs{tl_show:n} and \cs{tl_log:n} (defined % in \pkg{l3tl} and that performs line-wrapping). This displays % |>~|\meta{variable}|=|\meta{value}. We expand the value before-hand % as otherwise some integers (such as \tn{currentgrouplevel} or % \tn{currentgrouptype}) altered by the line-wrapping code would show % wrong values. % \begin{macrocode} \cs_new_protected:Npn \@@_register_show:N { \@@_register_show_aux:NN \tl_show:n } \cs_new_protected:Npn \@@_register_show:c { \exp_args:Nc \@@_register_show:N } \cs_new_protected:Npn \@@_register_log:N { \@@_register_show_aux:NN \tl_log:n } \cs_new_protected:Npn \@@_register_log:c { \exp_args:Nc \@@_register_log:N } \cs_new_protected:Npn \@@_register_show_aux:NN #1#2 { \@@_chk_defined:NT #2 { \exp_args:No \@@_register_show_aux:nNN { \tex_the:D #2 } #2 #1 } } \cs_new_protected:Npn \@@_register_show_aux:nNN #1#2#3 { \exp_args:No #3 { \token_to_str:N #2 = #1 } } % \end{macrocode} % \end{macro} % \end{macro} % % \begin{macro}{\cs_show:N, \cs_show:c, \cs_log:N, \cs_log:c, \@@_show:NN} % Some control sequences have a very long name or meaning. Thus, % simply using \TeX{}'s primitive \tn{show} could lead to overlong % lines. The output of this primitive is mimicked to some extent, % then the re-built string is given to \cs{tl_show:n} or \cs{tl_log:n} for % line-wrapping. We must expand the meaning before passing it to the % wrapping code as otherwise we would wrongly see the definitions that % are in place there. To get correct escape characters, set the % \tn{escapechar} in a group; this also localizes the assignment % performed by \texttt{e}-expansion. The \cs{cs_show:c} and \cs{cs_log:c} commands % convert their argument to a control sequence within a group to avoid % showing \tn{relax} for undefined control sequences. % \begin{macrocode} \cs_new_protected:Npn \cs_show:N { \@@_show:NN \tl_show:n } \cs_new_protected:Npn \cs_show:c { \group_begin: \exp_args:NNc \group_end: \cs_show:N } \cs_new_protected:Npn \cs_log:N { \@@_show:NN \tl_log:n } \cs_new_protected:Npn \cs_log:c { \group_begin: \exp_args:NNc \group_end: \cs_log:N } \cs_new_protected:Npn \@@_show:NN #1#2 { \group_begin: \int_set:Nn \tex_escapechar:D { `\\ } \exp_args:NNe \group_end: #1 { \token_to_str:N #2 = \cs_meaning:N #2 } } % \end{macrocode} % \end{macro} % % \begin{macro}{\group_show_list:, \group_log_list:, \@@_group_show:NN} % Wrapper around \tn{showgroups}. Getting \TeX{} to write to the log % without interruption the run is done by altering the interaction % mode. % \begin{macrocode} \cs_new_protected:Npn \group_show_list: { \@@_group_show:NN \use_none:n 1 } \cs_new_protected:Npn \group_log_list: { \@@_group_show:NN \int_gzero:N 0 } \cs_new_protected:Npn \@@_group_show:NN #1#2 { \use:e { #1 \tex_interactionmode:D \int_set:Nn \tex_tracingonline:D {#2} \int_set:Nn \tex_errorcontextlines:D { -1 } \exp_not:N \exp_after:wN \scan_stop: \tex_showgroups:D \int_gset:Nn \tex_interactionmode:D { \int_use:N \tex_interactionmode:D } \int_set:Nn \tex_tracingonline:D { \int_use:N \tex_tracingonline:D } \int_set:Nn \tex_errorcontextlines:D { \int_use:N \tex_errorcontextlines:D } } } % \end{macrocode} % \end{macro} % % \subsection{Decomposing a macro definition} % % \begin{macro}{\cs_prefix_spec:N} % \begin{macro}{\cs_parameter_spec:N} % \begin{macro}{\cs_replacement_spec:N} % \begin{macro}{\@@_prefix_arg_replacement:wN} % We sometimes want to test if a control sequence can be expanded to % reveal a hidden value. However, we cannot just expand the macro % blindly as it may have arguments and none might be % present. Therefore we define these functions to pick either the % prefix(es), the parameter specification, or the replacement text from % a macro. All of this information is returned as characters with % catcode~$12$. If the token in question isn't a macro, the token % \cs{scan_stop:} is returned instead. % \begin{macrocode} \use:e { \exp_not:n { \cs_new:Npn \@@_prefix_arg_replacement:wN #1 } \tl_to_str:n { macro : } \exp_not:n { #2 -> #3 \s_@@_stop #4 } } { #4 {#1} {#2} {#3} } \cs_new:Npn \cs_prefix_spec:N #1 { \token_if_macro:NTF #1 { \exp_after:wN \@@_prefix_arg_replacement:wN \token_to_meaning:N #1 \s_@@_stop \use_i:nnn } { \scan_stop: } } \cs_new:Npn \cs_parameter_spec:N #1 { \token_if_macro:NTF #1 { \exp_after:wN \@@_prefix_arg_replacement:wN \token_to_meaning:N #1 \s_@@_stop \use_ii:nnn } { \scan_stop: } } \cs_new:Npn \cs_replacement_spec:N #1 { \token_if_macro:NTF #1 { \exp_after:wN \@@_prefix_arg_replacement:wN \token_to_meaning:N #1 \s_@@_stop \use_iii:nnn } { \scan_stop: } } % \end{macrocode} % \end{macro} % \end{macro} % \end{macro} % \end{macro} % % \subsection{Doing nothing functions} % % \begin{macro}[EXP]{\prg_do_nothing:} % This does not fit anywhere else! % \begin{macrocode} \cs_new:Npn \prg_do_nothing: { } % \end{macrocode} % \end{macro} % % \subsection{Breaking out of mapping functions} % % \begin{macrocode} %<@@=prg> % \end{macrocode} % % \begin{macro}[EXP]{\prg_break_point:Nn, \prg_map_break:Nn} % In inline mappings, the nesting level must be reset % at the end of the mapping, even when the user decides % to break out. This is done by putting the code that % must be performed as an argument of \cs{@@_break_point:Nn}. % The breaking functions are then defined to jump to % that point and perform the argument of \cs{@@_break_point:Nn}, % before the user's code (if any). There is a check that we close the % correct loop, otherwise we continue breaking. % \begin{macrocode} \cs_new_eq:NN \prg_break_point:Nn \use_ii:nn \cs_new:Npn \prg_map_break:Nn #1#2#3 \prg_break_point:Nn #4#5 { #5 \if_meaning:w #1 #4 \exp_after:wN \use_iii:nnn \fi: \prg_map_break:Nn #1 {#2} } % \end{macrocode} % \end{macro} % % \begin{macro}{\prg_break_point:} % \begin{macro}{\prg_break:, \prg_break:n} % Very simple analogues of \cs{prg_break_point:Nn} and % \cs{prg_map_break:Nn}, for use in fast short-term recursions which % are not mappings, do not need to support nesting, and in which % nothing has to be done at the end of the loop. % \begin{macrocode} \cs_new_eq:NN \prg_break_point: \prg_do_nothing: \cs_new:Npn \prg_break: #1 \prg_break_point: { } \cs_new:Npn \prg_break:n #1#2 \prg_break_point: {#1} % \end{macrocode} % \end{macro} % \end{macro} % % \subsection{Starting a paragraph} % % \begin{macro}{\mode_leave_vertical:} % The approach here is different to that used by \LaTeXe{} or plain \TeX{}, % which unbox a void box to force horizontal mode. That inserts the % \tn{everypar} tokens \emph{before} the re-inserted unboxing tokens. The % approach here uses a protected macro, equivalent to the \tn{quitvmode} % primitive. In vertical mode, the \tn{indent} primitive is inserted: % this will switch to horizontal mode and insert \tn{everypar} tokens and % nothing else. Unlike the \LaTeXe{} version, the availability of \eTeX{} % means using a mode test can be done at for example the start of an % \tn{halign}. % \begin{macrocode} \cs_new_protected:Npn \mode_leave_vertical: { \if_mode_vertical: \exp_after:wN \tex_indent:D \fi: } % \end{macrocode} % \end{macro} % % \begin{macrocode} % % \end{macrocode} % % \end{implementation} % % \PrintIndex