From 6fca20c09474a7f6a3559af1c984243a83669f61 Mon Sep 17 00:00:00 2001 From: Karl Berry Date: Wed, 8 Mar 2017 23:01:35 +0000 Subject: l3 (8mar17) git-svn-id: svn://tug.org/texlive/trunk@43432 c570f23f-e606-0410-a88d-b1316a301751 --- .../source/latex/l3packages/l3keys2e/l3keys2e.dtx | 8 +- .../texmf-dist/source/latex/l3packages/xfp/xfp.dtx | 167 ++++ .../texmf-dist/source/latex/l3packages/xfp/xfp.ins | 45 ++ .../source/latex/l3packages/xfrac/xfrac.dtx | 8 +- .../source/latex/l3packages/xparse/xparse.dtx | 894 +++++++++++++-------- .../latex/l3packages/xtemplate/xtemplate.dtx | 22 +- 6 files changed, 805 insertions(+), 339 deletions(-) create mode 100644 Master/texmf-dist/source/latex/l3packages/xfp/xfp.dtx create mode 100644 Master/texmf-dist/source/latex/l3packages/xfp/xfp.ins (limited to 'Master/texmf-dist/source/latex/l3packages') 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] -%\@ifpackagelater{expl3}{2017/02/10} +\RequirePackage{expl3}[2017/03/07] +%\@ifpackagelater{expl3}{2017/03/07} % {} % {% % \PackageError{l3keys2e}{Support package l3kernel too old} @@ -38,8 +38,8 @@ % } \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> \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] +%\@ifpackagelater{expl3}{2017/03/07} +% {} +% {% +% \PackageError{xfpu}{Support package l3kernel too old} +% {% +% Please install an up to date version of l3kernel\MessageBreak +% using your TeX package manager or from CTAN.\MessageBreak +% \MessageBreak +% Loading xfpu will abort!% +% }% +% \endinput +% } +\def\ExplFileName{xfp} +\def\ExplFileDescription{LaTeX Floating Point Unit} +\def\ExplFileDate{2017/03/07} +\def\ExplFileVersion{6984} +% +%<*driver> +\documentclass[full]{l3doc} +\usepackage{amstext} +\begin{document} + \DocInput{\jobname.dtx} +\end{document} +% +% \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} +% +% \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] -%\@ifpackagelater{expl3}{2017/02/10} +\RequirePackage{expl3}[2017/03/07] +%\@ifpackagelater{expl3}{2017/03/07} % {} % {% % \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> \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] -%\@ifpackagelater{expl3}{2017/02/10} +\RequirePackage{expl3}[2017/03/07] +%\@ifpackagelater{expl3}{2017/03/07} % {} % {% % \PackageError{xparse}{Support package l3kernel too old} @@ -42,8 +42,8 @@ % } \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> \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] -%\@ifpackagelater{expl3}{2017/02/10} +\RequirePackage{expl3}[2017/03/07] +%\@ifpackagelater{expl3}{2017/03/07} % {} % {% % \PackageError{xtemplate}{Support package l3kernel too old} @@ -42,8 +42,8 @@ % } \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> \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} -- cgit v1.2.3