summaryrefslogtreecommitdiff
path: root/Master/texmf-dist/source/latex/l3packages
diff options
context:
space:
mode:
authorKarl Berry <karl@freefriends.org>2017-03-08 23:01:35 +0000
committerKarl Berry <karl@freefriends.org>2017-03-08 23:01:35 +0000
commit6fca20c09474a7f6a3559af1c984243a83669f61 (patch)
treecbfda048c91853241ef903a84a088c1e3a66fd50 /Master/texmf-dist/source/latex/l3packages
parentddbc1f2a5f193876d6f1df544e286029c6d671f8 (diff)
l3 (8mar17)
git-svn-id: svn://tug.org/texlive/trunk@43432 c570f23f-e606-0410-a88d-b1316a301751
Diffstat (limited to 'Master/texmf-dist/source/latex/l3packages')
-rw-r--r--Master/texmf-dist/source/latex/l3packages/l3keys2e/l3keys2e.dtx8
-rw-r--r--Master/texmf-dist/source/latex/l3packages/xfp/xfp.dtx167
-rw-r--r--Master/texmf-dist/source/latex/l3packages/xfp/xfp.ins45
-rw-r--r--Master/texmf-dist/source/latex/l3packages/xfrac/xfrac.dtx8
-rw-r--r--Master/texmf-dist/source/latex/l3packages/xparse/xparse.dtx894
-rw-r--r--Master/texmf-dist/source/latex/l3packages/xtemplate/xtemplate.dtx22
6 files changed, 805 insertions, 339 deletions
diff --git a/Master/texmf-dist/source/latex/l3packages/l3keys2e/l3keys2e.dtx b/Master/texmf-dist/source/latex/l3packages/l3keys2e/l3keys2e.dtx
index 9c895dd3b24..4217a5917b6 100644
--- a/Master/texmf-dist/source/latex/l3packages/l3keys2e/l3keys2e.dtx
+++ b/Master/texmf-dist/source/latex/l3packages/l3keys2e/l3keys2e.dtx
@@ -23,8 +23,8 @@
%<*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/02/10]
-%<package>\@ifpackagelater{expl3}{2017/02/10}
+\RequirePackage{expl3}[2017/03/07]
+%<package>\@ifpackagelater{expl3}{2017/03/07}
%<package> {}
%<package> {%
%<package> \PackageError{l3keys2e}{Support package l3kernel too old}
@@ -38,8 +38,8 @@
%<package> }
\def\ExplFileName{l3keys2e}
\def\ExplFileDescription{LaTeX2e option processing using LaTeX3 keys}
-\def\ExplFileDate{2017/02/10}
-\def\ExplFileVersion{6878}
+\def\ExplFileDate{2017/03/07}
+\def\ExplFileVersion{6984}
%</driver|package>
%<*driver>
\documentclass[full]{l3doc}
diff --git a/Master/texmf-dist/source/latex/l3packages/xfp/xfp.dtx b/Master/texmf-dist/source/latex/l3packages/xfp/xfp.dtx
new file mode 100644
index 00000000000..46d1becb514
--- /dev/null
+++ b/Master/texmf-dist/source/latex/l3packages/xfp/xfp.dtx
@@ -0,0 +1,167 @@
+% \iffalse meta-comment
+%
+%% File: xfp.dtx (C) Copyright 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/07]
+%<package>\@ifpackagelater{expl3}{2017/03/07}
+%<package> {}
+%<package> {%
+%<package> \PackageError{xfpu}{Support package l3kernel too old}
+%<package> {%
+%<package> Please install an up to date version of l3kernel\MessageBreak
+%<package> using your TeX package manager or from CTAN.\MessageBreak
+%<package> \MessageBreak
+%<package> Loading xfpu will abort!%
+%<package> }%
+%<package> \endinput
+%<package> }
+\def\ExplFileName{xfp}
+\def\ExplFileDescription{LaTeX Floating Point Unit}
+\def\ExplFileDate{2017/03/07}
+\def\ExplFileVersion{6984}
+%</driver|package>
+%<*driver>
+\documentclass[full]{l3doc}
+\usepackage{amstext}
+\begin{document}
+ \DocInput{\jobname.dtx}
+\end{document}
+%</driver>
+% \fi
+%
+% \providecommand\nan{\texttt{NaN}}
+%
+% \title{^^A
+% The \textsf{xfp} package\\Floating Point Unit^^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}
+%
+% This package provides a \LaTeXe{} document-level interface to the \LaTeX{}3
+% floating point unit (part of \pkg{expl3}).
+%
+% \begin{function}[EXP]{\fpeval}
+% The expandable command \cs{fpeval} takes as it's argument a floating
+% point expression and will produce a result using the normal rules of
+% mathematics. As this command is expandable it can be used where \TeX{}
+% requires a number and for example within a low-level \cs{edef} operation
+% to give a purely numerical result.
+% \end{function}
+%
+% Briefly, the floating point expressions may comprise:
+% \begin{itemize}
+% \item Basic arithmetic: addition $x+y$, subtraction $x-y$,
+% multiplication $x*y$, division $x/y$, square root~$\sqrt{x}$,
+% and parentheses.
+% \item Comparison operators: $x\mathop{\mathtt{<}}y$,
+% $x\mathop{\mathtt{<=}}y$, $x\mathop{\mathtt{>?}}y$,
+% $x\mathop{\mathtt{!=}}y$ \emph{etc.}
+% \item Boolean logic: negation $\mathop{!}x$, conjunction
+% $x\mathop{\&\&}y$, disjunction $x\mathop{\vert\vert}y$, ternary
+% operator $x\mathop{?}y\mathop{:}z$.
+% \item Exponentials: $\exp x$, $\ln x$, $x^y$.
+% \item Trigonometry: $\sin x$, $\cos x$, $\tan x$, $\cot x$, $\sec
+% x$, $\csc x$ expecting their arguments in radians, and
+% $\operatorname{sind} x$, $\operatorname{cosd} x$,
+% $\operatorname{tand} x$, $\operatorname{cotd} x$,
+% $\operatorname{secd} x$, $\operatorname{cscd} x$ expecting their
+% arguments in degrees.
+% \item Inverse trigonometric functions: $\operatorname{asin} x$,
+% $\operatorname{acos} x$, $\operatorname{atan} x$,
+% $\operatorname{acot} x$, $\operatorname{asec} x$,
+% $\operatorname{acsc} x$ giving a result in radians, and
+% $\operatorname{asind} x$, $\operatorname{acosd} x$,
+% $\operatorname{atand} x$, $\operatorname{acotd} x$,
+% $\operatorname{asecd} x$, $\operatorname{acscd} x$ giving a result
+% in degrees.
+% \item Extrema: $\max(x,y,\ldots)$, $\min(x,y,\ldots)$,
+% $\operatorname{abs}(x)$.
+% \item Rounding functions ($n=0$ by default, $t=\nan$ by default):
+% $\operatorname{trunc}(x,n)$ rounds towards zero,
+% $\operatorname{floor}(x,n)$ rounds towards~$-\infty$,
+% $\operatorname{ceil}(x,n)$ rounds towards~$+\infty$,
+% $\operatorname{round}(x,n,t)$ rounds to the closest value, with
+% ties rounded to an even value by default, towards zero if $t=0$,
+% towards $+\infty$ if $t>0$ and towards $-\infty$ if $t<0$.
+% \item Random numbers: $\mathop{rand}()$, $\mathop{randint}(m,n)$ (requires
+% \pdfTeX{} or \LuaTeX{}).
+% \item Constants: \texttt{pi}, \texttt{deg} (one degree in radians).
+% \item Dimensions, automatically expressed in points, \emph{e.g.},
+% \texttt{pc} is~$12$.
+% \item Automatic conversion (no need for \cs{number} of
+% integer, dimension, and skip variables to floating points,
+% expressing dimensions in points and ignoring the stretch and
+% shrink components of skips.
+% \end{itemize}
+%
+% An example of use could be the following.
+% \begin{verbatim}
+% \LaTeX{} can now compute: $ \frac{\sin (3.5)}{2} + 2\cdot 10^{-3}
+% = \fpeval{sin 3.5 /2 + 2e-3} $.
+% \end{verbatim}
+%
+% \end{documentation}
+%
+% \begin{implementation}
+%
+% \section{\pkg{xfpu} implementation}
+%
+% \begin{macrocode}
+%<*package>
+% \end{macrocode}
+%
+% \begin{macrocode}
+\ProvidesExplPackage
+ {\ExplFileName}{\ExplFileDate}{\ExplFileVersion}{\ExplFileDescription}
+% \end{macrocode}
+%
+% \begin{macro}{\fpeval}
+% A document level wrapper around the code level function.
+% \begin{macrocode}
+\NewExpandableDocumentCommand \fpeval { m } { \fp_eval:n {#1} }
+% \end{macrocode}
+% \end{macro}
+%
+% \begin{macrocode}
+%</package>
+% \end{macrocode}
+%
+% \end{implementation}
+%
+% \PrintIndex
diff --git a/Master/texmf-dist/source/latex/l3packages/xfp/xfp.ins b/Master/texmf-dist/source/latex/l3packages/xfp/xfp.ins
new file mode 100644
index 00000000000..421df85cb02
--- /dev/null
+++ b/Master/texmf-dist/source/latex/l3packages/xfp/xfp.ins
@@ -0,0 +1,45 @@
+\iffalse meta-comment
+
+File xfp.ins Copyright (C) 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 released version of this bundle is available from CTAN.
+
+\fi
+
+\input l3docstrip.tex
+\askforoverwritefalse
+
+\preamble
+
+Copyright (C) 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.
+
+\endpreamble
+% stop docstrip adding \endinput
+\postamble
+\endpostamble
+
+\keepsilent
+
+\generate{\file{xfp.sty}{\from{xfp.dtx}{package}}}
+
+\endbatchfile
diff --git a/Master/texmf-dist/source/latex/l3packages/xfrac/xfrac.dtx b/Master/texmf-dist/source/latex/l3packages/xfrac/xfrac.dtx
index 2d01dd37e08..d593178b19a 100644
--- a/Master/texmf-dist/source/latex/l3packages/xfrac/xfrac.dtx
+++ b/Master/texmf-dist/source/latex/l3packages/xfrac/xfrac.dtx
@@ -24,8 +24,8 @@
%<*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/02/10]
-%<package>\@ifpackagelater{expl3}{2017/02/10}
+\RequirePackage{expl3}[2017/03/07]
+%<package>\@ifpackagelater{expl3}{2017/03/07}
%<package> {}
%<package> {%
%<package> \PackageError{xfrac}{Support package l3kernel too old}
@@ -40,8 +40,8 @@
\RequirePackage{amstext,graphicx,l3keys2e,textcomp,xparse,xtemplate}
\def\ExplFileName{xfrac}
\def\ExplFileDescription{L3 Experimental split-level fractions}
-\def\ExplFileDate{2017/02/10}
-\def\ExplFileVersion{6878}
+\def\ExplFileDate{2017/03/07}
+\def\ExplFileVersion{6984}
%</driver|package>
%<*driver>
\documentclass[full]{l3doc}
diff --git a/Master/texmf-dist/source/latex/l3packages/xparse/xparse.dtx b/Master/texmf-dist/source/latex/l3packages/xparse/xparse.dtx
index 768a9a317a5..353aba233b0 100644
--- a/Master/texmf-dist/source/latex/l3packages/xparse/xparse.dtx
+++ b/Master/texmf-dist/source/latex/l3packages/xparse/xparse.dtx
@@ -27,8 +27,8 @@
%<*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/02/10]
-%<package>\@ifpackagelater{expl3}{2017/02/10}
+\RequirePackage{expl3}[2017/03/07]
+%<package>\@ifpackagelater{expl3}{2017/03/07}
%<package> {}
%<package> {%
%<package> \PackageError{xparse}{Support package l3kernel too old}
@@ -42,8 +42,8 @@
%<package> }
\def\ExplFileName{xparse}
\def\ExplFileDescription{L3 Experimental document command parser}
-\def\ExplFileDate{2017/02/10}
-\def\ExplFileVersion{6878}
+\def\ExplFileDate{2017/03/07}
+\def\ExplFileVersion{6984}
%</driver|package>
%<*driver>
\documentclass[full]{l3doc}
@@ -91,16 +91,20 @@
% At present, the functions in \pkg{xparse} which are regarded as
% \enquote{stable} are:
% \begin{itemize}
-% \item \cs{DeclareDocumentCommand}
% \item \cs{NewDocumentCommand}
% \item \cs{RenewDocumentCommand}
% \item \cs{ProvideDocumentCommand}
-% \item \cs{DeclareDocumentEnvironment}
+% \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
@@ -185,7 +189,7 @@
% \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}.
+% \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
@@ -215,7 +219,7 @@
% defined such that they require matched pairs of delimiters when collecting
% an argument. For example
% \begin{verbatim}
-% \DeclareDocumentCommand{\foo}{o}{#1}
+% \NewDocumentCommand{\foo}{o}{#1}
% \foo[[content]] % #1 = "[content]"
% \foo[[] % Error: missing closing "]"
% \end{verbatim}
@@ -226,15 +230,15 @@
% Within delimited arguments, non-balanced or otherwise awkward tokens may
% be included by protecting the entire argument with a brace pair
% \begin{verbatim}
-% \DeclareDocumentCommand{\foo}{o}{#1}
-% \foo[{[}] % Allowed as the "[" is 'hidden'
+% \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}
-% \DeclareDocumentCommand{\foo}{o}{#1}
-% \foo[{abc}] % => "abc"
-% \foo[ {abc}] % => " {abc}"
+% \NewDocumentCommand{\foobaz}{o}{#1}
+% \foobaz[{abc}] % => "abc"
+% \foobaz[ {abc}] % => " {abc}"
% \end{verbatim}
%
% Two more tokens have a special meaning when creating an argument
@@ -268,17 +272,17 @@
% to the last mandatory argument to be collected (as it must exist).
% So after
% \begin{verbatim}
-% \DeclareDocumentCommand \foo { m o m } { ... }
+% \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}
-% \DeclareDocumentCommand \foo { m o } { ... }
+% \NewDocumentCommand \foobar { m o } { ... }
% \end{verbatim}
-% |\foo{arg1}[arg2]| will find an optional argument but
-% \verb*|\foo{arg1} [arg2]| will not. This is so that trailing optional
+% |\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
@@ -293,8 +297,8 @@
% delimited} (\texttt{R}-type) argument is that an error will be raised if
% the latter is missing. Thus for example
% \begin{verbatim}
-% \DeclareDocumentCommand {\foo} {r()m} {}
-% \foo{oops}
+% \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
@@ -333,7 +337,7 @@
% default value can be expressed in terms of the value of any other
% arguments by using |#1|, |#2|, and so on.
% \begin{verbatim}
-% \DeclareDocumentCommand {\conjugate} { m O{#1ed} O{#2} } {(#1,#2,#3)}
+% \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)
@@ -342,7 +346,7 @@
% argument specification. For instance a command could accept two
% optional arguments, equal by default:
% \begin{verbatim}
-% \DeclareDocumentCommand {\margins} { O{#3} m O{#1} m } {(#1,#2,#3,#4)}
+% \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)}
@@ -385,13 +389,13 @@
%
% \begin{function}
% {
-% \DeclareDocumentCommand ,
% \NewDocumentCommand ,
% \RenewDocumentCommand ,
-% \ProvideDocumentCommand
+% \ProvideDocumentCommand ,
+% \DeclareDocumentCommand
% }
% \begin{syntax}
-% \cs{DeclareDocumentCommand} \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
@@ -401,7 +405,7 @@
%
% As an example:
% \begin{verbatim}
-% \DeclareDocumentCommand \chapter { s o m }
+% \NewDocumentCommand \chapter { s o m }
% {
% \IfBooleanTF {#1}
% { \typesetstarchapter {#3} }
@@ -414,43 +418,44 @@
% The \cs{typesetnormalchapter} could test its first argument for being
% |-NoValue-| to see if an optional argument was present.
%
-% The difference between the \cs{Declare\ldots}, \cs{New\ldots}
-% \cs{Renew\ldots} and \cs{Provide\ldots} versions is the behaviour
+% 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{DeclareDocumentCommand} will always create the new
-% definition, irrespective of any existing \meta{function} with the
-% same name.
% \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{DeclareDocumentCommand} family of functions do not prevent creation of
+% \cs{NewDocumentCommand} family of functions do not prevent creation of
% functions with names starting \cs{end\ldots}.
% \end{texnote}
%
% \begin{function}
% {
-% \DeclareDocumentEnvironment ,
% \NewDocumentEnvironment ,
% \RenewDocumentEnvironment ,
-% \ProvideDocumentEnvironment
+% \ProvideDocumentEnvironment ,
+% \DeclareDocumentEnvironment
% }
% \begin{syntax}
-% \cs{DeclareDocumentEnvironment} \Arg{environment} \Arg{arg spec}
+% \cs{NewDocumentEnvironment} \Arg{environment} \Arg{arg spec}
% ~~\Arg{start code} \Arg{end code}
% \end{syntax}
-% These commands work in the same way as \cs{DeclareDocumentCommand},
-% etc., but create environments (\cs{begin}|{|\meta{function}|}| \ldots
-% \cs{end}|{|\meta{function}|}|). Both the \meta{start code} and
+% 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}
@@ -468,7 +473,7 @@
% 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}
-% \DeclareDocumentCommand \foo { o m }
+% \NewDocumentCommand \foo { o m }
% {
% \IfNoValueTF {#1}
% { \DoSomethingJustWithMandatoryArgument {#2} }
@@ -493,6 +498,15 @@
% \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}
@@ -517,7 +531,7 @@
% Used to test if \meta{argument} (|#1|, |#2|, \emph{etc.}) is
% \cs{BooleanTrue} or \cs{BooleanFalse}. For example
% \begin{verbatim}
-% \DeclareDocumentCommand \foo { s m }
+% \NewDocumentCommand \foo { s m }
% {
% \IfBooleanTF #1
% { \DoSomethingWithStar {#2} }
@@ -565,7 +579,7 @@
% This processor reverses the logic of \cs{BooleanTrue} and
% \cs{BooleanFalse}, so that the example from earlier would become
% \begin{verbatim}
-% \DeclareDocumentCommand \foo { > { \ReverseBoolean } s m }
+% \NewDocumentCommand \foo { > { \ReverseBoolean } s m }
% {
% \IfBooleanTF #1
% { \DoSomethingWithoutStar {#2} }
@@ -588,7 +602,7 @@
% then \cs{NoValue} markers are added at the end of the processed
% argument.
% \begin{verbatim}
-% \DeclareDocumentCommand \foo
+% \NewDocumentCommand \foo
% { > { \SplitArgument { 2 } { ; } } m }
% { \InternalFunctionOfThreeArguments #1 }
% \end{verbatim}
@@ -606,7 +620,7 @@
% then wrapped in braces within |#1|. The result is that the
% processed argument can be further processed using a mapping function.
% \begin{verbatim}
-% \DeclareDocumentCommand \foo
+% \NewDocumentCommand \foo
% { > { \SplitList { ; } } m }
% { \MappingFunction #1 }
% \end{verbatim}
@@ -623,7 +637,7 @@
% 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}
-% \DeclareDocumentCommand \foo
+% \NewDocumentCommand \foo
% { > { \SplitList { ; } } m }
% { \ProcessList {#1} { \SomeDocumentFunction } }
% \end{verbatim}
@@ -639,7 +653,7 @@
% and category code~$10$) for the ends of the argument. Thus for example
% declaring a function
% \begin{verbatim}
-% \DeclareDocumentCommand \foo
+% \NewDocumentCommand \foo
% { > { \TrimSpaces } m }
% { \showtokens {#1} }
% \end{verbatim}
@@ -666,18 +680,24 @@
% if you do not understand when this might be, \emph{do not use these
% functions}!
%
-% \begin{function}{\DeclareExpandableDocumentCommand}
+% \begin{function}
+% {
+% \NewExpandableDocumentCommand ,
+% \RenewExpandableDocumentCommand ,
+% \ProvideExpandableDocumentCommand ,
+% \DeclareExpandableDocumentCommand
+% }
% \begin{syntax}
-% \cs{DeclareExpandableDocumentCommand}
+% \cs{NewExpandableDocumentCommand}
% ~~~~\meta{function} \Arg{arg spec} \Arg{code}
% \end{syntax}
-% This command is used to create a document-level \meta{function},
+% 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 token).
+% 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
@@ -685,10 +705,9 @@
% \begin{itemize}
% \item The last argument (if any are present) must be one of the
% mandatory types \texttt{m} or \texttt{r}.
-% \item All arguments are either short or long: it is not possible
-% to mix short and long argument types.
-% \item The mandatory argument types \texttt{l} and \texttt{u} are
-% not available.
+% \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.
@@ -791,24 +810,6 @@
% \end{macrocode}
% \end{variable}
%
-% \begin{variable}{\l_@@_all_long_bool}
-% For expandable commands, all arguments have the same long status, but this
-% needs to be checked. A flag is therefore needed to track whether arguments
-% are long at all.
-% \begin{macrocode}
-\bool_new:N \l_@@_all_long_bool
-% \end{macrocode}
-% \end{variable}
-%
-% \begin{variable}{\l_@@_all_long_set_bool}
-% Whether \cs{l_@@_all_long_bool}'s value is fixed yet or not. This
-% is to deal with the case of leading \texttt{t}-type argument, whose
-% \enquote{long} status should be ignored.
-% \begin{macrocode}
-\bool_new:N \l_@@_all_long_set_bool
-% \end{macrocode}
-% \end{variable}
-%
% \begin{variable}{\l_@@_arg_spec_tl}
% Holds the argument specification after normalization of shorthands.
% \begin{macrocode}
@@ -916,6 +917,16 @@
% \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
@@ -928,9 +939,7 @@
% \end{variable}
%
% \begin{variable}{\l_@@_long_bool}
-% Used to indicate that an argument is long: this is used on a per-argument
-% basis for non-expandable functions, or for the entire set of arguments
-% when working expandably.
+% Used to indicate that an argument is long, on a per-argument basis.
% \begin{macrocode}
\bool_new:N \l_@@_long_bool
% \end{macrocode}
@@ -986,6 +995,20 @@
% \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.
@@ -1029,6 +1052,13 @@
{ \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} }
}
@@ -1068,13 +1098,13 @@
% \begin{macrocode}
\cs_new_protected:Npn \@@_declare_cmd_code:Nnn
{
- \bool_if:NTF \l_@@_expandable_bool
+ \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 an auxiliary used for
+% 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}
@@ -1100,11 +1130,27 @@
}
}
}
+% \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
{
- \cs_generate_from_arg_count:cNnn
+ \exp_args:Ncc \cs_generate_from_arg_count:NNnn
{ \l_@@_function_tl \c_space_tl code }
- \cs_set:Npn \l_@@_current_arg_int {#3}
+ { cs_set \bool_if:NF \l_@@_expandable_bool { _protected } :Npn }
+ \l_@@_current_arg_int {#3}
\bool_if:NT \l_@@_defaults_bool
{
\use:x
@@ -1115,19 +1161,35 @@
{ \exp_not:o \l_@@_defaults_tl }
}
}
- \cs_set_nopar:Npx #1
+ \bool_if:NTF \l_@@_expandable_bool
+ { \cs_set_nopar:Npx } { \cs_set_protected_nopar:Npx } #1
{
- \exp_not:N \@@_start_expandable:nNNNn
+ \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 }
- \exp_not:c { \l_@@_function_tl \c_space_tl defaults }
+ \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_@@_all_long_bool
- { \cs_set:cpx }
+ \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} }
+ { \l_@@_function_tl \c_space_tl } ##1##2 { ##1 {##2} }
}
% \end{macrocode}
% \end{macro}
@@ -1196,12 +1258,20 @@
% \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.
+% 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:Npn \@@_start:nNNnnn #1#2#3#4#5#6
+\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}
@@ -1212,6 +1282,7 @@
}
% \end{macrocode}
% \end{macro}
+% \end{macro}
%
% \begin{macro}{\@@_run_code:}
% After arguments are grabbed, this function is responsible for
@@ -1359,29 +1430,30 @@
% \end{macro}
% \end{macro}
%
-% \begin{macro}[EXP]{\@@_start_expandable:nNNNn}
-% This is called for all expandable commands. |#5| is the signature,
-% responsible for grabbing arguments. |#4| is used to determine
-% default values. |#3| is the code to run.
-% |#2|~is a function (named after the command) that grabs a single
-% argument in the input stream. The argument specification |#1| is
-% unused but used by diagnostic functions.
+% \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:nNNNn #1#2#3#4#5
- { #5 \@@_end_expandable:NNw #4 #3 \q_@@ #2 }
+\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:nNNN}
+% \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, the code
-% |#2|, arguments that have been grabbed, then \cs{q_@@} and a generic
-% grabber. The idea to find default values is similar to the
+% 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
@@ -1392,11 +1464,11 @@
% \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_@@ #4
- { \exp_args:No \@@_end_expandable_aux:nNNN {#3} #1 #2 #4 }
-\cs_new:Npn \@@_end_expandable_aux:nNNN #1#2#3#4
+\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
{
- \cs_if_exist:NF #2 { \exp_after:wN \use_iv:nnnn }
+ \token_if_eq_charcode:NNT ? #2 { \exp_after:wN \use_iv:nnnn }
\@@_end_expandable_defaults:nnnNNn {#1} { } {#1} #2#3
{ } { } { } { } { } { } { } { } { } { }
{
@@ -1472,17 +1544,29 @@
% must be followed by arguments.
%
% The third is to check for forbidden types for expandable commands,
-% namely \texttt{g},
-% \texttt{G}, \texttt{l} (as the next left brace may have been inserted
-% by \pkg{xparse} due to a failed search for an optional argument),
-% \texttt{u} (any preceding optional argument may wrap part of the
-% delimiter up in braces), and \texttt{v}.
+% 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 last is to count mandatory arguments.
+% 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}
@@ -1500,6 +1584,10 @@
\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
@@ -1517,6 +1605,10 @@
\@@_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
{
@@ -1603,12 +1695,14 @@
}
\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}
}
@@ -1622,6 +1716,7 @@
% \@@_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
@@ -1637,8 +1732,9 @@
\@@_single_token_check:n {#1}
\@@_single_token_check:n {#2}
\quark_if_recursion_tail_stop_do:nn {#3} { \@@_bad_arg_spec:wn }
- \tl_put_right:Nn \l_@@_arg_spec_tl { D #1 #2 {#3} }
+ \@@_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
@@ -1646,17 +1742,27 @@
\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 }
- \tl_put_right:Nn \l_@@_arg_spec_tl { E {#1} {#2} }
+ \@@_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_error_if_expandable:N G
- \tl_put_right:Nn \l_@@_arg_spec_tl { G {#1} }
+ \@@_normalize_check_gv:N G
+ \@@_add_arg_spec:n { G {#1} }
\tl_put_right:Nn \l_@@_last_delimiters_tl { { } }
\@@_normalize_arg_spec_loop:n
}
@@ -1666,10 +1772,13 @@
\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}
% {
@@ -1690,8 +1799,8 @@
% \begin{macrocode}
\cs_new_protected:Npn \@@_normalize_type_l:w
{
- \@@_normalize_error_if_expandable:N l
- \tl_put_right:Nn \l_@@_arg_spec_tl { l }
+ \@@_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
@@ -1699,7 +1808,7 @@
\cs_new_protected:Npn \@@_normalize_type_m:w
{
\@@_delimiter_check:nnn { } { m } { \iow_char:N \{ }
- \tl_put_right:Nn \l_@@_arg_spec_tl { m }
+ \@@_add_arg_spec:n { m }
\int_incr:N \l_@@_mandatory_args_int
\tl_clear:N \l_@@_last_delimiters_tl
\@@_normalize_arg_spec_loop:n
@@ -1710,24 +1819,25 @@
\@@_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} }
- \tl_put_right:Nn \l_@@_arg_spec_tl { R #1 #2 {#3} }
+ \@@_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_error_if_expandable:N u
- \tl_put_right:Nn \l_@@_arg_spec_tl { u {#1} }
+ \@@_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_error_if_expandable:N v
- \tl_put_right:Nn \l_@@_arg_spec_tl { v }
+ \@@_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
@@ -1751,10 +1861,11 @@
% \end{macrocode}
% \end{macro}
%
-% \begin{macro}{\@@_normalize_error_if_expandable:N}
-% Called for arguments that are forbidden for expandable commands.
+% \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_error_if_expandable:N #1
+\cs_new_protected:Npn \@@_normalize_check_gv:N #1
{
\bool_if:NT \l_@@_expandable_bool
{
@@ -1763,6 +1874,20 @@
{ \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}
@@ -1788,8 +1913,8 @@
% \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.
+% 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
{
@@ -1800,6 +1925,38 @@
% \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}
@@ -1812,8 +1969,6 @@
% \begin{macrocode}
\cs_new_protected:Npn \@@_prepare_signature:n #1
{
- \bool_set_false:N \l_@@_all_long_bool
- \bool_set_false:N \l_@@_all_long_set_bool
\int_zero:N \l_@@_current_arg_int
\bool_set_false:N \l_@@_long_bool
\int_zero:N \l_@@_m_args_int
@@ -1849,7 +2004,7 @@
\use:c
{
@@_add
- \bool_if:NT \l_@@_expandable_bool { _expandable }
+ \bool_if:NT \l_@@_grab_expandably_bool { _expandable }
_type_ \token_to_str:N #1 :w
}
}
@@ -2047,7 +2202,7 @@
% \begin{macrocode}
\cs_new_protected:Npn \@@_flush_m_args:
{
- \int_compare:nNnT \l_@@_m_args_int > \c_zero
+ \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 } }
@@ -2090,7 +2245,7 @@
{
@@_grab_ #1
\bool_if:NT \l_@@_long_bool { _long }
- \int_compare:nNnF \l_@@_mandatory_args_int > \c_zero
+ \int_compare:nNnF \l_@@_mandatory_args_int > 0
{ _trailing }
:w
}
@@ -2153,7 +2308,11 @@
% the general grabbers are dealt with later.
%
% \begin{macro}{\@@_add_expandable_type_+:w}
-% ^^A todo
+% 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 }
{
@@ -2184,18 +2343,16 @@
\tl_if_eq:nnTF {#2} {#3}
{ \@@_add_expandable_type_D_aux:NN #1 #2 }
{ \@@_add_expandable_type_D_aux:NNN #1 #2 #3 }
- \bool_set_false:N \l_@@_long_bool
\@@_prepare_signature:N
}
\cs_new_protected:Npn \@@_add_expandable_type_D_aux:NNN #1#2#3
{
- \@@_add_expandable_grabber:n {#1}
- \bool_if:NTF \l_@@_all_long_bool
+ \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} }
- \tl_put_right:Nx \l_@@_signature_tl
+ \@@_add_expandable_grabber:nn {#1}
{
\exp_not:c { \l_@@_expandable_aux_name_tl }
\exp_not:n { #2 #3 }
@@ -2203,13 +2360,12 @@
}
\cs_new_protected:Npn \@@_add_expandable_type_D_aux:NN #1#2
{
- \@@_add_expandable_grabber:n { #1_alt }
- \bool_if:NTF \l_@@_all_long_bool
+ \bool_if:NTF \l_@@_long_bool
{ \cs_set:cpx }
{ \cs_set_nopar:cpx }
{ \l_@@_expandable_aux_name_tl } ##1 #2 ##2 #2
{ ##1 {##2} }
- \tl_put_right:Nx \l_@@_signature_tl
+ \@@_add_expandable_grabber:nn { #1_alt }
{
\exp_not:c { \l_@@_expandable_aux_name_tl }
\exp_not:n {#2}
@@ -2233,10 +2389,10 @@
\cs_new_protected:Npn \@@_add_expandable_type_E:w #1#2
{
\@@_add_default_E:nn {#1} {#2}
- \@@_add_expandable_grabber:n { E }
\tl_clear:N \l_@@_tmpb_tl
\tl_map_function:nN {#1} \@@_add_expandable_type_E_aux:n
- \tl_put_right:Nx \l_@@_signature_tl
+ \@@_add_expandable_grabber:nn
+ { E \bool_if:NT \l_@@_long_bool { _long } }
{
{ \exp_not:o \l_@@_tmpb_tl }
{
@@ -2244,7 +2400,6 @@
{ { \c_@@_no_value_tl } }
}
}
- \bool_set_false:N \l_@@_long_bool
\@@_prepare_signature:N
}
\cs_new_protected:Npn \@@_add_expandable_type_E_aux:n #1
@@ -2257,6 +2412,16 @@
% \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.
@@ -2264,7 +2429,8 @@
\cs_new_protected:Npn \@@_add_expandable_type_m:w
{
\@@_add_default:
- \@@_add_expandable_grabber:n { m }
+ \@@_add_expandable_grabber:nn
+ { m \bool_if:NT \l_@@_long_bool { _long } } { }
\@@_prepare_signature:N
}
% \end{macrocode}
@@ -2286,53 +2452,44 @@
\cs_new_protected:Npn \@@_add_expandable_type_t:w #1
{
\@@_add_default:
- \@@_add_expandable_grabber_t:
\@@_get_grabber:NN #1 \l_@@_tmpa_tl
- \tl_put_right:Nx \l_@@_signature_tl
+ \@@_add_expandable_grabber:nn { t }
{
\exp_not:o \l_@@_tmpa_tl
\exp_not:N #1
}
- \bool_set_false:N \l_@@_long_bool
\@@_prepare_signature:N
}
% \end{macrocode}
% \end{macro}
%
-% \begin{macro}{\@@_add_expandable_grabber:n, \@@_add_expandable_grabber_t:}
-% For \texttt{t}-type arguments, simply add a grabber to the signature
-% and reset the boolean keeping track of~\texttt{+} markers (they
-% should be ignored for the purpose of determining the long status of
-% the command because they take no argument). For all other
-% arguments, if the command's long status is already known then check
-% that this argument has the correct long status, and otherwise set
-% the long status to this argument's long status.
+% \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_grabber:n #1
+\cs_new_protected:Npn \@@_add_expandable_type_u:w #1
{
- \bool_if:NTF \l_@@_all_long_set_bool
- {
- \bool_if:nT
- { \bool_xor_p:nn { \l_@@_all_long_bool } { \l_@@_long_bool } }
- {
- \__msg_kernel_error:nnx { xparse } { inconsistent-long }
- { \iow_char:N \\ \l_@@_function_tl }
- \@@_bad_def:wn
- }
- }
- {
- \bool_set:Nn \l_@@_all_long_bool { \l_@@_long_bool }
- \bool_set_true:N \l_@@_all_long_set_bool
- }
- \tl_put_right:Nx \l_@@_signature_tl
- { \exp_not:c { @@_expandable_grab_ #1 :w } }
- \bool_set_false:N \l_@@_long_bool
+ \@@_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
}
-\cs_new_protected:Npn \@@_add_expandable_grabber_t:
+% \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:Nn \l_@@_signature_tl
- { \@@_expandable_grab_t:w }
- \bool_set_false:N \l_@@_long_bool
+ \tl_put_right:Nx \l_@@_signature_tl
+ { \exp_not:c { @@_expandable_grab_ #1 :w } #2 }
}
% \end{macrocode}
% \end{macro}
@@ -3041,7 +3198,7 @@
\cs_new_protected:Npx \@@_grab_v_bgroup:
{
\exp_not:N \@@_grab_v_aux_catcodes:
- \exp_not:n { \int_set_eq:NN \l_@@_v_nesting_int \c_one }
+ \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:
}
@@ -3058,7 +3215,7 @@
\token_if_eq_charcode:NNTF \c_group_end_token #1
{
\int_decr:N \l_@@_v_nesting_int
- \int_compare:nNnTF \l_@@_v_nesting_int > \c_zero
+ \int_compare:nNnTF \l_@@_v_nesting_int > 0
{
\@@_grab_v_aux_put:N #1
\@@_grab_v_bgroup_loop:
@@ -3175,33 +3332,37 @@
% \subsection{Grabbing arguments expandably}
%
% \begin{macro}[EXP]{\@@_expandable_grab_D:w}
-% \begin{macro}[EXP, aux]{\@@_expandable_grab_D:NNNwNn}
-% \begin{macro}[EXP, aux]{\@@_expandable_grab_D:NNNwNnnn}
+% \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:nnNNNwN}
-% The first step is to grab the first token or group. The generic grabber
-% \cs{\meta{function}}\verb*| | is just after \cs{q_@@}, we go and find
-% it.
-% \begin{macrocode}
-\cs_new:Npn \@@_expandable_grab_D:w #1 \q_@@ #2
- { #2 { \@@_expandable_grab_D:NNNwNn #1 \q_@@ #2 } }
-% \end{macrocode}
-% We then wish to test whether |#6|, which we just grabbed, is exactly |#2|.
-% Expand the only grabber function we have, |#1|, once: the two strings below
-% are equal if and only if |#6| matches |#2| exactly.\footnote{It is obvious
-% that if \texttt{\#6} matches \texttt{\#2} then the strings are equal. We
+% \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{\#6} starts with \texttt{\#2}, otherwise the brace group preceding
-% \texttt{\#6} would not vanish. The third brace group is empty, thus the
+% \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{\#6}), hence the second brace
-% group contains the end of \texttt{\#6} followed by \texttt{\#2}. Since this
+% 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{\#6} must contain nothing else than its leading \texttt{\#2}.} If
-% |#6| does not match |#2|, then the optional argument is missing, we use the
-% default |-NoValue-|, and put back the argument |#6| in the input stream.
+% \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:
@@ -3227,34 +3388,38 @@
% \begin{macrocode}
\cs_set_protected:Npn \@@_tmp:w #1
{
- \cs_new:Npn \@@_expandable_grab_D:NNNwNn ##1##2##3##4 \q_@@ ##5##6
+ \cs_new:Npn \@@_expandable_grab_D:NNNwNNn ##1##2##3##4 \q_@@ ##5##6##7
{
- \str_if_eq:onTF
- { ##1 { } { } ##6 ##2 \q_@@ ##3 }
- { { } {##2} { } }
+ \str_if_eq:nnTF {##2} {##7}
+ {
+ \str_if_eq:onTF
+ { ##1 { } { } ##7 ##2 \q_@@ ##3 }
+ { { } {##2} { } }
+ }
+ { \use_ii:nn }
{
##1
- { \@@_expandable_grab_D:NNNwNnnn ##1##2##3##4 \q_@@ ##5 }
+ { \@@_expandable_grab_D:NNNwNNnnn ##1##2##3##4 \q_@@ ##5##6 }
\q_nil { } ##2 \ERROR \q_@@ \ERROR
}
- { ##4 {#1} \q_@@ ##5 {##6} }
+ { ##4 {#1} \q_@@ ##5 ##6 {##7} }
}
}
\exp_args:No \@@_tmp:w { \c_@@_no_value_tl }
% \end{macrocode}
-% At this stage, |#6| is \cs{q_nil} \Arg{piece 1} \meta{more for piece 1},
+% 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, |#7| is
-% \meta{remainder of piece 2} \cs{ERROR}, and |#8| is \cs{ERROR} \meta{more
+% 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:NNNwNnnn #1#2#3#4 \q_@@ #5#6#7#8
+\cs_new:Npn \@@_expandable_grab_D:NNNwNNnnn #1#2#3#4 \q_@@ #5#6#7#8#9
{
- \exp_args:Nof \@@_expandable_grab_D:nnNNNwN
- { \use_ii:nn #6 #2 }
- { \@@_expandable_grab_D:Nw #3 \exp_stop_f: #7 #8 }
- #1#2#3 #4 \q_@@ #5
+ \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}
@@ -3266,10 +3431,10 @@
% 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:NNNwNnnn}. The code to deal with brace stripping
+% \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:nnNNNwN #1#2#3#4#5#6 \q_@@ #7
+\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 }
@@ -3283,11 +3448,11 @@
{ \@@_put_arg_expandable:ow { \use_iii:nnn #1#2 } }
{ \@@_put_arg_expandable:ow { \use_none:nn #1#2 } }
}
- #6 \q_@@ #7
+ #6 \q_@@ #7 #8
}
{
#3
- { \@@_expandable_grab_D:NNNwNnnn #3#4#5#6 \q_@@ #7 }
+ { \@@_expandable_grab_D:NNNwNNnnn #3#4#5#6 \q_@@ #7 #8 }
\q_nil {#1} #2 \ERROR \q_@@ \ERROR
}
}
@@ -3299,58 +3464,66 @@
% \end{macro}
%
% \begin{macro}[EXP]{\@@_expandable_grab_D_alt:w}
-% \begin{macro}[EXP]{\@@_expandable_grab_D_alt:NNwNn}
+% \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.
+% the delimiters are different but there cannot be any nesting.
% \begin{macrocode}
-\cs_new:Npn \@@_expandable_grab_D_alt:w #1 \q_@@ #2
- { #2 { \@@_expandable_grab_D_alt:NNwNn #1 \q_@@ #2 } }
+\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:NNwNn ##1##2##3 \q_@@ ##4##5
+ \cs_new:Npn \@@_expandable_grab_D_alt:NNwNNn ##1##2##3 \q_@@ ##4##5##6
{
- \str_if_eq:onTF
- { ##1 { } ##5 ##2 ##2 }
- { { } ##2 }
+ \str_if_eq:nnTF {##6} {##2}
+ {
+ \str_if_eq:onTF
+ { ##1 { } ##6 ##2 ##2 }
+ { { } ##2 }
+ }
+ { \use_ii:nn }
{
##1
- { \@@_expandable_grab_D_alt:Nwn ##4 ##3 \q_@@ }
- ##5 \ERROR
+ { \@@_expandable_grab_D_alt:NNwn ##4 ##5 ##3 \q_@@ }
+ ##6 \ERROR
}
- { ##3 {#1} \q_@@ ##4 {##5} }
+ { ##3 {#1} \q_@@ ##4 ##5 {##6} }
}
}
\exp_args:No \@@_tmp:w { \c_@@_no_value_tl }
-\cs_new:Npn \@@_expandable_grab_D_alt:Nwn #1#2 \q_@@ #3
+\cs_new:Npn \@@_expandable_grab_D_alt:NNwn #1#2#3 \q_@@ #4
{
- \tl_if_blank:oTF { \use_none:n #3 }
- { \@@_put_arg_expandable:ow { \use_none:n #3 } }
+ \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 #3 } }
- { { \exp_not:o { \use_ii:nnn #3 \q_nil } } }
- { \@@_put_arg_expandable:ow { \use_ii:nn #3 } }
- { \@@_put_arg_expandable:ow { \use_none:n #3 } }
+ { \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 } }
}
- #2 \q_@@ #1
+ #3 \q_@@ #1 #2
}
% \end{macrocode}
% \end{macro}
% \end{macro}
% \end{macro}
%
-% \begin{macro}[EXP]{\@@_expandable_grab_E:w}
-% \begin{macro}[EXP,aux]{\@@_expandable_grab_E_test:nnwn}
+% \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_aux:nnw}
-% \begin{macro}[EXP,aux]{\@@_expandable_grab_E_aux:nnnnn}
+% \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}
-% The function will be called repeatedly with two arguments: the set
+% 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:nnnNNwn}
+% 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
@@ -3365,18 +3538,22 @@
% 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{:w} auxiliary. To avoid
-% losing braces around that auxiliary's argument |#4| we include a
+% 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
- { #2 { \@@_expandable_grab_E_test:nnwn #1 \q_@@ #2 } }
-\cs_new:Npn \@@_expandable_grab_E_test:nnwn #1#2#3 \q_@@ #4#5
+\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 {#5} { } { }
+ \@@_expandable_grab_E_loop:nnnNNw {#7} { } { }
#1 \q_nil \q_nil \q_nil \q_mark #2 \q_nil
- #3 \q_@@ #4
+ #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
@@ -3387,7 +3564,7 @@
\@@_if_no_value:nTF {#8}
{ \str_if_eq:onTF { #4 { } #1 #5 } {#5} }
{ \use_ii:nn }
- { \@@_expandable_grab_E_aux:w { #2 #4 #5 #6 } {#3} ~ }
+ { \@@_expandable_grab_E_find:w { #2 #4 #5 #6 } {#3} ~ }
{
\@@_expandable_grab_E_loop:nnnNNw
{#1} { #2 #4 #5 } { #3 {#8} }
@@ -3395,12 +3572,12 @@
}
}
}
-\cs_new:Npn \@@_expandable_grab_E_aux:w #1 \q_@@ #2
- { #2 { \@@_expandable_grab_E_aux:nnw #1 \q_@@ #2 } }
-\cs_new:Npn \@@_expandable_grab_E_aux:nnw #1#2#3 \q_nil #4 \q_@@ #5#6
- { \@@_expandable_grab_E:w {#1} { #2 {#6} #3 } #4 \q_@@ #5 }
-\cs_new:Npn \@@_expandable_grab_E_end:nnw #1#2#3 \q_@@ #4
- { #3 {#2} \q_@@ #4 {#1} }
+\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}
@@ -3408,43 +3585,51 @@
% \end{macro}
% \end{macro}
% \end{macro}
+% \end{macro}
%
-% \begin{macro}[EXP]{\@@_expandable_grab_m:w}
+% \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.
+% 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
- { #2 { \@@_expandable_grab_m_aux:wNn #1 \q_@@ #2 } }
-\cs_new:Npn \@@_expandable_grab_m_aux:wNn #1 \q_@@ #2#3
- { #1 {#3} \q_@@ #2 }
+\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:NNNwNn}
+% \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
- { #2 { \@@_expandable_grab_R_aux:NNNwNn #1 \q_@@ #2 } }
+\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:NNNwNn ##1##2##3##4 \q_@@ ##5##6
+ \cs_new:Npn \@@_expandable_grab_R_aux:NNNwNNn ##1##2##3##4 \q_@@ ##5##6##7
{
- \str_if_eq:onTF
- { ##1 { } { } ##6 ##2 \q_@@ ##3 }
- { { } {##2} { } }
+ \str_if_eq:nnTF {##7} {##2}
+ {
+ \str_if_eq:onTF
+ { ##1 { } { } ##7 ##2 \q_@@ ##3 }
+ { { } {##2} { } }
+ }
+ { \use_ii:nn }
{
##1
- { \@@_expandable_grab_D:NNNwNnnn ##1##2##3##4 \q_@@ ##5 }
+ { \@@_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}
+ ##4 {#1} \q_@@ ##5 ##6 {##7}
}
}
}
@@ -3454,29 +3639,33 @@
% \end{macro}
%
% \begin{macro}[EXP]{\@@_expandable_grab_R_alt:w}
-% \begin{macro}[EXP]{\@@_expandable_grab_R_alt_aux:NNwNn}
+% \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
- { #2 { \@@_expandable_grab_R_alt_aux:NNnwNn #1 \q_@@ #2 } }
+\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
+ \cs_new:Npn \@@_expandable_grab_R_alt_aux:NNwNn ##1##2##3 \q_@@ ##4##5##6
{
- \str_if_eq:onTF
- { ##1 { } ##5 ##2 ##2 }
- { { } ##2 }
+ \str_if_eq:nnTF {##6} {##2}
+ {
+ \str_if_eq:onTF
+ { ##1 { } ##6 ##2 ##2 }
+ { { } ##2 }
+ }
+ { \use_ii:nn }
{
##1
- { \@@_expandable_grab_D_alt:Nwn ##4 ##3 \q_@@ }
- ##5 \ERROR
+ { \@@_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}
+ ##3 {#1} \q_@@ ##4 ##5 {##6}
}
}
}
@@ -3491,18 +3680,26 @@
% 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
- { #2 { \@@_expandable_grab_t_aux:NNwn #1 \q_@@ #2 } }
-\cs_new:Npn \@@_expandable_grab_t_aux:NNwn #1#2#3 \q_@@ #4#5
+\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 { } #5 #2 } {#2}
- { #3 { \BooleanTrue } \q_@@ #4 }
- { #3 { \BooleanFalse } \q_@@ #4 {#5} }
+ \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.
@@ -3593,27 +3790,27 @@
}
\cs_new_protected:Npn \@@_split_argument_aux:nnnn #1#2#3#4
{
- \int_compare:nNnF {#1} = { #2 + \c_one }
+ \int_compare:nNnF {#1} = { #2 + 1 }
{
- \int_compare:nNnTF {#1} > { #2 + \c_one }
+ \int_compare:nNnTF {#1} > { #2 + 1 }
{
\tl_set:Nx \ProcessedArgument
{
\exp_last_unbraced:NnNo
\@@_split_argument_aux:n
- { #2 + \c_one }
+ { #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 + \c_one } }
+ { \tl_to_str:n {#3} } { \int_eval:n { #2 + 1 } }
{ \tl_to_str:n {#4} }
}
{
\tl_put_right:Nx \ProcessedArgument
{
- \prg_replicate:nn { #2 + \c_one - (#1) }
+ \prg_replicate:nn { #2 + 1 - (#1) }
{ { \exp_not:V \c_@@_no_value_tl } }
}
}
@@ -3768,7 +3965,7 @@
%
% \begin{macro}{\@@_check_definable:nNT, \@@_check_definable_aux:nN}
% Check that a token list is appropriate as a first argument of
-% \cs{DeclareDocumentCommand} and similar functions and otherwise
+% \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
@@ -3857,7 +4054,7 @@
% 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:nNNNn}
+% (non-expandable command) or \cs{@@_start_expandable:nNNNNn}
% (expandable command).
% \begin{macrocode}
\cs_new_protected:Npn \@@_cmd_if_xparse:NTF #1
@@ -3872,7 +4069,7 @@
}
{
{ \token_to_str:N \@@_start:nNNnnn } { }
- { \token_to_str:N \@@_start_expandable:nNNNn } { }
+ { \token_to_str:N \@@_start_expandable:nNNNNn } { }
}
}
\cs_new:Npn \@@_cmd_if_xparse_aux:w #1 ~ #2 \q_stop {#1}
@@ -3895,16 +4092,16 @@
\__msg_kernel_new:nnnn { xparse } { command-already-defined }
{ Command~'#1'~already~defined! }
{
- You~have~used~\NewDocumentCommand
+ 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~\RenewDocumentCommand
+ You~have~used~#2~
with~a~command~that~was~never~defined. \\
- A~new~command~'#1'~will~be~created.
+ LaTeX~will~ignore~this~entire~definition.
}
\__msg_kernel_new:nnnn { xparse } { environment-already-defined }
{ Environment~'#1'~already~defined! }
@@ -3918,7 +4115,7 @@
{
You~have~used~\RenewDocumentEnvironment
with~an~environment~that~was~never~defined. \\
- A~new~environment~'#1'~will~be~created.
+ LaTeX~will~ignore~this~entire~definition.
}
\__msg_kernel_new:nnnn { xparse } { expandable-ending-optional }
{
@@ -3935,8 +4132,8 @@
{ Inconsistent~long~arguments~for~expandable~command~'#1'. }
{
\c__msg_coding_error_text_tl
- The~arguments~for~an~expandable~command~must~either~all~be~
- short~or~all~be~long.~You~have~tried~to~mix~the~two~types.
+ 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'. }
@@ -3947,6 +4144,18 @@
\\ \\
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'. }
{
@@ -4093,6 +4302,12 @@
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}
@@ -4110,27 +4325,24 @@
% \end{macro}
% \end{macro}
%
-% \begin{macro}{\DeclareDocumentCommand}
% \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
-% and is definable.
+% 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 \DeclareDocumentCommand #1#2#3
- {
- \@@_check_definable:nNT {#1} \DeclareDocumentCommand
- { \@@_declare_cmd:Nnn #1 {#2} {#3} }
- }
\cs_new_protected:Npn \NewDocumentCommand #1#2#3
{
\@@_check_definable:nNT {#1} \NewDocumentCommand
{
\cs_if_exist:NTF #1
{
- \__msg_kernel_error:nnx { xparse } { command-already-defined }
- { \token_to_str:N #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} }
}
@@ -4142,8 +4354,9 @@
\cs_if_exist:NTF #1
{ \@@_declare_cmd:Nnn #1 {#2} {#3} }
{
- \__msg_kernel_error:nnx { xparse } { command-not-yet-defined }
- { \token_to_str:N #1 }
+ \__msg_kernel_error:nnxx { xparse } { command-not-yet-defined }
+ { \use:nnn \token_to_str:N #1 { } }
+ { \token_to_str:N \RenewDocumentCommand }
}
}
}
@@ -4152,20 +4365,23 @@
\@@_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}{\DeclareDocumentEnvironment}
% \begin{macro}{\NewDocumentEnvironment}
% \begin{macro}{\RenewDocumentEnvironment}
% \begin{macro}{\ProvideDocumentEnvironment}
+% \begin{macro}{\DeclareDocumentEnvironment}
% Very similar for environments.
% \begin{macrocode}
-\cs_new_protected:Npn \DeclareDocumentEnvironment #1#2#3#4
- { \@@_declare_env:nnnn {#1} {#2} {#3} {#4} }
\cs_new_protected:Npn \NewDocumentEnvironment #1#2#3#4
{
\cs_if_exist:cTF {#1}
@@ -4180,15 +4396,54 @@
}
\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 version of the basic function is essentially the same.
+% 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
@@ -4196,6 +4451,9 @@
}
% \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
diff --git a/Master/texmf-dist/source/latex/l3packages/xtemplate/xtemplate.dtx b/Master/texmf-dist/source/latex/l3packages/xtemplate/xtemplate.dtx
index 430b5d9490e..a749c690157 100644
--- a/Master/texmf-dist/source/latex/l3packages/xtemplate/xtemplate.dtx
+++ b/Master/texmf-dist/source/latex/l3packages/xtemplate/xtemplate.dtx
@@ -27,8 +27,8 @@
%<*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/02/10]
-%<package>\@ifpackagelater{expl3}{2017/02/10}
+\RequirePackage{expl3}[2017/03/07]
+%<package>\@ifpackagelater{expl3}{2017/03/07}
%<package> {}
%<package> {%
%<package> \PackageError{xtemplate}{Support package l3kernel too old}
@@ -42,8 +42,8 @@
%<package> }
\def\ExplFileName{xtemplate}
\def\ExplFileDescription{L3 Experimental prototype document functions}
-\def\ExplFileDate{2017/02/10}
-\def\ExplFileVersion{6878}
+\def\ExplFileDate{2017/03/07}
+\def\ExplFileVersion{6984}
%</driver|package>
%<*driver>
\documentclass[full]{l3doc}
@@ -1123,21 +1123,17 @@
\cs_new_protected:Npn \@@_declare_object_type:nn #1#2
{
\int_set:Nn \l_@@_tmp_int {#2}
- \bool_if:nTF
+ \int_compare:nTF { 0 <= \l_@@_tmp_int <= 9 }
{
- \int_compare_p:nNn {#2} > \c_nine ||
- \int_compare_p:nNn {#2} < \c_zero
+ \msg_info:nnxx { xtemplate } { declare-object-type }
+ {#1} { \exp_not:V \l_@@_tmp_int }
+ \prop_gput:NnV \g_@@_object_type_prop {#1}
+ \l_@@_tmp_int
}
{
\msg_error:nnxx { xtemplate } { bad-number-of-arguments }
{#1} { \exp_not:V \l_@@_tmp_int }
}
- {
- \msg_info:nnxx { xtemplate } { declare-object-type }
- {#1} {#2}
- \prop_gput:NnV \g_@@_object_type_prop {#1}
- \l_@@_tmp_int
- }
}
% \end{macrocode}
% \end{macro}