Skip to content

Commit

Permalink
Make \cs_generate_variant:Nn stricter (forbid n to c etc) (fixes #418)
Browse files Browse the repository at this point in the history
This forbids variants that try to change N to n,o,f,V,v,x or n to N,c.
It also makes it an error to try and use unknown letters (more precisely,
that's only an error if the letter changes).
  • Loading branch information
Bruno Le Floch committed Nov 27, 2017
1 parent f284cc4 commit 9e813f4
Show file tree
Hide file tree
Showing 3 changed files with 192 additions and 32 deletions.
70 changes: 43 additions & 27 deletions l3kernel/l3expan.dtx
Expand Up @@ -1611,32 +1611,34 @@
%
% There are further subtleties:
% \begin{itemize}
% \item In \cs{cs_generate_variant:Nn} |\foo:nnTF| |{xxTF}|, it
% would be better to define |\foo:xxTF| using |\exp_args:Nxx|,
% \item In \cs{cs_generate_variant:Nn} |\foo:nnTF| |{xxTF}|, we must define
% |\foo:xxTF| using |\exp_args:Nxx|,
% rather than a hypothetical |\exp_args:NxxTF|. Thus, we wish to
% trim a common trailing part from the base signature and the
% variant signature.
% \item In \cs{cs_generate_variant:Nn} |\foo:on| |{ox}|, the
% function |\foo:ox| should be defined using |\exp_args:Nnx|, not
% function |\foo:ox| must be defined using |\exp_args:Nnx|, not
% |\exp_args:Nox|, to avoid double |o| expansion.
% \item Lastly, \cs{cs_generate_variant:Nn} |\foo:on| |{xn}| should
% \item Lastly, \cs{cs_generate_variant:Nn} |\foo:on| |{xn}| must
% trigger an error, because we do not have a means to replace
% |o|-expansion by |x|-expansion.
% More generally, we can only convert |N| to |c|, or convert |n|
% to |V|, |v|, |o|, |f|, |x|.
% \end{itemize}
% All this boils down to a few rules. Only |n| and |N|-type
% arguments can be replaced by \cs{cs_generate_variant:Nn}. Other
% argument types are allowed to be passed unchanged from the base
% form to the variant: in the process they are changed to |n|
% (except for two cases: |N| and |p|-type arguments). A common
% trailing part is ignored.
% except for |N| and |p|-type arguments. A common trailing
% part is ignored.
%
% We compare the base and variant signatures one character at a time
% within |x|-expansion. The result is given to
% \cs{@@_generate_variant:wwNN} in the form \meta{processed variant
% signature} \cs{q_mark} \meta{errors} \cs{q_stop} \meta{base
% function} \meta{new function}. If all went well, \meta{errors}
% is empty; otherwise, it is a kernel error message, followed by
% some clean-up code (\cs{use_none:nnn}).
% \cs{@@_generate_variant:wwNN} (defined later) in the form
% \meta{processed variant signature} \cs{q_mark} \meta{errors}
% \cs{q_stop} \meta{base function} \meta{new function}. If all went
% well, \meta{errors} is empty; otherwise, it is a kernel error
% message and some clean-up code.
%
% Note the space after |#3| and after the following brace group.
% Those are ignored by \TeX{} when fetching the last argument for
Expand Down Expand Up @@ -1666,7 +1668,7 @@
% \end{macrocode}
% \end{macro}
%
% \begin{macro}[aux, EXP]
% \begin{macro}[aux, rEXP]
% {
% \@@_generate_variant_loop:nNwN,
% \@@_generate_variant_loop_same:w,
Expand All @@ -1675,8 +1677,8 @@
% \@@_generate_variant_loop_invalid:NNwNNnn,
% }
% \begin{arguments}
% \item Last few (consecutive) letters common between the base
% and variant (in fact, \cs{@@_generate_variant_same:N}
% \item Last few consecutive letters common between the base and
% variant (more precisely, \cs{@@_generate_variant_same:N}
% \meta{letter} for each letter).
% \item Next variant letter.
% \item Remainder of variant form.
Expand All @@ -1688,15 +1690,16 @@
% two letters are different: if the loop ends before, the argument is
% dropped, which means that trailing common letters are ignored.
%
% The case where the two letters are different is only allowed with a
% base letter of |N| or |n|. Otherwise, call
% The case where the two letters are different is only allowed if the
% base is |N| and the variant is |c|, or when the base is |n| and the
% variant is |o|, |V|, |v|, |f| or |x|. Otherwise, call
% \cs{@@_generate_variant_loop_invalid:NNwNNnn} to remove the end of
% the loop, get arguments at the end of the loop, and place an
% appropriate error message as a second argument of
% \cs{@@_generate_variant:wwNN}. If the letters are distinct and
% the base letter is indeed |n| or |N|, leave in the input stream
% whatever argument was collected, and the next variant letter |#2|,
% then loop by calling \cs{@@_generate_variant_loop:nNwN}.
% \cs{@@_generate_variant:wwNN}. If the letters are distinct and the
% base letter is indeed |n| or |N|, leave in the input stream whatever
% argument |#1| was collected, and the next variant letter |#2|, then
% loop by calling \cs{@@_generate_variant_loop:nNwN}.
%
% The loop can stop in three ways.
% \begin{itemize}
Expand All @@ -1714,8 +1717,9 @@
% \cs{@@_generate_variant:wwNN}.
% \item The loop can be interrupted early if the requested expansion
% is unavailable, namely when the variant and base letters differ
% and the base is neither |n| nor |N|. Again, an error is placed
% as the second argument of \cs{@@_generate_variant:wwNN}.
% and the base is not the right one (|n| or |N| to support the
% variant). In that case too an error is placed as the second
% argument of \cs{@@_generate_variant:wwNN}.
% \end{itemize}
% Note that if the variant form has the same length as the base form,
% |#2| is as described in the first point, and |#4| as described in
Expand All @@ -1729,10 +1733,22 @@
\if:w #2 #4
\exp_after:wN \@@_generate_variant_loop_same:w
\else:
\if:w N #4 \else:
\if:w n #4 \else:
\@@_generate_variant_loop_invalid:NNwNNnn #4#2
\if:w #4
\if:w c #2 N \else:
\if:w o #2 n \else:
\if:w V #2 n \else:
\if:w v #2 n \else:
\if:w f #2 n \else:
\if:w x #2 n \else:
\scan_stop:
\fi:
\fi:
\fi:
\fi:
\fi:
\fi:
\else:
\@@_generate_variant_loop_invalid:NNwNNnn #4#2
\fi:
\fi:
#1
Expand Down Expand Up @@ -1768,9 +1784,9 @@
}
}
\cs_new:Npn \@@_generate_variant_loop_invalid:NNwNNnn
#1#2 \fi: \fi: \fi: #3 \q_stop #4#5#6#7
#1#2 \fi: \fi: #3 \q_stop #4#5#6#7
{
\fi: \fi: \fi:
\fi: \fi:
\exp_not:n
{
\q_mark
Expand Down
25 changes: 23 additions & 2 deletions l3kernel/testfiles/m3expan001.lvt
@@ -1,6 +1,6 @@
%
% Copyright (C) 2008 Frank Mittelbach
% 2009-2012 The LaTeX3 Project
% 2009-2012,2017 The LaTeX3 Project
%

% Input the regression test macros for LaTeX
Expand Down Expand Up @@ -51,7 +51,6 @@
\foo:oo { \c_aa_tl } { \c_bb_tl }
\foo:VV \c_aa_tl \c_bb_tl
\foo:xx { \c_aa_tl } { \c_bb_tl }
\foo:cc { a } { b }
\foo:nx { a } { \c_b_tl }
\foo:fx { \c_aaa_tl } { \c_bbb_tl }
\foo:xf { \c_aaa_tl } { \c_bbb_tl }
Expand Down Expand Up @@ -107,4 +106,26 @@
\iow_term:x { \cs_meaning:N \foo: }
}

\cs_new:Npn \foobar:Nn { }
\TEST { Incorrect~letters }
{
\cs_generate_variant:Nn \foobar:Nn { pn , :Nn }
\TYPE
{
\cs_meaning:N \foobar:pn ,
\cs_meaning:N \foobar::Nn ,
}
}

\TEST { Issue~418:~changing~N/n~to~incompatible~variants }
{
\cs_generate_variant:Nn \foobar:Nn { on , Nc , n }
\TYPE
{
\cs_meaning:N \foobar:on ,
\cs_meaning:N \foobar:Nc ,
\cs_meaning:N \foobar:nn ,
}
}

\END
129 changes: 126 additions & 3 deletions l3kernel/testfiles/m3expan001.tlg
Expand Up @@ -11,7 +11,25 @@ Defining \foo:nn on line ...
Defining \foo:oo on line ...
Defining \foo:VV on line ...
Defining \foo:xx on line ...
Defining \foo:cc on line ...
Variant \foo:nn already defined; not changing it on line ...
!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!
!
! LaTeX error: "kernel/invalid-variant"
!
! Variant form 'cc' invalid for base form '\foo:nn'.
!
! See the LaTeX3 documentation for further information.
!
! For immediate help type H <return>.
!...............................................
l. ... { oo , VV , xx , cc , nx , fx , xf }
|'''''''''''''''''''''''''''''''''''''''''''''''
| This is a coding error.
|
| LaTeX has been asked to create a variant of the function '\foo:nn' with a
| signature starting with 'cc', but cannot change an argument from type 'n' to
| type 'c'.
|...............................................
Defining \foo:nx on line ...
Defining \exp_args:Nfx on line ...
Defining \foo:fx on line ...
Expand All @@ -26,7 +44,7 @@ TEST 1: protection
\long macro:->\exp_args:Noo \foo:nn
\long macro:->\exp_args:NVV \foo:nn
\protected\long macro:->\exp_args:Nxx \foo:nn
\long macro:->\exp_args:Ncc \foo:nn
undefined
\protected\long macro:->\exp_args:Nnx \foo:nn
\protected\long macro:->\exp_args:Nfx \foo:nn
\protected\long macro:->\exp_args:Nxf \foo:nn
Expand All @@ -41,7 +59,6 @@ TEST 2: expansion
(\c_a_tl )(\c_b_tl )
(\c_a_tl )(\c_b_tl )
(A)(B)
(\a )(\b )
(a)(B)
(A\c_a_tl )(BB)
(AA)(B\c_b_tl )
Expand Down Expand Up @@ -183,3 +200,109 @@ l. ... }
|...............................................
undefined
============================================================
Defining \foobar:Nn on line ...
============================================================
TEST 9: Incorrect letters
============================================================
Variant \foobar:Nn already defined; not changing it on line ...
!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!
!
! LaTeX error: "kernel/invalid-variant"
!
! Variant form 'pn' invalid for base form '\foobar:Nn'.
!
! See the LaTeX3 documentation for further information.
!
! For immediate help type H <return>.
!...............................................
l. ... }
|'''''''''''''''''''''''''''''''''''''''''''''''
| This is a coding error.
|
| LaTeX has been asked to create a variant of the function '\foobar:Nn' with a
| signature starting with 'pn', but cannot change an argument from type 'N' to
| type 'p'.
|...............................................
Variant \foobar:Nn already defined; not changing it on line ...
!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!
!
! LaTeX error: "kernel/invalid-variant"
!
! Variant form ':Nn' invalid for base form '\foobar:Nn'.
!
! See the LaTeX3 documentation for further information.
!
! For immediate help type H <return>.
!...............................................
l. ... }
|'''''''''''''''''''''''''''''''''''''''''''''''
| This is a coding error.
|
| LaTeX has been asked to create a variant of the function '\foobar:Nn' with a
| signature starting with ':Nn', but cannot change an argument from type 'N'
| to type ':'.
|...............................................
undefined,undefined,
============================================================
============================================================
TEST 10: Issue 418: changing N/n to incompatible variants
============================================================
Variant \foobar:Nn already defined; not changing it on line ...
!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!
!
! LaTeX error: "kernel/invalid-variant"
!
! Variant form 'on' invalid for base form '\foobar:Nn'.
!
! See the LaTeX3 documentation for further information.
!
! For immediate help type H <return>.
!...............................................
l. ... }
|'''''''''''''''''''''''''''''''''''''''''''''''
| This is a coding error.
|
| LaTeX has been asked to create a variant of the function '\foobar:Nn' with a
| signature starting with 'on', but cannot change an argument from type 'N' to
| type 'o'.
|...............................................
Variant \foobar:Nn already defined; not changing it on line ...
!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!
!
! LaTeX error: "kernel/invalid-variant"
!
! Variant form 'Nc' invalid for base form '\foobar:Nn'.
!
! See the LaTeX3 documentation for further information.
!
! For immediate help type H <return>.
!...............................................
l. ... }
|'''''''''''''''''''''''''''''''''''''''''''''''
| This is a coding error.
|
| LaTeX has been asked to create a variant of the function '\foobar:Nn' with a
| signature starting with 'Nc', but cannot change an argument from type 'n' to
| type 'c'.
|...............................................
Variant \foobar:Nn already defined; not changing it on line ...
!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!
!
! LaTeX error: "kernel/invalid-variant"
!
! Variant form 'n' invalid for base form '\foobar:Nn'.
!
! See the LaTeX3 documentation for further information.
!
! For immediate help type H <return>.
!...............................................
l. ... }
|'''''''''''''''''''''''''''''''''''''''''''''''
| This is a coding error.
|
| LaTeX has been asked to create a variant of the function '\foobar:Nn' with a
| signature starting with 'n', but cannot change an argument from type 'N' to
| type 'n'.
|...............................................
undefined,undefined,undefined,
============================================================

0 comments on commit 9e813f4

Please sign in to comment.