diff options
author | Karl Berry <karl@freefriends.org> | 2019-03-05 22:35:14 +0000 |
---|---|---|
committer | Karl Berry <karl@freefriends.org> | 2019-03-05 22:35:14 +0000 |
commit | 68872ff6a2a91fa0e84763fc9316493d82075c95 (patch) | |
tree | 0546ec4c414553802e31a423aec44f74d252f645 /Master/texmf-dist/source/latex/l3packages/xparse/xparse.dtx | |
parent | 541c4ddf7c5b402b9cfe8af5ef4e49ffa15d3e83 (diff) |
l3 (5mar19)
git-svn-id: svn://tug.org/texlive/trunk@50246 c570f23f-e606-0410-a88d-b1316a301751
Diffstat (limited to 'Master/texmf-dist/source/latex/l3packages/xparse/xparse.dtx')
-rw-r--r-- | Master/texmf-dist/source/latex/l3packages/xparse/xparse.dtx | 856 |
1 files changed, 554 insertions, 302 deletions
diff --git a/Master/texmf-dist/source/latex/l3packages/xparse/xparse.dtx b/Master/texmf-dist/source/latex/l3packages/xparse/xparse.dtx index 5ee7072feec..91d6a006658 100644 --- a/Master/texmf-dist/source/latex/l3packages/xparse/xparse.dtx +++ b/Master/texmf-dist/source/latex/l3packages/xparse/xparse.dtx @@ -1,10 +1,10 @@ % \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-2018 The LaTeX3 Project +%% File: xparse.dtx +% +% Copyright (C) 1999 Frank Mittelbach, Chris Rowley, David Carlisle +% (C) 2004-2008 Frank Mittelbach, The LaTeX3 Project +% (C) 2009-2019 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 @@ -67,7 +67,7 @@ % }^^A % } % -% \date{Released 2018-10-17} +% \date{Released 2019-03-05} % % \maketitle % @@ -85,18 +85,18 @@ % 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{NewDocumentCommand}\\ +% \cs{RenewDocumentCommand}\\ +% \cs{ProvideDocumentCommand}\\ +% \cs{DeclareDocumentCommand} +% \item \cs{NewDocumentEnvironment}\\ +% \cs{RenewDocumentEnvironment}\\ +% \cs{ProvideDocumentEnvironment}\\ +% \cs{DeclareDocumentEnvironment} +% \item \cs{NewExpandableDocumentCommand}\\ +% \cs{RenewExpandableDocumentCommand}\\ +% \cs{ProvideExpandableDocumentCommand}\\ +% \cs{DeclareExpandableDocumentCommand} % \item \cs{IfNoValue(TF)} % \item \cs{IfValue(TF)} % \item \cs{IfBoolean(TF)} @@ -105,7 +105,7 @@ % try all of the commands provided here, but be aware that the % experimental ones may change or disappear. % -% \subsection{Specifying arguments} +% \section{Specifying arguments} % % Before introducing the functions used to create document commands, % the method for specifying arguments with \pkg{xparse} will be @@ -126,41 +126,46 @@ % 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. +% 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} +% internal code without the outer braces. This is the \pkg{xparse} % type specifier for a normal \TeX{} argument. -% \item[r] Reads a \enquote{required} delimited argument, where the -% delimiters are given as \meta{char1} and \meta{char2}: -% \texttt{r}\meta{char1}\meta{char2}. If the opening \meta{character} -% 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{char1}\meta{char2}\marg{default}. +% \item[r] Given as \texttt{r}\meta{char1}\meta{char2}, this denotes a +% \enquote{required} delimited argument, where the delimiters are +% \meta{char1} and \meta{char2}. If the opening delimiter +% \meta{char1} is missing, the default marker |-NoValue-| will be +% inserted after a suitable error. +% \item[R] Given as \texttt{R}\meta{char1}\meta{char2}\marg{default}, +% this is a \enquote{required} delimited argument as for~\texttt{r}, +% but it has a user-definable recovery \meta{default} instead of +% |-NoValue-|. % \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 |%|, |\|, +% is read between two identical characters, 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 +% argument will produce an error when it appears within an argument of % another function. +% \item[b] Only suitable in the argument specification of an +% environment, it denotes the body of the environment, between +% |\begin|\marg{environment} and |\end|\marg{environment}. See +% Section~\ref{sec:body} for details. % \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{char1} -% and \meta{char2}, given as follows: -% \texttt{d}\meta{char1}\meta{char2}. As with \texttt{o}, if no +% \item[d] Given as \texttt{d}\meta{char1}\meta{char2}, an optional +% argument which is delimited by \meta{char1} and \meta{char2}. +% 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{char1}\meta{char2}\marg{default}. +% \item[O] Given as \texttt{O}\marg{default}, is like \texttt{o}, but +% returns \meta{default} if no value is given. +% \item[D] Given as \texttt{D}\meta{char1}\meta{char2}\marg{default}, +% it is as for \texttt{d}, but returns \meta{default} if no value is given. % 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 @@ -169,9 +174,9 @@ % \item[t] An optional \meta{char}, which will result in a value % \cs{BooleanTrue} if \meta{char} is present and \cs{BooleanFalse} % otherwise. Given as \texttt{t}\meta{char}. -% \item[e] A set of optional \emph{embellishments}, each of which -% requires a \emph{value}: \texttt{e}\marg{chars}. If an -% embellishment is not present, |-NoValue-| is returned. Each +% \item[e] Given as \texttt{e}\marg{chars}, a set of optional +% \emph{embellishments}, each of which requires a \emph{value}. +% If an embellishment is not present, |-NoValue-| is returned. Each % embellishment gives one argument, ordered as for the list of % \meta{chars} in the argument specification. All \meta{chars} % must be distinct. \emph{This is an experimental type}. @@ -217,7 +222,7 @@ % \NewDocumentCommand{\foobar}{o}{#1} % \foobar[{[}] % Allowed as the "[" is 'hidden' % \end{verbatim} -% These braces will be stripped if they surround the \emph{entire} content +% These braces will be stripped only if they surround the \emph{entire} content % of the optional argument % \begin{verbatim} % \NewDocumentCommand{\foobaz}{o}{#1} @@ -241,7 +246,7 @@ % 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}, +% mandatory. This can apply 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 @@ -313,10 +318,6 @@ % (\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 @@ -385,7 +386,107 @@ % |-NoValue-| marker as a default for |_|. This allows mixing of explicit % defaults with testing for missing values. % -% \subsection{Declaring commands and environments} +% \subsection{Body of an environment} +% \label{sec:body} +% +% While environments |\begin|\marg{environment} \dots{} +% |\end|\marg{environment} are typically used in cases where the code +% implementing the \meta{environment} does not need to access the +% contents of the environment (its \enquote{body}), it is sometimes +% useful to have the body as a standard argument. +% +% This is achieved in \pkg{xparse} by ending the argument specification +% with~\texttt{b}. The approach taken in \pkg{xparse} is +% different from the earlier packages \pkg{environ} or \pkg{newenviron}: +% the body of the environment is provided to the code part as a usual +% argument |#1|, |#2| etc.\@, rather than stored in a macro such as +% \cs[no-index]{BODY}. +% +% For instance +% \begin{verbatim} +% \NewDocumentEnvironment { twice } +% { O{\ttfamily} +b } +% {#2#1#2} {} +% \begin{twice}[\itshape] +% Hello world! +% \end{twice} +% \end{verbatim} +% typesets \enquote{Hello world!{\itshape Hello world!}}. +% +% The prefix |+| is used to allow multiple paragraphs in the +% environment's body. Argument processors can also be applied to +% \texttt{b}~arguments. +% +% By default, spaces are trimmed at both ends of the body: in the +% example there would otherwise be spaces coming from the ends the lines +% after |[\itshape]| and |world!|. Putting the prefix |!| before +% \texttt{b} suppresses space-trimming. +% +% When \texttt{b} is used in the argument specification, +% the last argument of \cs{NewDocumentEnvironment}, which consists of +% an \meta{end code} to insert at |\end|\marg{environment}, is +% redundant since one can simply put that code at the end of the +% \meta{start code}. Nevertheless this (empty) \meta{end code} must be +% provided. +% +% Environments that use this feature can be nested. +% +% Users should note that this feature is somewhat experimental. Feedback +% is therefore very welcome on the \texttt{LaTeX-L} mailing list. +% +% \subsection{Starred environments} +% +% Many packages define environments with and without \texttt{*} in their +% name, for instance \texttt{tabular} and \texttt{tabular*}. At +% present, \pkg{xparse} does not provide specific tools to define these: +% one should simply define the two environment separately, for instance +% \begin{verbatim} +% \NewDocumentEnvironment { tabular } { o +m } {...} {...} +% \NewDocumentEnvironment { tabular* } { m o +m } {...} {...} +% \end{verbatim} +% Of course the implementation of these two environments, denoted +% \enquote{\texttt{...}} in this example, can rely on the same internal +% commands. +% +% Note that this situation is different from the \texttt{s} argument +% type: if the signature of an environment starts with~\texttt{s} then +% the star is searched for after the argument of \cs{begin}. For +% instance, the following typesets \texttt{star}. +% \begin{verbatim} +% \NewDocumentEnvironment { envstar } { s } +% {\IfBooleanTF {#1} {star} {no star}} {} +% \begin{envstar}* +% \end{envstar} +% \end{verbatim} +% +% \subsection{Backwards Compatibility} +% \label{sec:backwards} +% +% One role of \pkg{xparse} is to describe existing \LaTeX{} interfaces, +% including some that are rather unusual in \LaTeX{} (as opposed to +% formats such as plain \TeX{}) such as delimited arguments. As such, +% the package defines some argument specifiers that should largely be +% avoided nowadays as using them in packages leads to inconsistent user +% interfaces. The simplest syntax is often best, with argument +% specifications such as |mmmm| or |ommmm|, namely an optional argument +% followed by some standard mandatory ones. The optional argument can +% be made to support key--value syntax using tools from \pkg{l3keys}. +% +% The argument types that are not recommended any longer are: +% \begin{itemize}[font=\ttfamily] +% \item[l] A mandatory argument which reads everything up to the first +% begin-group token: in standard \LaTeX{} this is a left brace. +% \item[u] Reads a mandatory 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[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}. +% \end{itemize} +% +% \section{Declaring commands and environments} % % With the concept of an argument specifier defined, it is now % possible to describe the methods available for creating both @@ -404,12 +505,13 @@ % \DeclareDocumentCommand % } % \begin{syntax} -% \cs{NewDocumentCommand} \meta{Function} \Arg{arg spec} \Arg{code} +% \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}. +% given by \meta{arg spec}, and the function expands to the +% \meta{code} with |#1|, |#2|, etc.\ replaced by the arguments found +% by \pkg{xparse}. % \end{function} % % As an example: @@ -467,6 +569,8 @@ % The arguments will be given following \cs{begin}\Arg{environment}. % \end{function} % +% \section{Other \pkg{xparse} commands} +% % \subsection{Testing special values} % % Optional arguments created using \pkg{xparse} make use of dedicated @@ -599,10 +703,10 @@ % % \begin{function}[updated = 2012-02-12]{\SplitArgument} % \begin{syntax} -% \cs{SplitArgument} \Arg{number} \Arg{token} +% \cs{SplitArgument} \Arg{number} \Arg{token(s)} % \end{syntax} % This processor splits the argument given at each occurrence of the -% \meta{token} up to a maximum of \meta{number} tokens (thus +% \meta{tokens} 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 @@ -615,9 +719,10 @@ % { > { \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. +% If only a single character \meta{token} is used for the split, any +% category code $13$ (active) character matching the \meta{token} will +% be replaced before the split takes place. +% Spaces are trimmed at each end of each item parsed. % \end{function} % % \begin{function}{\SplitList} @@ -633,9 +738,10 @@ % { > { \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. +% If only a single character \meta{token} is used for the split, any +% category code $13$ (active) character matching the \meta{token} will +% be replaced before the split takes place. +% Spaces are trimmed at each end of each item parsed. % \end{function} % % \begin{function}[EXP]{\ProcessList} @@ -713,7 +819,8 @@ % available: % \begin{itemize} % \item The last argument (if any are present) must be one of the -% mandatory types \texttt{m} or \texttt{r}. +% mandatory types \texttt{m}, \texttt{r}, \texttt{R}, \texttt{l} +% or~\texttt{u}. % \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. @@ -768,40 +875,13 @@ % \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 +% \texttt{false}. By default, the option is set to \texttt{false}, meaning +% that no command or environment declared is logged. By loading % \pkg{xparse} using % \begin{verbatim} -% \usepackage[log-declarations=false]{xparse} +% \usepackage[log-declarations=true]{xparse} % \end{verbatim} -% this may be suppressed and no information messages are produced. -% -% \section{Backwards Compatibility} -% \label{sec:backwards} -% -% One role of \pkg{xparse} is to describe existing \LaTeX{} interfaces, -% including some that are rather unusual in \LaTeX{} (as opposed to -% formats such as plain \TeX{}) such as delimited arguments. As such, -% the package defines some argument specifiers that should largely be -% avoided nowadays as using them in packages leads to inconsistent user -% interfaces. The simplest syntax is often best, with argument -% specifications such as |mmmm| or |ommmm|, namely an optional argument -% followed by some standard mandatory ones. The optional argument can -% be made to support key--value syntax using tools from \pkg{l3keys}. -% -% The argument types that are not recommended any longer are: -% \begin{itemize}[font=\ttfamily] -% \item[l] A mandatory argument which reads everything up to the first -% begin-group token: in standard \LaTeX{} this is a left brace. -% \item[u] Reads a mandatory 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[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}. -% \end{itemize} +% each new, declared or renewed command or environment is logged. % % \end{documentation} % @@ -818,7 +898,7 @@ % \end{macrocode} % % \begin{macrocode} -\ProvidesExplPackage{xparse}{2018-10-17}{} +\ProvidesExplPackage{xparse}{2019-03-05}{} {L3 Experimental document command parser} % \end{macrocode} % @@ -883,11 +963,19 @@ % 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. +% This variable is also used at run time to give correct error messages. % \begin{macrocode} \bool_new:N \l_@@_environment_bool % \end{macrocode} % \end{variable} % +% \begin{variable}{\l_@@_environment_str} +% Name of the environment, used at definition time and at run time. +% \begin{macrocode} +\str_new:N \l_@@_environment_str +% \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. @@ -987,15 +1075,6 @@ % \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 |+| @@ -1018,6 +1097,14 @@ % \end{macrocode} % \end{variable} % +% \begin{variable}{\l_@@_saved_args_tl} +% Stores \cs{l_@@_args_tl} to deal with space-trimming of +% \texttt{b}-type arguments. +% \begin{macrocode} +\tl_new:N \l_@@_saved_args_tl +% \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. @@ -1064,7 +1151,7 @@ % \begin{macro}{\@@_declare_cmd:Nnn, \@@_declare_expandable_cmd:Nnn} % \begin{macro}{\@@_declare_cmd_aux:Nnn} % \begin{macro} -% {\@@_declare_cmd_internal:Nnn, \@@_declare_cmd_internal:cnx} +% {\@@_declare_cmd_internal:Nnnn, \@@_declare_cmd_internal:cnxn} % The main functions for creating commands set the appropriate flag then % use the same internal code to do the definition. % \begin{macrocode} @@ -1082,7 +1169,7 @@ % 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_new_protected:Npn \@@_declare_cmd_aux:Nnn #1#2#3 { \cs_if_exist:NTF #1 { @@ -1101,22 +1188,26 @@ { \token_to_str:N #1 } { \tl_to_str:n {#2} } } \bool_set_false:N \l_@@_environment_bool - \@@_declare_cmd_internal:Nnn #1 {#2} + \@@_declare_cmd_internal:Nnnn #1 {#2} {#3} { } } % \end{macrocode} +% At definition time, the variable \cs{l_@@_fn_tl} is only used for error messages. % 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). +% shorthands. % \begin{macrocode} -\cs_new_protected:Npn \@@_declare_cmd_internal:Nnn #1#2#3 +\cs_new_protected:Npn \@@_declare_cmd_internal:Nnnn #1#2#3#4 { \tl_set:Nx \l_@@_function_tl { \cs_to_str:N #1 } + \tl_set:Nx \l_@@_fn_tl + { \exp_not:c { \l_@@_function_tl \c_space_tl } } \@@_normalize_arg_spec:n {#2} \exp_args:No \@@_prepare_signature:n \l_@@_arg_spec_tl \@@_declare_cmd_code:Nnn #1 {#2} {#3} + #4 \@@_break_point:n {#2} } -\cs_generate_variant:Nn \@@_declare_cmd_internal:Nnn { cnx } +\cs_generate_variant:Nn \@@_declare_cmd_internal:Nnnn { cnx } % \end{macrocode} % \end{macro} % \end{macro} @@ -1153,10 +1244,16 @@ \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 } + \bool_if:NTF \l_@@_environment_bool + { + \@@_start_env:nnnnn { \exp_not:n {#2} } + { \l_@@_environment_str } + } + { + \@@_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 @@ -1241,23 +1338,27 @@ % \begin{macrocode} \cs_new_protected:Npn \@@_declare_env:nnnn #1#2 { + \str_set:Nx \l_@@_environment_str {#1} + \str_set:Nx \l_@@_environment_str + { \tl_trim_spaces:o { \l_@@_environment_str } } %<*initex> - \cs_if_exist:cTF { environment~ #1 } + \cs_if_exist:cTF { environment~ \l_@@_environment_str } %</initex> %<*package> - \cs_if_exist:cTF {#1} + \cs_if_exist:cTF { \l_@@_environment_str } %</package> { \__kernel_msg_info:nnxx { xparse } { redefine-environment } - {#1} { \tl_to_str:n {#2} } + { \l_@@_environment_str } { \tl_to_str:n {#2} } } { \__kernel_msg_info:nnxx { xparse } { define-environment } - {#1} { \tl_to_str:n {#2} } + { \l_@@_environment_str } { \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} + \exp_args:NV \@@_declare_env_internal:nnnn + \l_@@_environment_str {#2} } % \end{macrocode} % Creating a document environment requires a few more steps than creating @@ -1267,10 +1368,16 @@ % 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. +% The last argument of \cs{@@_declare_cmd_internal:Nnnn} is only run +% if the definition succeeded. In package mode this ensures that the +% original definition of the environment is not changed if the +% definition fails for any reason. This also avoids an error when +% defining the \verb*|end aux | function when the user asks for more +% than $9$ arguments. % \begin{macrocode} \cs_new_protected:Npn \@@_declare_env_internal:nnnn #1#2#3#4 { - \@@_declare_cmd_internal:cnx { environment~ #1 } {#2} + \@@_declare_cmd_internal:cnxn { environment~ #1 } {#2} { \cs_set_nopar:Npx \exp_not:c { environment~ #1 ~end~aux } { @@ -1279,15 +1386,17 @@ } \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} + { + \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 } + \cs_set_eq:cc {#1} { environment~ #1 } + \cs_set_eq:cc { end #1 } { environment~ #1 ~end } %</package> + } } % \end{macrocode} % \end{macro} @@ -1295,32 +1404,52 @@ % % \subsection{Structure of \pkg{xparse} commands} % -% \begin{macro}{\@@_start:nNNnnn} -% \begin{macro}{\@@_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{macro}{\@@_start_env:nnnnn, \@@_start:nNNnnn} +% For error messages that occur during run-time when getting arguments +% of environments it is necessary to keep track of the environment +% name. We begin non-expandable commands with a token equal to +% \cs{scan_stop:}, whose name gives a reasonable error message if the +% command is used inside a csname and protects against +% \texttt{f}-expansion. This is useless for environments since +% \cs{begin} is already not expandable. % \begin{macrocode} -\cs_new_protected:Npx \@@_start:nNNnnn +\cs_new_protected:Npn \@@_start_env:nnnnn #1#2 + { + \str_set:Nn \l_@@_environment_str {#2} + \bool_set_true:N \l_@@_environment_bool + \@@_start_aux:ccnnnn + { environment~ \l_@@_environment_str \c_space_tl } + { environment~ \l_@@_environment_str \c_space_tl code } + {#1} + } +\cs_new_protected:Npx \@@_start:nNNnnn #1#2#3 { \exp_not:c { xparse~function~is~not~expandable } - \exp_not:N \@@_start_aux:nNNnnn + \exp_not:n { \bool_set_false:N \l_@@_environment_bool } + \exp_not:N \@@_start_aux:NNnnnn + #2 #3 {#1} } -\cs_new_protected:Npn \@@_start_aux:nNNnnn #1#2#3#4#5#6 +% \end{macrocode} +% \end{macro} +% +% \begin{macro}{\@@_start_aux:NNnnnn, \@@_start_aux:ccnnnn} +% 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. +% \begin{macrocode} +\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_@@_fn_tl {#1} + \tl_set:Nn \l_@@_fn_code_tl {#2} \tl_set:Nn \l_@@_defaults_tl {#5} \tl_set:Nn \l_@@_process_all_tl {#6} #4 \@@_run_code: } +\cs_generate_variant:Nn \@@_start_aux:NNnnnn { cc } % \end{macrocode} % \end{macro} -% \end{macro} % % \begin{macro}{\@@_run_code:} % After arguments are grabbed, this function is responsible for @@ -1369,7 +1498,7 @@ \cs_new_protected:Npn \@@_defaults_error:w \q_recursion_stop { \__kernel_msg_error:nnx { xparse } { loop-in-defaults } - { \exp_after:wN \token_to_str:N \l_@@_fn_tl } + { \@@_environment_or_command: } } % \end{macrocode} % To construct \cs{@@_tmp:w}, first go through the arguments @@ -1485,8 +1614,9 @@ \@@_end_expandable_defaults:nnnNNn {#1} { } {#1} #2#3 { } { } { } { } { } { } { } { } { } { } { - \__kernel_msg_expandable_error:nnn - { xparse } { loop-in-defaults } {#4} + \__kernel_msg_expandable_error:nnf + { xparse } { loop-in-defaults } + { \exp_args:Nf \tl_trim_spaces:n { \token_to_str:N #4 } } \use_iv:nnnn } \q_stop @@ -1552,8 +1682,6 @@ % 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). -% \item Count mandatory arguments, used later to detect which optional -% arguments are trailing. % \end{itemize} % Further checks happen at the end of the loop: % \begin{itemize} @@ -1572,7 +1700,6 @@ % \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 @@ -1587,7 +1714,7 @@ \int_compare:nNnT \l_@@_current_arg_int > 9 { \__kernel_msg_error:nnxx { xparse } { too-many-arguments } - { \iow_char:N \\ \l_@@_function_tl } { \tl_to_str:n {#1} } + { \@@_environment_or_command: } { \tl_to_str:n {#1} } \@@_bad_def:wn } \bool_if:NT \l_@@_expandable_bool @@ -1611,7 +1738,7 @@ \cs_if_exist_use:cF { @@_normalize_type_ \tl_to_str:n {#1} :w } { \__kernel_msg_error:nnxx { xparse } { unknown-argument-type } - { \iow_char:N \\ \l_@@_function_tl } { \tl_to_str:n {#1} } + { \@@_environment_or_command: } { \tl_to_str:n {#1} } \@@_bad_def:wn } } @@ -1699,7 +1826,7 @@ \bool_if:NT \l_@@_long_bool { \__kernel_msg_error:nnxx { xparse } { two-markers } - { \iow_char:N \\ \l_@@_function_tl } { + } + { \@@_environment_or_command: } { + } \@@_bad_def:wn } \bool_set_true:N \l_@@_long_bool @@ -1712,7 +1839,7 @@ \bool_if:NT \l_@@_obey_spaces_bool { \__kernel_msg_error:nnxx { xparse } { two-markers } - { \iow_char:N \\ \l_@@_function_tl } { ! } + { \@@_environment_or_command: } { ! } \@@_bad_def:wn } \bool_set_true:N \l_@@_obey_spaces_bool @@ -1857,6 +1984,31 @@ % \end{macrocode} % \end{macro} % +% \begin{macro}{\@@_normalize_type_b:w} +% This argument type is not allowed for commands. This is only +% allowed at the end of the argument specification, hence we check +% that |#1| is the end. +% \begin{macrocode} +\cs_new_protected:Npn \@@_normalize_type_b:w #1 + { + \bool_if:NF \l_@@_environment_bool + { + \__kernel_msg_error:nnxx + { xparse } { invalid-command-arg } + { \@@_environment_or_command: } { b } + \@@_bad_def:wn + } + \tl_clear:N \l_@@_last_delimiters_tl + \@@_add_arg_spec:n { b } + \quark_if_recursion_tail_stop:n {#1} + \__kernel_msg_error:nnxx { xparse } { arg-after-body } + { \@@_environment_or_command: } + { \tl_to_str:n {#1} } + \@@_bad_def:wn + } +% \end{macrocode} +% \end{macro} +% % \begin{macro}{\@@_single_char_check:n} % Checks that what should be single characters really are single % characters (possibly surrounded by spaces). @@ -1871,13 +2023,13 @@ { \exp_args:No \tl_to_str:n { \use:nn #1 { } } } { \__kernel_msg_warning:nnxx { xparse } { not-single-char } - { \iow_char:N \\ \l_@@_function_tl } { \tl_to_str:n {#1} } + { \@@_environment_or_command: } { \tl_to_str:n {#1} } } \group_end: } { \__kernel_msg_error:nnxx { xparse } { not-single-char } - { \iow_char:N \\ \l_@@_function_tl } { \tl_to_str:n {#1} } + { \@@_environment_or_command: } { \tl_to_str:n {#1} } \@@_bad_def:wn } } @@ -1942,7 +2094,7 @@ \cs_new_protected:Npn \@@_bad_arg_spec:wn #1 \@@_break_point:n #2 { \__kernel_msg_error:nnxx { xparse } { bad-arg-spec } - { \iow_char:N \\ \l_@@_function_tl } { \tl_to_str:n {#2} } + { \@@_environment_or_command: } { \tl_to_str:n {#2} } } \cs_new_protected:Npn \@@_bad_def:wn #1 \@@_break_point:n #2 { } % \end{macrocode} @@ -1990,10 +2142,9 @@ \bool_if:NT \l_@@_some_obey_spaces_bool { \__kernel_msg_error:nnxx { xparse } { non-trailing-obey-spaces } - { \iow_char:N \\ \l_@@_function_tl } { \tl_to_str:n {#1} } + { \@@_environment_or_command: } { \tl_to_str:n {#1} } \@@_bad_def:wn } - \int_incr:N \l_@@_mandatory_args_int \tl_clear:N \l_@@_last_delimiters_tl \@@_add_arg_spec:n {#1} } @@ -2033,8 +2184,7 @@ % % 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. +% standard functions, as the approaches are different. % \begin{macrocode} \cs_new_protected:Npn \@@_prepare_signature:N { @@ -2098,7 +2248,7 @@ % % \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, +% used by \cs{@@_args_process:} once arguments are all found. Here too % the loop calls \cs{@@_prepare_signature_bypass:N} rather than % \cs{@@_prepare_signature:N} so that the flag is not reset. % \begin{macrocode} @@ -2113,13 +2263,25 @@ % \end{macrocode} % \end{macro} % +% \begin{macro}{\@@_add_type_b:w} +% \begin{macrocode} +\cs_new_protected:Npn \@@_add_type_b:w + { + \@@_flush_m_args: + \@@_add_default: + \@@_add_grabber:N b + \@@_prepare_signature: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 + \@@_add_grabber:N D \tl_put_right:Nn \l_@@_signature_tl { #1 #2 } \@@_prepare_signature:N } @@ -2134,7 +2296,7 @@ { \@@_flush_m_args: \@@_add_default_E:nn {#1} {#2} - \@@_add_grabber_optional:N E + \@@_add_grabber:N E \tl_put_right:Nn \l_@@_signature_tl { {#1} } \@@_prepare_signature:N } @@ -2149,7 +2311,7 @@ { \@@_flush_m_args: \@@_add_default:n {#1} - \@@_add_grabber_optional:N G + \@@_add_grabber:N G \@@_prepare_signature:N } % \end{macrocode} @@ -2163,7 +2325,7 @@ { \@@_flush_m_args: \@@_add_default: - \@@_add_grabber_mandatory:N l + \@@_add_grabber:N l \@@_prepare_signature:N } % \end{macrocode} @@ -2181,7 +2343,7 @@ { \@@_add_default: \bool_if:NTF \l_@@_prefixed_bool - { \@@_add_grabber_mandatory:N m } + { \@@_add_grabber:N m } { \int_incr:N \l_@@_m_args_int } \@@_prepare_signature:N } @@ -2195,7 +2357,7 @@ { \@@_flush_m_args: \@@_add_default:n {#3} - \@@_add_grabber_mandatory:N R + \@@_add_grabber:N R \tl_put_right:Nn \l_@@_signature_tl { #1 #2 } \@@_prepare_signature:N } @@ -2210,7 +2372,7 @@ { \@@_flush_m_args: \@@_add_default: - \@@_add_grabber_optional:N t + \@@_add_grabber:N t \tl_put_right:Nn \l_@@_signature_tl {#1} \@@_prepare_signature:N } @@ -2225,7 +2387,7 @@ { \@@_flush_m_args: \@@_add_default: - \@@_add_grabber_mandatory:N u + \@@_add_grabber:N u \tl_put_right:Nn \l_@@_signature_tl { {#1} } \@@_prepare_signature:N } @@ -2241,7 +2403,7 @@ { \@@_flush_m_args: \exp_args:No \@@_add_default:n \c_novalue_tl - \@@_add_grabber_mandatory:N v + \@@_add_grabber:N v \@@_prepare_signature:N } % \end{macrocode} @@ -2251,9 +2413,7 @@ % 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. +% be switched here. % \begin{macrocode} \cs_new_protected:Npn \@@_flush_m_args: { @@ -2261,7 +2421,6 @@ { \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 } { { } } } } @@ -2270,8 +2429,7 @@ % \end{macrocode} % \end{macro} % -% \begin{macro}{\@@_add_grabber_mandatory:N} -% \begin{macro}{\@@_add_grabber_optional:N} +% \begin{macro}{\@@_add_grabber:N} % To keep the various checks needed in one place, adding the grabber % to the signature is done here. The only questions are whether the % grabber should be long or not, and whether to obey spaces. The @@ -2279,12 +2437,7 @@ % trailing optional arguments. In that case spaces will not be % ignored when looking for that optional argument. % \begin{macrocode} -\cs_new_protected:Npn \@@_add_grabber_mandatory:N #1 - { - \@@_add_grabber_optional:N #1 - \int_decr:N \l_@@_mandatory_args_int - } -\cs_new_protected:Npn \@@_add_grabber_optional:N #1 +\cs_new_protected:Npn \@@_add_grabber:N #1 { \tl_put_right:Nx \l_@@_signature_tl { @@ -2304,7 +2457,6 @@ } % \end{macrocode} % \end{macro} -% \end{macro} % % \begin{macro}{\@@_add_default:n, \@@_add_default:, \@@_add_default_E:nn} % Store the default value of an argument, or rather code that gives @@ -2593,6 +2745,60 @@ % calls \cs{@@_add_arg:n}, responsible for calling processors and % grabbing further arguments. % +% \begin{macro} +% { +% \@@_grab_b:w, +% \@@_grab_b_long:w, +% \@@_grab_b_obey_spaces:w, +% \@@_grab_b_long_obey_spaces:w, +% \@@_grab_b_aux:NNw, +% \@@_grab_b_end:Nw +% } +% This uses the well-tested code of \texttt{D}-type arguments, +% skipping the peeking step because the \texttt{b}-type argument is +% always present, and adding a cleanup stage at the end by hijacking +% the signature. The clean-up consists of properly +% dealing with \cs{l_@@_args_tl} and also putting back the \cs{end} +% that served as an end-delimiter: this \cs{end} receives the +% environment name as its argument and is run normally. The +% \texttt{D}-type code stores the argument found (body of the +% environment) as a brace group in \cs{l_@@_args_tl} and depending on +% the presence of a prefix~|!| we trim spaces or not before adding +% this braced argument into the saved \cs{l_@@_args_tl}. +% The strange \verb*|\begin | control sequence is there for display +% purposes only: it has to look like |\begin| in the terminal but +% not to delimited arguments. +% \begin{macrocode} +\cs_new_protected:Npn \@@_grab_b:w + { \@@_grab_b_aux:NNw \cs_set_protected_nopar:Npn \tl_trim_spaces:n } +\cs_new_protected:Npn \@@_grab_b_long:w + { \@@_grab_b_aux:NNw \cs_set_protected:Npn \tl_trim_spaces:n } +\cs_new_protected:Npn \@@_grab_b_obey_spaces:w + { \@@_grab_b_aux:NNw \cs_set_protected_nopar:Npn \exp_not:n } +\cs_new_protected:Npn \@@_grab_b_long_obey_spaces:w + { \@@_grab_b_aux:NNw \cs_set_protected:Npn \exp_not:n } +\cs_new_protected:Npn \@@_grab_b_aux:NNw #1#2#3 \@@_run_code: + { + \@@_grab_D_aux:NNnN \begin \end {#3} #1 + \tl_put_left:Nn \l_@@_signature_tl { \@@_grab_b_end:Nw #2 } + \tl_set_eq:NN \l_@@_saved_args_tl \l_@@_args_tl + \tl_clear:N \l_@@_args_tl + \exp_args:Nc \l_@@_fn_tl { begin ~ } + } +\cs_new_protected:Npn \@@_grab_b_end:Nw #1#2 \@@_run_code: + { + \tl_set:Nx \l_@@_args_tl + { + \exp_not:V \l_@@_saved_args_tl + { \exp_after:wN #1 \l_@@_args_tl } + } + #2 + \@@_run_code: + \end + } +% \end{macrocode} +% \end{macro} +% % \begin{macro}{\@@_grab_D:w} % \begin{macro}{\@@_grab_D_long:w} % \begin{macro}{\@@_grab_D_obey_spaces:w} @@ -3037,7 +3243,7 @@ { \@@_grab_D_call:Nw #1 } { \__kernel_msg_error:nnxx { xparse } { missing-required } - { \exp_after:wN \token_to_str:N \l_@@_fn_tl } + { \@@_environment_or_command: } { \token_to_str:N #1 } \@@_add_arg:o \c_novalue_tl } @@ -3316,14 +3522,14 @@ \peek_meaning_remove:NTF \char_generate:nn { \tex_endlinechar:D } { 6 } { \__kernel_msg_error:nnxxx { xparse } { verbatim-newline } - { \exp_after:wN \token_to_str:N \l_@@_fn_tl } + { \@@_environment_or_command: } { \tl_to_str:N \l_@@_v_arg_tl } { \tl_to_str:n {#1} } \@@_add_arg:o \c_novalue_tl } { \__kernel_msg_error:nnxxx { xparse } { verbatim-tokenized } - { \exp_after:wN \token_to_str:N \l_@@_fn_tl } + { \@@_environment_or_command: } { \tl_to_str:N \l_@@_v_arg_tl } { \tl_to_str:n {#1} } \@@_add_arg:o \c_novalue_tl @@ -3673,8 +3879,10 @@ \q_nil { } ##2 \ERROR \q_@@ \ERROR } { - \__kernel_msg_expandable_error:nnnn - { xparse } { missing-required } {##5} {##2} + \__kernel_msg_expandable_error:nnff + { xparse } { missing-required } + { \exp_args:Nf \tl_trim_spaces:n { \token_to_str:N ##5 } } + { \tl_to_str:n {##2} } ##4 {#1} \q_@@ ##5 ##6 {##7} } } @@ -3709,8 +3917,10 @@ ##6 \ERROR } { - \__kernel_msg_expandable_error:nnnn - { xparse } { missing-required } {##4} {##2} + \__kernel_msg_expandable_error:nnff + { xparse } { missing-required } + { \exp_args:Nf \tl_trim_spaces:n { \token_to_str:N ##4 } } + { \tl_to_str:n {##2} } ##3 {#1} \q_@@ ##4 ##5 {##6} } } @@ -3891,35 +4101,38 @@ % \subsection{Access to the argument specification} % % \begin{macro}{\@@_get_arg_spec_error:N, \@@_get_arg_spec_error:n} +% \begin{macro}{\@@_get_arg_spec_error_aux: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 - { - \__kernel_msg_error:nnx { xparse } { non-xparse-command } - { \token_to_str:N #1 } - } - { - \__kernel_msg_error:nnx { xparse } { unknown-command } - { \token_to_str:N #1 } - } + \bool_set_false:N \l_@@_environment_bool + \tl_set:Nn \l_@@_fn_tl {#1} + \@@_get_arg_spec_error_aux:n { \cs_if_exist:NTF #1 } } \cs_new_protected:Npn \@@_get_arg_spec_error:n #1 { - \cs_if_exist:cTF {#1} + \bool_set_true:N \l_@@_environment_bool + \str_set:Nx \l_@@_environment_str {#1} + \@@_get_arg_spec_error_aux:n + { \cs_if_exist:cTF { \l_@@_environment_str } } + } +\cs_new_protected:Npn \@@_get_arg_spec_error_aux:n #1 + { + #1 { - \__kernel_msg_error:nnx { xparse } { non-xparse-environment } - { \tl_to_str:n {#1} } + \__kernel_msg_error:nnx { xparse } { non-xparse } + { \@@_environment_or_command: } } { - \__kernel_msg_error:nnx { xparse } { unknown-environment } - { \tl_to_str:n {#1} } + \__kernel_msg_error:nnx { xparse } { unknown } + { \@@_environment_or_command: } } } % \end{macrocode} % \end{macro} +% \end{macro} % % \begin{macro}{\@@_get_arg_spec:NTF} % If the command is not an \pkg{xparse} command, complain. If it is, @@ -4076,21 +4289,22 @@ % 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). +% (expandable command) or \cs{@@_start_env:nnnnn} (environment). % \begin{macrocode} \cs_new_protected:Npn \@@_cmd_if_xparse:NTF #1 { \exp_args:Nf \str_case_e:nnTF { - \exp_args:Nf \tl_if_empty:nT { \token_get_arg_spec:N #1 } + \exp_args:Nf \tl_if_empty:nT { \cs_argument_spec:N #1 } { \exp_last_unbraced:Nf \@@_cmd_if_xparse_aux:w - { \token_get_replacement_spec:N #1 } ~ \q_stop + { \cs_replacement_spec:N #1 } ~ \q_stop } } { { \token_to_str:N \@@_start:nNNnnn } { } { \token_to_str:N \@@_start_expandable:nNNNNn } { } + { \token_to_str:N \@@_start_env:nnnnn } { } } } \cs_new:Npn \@@_cmd_if_xparse_aux:w #1 ~ #2 \q_stop {#1} @@ -4117,42 +4331,70 @@ % % \subsection{Messages} % -% Some messages intended as errors. +% \begin{macro}{\@@_environment_or_command:} +% \begin{variable}{\c_@@_ignore_def_tl} +% Two texts used in several messages. +% \begin{macrocode} +\cs_new:Npn \@@_environment_or_command: + { + \bool_if:NTF \l_@@_environment_bool + { environment ~ ' \l_@@_environment_str ' } + { + command ~ ' + \exp_args:Nf \tl_trim_spaces:n + { \exp_after:wN \token_to_str:N \l_@@_fn_tl } + ' + } + } +\tl_const:Nn \c_@@_ignore_def_tl + { \\ \\ LaTeX~will~ignore~this~entire~definition. } +% \end{macrocode} +% \end{variable} +% \end{macro} +% +% Some messages intended as errors when defining commands/environments. % \begin{macrocode} +\__kernel_msg_new:nnnn { xparse } { arg-after-body } + { In~the~definition~of~#1,~b~(body)~argument~must~be~last. } + { + The~'body'~argument~type~is~followed~by~'#2'~in~the~argument~ + specification~of~the~#1.~This~is~not~allowed. + \c_@@_ignore_def_tl + } \__kernel_msg_new:nnnn { xparse } { bad-arg-spec } - { Bad~argument~specification~'#2'~for~command~'#1'. } + { Bad~argument~specification~'#2'~for~#1. } { The~argument~specification~provided~was~not~valid:~ - one~or~more~mandatory~pieces~of~information~were~missing. \\ \\ - LaTeX~will~ignore~this~entire~definition. + one~or~more~mandatory~pieces~of~information~were~missing. + \c_@@_ignore_def_tl } \__kernel_msg_new:nnnn { xparse } { command-already-defined } { Command~'#1'~already~defined! } { You~have~used~#2~ - with~a~command~that~already~has~a~definition. \\ + with~a~command~that~already~has~a~definition. \\ \\ The~existing~definition~of~'#1'~will~not~be~altered. } \__kernel_msg_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. + with~a~command~that~was~never~defined. + \c_@@_ignore_def_tl } \__kernel_msg_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. + with~an~environment~that~already~has~a~definition. \\ \\ + The~existing~definition~of~'#1'~will~not~be~altered. } \__kernel_msg_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. + with~an~environment~that~was~never~defined. + \c_@@_ignore_def_tl } \__kernel_msg_new:nnnn { xparse } { expandable-ending-optional } { @@ -4164,25 +4406,26 @@ (or~no~arguments~at~all).~You~cannot~have~a~terminal~optional~ argument~with~expandable~commands. } -\__kernel_msg_new:nnnn { xparse } { if-boolean } - { Invalid~use~\iow_char:N\\IfBooleanTF~{#1} } - { - The~first~argument~of~\iow_char:N\\IfBoolean(TF/T/F)~must~be~ - a~boolean~argument~obtained~from~parsing~'s'~or~'t'~arguments. - } \__kernel_msg_new:nnnn { xparse } { inconsistent-long } { Inconsistent~long~arguments~for~expandable~command~'#1'. } { The~arguments~for~an~expandable~command~must~not~involve~short~ arguments~after~long~arguments.~You~have~tried~to~mix~the~two~types. } +\__kernel_msg_new:nnnn { xparse } { invalid-command-arg } + { Argument~type~'#2'~not~available~for~#1. } + { + The~letter~'#2'~can~only~be~used~in~environment~argument~ + specifications,~not~for~commands. + \\ \\ + LaTeX~will~ignore~this~entire~definition. + } \__kernel_msg_new:nnnn { xparse } { invalid-expandable-argument-type } { Argument~type~'#2'~not~available~for~expandable~command~'#1'. } { - The~letter~'#2'~does~not~specify~an~argument~type~which~can~be~used~ + The~letter~'#2'~specifies~an~argument~type~which~cannot~be~used~ in~an~expandable~command. - \\ \\ - LaTeX~will~ignore~this~entire~definition. + \c_@@_ignore_def_tl } \__kernel_msg_new:nnnn { xparse } { invalid-after-optional-expandably } { @@ -4190,41 +4433,15 @@ for~expandable~command~'#1'. } { - The~letter~'#2'~does~not~specify~an~argument~type~which~can~be~used~ + The~letter~'#2'~specifies~an~argument~type~which~cannot~be~used~ in~an~expandable~command~after~an~optional~argument. - \\ \\ - LaTeX~will~ignore~this~entire~definition. - } -\__kernel_msg_new:nnnn { xparse } { loop-in-defaults } - { Circular~dependency~in~defaults~of~'#1'. } - { - The~default~values~of~two~or~more~arguments~of~'#1'~depend~on~each~ - other~in~a~way~that~cannot~be~resolved. - } -\__kernel_msg_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. + \c_@@_ignore_def_tl } \__kernel_msg_new:nnnn { xparse } { non-trailing-obey-spaces } - { Prefix~'!'~used~before~mandatory~argument~'#2'~of~command~'#1'. } + { Prefix~'!'~used~before~mandatory~argument~'#2'~of~#1. } { The~prefix~'!'~can~only~apply~to~trailing~optional~arguments. - \\ \\ - LaTeX~will~ignore~this~entire~definition. - } -\__kernel_msg_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. - } -\__kernel_msg_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. + \c_@@_ignore_def_tl } \__kernel_msg_new:nnnn { xparse } { not-definable } { First~argument~of~'#2'~must~be~a~command. } @@ -4232,89 +4449,106 @@ 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. + \c_@@_ignore_def_tl } \__kernel_msg_new:nnnn { xparse } { not-one-token } { First~argument~of~'#2'~must~be~a~command. } { 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. + token.~Perhaps~a~backslash~is~missing? + \c_@@_ignore_def_tl } \__kernel_msg_new:nnnn { xparse } { not-single-char } { - Argument~delimiter~'#2'~for~the~command~'#1'~should~be~ + Argument~delimiter~'#2'~for~the~#1~should~be~ a~single~character. } { The~argument~specification~provided~was~not~valid:~in~a~place~ - where~a~single~character~is~required,~LaTeX~found~'#2'. \\ \\ - LaTeX~will~ignore~this~entire~definition. + where~a~single~character~is~required,~LaTeX~found~'#2'. + \c_@@_ignore_def_tl } \__kernel_msg_new:nnnn { xparse } { processor-in-expandable } { Argument~processor~'>{#2}'~cannot~be~used~for~the~expandable~command~'#1'. } { The~argument~specification~for~#1~contains~a~processor~function:~ - this~is~only~supported~for~standard~robust~commands. \\ \\ - LaTeX~will~ignore~this~entire~definition. - } -\__kernel_msg_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. + this~is~only~supported~for~standard~robust~commands. + \c_@@_ignore_def_tl } \__kernel_msg_new:nnnn { xparse } { too-many-arguments } - { Too~many~arguments~in~argument~specification~'#2'~of~command~'#1'. } + { Too~many~arguments~in~argument~specification~'#2'~of~#1. } { The~argument~specification~provided~has~more~than~9~arguments.~ - This~cannot~be~implemented. \\ \\ - LaTeX~will~ignore~this~entire~definition. + This~cannot~be~implemented. + \c_@@_ignore_def_tl } \__kernel_msg_new:nnnn { xparse } { two-markers } - { Two~'#2'~apply~to~the~same~argument~in~argument~specification~of~command~'#1'. } + { Two~'#2'~apply~to~the~same~argument~in~argument~specification~of~#1. } { The~argument~specification~provided~has~two~markers~'#2'~applying~ to~the~same~argument;~these~are~redundant. } \__kernel_msg_new:nnnn { xparse } { unknown-argument-type } - { Unknown~argument~type~'#2'~for~the~command~'#1'. } + { Unknown~argument~type~'#2'~for~the~#1. } { - The~letter~'#2'~does~not~specify~a~known~argument~type.~ - LaTeX~will~ignore~this~entire~definition. + The~letter~'#2'~does~not~specify~a~known~argument~type. + \c_@@_ignore_def_tl + } +% \end{macrocode} +% +% Errors when using commands/environments. The \texttt{if-boolean} +% message is always used in expandable errors. The +% \texttt{loop-in-defaults} and \texttt{missing-required} messages can +% be expandable or not expandable. +% \begin{macrocode} +\__kernel_msg_new:nnn { xparse } { if-boolean } + { Invalid~use~\iow_char:N\\IfBooleanTF~{#1} } +\__kernel_msg_new:nnnn { xparse } { loop-in-defaults } + { Defaults~of~#1~have~circular~dependency. } + { + The~default~values~of~two~or~more~arguments~of~the~#1~ + depend~on~each~other~in~a~way~that~cannot~be~resolved. } -\__kernel_msg_new:nnnn { xparse } { unknown-command } - { Unknown~document~command~'#1'. } +\__kernel_msg_new:nnnn { xparse } { missing-required } + { Missing~required~argument~for~#1. } { - You~have~asked~for~the~argument~specification~for~a~command~'#1',~ - but~it~is~not~defined. + The~current~#1~expects~an~argument~starting~with~'#2'.~ + LaTeX~did~not~find~it,~and~will~insert~a~default~value~to~be~processed. } -\__kernel_msg_new:nnnn { xparse } { unknown-environment } - { Unknown~document~environment~'#1'. } +\__kernel_msg_new:nnnn { xparse } { non-xparse } + { \str_upper_case:n #1~not~defined~using~xparse. } { - You~have~asked~for~the~argument~specification~for~an~environment~'#1',~ + You~have~asked~for~the~argument~specification~for~the~#1,~ + but~this~was~not~defined~using~xparse. + } +\__kernel_msg_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. + } +\__kernel_msg_new:nnnn { xparse } { unknown } + { Unknown~document~#1. } + { + You~have~asked~for~the~argument~specification~for~the~#1,~ but~it~is~not~defined. } \__kernel_msg_new:nnnn { xparse } { verbatim-newline } - { Verbatim~argument~of~'#1'~ended~by~end~of~line. } + { Verbatim~argument~of~#1~ended~by~end~of~line. } { - The~verbatim~argument~of~'#1'~cannot~contain~more~than~one~line,~ + The~verbatim~argument~of~the~#1~cannot~contain~more~than~one~line,~ but~the~end~ - of~the~current~line~has~been~reached.~You~have~probably~forgotten~the~ + of~the~current~line~has~been~reached.~You~may~have~forgotten~the~ closing~delimiter. \\ \\ LaTeX~will~ignore~'#2'. } \__kernel_msg_new:nnnn { xparse } { verbatim-tokenized } + { The~verbatim~#1~cannot~be~used~inside~an~argument. } { - The~verbatim~command~'#1'~cannot~be~used~inside~an~argument.~ - } - { - The~command~'#1'~takes~a~verbatim~argument.~ + The~#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' } . \\ \\ @@ -4435,7 +4669,7 @@ \cs_if_exist:cTF {#1} { \__kernel_msg_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} @@ -4456,7 +4690,10 @@ % \begin{macro}{\RenewExpandableDocumentCommand} % \begin{macro}{\ProvideExpandableDocumentCommand} % \begin{macro}{\DeclareExpandableDocumentCommand} -% The expandable versions are essentially the same as the basic functions. +% The expandable versions are essentially the same as the basic +% functions. The strange \cs{use:nnn} is there in case |#1| is +% surrounded with spaces, as can happen with usual document catcodes +% in \cs{RenewExpandableDocumentCommand} |{| |\!| |}| \ldots{} % \begin{macrocode} \cs_new_protected:Npn \NewExpandableDocumentCommand #1#2#3 { @@ -4505,19 +4742,34 @@ % % \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}. +% normal \cs{c_true_bool} and \cs{c_false_bool} so \cs{bool_if:NTF} is +% almost enough. However, this code-level function blows up badly +% when passed invalid input. We want \cs{IfBooleanTF} to accept a +% single (non-space) token equal to \cs{c_true_bool} or +% \cs{c_false_bool}, possibly surrounded by spaces. If the input is +% blank or multiple items, jump to the error and pick the false +% branch. If the input, ignoring spaces (we do this by omitting +% braces in the \cs{tl_if_single_token:nF} test), is not a single +% token then jump to the error as well. It is then safe to compare +% the token to the two booleans, picking the appropriate branch. If +% neither matches, we jump to the error as well. % \begin{macrocode} \cs_new:Npn \IfBooleanTF #1 { - \bool_lazy_and:nnTF - { \tl_if_single_p:n {#1} } - { \tl_if_single_token_p:n #1 } - { \bool_if:NTF #1 } - { - \__kernel_msg_error:nnn { xparse } { if-boolean } {#1} - \use_ii:nn - } + \tl_if_single:nF {#1} + { \prg_break:n { \use:n } } + \tl_if_single_token:nF #1 + { \prg_break:n { \use:n } } + \token_if_eq_meaning:NNT #1 \c_true_bool + { \prg_break:n { \use_ii:nnn } } + \token_if_eq_meaning:NNT #1 \c_false_bool + { \prg_break:n { \use_iii:nnn } } + \prg_break:n { \use:n } + \prg_break_point: + { + \__kernel_msg_expandable_error:nnn { xparse } { if-boolean } {#1} + \use_ii:nn + } } \cs_new:Npn \IfBooleanT #1#2 { \IfBooleanTF {#1} {#2} { } } \cs_new:Npn \IfBooleanF #1 { \IfBooleanTF {#1} { } } |