% \iffalse meta-comment % %% File: xparse.dtx (C) Copyright 1999 Frank Mittelbach, Chris Rowley, %% David Carlisle %% (C) Copyright 2004-2008 Frank Mittelbach, %% The LaTeX3 Project %% (C) Copyright 2009-2017 The LaTeX3 Project % % It may be distributed and/or modified under the conditions of the % LaTeX Project Public License (LPPL), either version 1.3c of this % license or (at your option) any later version. The latest version % of this license is in the file % % http://www.latex-project.org/lppl.txt % % This file is part of the "l3packages 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|package> % The version of expl3 required is tested as early as possible, as % some really old versions do not define \ProvidesExplPackage. \RequirePackage{expl3}[2017/03/18] %\@ifpackagelater{expl3}{2017/03/18} % {} % {% % \PackageError{xparse}{Support package l3kernel too old} % {% % Please install an up to date version of l3kernel\MessageBreak % using your TeX package manager or from CTAN.\MessageBreak % \MessageBreak % Loading xparse will abort!% % }% % \endinput % } \def\ExplFileDate{2017/03/18} \def\ExplFileVersion{7019} % %<*driver> \documentclass[full]{l3doc} \usepackage{amstext} \begin{document} \DocInput{\jobname.dtx} \end{document} % % \fi % % \providecommand\acro[1]{\textsc{\MakeLowercase{#1}}} % \newenvironment{arg-description}{% % \begin{itemize}\def\makelabel##1{\hss\llap{\bfseries##1}}}{\end{itemize}} % % \title{^^A % The \textsf{xparse} package\\ Document command parser^^A % \thanks{This file describes v\ExplFileVersion, % last revised \ExplFileDate.}^^A % } % % \author{^^A % The \LaTeX3 Project\thanks % {^^A % E-mail: % \href{mailto:latex-team@latex-project.org} % {latex-team@latex-project.org}^^A % }^^A % } % % \date{Released \ExplFileDate} % % \maketitle % % \begin{documentation} % % The \pkg{xparse} package provides a high-level interface for % producing document-level commands. In that way, it is intended as % a replacement for the \LaTeXe{} \cs{newcommand} macro. However, % \pkg{xparse} works so that the interface to a function (optional % arguments, stars and mandatory arguments, for example) is separate % from the internal implementation. \pkg{xparse} provides a normalised % input for the internal form of a function, independent of the % document-level argument arrangement. % % At present, the functions in \pkg{xparse} which are regarded as % \enquote{stable} are: % \begin{itemize} % \item \cs{NewDocumentCommand} % \item \cs{RenewDocumentCommand} % \item \cs{ProvideDocumentCommand} % \item \cs{DeclareDocumentCommand} % \item \cs{NewDocumentEnvironment} % \item \cs{RenewDocumentEnvironment} % \item \cs{ProvideDocumentEnvironment} % \item \cs{DeclareDocumentEnvironment} % \item \cs{NewExpandableDocumentCommand} % \item \cs{RenewExpandableDocumentCommand} % \item \cs{ProvideExpandableDocumentCommand} % \item \cs{DeclareExpandableDocumentCommand} % \item \cs{IfNoValue(TF)} % \item \cs{IfValue(TF)} % \item \cs{IfBoolean(TF)} % \end{itemize} % with the other functions currently regarded as \enquote{experimental}. Please % try all of the commands provided here, but be aware that the % experimental ones may change or disappear. % % \subsection{Specifying arguments} % % Before introducing the functions used to create document commands, % the method for specifying arguments with \pkg{xparse} will be % illustrated. In order to allow each argument to be defined % independently, \pkg{xparse} does not simply need to know the % number of arguments for a function, but also the nature of each % one. This is done by constructing an \emph{argument specification}, % which defines the number of arguments, the type of each argument % and any additional information needed for \pkg{xparse} to read the % user input and properly pass it through to internal functions. % % The basic form of the argument specifier is a list of letters, where % each letter defines a type of argument. As will be described below, % some of the types need additional information, such as default values. % The argument types can be divided into two, those which define % arguments that are mandatory (potentially raising an error if not % found) and those which define optional arguments. The mandatory types % are: % \begin{itemize}[font=\ttfamily] % \item[m] A standard mandatory argument, which can either be a single % token alone or multiple tokens surrounded by curly braces. % Regardless of the input, the argument will be passed to the % internal code surrounded by a brace pair. This is the \pkg{xparse} % type specifier for a normal \TeX{} argument. % \item[l] An argument which reads everything up to the first % open group token: in standard \LaTeX{} this is a left brace. % \item[r] Reads a \enquote{required} delimited argument, where the % delimiters are given as \meta{token1} and \meta{token2}: % \texttt{r}\meta{token1}\meta{token2}. If the opening \meta{token} % is missing, the default marker |-NoValue-| will be inserted after % a suitable error. % \item[R] As for \texttt{r}, this is a \enquote{required} delimited % argument but has a user-definable recovery \meta{default}, given % as \texttt{R}\meta{token1}\meta{token2}\marg{default}. % \item[u] Reads an argument \enquote{until} \meta{tokens} are encountered, % where the desired \meta{tokens} are given as an argument to the % specifier: \texttt{u}\marg{tokens}. % \item[v] Reads an argument \enquote{verbatim}, between the following % character and its next occurrence, in a way similar to the argument % of the \LaTeXe{} command \cs{verb}. Thus a \texttt{v}-type argument % is read between two matching tokens, which cannot be any of |%|, |\|, % |#|, |{|, |}| or \verb*| |. % The verbatim argument can also be enclosed between braces, |{| and |}|. % A command with a verbatim % argument will not work when it appears within an argument of % another function. % \end{itemize} % The types which define optional arguments are: % \begin{itemize}[font=\ttfamily] % \item[o] A standard \LaTeX{} optional argument, surrounded with square % brackets, which will supply % the special |-NoValue-| marker if not given (as described later). % \item[d] An optional argument which is delimited by \meta{token1} % and \meta{token2}, which are given as arguments: % \texttt{d}\meta{token1}\meta{token2}. As with \texttt{o}, if no % value is given the special marker |-NoValue-| is returned. % \item[O] As for \texttt{o}, but returns \meta{default} if no % value is given. Should be given as \texttt{O}\marg{default}. % \item[D] As for \texttt{d}, but returns \meta{default} if no % value is given: \texttt{D}\meta{token1}\meta{token2}\marg{default}. % Internally, the \texttt{o}, \texttt{d} and \texttt{O} types are % short-cuts to an appropriated-constructed \texttt{D} type argument. % \item[s] An optional star, which will result in a value % \cs{BooleanTrue} if a star is present and \cs{BooleanFalse} % otherwise (as described later). % \item[t] An optional \meta{token}, which will result in a value % \cs{BooleanTrue} if \meta{token} is present and \cs{BooleanFalse} % otherwise. Given as \texttt{t}\meta{token}. % \item[g] An optional argument given inside a pair of \TeX{} group % tokens (in standard \LaTeX, |{| \ldots |}|), which returns % |-NoValue-| if not present. % \item[G] As for \texttt{g} but returns \meta{default} if no value % is given: \texttt{G}\marg{default}. % \item[e] An optional set of \emph{embellishments}, each of which requires a % \emph{value}. If a key is not present, |-NoValue-| is returned. % The returned data is a token list comprising one braced entry per key, % ordered as for the key list in the argument specification. Given as % \texttt{e}\marg{tokens}. All \meta{tokens} must be distinct. % \emph{This is an experimental type}. % \item[E] As for \texttt{e} but returns one or more \meta{defaults} % if values are not given: \texttt{E}\marg{tokens}\marg{defaults}. See % Section~\ref{sec:embellishment} for more details. % \end{itemize} % % Using these specifiers, it is possible to create complex input syntax % very easily. For example, given the argument definition % `|s o o m O{default}|', the input `|*[Foo]{Bar}|' would be parsed as: % \begin{itemize}[nolistsep] % \item |#1| = |\BooleanTrue| % \item |#2| = |Foo| % \item |#3| = |-NoValue-| % \item |#4| = |Bar| % \item |#5| = |default| % \end{itemize} % whereas `|[One][Two]{}[Three]|' would be parsed as: % \begin{itemize}[nolistsep] % \item |#1| = |\BooleanFalse| % \item |#2| = |One| % \item |#3| = |Two| % \item |#4| = || % \item |#5| = |Three| % \end{itemize} % % Delimited argument types (\texttt{d}, \texttt{o} and \texttt{r}) are % defined such that they require matched pairs of delimiters when collecting % an argument. For example % \begin{verbatim} % \NewDocumentCommand{\foo}{o}{#1} % \foo[[content]] % #1 = "[content]" % \foo[[] % Error: missing closing "]" % \end{verbatim} % Also note that |{| and |}| cannot be used as delimiters as they are used % by \TeX{} as grouping tokens. Arguments to be grabbed inside these tokens % must be created as either \texttt{m}- or \texttt{g}-type arguments. % % Within delimited arguments, non-balanced or otherwise awkward tokens may % be included by protecting the entire argument with a brace pair % \begin{verbatim} % \NewDocumentCommand{\foobar}{o}{#1} % \foobar[{[}] % Allowed as the "[" is 'hidden' % \end{verbatim} % These braces will be stripped if they surround the \emph{entire} content % of the optional argument % \begin{verbatim} % \NewDocumentCommand{\foobaz}{o}{#1} % \foobaz[{abc}] % => "abc" % \foobaz[ {abc}] % => " {abc}" % \end{verbatim} % % Two more tokens have a special meaning when creating an argument % specifier. First, \texttt{+} is used to make an argument long (to % accept paragraph tokens). In contrast to \LaTeXe's \cs{newcommand}, % this applies on an argument-by-argument basis. So modifying the % example to `|s o o +m O{default}|' means that the mandatory argument % is now \cs{long}, whereas the optional arguments are not. % % Secondly, the token \texttt{>} is used to declare so-called % \enquote{argument processors}, which can be used to modify the contents of an % argument before it is passed to the macro definition. The use of % argument processors is a somewhat advanced topic, (or at least a less % commonly used feature) and is covered in Section~\ref{sec:processors}. % % When an optional argument is followed by a mandatory argument with the % same delimiter, \pkg{xparse} issues a warning because the optional % argument could not be omitted by the user, thus becoming in effect % mandatory. This applies to \texttt{o}, \texttt{d}, \texttt{O}, % \texttt{D}, \texttt{s}, \texttt{t}, \texttt{e}, and \texttt{E} type % arguments followed by \texttt{r} or \texttt{R}-type required % arguments, but also to \texttt{g} or \texttt{G} type arguments % followed by \texttt{m} type arguments. % % \subsection{Spacing and optional arguments} % % \TeX{} will find the first argument after a function name irrespective % of any intervening spaces. This is true for both mandatory and % optional arguments. So |\foo[arg]| and \verb*|\foo [arg]| are % equivalent. Spaces are also ignored when collecting arguments up % to the last mandatory argument to be collected (as it must exist). % So after % \begin{verbatim} % \NewDocumentCommand \foo { m o m } { ... } % \end{verbatim} % the user input |\foo{arg1}[arg2]{arg3}| and % \verb*|\foo{arg1} [arg2] {arg3}| will both be parsed in the same % way. However, spaces are \emph{not} ignored when parsing optional % arguments after the last mandatory argument. Thus with % \begin{verbatim} % \NewDocumentCommand \foobar { m o } { ... } % \end{verbatim} % |\foobar{arg1}[arg2]| will find an optional argument but % \verb*|\foobar{arg1} [arg2]| will not. This is so that trailing optional % arguments are not picked up \enquote{by accident} in input. % % There is one major exception to the rules listed above: when % \pkg{xparse} is used to define what \TeX\ defines as \enquote{control % symbols} in which the function name is made up of a single character, % such as \enquote{\cmd{\\}}, spaces are \emph{not} ignored directly % after them even for mandatory arguments. % % \subsection{Required delimited arguments} % % The contrast between a delimited (\texttt{D}-type) and \enquote{required % delimited} (\texttt{R}-type) argument is that an error will be raised if % the latter is missing. Thus for example % \begin{verbatim} % \NewDocumentCommand {\foobaz} {r()m} {} % \foobaz{oops} % \end{verbatim} % will lead to an error message being issued. The marker |-NoValue-| % (\texttt{r}-type) or user-specified default (for \texttt{R}-type) will be % inserted to allow error recovery. % % Users should note that support for required delimited arguments is somewhat % experimental. Feedback is therefore very welcome on the \texttt{LaTeX-L} % mailing list. % % \subsection{Verbatim arguments} % % Arguments of type~\texttt{v} are read in verbatim mode, which will % result in the grabbed argument consisting of tokens of category codes % $12$~(\enquote{other}) and $13$~(\enquote{active}), except spaces, % which are given category code $10$~(\enquote{space}). The argument is % delimited in a similar manner to the \LaTeXe{} \cs{verb} function, or % by (correctly nested) pairs of braces. % % Functions containing verbatim arguments cannot appear in the arguments % of other functions. The \texttt{v}~argument specifier includes code to check % this, and will raise an error if the grabbed argument has already been % tokenized by \TeX{} in an irreversible way. % % By default, an argument of type~\texttt{v} must be at most one line. % Prefixing with \texttt{+} allows line breaks within the argument. % % Users should note that support for verbatim arguments is somewhat % experimental. Feedback is therefore very welcome on the \texttt{LaTeX-L} % mailing list. % % \subsection{Default values of arguments} % % Uppercase argument types (\texttt{O}, \texttt{D}, \ldots{}) allow to % specify a default value to be used when the argument is missing; their % lower-case counterparts use the special marker |-NoValue-|. The % default value can be expressed in terms of the value of any other % arguments by using |#1|, |#2|, and so on. % \begin{verbatim} % \NewDocumentCommand {\conjugate} { m O{#1ed} O{#2} } {(#1,#2,#3)} % \conjugate {walk} % => (walk,walked,walked) % \conjugate {find} [found] % => (find,found,found) % \conjugate {do} [did] [done] % => (do,did,done) % \end{verbatim} % The default values may refer to arguments that appear later in the % argument specification. For instance a command could accept two % optional arguments, equal by default: % \begin{verbatim} % \NewDocumentCommand {\margins} { O{#3} m O{#1} m } {(#1,#2,#3,#4)} % \margins {a} {b} % => {(-NoValue-,a,-NoValue-,b)} % \margins [1cm] {a} {b} % => {(1cm,a,1cm,b)} % \margins {a} [1cm] {b} % => {(1cm,a,1cm,b)} % \margins [1cm] {a} [2cm] {b} % => {(1cm,a,2cm,b)} % \end{verbatim} % % Users should note that support for default arguments referring to % other arguments is somewhat experimental. Feedback is therefore very % welcome on the \texttt{LaTeX-L} mailing list. % % \subsection{Default values for \enquote{embellishments}} % \label{sec:embellishment} % % The \texttt{E}-type argument allows one default value per test token. % This is achieved by giving a list of defaults for each entry in the % list, for example: % \begin{verbatim} % E{^_}{{UP}{DOWN}} % \end{verbatim} % If the list of default values is \emph{shorter} than the list of test tokens, % the special \cs{NoValue} marker will be returned (as for the \texttt{e}-type % argument). Thus for example % \begin{verbatim} % E{^_}{{UP}} % \end{verbatim} % has default \texttt{UP} for the |^| test token, but will return the % \cs{NoValue} marker as a default for |_|. This allows mixing of explicit % defaults with testing for missing values. % % \subsection{Declaring commands and environments} % % With the concept of an argument specifier defined, it is now % possible to describe the methods available for creating both % functions and environments using \pkg{xparse}. % % The interface-building commands are the preferred method for % creating document-level functions in \LaTeX3. All of the functions % generated in this way are naturally robust (using the \eTeX{} % \cs{protected} mechanism). % % \begin{function} % { % \NewDocumentCommand , % \RenewDocumentCommand , % \ProvideDocumentCommand , % \DeclareDocumentCommand % } % \begin{syntax} % \cs{NewDocumentCommand} \meta{Function} \Arg{arg spec} \Arg{code} % \end{syntax} % This family of commands are used to create a document-level % \meta{function}. The argument specification for the function is % given by \meta{arg spec}, and expanding % to be replaced by the \meta{code}. % \end{function} % % As an example: % \begin{verbatim} % \NewDocumentCommand \chapter { s o m } % { % \IfBooleanTF {#1} % { \typesetstarchapter {#3} } % { \typesetnormalchapter {#2} {#3} } % } % \end{verbatim} % would be a way to define a \cs{chapter} command which would % essentially behave like the current \LaTeXe{} command (except that it % would accept an optional argument even when a \texttt{*} was parsed). % The \cs{typesetnormalchapter} could test its first argument for being % |-NoValue-| to see if an optional argument was present. % % The difference between the \cs{New\ldots} \cs{Renew\ldots}, % \cs{Provide\ldots} and \cs{Declare\ldots} versions is the behaviour % if \meta{function} is already defined. % \begin{itemize} % \item \cs{NewDocumentCommand} will issue an error if \meta{function} % has already been defined. % \item \cs{RenewDocumentCommand} will issue an error if \meta{function} % has not previously been defined. % \item \cs{ProvideDocumentCommand} creates a new definition for % \meta{function} only if one has not already been given. % \item \cs{DeclareDocumentCommand} will always create the new % definition, irrespective of any existing \meta{function} with the % same name. This should be used sparingly. % \end{itemize} % % \begin{texnote} % Unlike \LaTeXe{}'s \cs{newcommand} and relatives, the % \cs{NewDocumentCommand} family of functions do not prevent creation of % functions with names starting \cs{end\ldots}. % \end{texnote} % % \begin{function} % { % \NewDocumentEnvironment , % \RenewDocumentEnvironment , % \ProvideDocumentEnvironment , % \DeclareDocumentEnvironment % } % \begin{syntax} % \cs{NewDocumentEnvironment} \Arg{environment} \Arg{arg spec} % ~~\Arg{start code} \Arg{end code} % \end{syntax} % These commands work in the same way as \cs{NewDocumentCommand}, % etc.\@, but create environments (\cs{begin}\Arg{environment} \ldots{} % \cs{end}\Arg{environment}). Both the \meta{start code} and % \meta{end code} % may access the arguments as defined by \meta{arg spec}. % The arguments will be given following \cs{begin}\Arg{environment}. % \end{function} % % \subsection{Testing special values} % % Optional arguments created using \pkg{xparse} make use of dedicated % variables to return information about the nature of the argument % received. % % \begin{function}[EXP]{\IfNoValueT, \IfNoValueF, \IfNoValueTF} % \begin{syntax} % \cs{IfNoValueTF} \Arg{argument} \Arg{true code} \Arg{false code} % \cs{IfNoValueT} \Arg{argument} \Arg{true code} % \cs{IfNoValueF} \Arg{argument} \Arg{false code} % \end{syntax} % The \cs{IfNoValue(TF)} tests are used to check if \meta{argument} (|#1|, % |#2|, \emph{etc.}) is the special |-NoValue-| marker For example % \begin{verbatim} % \NewDocumentCommand \foo { o m } % { % \IfNoValueTF {#1} % { \DoSomethingJustWithMandatoryArgument {#2} } % { \DoSomethingWithBothArguments {#1} {#2} } % } % \end{verbatim} % will use a different internal function if the optional argument % is given than if it is not present. % % Note that three tests are available, depending on which outcome % branches are required: \cs{IfNoValueTF}, \cs{IfNoValueT} and % \cs{IfNoValueF}. % % As the \cs{IfNoValue(TF)} tests are expandable, it is possible to % test these values later, for example at the point of typesetting or % in an expansion context. % % It is important to note that |-NoValue-| is constructed such that it % will \emph{not} match the simple text input |-NoValue-|, \emph{i.e.} % that % \begin{verbatim} % \IfNoValueTF{-NoValue-} % \end{verbatim} % will be logically \texttt{false}. % % When two optional arguments follow each other (a syntax we typically % discourage), it can make sense to allow users of the command to % specify only the second argument by providing an empty first % argument. Rather than testing separately for emptyness and for % |-NoValue-| it is then best to use the argument type~|O| with an % empty default value, and simply test for emptyness using the % \pkg{expl3} conditional \cs{tl_if_blank:nTF} or its \pkg{etoolbox} % analogue \tn{ifblank}. % \end{function} % % \begin{function}[EXP]{\IfValueT, \IfValueF, \IfValueTF} % \begin{syntax} % \cs{IfValueTF} \Arg{argument} \Arg{true code} \Arg{false code} % \end{syntax} % The reverse form of the \cs{IfNoValue(TF)} tests are also available % as \cs{IfValue(TF)}. The context will determine which logical % form makes the most sense for a given code scenario. % \end{function} % % \begin{variable}{\BooleanFalse, \BooleanTrue} % The \texttt{true} and \texttt{false} flags set when searching for % an optional token (using \texttt{s} or \texttt{t\meta{token}}) have % names which are accessible outside of code blocks. % \end{variable} % % \begin{function}[EXP]{\IfBooleanT, \IfBooleanF, \IfBooleanTF} % \begin{syntax} % \cs{IfBooleanTF} \meta{argument} \Arg{true code} \Arg{false code} % \end{syntax} % Used to test if \meta{argument} (|#1|, |#2|, \emph{etc.}) is % \cs{BooleanTrue} or \cs{BooleanFalse}. For example % \begin{verbatim} % \NewDocumentCommand \foo { s m } % { % \IfBooleanTF #1 % { \DoSomethingWithStar {#2} } % { \DoSomethingWithoutStar {#2} } % } % \end{verbatim} % checks for a star as the first argument, then chooses the action to % take based on this information. % \end{function} % % \subsection{Argument processors} % \label{sec:processors} % % \pkg{xparse} introduces the idea of an argument processor, which is % applied to an argument \emph{after} it has been grabbed by the % underlying system but before it is passed to \meta{code}. An argument % processor can therefore be used to regularise input at an early stage, % allowing the internal functions to be completely independent of input % form. Processors are applied to user input and to default values for % optional arguments, but \emph{not} to the special \cs{NoValue} marker. % % Each argument processor is specified by the syntax % \texttt{>}\marg{processor} in the argument specification. Processors % are applied from right to left, so that % \begin{verbatim} % >{\ProcessorB} >{\ProcessorA} m % \end{verbatim} % would apply \cs{ProcessorA} % followed by \cs{ProcessorB} to the tokens grabbed by the \texttt{m} % argument. % % \begin{variable}{\ProcessedArgument} % \pkg{xparse} defines a very small set of processor functions. In the % main, it is anticipated that code writers will want to create their % own processors. These need to accept one argument, which is the % tokens as grabbed (or as returned by a previous processor function). % Processor functions should return the processed argument as the % variable \cs{ProcessedArgument}. % \end{variable} % % \begin{function}{\ReverseBoolean} % \begin{syntax} % \cs{ReverseBoolean} % \end{syntax} % This processor reverses the logic of \cs{BooleanTrue} and % \cs{BooleanFalse}, so that the example from earlier would become % \begin{verbatim} % \NewDocumentCommand \foo { > { \ReverseBoolean } s m } % { % \IfBooleanTF #1 % { \DoSomethingWithoutStar {#2} } % { \DoSomethingWithStar {#2} } % } % \end{verbatim} % \end{function} % % \begin{function}[updated = 2012-02-12]{\SplitArgument} % \begin{syntax} % \cs{SplitArgument} \Arg{number} \Arg{token} % \end{syntax} % This processor splits the argument given at each occurrence of the % \meta{token} up to a maximum of \meta{number} tokens (thus % dividing the input into $\text{\meta{number}} + 1$ parts). % An error is given if too many \meta{tokens} are present in the % input. The processed input is placed inside % $\text{\meta{number}} + 1$ sets of braces for further use. % If there are fewer than \Arg{number} of \Arg{tokens} in the argument % then \cs{NoValue} markers are added at the end of the processed % argument. % \begin{verbatim} % \NewDocumentCommand \foo % { > { \SplitArgument { 2 } { ; } } m } % { \InternalFunctionOfThreeArguments #1 } % \end{verbatim} % Any category code $13$ (active) \meta{tokens} will be replaced % before the split takes place. Spaces are trimmed at each end of each % item parsed. % \end{function} % % \begin{function}{\SplitList} % \begin{syntax} % \cs{SplitList} \Arg{token(s)} % \end{syntax} % This processor splits the argument given at each occurrence of the % \meta{token(s)} where the number of items is not fixed. Each item is % then wrapped in braces within |#1|. The result is that the % processed argument can be further processed using a mapping function. % \begin{verbatim} % \NewDocumentCommand \foo % { > { \SplitList { ; } } m } % { \MappingFunction #1 } % \end{verbatim} % If only a single \meta{token} is used for the split, any % category code $13$ (active) \meta{token} will be replaced % before the split takes place. % \end{function} % % \begin{function}[EXP]{\ProcessList} % \begin{syntax} % \cs{ProcessList} \Arg{list} \Arg{function} % \end{syntax} % To support \cs{SplitList}, the function \cs{ProcessList} is available % to apply a \meta{function} to every entry in a \meta{list}. The % \meta{function} should absorb one argument: the list entry. For example % \begin{verbatim} % \NewDocumentCommand \foo % { > { \SplitList { ; } } m } % { \ProcessList {#1} { \SomeDocumentFunction } } % \end{verbatim} % % \textbf{This function is experimental.} % \end{function} % % \begin{function}{\TrimSpaces} % \begin{syntax} % \cs{TrimSpaces} % \end{syntax} % Removes any leading and trailing spaces (tokens with character code~$32$ % and category code~$10$) for the ends of the argument. Thus for example % declaring a function % \begin{verbatim} % \NewDocumentCommand \foo % { > { \TrimSpaces } m } % { \showtokens {#1} } % \end{verbatim} % and using it in a document as % \begin{verbatim} % \foo{ hello world } % \end{verbatim} % will show \texttt{hello world} at the terminal, with the space at each % end removed. \cs{TrimSpaces} will remove multiple spaces from the ends of % the input in cases where these have been included such that the standard % \TeX{} conversion of multiple spaces to a single space does not apply. % % \textbf{This function is experimental.} % \end{function} % % \subsection{Fully-expandable document commands} % % There are \emph{very rare} occasion when it may be useful to create % functions using a fully-expandable argument grabber. To support this, % \pkg{xparse} can create expandable functions as well as the usual % robust ones. This imposes a number of restrictions on the nature of % the arguments accepted by a function, and the code it implements. % This facility should only be used when \emph{absolutely necessary}; % if you do not understand when this might be, \emph{do not use these % functions}! % % \begin{function} % { % \NewExpandableDocumentCommand , % \RenewExpandableDocumentCommand , % \ProvideExpandableDocumentCommand , % \DeclareExpandableDocumentCommand % } % \begin{syntax} % \cs{NewExpandableDocumentCommand} % ~~~~\meta{function} \Arg{arg spec} \Arg{code} % \end{syntax} % This family of commands is used to create a document-level \meta{function}, % which will grab its arguments in a fully-expandable manner. The % argument specification for the function is given by \meta{arg spec}, % and the function will execute \meta{code}. In general, \meta{code} will % also be fully expandable, although it is possible that this will % not be the case (for example, a function for use in a table might % expand so that \cs{omit} is the first non-expandable non-space token). % % Parsing arguments expandably imposes a number of restrictions on % both the type of arguments that can be read and the error checking % available: % \begin{itemize} % \item The last argument (if any are present) must be one of the % mandatory types \texttt{m} or \texttt{r}. % \item All short arguments appear before long arguments. % \item The mandatory argument types \texttt{l} and \texttt{u} may % not be used after optional arguments. % \item The optional argument types \texttt{g} % and \texttt{G} are not available. % \item The \enquote{verbatim} argument type \texttt{v} is not available. % \item Argument processors (using \texttt{>}) are not available. % \item It is not possible to differentiate between, for example % |\foo[| and |\foo{[}|: in both cases the \texttt{[} will be % interpreted as the start of an optional argument. As a % result, checking for optional arguments is less robust than % in the standard version. % \end{itemize} % \pkg{xparse} will issue an error if an argument specifier is given % which does not conform to the first six requirements. The last % item is an issue when the function is used, and so is beyond the % scope of \pkg{xparse} itself. % \end{function} % % \subsection{Access to the argument specification} % % The argument specifications for document commands and environments are % available for examination and use. % % \begin{function}{\GetDocumentCommandArgSpec, \GetDocumentEnvironmentArgSpec} % \begin{syntax} % \cs{GetDocumentCommandArgSpec} \meta{function} % \cs{GetDocumentEnvironmentArgSpec} \meta{environment} % \end{syntax} % These functions transfer the current argument specification for the % requested \meta{function} or \meta{environment} into the token list % variable \cs{ArgumentSpecification}. If the \meta{function} or % \meta{environment} has no known argument specification then an error % is issued. The assignment to \cs{ArgumentSpecification} is local to % the current \TeX{} group. % \end{function} % % \begin{function} % {\ShowDocumentCommandArgSpec, \ShowDocumentEnvironmentArgSpec} % \begin{syntax} % \cs{ShowDocumentCommandArgSpec} \meta{function} % \cs{ShowDocumentEnvironmentArgSpec} \meta{environment} % \end{syntax} % These functions show the current argument specification for the % requested \meta{function} or \meta{environment} at the terminal. If % the \meta{function} or \meta{environment} has no known argument % specification then an error is issued. % \end{function} % % \section{Load-time options} % % \DescribeOption{log-declarations} % The package recognises the load-time option \texttt{log-declarations}, % which is a key--value option taking the value \texttt{true} and % \texttt{false}. By default, the option is set to \texttt{true}, meaning % that each command or environment declared is logged. By loading % \pkg{xparse} using % \begin{verbatim} % \usepackage[log-declarations=false]{xparse} % \end{verbatim} % this may be suppressed and no information messages are produced. % % \end{documentation} % % \begin{implementation} % % \section{\pkg{xparse} implementation} % % \begin{macrocode} %<*package> % \end{macrocode} % % \begin{macrocode} %<@@=xparse> % \end{macrocode} % % \begin{macrocode} \ProvidesExplPackage{xparse}{\ExplFileDate}{\ExplFileVersion} {L3 Experimental document command parser} % \end{macrocode} % % \subsection{Variables and constants} % % \begin{variable}{\c_@@_no_value_tl} % A special \enquote{awkward} token list: it contains two |-|~tokens with % different category codes. This is used as the marker for nothing being % returned when no optional argument is given. % \begin{macrocode} \tl_const:Nx \c_@@_no_value_tl { \char_generate:nn { `\- } { 11 } NoValue- } % \end{macrocode} % \end{variable} % % \begin{variable}{\c_@@_special_chars_seq} % In \IniTeX{} mode, we store special characters in a sequence. % Maybe |$| or |&| will have to be added later. % \begin{macrocode} %<*initex> \seq_new:N \c_@@_special_chars_seq \seq_set_split:Nnn \c_@@_special_chars_seq { } { \ \\ \{ \} \# \^ \_ \% \~ } % % \end{macrocode} % \end{variable} % % \begin{variable}{\l_@@_arg_spec_tl} % Holds the argument specification after normalization of shorthands. % \begin{macrocode} \tl_new:N \l_@@_arg_spec_tl % \end{macrocode} % \end{variable} % % \begin{variable}{\l_@@_args_tl} % Token list variable for grabbed arguments. % \begin{macrocode} \tl_new:N \l_@@_args_tl % \end{macrocode} % \end{variable} % % \begin{variable}{\l_@@_args_i_tl, \l_@@_args_ii_tl} % Hold the modified arguments when dealing with default values or % processors. % \begin{macrocode} \tl_new:N \l_@@_args_i_tl \tl_new:N \l_@@_args_ii_tl % \end{macrocode} % \end{variable} % % \begin{variable}{\l_@@_current_arg_int} % The number of the current argument being set up: this is used for creating % the expandable auxiliary functions, and also to indicate if all arguments % are \texttt{m}-type. % \begin{macrocode} \int_new:N \l_@@_current_arg_int % \end{macrocode} % \end{variable} % % \begin{variable}{\l_@@_defaults_bool, \l_@@_defaults_tl} % The boolean indicates whether there are any argument with default % value other than |-NoValue-|; the token list holds the code to % determine these default values in terms of other arguments. % \begin{macrocode} \bool_new:N \l_@@_defaults_bool \tl_new:N \l_@@_defaults_tl % \end{macrocode} % \end{variable} % % \begin{variable}{\l_@@_environment_bool} % Generating environments uses the same mechanism as generating functions. % However, full processing of arguments is always needed for environments, % and so the function-generating code needs to know this. % \begin{macrocode} \bool_new:N \l_@@_environment_bool % \end{macrocode} % \end{variable} % % \begin{variable}{\l_@@_expandable_bool} % Used to indicate if an expandable command is begin generated, as this % affects both the acceptable argument types and how they are implemented. % \begin{macrocode} \bool_new:N \l_@@_expandable_bool % \end{macrocode} % \end{variable} % % \begin{variable}{\l_@@_expandable_aux_name_tl} % Used to create pretty-printing names for the auxiliaries: although the % immediate definition does not vary, the full expansion does and so it % does not count as a constant. % \begin{macrocode} \tl_new:N \l_@@_expandable_aux_name_tl \tl_set:Nn \l_@@_expandable_aux_name_tl { \l_@@_function_tl \c_space_tl ( arg~ \int_use:N \l_@@_current_arg_int ) } % \end{macrocode} % \end{variable} % % \begin{variable}{\g_@@_grabber_int} % Used (in exceptional cases) to get unique names for grabbers used by % expandable commands. % \begin{macrocode} \int_new:N \g_@@_grabber_int % \end{macrocode} % \end{variable} % % \begin{variable}{\l_@@_fn_tl} % For passing the pre-formed name of the auxiliary to be used as the % parsing function. % \begin{macrocode} \tl_new:N \l_@@_fn_tl % \end{macrocode} % \end{variable} % % \begin{variable}{\l_@@_fn_code_tl} % For passing the pre-formed name of the auxiliary that contains the % actual code. % \begin{macrocode} \tl_new:N \l_@@_fn_code_tl % \end{macrocode} % \end{variable} % % \begin{variable}{\l_@@_function_tl} % Holds the control sequence name of the function currently being % defined: used to avoid passing this as an argument and to avoid repeated % use of \cs{cs_to_str:N}. % \begin{macrocode} \tl_new:N \l_@@_function_tl % \end{macrocode} % \end{variable} % % \begin{variable}{\l_@@_grab_expandably_bool} % When defining a non-expandable command, indicates whether the % arguments can all safely be grabbed by expandable grabbers. This is % to support abuses of \pkg{xparse} that use protected functions % inside csname constructions. % \begin{macrocode} \bool_new:N \l_@@_grab_expandably_bool % \end{macrocode} % \end{variable} % % \begin{variable}{\l_@@_last_delimiters_tl} % Holds the delimiters (first tokens) of all optional arguments since % the previous mandatory argument, to warn about cases where it would % be impossible to omit optional arguments completely because the % following mandatory argument has the same delimiter as one of the % optional arguments. % \begin{macrocode} \tl_new:N \l_@@_last_delimiters_tl % \end{macrocode} % \end{variable} % % \begin{variable}{\l_@@_long_bool} % Used to indicate that an argument is long, on a per-argument basis. % \begin{macrocode} \bool_new:N \l_@@_long_bool % \end{macrocode} % \end{variable} % % \begin{variable}{\l_@@_m_args_int} % The number of \texttt{m} arguments: if this is the same as the total % number of arguments, then a short-cut can be taken in the creation of % the grabber code. % \begin{macrocode} \int_new:N \l_@@_m_args_int % \end{macrocode} % \end{variable} % % \begin{variable}{\l_@@_mandatory_args_int} % Holds the total number of mandatory arguments for a function, which is % needed to tell whether further mandatory arguments follow an optional % one. % \begin{macrocode} \int_new:N \l_@@_mandatory_args_int % \end{macrocode} % \end{variable} % % \begin{variable}{\l_@@_prefixed_bool} % When preparing the signature of non-expandable commands, indicates % that the current argument is affected by a processor or by |+| % (namely is long). % \begin{macrocode} \bool_new:N \l_@@_prefixed_bool % \end{macrocode} % \end{variable} % % \begin{variable}{\l_@@_process_all_tl, \l_@@_process_one_tl, \l_@@_process_some_bool} % When preparing the signature, the processors that will be applied to % a given argument are collected in \cs{l_@@_process_one_tl}, while % \cs{l_@@_process_all_tl} contains processors for all arguments. The % boolean indicates whether there are any processors (to bypass the % whole endeavour otherwise). % \begin{macrocode} \tl_new:N \l_@@_process_all_tl \tl_new:N \l_@@_process_one_tl \bool_new:N \l_@@_process_some_bool % \end{macrocode} % \end{variable} % % \begin{variable}{\l_@@_signature_tl} % Used when constructing the signature (code for argument grabbing) to % hold what will become the implementation of the main function. % When arguments are grabbed (at point of use of the command/environment), % it also stores the code for grabbing the remaining arguments. % \begin{macrocode} \tl_new:N \l_@@_signature_tl % \end{macrocode} % \end{variable} % % \begin{variable}{\l_@@_some_long_bool, \l_@@_some_short_bool} % Both of these flags are set while normalizing the argument % specification. To grab arguments expandably, all short arguments % must appear before long arguments, so as soon as the first long % argument is seen (other than \texttt{t}-type, whose long status is % ignored) the \texttt{some_long} flag is set. The % \texttt{some_short} flag is used for expandable commands, to know % whether to define a short auxiliary too. % \begin{macrocode} \bool_new:N \l_@@_some_long_bool \bool_new:N \l_@@_some_short_bool % \end{macrocode} % \end{variable} % % \begin{variable}{\l_@@_tmp_prop, \l_@@_tmpa_tl, \l_@@_tmpb_tl} % \begin{macro}{\@@_tmp:w} % Scratch space. % \begin{macrocode} \prop_new:N \l_@@_tmp_prop \tl_new:N \l_@@_tmpa_tl \tl_new:N \l_@@_tmpb_tl \cs_new_eq:NN \@@_tmp:w ? % \end{macrocode} % \end{macro} % \end{variable} % % \subsection{Declaring commands and environments} % % \begin{macro}{\@@_declare_cmd:Nnn, \@@_declare_expandable_cmd:Nnn} % \begin{macro}[aux]{\@@_declare_cmd_aux:Nnn} % \begin{macro}[int] % {\@@_declare_cmd_internal:Nnn, \@@_declare_cmd_internal:cnx} % The main functions for creating commands set the appropriate flag then % use the same internal code to do the definition. % \begin{macrocode} \cs_new_protected:Npn \@@_declare_cmd:Nnn { \bool_set_false:N \l_@@_expandable_bool \@@_declare_cmd_aux:Nnn } \cs_new_protected:Npn \@@_declare_expandable_cmd:Nnn { \bool_set_true:N \l_@@_expandable_bool \@@_declare_cmd_aux:Nnn } % \end{macrocode} % The first stage is to log information, both for the user in the log and % for programmatic use in a property list of all declared commands. % \begin{macrocode} \cs_new_protected:Npn \@@_declare_cmd_aux:Nnn #1#2 { \cs_if_exist:NTF #1 { \__msg_kernel_info:nnxx { xparse } { redefine-command } { \token_to_str:N #1 } { \tl_to_str:n {#2} } } { \bool_lazy_or:nnT { \cs_if_exist_p:c { \cs_to_str:N #1 ~ code } } { \cs_if_exist_p:c { \cs_to_str:N #1 ~ defaults } } { \__msg_kernel_warning:nnx { xparse } { unsupported-let } { \token_to_str:N #1 } } \__msg_kernel_info:nnxx { xparse } { define-command } { \token_to_str:N #1 } { \tl_to_str:n {#2} } } \bool_set_false:N \l_@@_environment_bool \@@_declare_cmd_internal:Nnn #1 {#2} } % \end{macrocode} % The real business of defining a document command starts with setting up % the appropriate name, then normalizing the argument specification to get rid of % shorthands (this step also counts the number of mandatory arguments). % \begin{macrocode} \cs_new_protected:Npn \@@_declare_cmd_internal:Nnn #1#2#3 { \tl_set:Nx \l_@@_function_tl { \cs_to_str:N #1 } \@@_normalize_arg_spec:n {#2} \exp_args:No \@@_prepare_signature:n \l_@@_arg_spec_tl \@@_declare_cmd_code:Nnn #1 {#2} {#3} \@@_break_point:n {#2} } \cs_generate_variant:Nn \@@_declare_cmd_internal:Nnn { cnx } % \end{macrocode} % \end{macro} % \end{macro} % \end{macro} % % \begin{macro}{\@@_break_point:n} % A marker used to escape from creating a definition if necessary. % \begin{macrocode} \cs_new_eq:NN \@@_break_point:n \use_none:n % \end{macrocode} % \end{macro} % % \begin{macro}{\@@_declare_cmd_code:Nnn} % \begin{macro}[aux] % {\@@_declare_cmd_code_aux:Nnn, \@@_declare_cmd_code_expandable:Nnn} % The appropriate auxiliary is called. % \begin{macrocode} \cs_new_protected:Npn \@@_declare_cmd_code:Nnn { \bool_if:NTF \l_@@_grab_expandably_bool { \@@_declare_cmd_code_expandable:Nnn } { \@@_declare_cmd_code_aux:Nnn } } % \end{macrocode} % Standard functions call \cs{@@_start:nNNnnn}, which receives the % argument specification, an auxiliary used for % grabbing arguments, an auxiliary containing the code, and then the % signature, default arguments, and processors. % \begin{macrocode} \cs_new_protected:Npn \@@_declare_cmd_code_aux:Nnn #1#2#3 { \cs_generate_from_arg_count:cNnn { \l_@@_function_tl \c_space_tl code } \cs_set_protected:Npn \l_@@_current_arg_int {#3} \cs_set_protected_nopar:Npx #1 { \@@_start:nNNnnn { \exp_not:n {#2} } \exp_not:c { \l_@@_function_tl \c_space_tl } \exp_not:c { \l_@@_function_tl \c_space_tl code } { \exp_not:o \l_@@_signature_tl } { \bool_if:NT \l_@@_defaults_bool { \exp_not:o \l_@@_defaults_tl } } { \bool_if:NT \l_@@_process_some_bool { \exp_not:o \l_@@_process_all_tl } } } } % \end{macrocode} % Expandable functions and functions whose arguments can be grabbed % expandably call \cs{@@_start_expandable:nNNNNn}, which receives the % argument specification, four auxiliaries (two for grabbing arguments, one for % the code, and one for default arguments), and finally the signature. % Non-expandable functions that take this branch should nevertheless % be protected, as well as their \texttt{code} function. They will % only be expanded in contexts such as constructing a csname. % The two grabbers (named after the function with one or two spaces) % are needed when there are both short and long arguments; otherwise % the same grabber is included twice in the definition. If all % arguments are long or all are short the (only) grabber is defined % correspondingly to be long/short. Otherwise two grabbers are % defined, one long, one short. % \begin{macrocode} \cs_new_protected:Npn \@@_declare_cmd_code_expandable:Nnn #1#2#3 { \exp_args:Ncc \cs_generate_from_arg_count:NNnn { \l_@@_function_tl \c_space_tl code } { cs_set \bool_if:NF \l_@@_expandable_bool { _protected } :Npn } \l_@@_current_arg_int {#3} \bool_if:NT \l_@@_defaults_bool { \use:x { \cs_generate_from_arg_count:cNnn { \l_@@_function_tl \c_space_tl defaults } \cs_set:Npn \l_@@_current_arg_int { \exp_not:o \l_@@_defaults_tl } } } \bool_if:NTF \l_@@_expandable_bool { \cs_set_nopar:Npx } { \cs_set_protected_nopar:Npx } #1 { \exp_not:N \@@_start_expandable:nNNNNn { \exp_not:n {#2} } \exp_not:c { \l_@@_function_tl \c_space_tl } \exp_not:c { \l_@@_function_tl \c_space_tl \bool_if:NT \l_@@_some_short_bool { \bool_if:NT \l_@@_some_long_bool { \c_space_tl } } } \exp_not:c { \l_@@_function_tl \c_space_tl code } \bool_if:NTF \l_@@_defaults_bool { \exp_not:c { \l_@@_function_tl \c_space_tl defaults } } { ? } { \exp_not:o \l_@@_signature_tl } } \bool_if:NTF \l_@@_some_long_bool { \bool_if:NT \l_@@_some_short_bool { \cs_set_nopar:cpx { \l_@@_function_tl \c_space_tl \c_space_tl } ##1##2 { ##1 {##2} } } \cs_set:cpx } { \cs_set_nopar:cpx } { \l_@@_function_tl \c_space_tl } ##1##2 { ##1 {##2} } } % \end{macrocode} % \end{macro} % \end{macro} % % \begin{macro}{\@@_declare_env:nnnn} % \begin{macro}[int]{\@@_declare_env_internal:nnnn} % The lead-off to creating an environment is much the same as that for % creating a command: issue the appropriate message, store the argument % specification then hand off to an internal function. % \begin{macrocode} \cs_new_protected:Npn \@@_declare_env:nnnn #1#2 { %<*initex> \cs_if_exist:cTF { environment~ #1 } % %<*package> \cs_if_exist:cTF {#1} % { \__msg_kernel_info:nnxx { xparse } { redefine-environment } {#1} { \tl_to_str:n {#2} } } { \__msg_kernel_info:nnxx { xparse } { define-environment } {#1} { \tl_to_str:n {#2} } } \bool_set_false:N \l_@@_expandable_bool \bool_set_true:N \l_@@_environment_bool \@@_declare_env_internal:nnnn {#1} {#2} } % \end{macrocode} % Creating a document environment requires a few more steps than creating % a single command. In order to pass the arguments of the command to the % end of the function, it is necessary to store the grabbed arguments. % To do that, the function used at the end of the environment has to be % redefined to contain the appropriate information. To minimize the amount % of expansion at point of use, the code here is expanded now as well as % when used. % \begin{macrocode} \cs_new_protected:Npn \@@_declare_env_internal:nnnn #1#2#3#4 { \@@_declare_cmd_internal:cnx { environment~ #1 } {#2} { \cs_set_nopar:Npx \exp_not:c { environment~ #1 ~end~aux } { \exp_not:N \exp_not:N \exp_not:c { environment~ #1~end~aux~ } \exp_not:n { \exp_not:o \l_@@_args_tl } } \exp_not:n {#3} } \cs_set_nopar:cpx { environment~ #1 ~end } { \exp_not:c { environment~ #1 ~end~aux } } \cs_generate_from_arg_count:cNnn { environment~ #1 ~end~aux~ } \cs_set:Npn \l_@@_current_arg_int {#4} %<*package> \cs_set_eq:cc {#1} { environment~ #1 } \cs_set_eq:cc { end #1 } { environment~ #1 ~end } % } % \end{macrocode} % \end{macro} % \end{macro} % % \subsection{Structure of \pkg{xparse} commands} % % \begin{macro}{\@@_start:nNNnnn} % \begin{macro}[aux]{\@@_start_aux:nNNnnn} % This sets up a few variables to minimize the boilerplate code % included in all \pkg{xparse}-defined commands. It then runs the % grabbers~|#4|. Again, the argument specification |#1| is only for % diagnostics. The control sequence equal to \cs{scan_stop:} protects % against \texttt{f}-expansion and ensures errors are more reasonable % when an \pkg{xparse} command is placed in a csname. % \begin{macrocode} \cs_new_protected:Npx \@@_start:nNNnnn { \exp_not:c { xparse~function~is~not~expandable } \exp_not:N \@@_start_aux:nNNnnn } \cs_new_protected:Npn \@@_start_aux:nNNnnn #1#2#3#4#5#6 { \tl_clear:N \l_@@_args_tl \tl_set:Nn \l_@@_fn_tl {#2} \tl_set:Nn \l_@@_fn_code_tl {#3} \tl_set:Nn \l_@@_defaults_tl {#5} \tl_set:Nn \l_@@_process_all_tl {#6} #4 \@@_run_code: } % \end{macrocode} % \end{macro} % \end{macro} % % \begin{macro}{\@@_run_code:} % After arguments are grabbed, this function is responsible for % inserting default values, running processors, and finally running % the code. % \begin{macrocode} \cs_new_protected:Npn \@@_run_code: { \tl_if_empty:NF \l_@@_defaults_tl { \@@_defaults: } \tl_if_empty:NF \l_@@_process_all_tl { \@@_args_process: } \exp_after:wN \l_@@_fn_code_tl \l_@@_args_tl } % \end{macrocode} % \end{macro} % % \begin{macro}{\@@_defaults:} % \begin{macro}[aux]{\@@_defaults_def:, \@@_defaults_def:nn, \@@_defaults_def:nnn, \@@_defaults_def_aux:nn} % \begin{macro}[aux]{\@@_defaults_aux:, \@@_defaults_error:w} % First construct \cs{@@_tmp:w} (see below) that will receive % the arguments found so far and determine default values for any % missing argument. Then call it repeatedly until the set of % arguments stabilizes. Since that could lead to an infinite loop we % only call it up to nine times, the maximal number needed for % stabilization if there is a chain of arguments that depend on each % other. If that fails to stabilize raise an error. % \begin{macrocode} \cs_new_protected:Npn \@@_defaults: { \@@_defaults_def: \tl_set_eq:NN \l_@@_args_i_tl \l_@@_args_tl \@@_defaults_aux: \@@_defaults_aux: \@@_defaults_aux: \@@_defaults_aux: \@@_defaults_aux: \@@_defaults_aux: \@@_defaults_aux: \@@_defaults_aux: \@@_defaults_aux: \@@_defaults_error:w \q_recursion_stop \tl_set_eq:NN \l_@@_args_tl \l_@@_args_i_tl } \cs_new_protected:Npn \@@_defaults_aux: { \tl_set:Nx \l_@@_args_ii_tl { \exp_after:wN \@@_tmp:w \l_@@_args_i_tl } \tl_if_eq:NNT \l_@@_args_ii_tl \l_@@_args_i_tl { \use_none_delimit_by_q_recursion_stop:w } \tl_set_eq:NN \l_@@_args_i_tl \l_@@_args_ii_tl } \cs_new_protected:Npn \@@_defaults_error:w \q_recursion_stop { \__msg_kernel_error:nnx { xparse } { loop-in-defaults } { \exp_after:wN \token_to_str:N \l_@@_fn_tl } } % \end{macrocode} % To construct \cs{@@_tmp:w}, first go through the arguments % found and the corresponding defaults, building a token list with % |{#|\meta{arg number}|}| for arguments found in the input (whose % default will not be used) and otherwise % |{|\cs{exp_not:n}\Arg{default}|}| for arguments whose default will % be used. The case of \texttt{E}-type arguments, detected by % \cs{tl_if_head_is_group:nTF}, is special because we may need to % partly use an argument found in the input and partly some default. % This case is delayed until \cs{@@_tmp:w} is called: then we % map through the original argument and its corresponding list of % defaults; for each item (corresponding to one embellishment) if a % value has already been found use it otherwise use the default. % \begin{macrocode} \cs_new_protected:Npn \@@_defaults_def: { \tl_clear:N \l_@@_tmpa_tl \int_zero:N \l_@@_current_arg_int \@@_tl_mapthread_function:NNN \l_@@_args_tl \l_@@_defaults_tl \@@_defaults_def:nn \cs_generate_from_arg_count:NNVo \@@_tmp:w \cs_set:Npn \l_@@_current_arg_int \l_@@_tmpa_tl } \cs_generate_variant:Nn \cs_generate_from_arg_count:NNnn { NNVo } \cs_new_protected:Npn \@@_defaults_def:nn { \int_incr:N \l_@@_current_arg_int \exp_args:NV \@@_defaults_def:nnn \l_@@_current_arg_int } \cs_new_protected:Npn \@@_defaults_def:nnn #1#2#3 { \tl_if_head_is_group:nTF {#3} { \tl_put_right:Nn \l_@@_tmpa_tl { { \exp_args:Nf \@@_tl_mapthread_function:nnN { \tl_item:Nn \l_@@_args_tl {#1} } {#3} \@@_defaults_def_aux:nn } } } { \@@_if_no_value:nTF {#2} { \tl_put_right:Nx \l_@@_tmpa_tl { { \exp_not:N \exp_not:n { \exp_not:o {#3} } } } } { \tl_put_right:Nn \l_@@_tmpa_tl { { \exp_not:n { ## #1 } } } } } } \cs_new:Npn \@@_defaults_def_aux:nn #1#2 { \@@_if_no_value:nTF {#1} { { \exp_not:n {#2} } } { { \exp_not:n {#1} } } } % \end{macrocode} % \end{macro} % \end{macro} % \end{macro} % % \begin{macro}{\@@_args_process:} % \begin{macro}[aux]{\@@_args_process_loop:nn, \@@_args_process_aux:n, \@@_args_process_aux:nn} % Loop through arguments (stored in \cs{l_@@_args_tl}) and the % corresponding processors (in \cs{l_@@_process_all_tl}) % simultaneously, apply all processors for each argument and store the % result back into \cs{l_@@_args_tl}. % \begin{macrocode} \cs_new_protected:Npn \@@_args_process: { \tl_clear:N \l_@@_args_ii_tl \@@_tl_mapthread_function:NNN \l_@@_args_tl \l_@@_process_all_tl \@@_args_process_loop:nn \tl_set_eq:NN \l_@@_args_tl \l_@@_args_ii_tl } \cs_new_protected:Npn \@@_args_process_loop:nn #1#2 { \tl_set:Nn \ProcessedArgument {#1} \@@_if_no_value:nF {#1} { \tl_map_function:nN {#2} \@@_args_process_aux:n } \tl_put_right:No \l_@@_args_ii_tl { \exp_after:wN { \ProcessedArgument } } } \cs_new_protected:Npn \@@_args_process_aux:n { \exp_args:No \@@_args_process_aux:nn { \ProcessedArgument } } \cs_new_protected:Npn \@@_args_process_aux:nn #1#2 { #2 {#1} } % \end{macrocode} % \end{macro} % \end{macro} % % \begin{macro}[EXP]{\@@_start_expandable:nNNNNn} % This is called for all expandable commands. |#6| is the signature, % responsible for grabbing arguments. |#5| is used to determine % default values (or is |?| if there are none). |#4| is the code to run. % |#2|~and~|#3| are functions (named after the command) that grab a single % argument in the input stream (|#3|~is~short). The argument specification |#1| is % only used by diagnostic functions. % \begin{macrocode} \cs_new:Npn \@@_start_expandable:nNNNNn #1#2#3#4#5#6 { #6 \@@_end_expandable:NNw #5 #4 \q_@@ #2#3 } % \end{macrocode} % \end{macro} % % \begin{macro}[EXP]{\@@_end_expandable:NNw} % \begin{macro}[EXP,aux]{\@@_end_expandable_aux:w} % \begin{macro}[EXP,aux]{\@@_end_expandable_aux:nNNNN} % \begin{macro}[EXP,aux]{\@@_end_expandable_defaults:nnnNNn} % \begin{macro}[EXP,aux]{\@@_end_expandable_defaults:nnw} % \begin{macro}[EXP,aux]{\@@_end_expandable_defaults:nw} % \begin{macro}[EXP,aux]{\@@_end_expandable_defaults_E:nnw} % Followed by a function |#1| to determine default values (or |?| if % there are no defaults), the code % |#2|, arguments that have been grabbed, then \cs{q_@@} and two generic % grabbers. The idea to find default values is similar to the % non-expandable case but we cannot define an auxiliary function, so % at every step in the loop we need to go through all arguments % searching for which ones started out as |-NoValue-| and replacing % these by the newly computed values. In fact we need to keep track % of three versions of all arguments: the original version, the % previous version with default values, and the currently built % version (first argument of \cs{@@_end_expandable_defaults:nnnNNn}). % \begin{macrocode} \cs_new:Npn \@@_end_expandable:NNw #1#2 { \@@_end_expandable_aux:w #1#2 \prg_do_nothing: } \cs_new:Npn \@@_end_expandable_aux:w #1#2#3 \q_@@ { \exp_args:No \@@_end_expandable_aux:nNNNN {#3} #1 #2 } \cs_new:Npn \@@_end_expandable_aux:nNNNN #1#2#3#4#5 { \token_if_eq_charcode:NNT ? #2 { \exp_after:wN \use_iv:nnnn } \@@_end_expandable_defaults:nnnNNn {#1} { } {#1} #2#3 { } { } { } { } { } { } { } { } { } { } { \__msg_kernel_expandable_error:nnn { xparse } { loop-in-defaults } {#4} \use_iv:nnnn } \q_stop } \cs_new:Npn \@@_end_expandable_defaults:nnnNNn #1#2#3#4#5#6 { #6 \str_if_eq:nnTF {#1} {#2} { \use_i_delimit_by_q_stop:nw { #5 #1 } } { \exp_args:No \@@_tl_mapthread_function:nnN { #4 #1 } {#3} \@@_end_expandable_defaults:nnw \@@_end_expandable_defaults:nnnNNn { } {#1} {#3} #4 #5 } } \cs_new:Npn \@@_end_expandable_defaults:nnw #1#2 { \tl_if_head_is_group:nTF {#1} { \@@_end_expandable_defaults_E:nnw { } #1 \q_nil \q_mark #2 \q_nil } { \@@_if_no_value:nTF {#2} { \exp_args:No \@@_end_expandable_defaults:nw {#1} } { \@@_end_expandable_defaults:nw {#2} } } } \cs_new:Npn \@@_end_expandable_defaults_E:nnw #1#2#3 \q_mark #4 { \quark_if_nil:nTF {#2} { \@@_end_expandable_defaults:nw {#1} } { \@@_if_no_value:nTF {#4} { \@@_end_expandable_defaults_E:nnw { #1 {#2} } } { \@@_end_expandable_defaults_E:nnw { #1 {#4} } } #3 \q_mark } } \cs_new:Npn \@@_end_expandable_defaults:nw #1#2 \@@_end_expandable_defaults:nnnNNn #3 { #2 \@@_end_expandable_defaults:nnnNNn { #3 {#1} } } % \end{macrocode} % \end{macro} % \end{macro} % \end{macro} % \end{macro} % \end{macro} % \end{macro} % \end{macro} % % \subsection{Normalizing the argument specifications} % % The goal here is to expand aliases and check that the argument % specification is valid before the main parsing run. If it is not % valid the entire set up is abandoned to avoid any strange internal % errors. A function is provided for each argument type that will grab % any extra arguments and call the loop function. % % The first thing that is done in the loop is to check that the various % argument types have the correct number of data items associated with % them. The opportunity is also taken to make sure that where a single % token is required, one has actually been supplied. % % The second is that processors and the marker~|+| for long arguments % must be followed by arguments. % % The third is to check for forbidden types for expandable commands, % namely \texttt{G}/\texttt{v} always, and \texttt{l}/\texttt{u} after % optional arguments (\pkg{xparse} may have inserted braces due to a % failed search for an optional argument). % % The fourth is that an optional argument should not be followed by a % mandatory argument with the same delimiter, as otherwise the optional % argument could never be omitted. % % The fifth is to keep track in \cs{l_@@_some_long_bool} and % \cs{l_@@_some_short_bool} of whether the command has some long/short % arguments. % % The sixth is to keep track in \cs{l_@@_grab_expandably_bool} of % whether all arguments are \texttt{m}/\texttt{l}/\texttt{u} type and % short arguments appear before long ones, in which case they can be % grabbed expandably just as safely as they could be grabbed expandably. % Regardless of that, arguments of expandable commands will be grabbed % expandably and arguments of environments will not (because the list of % arguments built by non-expandable grabbing is used to pass them to the % end-environment code). % % The last is to count mandatory arguments, used later to detect which % optional arguments are trailing. % % \begin{macro}{\@@_normalize_arg_spec:n} % \begin{macro}{\@@_normalize_arg_spec_loop:n} % Loop through the argument specification, calling an auxiliary % specific to each argument type. If any argument is unknown stop the % definition. After the loop, if there are more than % $9$ arguments, stop. Additionally, expandable commands may not end % with an optional argument; this case is detected by using the fact % that \cs{l_@@_last_delimiters_tl} is cleared by every mandatory % argument and filled by every optional argument. % \begin{macrocode} \cs_new_protected:Npn \@@_normalize_arg_spec:n #1 { \int_zero:N \l_@@_mandatory_args_int \int_zero:N \l_@@_current_arg_int \tl_clear:N \l_@@_last_delimiters_tl \tl_clear:N \l_@@_arg_spec_tl \bool_set_true:N \l_@@_grab_expandably_bool \bool_set_false:N \l_@@_long_bool \bool_set_false:N \l_@@_some_long_bool \bool_set_false:N \l_@@_some_short_bool \@@_normalize_arg_spec_loop:n #1 \q_recursion_tail \q_recursion_tail \q_recursion_tail \q_recursion_stop \int_compare:nNnT \l_@@_current_arg_int > 9 { \__msg_kernel_error:nnxx { xparse } { too-many-arguments } { \iow_char:N \\ \l_@@_function_tl } { \tl_to_str:n {#1} } \@@_bad_def:wn } \bool_if:NT \l_@@_expandable_bool { \tl_if_empty:NF \l_@@_last_delimiters_tl { \__msg_kernel_error:nnxx { xparse } { expandable-ending-optional } { \iow_char:N \\ \l_@@_function_tl } { \tl_to_str:n {#1} } \@@_bad_def:wn } } \bool_if:NT \l_@@_expandable_bool { \bool_set_true:N \l_@@_grab_expandably_bool } \bool_if:NT \l_@@_environment_bool { \bool_set_false:N \l_@@_grab_expandably_bool } } \cs_new_protected:Npn \@@_normalize_arg_spec_loop:n #1 { \quark_if_recursion_tail_stop:n {#1} \int_incr:N \l_@@_current_arg_int \cs_if_exist_use:cF { @@_normalize_type_ \tl_to_str:n {#1} :w } { \__msg_kernel_error:nnxx { xparse } { unknown-argument-type } { \iow_char:N \\ \l_@@_function_tl } { \tl_to_str:n {#1} } \@@_bad_def:wn } } % \end{macrocode} % \end{macro} % \end{macro} % % \begin{macro} % { % \@@_normalize_type_d:w, % \@@_normalize_type_e:w, % \@@_normalize_type_g:w, % \@@_normalize_type_o:w, % \@@_normalize_type_O:w, % \@@_normalize_type_r:w, % \@@_normalize_type_s:w, % } % These argument types are aliases of more general ones, for example % with the default argument |-NoValue-|. To easily insert that marker % expanded in the definitions we call \cs{@@_tmp:w} with the argument % |-NoValue-|. For argument types that need additional data, check % that that data is present (not \cs{q_recursion_tail}) before % proceeding. % \begin{macrocode} \cs_set_protected:Npn \@@_tmp:w #1 { \cs_new_protected:Npn \@@_normalize_type_d:w ##1##2 { \quark_if_recursion_tail_stop_do:nn {##2} { \@@_bad_arg_spec:wn } \@@_normalize_type_D:w {##1} {##2} {#1} } \cs_new_protected:Npn \@@_normalize_type_e:w ##1 { \quark_if_recursion_tail_stop_do:nn {##1} { \@@_bad_arg_spec:wn } \@@_normalize_type_E:w {##1} { } } \cs_new_protected:Npn \@@_normalize_type_g:w { \@@_normalize_type_G:w {#1} } \cs_new_protected:Npn \@@_normalize_type_o:w { \@@_normalize_type_D:w [ ] {#1} } \cs_new_protected:Npn \@@_normalize_type_O:w { \@@_normalize_type_D:w [ ] } \cs_new_protected:Npn \@@_normalize_type_r:w ##1##2 { \quark_if_recursion_tail_stop_do:nn {##2} { \@@_bad_arg_spec:wn } \@@_normalize_type_R:w {##1} {##2} {#1} } \cs_new_protected:Npn \@@_normalize_type_s:w { \@@_normalize_type_t:w * } } \exp_args:No \@@_tmp:w { \c_@@_no_value_tl } % \end{macrocode} % \end{macro} % % \begin{macro} % { % \@@_normalize_type_>:w, % \@@_normalize_type_+:w, % } % Check that these prefixes have arguments, namely that the next token % is not \cs{q_recursion_tail}, and remember to leave it after the % looping macro. Processors are forbidden in expandable commands. % If all is good, store the prefix in the cleaned up % \cs{l_@@_arg_spec_tl}, and decrement the argument number as prefixes % do not correspond to arguments. % \begin{macrocode} \cs_new_protected:cpn { @@_normalize_type_>:w } #1#2 { \quark_if_recursion_tail_stop_do:nn {#2} { \@@_bad_arg_spec:wn } \bool_if:NT \l_@@_expandable_bool { \__msg_kernel_error:nnxx { xparse } { processor-in-expandable } { \iow_char:N \\ \l_@@_function_tl } { \tl_to_str:n {#1} } \@@_bad_def:wn } \tl_put_right:Nn \l_@@_arg_spec_tl { > {#1} } \int_decr:N \l_@@_current_arg_int \bool_set_false:N \l_@@_grab_expandably_bool \@@_normalize_arg_spec_loop:n {#2} } \cs_new_protected:cpn { @@_normalize_type_+:w } #1 { \quark_if_recursion_tail_stop_do:nn {#1} { \@@_bad_arg_spec:wn } \tl_put_right:Nn \l_@@_arg_spec_tl { + } \bool_set_true:N \l_@@_long_bool \int_decr:N \l_@@_current_arg_int \@@_normalize_arg_spec_loop:n {#1} } % \end{macrocode} % \end{macro} % % \begin{macro} % { % \@@_normalize_type_D:w, % \@@_normalize_type_E:w, % \@@_normalize_type_G:w, % \@@_normalize_type_t:w, % } % \begin{macro}[aux]{\@@_normalize_E_unique_check:w} % Optional argument types. Check that all required data is present % (and consists of single tokens if applicable) and check for % forbidden types for expandable commands. For \texttt{E}-type % require that there is at least one embellishment, that each one is a % single token, and that there aren't more optional arguments than % embellishments. Then store the data in \cs{l_@@_arg_spec_tl}, and % for later checks store in \cs{l_@@_last_delimiters_tl} the tokens % whose presence determines whether there is an optional argument (for % braces store |{}|, seen later as an empty delimiter). % \begin{macrocode} \cs_new_protected:Npn \@@_normalize_type_D:w #1#2#3 { \@@_single_token_check:n {#1} \@@_single_token_check:n {#2} \quark_if_recursion_tail_stop_do:nn {#3} { \@@_bad_arg_spec:wn } \@@_add_arg_spec:n { D #1 #2 {#3} } \tl_put_right:Nn \l_@@_last_delimiters_tl {#1} \bool_set_false:N \l_@@_grab_expandably_bool \@@_normalize_arg_spec_loop:n } \cs_new_protected:Npn \@@_normalize_type_E:w #1#2 { \quark_if_recursion_tail_stop_do:nn {#2} { \@@_bad_arg_spec:wn } \tl_if_blank:nT {#1} { \@@_bad_arg_spec:wn } \tl_map_function:nN {#1} \@@_single_token_check:n \@@_normalize_E_unique_check:w #1 \q_nil \q_stop \int_compare:nNnT { \tl_count:n {#2} } > { \tl_count:n {#1} } { \@@_bad_arg_spec:wn } \@@_add_arg_spec:n { E {#1} {#2} } \tl_put_right:Nn \l_@@_last_delimiters_tl {#1} \bool_set_false:N \l_@@_grab_expandably_bool \@@_normalize_arg_spec_loop:n } \cs_new_protected:Npn \@@_normalize_E_unique_check:w #1#2 \q_stop { \quark_if_nil:NF #1 { \tl_if_in:nnT {#2} {#1} { \@@_bad_arg_spec:wn } \@@_normalize_E_unique_check:w #2 \q_stop } } \cs_new_protected:Npn \@@_normalize_type_G:w #1 { \quark_if_recursion_tail_stop_do:nn {#1} { \@@_bad_arg_spec:wn } \@@_normalize_check_gv:N G \@@_add_arg_spec:n { G {#1} } \tl_put_right:Nn \l_@@_last_delimiters_tl { { } } \@@_normalize_arg_spec_loop:n } \cs_new_protected:Npn \@@_normalize_type_t:w #1 { \@@_single_token_check:n {#1} \quark_if_recursion_tail_stop_do:Nn #1 { \@@_bad_arg_spec:wn } \tl_put_right:Nn \l_@@_arg_spec_tl { t #1 } \tl_put_right:Nn \l_@@_last_delimiters_tl {#1} \bool_set_false:N \l_@@_grab_expandably_bool \bool_set_false:N \l_@@_long_bool \@@_normalize_arg_spec_loop:n } % \end{macrocode} % \end{macro} % \end{macro} % % \begin{macro} % { % \@@_normalize_type_l:w, % \@@_normalize_type_m:w, % \@@_normalize_type_R:w, % \@@_normalize_type_u:w % \@@_normalize_type_v:w % } % Mandatory arguments. First check the required data is present, % consists of single tokens where applicable, and that the argument % type is allowed for expandable commands if applicable. For the % \texttt{m} and \texttt{R} argument types check that they do not % follow some optional argument with that delimiter as otherwise the % optional argument could not be omitted. Then save data in % \cs{l_@@_arg_spec_tl}, count the mandatory argument, and empty the % list of last delimiters. % \begin{macrocode} \cs_new_protected:Npn \@@_normalize_type_l:w { \@@_normalize_check_lu:N l \@@_add_arg_spec:n { l } \int_incr:N \l_@@_mandatory_args_int \tl_clear:N \l_@@_last_delimiters_tl \@@_normalize_arg_spec_loop:n } \cs_new_protected:Npn \@@_normalize_type_m:w { \@@_delimiter_check:nnn { } { m } { \iow_char:N \{ } \@@_add_arg_spec:n { m } \int_incr:N \l_@@_mandatory_args_int \tl_clear:N \l_@@_last_delimiters_tl \@@_normalize_arg_spec_loop:n } \cs_new_protected:Npn \@@_normalize_type_R:w #1#2#3 { \@@_single_token_check:n {#1} \@@_single_token_check:n {#2} \quark_if_recursion_tail_stop_do:nn {#3} { \@@_bad_arg_spec:wn } \@@_delimiter_check:nnn {#1} { R/r } { \tl_to_str:n {#1} } \@@_add_arg_spec:n { R #1 #2 {#3} } \int_incr:N \l_@@_mandatory_args_int \tl_clear:N \l_@@_last_delimiters_tl \bool_set_false:N \l_@@_grab_expandably_bool \@@_normalize_arg_spec_loop:n } \cs_new_protected:Npn \@@_normalize_type_u:w #1 { \quark_if_recursion_tail_stop_do:nn {#1} { \@@_bad_arg_spec:wn } \@@_normalize_check_lu:N u \@@_add_arg_spec:n { u {#1} } \int_incr:N \l_@@_mandatory_args_int \tl_clear:N \l_@@_last_delimiters_tl \@@_normalize_arg_spec_loop:n } \cs_new_protected:Npn \@@_normalize_type_v:w { \@@_normalize_check_gv:N v \@@_add_arg_spec:n { v } \int_incr:N \l_@@_mandatory_args_int \tl_clear:N \l_@@_last_delimiters_tl \@@_normalize_arg_spec_loop:n } % \end{macrocode} % \end{macro} % % \begin{macro}{\@@_single_token_check:n} % A spin-out function to check that what should be single tokens really % are single tokens. % \begin{macrocode} \cs_new_protected:Npn \@@_single_token_check:n #1 { \exp_args:Nx \tl_if_single_token:nF { \tl_trim_spaces:n {#1} } { \__msg_kernel_error:nnxx { xparse } { not-single-token } { \iow_char:N \\ \l_@@_function_tl } { \tl_to_str:n {#1} } \@@_bad_def:wn } } % \end{macrocode} % \end{macro} % % \begin{macro}{\@@_normalize_check_gv:N, \@@_normalize_check_lu:N} % Called for arguments that are always forbidden, or forbidden after % an optional argument, for expandable commands. % \begin{macrocode} \cs_new_protected:Npn \@@_normalize_check_gv:N #1 { \bool_if:NT \l_@@_expandable_bool { \__msg_kernel_error:nnxx { xparse } { invalid-expandable-argument-type } { \iow_char:N \\ \l_@@_function_tl } { \tl_to_str:n {#1} } \@@_bad_def:wn } \bool_set_false:N \l_@@_grab_expandably_bool } \cs_new_protected:Npn \@@_normalize_check_lu:N #1 { \bool_if:NT \l_@@_expandable_bool { \tl_if_empty:NF \l_@@_last_delimiters_tl { \__msg_kernel_error:nnxx { xparse } { invalid-after-optional-expandably } { \iow_char:N \\ \l_@@_function_tl } { \tl_to_str:n {#1} } \@@_bad_def:wn } } } % \end{macrocode} % \end{macro} % % \begin{macro}{\@@_delimiter_check:nnn} % Called for \texttt{m} and \texttt{R} arguments. Checks that the % leading token does not coincide with the token denoting the presence % of a previous optional argument. Instead of dealing with braces for % the \texttt{m}-type we use an empty delimiter to denote that case. % \begin{macrocode} \cs_new_protected:Npn \@@_delimiter_check:nnn #1#2#3 { \tl_map_inline:Nn \l_@@_last_delimiters_tl { \tl_if_eq:nnT {##1} {#1} { \__msg_kernel_warning:nnxx { xparse } { optional-mandatory } {#2} {#3} } } } % \end{macrocode} % \end{macro} % % \begin{macro}{\@@_bad_arg_spec:wn, \@@_bad_def:wn} % If the argument specification is wrong, this provides an escape from % the entire definition process. % \begin{macrocode} \cs_new_protected:Npn \@@_bad_arg_spec:wn #1 \@@_break_point:n #2 { \__msg_kernel_error:nnxx { xparse } { bad-arg-spec } { \iow_char:N \\ \l_@@_function_tl } { \tl_to_str:n {#2} } } \cs_new_protected:Npn \@@_bad_def:wn #1 \@@_break_point:n #2 { } % \end{macrocode} % \end{macro} % % \begin{macro}{\@@_add_arg_spec:n} % When adding an argument to the argument specification, set the % \texttt{some_long} or \texttt{some_short} booleans as appropriate % and clear the boolean keeping track of whether the argument is long. % Before that, test for a short argument following some long % arguments: this is forbidden for expandable commands and prevents % grabbing arguments expandably. % \begin{macrocode} \cs_new_protected:Npn \@@_add_arg_spec:n #1 { \bool_if:NF \l_@@_long_bool { \bool_if:NT \l_@@_some_long_bool { \bool_if:NT \l_@@_expandable_bool { \__msg_kernel_error:nnx { xparse } { inconsistent-long } { \iow_char:N \\ \l_@@_function_tl } \@@_bad_def:wn } \bool_set_false:N \l_@@_grab_expandably_bool } } \bool_if:NTF \l_@@_long_bool { \bool_set_true:N \l_@@_some_long_bool } { \bool_set_true:N \l_@@_some_short_bool } \bool_set_false:N \l_@@_long_bool \tl_put_right:Nn \l_@@_arg_spec_tl {#1} } % \end{macrocode} % \end{macro} % % \subsection{Preparing the signature: general mechanism} % % \begin{macro}{\@@_prepare_signature:n} % \begin{macro}{\@@_prepare_signature:N} % \begin{macro}{\@@_prepare_signature_bypass:N} % Actually creating the signature uses the same loop approach as counting % up mandatory arguments. There are first a number of variables which need % to be set to track what is going on. Many of these variables are unused % when defining expandable commands. % \begin{macrocode} \cs_new_protected:Npn \@@_prepare_signature:n #1 { \int_zero:N \l_@@_current_arg_int \bool_set_false:N \l_@@_long_bool \int_zero:N \l_@@_m_args_int \bool_set_false:N \l_@@_defaults_bool \tl_clear:N \l_@@_defaults_tl \tl_clear:N \l_@@_process_all_tl \tl_clear:N \l_@@_process_one_tl \bool_set_false:N \l_@@_process_some_bool \tl_clear:N \l_@@_signature_tl \@@_prepare_signature:N #1 \q_recursion_tail \q_recursion_stop \bool_if:NF \l_@@_expandable_bool { \@@_flush_m_args: } } % \end{macrocode} % The main looping function does not take an argument, but carries out the % reset on the processor boolean. This is split off from the rest of the % process so that when actually setting up processors the flag-reset can % be bypassed. % % For each known argument type there is an appropriate function to actually % do the addition to the signature. These are separate for expandable and % standard functions, as the approaches are different. Of course, if the type % is not known at all then a fall-back is needed. % \begin{macrocode} \cs_new_protected:Npn \@@_prepare_signature:N { \bool_set_false:N \l_@@_prefixed_bool \@@_prepare_signature_bypass:N } \cs_new_protected:Npn \@@_prepare_signature_bypass:N #1 { \quark_if_recursion_tail_stop:N #1 \int_incr:N \l_@@_current_arg_int \use:c { @@_add \bool_if:NT \l_@@_grab_expandably_bool { _expandable } _type_ \token_to_str:N #1 :w } } % \end{macrocode} % \end{macro} % \end{macro} % \end{macro} % % \subsection{Setting up a standard signature} % % Each argument-adding function appends to the signature a grabber (and % for some types, the delimiters or default value), except the one for % \texttt{m} arguments. These are collected and added to the signature % all at once by \cs{@@_flush_m_args:}, called for every other argument % type. All of the functions then call the loop function % \cs{@@_prepare_signature:N}. Default values of arguments are % collected by \cs{@@_add_default:n} rather than being stored with the % argument. % % \begin{macro}{\@@_add_type_+:w} % Making the next argument long means setting the flag and knocking one back % off the total argument count. The \texttt{m} arguments are recorded here as % this has to be done for every case where there is then a long argument. % \begin{macrocode} \cs_new_protected:cpn { @@_add_type_+:w } { \@@_flush_m_args: \bool_set_true:N \l_@@_long_bool \bool_set_true:N \l_@@_prefixed_bool \int_decr:N \l_@@_current_arg_int \@@_prepare_signature_bypass:N } % \end{macrocode} % \end{macro} % % \begin{macro}{\@@_add_type_>:w} % When a processor is found, the processor code is stored. It will be % used by \cs{@@_args_process:} once arguments are all found. Here, % the loop calls \cs{@@_prepare_signature_bypass:N} rather than % \cs{@@_prepare_signature:N} so that the flag is not reset. % \begin{macrocode} \cs_new_protected:cpn { @@_add_type_>:w } #1 { \@@_flush_m_args: \bool_set_true:N \l_@@_prefixed_bool \bool_set_true:N \l_@@_process_some_bool \int_decr:N \l_@@_current_arg_int \tl_put_left:Nn \l_@@_process_one_tl { {#1} } \@@_prepare_signature_bypass:N } % \end{macrocode} % \end{macro} % % \begin{macro}{\@@_add_type_D:w} % \begin{macrocode} \cs_new_protected:Npn \@@_add_type_D:w #1#2#3 { \@@_flush_m_args: \@@_add_default:n {#3} \@@_add_grabber_optional:N D \tl_put_right:Nn \l_@@_signature_tl { #1 #2 } \@@_prepare_signature:N } % \end{macrocode} % \end{macro} % % \begin{macro}{\@@_add_type_E:w} % The \texttt{E}-type argument needs a special handling of default % values. % \begin{macrocode} \cs_new_protected:Npn \@@_add_type_E:w #1#2 { \@@_flush_m_args: \@@_add_default_E:nn {#1} {#2} \@@_add_grabber_optional:N E \tl_put_right:Nn \l_@@_signature_tl { {#1} } \@@_prepare_signature:N } % \end{macrocode} % \end{macro} % % \begin{macro}{\@@_add_type_G:w} % For the \texttt{G} type, the grabber and the default are added to the % signature. % \begin{macrocode} \cs_new_protected:Npn \@@_add_type_G:w #1 { \@@_flush_m_args: \@@_add_default:n {#1} \@@_add_grabber_optional:N G \@@_prepare_signature:N } % \end{macrocode} % \end{macro} % % \begin{macro}{\@@_add_type_l:w} % Finding \texttt{l} arguments is very simple: there is nothing to do % other than add the grabber. % \begin{macrocode} \cs_new_protected:Npn \@@_add_type_l:w { \@@_flush_m_args: \@@_add_default: \@@_add_grabber_mandatory:N l \@@_prepare_signature:N } % \end{macrocode} % \end{macro} % % \begin{macro}{\@@_add_type_m:w} % The \texttt{m} type is special as short arguments which are not % post-processed are simply counted at this stage. Thus there is a check % to see if either of these cases apply. If so, a one-argument grabber % is added to the signature. On the other hand, if a standard short % argument is required it is simply counted at this stage, to be % added later using \cs{@@_flush_m_args:}. % \begin{macrocode} \cs_new_protected:Npn \@@_add_type_m:w { \@@_add_default: \bool_if:NTF \l_@@_prefixed_bool { \@@_add_grabber_mandatory:N m } { \int_incr:N \l_@@_m_args_int } \@@_prepare_signature:N } % \end{macrocode} % \end{macro} % % \begin{macro}{\@@_add_type_R:w} % The \texttt{R}-type argument is very similar to the \texttt{D}-type. % \begin{macrocode} \cs_new_protected:Npn \@@_add_type_R:w #1#2#3 { \@@_flush_m_args: \@@_add_default:n {#3} \@@_add_grabber_mandatory:N R \tl_put_right:Nn \l_@@_signature_tl { #1 #2 } \@@_prepare_signature:N } % \end{macrocode} % \end{macro} % % \begin{macro}{\@@_add_type_t:w} % Setting up a \texttt{t} argument means collecting one token for the test, % and adding it along with the grabber to the signature. % \begin{macrocode} \cs_new_protected:Npn \@@_add_type_t:w #1 { \@@_flush_m_args: \@@_add_default: \@@_add_grabber_optional:N t \tl_put_right:Nn \l_@@_signature_tl {#1} \@@_prepare_signature:N } % \end{macrocode} % \end{macro} % % \begin{macro}{\@@_add_type_u:w} % At the set up stage, the \texttt{u} type argument is identical to the % \texttt{G} type except for the name of the grabber function. % \begin{macrocode} \cs_new_protected:Npn \@@_add_type_u:w #1 { \@@_flush_m_args: \@@_add_default: \@@_add_grabber_mandatory:N u \tl_put_right:Nn \l_@@_signature_tl { {#1} } \@@_prepare_signature:N } % \end{macrocode} % \end{macro} % % \begin{macro}{\@@_add_type_v:w} % At this stage, the \texttt{v} argument is identical to \texttt{l} % except that since the grabber may fail to read a verbatim argument % we need a default value. % \begin{macrocode} \cs_new_protected:Npn \@@_add_type_v:w { \@@_flush_m_args: \exp_args:No \@@_add_default:n \c_@@_no_value_tl \@@_add_grabber_mandatory:N v \@@_prepare_signature:N } % \end{macrocode} % \end{macro} % % \begin{macro}{\@@_flush_m_args:} % As \texttt{m} arguments are simply counted, there is a need to add % them to the token register in a block. As this function can only % be called if something other than \texttt{m} turns up, the flag can % be switched here. The total number of mandatory arguments which % remain to be added to % the signature is also decreased by the appropriate amount. % \begin{macrocode} \cs_new_protected:Npn \@@_flush_m_args: { \int_compare:nNnT \l_@@_m_args_int > 0 { \tl_put_right:Nx \l_@@_signature_tl { \exp_not:c { @@_grab_m_ \int_use:N \l_@@_m_args_int :w } } \int_sub:Nn \l_@@_mandatory_args_int { \l_@@_m_args_int } \tl_put_right:Nx \l_@@_process_all_tl { \prg_replicate:nn { \l_@@_m_args_int } { { } } } } \int_zero:N \l_@@_m_args_int } % \end{macrocode} % \end{macro} % % \begin{macro}{\@@_add_grabber_mandatory:N} % \begin{macro}{\@@_add_grabber_optional:N} % To keep the various checks needed in one place, adding the grabber to % the signature is done here. For mandatory arguments, the only question % is whether to add a long grabber. For optional arguments, there is % also a check to see if any mandatory arguments are still to be added. % This is used to determine whether to skip spaces or not where % searching for the argument. % \begin{macrocode} \cs_new_protected:Npn \@@_add_grabber_mandatory:N #1 { \tl_put_right:Nx \l_@@_signature_tl { \exp_not:c { @@_grab_ #1 \bool_if:NT \l_@@_long_bool { _long } :w } } \bool_set_false:N \l_@@_long_bool \tl_put_right:Nx \l_@@_process_all_tl { { \exp_not:o \l_@@_process_one_tl } } \tl_clear:N \l_@@_process_one_tl \int_decr:N \l_@@_mandatory_args_int } \cs_new_protected:Npn \@@_add_grabber_optional:N #1 { \tl_put_right:Nx \l_@@_signature_tl { \exp_not:c { @@_grab_ #1 \bool_if:NT \l_@@_long_bool { _long } \int_compare:nNnF \l_@@_mandatory_args_int > 0 { _trailing } :w } } \bool_set_false:N \l_@@_long_bool \tl_put_right:Nx \l_@@_process_all_tl { { \exp_not:o \l_@@_process_one_tl } } \tl_clear:N \l_@@_process_one_tl } % \end{macrocode} % \end{macro} % \end{macro} % % \begin{macro}{\@@_add_default:n, \@@_add_default:, \@@_add_default_E:nn} % \begin{macro}[aux]{\@@_add_default_E_aux:n} % Store the default value of an argument, or rather code that gives % that default value (it may involve other arguments). This is % \cs{c_@@_no_value_tl} for arguments with no actual default or with % default |-NoValue-|; \cs{prg_do_nothing:} followed by a default % value for most others, and a token list of braced arguments for % \texttt{E}-type arguments. For \texttt{E}-type arguments, pad the % defaults |#2| with some |{-NoValue-}| until there are as many as % embellishments~|#1|. These functions are also used when defining % expandable commands. % \begin{macrocode} \cs_new_protected:Npn \@@_add_default:n #1 { \@@_if_no_value:nTF {#1} { \@@_add_default: } { \bool_set_true:N \l_@@_defaults_bool \tl_put_right:Nn \l_@@_defaults_tl { { \prg_do_nothing: #1 } } } } \cs_new_protected:Npn \@@_add_default: { \tl_put_right:Nn \l_@@_defaults_tl { \c_@@_no_value_tl } } \cs_new_protected:Npn \@@_add_default_E:nn #1#2 { \bool_set_true:N \l_@@_defaults_bool \tl_put_right:Nx \l_@@_defaults_tl { { \tl_map_function:nN {#2} \@@_add_default_E_aux:n \prg_replicate:nn { \tl_count:n {#1} - \tl_count:n {#2} } { { \c_@@_no_value_tl } } } } } \cs_new:Npn \@@_add_default_E_aux:n #1 { \exp_not:n { {#1} } } % \end{macrocode} % \end{macro} % \end{macro} % % \subsection{Setting up expandable types} % % The approach here is not dissimilar to that for standard types, but fewer types % are supported. There is % also a need to define the per-function auxiliaries: this is done here, while % the general grabbers are dealt with later. % % \begin{macro}{\@@_add_expandable_type_+:w} % We have already checked that short arguments are before long % arguments, so \cs{l_@@_long_bool} only changes from \texttt{false} % to \texttt{true} once (and there is no need to reset it after each % argument). Also knock back the argument count because |+| is not an % argument. Continue the loop. % \begin{macrocode} \cs_new_protected:cpn { @@_add_expandable_type_+:w } { \bool_set_true:N \l_@@_long_bool \int_decr:N \l_@@_current_arg_int \@@_prepare_signature:N } % \end{macrocode} % \end{macro} % % \begin{macro}{\@@_add_expandable_type_D:w} % \begin{macro}{\@@_add_expandable_type_D_aux:NNNn} % \begin{macro}{\@@_add_expandable_type_D_aux:NNN} % \begin{macro}{\@@_add_expandable_type_D_aux:NN} % The set up for \texttt{D}-type arguments involves constructing a % rather complex auxiliary which is used % repeatedly when grabbing. There is an auxiliary here so that the % \texttt{R}-type can share code readily: |#1| is |D| or~|R|. % The |_aux:NN| auxiliary is needed if the two delimiting tokens are % identical: in contrast to the non-expandable route, the grabber here % has to act differently for this case. % \begin{macrocode} \cs_new_protected:Npn \@@_add_expandable_type_D:w { \@@_add_expandable_type_D_aux:NNNn D } \cs_new_protected:Npn \@@_add_expandable_type_D_aux:NNNn #1#2#3#4 { \@@_add_default:n {#4} \tl_if_eq:nnTF {#2} {#3} { \@@_add_expandable_type_D_aux:NN #1 #2 } { \@@_add_expandable_type_D_aux:NNN #1 #2 #3 } \@@_prepare_signature:N } \cs_new_protected:Npn \@@_add_expandable_type_D_aux:NNN #1#2#3 { \bool_if:NTF \l_@@_long_bool { \cs_set:cpx } { \cs_set_nopar:cpx } { \l_@@_expandable_aux_name_tl } ##1 ##2 #2 ##3 \q_@@ ##4 #3 { ##1 {##2} {##3} {##4} } \@@_add_expandable_grabber:nn {#1} { \exp_not:c { \l_@@_expandable_aux_name_tl } \exp_not:n { #2 #3 } } } \cs_new_protected:Npn \@@_add_expandable_type_D_aux:NN #1#2 { \bool_if:NTF \l_@@_long_bool { \cs_set:cpx } { \cs_set_nopar:cpx } { \l_@@_expandable_aux_name_tl } ##1 #2 ##2 #2 { ##1 {##2} } \@@_add_expandable_grabber:nn { #1_alt } { \exp_not:c { \l_@@_expandable_aux_name_tl } \exp_not:n {#2} } } % \end{macrocode} % \end{macro} % \end{macro} % \end{macro} % \end{macro} % % \begin{macro}{\@@_add_expandable_type_E:w} % \begin{macro}[aux]{\@@_add_expandable_type_E_aux:n} % For each embellishment, use \cs{@@_get_grabber:NN} to obtain an % auxiliary delimited by that token and store a pair constituted of % the auxiliary and the token in \cs{l_@@_tmpb_tl}, before appending % the whole set of these pairs to the signature, and an equal number % of |-NoValue-| markers (regardless of the default values of % arguments). % \begin{macrocode} \cs_new_protected:Npn \@@_add_expandable_type_E:w #1#2 { \@@_add_default_E:nn {#1} {#2} \tl_clear:N \l_@@_tmpb_tl \tl_map_function:nN {#1} \@@_add_expandable_type_E_aux:n \@@_add_expandable_grabber:nn { E \bool_if:NT \l_@@_long_bool { _long } } { { \exp_not:o \l_@@_tmpb_tl } { \prg_replicate:nn { \tl_count:n {#1} } { { \c_@@_no_value_tl } } } } \@@_prepare_signature:N } \cs_new_protected:Npn \@@_add_expandable_type_E_aux:n #1 { \@@_get_grabber:NN #1 \l_@@_tmpa_tl \tl_put_right:Nx \l_@@_tmpb_tl { \exp_not:o \l_@@_tmpa_tl \exp_not:N #1 } } % \end{macrocode} % \end{macro} % \end{macro} % % \begin{macro}{\@@_add_expandable_type_l:w} % Reuse type \texttt{u}, thanks to the fact that \TeX{} macros whose % parameter text ends with |#| in fact end up being delimited by an % open brace. % \begin{macrocode} \cs_new_protected:Npn \@@_add_expandable_type_l:w { \@@_add_expandable_type_u:w ## } % \end{macrocode} % \end{macro} % % \begin{macro}{\@@_add_expandable_type_m:w} % Unlike the standard case, when working expandably each argument is always % grabbed separately. % \begin{macrocode} \cs_new_protected:Npn \@@_add_expandable_type_m:w { \@@_add_default: \@@_add_expandable_grabber:nn { m \bool_if:NT \l_@@_long_bool { _long } } { } \@@_prepare_signature:N } % \end{macrocode} % \end{macro} % % \begin{macro}{\@@_add_expandable_type_R:w} % The \texttt{R}-type is very similar to the \texttt{D}-type % argument, and so the same internals are used. % \begin{macrocode} \cs_new_protected:Npn \@@_add_expandable_type_R:w { \@@_add_expandable_type_D_aux:NNNn R } % \end{macrocode} % \end{macro} % % \begin{macro}{\@@_add_expandable_type_t:w} % An auxiliary delimited by |#1| is built now. It will be used to % test for the presence of that token. % \begin{macrocode} \cs_new_protected:Npn \@@_add_expandable_type_t:w #1 { \@@_add_default: \@@_get_grabber:NN #1 \l_@@_tmpa_tl \@@_add_expandable_grabber:nn { t } { \exp_not:o \l_@@_tmpa_tl \exp_not:N #1 } \@@_prepare_signature:N } % \end{macrocode} % \end{macro} % % \begin{macro}{\@@_add_expandable_type_u:w} % Define an auxiliary that will be used directly in the signature. It % grabs one argument delimited by |#1| and places it before \cs{q_@@}. % \begin{macrocode} \cs_new_protected:Npn \@@_add_expandable_type_u:w #1 { \@@_add_default: \bool_if:NTF \l_@@_long_bool { \cs_set:cpn } { \cs_set_nopar:cpn } { \l_@@_expandable_aux_name_tl } ##1 \q_@@ ##2 ##3 ##4 #1 { ##1 {##4} \q_@@ ##2 ##3 } \@@_add_expandable_grabber:nn { u } { \exp_not:c { \l_@@_expandable_aux_name_tl } } \@@_prepare_signature:N } % \end{macrocode} % \end{macro} % % \begin{macro}{\@@_add_expandable_grabber:nn} % This is called for all arguments to place the right grabber in the % signature. % \begin{macrocode} \cs_new_protected:Npn \@@_add_expandable_grabber:nn #1#2 { \tl_put_right:Nx \l_@@_signature_tl { \exp_not:c { @@_expandable_grab_ #1 :w } #2 } } % \end{macrocode} % \end{macro} % % \begin{macro}{\@@_get_grabber:NN} % \begin{macro}[aux]{\@@_get_grabber_auxi:NN} % \begin{macro}[aux]{\@@_get_grabber_auxii:NN} % Given a token |#1|, defines an expandable function delimited by that % token and stores it in the token list~|#2|. The function is named % after the token, unless that function name is already taken by some % other grabber (this can happen in the rare case where delimiters % with different category codes are used in the same document): in % that case use a global counter to get a unique name. Since the % grabbers are not named after \pkg{xparse} commands they should not % be used to get material from the input stream. % \begin{macrocode} \cs_new_protected:Npn \@@_get_grabber:NN #1#2 { \cs_set:Npn \@@_tmp:w ##1 #1 {##1} \exp_args:Nc \@@_get_grabber_auxi:NN { @@_grabber_ \token_to_str:N #1 :w } #2 } \cs_new_protected:Npn \@@_get_grabber_auxi:NN #1#2 { \cs_if_eq:NNTF \@@_tmp:w #1 { \tl_set:Nn #2 {#1} } { \cs_if_exist:NTF #1 { \int_gincr:N \g_@@_grabber_int \exp_args:Nc \@@_get_grabber_auxi:NN { @@_grabber_ - \int_use:N \g_@@_grabber_int :w } #2 } { \@@_get_grabber_auxii:NN #1 #2 } } } \cs_new_protected:Npn \@@_get_grabber_auxii:NN #1#2 { \cs_set_eq:NN #1 \@@_tmp:w \tl_set:Nn #2 {#1} } % \end{macrocode} % \end{macro} % \end{macro} % \end{macro} % % \subsection{Grabbing arguments} % % All of the grabbers follow the same basic pattern. The initial % function stores in \cs{l_@@_signature_tl} the code to grab further % arguments, defines (the function in) \cs{l_@@_fn_tl} that will grab % the argument, and calls it. % % Defining \cs{l_@@_fn_tl} means determining whether to use % \cs{cs_set:Npn} or \cs{cs_set_nopar:Npn}, and for optional arguments % whether to skip spaces. Once the argument is found, \cs{l_@@_fn_tl} % calls \cs{@@_add_arg:n}, responsible for calling processors and % grabbing further arguments. % % \begin{macro}{\@@_grab_D:w} % \begin{macro}{\@@_grab_D_long:w} % \begin{macro}{\@@_grab_D_trailing:w} % \begin{macro}{\@@_grab_D_long_trailing:w} % The generic delimited argument grabber. The auxiliary function does % a peek test before calling \cs{@@_grab_D_call:Nw}, so that the % optional nature of the argument works as expected. % \begin{macrocode} \cs_new_protected:Npn \@@_grab_D:w #1#2#3 \@@_run_code: { \@@_grab_D_aux:NNnNn #1 #2 {#3} \cs_set_protected_nopar:Npn { _ignore_spaces } } \cs_new_protected:Npn \@@_grab_D_long:w #1#2#3 \@@_run_code: { \@@_grab_D_aux:NNnNn #1 #2 {#3} \cs_set_protected:Npn { _ignore_spaces } } \cs_new_protected:Npn \@@_grab_D_trailing:w #1#2#3 \@@_run_code: { \@@_grab_D_aux:NNnNn #1 #2 {#3} \cs_set_protected_nopar:Npn { } } \cs_new_protected:Npn \@@_grab_D_long_trailing:w #1#2#3 \@@_run_code: { \@@_grab_D_aux:NNnNn #1 #2 {#3} \cs_set_protected:Npn { } } % \end{macrocode} % \begin{macro}[aux]{\@@_grab_D_aux:NNnNn} % \begin{macro}[aux]{\@@_grab_D_aux:NNnN} % This is a bit complicated. The idea is that, in order to check for % nested optional argument tokens (\texttt{[[...]]} and so on) the % argument needs to be grabbed without removing any braces at all. If % this is not done, then cases like |[{[}]| fail. So after testing for % an optional argument, it is collected piece-wise. Inserting a quark % prevents loss of braces, and there is then a test to see if there are % nested delimiters to handle. % \begin{macrocode} \cs_new_protected:Npn \@@_grab_D_aux:NNnNn #1#2#3#4#5 { \@@_grab_D_aux:NNnN #1#2 {#3} #4 \use:c { peek_meaning_remove #5 :NTF } #1 { \@@_grab_D_call:Nw #1 } { \@@_add_arg:o \c_@@_no_value_tl } } % \end{macrocode} % Inside the \enquote{standard} grabber, there is a test to see if the % grabbed argument is entirely enclosed by braces. There are a couple of % extra factors to allow for: the argument might be entirely empty, and % spaces at the start and end of the input must be retained around a brace % group. Also notice that a \emph{blank} argument might still contain % spaces. % \begin{macrocode} \cs_new_protected:Npn \@@_grab_D_aux:NNnN #1#2#3#4 { \tl_set:Nn \l_@@_signature_tl {#3} \exp_after:wN #4 \l_@@_fn_tl ##1 #2 { \tl_if_in:nnTF {##1} {#1} { \@@_grab_D_nested:NNnN #1 #2 {##1} #4 } { \tl_if_blank:oTF { \use_none:n ##1 } { \@@_add_arg:o { \use_none:n ##1 } } { \str_if_eq_x:nnTF { \exp_not:o { \use_none:n ##1 } } { { \exp_not:o { \use_ii:nnn ##1 \q_nil } } } { \@@_add_arg:o { \use_ii:nn ##1 } } { \@@_add_arg:o { \use_none:n ##1 } } } } } } % \end{macrocode} % \end{macro} % \end{macro} % \end{macro} % \end{macro} % \end{macro} % \end{macro} % \begin{macro}[aux]{\@@_grab_D_nested:NNnN} % \begin{macro}[aux]{\@@_grab_D_nested:w} % \begin{macro}{\l_@@_nesting_a_tl} % \begin{macro}{\l_@@_nesting_b_tl} % \begin{macro}{\q_@@} % Catching nested optional arguments means more work. The aim here is % to collect up each pair of optional tokens without \TeX{} helping out, % and without counting anything. The code above will already have % removed the leading opening token and a closing token, but the % wrong one. The aim is then to work through the material grabbed % so far and divide it up on each opening token, grabbing a closing % token to match (thus working in pairs). Once there are no opening % tokens, then there is a second check to see if there are any % opening tokens in the second part of the argument (for things % like |[][]|). Once everything has been found, the entire collected % material is added to the output as a single argument. The only tricky part % here is ensuring that any grabbing function that might run away is named % after the function currently being parsed and not after \pkg{xparse}. That % leads to some rather complex nesting! There is also a need to prevent the % loss of any braces, hence the insertion and removal of quarks along the % way. % \begin{macrocode} \tl_new:N \l_@@_nesting_a_tl \tl_new:N \l_@@_nesting_b_tl \quark_new:N \q_@@ \cs_new_protected:Npn \@@_grab_D_nested:NNnN #1#2#3#4 { \tl_clear:N \l_@@_nesting_a_tl \tl_clear:N \l_@@_nesting_b_tl \exp_after:wN #4 \l_@@_fn_tl ##1 #1 ##2 \q_@@ ##3 #2 { \tl_put_right:No \l_@@_nesting_a_tl { \use_none:n ##1 #1 } \tl_put_right:No \l_@@_nesting_b_tl { \use_i:nn #2 ##3 } \tl_if_in:nnTF {##2} {#1} { \l_@@_fn_tl \q_nil ##2 \q_@@ \ERROR } { \tl_put_right:Nx \l_@@_nesting_a_tl { \@@_grab_D_nested:w \q_nil ##2 \q_stop } \tl_if_in:NnTF \l_@@_nesting_b_tl {#1} { \tl_set_eq:NN \l_@@_tmpa_tl \l_@@_nesting_b_tl \tl_clear:N \l_@@_nesting_b_tl \exp_after:wN \l_@@_fn_tl \exp_after:wN \q_nil \l_@@_tmpa_tl \q_nil \q_@@ \ERROR } { \tl_put_right:No \l_@@_nesting_a_tl \l_@@_nesting_b_tl \@@_add_arg:V \l_@@_nesting_a_tl } } } \l_@@_fn_tl #3 \q_nil \q_@@ \ERROR } \cs_new:Npn \@@_grab_D_nested:w #1 \q_nil \q_stop { \exp_not:o { \use_none:n #1 } } % \end{macrocode} % \end{macro} % \end{macro} % \end{macro} % \end{macro} % \end{macro} % \begin{macro}{\@@_grab_D_call:Nw} % For \texttt{D} and \texttt{R}-type arguments, to avoid losing any % braces, a token needs to be inserted before the argument to be grabbed. % If the argument runs away because the closing token is missing then this % inserted token shows up in the terminal. Ideally, |#1| would therefore be % used directly, but that is no good as it will mess up the rest of the % grabber. Instead, a copy of |#1| with an altered category code is used, % as this will look right in the terminal but will not mess up the grabber. % The only issue then is that the category code of |#1| is unknown. So there % is a quick test to ensure that the inserted token can never be matched by % the grabber. (This assumes that the open and close delimiters are not the % same character with different category codes, but that really should not % happen in any sensible document-level syntax.) % \begin{macrocode} \cs_set_protected_nopar:Npn \@@_grab_D_call:Nw #1 { \token_if_eq_catcode:NNTF + #1 { \exp_after:wN \exp_after:wN \exp_after:wN \l_@@_fn_tl \char_generate:nn { `#1 } { 11 } } { \exp_after:wN \l_@@_fn_tl \token_to_str:N #1 } } % \end{macrocode} % \end{macro} % % \begin{macro} % { % \@@_grab_E:w, \@@_grab_E_long:w, % \@@_grab_E_trailing:w, \@@_grab_E_long_trailing:w % } % \begin{macro}[aux]{\@@_grab_E:nnNn} % \begin{macro}[aux]{\@@_grab_E_loop:nnN} % \begin{macro}[aux]{\@@_grab_E_finalise:} % Everything here needs to point to a loop. % \begin{macrocode} \cs_new_protected:Npn \@@_grab_E:w #1#2 \@@_run_code: { \@@_grab_E:nnNn {#1} {#2} \cs_set_protected_nopar:Npn { _ignore_spaces } } \cs_new_protected:Npn \@@_grab_E_long:w #1#2 \@@_run_code: { \@@_grab_E:nnNn {#1} {#2} \cs_set_protected:Npn { _ignore_spaces } } \cs_new_protected:Npn \@@_grab_E_trailing:w #1#2 \@@_run_code: { \@@_grab_E:nnNn {#1} {#2} \cs_set_protected_nopar:Npn { } } \cs_new_protected:Npn \@@_grab_E_long_trailing:w #1#2 \@@_run_code: { \@@_grab_E:nnNn {#1} {#2} \cs_set_protected:Npn { } } % \end{macrocode} % A loop is needed here to allow a random ordering of keys. These are % searched for one at a time, with any not found needing to be tracked: % they can appear later. The grabbed values are held in a property list % which is then turned into an ordered list to be passed back to the user. % \begin{macrocode} \cs_new_protected:Npn \@@_grab_E:nnNn #1#2#3#4 { \exp_after:wN #3 \l_@@_fn_tl ##1##2##3 { \prop_put:Nnn \l_@@_tmp_prop {##1} {##3} \@@_grab_E_loop:nnN {#4} { } ##2 \q_recursion_stop } \prop_clear:N \l_@@_tmp_prop \tl_set:Nn \l_@@_signature_tl {#2} \cs_set_protected:Npn \@@_grab_E_finalise: { \tl_clear:N \l_@@_tmpa_tl \tl_map_inline:nn {#1} { \prop_get:NnNF \l_@@_tmp_prop {####1} \l_@@_tmpb_tl { \tl_set_eq:NN \l_@@_tmpb_tl \c_@@_no_value_tl } \tl_set:Nx \l_@@_tmpa_tl { \exp_not:V \l_@@_tmpa_tl { \exp_not:V \l_@@_tmpb_tl } } } \@@_add_arg:V \l_@@_tmpa_tl } \@@_grab_E_loop:nnN {#4} { } #1 \q_recursion_tail \q_recursion_stop } \cs_new_protected:Npn \@@_grab_E_loop:nnN #1#2#3#4 \q_recursion_stop { \cs_if_eq:NNTF #3 \q_recursion_tail { \@@_grab_E_finalise: } { \use:c { peek_meaning_remove #1 :NTF } #3 { \l_@@_fn_tl #3 {#2#4} } { \@@_grab_E_loop:nnN {#1} {#2#3} #4 \q_recursion_stop } } } \cs_new_protected:Npn \@@_grab_E_finalise: { } % \end{macrocode} % \end{macro} % \end{macro} % \end{macro} % \end{macro} % % \begin{macro}{\@@_grab_G:w} % \begin{macro}{\@@_grab_G_long:w} % \begin{macro}{\@@_grab_G_trailing:w} % \begin{macro}{\@@_grab_G_long_trailing:w} % \begin{macro}[aux]{\@@_grab_G_aux:nNn} % Optional groups are checked by meaning, so that the same code will % work with, for example, Con\TeX{}t-like input. % \begin{macrocode} \cs_new_protected:Npn \@@_grab_G:w #1 \@@_run_code: { \@@_grab_G_aux:nNn {#1} \cs_set_protected_nopar:Npn { _ignore_spaces } } \cs_new_protected:Npn \@@_grab_G_long:w #1 \@@_run_code: { \@@_grab_G_aux:nNn {#1} \cs_set_protected:Npn { _ignore_spaces } } \cs_new_protected:Npn \@@_grab_G_trailing:w #1 \@@_run_code: { \@@_grab_G_aux:nNn {#1} \cs_set_protected_nopar:Npn { } } \cs_new_protected:Npn \@@_grab_G_long_trailing:w #1 \@@_run_code: { \@@_grab_G_aux:nNn {#1} \cs_set_protected:Npn { } } \cs_new_protected:Npn \@@_grab_G_aux:nNn #1#2#3 { \tl_set:Nn \l_@@_signature_tl {#1} \exp_after:wN #2 \l_@@_fn_tl ##1 { \@@_add_arg:n {##1} } \use:c { peek_meaning #3 :NTF } \c_group_begin_token { \l_@@_fn_tl } { \@@_add_arg:o \c_@@_no_value_tl } } % \end{macrocode} % \end{macro} % \end{macro} % \end{macro} % \end{macro} % \end{macro} % % \begin{macro}{\@@_grab_l:w} % \begin{macro}{\@@_grab_l_long:w} % \begin{macro}[aux]{\@@_grab_l_aux:nN} % Argument grabbers for mandatory \TeX{} arguments are pretty simple. % \begin{macrocode} \cs_new_protected:Npn \@@_grab_l:w #1 \@@_run_code: { \@@_grab_l_aux:nN {#1} \cs_set_protected_nopar:Npn } \cs_new_protected:Npn \@@_grab_l_long:w #1 \@@_run_code: { \@@_grab_l_aux:nN {#1} \cs_set_protected:Npn } \cs_new_protected:Npn \@@_grab_l_aux:nN #1#2 { \tl_set:Nn \l_@@_signature_tl {#1} \exp_after:wN #2 \l_@@_fn_tl ##1## { \@@_add_arg:n {##1} } \l_@@_fn_tl } % \end{macrocode} % \end{macro} % \end{macro} % \end{macro} % % \begin{macro}{\@@_grab_m:w} % \begin{macro}{\@@_grab_m_long:w} % Collecting a single mandatory argument is quite easy. % \begin{macrocode} \cs_new_protected:Npn \@@_grab_m:w #1 \@@_run_code: { \tl_set:Nn \l_@@_signature_tl {#1} \exp_after:wN \cs_set_protected_nopar:Npn \l_@@_fn_tl ##1 { \@@_add_arg:n {##1} } \l_@@_fn_tl } \cs_new_protected:Npn \@@_grab_m_long:w #1 \@@_run_code: { \tl_set:Nn \l_@@_signature_tl {#1} \exp_after:wN \cs_set_protected:Npn \l_@@_fn_tl ##1 { \@@_add_arg:n {##1} } \l_@@_fn_tl } % \end{macrocode} % \end{macro} % \end{macro} % % \begin{macro}{\@@_grab_m_1:w} % \begin{macro}{\@@_grab_m_2:w} % \begin{macro}{\@@_grab_m_3:w} % \begin{macro}{\@@_grab_m_4:w} % \begin{macro}{\@@_grab_m_5:w} % \begin{macro}{\@@_grab_m_6:w} % \begin{macro}{\@@_grab_m_7:w} % \begin{macro}{\@@_grab_m_8:w} % \begin{macro}{\@@_grab_m_9:w} % \begin{macro}[aux]{\@@_grab_m_aux:Nnnnnnnnn} % Grabbing 1--8 mandatory arguments is done by giving 8--1 known % arguments to a 9-argument function that stores them in % \cs{l_@@_args_tl}. For simplicity, grabbing 9 mandatory arguments % is done by grabbing 5 then 4 arguments. % \begin{macrocode} \cs_new_protected_nopar:Npn \@@_grab_m_aux:Nnnnnnnnn #1#2#3#4#5#6#7#8#9 { \tl_put_right:No \l_@@_args_tl { #1 {#2} {#3} {#4} {#5} {#6} {#7} {#8} {#9} } \l_@@_signature_tl \@@_run_code: } \cs_new_protected:cpn { @@_grab_m_1:w } #1 \@@_run_code: { \tl_set:Nn \l_@@_signature_tl {#1} \exp_after:wN \cs_set_eq:NN \l_@@_fn_tl \@@_grab_m_aux:Nnnnnnnnn \l_@@_fn_tl \use_none:nnnnnnn { } { } { } { } { } { } { } } \cs_new_protected:cpn { @@_grab_m_2:w } #1 \@@_run_code: { \tl_set:Nn \l_@@_signature_tl {#1} \exp_after:wN \cs_set_eq:NN \l_@@_fn_tl \@@_grab_m_aux:Nnnnnnnnn \l_@@_fn_tl \use_none:nnnnnn { } { } { } { } { } { } } \cs_new_protected:cpn { @@_grab_m_3:w } #1 \@@_run_code: { \tl_set:Nn \l_@@_signature_tl {#1} \exp_after:wN \cs_set_eq:NN \l_@@_fn_tl \@@_grab_m_aux:Nnnnnnnnn \l_@@_fn_tl \use_none:nnnnn { } { } { } { } { } } \cs_new_protected:cpn { @@_grab_m_4:w } #1 \@@_run_code: { \tl_set:Nn \l_@@_signature_tl {#1} \exp_after:wN \cs_set_eq:NN \l_@@_fn_tl \@@_grab_m_aux:Nnnnnnnnn \l_@@_fn_tl \use_none:nnnn { } { } { } { } } \cs_new_protected:cpn { @@_grab_m_5:w } #1 \@@_run_code: { \tl_set:Nn \l_@@_signature_tl {#1} \exp_after:wN \cs_set_eq:NN \l_@@_fn_tl \@@_grab_m_aux:Nnnnnnnnn \l_@@_fn_tl \use_none:nnn { } { } { } } \cs_new_protected:cpn { @@_grab_m_6:w } #1 \@@_run_code: { \tl_set:Nn \l_@@_signature_tl {#1} \exp_after:wN \cs_set_eq:NN \l_@@_fn_tl \@@_grab_m_aux:Nnnnnnnnn \l_@@_fn_tl \use_none:nn { } { } } \cs_new_protected:cpn { @@_grab_m_7:w } #1 \@@_run_code: { \tl_set:Nn \l_@@_signature_tl {#1} \exp_after:wN \cs_set_eq:NN \l_@@_fn_tl \@@_grab_m_aux:Nnnnnnnnn \l_@@_fn_tl \use_none:n { } } \cs_new_protected:cpn { @@_grab_m_8:w } #1 \@@_run_code: { \tl_set:Nn \l_@@_signature_tl {#1} \exp_after:wN \cs_set_eq:NN \l_@@_fn_tl \@@_grab_m_aux:Nnnnnnnnn \l_@@_fn_tl \prg_do_nothing: } \cs_new_protected:cpx { @@_grab_m_9:w } { \exp_not:c { @@_grab_m_5:w } \exp_not:c { @@_grab_m_4:w } } % \end{macrocode} % \end{macro} % \end{macro} % \end{macro} % \end{macro} % \end{macro} % \end{macro} % \end{macro} % \end{macro} % \end{macro} % \end{macro} % % \begin{macro}{\@@_grab_R:w, \@@_grab_R_long:w} % \begin{macro}[aux]{\@@_grab_R_aux:NNnN} % The grabber for \texttt{R}-type arguments is basically the same as % that for \texttt{D}-type ones, but always skips spaces (as it is mandatory) % and has a hard-coded error message. % \begin{macrocode} \cs_new_protected:Npn \@@_grab_R:w #1#2#3 \@@_run_code: { \@@_grab_R_aux:NNnN #1 #2 {#3} \cs_set_protected_nopar:Npn } \cs_new_protected:Npn \@@_grab_R_long:w #1#2#3 \@@_run_code: { \@@_grab_R_aux:NNnN #1 #2 {#3} \cs_set_protected:Npn } \cs_new_protected:Npn \@@_grab_R_aux:NNnN #1#2#3#4 { \@@_grab_D_aux:NNnN #1 #2 {#3} #4 \peek_meaning_remove_ignore_spaces:NTF #1 { \@@_grab_D_call:Nw #1 } { \__msg_kernel_error:nnxx { xparse } { missing-required } { \exp_after:wN \token_to_str:N \l_@@_fn_tl } { \token_to_str:N #1 } \@@_add_arg:o \c_@@_no_value_tl } } % \end{macrocode} % \end{macro} % \end{macro} % % \begin{macro}{\@@_grab_t:w} % \begin{macro}{\@@_grab_t_long:w} % \begin{macro}{\@@_grab_t_trailing:w} % \begin{macro}{\@@_grab_t_long_trailing:w} % \begin{macro}[aux]{\@@_grab_t_aux:NNw} % Dealing with a token is quite easy. Check the match, remove the % token if needed and add a flag to the output. % \begin{macrocode} \cs_new_protected:Npn \@@_grab_t:w { \@@_grab_t_aux:NNw \peek_meaning_remove_ignore_spaces:NTF } \cs_new_eq:NN \@@_grab_t_long:w \@@_grab_t:w \cs_new_protected:Npn \@@_grab_t_trailing:w { \@@_grab_t_aux:NNw \peek_meaning_remove:NTF } \cs_new_eq:NN \@@_grab_t_long_trailing:w \@@_grab_t_trailing:w \cs_new_protected:Npn \@@_grab_t_aux:NNw #1#2#3 \@@_run_code: { \tl_set:Nn \l_@@_signature_tl {#3} \exp_after:wN \cs_set_protected:Npn \l_@@_fn_tl { #1 #2 { \@@_add_arg:n { \BooleanTrue } } { \@@_add_arg:n { \BooleanFalse } } } \l_@@_fn_tl } % \end{macrocode} % \end{macro} % \end{macro} % \end{macro} % \end{macro} % \end{macro} % % \begin{macro}{\@@_grab_u:w} % \begin{macro}{\@@_grab_u_long:w} % \begin{macro}[aux]{\@@_grab_u_aux:nnN} % Grabbing up to a list of tokens is quite easy: define the grabber, % and then collect. % \begin{macrocode} \cs_new_protected:Npn \@@_grab_u:w #1#2 \@@_run_code: { \@@_grab_u_aux:nnN {#1} {#2} \cs_set_protected_nopar:Npn } \cs_new_protected:Npn \@@_grab_u_long:w #1#2 \@@_run_code: { \@@_grab_u_aux:nnN {#1} {#2} \cs_set_protected:Npn } \cs_new_protected:Npn \@@_grab_u_aux:nnN #1#2#3 { \tl_set:Nn \l_@@_signature_tl {#2} \exp_after:wN #3 \l_@@_fn_tl ##1 #1 { \@@_add_arg:n {##1} } \l_@@_fn_tl } % \end{macrocode} % \end{macro} % \end{macro} % \end{macro} % % \begin{macro}{\@@_grab_v:w} % \begin{macro}{\@@_grab_v_long:w} % \begin{macro}{\@@_grab_v_aux:w} % \begin{macro}{\@@_grab_v_group_end:} % \begin{variable}{\l_@@_v_arg_tl} % The opening delimiter is the first non-space token, and is never % read verbatim. This is required by consistency with the case where % the preceding argument was optional and absent: then \TeX{} has % already read and tokenized that token when looking for the optional % argument. The first thing is thus to check is that this delimiter % is a character, and to distinguish the case of a left brace (in that % case, \cs{group_align_safe_end:} is needed to compensate for the % begin-group character that was just seen). Then set verbatim % catcodes with \cs{@@_grab_v_aux_catcodes:}. % % The group keep catcode changes local, and % \cs{group_align_safe_begin/end:} allow to use a character % with category code~$4$ (normally |&|) as the delimiter. % It is ended by \cs{@@_grab_v_group_end:}, which smuggles % the collected argument out of the group. % \begin{macrocode} \tl_new:N \l_@@_v_arg_tl \cs_new_protected:Npn \@@_grab_v:w { \bool_set_false:N \l_@@_long_bool \@@_grab_v_aux:w } \cs_new_protected:Npn \@@_grab_v_long:w { \bool_set_true:N \l_@@_long_bool \@@_grab_v_aux:w } \cs_new_protected:Npn \@@_grab_v_aux:w #1 \@@_run_code: { \tl_set:Nn \l_@@_signature_tl {#1} \group_begin: \group_align_safe_begin: \tex_escapechar:D = 92 \scan_stop: \tl_clear:N \l_@@_v_arg_tl \peek_meaning_remove_ignore_spaces:NTF \c_group_begin_token { \group_align_safe_end: \@@_grab_v_bgroup: } { \peek_N_type:TF { \@@_grab_v_aux_test:N } { \@@_grab_v_aux_abort:n { } } } } \cs_new_protected:Npn \@@_grab_v_group_end: { \group_align_safe_end: \exp_args:NNNo \group_end: \tl_set:Nn \l_@@_v_arg_tl { \l_@@_v_arg_tl } } % \end{macrocode} % \end{variable} % \end{macro} % \end{macro} % \end{macro} % \end{macro} % % \begin{macro}{\@@_grab_v_aux_test:N} % \begin{macro} % { % \@@_grab_v_aux_loop:N, % \@@_grab_v_aux_loop:NN, % \@@_grab_v_aux_loop_end: % } % Check that the opening delimiter is a character, setup category codes, % then start reading tokens one by one, keeping the delimiter as an argument. % If the verbatim was not nested, we will be grabbing one character % at each step. Unfortunately, it can happen that what follows the % verbatim argument is already tokenized. Thus, we check at each step % that the next token is indeed a \enquote{nice} % character, \emph{i.e.}, is not a character with % category code $1$ (begin-group), $2$ (end-group) % or $6$ (macro parameter), nor the space character, % with category code~$10$ and character code~$32$, % nor a control sequence. % The partially built argument is stored in \cs{l_@@_v_arg_tl}. % If we ever meet a token which we cannot grab (non-N-type), % or which is not a character according to % \cs{@@_grab_v_token_if_char:NTF}, then we bail out with % \cs{@@_grab_v_aux_abort:n}. Otherwise, we stop at the first % character matching the delimiter. % \begin{macrocode} \cs_new_protected:Npn \@@_grab_v_aux_test:N #1 { \@@_grab_v_token_if_char:NTF #1 { \@@_grab_v_aux_put:N #1 \@@_grab_v_aux_catcodes: \@@_grab_v_aux_loop:N #1 } { \@@_grab_v_aux_abort:n {#1} #1 } } \cs_new_protected:Npn \@@_grab_v_aux_loop:N #1 { \peek_N_type:TF { \@@_grab_v_aux_loop:NN #1 } { \@@_grab_v_aux_abort:n { } } } \cs_new_protected:Npn \@@_grab_v_aux_loop:NN #1#2 { \@@_grab_v_token_if_char:NTF #2 { \token_if_eq_charcode:NNTF #1 #2 { \@@_grab_v_aux_loop_end: } { \@@_grab_v_aux_put:N #2 \@@_grab_v_aux_loop:N #1 } } { \@@_grab_v_aux_abort:n {#2} #2 } } \cs_new_protected:Npn \@@_grab_v_aux_loop_end: { \@@_grab_v_group_end: \@@_add_arg:x { \tl_tail:N \l_@@_v_arg_tl } } % \end{macrocode} % \end{macro} % \end{macro} % % \begin{macro}{\@@_grab_v_bgroup:} % \begin{macro}{\@@_grab_v_bgroup_loop:} % \begin{macro}{\@@_grab_v_bgroup_loop:N} % \begin{variable}{\l_@@_v_nesting_int} % If the opening delimiter is a left brace, we keep track of % how many left and right braces were encountered so far in % \cs{l_@@_v_nesting_int} (the methods used for optional % arguments cannot apply here), and stop as soon as it reaches~$0$. % % Some care was needed when removing the opening delimiter, which % has already been assigned category code~$1$: using % \cs{peek_meaning_remove:NTF} in the \cs{@@_grab_v_aux:w} % function would break within alignments. Instead, we first % convert that token to a string, and remove the result as a % normal undelimited argument. % \begin{macrocode} \int_new:N \l_@@_v_nesting_int \cs_new_protected:Npx \@@_grab_v_bgroup: { \exp_not:N \@@_grab_v_aux_catcodes: \exp_not:n { \int_set:Nn \l_@@_v_nesting_int { 1 } } \exp_not:N \@@_grab_v_aux_put:N \iow_char:N \{ \exp_not:N \@@_grab_v_bgroup_loop: } \cs_new_protected:Npn \@@_grab_v_bgroup_loop: { \peek_N_type:TF { \@@_grab_v_bgroup_loop:N } { \@@_grab_v_aux_abort:n { } } } \cs_new_protected:Npn \@@_grab_v_bgroup_loop:N #1 { \@@_grab_v_token_if_char:NTF #1 { \token_if_eq_charcode:NNTF \c_group_end_token #1 { \int_decr:N \l_@@_v_nesting_int \int_compare:nNnTF \l_@@_v_nesting_int > 0 { \@@_grab_v_aux_put:N #1 \@@_grab_v_bgroup_loop: } { \@@_grab_v_aux_loop_end: } } { \token_if_eq_charcode:NNT \c_group_begin_token #1 { \int_incr:N \l_@@_v_nesting_int } \@@_grab_v_aux_put:N #1 \@@_grab_v_bgroup_loop: } } { \@@_grab_v_aux_abort:n {#1} #1 } } % \end{macrocode} % \end{variable} % \end{macro} % \end{macro} % \end{macro} % % \begin{macro}{\@@_grab_v_aux_catcodes:} % \begin{macro}{\@@_grab_v_aux_abort:n} % In a standalone format, the list of special characters is kept % as a sequence, \cs{c_@@_special_chars_seq}, and we use % \tn{dospecials} in package mode. % The approach for short verbatim arguments is to make the end-line % character a macro parameter character: this is forbidden by the % rest of the code. Then the error branch can check what caused the % bail out and give the appropriate error message. % \begin{macrocode} \cs_new_protected:Npn \@@_grab_v_aux_catcodes: { %<*initex> \seq_map_function:NN \c_@@_special_chars_seq \char_set_catcode_other:N % %<*package> \cs_set_eq:NN \do \char_set_catcode_other:N \dospecials % \tex_endlinechar:D = `\^^M \scan_stop: \bool_if:NTF \l_@@_long_bool { \char_set_catcode_other:n { \tex_endlinechar:D } } { \char_set_catcode_parameter:n { \tex_endlinechar:D } } } \cs_new_protected:Npn \@@_grab_v_aux_abort:n #1 { \@@_grab_v_group_end: \exp_after:wN \exp_after:wN \exp_after:wN \peek_meaning_remove:NTF \char_generate:nn { \tex_endlinechar:D } { 6 } { \__msg_kernel_error:nnxxx { xparse } { verbatim-newline } { \exp_after:wN \token_to_str:N \l_@@_fn_tl } { \tl_to_str:N \l_@@_v_arg_tl } { \tl_to_str:n {#1} } \@@_add_arg:o \c_@@_no_value_tl } { \__msg_kernel_error:nnxxx { xparse } { verbatim-tokenized } { \exp_after:wN \token_to_str:N \l_@@_fn_tl } { \tl_to_str:N \l_@@_v_arg_tl } { \tl_to_str:n {#1} } \@@_add_arg:o \c_@@_no_value_tl } } % \end{macrocode} % \end{macro} % \end{macro} % % \begin{macro}{\@@_grab_v_aux_put:N} % Storing one token in the collected argument. Most tokens are % converted to category code $12$, with the exception of active % characters, and spaces (not sure what should be done for those). % \begin{macrocode} \cs_new_protected:Npn \@@_grab_v_aux_put:N #1 { \tl_put_right:Nx \l_@@_v_arg_tl { \token_if_active:NTF #1 { \exp_not:N #1 } { \token_to_str:N #1 } } } % \end{macrocode} % \end{macro} % % \begin{macro}{\@@_grab_v_token_if_char:NTF} % This function assumes that the escape character is printable. % Then the string representation of control sequences is at least % two characters, and \cs{str_tail:n} only removes the escape % character. Macro parameter characters are doubled by % \cs{tl_to_str:n}, and will also yield a non-empty result, % hence are not considered as characters. % \begin{macrocode} \cs_new_protected:Npn \@@_grab_v_token_if_char:NTF #1 { \str_if_eq_x:nnTF { } { \str_tail:n {#1} } } % \end{macrocode} % \end{macro} % % \begin{macro}{\@@_add_arg:n, \@@_add_arg:V, \@@_add_arg:o, \@@_add_arg:x} % When an argument is found it is stored, then further arguments are % grabbed by calling \cs{l_@@_signature_tl}. % \begin{macrocode} \cs_new_protected:Npn \@@_add_arg:n #1 { \tl_put_right:Nn \l_@@_args_tl { {#1} } \l_@@_signature_tl \@@_run_code: } \cs_generate_variant:Nn \@@_add_arg:n { V , o , x } % \end{macrocode} % \end{macro} % % \subsection{Grabbing arguments expandably} % % \begin{macro}[EXP]{\@@_expandable_grab_D:w} % \begin{macro}[EXP, aux]{\@@_expandable_grab_D:NNNwNNn} % \begin{macro}[EXP, aux]{\@@_expandable_grab_D:NNNwNNnnn} % \begin{macro}[EXP, aux]{\@@_expandable_grab_D:Nw} % \begin{macro}[EXP, aux]{\@@_expandable_grab_D:nnNNNwNN} % The first step is to grab the first token or group. The generic grabbers % \cs{\meta{function}}\verb*| | and \cs{\meta{function}}\verb*| | are just after \cs{q_@@}, we go and find % them (and use the long one). % \begin{macrocode} \cs_new:Npn \@@_expandable_grab_D:w #1 \q_@@ #2#3 { #2 { \@@_expandable_grab_D:NNNwNNn #1 \q_@@ #2 #3 } } % \end{macrocode} % We then wish to test whether |#7|, which we just grabbed, is exactly |#2|. % A preliminary test is whether their string representations coincide, then % expand the only grabber function we have, |#1|, once: the two strings below % are equal if and only if |#7| matches |#2| exactly.\footnote{It is obvious % that if \texttt{\#7} matches \texttt{\#2} then the strings are equal. We % must check the converse. The right-hand-side of \cs{str_if_eq:onTF} does % not end with \texttt{\#3}, implying that the grabber function took % everything as its arguments. The first brace group can only be empty if % \texttt{\#7} starts with \texttt{\#2}, otherwise the brace group preceding % \texttt{\#7} would not vanish. The third brace group is empty, thus the % \cs{q_@@} that was used by our grabber \texttt{\#1} must be the one % that we inserted (not some token in \texttt{\#7}), hence the second brace % group contains the end of \texttt{\#7} followed by \texttt{\#2}. Since this % is \texttt{\#2} on the right-hand-side, and no brace can be lost there, % \texttt{\#7} must contain nothing else than its leading \texttt{\#2}.} % The preliminary test is needed as |#7| could validly contain % \tn{par} (because a later mandatory argument could be long) and our % grabber may be short. If % |#7| does not match |#2|, then the optional argument is missing, we use the % default |-NoValue-|, and put back the argument |#7| in the input stream. % % If it does match, then interesting things need to be done. We will grab the % argument piece by piece, with the following pattern: % \begin{quote} % \meta{grabber} \Arg{tokens} \\ % ~~\cs{q_nil} \Arg{piece 1} \meta{piece 2} \cs{ERROR} \cs{q_@@}\\ % ~~\cs{q_nil} \meta{input stream} % \end{quote} % The \meta{grabber} will find an opening delimiter in \meta{piece 2}, take % the \cs{q_@@} as a second delimiter, and find more material delimited % by the closing delimiter in the \meta{input stream}. We then move the part % before the opening delimiter from \meta{piece 2} to \meta{piece 1}, and the % material taken from the \meta{input stream} to the \meta{piece 2}. Thus, % the argument moves gradually from the \meta{input stream} to the % \meta{piece 2}, then to the \meta{piece 1} when we have made sure to find % all opening and closing delimiters. This two-step process ensures that % nesting works: the number of opening delimiters minus closing delimiters in % \meta{piece 1} is always equal to the number of closing delimiters in % \meta{piece 2}. We stop grabbing arguments once the \meta{piece 2} contains % no opening delimiter any more, hence the balance is reached, and the final % argument is \meta{piece 1} \meta{piece 2}. % The indirection via \cs{@@_tmp:w} allows to insert |-NoValue-| expanded. % \begin{macrocode} \cs_set_protected:Npn \@@_tmp:w #1 { \cs_new:Npn \@@_expandable_grab_D:NNNwNNn ##1##2##3##4 \q_@@ ##5##6##7 { \str_if_eq:nnTF {##2} {##7} { \str_if_eq:onTF { ##1 { } { } ##7 ##2 \q_@@ ##3 } { { } {##2} { } } } { \use_ii:nn } { ##1 { \@@_expandable_grab_D:NNNwNNnnn ##1##2##3##4 \q_@@ ##5##6 } \q_nil { } ##2 \ERROR \q_@@ \ERROR } { ##4 {#1} \q_@@ ##5 ##6 {##7} } } } \exp_args:No \@@_tmp:w { \c_@@_no_value_tl } % \end{macrocode} % At this stage, |#7| is \cs{q_nil} \Arg{piece 1} \meta{more for piece 1}, % and we want to concatenate all that, removing \cs{q_nil}, and keeping the % opening delimiter |#2|. Simply use \cs{use_ii:nn}. Also, |#8| is % \meta{remainder of piece 2} \cs{ERROR}, and |#9| is \cs{ERROR} \meta{more % for piece 2}. We concatenate those, replacing the two \cs{ERROR} by the % closing delimiter |#3|. % \begin{macrocode} \cs_new:Npn \@@_expandable_grab_D:NNNwNNnnn #1#2#3#4 \q_@@ #5#6#7#8#9 { \exp_args:Nof \@@_expandable_grab_D:nnNNNwNN { \use_ii:nn #7 #2 } { \@@_expandable_grab_D:Nw #3 \exp_stop_f: #8 #9 } #1#2#3 #4 \q_@@ #5 #6 } \cs_new:Npn \@@_expandable_grab_D:Nw #1#2 \ERROR \ERROR { #2 #1 } % \end{macrocode} % Armed with our two new \meta{pieces}, we are ready to loop. However, we % must first see if \meta{piece 2} (here |#2|) contains any opening % delimiter |#4|. Again, we expand |#3|, this time removing its whole output % with \cs{use_none:nnn}. The test is similar to \cs{tl_if_in:nnTF}. The % token list is empty if and only if |#2| does not contain the opening % delimiter. In that case, we are done, and put the argument (from which we % remove a spurious pair of delimiters coming from how we started the loop). % Otherwise, we go back to looping with % \cs{@@_expandable_grab_D:NNNwNNnnn}. The code to deal with brace stripping % is much the same as for the non-expandable case. % \begin{macrocode} \cs_new:Npn \@@_expandable_grab_D:nnNNNwNN #1#2#3#4#5#6 \q_@@ #7#8 { \exp_args:No \tl_if_empty:oTF { #3 { \use_none:nnn } #2 \q_@@ #5 #4 \q_@@ #5 } { \tl_if_blank:oTF { \use_none:nn #1#2 } { \@@_put_arg_expandable:ow { \use_none:nn #1#2 } } { \str_if_eq_x:nnTF { \exp_not:o { \use_none:nn #1#2 } } { { \exp_not:o { \use_iii:nnnn #1#2 \q_nil } } } { \@@_put_arg_expandable:ow { \use_iii:nnn #1#2 } } { \@@_put_arg_expandable:ow { \use_none:nn #1#2 } } } #6 \q_@@ #7 #8 } { #3 { \@@_expandable_grab_D:NNNwNNnnn #3#4#5#6 \q_@@ #7 #8 } \q_nil {#1} #2 \ERROR \q_@@ \ERROR } } % \end{macrocode} % \end{macro} % \end{macro} % \end{macro} % \end{macro} % \end{macro} % % \begin{macro}[EXP]{\@@_expandable_grab_D_alt:w} % \begin{macro}[EXP]{\@@_expandable_grab_D_alt:NNwNNn} % \begin{macro}[EXP]{\@@_expandable_grab_D_alt:Nwn} % When the delimiters are identical, nesting is not possible and a simplified % approach is used. The test concept here is the same as for the case where % the delimiters are different but there cannot be any nesting. % \begin{macrocode} \cs_new:Npn \@@_expandable_grab_D_alt:w #1 \q_@@ #2#3 { #2 { \@@_expandable_grab_D_alt:NNwNNn #1 \q_@@ #2 #3 } } \cs_set_protected:Npn \@@_tmp:w #1 { \cs_new:Npn \@@_expandable_grab_D_alt:NNwNNn ##1##2##3 \q_@@ ##4##5##6 { \str_if_eq:nnTF {##6} {##2} { \str_if_eq:onTF { ##1 { } ##6 ##2 ##2 } { { } ##2 } } { \use_ii:nn } { ##1 { \@@_expandable_grab_D_alt:NNwn ##4 ##5 ##3 \q_@@ } ##6 \ERROR } { ##3 {#1} \q_@@ ##4 ##5 {##6} } } } \exp_args:No \@@_tmp:w { \c_@@_no_value_tl } \cs_new:Npn \@@_expandable_grab_D_alt:NNwn #1#2#3 \q_@@ #4 { \tl_if_blank:oTF { \use_none:n #4 } { \@@_put_arg_expandable:ow { \use_none:n #4 } } { \str_if_eq_x:nnTF { \exp_not:o { \use_none:n #4 } } { { \exp_not:o { \use_ii:nnn #4 \q_nil } } } { \@@_put_arg_expandable:ow { \use_ii:nn #4 } } { \@@_put_arg_expandable:ow { \use_none:n #4 } } } #3 \q_@@ #1 #2 } % \end{macrocode} % \end{macro} % \end{macro} % \end{macro} % % \begin{macro}[EXP]{\@@_expandable_grab_E:w, \@@_expandable_grab_E_long:w} % \begin{macro}[EXP,aux]{\@@_expandable_grab_E_aux:w} % \begin{macro}[EXP,aux]{\@@_expandable_grab_E_test:nnw} % \begin{macro}[EXP,aux]{\@@_expandable_grab_E_loop:nnnNNw} % \begin{macro}[EXP,aux]{\@@_expandable_grab_E_find:w} % \begin{macro}[EXP,aux]{\@@_expandable_grab_E_find:nnw} % \begin{macro}[EXP,aux]{\@@_expandable_grab_E_end:nnw} % We keep track of long/short by placing the appropriate grabber as % the third token after \cs{q_@@}; it is eventually removed by the % \texttt{end:nnw} auxiliary. The \texttt{aux:w} auxiliary will be % called repeatedly with two arguments: the set % of pairs \meta{parser} \meta{token}, and the set of arguments found % so far (initially all |{-NoValue-}|). At each step, grab what % follows in the input stream then call the \texttt{loop:nnnNNw} % auxiliary to compare it with each possible embellishment in turn. % This auxiliary's |#1| is what was found in the input, |#2| collects % \meta{parser} \meta{token} pairs that did not match, |#3| collects % the corresponding arguments found previously, |#4| and |#5| is the % current pair, |#6| is the remaining pairs, |#7| is empty or two % \cs{q_nil}, and |#8| is the current argument. If none of the pairs % matched (determined by \cs{quark_if_nil:NTF}) then call the % \texttt{end} auxiliary to stop looking for embellishments, % remembering to put what was grabbed in the input back where it % belongs, and storing the arguments found just before \cs{q_@@}. If % the current argument |#8| is not |-NoValue-| or if the input |#1| % does not match |#5| (see \texttt{t}-type arguments below for a % similar \cs{str_if_eq:onTF} test) then carry on the loop. % Otherwise, we found a new embellishment: grab the corresponding % argument in the input using the \texttt{find:w} auxiliary. To avoid % losing braces around that auxiliary's argument we include a % space, which will be eliminated in the next loop through % embellishments. % \begin{macrocode} \cs_new:Npn \@@_expandable_grab_E:w #1 \q_@@ #2#3 { \@@_expandable_grab_E_aux:w #1 \q_@@ #2 #3 #3 } \cs_new:Npn \@@_expandable_grab_E_long:w #1 \q_@@ #2#3 { \@@_expandable_grab_E_aux:w #1 \q_@@ #2 #3 #2 } \cs_new:Npn \@@_expandable_grab_E_aux:w #1 \q_@@ #2#3#4 { #2 { \@@_expandable_grab_E_test:nnw #1 \q_@@ #2 #3 #4 } } \cs_new:Npn \@@_expandable_grab_E_test:nnw #1#2#3 \q_@@ #4#5#6#7 { \@@_expandable_grab_E_loop:nnnNNw {#7} { } { } #1 \q_nil \q_nil \q_nil \q_mark #2 \q_nil #3 \q_@@ #4 #5 #6 } \cs_new:Npn \@@_expandable_grab_E_loop:nnnNNw #1#2#3#4#5#6 \q_nil #7 \q_mark #8 { \quark_if_nil:NTF #4 { \@@_expandable_grab_E_end:nnw {#1} {#3} } { \@@_if_no_value:nTF {#8} { \str_if_eq:onTF { #4 { } #1 #5 } {#5} } { \use_ii:nn } { \@@_expandable_grab_E_find:w { #2 #4 #5 #6 } {#3} ~ } { \@@_expandable_grab_E_loop:nnnNNw {#1} { #2 #4 #5 } { #3 {#8} } #6 \q_nil #7 \q_mark } } } \cs_new:Npn \@@_expandable_grab_E_find:w #1 \q_@@ #2#3#4 { #4 { \@@_expandable_grab_E_find:nnw #1 \q_@@ #2 #3 #4 } } \cs_new:Npn \@@_expandable_grab_E_find:nnw #1#2#3 \q_nil #4 \q_@@ #5#6#7#8 { \@@_expandable_grab_E_aux:w {#1} { #2 {#8} #3 } #4 \q_@@ #5 #6 #7 } \cs_new:Npn \@@_expandable_grab_E_end:nnw #1#2#3 \q_@@ #4#5#6 { #3 {#2} \q_@@ #4 #5 {#1} } % \end{macrocode} % \end{macro} % \end{macro} % \end{macro} % \end{macro} % \end{macro} % \end{macro} % \end{macro} % % \begin{macro}[EXP]{\@@_expandable_grab_m:w, \@@_expandable_grab_m_long:w} % \begin{macro}[EXP, aux]{\@@_expandable_grab_m_aux:wNn} % The mandatory case is easy: find the auxiliary after the \cs{q_@@}, % and use it directly to grab the argument, then correctly position % the argument before \cs{q_@@}. % \begin{macrocode} \cs_new:Npn \@@_expandable_grab_m:w #1 \q_@@ #2#3 { #3 { \@@_expandable_grab_m_aux:wNn #1 \q_@@ #2 #3 } } \cs_new:Npn \@@_expandable_grab_m_long:w #1 \q_@@ #2#3 { #2 { \@@_expandable_grab_m_aux:wNn #1 \q_@@ #2 #3 } } \cs_new:Npn \@@_expandable_grab_m_aux:wNn #1 \q_@@ #2#3#4 { #1 {#4} \q_@@ #2 #3 } % \end{macrocode} % \end{macro} % \end{macro} % % \begin{macro}[EXP]{\@@_expandable_grab_R:w} % \begin{macro}[EXP, aux]{\@@_expandable_grab_R_aux:NNNwNNn} % Much the same as for the \texttt{D}-type argument, with only the lead-off % function varying. % \begin{macrocode} \cs_new:Npn \@@_expandable_grab_R:w #1 \q_@@ #2#3 { #2 { \@@_expandable_grab_R_aux:NNNwNNn #1 \q_@@ #2#3 } } \cs_set_protected:Npn \@@_tmp:w #1 { \cs_new:Npn \@@_expandable_grab_R_aux:NNNwNNn ##1##2##3##4 \q_@@ ##5##6##7 { \str_if_eq:nnTF {##7} {##2} { \str_if_eq:onTF { ##1 { } { } ##7 ##2 \q_@@ ##3 } { { } {##2} { } } } { \use_ii:nn } { ##1 { \@@_expandable_grab_D:NNNwNNnnn ##1##2##3##4 \q_@@ ##5##6 } \q_nil { } ##2 \ERROR \q_@@ \ERROR } { \__msg_kernel_expandable_error:nnnn { xparse } { missing-required } {##5} {##2} ##4 {#1} \q_@@ ##5 ##6 {##7} } } } \exp_args:No \@@_tmp:w { \c_@@_no_value_tl } % \end{macrocode} % \end{macro} % \end{macro} % % \begin{macro}[EXP]{\@@_expandable_grab_R_alt:w} % \begin{macro}[EXP]{\@@_expandable_grab_R_alt_aux:NNwNNn} % When the delimiters are identical, nesting is not possible and a simplified % approach is used. The test concept here is the same as for the case where % the delimiters are different. % \begin{macrocode} \cs_new:Npn \@@_expandable_grab_R_alt:w #1 \q_@@ #2#3 { #2 { \@@_expandable_grab_R_alt_aux:NNnwNn #1 \q_@@ #2#3 } } \cs_set_protected:Npn \@@_tmp:w #1 { \cs_new:Npn \@@_expandable_grab_R_alt_aux:NNwNn ##1##2##3 \q_@@ ##4##5##6 { \str_if_eq:nnTF {##6} {##2} { \str_if_eq:onTF { ##1 { } ##6 ##2 ##2 } { { } ##2 } } { \use_ii:nn } { ##1 { \@@_expandable_grab_D_alt:NNwn ##4 ##5 ##3 \q_@@ } ##6 \ERROR } { \__msg_kernel_expandable_error:nnnn { xparse } { missing-required } {##4} {##2} ##3 {#1} \q_@@ ##4 ##5 {##6} } } } \exp_args:No \@@_tmp:w { \c_@@_no_value_tl } % \end{macrocode} % \end{macro} % \end{macro} % % \begin{macro}[EXP]{\@@_expandable_grab_t:w} % \begin{macro}[EXP, aux]{\@@_expandable_grab_t_aux:NNwn} % As for a \texttt{D}-type argument, here we compare the grabbed tokens using % the only parser we have in order to work out if |#2| is exactly equal to % the output of the grabber. % \begin{macrocode} \cs_new:Npn \@@_expandable_grab_t:w #1 \q_@@ #2#3 { #2 { \@@_expandable_grab_t_aux:NNwn #1 \q_@@ #2 #3 } } \cs_new:Npn \@@_expandable_grab_t_aux:NNwn #1#2#3 \q_@@ #4#5#6 { \str_if_eq:onTF { #1 { } #6 #2 } {#2} { #3 { \BooleanTrue } \q_@@ #4 #5 } { #3 { \BooleanFalse } \q_@@ #4 #5 {#6} } } % \end{macrocode} % \end{macro} % \end{macro} % % \begin{macro}[EXP]{\@@_expandable_grab_u:w} % It turns out there is nothing to do: this is followed by an % auxiliary named after the function, that does everything. % \begin{macrocode} \cs_new_eq:NN \@@_expandable_grab_u:w \prg_do_nothing: % \end{macrocode} % \end{macro} % % \begin{macro}[EXP] % {\@@_put_arg_expandable:nw, \@@_put_arg_expandable:ow} % A useful helper, to store arguments when they are ready. % \begin{macrocode} \cs_new:Npn \@@_put_arg_expandable:nw #1#2 \q_@@ { #2 {#1} \q_@@ } \cs_generate_variant:Nn \@@_put_arg_expandable:nw { o } % \end{macrocode} % \end{macro} % % \subsection{Argument processors} % % \begin{macro}{\@@_bool_reverse:N} % A simple reversal. % \begin{macrocode} \cs_new_protected:Npn \@@_bool_reverse:N #1 { \bool_if:NTF #1 { \tl_set:Nn \ProcessedArgument { \c_false_bool } } { \tl_set:Nn \ProcessedArgument { \c_true_bool } } } % \end{macrocode} % \end{macro} % % \begin{variable}{\l_@@_split_list_seq, \l_@@_split_list_tl} % \begin{macro}{\@@_split_list:nn} % \begin{macro}[aux]{\@@_split_list_multi:nn, \@@_split_list_multi:nV} % \begin{macro}[aux]{\@@_split_list_single:Nn} % Splitting can take place either at a single token or at a longer % identifier. To deal with single active tokens, a two-part procedure is % needed. % \begin{macrocode} \seq_new:N \l_@@_split_list_seq \tl_new:N \l_@@_split_list_tl \cs_new_protected:Npn \@@_split_list:nn #1#2 { \tl_if_single:nTF {#1} { \token_if_cs:NTF #1 { \@@_split_list_multi:nn {#1} {#2} } { \@@_split_list_single:Nn #1 {#2} } } { \@@_split_list_multi:nn {#1} {#2} } } \cs_new_protected:Npn \@@_split_list_multi:nn #1#2 { \seq_set_split:Nnn \l_@@_split_list_seq {#1} {#2} \tl_clear:N \ProcessedArgument \seq_map_inline:Nn \l_@@_split_list_seq { \tl_put_right:Nn \ProcessedArgument { {##1} } } } \cs_generate_variant:Nn \@@_split_list_multi:nn { nV } \group_begin: \char_set_catcode_active:N \^^@ \cs_new_protected:Npn \@@_split_list_single:Nn #1#2 { \tl_set:Nn \l_@@_split_list_tl {#2} \group_begin: \char_set_lccode:nn { `\^^@ } { `#1 } \tex_lowercase:D { \group_end: \tl_replace_all:Nnn \l_@@_split_list_tl { ^^@ } } {#1} \@@_split_list_multi:nV {#1} \l_@@_split_list_tl } \group_end: % \end{macrocode} % \end{macro} % \end{macro} % \end{macro} % \end{variable} % % \begin{macro}{\@@_split_argument:nnn} % \begin{macro}[aux]{\@@_split_argument_aux:nnnn} % \begin{macro}[aux, EXP]{\@@_split_argument_aux:n} % \begin{macro}[aux, rEXP]{\@@_split_argument_aux:wn} % Splitting to a known number of items is a special version of splitting % a list, in which the limit is hard-coded and where there will always be % exactly the correct number of output items. An auxiliary function is % used to save on working out the token list length several times. % \begin{macrocode} \cs_new_protected:Npn \@@_split_argument:nnn #1#2#3 { \@@_split_list:nn {#2} {#3} \exp_args:Nf \@@_split_argument_aux:nnnn { \tl_count:N \ProcessedArgument } {#1} {#2} {#3} } \cs_new_protected:Npn \@@_split_argument_aux:nnnn #1#2#3#4 { \int_compare:nNnF {#1} = { #2 + 1 } { \int_compare:nNnTF {#1} > { #2 + 1 } { \tl_set:Nx \ProcessedArgument { \exp_last_unbraced:NnNo \@@_split_argument_aux:n { #2 + 1 } \use_none_delimit_by_q_stop:w \ProcessedArgument \q_stop } \__msg_kernel_error:nnxxx { xparse } { split-excess-tokens } { \tl_to_str:n {#3} } { \int_eval:n { #2 + 1 } } { \tl_to_str:n {#4} } } { \tl_put_right:Nx \ProcessedArgument { \prg_replicate:nn { #2 + 1 - (#1) } { { \exp_not:V \c_@@_no_value_tl } } } } } } % \end{macrocode} % Auxiliaries to leave exactly the correct number of arguments in % \cs{ProcessedArgument}. % \begin{macrocode} \cs_new:Npn \@@_split_argument_aux:n #1 { \prg_replicate:nn {#1} { \@@_split_argument_aux:wn } } \cs_new:Npn \@@_split_argument_aux:wn #1 \use_none_delimit_by_q_stop:w #2 { \exp_not:n { {#2} } #1 \use_none_delimit_by_q_stop:w } % \end{macrocode} % \end{macro} % \end{macro} % \end{macro} % \end{macro} % % \begin{macro}{\@@_trim_spaces:n} % This one is almost trivial. % \begin{macrocode} \cs_new_protected:Npn \@@_trim_spaces:n #1 { \tl_set:Nx \ProcessedArgument { \tl_trim_spaces:n {#1} } } % \end{macrocode} % \end{macro} % % \subsection{Access to the argument specification} % % \begin{macro}{\@@_get_arg_spec_error:N, \@@_get_arg_spec_error:n} % Provide an informative error when trying to get the argument % specification of a non-\pkg{xparse} command or environment. % \begin{macrocode} \cs_new_protected:Npn \@@_get_arg_spec_error:N #1 { \cs_if_exist:NTF #1 { \__msg_kernel_error:nnx { xparse } { non-xparse-command } { \token_to_str:N #1 } } { \__msg_kernel_error:nnx { xparse } { unknown-command } { \token_to_str:N #1 } } } \cs_new_protected:Npn \@@_get_arg_spec_error:n #1 { \cs_if_exist:cTF {#1} { \__msg_kernel_error:nnx { xparse } { non-xparse-environment } { \tl_to_str:n {#1} } } { \__msg_kernel_error:nnx { xparse } { unknown-environment } { \tl_to_str:n {#1} } } } % \end{macrocode} % \end{macro} % % \begin{macro}{\@@_get_arg_spec:NTF} % If the command is not an \pkg{xparse} command, complain. If it is, % its second \enquote{item} is the argument specification. % \begin{macrocode} \cs_new_protected:Npn \@@_get_arg_spec:NTF #1#2#3 { \@@_cmd_if_xparse:NTF #1 { \tl_set:Nx \ArgumentSpecification { \tl_item:Nn #1 { 2 } } #2 } {#3} } % \end{macrocode} % \end{macro} % % \begin{macro}{\@@_get_arg_spec:N} % \begin{macro}{\@@_get_arg_spec:n} % \begin{variable}{\ArgumentSpecification} % Recovering the argument specification is now trivial. % \begin{macrocode} \cs_new_protected:Npn \@@_get_arg_spec:N #1 { \@@_get_arg_spec:NTF #1 { } { \@@_get_arg_spec_error:N #1 } } \cs_new_protected:Npn \@@_get_arg_spec:n #1 { \exp_args:Nc \@@_get_arg_spec:NTF { environment~ \tl_to_str:n {#1} } { } { \@@_get_arg_spec_error:n {#1} } } \tl_new:N \ArgumentSpecification % \end{macrocode} % \end{variable} % \end{macro} % \end{macro} % % \begin{macro}{\@@_show_arg_spec:N} % \begin{macro}{\@@_show_arg_spec:n} % Showing the argument specification simply means finding it and then % calling the \cs{tl_show:N} function. % \begin{macrocode} \cs_new_protected:Npn \@@_show_arg_spec:N #1 { \@@_get_arg_spec:NTF #1 { \tl_show:N \ArgumentSpecification } { \@@_get_arg_spec_error:N #1 } } \cs_new_protected:Npn \@@_show_arg_spec:n #1 { \exp_args:Nc \@@_get_arg_spec:NTF { environment~ \tl_to_str:n {#1} } { \tl_show:N \ArgumentSpecification } { \@@_get_arg_spec_error:n {#1} } } % \end{macrocode} % \end{macro} % \end{macro} % % \subsection{Utilities} % % \begin{macro}[TF]{\@@_if_no_value:n} % Tests for |-NoValue-|: this is similar to \cs{tl_if_in:nn} but set % up to be expandable and to check the value exactly. The question % mark prevents the auxiliary from losing braces. % \begin{macrocode} \use:x { \prg_new_conditional:Npnn \exp_not:N \@@_if_no_value:n ##1 { T , F , TF } { \exp_not:N \str_if_eq:onTF { \exp_not:N \@@_if_value_aux:w ? ##1 { } \c_@@_no_value_tl } { ? { } \c_@@_no_value_tl } { \exp_not:N \prg_return_true: } { \exp_not:N \prg_return_false: } } \cs_new:Npn \exp_not:N \@@_if_value_aux:w ##1 \c_@@_no_value_tl {##1} } % \end{macrocode} % \end{macro} % % \begin{macro}{\@@_check_definable:nNT, \@@_check_definable_aux:nN} % Check that a token list is appropriate as a first argument of % \cs{NewDocumentCommand} and similar functions and otherwise % produce an error. First trim whitespace to allow for spaces around % the actual command to be defined. If the result has multiple % tokens, it is not a valid argument. The single token is a control % sequence exactly if its string representation has more than one % character (using \cs{token_to_str:N} rather than \cs{tl_to_str:n} % to avoid problems with macro parameter characters, and setting % \cs{tex_escapechar:D} to prevent it from being non-printable). % Finally, check for an active character: this is done by lowercasing % the token to fix its character code (arbitrarily to that of~|?|) % and comparing the result to an active~|?|. Both control sequences % and active characters are valid arguments, and non-active character % tokens are not. In all cases, the group opened to keep assignments % local must be closed. % \begin{macrocode} \cs_new_protected:Npn \@@_check_definable:nNT #1 { \exp_args:Nx \@@_check_definable_aux:nN { \tl_trim_spaces:n {#1} } } \group_begin: \char_set_catcode_active:n { `? } \cs_new_protected:Npn \@@_check_definable_aux:nN #1#2 { \group_begin: \tl_if_single_token:nTF {#1} { \int_set:Nn \tex_escapechar:D { 92 } \exp_args:Nx \tl_if_empty:nTF { \exp_args:No \str_tail:n { \token_to_str:N #1 } } { \exp_args:Nx \char_set_lccode:nn { ` \str_head:n {#1} } { `? } \tex_lowercase:D { \tl_if_eq:nnTF {#1} } { ? } { \group_end: \use_iii:nnn } { \group_end: \use_i:nnn } } { \group_end: \use_iii:nnn } } { \group_end: \use_ii:nnn } { \__msg_kernel_error:nnxx { xparse } { not-definable } { \tl_to_str:n {#1} } { \token_to_str:N #2 } } { \__msg_kernel_error:nnxx { xparse } { not-one-token } { \tl_to_str:n {#1} } { \token_to_str:N #2 } } } \group_end: % \end{macrocode} % \end{macro} % % \begin{macro}{\@@_tl_mapthread_function:NNN, \@@_tl_mapthread_function:nnN} % \begin{macro}[aux]{\@@_tl_mapthread_loop:w} % Analogue of \cs{seq_mapthread_function:NNN} for token lists. % \begin{macrocode} \cs_new:Npn \@@_tl_mapthread_function:NNN #1#2#3 { \exp_after:wN \exp_after:wN \exp_after:wN \@@_tl_mapthread_loop:w \exp_after:wN \exp_after:wN \exp_after:wN #3 \exp_after:wN #1 \exp_after:wN \q_recursion_tail \exp_after:wN \q_mark #2 \q_recursion_tail \q_recursion_stop } \cs_new:Npn \@@_tl_mapthread_function:nnN #1#2#3 { \@@_tl_mapthread_loop:w #3 #1 \q_recursion_tail \q_mark #2 \q_recursion_tail \q_recursion_stop } \cs_new:Npn \@@_tl_mapthread_loop:w #1#2#3 \q_mark #4 { \quark_if_recursion_tail_stop:n {#2} \quark_if_recursion_tail_stop:n {#4} #1 {#2} {#4} \@@_tl_mapthread_loop:w #1#3 \q_mark } % \end{macrocode} % \end{macro} % \end{macro} % % \begin{macro}{\@@_cmd_if_xparse:NTF} % \begin{macro}[aux]{\@@_cmd_if_xparse_aux:N} % To determine whether the command is an \pkg{xparse} command check % that its |arg_spec| is empty (this also excludes non-macros) and % that its |replacement_spec| starts with either \cs{@@_start:nNNnnn} % (non-expandable command) or \cs{@@_start_expandable:nNNNNn} % (expandable command). % \begin{macrocode} \cs_new_protected:Npn \@@_cmd_if_xparse:NTF #1 { \exp_args:Nf \str_case_x:nnTF { \exp_args:Nf \tl_if_empty:nT { \token_get_arg_spec:N #1 } { \exp_last_unbraced:Nf \@@_cmd_if_xparse_aux:w { \token_get_replacement_spec:N #1 } ~ \q_stop } } { { \token_to_str:N \@@_start:nNNnnn } { } { \token_to_str:N \@@_start_expandable:nNNNNn } { } } } \cs_new:Npn \@@_cmd_if_xparse_aux:w #1 ~ #2 \q_stop {#1} % \end{macrocode} % \end{macro} % \end{macro} % % \subsection{Messages} % % Some messages intended as errors. % \begin{macrocode} \__msg_kernel_new:nnnn { xparse } { bad-arg-spec } { Bad~argument~specification~'#2'~for~command~'#1'. } { \c__msg_coding_error_text_tl The~argument~specification~provided~was~not~valid:~ one~or~more~mandatory~pieces~of~information~were~missing. \\ \\ LaTeX~will~ignore~this~entire~definition. } \__msg_kernel_new:nnnn { xparse } { command-already-defined } { Command~'#1'~already~defined! } { You~have~used~#2~ with~a~command~that~already~has~a~definition. \\ The~existing~definition~of~'#1'~will~not~be~altered. } \__msg_kernel_new:nnnn { xparse } { command-not-yet-defined } { Command ~'#1'~not~yet~defined! } { You~have~used~#2~ with~a~command~that~was~never~defined. \\ LaTeX~will~ignore~this~entire~definition. } \__msg_kernel_new:nnnn { xparse } { environment-already-defined } { Environment~'#1'~already~defined! } { You~have~used~\NewDocumentEnvironment with~an~environment~that~already~has~a~definition. \\ The~existing~definition~of~'#1'~will~be~overwritten. } \__msg_kernel_new:nnnn { xparse } { environment-not-yet-defined } { Environment~'#1'~not~yet~defined! } { You~have~used~\RenewDocumentEnvironment with~an~environment~that~was~never~defined. \\ LaTeX~will~ignore~this~entire~definition. } \__msg_kernel_new:nnnn { xparse } { expandable-ending-optional } { Argument~specification~'#2'~for~expandable~command~'#1'~ ends~with~optional~argument. } { \c__msg_coding_error_text_tl Expandable~commands~must~have~a~final~mandatory~argument~ (or~no~arguments~at~all).~You~cannot~have~a~terminal~optional~ argument~with~expandable~commands. } \__msg_kernel_new:nnnn { xparse } { inconsistent-long } { Inconsistent~long~arguments~for~expandable~command~'#1'. } { \c__msg_coding_error_text_tl The~arguments~for~an~expandable~command~must~not~involve~short~ arguments~after~long~arguments.~You~have~tried~to~mix~the~two~types. } \__msg_kernel_new:nnnn { xparse } { invalid-expandable-argument-type } { Argument~type~'#2'~not~available~for~expandable~command~'#1'. } { \c__msg_coding_error_text_tl The~letter~'#2'~does~not~specify~an~argument~type~which~can~be~used~ in~an~expandable~command. \\ \\ LaTeX~will~ignore~this~entire~definition. } \__msg_kernel_new:nnnn { xparse } { invalid-after-optional-expandably } { Argument~type~'#2'~not~available~after~optional~argument~ for~expandable~command~'#1'. } { \c__msg_coding_error_text_tl The~letter~'#2'~does~not~specify~an~argument~type~which~can~be~used~ in~an~expandable~command~after~an~optional~argument. \\ \\ LaTeX~will~ignore~this~entire~definition. } \__msg_kernel_new:nnnn { xparse } { loop-in-defaults } { Circular~dependency~in~defaults~of~'#1'. } { \c__msg_coding_error_text_tl The~default~values~of~two~or~more~arguments~of~'#1'~depend~on~each~ other~in~a~way~that~cannot~be~resolved. } \__msg_kernel_new:nnnn { xparse } { missing-required } { Failed~to~find~required~argument~starting~with~'#2'~for~command~'#1'. } { The~current~command~'#1'~expects~an~argument~starting~with~'#2'.~ LaTeX~did~not~find~it,~and~will~insert~a~default~value~to~be~processed. } \__msg_kernel_new:nnnn { xparse } { non-xparse-command } { Command~'#1'~not~defined~using~xparse. } { You~have~asked~for~the~argument~specification~for~a~command~'#1',~ but~this~is~not~a~command~defined~using~xparse. } \__msg_kernel_new:nnnn { xparse } { non-xparse-environment } { Environment~'#1'~not~defined~using~xparse. } { You~have~asked~for~the~argument~specification~for~an~environment~'#1',~ but~this~is~not~an~environment~defined~using~xparse. } \__msg_kernel_new:nnnn { xparse } { not-definable } { First~argument~of~'#2'~must~be~a~command. } { \c__msg_coding_error_text_tl The~first~argument~of~'#2'~should~be~the~document~command~that~will~ be~defined.~The~provided~argument~'#1'~is~a~character.~Perhaps~a~ backslash~is~missing? \\ \\ LaTeX~will~ignore~this~entire~definition. } \__msg_kernel_new:nnnn { xparse } { not-one-token } { First~argument~of~'#2'~must~be~a~command. } { \c__msg_coding_error_text_tl The~first~argument~of~'#2'~should~be~the~document~command~that~will~ be~defined.~The~provided~argument~'#1'~contains~more~than~one~ token. \\ \\ LaTeX~will~ignore~this~entire~definition. } \__msg_kernel_new:nnnn { xparse } { not-single-token } { Argument~delimiter~'#2'~for~the~command~'#1'~should~be~a~single~token. } { \c__msg_coding_error_text_tl The~argument~specification~provided~was~not~valid:~ in~a~place~where~a~single~token~is~required,~LaTeX~found~'#2'. \\ \\ LaTeX~will~ignore~this~entire~definition. } \__msg_kernel_new:nnnn { xparse } { processor-in-expandable } { Argument~processor~'>{#2}'~cannot~be~used~for~the~expandable~command~'#1'. } { \c__msg_coding_error_text_tl The~argument~specification~for~#1~contains~a~processor~function:~ this~is~only~supported~for~standard~robust~commands. \\ \\ LaTeX~will~ignore~this~entire~definition. } \__msg_kernel_new:nnnn { xparse } { split-excess-tokens } { Too~many~'#1'~tokens~when~trying~to~split~argument. } { LaTeX~was~asked~to~split~the~input~'#3'~ at~each~occurrence~of~the~token~'#1',~up~to~a~maximum~of~#2~parts.~ There~were~too~many~'#1'~tokens. } \__msg_kernel_new:nnnn { xparse } { too-many-arguments } { Too~many~arguments~in~argument~specification~'#2'~of~command~'#1'. } { \c__msg_coding_error_text_tl The~argument~specification~provided~has~more~than~9~arguments.~ This~cannot~be~implemented. \\ \\ LaTeX~will~ignore~this~entire~definition. } \__msg_kernel_new:nnnn { xparse } { unknown-argument-type } { Unknown~argument~type~'#2'~for~the~command~'#1'. } { \c__msg_coding_error_text_tl The~letter~'#2'~does~not~specify~a~known~argument~type.~ LaTeX~will~ignore~this~entire~definition. } \__msg_kernel_new:nnnn { xparse } { unknown-command } { Unknown~document~command~'#1'. } { You~have~asked~for~the~argument~specification~for~a~command~'#1',~ but~it~is~not~defined. } \__msg_kernel_new:nnnn { xparse } { unknown-environment } { Unknown~document~environment~'#1'. } { You~have~asked~for~the~argument~specification~for~an~environment~'#1',~ but~it~is~not~defined. } \__msg_kernel_new:nnnn { xparse } { verbatim-newline } { Verbatim~argument~of~'#1'~ended~by~end~of~line. } { The~verbatim~argument~of~'#1'~cannot~contain~more~than~one~line,~ but~the~end~ of~the~current~line~has~been~reached.~You~have~probably~forgotten~the~ closing~delimiter. \\ \\ LaTeX~will~ignore~'#2'. } \__msg_kernel_new:nnnn { xparse } { verbatim-tokenized } { The~verbatim~command~'#1'~cannot~be~used~inside~an~argument.~ } { The~command~'#1'~takes~a~verbatim~argument.~ It~may~not~appear~within~the~argument~of~another~function.~ It~received~an~illegal~token \tl_if_empty:nF {#3} { ~'#3' } . \\ \\ LaTeX~will~ignore~'#2'. } % \end{macrocode} % % Intended more for information. % \begin{macrocode} \__msg_kernel_new:nnn { xparse } { define-command } { Defining~command~#1~ with~sig.~'#2'~\msg_line_context:. } \__msg_kernel_new:nnn { xparse } { define-environment } { Defining~environment~'#1'~ with~sig.~'#2'~\msg_line_context:. } \__msg_kernel_new:nnn { xparse } { redefine-command } { Redefining~command~#1~ with~sig.~'#2'~\msg_line_context:. } \__msg_kernel_new:nnn { xparse } { redefine-environment } { Redefining~environment~'#1'~ with~sig.~'#2'~\msg_line_context:. } \__msg_kernel_new:nnn { xparse } { optional-mandatory } { Since~the~mandatory~argument~'#1'~has~the~same~delimiter~'#2'~ as~a~previous~optional~argument,~it~will~not~be~possible~to~ omit~all~optional~arguments~when~calling~this~command. } \__msg_kernel_new:nnn { xparse } { unsupported-let } { The~command~'#1'~was~undefined~but~not~the~associated~commands~ '#1~code'~and/or~'#1~defaults'.~Maybe~you~tried~using~ \iow_char:N\\let.~This~may~lead~to~an~infinite~loop. } % \end{macrocode} % % \subsection{User functions} % % The user functions are more or less just the internal functions % renamed. % % \begin{macro}{\BooleanFalse} % \begin{macro}{\BooleanTrue} % Design-space names for the Boolean values. % \begin{macrocode} \cs_new_eq:NN \BooleanFalse \c_false_bool \cs_new_eq:NN \BooleanTrue \c_true_bool % \end{macrocode} % \end{macro} % \end{macro} % % \begin{macro}{\NewDocumentCommand} % \begin{macro}{\RenewDocumentCommand} % \begin{macro}{\ProvideDocumentCommand} % \begin{macro}{\DeclareDocumentCommand} % The user macros are pretty simple wrappers around the internal ones. % There is however a check that the first argument is a single token, % possibly surrounded by spaces (hence the strange \cs{use:nnn}), and % is definable. % \begin{macrocode} \cs_new_protected:Npn \NewDocumentCommand #1#2#3 { \@@_check_definable:nNT {#1} \NewDocumentCommand { \cs_if_exist:NTF #1 { \__msg_kernel_error:nnxx { xparse } { command-already-defined } { \use:nnn \token_to_str:N #1 { } } { \token_to_str:N \NewDocumentCommand } } { \@@_declare_cmd:Nnn #1 {#2} {#3} } } } \cs_new_protected:Npn \RenewDocumentCommand #1#2#3 { \@@_check_definable:nNT {#1} \RenewDocumentCommand { \cs_if_exist:NTF #1 { \@@_declare_cmd:Nnn #1 {#2} {#3} } { \__msg_kernel_error:nnxx { xparse } { command-not-yet-defined } { \use:nnn \token_to_str:N #1 { } } { \token_to_str:N \RenewDocumentCommand } } } } \cs_new_protected:Npn \ProvideDocumentCommand #1#2#3 { \@@_check_definable:nNT {#1} \ProvideDocumentCommand { \cs_if_exist:NF #1 { \@@_declare_cmd:Nnn #1 {#2} {#3} } } } \cs_new_protected:Npn \DeclareDocumentCommand #1#2#3 { \@@_check_definable:nNT {#1} \DeclareDocumentCommand { \@@_declare_cmd:Nnn #1 {#2} {#3} } } % \end{macrocode} % \end{macro} % \end{macro} % \end{macro} % \end{macro} % % \begin{macro}{\NewDocumentEnvironment} % \begin{macro}{\RenewDocumentEnvironment} % \begin{macro}{\ProvideDocumentEnvironment} % \begin{macro}{\DeclareDocumentEnvironment} % Very similar for environments. % \begin{macrocode} \cs_new_protected:Npn \NewDocumentEnvironment #1#2#3#4 { \cs_if_exist:cTF {#1} { \__msg_kernel_error:nnx { xparse } { environment-already-defined } {#1} } { \@@_declare_env:nnnn {#1} {#2} {#3} {#4} } } \cs_new_protected:Npn \RenewDocumentEnvironment #1#2#3#4 { \cs_if_exist:cTF {#1} { \@@_declare_env:nnnn {#1} {#2} {#3} {#4} } { \__msg_kernel_error:nnx { xparse } { environment-not-yet-defined } {#1} } } \cs_new_protected:Npn \ProvideDocumentEnvironment #1#2#3#4 { \cs_if_exist:cF {#1} { \@@_declare_env:nnnn {#1} {#2} {#3} {#4} } } \cs_new_protected:Npn \DeclareDocumentEnvironment #1#2#3#4 { \@@_declare_env:nnnn {#1} {#2} {#3} {#4} } % \end{macrocode} % \end{macro} % \end{macro} % \end{macro} % \end{macro} % % \begin{macro}{\NewExpandableDocumentCommand} % \begin{macro}{\RenewExpandableDocumentCommand} % \begin{macro}{\ProvideExpandableDocumentCommand} % \begin{macro}{\DeclareExpandableDocumentCommand} % The expandable versions are essentially the same as the basic functions. % \begin{macrocode} \cs_new_protected:Npn \NewExpandableDocumentCommand #1#2#3 { \@@_check_definable:nNT {#1} \NewExpandableDocumentCommand { \cs_if_exist:NTF #1 { \__msg_kernel_error:nnxx { xparse } { command-already-defined } { \use:nnn \token_to_str:N #1 { } } { \token_to_str:N \NewExpandableDocumentCommand } } { \@@_declare_expandable_cmd:Nnn #1 {#2} {#3} } } } \cs_new_protected:Npn \RenewExpandableDocumentCommand #1#2#3 { \@@_check_definable:nNT {#1} \RenewExpandableDocumentCommand { \cs_if_exist:NTF #1 { \@@_declare_expandable_cmd:Nnn #1 {#2} {#3} } { \__msg_kernel_error:nnxx { xparse } { command-not-yet-defined } { \use:nnn \token_to_str:N #1 { } } { \token_to_str:N \RenewExpandableDocumentCommand } } } } \cs_new_protected:Npn \ProvideExpandableDocumentCommand #1#2#3 { \@@_check_definable:nNT {#1} \ProvideExpandableDocumentCommand { \cs_if_exist:NF #1 { \@@_declare_expandable_cmd:Nnn #1 {#2} {#3} } } } \cs_new_protected:Npn \DeclareExpandableDocumentCommand #1#2#3 { \@@_check_definable:nNT {#1} \DeclareExpandableDocumentCommand { \@@_declare_expandable_cmd:Nnn #1 {#2} {#3} } } % \end{macrocode} % \end{macro} % \end{macro} % \end{macro} % \end{macro} % % \begin{macro}{\IfBooleanT, \IfBooleanF, \IfBooleanTF} % The logical \meta{true} and \meta{false} statements are just the % normal \cs{c_true_bool} and \cs{c_false_bool}, so testing for them is % done with the \cs{bool_if:NTF} functions from \textsf{l3prg}. % \begin{macrocode} \cs_new_eq:NN \IfBooleanTF \bool_if:NTF \cs_new_eq:NN \IfBooleanT \bool_if:NT \cs_new_eq:NN \IfBooleanF \bool_if:NF % \end{macrocode} % \end{macro} % % \begin{macro}{\IfNoValueT, \IfNoValueF, \IfNoValueTF} % Simple re-naming. % \begin{macrocode} \cs_new_eq:NN \IfNoValueF \@@_if_no_value:nF \cs_new_eq:NN \IfNoValueT \@@_if_no_value:nT \cs_new_eq:NN \IfNoValueTF \@@_if_no_value:nTF % \end{macrocode} % \end{macro} % \begin{macro}{\IfValueT, \IfValueF, \IfValueTF} % Inverted logic. % \begin{macrocode} \cs_new:Npn \IfValueF { \@@_if_no_value:nT } \cs_new:Npn \IfValueT { \@@_if_no_value:nF } \cs_new:Npn \IfValueTF #1#2#3 { \@@_if_no_value:nTF {#1} {#3} {#2} } % \end{macrocode} % \end{macro} % % \begin{macro}{\ProcessedArgument} % Processed arguments are returned using this name, which is reserved % here although the definition will change. % \begin{macrocode} \tl_new:N \ProcessedArgument % \end{macrocode} % \end{macro} % % \begin{macro}{\ReverseBoolean, \SplitArgument, \SplitList, \TrimSpaces} % Simple copies. % \begin{macrocode} \cs_new_eq:NN \ReverseBoolean \@@_bool_reverse:N \cs_new_eq:NN \SplitArgument \@@_split_argument:nnn \cs_new_eq:NN \SplitList \@@_split_list:nn \cs_new_eq:NN \TrimSpaces \@@_trim_spaces:n % \end{macrocode} % \end{macro} % % \begin{macro}{\ProcessList} % To support \cs{SplitList}. % \begin{macrocode} \cs_new_eq:NN \ProcessList \tl_map_function:nN % \end{macrocode} % \end{macro} % % \begin{macro}{\GetDocumentCommandArgSpec} % \begin{macro}{\GetDocumentEnvironmentArgSpec} % \begin{macro}{\ShowDocumentCommandArgSpec} % \begin{macro}{\ShowDocumentEnvironmentArgSpec} % More simple mappings, with a check that the argument is a single % control sequence or active character. % \begin{macrocode} \cs_new_protected:Npn \GetDocumentCommandArgSpec #1 { \@@_check_definable:nNT {#1} \GetDocumentCommandArgSpec { \@@_get_arg_spec:N #1 } } \cs_new_eq:NN \GetDocumentEnvironmentArgSpec \@@_get_arg_spec:n \cs_new_protected:Npn \ShowDocumentCommandArgSpec #1 { \@@_check_definable:nNT {#1} \ShowDocumentCommandArgSpec { \@@_show_arg_spec:N #1 } } \cs_new_eq:NN \ShowDocumentEnvironmentArgSpec \@@_show_arg_spec:n % \end{macrocode} % \end{macro} % \end{macro} % \end{macro} % \end{macro} % % \subsection{Package options} % % \begin{variable}{\l_@@_options_clist} % \begin{variable}{\l_@@_log_bool} % Key--value option to log information: done by hand to keep dependencies % down. % \begin{macrocode} \clist_new:N \l_@@_options_clist \DeclareOption* { \clist_put_right:NV \l_@@_options_clist \CurrentOption } \ProcessOptions \relax \keys_define:nn { xparse } { log-declarations .bool_set:N = \l_@@_log_bool , log-declarations .initial:n = true } \keys_set:nV { xparse } \l_@@_options_clist \bool_if:NF \l_@@_log_bool { \msg_redirect_module:nnn { LaTeX / xparse } { info } { none } \msg_redirect_module:nnn { LaTeX / xparse } { warning } { none } } % \end{macrocode} % \end{variable} % \end{variable} % % \begin{macrocode} % % \end{macrocode} % % \end{implementation} % % \PrintIndex