[latex3-commits] [l3svn] r6858 - Warn when optional arguments cannot be omitted (fixes #3)

noreply at latex-project.org noreply at latex-project.org
Thu Feb 9 18:17:23 CET 2017


Author: bruno
Date: 2017-02-09 18:17:22 +0100 (Thu, 09 Feb 2017)
New Revision: 6858

Modified:
   trunk/l3packages/xparse/testfiles/xparse001.ptex.tlg
   trunk/l3packages/xparse/testfiles/xparse001.tlg
   trunk/l3packages/xparse/testfiles/xparse001.uptex.tlg
   trunk/l3packages/xparse/testfiles/xparse002.luatex.tlg
   trunk/l3packages/xparse/testfiles/xparse002.tlg
   trunk/l3packages/xparse/testfiles/xparse004.lvt
   trunk/l3packages/xparse/testfiles/xparse004.tlg
   trunk/l3packages/xparse/xparse.dtx
Log:
Warn when optional arguments cannot be omitted (fixes #3)

With an argument specifications such as {gom} or {e{_^}or__}
the optional arguments cannot be completely omitted because the
following mandatory argument starts with the same token as an
optional one.  This is now detected but I thought it dangerous
to produce an error so I just put a warning.


Modified: trunk/l3packages/xparse/testfiles/xparse001.ptex.tlg
===================================================================
--- trunk/l3packages/xparse/testfiles/xparse001.ptex.tlg	2017-02-09 04:15:05 UTC (rev 6857)
+++ trunk/l3packages/xparse/testfiles/xparse001.ptex.tlg	2017-02-09 17:17:22 UTC (rev 6858)
@@ -561,6 +561,13 @@
 . 
 . Redefining command \foo with sig. 'mgom' on line ....
 .................................................
+*************************************************
+* LaTeX warning: "xparse/optional-mandatory"
+* 
+* Since the mandatory argument 'm' has the same delimiter '{' as a previous
+* optional argument, it will not be possible to omit all optional arguments
+* when calling this command.
+*************************************************
 > \foo=\protected macro:->\__xparse_start:nNNnnn {mgom}\foo  \foo code
 {\__xparse_grab_m_1:w \__xparse_grab_G:w \__xparse_grab_D:w
 []\__xparse_grab_m_1:w }{.{.-NoValue-}{.-NoValue-}.}{}.
@@ -574,6 +581,13 @@
 . 
 . Redefining command \foo with sig. 'mG{test}sm' on line ....
 .................................................
+*************************************************
+* LaTeX warning: "xparse/optional-mandatory"
+* 
+* Since the mandatory argument 'm' has the same delimiter '{' as a previous
+* optional argument, it will not be possible to omit all optional arguments
+* when calling this command.
+*************************************************
 > \foo=\protected macro:->\__xparse_start:nNNnnn {mG{test}sm}\foo  \foo code
 {\__xparse_grab_m_1:w \__xparse_grab_G:w \__xparse_grab_t:w
 *\__xparse_grab_m_1:w }{.{.test}..}{}.

Modified: trunk/l3packages/xparse/testfiles/xparse001.tlg
===================================================================
--- trunk/l3packages/xparse/testfiles/xparse001.tlg	2017-02-09 04:15:05 UTC (rev 6857)
+++ trunk/l3packages/xparse/testfiles/xparse001.tlg	2017-02-09 17:17:22 UTC (rev 6858)
@@ -561,6 +561,13 @@
 . 
 . Redefining command \foo with sig. 'mgom' on line ....
 .................................................
+*************************************************
+* LaTeX warning: "xparse/optional-mandatory"
+* 
+* Since the mandatory argument 'm' has the same delimiter '{' as a previous
+* optional argument, it will not be possible to omit all optional arguments
+* when calling this command.
+*************************************************
 > \foo=\protected macro:->\__xparse_start:nNNnnn {mgom}\foo  \foo code
 {\__xparse_grab_m_1:w \__xparse_grab_G:w \__xparse_grab_D:w
 []\__xparse_grab_m_1:w }{.{.-NoValue-}{.-NoValue-}.}{}.
@@ -574,6 +581,13 @@
 . 
 . Redefining command \foo with sig. 'mG{test}sm' on line ....
 .................................................
+*************************************************
+* LaTeX warning: "xparse/optional-mandatory"
+* 
+* Since the mandatory argument 'm' has the same delimiter '{' as a previous
+* optional argument, it will not be possible to omit all optional arguments
+* when calling this command.
+*************************************************
 > \foo=\protected macro:->\__xparse_start:nNNnnn {mG{test}sm}\foo  \foo code
 {\__xparse_grab_m_1:w \__xparse_grab_G:w \__xparse_grab_t:w
 *\__xparse_grab_m_1:w }{.{.test}..}{}.

Modified: trunk/l3packages/xparse/testfiles/xparse001.uptex.tlg
===================================================================
--- trunk/l3packages/xparse/testfiles/xparse001.uptex.tlg	2017-02-09 04:15:05 UTC (rev 6857)
+++ trunk/l3packages/xparse/testfiles/xparse001.uptex.tlg	2017-02-09 17:17:22 UTC (rev 6858)
@@ -561,6 +561,13 @@
 . 
 . Redefining command \foo with sig. 'mgom' on line ....
 .................................................
+*************************************************
+* LaTeX warning: "xparse/optional-mandatory"
+* 
+* Since the mandatory argument 'm' has the same delimiter '{' as a previous
+* optional argument, it will not be possible to omit all optional arguments
+* when calling this command.
+*************************************************
 > \foo=\protected macro:->\__xparse_start:nNNnnn {mgom}\foo  \foo code
 {\__xparse_grab_m_1:w \__xparse_grab_G:w \__xparse_grab_D:w
 []\__xparse_grab_m_1:w }{.{.-NoValue-}{.-NoValue-}.}{}.
@@ -574,6 +581,13 @@
 . 
 . Redefining command \foo with sig. 'mG{test}sm' on line ....
 .................................................
+*************************************************
+* LaTeX warning: "xparse/optional-mandatory"
+* 
+* Since the mandatory argument 'm' has the same delimiter '{' as a previous
+* optional argument, it will not be possible to omit all optional arguments
+* when calling this command.
+*************************************************
 > \foo=\protected macro:->\__xparse_start:nNNnnn {mG{test}sm}\foo  \foo code
 {\__xparse_grab_m_1:w \__xparse_grab_G:w \__xparse_grab_t:w
 *\__xparse_grab_m_1:w }{.{.test}..}{}.

Modified: trunk/l3packages/xparse/testfiles/xparse002.luatex.tlg
===================================================================
--- trunk/l3packages/xparse/testfiles/xparse002.luatex.tlg	2017-02-09 04:15:05 UTC (rev 6857)
+++ trunk/l3packages/xparse/testfiles/xparse002.luatex.tlg	2017-02-09 17:17:22 UTC (rev 6858)
@@ -150,6 +150,13 @@
 . 
 . Defining command \foo with sig. 'gom' on line ....
 .................................................
+*************************************************
+* LaTeX warning: "xparse/optional-mandatory"
+* 
+* Since the mandatory argument 'm' has the same delimiter '{' as a previous
+* optional argument, it will not be possible to omit all optional arguments
+* when calling this command.
+*************************************************
 (-NoValue-)(-NoValue-)(a)
 (text)(-NoValue-)(b)
 (text)(opt)(text)
@@ -183,6 +190,13 @@
 . 
 . Defining command \foo with sig. 'gom' on line ....
 .................................................
+*************************************************
+* LaTeX warning: "xparse/optional-mandatory"
+* 
+* Since the mandatory argument 'm' has the same delimiter '{' as a previous
+* optional argument, it will not be possible to omit all optional arguments
+* when calling this command.
+*************************************************
 Runaway argument?
 {
 ! Paragraph ended before \foo  was complete.

Modified: trunk/l3packages/xparse/testfiles/xparse002.tlg
===================================================================
--- trunk/l3packages/xparse/testfiles/xparse002.tlg	2017-02-09 04:15:05 UTC (rev 6857)
+++ trunk/l3packages/xparse/testfiles/xparse002.tlg	2017-02-09 17:17:22 UTC (rev 6858)
@@ -150,6 +150,13 @@
 . 
 . Defining command \foo with sig. 'gom' on line ....
 .................................................
+*************************************************
+* LaTeX warning: "xparse/optional-mandatory"
+* 
+* Since the mandatory argument 'm' has the same delimiter '{' as a previous
+* optional argument, it will not be possible to omit all optional arguments
+* when calling this command.
+*************************************************
 (-NoValue-)(-NoValue-)(a)
 (text)(-NoValue-)(b)
 (text)(opt)(text)
@@ -183,6 +190,13 @@
 . 
 . Defining command \foo with sig. 'gom' on line ....
 .................................................
+*************************************************
+* LaTeX warning: "xparse/optional-mandatory"
+* 
+* Since the mandatory argument 'm' has the same delimiter '{' as a previous
+* optional argument, it will not be possible to omit all optional arguments
+* when calling this command.
+*************************************************
 Runaway argument?
 {
 ! Paragraph ended before \foo  was complete.

Modified: trunk/l3packages/xparse/testfiles/xparse004.lvt
===================================================================
--- trunk/l3packages/xparse/testfiles/xparse004.lvt	2017-02-09 04:15:05 UTC (rev 6857)
+++ trunk/l3packages/xparse/testfiles/xparse004.lvt	2017-02-09 17:17:22 UTC (rev 6858)
@@ -279,4 +279,29 @@
     \DeclareExpandableDocumentCommand { \foo } { >{\abc} m } { }
     \TYPE { \cs_meaning:N \foo }
   }
+
+\TEST { Optional+mandatory~with~same~delimiter }
+  {
+    \DeclareDocumentCommand { \foo } { o R[]{} } { \TYPE{|#1|#2|} }
+    \foo [a][b]
+    \DeclareDocumentCommand { \foo } { O{} r[] } { \TYPE{|#1|#2|} }
+    \foo [a][b]
+    \DeclareDocumentCommand { \foo } { d:, r:. } { \TYPE{|#1|#2|} }
+    \foo :a:b,c,:d.
+    \DeclareDocumentCommand { \foo } { D:,{} R:.{} } { \TYPE{|#1|#2|} }
+    \foo :a:b,c,:d.
+    \DeclareDocumentCommand { \foo } { o s r[] } { \TYPE{|#1|#2|#3|} }
+    \foo *[a]
+    \DeclareDocumentCommand { \foo } { g m } { \TYPE{|#1|#2|} }
+    \foo a     \foo {a}{b}
+    \DeclareDocumentCommand { \foo } { G{} m } { \TYPE{|#1|#2|} }
+    \foo a     \foo {a}{b}
+    \DeclareDocumentCommand { \foo } { s r** } { \TYPE{|#1|#2|} }
+    \foo **a*
+    \DeclareDocumentCommand { \foo } { t( r() t) } { \TYPE{|#1|#2|#3|} }
+    \foo ((a(b)c))
+    \DeclareDocumentCommand { \foo } { e{_^} s r__ } { \TYPE{|#1|#2|#3|} }
+    \foo ^{a}____ \foo _a_abc_ \foo *_a_
+  }
+
 \END

Modified: trunk/l3packages/xparse/testfiles/xparse004.tlg
===================================================================
--- trunk/l3packages/xparse/testfiles/xparse004.tlg	2017-02-09 04:15:05 UTC (rev 6857)
+++ trunk/l3packages/xparse/testfiles/xparse004.tlg	2017-02-09 17:17:22 UTC (rev 6858)
@@ -1070,6 +1070,13 @@
 . Defining command \foo with sig. 'D<>{##2}G{##4##1}E{_^}{{1}{2}}O{##3##5}m'
 . on line ....
 .................................................
+*************************************************
+* LaTeX warning: "xparse/optional-mandatory"
+* 
+* Since the mandatory argument 'm' has the same delimiter '{' as a previous
+* optional argument, it will not be possible to omit all optional arguments
+* when calling this command.
+*************************************************
 \A |{\B }{2}\C \A |{\B }{2}|{\B }{2}\C |\C 
 \A |\A |{1}{2}|{1}{2}\B |\B 
 \A |\A |{1}{2}|\B |\C 
@@ -1263,3 +1270,141 @@
 |...............................................
 undefined
 ============================================================
+============================================================
+TEST 15: Optional+mandatory with same delimiter
+============================================================
+.................................................
+. LaTeX info: "xparse/define-command"
+. 
+. Defining command \foo with sig. 'oR[]{}' on line ....
+.................................................
+*************************************************
+* LaTeX warning: "xparse/optional-mandatory"
+* 
+* Since the mandatory argument 'R' has the same delimiter '[' as a previous
+* optional argument, it will not be possible to omit all optional arguments
+* when calling this command.
+*************************************************
+|a|b|
+.................................................
+. LaTeX info: "xparse/redefine-command"
+. 
+. Redefining command \foo with sig. 'O{}r[]' on line ....
+.................................................
+*************************************************
+* LaTeX warning: "xparse/optional-mandatory"
+* 
+* Since the mandatory argument 'r' has the same delimiter '[' as a previous
+* optional argument, it will not be possible to omit all optional arguments
+* when calling this command.
+*************************************************
+|a|b|
+.................................................
+. LaTeX info: "xparse/redefine-command"
+. 
+. Redefining command \foo with sig. 'd:,r:.' on line ....
+.................................................
+*************************************************
+* LaTeX warning: "xparse/optional-mandatory"
+* 
+* Since the mandatory argument 'r' has the same delimiter ':' as a previous
+* optional argument, it will not be possible to omit all optional arguments
+* when calling this command.
+*************************************************
+|a:b,c|d|
+.................................................
+. LaTeX info: "xparse/redefine-command"
+. 
+. Redefining command \foo with sig. 'D:,{}R:.{}' on line ....
+.................................................
+*************************************************
+* LaTeX warning: "xparse/optional-mandatory"
+* 
+* Since the mandatory argument 'R' has the same delimiter ':' as a previous
+* optional argument, it will not be possible to omit all optional arguments
+* when calling this command.
+*************************************************
+|a:b,c|d|
+.................................................
+. LaTeX info: "xparse/redefine-command"
+. 
+. Redefining command \foo with sig. 'osr[]' on line ....
+.................................................
+*************************************************
+* LaTeX warning: "xparse/optional-mandatory"
+* 
+* Since the mandatory argument 'r' has the same delimiter '[' as a previous
+* optional argument, it will not be possible to omit all optional arguments
+* when calling this command.
+*************************************************
+|-NoValue-|\BooleanTrue |a|
+.................................................
+. LaTeX info: "xparse/redefine-command"
+. 
+. Redefining command \foo with sig. 'gm' on line ....
+.................................................
+*************************************************
+* LaTeX warning: "xparse/optional-mandatory"
+* 
+* Since the mandatory argument 'm' has the same delimiter '{' as a previous
+* optional argument, it will not be possible to omit all optional arguments
+* when calling this command.
+*************************************************
+|-NoValue-|a|
+|a|b|
+.................................................
+. LaTeX info: "xparse/redefine-command"
+. 
+. Redefining command \foo with sig. 'G{}m' on line ....
+.................................................
+*************************************************
+* LaTeX warning: "xparse/optional-mandatory"
+* 
+* Since the mandatory argument 'm' has the same delimiter '{' as a previous
+* optional argument, it will not be possible to omit all optional arguments
+* when calling this command.
+*************************************************
+||a|
+|a|b|
+.................................................
+. LaTeX info: "xparse/redefine-command"
+. 
+. Redefining command \foo with sig. 'sr**' on line ....
+.................................................
+*************************************************
+* LaTeX warning: "xparse/optional-mandatory"
+* 
+* Since the mandatory argument 'r' has the same delimiter '*' as a previous
+* optional argument, it will not be possible to omit all optional arguments
+* when calling this command.
+*************************************************
+|\BooleanTrue |a|
+.................................................
+. LaTeX info: "xparse/redefine-command"
+. 
+. Redefining command \foo with sig. 't(r()t)' on line ....
+.................................................
+*************************************************
+* LaTeX warning: "xparse/optional-mandatory"
+* 
+* Since the mandatory argument 'r' has the same delimiter '(' as a previous
+* optional argument, it will not be possible to omit all optional arguments
+* when calling this command.
+*************************************************
+|\BooleanTrue |a(b)c|\BooleanTrue |
+.................................................
+. LaTeX info: "xparse/redefine-command"
+. 
+. Redefining command \foo with sig. 'e{_^}sr__' on line ....
+.................................................
+*************************************************
+* LaTeX warning: "xparse/optional-mandatory"
+* 
+* Since the mandatory argument 'r' has the same delimiter '_' as a previous
+* optional argument, it will not be possible to omit all optional arguments
+* when calling this command.
+*************************************************
+|{_}{a}|\BooleanFalse ||
+|{a}{-NoValue-}|\BooleanFalse |abc|
+|{-NoValue-}{-NoValue-}|\BooleanTrue |a|
+============================================================

Modified: trunk/l3packages/xparse/xparse.dtx
===================================================================
--- trunk/l3packages/xparse/xparse.dtx	2017-02-09 04:15:05 UTC (rev 6857)
+++ trunk/l3packages/xparse/xparse.dtx	2017-02-09 17:17:22 UTC (rev 6858)
@@ -255,6 +255,15 @@
 % argument is given as a string of characters with category codes~$12$
 % or~$13$, except spaces, which have category code~$10$.
 %
+% When an optional argument is followed by a mandatory argument with the
+% same delimiter, \pkg{xparse} issues a warning because the optional
+% argument could not be omitted by the user, thus becoming in effect
+% mandatory.  This applies to \texttt{o}, \texttt{d}, \texttt{O},
+% \texttt{D}, \texttt{s}, \texttt{t}, \texttt{e}, and \texttt{E} type
+% arguments followed by \texttt{r} or \texttt{R}-type required
+% arguments, but also to \texttt{g} or \texttt{G} type arguments
+% followed by \texttt{m} type arguments.
+%
 % \subsection{Spacing and optional arguments}
 %
 % \TeX{} will find the first argument after a function name irrespective
@@ -894,6 +903,17 @@
 %    \end{macrocode}
 % \end{variable}
 %
+% \begin{variable}{\l_@@_last_delimiters_tl}
+%   Holds the delimiters (first tokens) of all optional arguments since
+%   the previous mandatory argument, to warn about cases where it would
+%   be impossible to omit optional arguments completely because the
+%   following mandatory argument has the same delimiter as one of the
+%   optional arguments.
+%    \begin{macrocode}
+\tl_new:N \l_@@_last_delimiters_tl
+%    \end{macrocode}
+% \end{variable}
+%
 % \begin{variable}{\l_@@_long_bool}
 %   Used to indicate that an argument is long: this is used on a per-argument
 %   basis for non-expandable functions, or for the entire set of arguments
@@ -1340,6 +1360,7 @@
   {
     \int_zero:N \l_@@_mandatory_args_int
     \int_zero:N \l_@@_current_arg_int
+    \tl_clear:N \l_@@_last_delimiters_tl
     \tl_clear:N \l_@@_arg_spec_tl
     \@@_normalize_arg_spec_loop:n #1
       \q_recursion_tail \q_recursion_tail \q_recursion_tail \q_recursion_stop
@@ -1408,6 +1429,10 @@
 %   argument), \texttt{u} (any preceding optional argument may wrap part
 %   of the delimiter up in braces), and \texttt{v}.
 %
+%   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.
 %    \begin{macrocode}
 \cs_new_protected:cpn { @@_normalize_type_>:w } #1#2
@@ -1437,6 +1462,7 @@
     \quark_if_recursion_tail_stop_do:Nn #2 { \@@_bad_arg_spec:wn }
     \tl_put_right:Nx \l_@@_arg_spec_tl
       { \exp_not:n { D #1 #2 } { \c_@@_no_value_tl } }
+    \tl_put_right:Nn \l_@@_last_delimiters_tl {#1}
     \@@_normalize_arg_spec_loop:n
   }
 \cs_new_protected:Npn \@@_normalize_type_D:w #1#2#3
@@ -1445,6 +1471,7 @@
     \@@_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} }
+    \tl_put_right:Nn \l_@@_last_delimiters_tl {#1}
     \@@_normalize_arg_spec_loop:n
   }
 \cs_new_protected:Npn \@@_normalize_type_e:w #1
@@ -1454,6 +1481,7 @@
     \tl_map_function:nN {#1} \@@_single_token_check:n
     \@@_normalize_error_if_expandable:N e
     \tl_put_right:Nn \l_@@_arg_spec_tl { E {#1} { } }
+    \tl_put_right:Nn \l_@@_last_delimiters_tl {#1}
     \@@_normalize_arg_spec_loop:n
   }
 \cs_new_protected:Npn \@@_normalize_type_E:w #1#2
@@ -1465,12 +1493,14 @@
       { \@@_bad_arg_spec:wn }
     \@@_normalize_error_if_expandable:N E
     \tl_put_right:Nn \l_@@_arg_spec_tl { E {#1} {#2} }
+    \tl_put_right:Nn \l_@@_last_delimiters_tl {#1}
     \@@_normalize_arg_spec_loop:n
   }
 \cs_new_protected:Npn \@@_normalize_type_g:w
   {
     \@@_normalize_error_if_expandable:N g
     \tl_put_right:Nx \l_@@_arg_spec_tl { G { \c_@@_no_value_tl } }
+    \tl_put_right:Nn \l_@@_last_delimiters_tl { { } }
     \@@_normalize_arg_spec_loop:n
   }
 \cs_new_protected:Npn \@@_normalize_type_G:w #1
@@ -1478,6 +1508,7 @@
     \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} }
+    \tl_put_right:Nn \l_@@_last_delimiters_tl { { } }
     \@@_normalize_arg_spec_loop:n
   }
 \cs_new_protected:Npn \@@_normalize_type_l:w
@@ -1485,24 +1516,28 @@
     \@@_normalize_error_if_expandable:N l
     \int_incr:N \l_@@_mandatory_args_int
     \tl_put_right:Nn \l_@@_arg_spec_tl { l }
+    \tl_clear:N \l_@@_last_delimiters_tl
     \@@_normalize_arg_spec_loop:n
   }
 \cs_new_protected:Npn \@@_normalize_type_m:w
   {
     \int_incr:N \l_@@_mandatory_args_int
     \tl_put_right:Nn \l_@@_arg_spec_tl { m }
+    \@@_delimiter_check:nnn { } { m } { \iow_char:N \{ }
     \@@_normalize_arg_spec_loop:n
   }
 \cs_new_protected:Npn \@@_normalize_type_o:w
   {
     \tl_put_right:Nx \l_@@_arg_spec_tl
       { \exp_not:n { D [ ] } { \c_@@_no_value_tl } }
+    \tl_put_right:Nn \l_@@_last_delimiters_tl { [ }
     \@@_normalize_arg_spec_loop:n
   }
 \cs_new_protected:Npn \@@_normalize_type_O:w #1
   {
     \quark_if_recursion_tail_stop_do:nn {#1} { \@@_bad_arg_spec:wn }
     \tl_put_right:Nn \l_@@_arg_spec_tl { D [ ] {#1} }
+    \tl_put_right:Nn \l_@@_last_delimiters_tl { [ }
     \@@_normalize_arg_spec_loop:n
   }
 \cs_new_protected:Npn \@@_normalize_type_r:w #1#2
@@ -1513,6 +1548,7 @@
     \tl_put_right:Nx \l_@@_arg_spec_tl
       { \exp_not:n { R #1 #2 } { \c_@@_no_value_tl } }
     \int_incr:N \l_@@_mandatory_args_int
+    \@@_delimiter_check:nnn {#1} { r } { \tl_to_str:n {#1} }
     \@@_normalize_arg_spec_loop:n
   }
 \cs_new_protected:Npn \@@_normalize_type_R:w #1#2#3
@@ -1522,11 +1558,13 @@
     \quark_if_recursion_tail_stop_do:nn {#3} { \@@_bad_arg_spec:wn }
     \tl_put_right:Nn \l_@@_arg_spec_tl { R #1 #2 {#3} }
     \int_incr:N \l_@@_mandatory_args_int
+    \@@_delimiter_check:nnn {#1} { R } { \tl_to_str:n {#1} }
     \@@_normalize_arg_spec_loop:n
   }
 \cs_new_protected:Npn \@@_normalize_type_s:w
   {
     \tl_put_right:Nn \l_@@_arg_spec_tl { t * }
+    \tl_put_right:Nn \l_@@_last_delimiters_tl { * }
     \@@_normalize_arg_spec_loop:n
   }
 \cs_new_protected:Npn \@@_normalize_type_t:w #1
@@ -1534,6 +1572,7 @@
     \@@_single_token_check:n {#1}
     \quark_if_recursion_tail_stop_do:Nn #1 { \@@_bad_arg_spec:wn }
     \tl_put_right:Nn \l_@@_arg_spec_tl { t #1 }
+    \tl_put_right:Nn \l_@@_last_delimiters_tl {#1}
     \@@_normalize_arg_spec_loop:n
   }
 \cs_new_protected:Npn \@@_normalize_type_u:w #1
@@ -1542,6 +1581,7 @@
     \@@_normalize_error_if_expandable:N u
     \tl_put_right:Nn \l_@@_arg_spec_tl { 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
@@ -1549,6 +1589,7 @@
     \@@_normalize_error_if_expandable:N v
     \int_incr:N \l_@@_mandatory_args_int
     \tl_put_right:Nn \l_@@_arg_spec_tl { v }
+    \tl_clear:N \l_@@_last_delimiters_tl
     \@@_normalize_arg_spec_loop:n
   }
 %    \end{macrocode}
@@ -1585,6 +1626,26 @@
 %    \end{macrocode}
 % \end{macro}
 %
+% \begin{macro}{\@@_delimiter_check:nnn}
+%   Called for mandatory arguments.  Checks that the leading token does
+%   not coincide with the token denoting the presence of a previous
+%   optional argument.
+%    \begin{macrocode}
+\cs_new_protected:Npn \@@_delimiter_check:nnn #1#2#3
+  {
+    \tl_map_inline:Nn \l_@@_last_delimiters_tl
+      {
+        \tl_if_eq:nnT {##1} {#1}
+          {
+            \__msg_kernel_warning:nnxx { xparse } { optional-mandatory }
+              {#2} {#3}
+          }
+      }
+    \tl_clear:N \l_@@_last_delimiters_tl
+  }
+%    \end{macrocode}
+% \end{macro}
+%
 % \begin{macro}{\@@_bad_arg_spec:wn, \@@_bad_arg_spec_no_error:wn}
 %   If the argument specification is wrong, this provides an escape from the entire
 %   definition process.
@@ -3739,6 +3800,12 @@
     Redefining~environment~'#1'~
     with~sig.~'#2'~\msg_line_context:.
   }
+\__msg_kernel_new:nnn { xparse } { optional-mandatory }
+  {
+    Since~the~mandatory~argument~'#1'~has~the~same~delimiter~'#2'~
+    as~a~previous~optional~argument,~it~will~not~be~possible~to~
+    omit~all~optional~arguments~when~calling~this~command.
+  }
 %    \end{macrocode}
 %
 % \subsection{User functions}



More information about the latex3-commits mailing list