[latex3-commits] [git/LaTeX3-latex3-latex2e] gh239: First implementation of \LetRobustCommand (9aa1c9ca)

PhelypeOleinik tex.phelype at gmail.com
Mon May 4 13:59:02 CEST 2020


Repository : https://github.com/latex3/latex2e
On branch  : gh239
Link       : https://github.com/latex3/latex2e/commit/9aa1c9ca488c022f9441f789e9737fac5f726494

>---------------------------------------------------------------

commit 9aa1c9ca488c022f9441f789e9737fac5f726494
Author: PhelypeOleinik <tex.phelype at gmail.com>
Date:   Mon May 4 08:59:02 2020 -0300

    First implementation of \LetRobustCommand
    
    This implementation is a copy of Heiko's \LetLtxMacro with slight modifications thanks to e-TeX.


>---------------------------------------------------------------

9aa1c9ca488c022f9441f789e9737fac5f726494
 base/ltdefns.dtx                                   | 224 ++++++++++++++++++++-
 base/testfiles/github-0239.lvt                     |  50 +++++
 base/testfiles/github-0239.tlg                     |  29 +++
 .../tlb-latexrelease-rollback-003-often.luatex.tlg |   4 +
 .../tlb-latexrelease-rollback-003-often.tlg        |   4 +
 .../tlb-latexrelease-rollback-003-often.xetex.tlg  |   4 +
 base/testfiles/tlb-rollback-004-often.luatex.tlg   |   2 +
 base/testfiles/tlb-rollback-004-often.tlg          |   2 +
 base/testfiles/tlb-rollback-004-often.xetex.tlg    |   2 +
 9 files changed, 319 insertions(+), 2 deletions(-)

diff --git a/base/ltdefns.dtx b/base/ltdefns.dtx
index 303b9e56..53d1c444 100644
--- a/base/ltdefns.dtx
+++ b/base/ltdefns.dtx
@@ -32,7 +32,7 @@
 %<*driver>
 % \fi
 \ProvidesFile{ltdefns.dtx}
-             [2020/02/27 v1.5g LaTeX Kernel (definition commands)]
+             [2020/02/27 v1.5h LaTeX Kernel (definition commands)]
 % \iffalse
 \documentclass{ltxdoc}
 \GetFileInfo{ltdefns.dtx}
@@ -1261,8 +1261,228 @@
 % \end{macro}
 %
 %
+% \begin{macro}{\LetRobustCommand}
+% \changes{v1.5h}{2020/05/01}{Added macro (gh/239)}
+%
+%   With most document level commands being robust now there is more of a
+%   requirement to have a standard way of aliasing (or copying) a command to a
+%   new name, for example to save an original definition before changing a
+%   command.  \cs{LetRobustCommand} is analogous to \TeX's \cs{let}, except that
+%   it copes with the different types of robust commands defined by \LaTeX's
+%   mechanisms.
+%
+%   The current implementation is an almost exact copy of Heiko Oberdiek's
+%   \cs{LetLtxMacro}, with changed names and some simplifications thanks to
+%   $\epsilon$-\TeX.
+%    \begin{macrocode}
+%</2ekernel>
+%<latexrelease>\IncludeInRelease{2020/10/01}{\LetRobustCommand}{\LetRobustCommand}%
+%<*2ekernel|latexrelease>
+%    \end{macrocode}
+%   \cs{LetRobustCommand} just calls \cs{let at robustcommand} with a \cs{relax}
+%   which serves as a prefix for definitions.  Heiko's \pkg{letltxmacro} defines
+%   a global variant of \cs{LetLtxMacro}, but since none of our definition
+%   commands have a global version, this one won't either, for consistency.
+%    \begin{macrocode}
+\def\LetRobustCommand{\let at robustcommand\relax}
+%    \end{macrocode}
+%   Start by saving the current value of \cs{escapechar} and setting it to $-1$.
+%    \begin{macrocode}
+\def\let at robustcommand#1#2#3{%
+  \edef\reserved at a{\the\escapechar}%
+  \escapechar=-1 %
+%    \end{macrocode}
+%   First we do some normalisation, to cover the case where \verb=#3= expands to
+%   \verb*=\protect\#3 =.  This is the case when \verb=#3= is a multi-letter
+%   control sequence defined with \cs{DeclareRobustCommand}.  In this case we
+%   copy \verb*=\#3 = into \verb*=\#2 = and then call the inner
+%   \cs{let at robust@command} with \verb*=\#2 = and \verb*=\#3 = rather than
+%   \verb*=\#2= and \verb*=\#3=.
+%    \begin{macrocode}
+  \edef\reserved at b{%
+    \noexpand\protect
+    \expandafter\noexpand\csname\string#3 \endcsname
+  }%
+  \ifx\reserved at b#3\relax
+    #1\edef#2{%
+      \noexpand\protect
+      \expandafter\noexpand
+      \csname\string#2 \endcsname
+    }%
+    #1\expandafter\let
+    \csname\string#2 \expandafter\endcsname
+    \csname\string#3 \endcsname
+    \expandafter\let at robust@command
+      \csname\string#2 \expandafter\endcsname
+      \csname\string#3 \endcsname{#1}%
+%    \end{macrocode}
+%   Otherwise just call \cs{let at robust@command} with \verb*=\#2= and \verb*=\#3=
+%   to do the heavy-lifting.
+%    \begin{macrocode}
+  \else
+    \let at robust@command{#2}{#3}{#1}%
+  \fi
+%    \end{macrocode}
+%   Reset \cs{escapechar} when we're done.
+%    \begin{macrocode}
+  \escapechar=\reserved at a\relax
+}
+%    \end{macrocode}
+%   Check if the \verb=#2= is actually a macro, otherwise just use \cs{let}.
+%    \begin{macrocode}
+\def\let at robust@command#1#2#3{%
+  \escapechar=92 %
+  \expandafter\let at robust@chk at parm\meaning#2:->\@nil{%
+%    \end{macrocode}
+%   Now the real fun begins.  We'll redefine (in a group) some of \LaTeX's
+%   optional argument-processing macros because TODO
+%   Also make \cs{let at robust@testopt} equal to \cs{@empty} to signal no optional
+%   argument (may change).
+%    \begin{macrocode}
+    \begingroup
+      \def\@protected at testopt{%
+        \expandafter\@testopt\@gobble}%
+      \def\@testopt##1##2{%
+        \toks@={##2}}%
+      \let\let at robust@testopt\@empty
+%    \end{macrocode}
+%   Define \cs{reserved at c} as \verb=\@protected at testopt\#2\\#2=\ldots
+%    \begin{macrocode}
+      \edef\reserved at c{%
+        \noexpand\@protected at testopt
+        \noexpand#2%
+        \expandafter\noexpand\csname\string#2\endcsname
+      }%
+%    \end{macrocode}
+%   and define \cs{reserved at d} as the first three (or fewer) tokens in the
+%   expansion of \verb=#2=\ldots
+%    \begin{macrocode}
+      \edef\reserved at d{%
+        \unexpanded\expandafter\expandafter\expandafter
+          {\expandafter\let at robust@CarThree#2{}{}{}\@nil}}
+%    \end{macrocode}
+%   then compare both.  If they are equal, the macro contains a test for an
+%   optional argument, in which case \verb=#2= is executed, so that the default
+%   value of the optional argument is stored in \cs{toks@} and
+%   \cs{let at robust@testopt} is redefined accordingly.
+%    \begin{macrocode}
+      \ifx\reserved at c\reserved at d
+        #2%
+        \def\let at robust@testopt{%
+          \noexpand\@protected at testopt
+          \noexpand#1%
+        }%
+%    \end{macrocode}
+%   Otherwise we try again and redefine \cs{reserved at c} as
+%   \verb=\@testopt\\#2=\ldots
+%    \begin{macrocode}
+      \else
+        \edef\reserved at c{%
+          \noexpand\@testopt
+          \expandafter\noexpand
+          \csname\string#2\endcsname
+        }%
+%    \end{macrocode}
+%   and \cs{reserved at d} as the first two (or fewer) tokens in the expansion of
+%   \verb=#2=.  Now if they are equal, execute \verb=#2= so that the default
+%   value of the optional argument of \verb=#2= is stored in \cs{toks@}, and
+%   then reassign \cs{let at robust@testopt} to be \cs{@testopt}.
+%    \begin{macrocode}
+        \edef\reserved at d{%
+          \unexpanded\expandafter\expandafter\expandafter
+            {\expandafter\let at robust@CarTwo#2{}{}{}\@nil}}
+        \ifx\reserved at c\reserved at d
+          #2%
+          \def\let at robust@testopt{%
+            \noexpand\@testopt
+          }%
+        \fi
+      \fi
+%    \end{macrocode}
+%   Now, unless \cs{let at robust@testopt} is empty (that is, no optional argument)
+%   define \cs{let at robust@GlobalTemp} to be
+%   \meta{testopt}\cs{\#1}\{\meta{opt-default}\}, where
+%   \meta{testopt} is either \verb=\@protected at testopt\#2=, or \verb=\@testopt=.
+%    \begin{macrocode}
+      \ifx\let at robust@testopt\@empty
+      \else
+        \let at robust@protected\xdef\let at robust@GlobalTemp{%
+          \let at robust@testopt
+          \expandafter\noexpand
+          \csname\string#1\endcsname
+          {\the\toks@}%
+        }%
+      \fi
+%    \end{macrocode}
+%   We're almost done now.  If \cs{let at robust@testopt} remained empty all along,
+%   then the macro didn't have an optional argument and we just need to \cs{let}
+%   one to the other.
+%   Otherwise we \cs{let} \verb=\#1=, the top-level macro, to
+%   \cs{let at robust@GlobalTemp}, and then \cs{let} \verb=\\#1= to \verb=\\#2=,
+%   which is the actual definition of the macro.
+%    \begin{macrocode}
+    \expandafter\endgroup\ifx\let at robust@testopt\@empty
+      #3\let#1=#2\relax
+    \else
+      #3\let#1=\let at robust@GlobalTemp
+      #3\expandafter\let
+          \csname\string#1\expandafter\endcsname
+          \csname\string#2\endcsname
+    \fi
+  }{%
+    #3\let#1=#2\relax
+  }%
+}
+%    \end{macrocode}
+%   This auxiliary detects whether the argument is a macro (otherwise this
+%   entire process boils down to \TeX's \cs{let}), and in case of a
+%   \cs{protected} macro (using \pkg{etoolbox}'s \cs{newrobustcmd}), define
+%   \cs{let at robust@protected} accordingly.
+%    \begin{macrocode}
+\def\let at robust@chk at parm#1:->#2\@nil{%
+  \tmp at strifeq{#1}{macro}%
+    {%
+      \def\let at robust@protected{}%
+      \@firstoftwo
+    }{%
+      \tmp at strifeq{#1}{\protected macro}%
+        {%
+          \def\let at robust@protected{\protected}%
+          \@firstoftwo%
+        }
+        {\@secondoftwo}%
+    }%
+}
+%    \end{macrocode}
+%   This is just a temporary poor-man's string comparison macro to make things
+%   easier.  This should be replaced by \cs{@expl at str@if at eq@nnTF} once that's
+%   defined.
+%    \begin{macrocode}
+\def\tmp at strifeq#1#2{%
+  \begingroup
+    \edef\reserved at a{\detokenize{#1}}%
+    \edef\reserved at b{\detokenize{#2}}%
+  \expandafter\endgroup
+  \ifx\reserved at a\reserved at b
+    \expandafter\@firstoftwo
+  \else
+    \expandafter\@secondoftwo
+  \fi}
+%    \end{macrocode}
+%   Takes the first two or three tokens of the argument.
+%    \begin{macrocode}
+\def\let at robust@CarTwo#1#2#3\@nil{#1#2}%
+\def\let at robust@CarThree#1#2#3#4\@nil{#1#2#3}%
+%</2ekernel|latexrelease>
+%<latexrelease>\EndIncludeInRelease
+%<latexrelease>\IncludeInRelease{0000/00/00}{\LetRobustCommand}{\LetRobustCommand}%
+%<latexrelease>\let\LetRobustCommand\@undefined
+%<latexrelease>\EndIncludeInRelease
+%<*2ekernel>
+%    \end{macrocode}
+% \end{macro}
+%
 %
-
 %  \begin{macro}{\kernel at make@fragile}
 %    The opposite of |\MakeRobust| execpt that it doesn't do many
 %    checks as it is internal to the kernel. Why does one want such a
diff --git a/base/testfiles/github-0239.lvt b/base/testfiles/github-0239.lvt
new file mode 100644
index 00000000..ef43b8b7
--- /dev/null
+++ b/base/testfiles/github-0239.lvt
@@ -0,0 +1,50 @@
+
+\documentclass{article}
+\input{test2e}
+
+\showoutput
+
+\begin{document}
+
+\START
+
+\def\testt#1#2#3#4{%
+  #4%
+  \LetRobustCommand#1#3%
+  \testtt#1
+  \expandafter\testtt\csname#2\space\endcsname
+  \expandafter\testtt\csname\string#1\endcsname
+  \expandafter\testtt\csname\string#1\space\endcsname
+  \typeout{}}
+\def\testtt#1{%
+  \typeout{\string#1=\meaning#1|}%
+  \let#1\undefined}
+
+% Here we need control words
+\def\test{\testt\tmp{tmp}}
+
+\test\cmda{\newcommand\cmda[1][]{boo}}
+
+\test\cmdb{\DeclareRobustCommand\cmdb[1]{boo}}
+
+\test\cmdc{\DeclareRobustCommand\cmdc[1][]{boo}}
+
+% \test\cmdd{\newrobustcmd\cmdd[1]{boo}}
+
+% \test\cmde{\newrobustcmd\cmde[1][]{boo}}
+
+% And here control symbols
+\def\test{\testt\+{+}}
+
+\test\!{\renewcommand\![1][]{boo}}
+
+\test\@{\DeclareRobustCommand\@[1]{boo}}
+
+\test\#{\DeclareRobustCommand\#[1][]{boo}}
+
+% \test\${\renewrobustcmd\$[1]{boo}}
+
+% \test\&{\renewrobustcmd\&[1][]{boo}}
+
+\end{document}
+
diff --git a/base/testfiles/github-0239.tlg b/base/testfiles/github-0239.tlg
new file mode 100644
index 00000000..43bcd13c
--- /dev/null
+++ b/base/testfiles/github-0239.tlg
@@ -0,0 +1,29 @@
+This is a generated file for the LaTeX2e validation system.
+Don't change this file in any respect.
+\tmp=macro:->\@protected at testopt \tmp \\tmp {}|
+\tmp =\relax|
+\\tmp=\long macro:[#1]->boo|
+\\tmp =\relax|
+\tmp=macro:->\protect \tmp  |
+\tmp =\long macro:#1->boo|
+\\tmp=\relax|
+\\tmp =\relax|
+\tmp=macro:->\protect \tmp  |
+\tmp =macro:->\@protected at testopt \tmp  \\tmp  {}|
+\\tmp=\relax|
+\\tmp =\long macro:[#1]->boo|
+\+=macro:->\@protected at testopt \+\\+ {}|
+\+ =\relax|
+\\+=\long macro:[#1]->boo|
+\\+ =\relax|
+LaTeX Info: Redefining \@ on input line ....
+\+=macro:->\protect \+  |
+\+ =\long macro:#1->boo|
+\\+=\relax|
+\\+ =\relax|
+LaTeX Info: Redefining \# on input line ....
+\+=macro:->\x at protect \#\protect \#  |
+\+ =\relax|
+\\+=\relax|
+\\+ =\relax|
+(github-0239.aux)
diff --git a/base/testfiles/tlb-latexrelease-rollback-003-often.luatex.tlg b/base/testfiles/tlb-latexrelease-rollback-003-often.luatex.tlg
index 91f7a347..8f09d413 100644
--- a/base/testfiles/tlb-latexrelease-rollback-003-often.luatex.tlg
+++ b/base/testfiles/tlb-latexrelease-rollback-003-often.luatex.tlg
@@ -13,6 +13,8 @@ Applying: [....-..-..] Final dot for extension on input line ....
 Skipping: [....-..-..] \MakeRobust  on input line ....
 Skipping: [....-..-..] \MakeRobust  on input line ....
 Applying: [....-..-..] \MakeRobust  on input line ....
+Skipping: [....-..-..] \LetRobustCommand  on input line ....
+Applying: [....-..-..] \LetRobustCommand  on input line ....
 Applying: [....-..-..] Undo robustness on input line ....
 Skipping: [....-..-..] Leave commands undefined in \@ifundefined  on input line ....
 Applying: [....-..-..] Leave commands undefined in \@ifundefined  on input line ....
@@ -322,6 +324,8 @@ Already applied: [....-..-..] Final dot for extension on input line ....
 Applying: [....-..-..] \MakeRobust  on input line ....
 Already applied: [....-..-..] \MakeRobust  on input line ....
 Already applied: [....-..-..] \MakeRobust  on input line ....
+Skipping: [....-..-..] \LetRobustCommand  on input line ....
+Applying: [....-..-..] \LetRobustCommand  on input line ....
 Applying: [....-..-..] Undo robustness on input line ....
 Applying: [....-..-..] Leave commands undefined in \@ifundefined  on input line ....
 Already applied: [....-..-..] Leave commands undefined in \@ifundefined  on input line ....
diff --git a/base/testfiles/tlb-latexrelease-rollback-003-often.tlg b/base/testfiles/tlb-latexrelease-rollback-003-often.tlg
index 4ff8aad5..cf9bedf3 100644
--- a/base/testfiles/tlb-latexrelease-rollback-003-often.tlg
+++ b/base/testfiles/tlb-latexrelease-rollback-003-often.tlg
@@ -11,6 +11,8 @@ Applying: [....-..-..] Final dot for extension on input line ....
 Skipping: [....-..-..] \MakeRobust  on input line ....
 Skipping: [....-..-..] \MakeRobust  on input line ....
 Applying: [....-..-..] \MakeRobust  on input line ....
+Skipping: [....-..-..] \LetRobustCommand  on input line ....
+Applying: [....-..-..] \LetRobustCommand  on input line ....
 Applying: [....-..-..] Undo robustness on input line ....
 Skipping: [....-..-..] Leave commands undefined in \@ifundefined  on input line ....
 Applying: [....-..-..] Leave commands undefined in \@ifundefined  on input line ....
@@ -314,6 +316,8 @@ Already applied: [....-..-..] Final dot for extension on input line ....
 Applying: [....-..-..] \MakeRobust  on input line ....
 Already applied: [....-..-..] \MakeRobust  on input line ....
 Already applied: [....-..-..] \MakeRobust  on input line ....
+Skipping: [....-..-..] \LetRobustCommand  on input line ....
+Applying: [....-..-..] \LetRobustCommand  on input line ....
 Applying: [....-..-..] Undo robustness on input line ....
 Applying: [....-..-..] Leave commands undefined in \@ifundefined  on input line ....
 Already applied: [....-..-..] Leave commands undefined in \@ifundefined  on input line ....
diff --git a/base/testfiles/tlb-latexrelease-rollback-003-often.xetex.tlg b/base/testfiles/tlb-latexrelease-rollback-003-often.xetex.tlg
index daf145e1..b864a35b 100644
--- a/base/testfiles/tlb-latexrelease-rollback-003-often.xetex.tlg
+++ b/base/testfiles/tlb-latexrelease-rollback-003-often.xetex.tlg
@@ -11,6 +11,8 @@ Applying: [....-..-..] Final dot for extension on input line ....
 Skipping: [....-..-..] \MakeRobust  on input line ....
 Skipping: [....-..-..] \MakeRobust  on input line ....
 Applying: [....-..-..] \MakeRobust  on input line ....
+Skipping: [....-..-..] \LetRobustCommand  on input line ....
+Applying: [....-..-..] \LetRobustCommand  on input line ....
 Applying: [....-..-..] Undo robustness on input line ....
 Skipping: [....-..-..] Leave commands undefined in \@ifundefined  on input line ....
 Applying: [....-..-..] Leave commands undefined in \@ifundefined  on input line ....
@@ -323,6 +325,8 @@ Already applied: [....-..-..] Final dot for extension on input line ....
 Applying: [....-..-..] \MakeRobust  on input line ....
 Already applied: [....-..-..] \MakeRobust  on input line ....
 Already applied: [....-..-..] \MakeRobust  on input line ....
+Skipping: [....-..-..] \LetRobustCommand  on input line ....
+Applying: [....-..-..] \LetRobustCommand  on input line ....
 Applying: [....-..-..] Undo robustness on input line ....
 Applying: [....-..-..] Leave commands undefined in \@ifundefined  on input line ....
 Already applied: [....-..-..] Leave commands undefined in \@ifundefined  on input line ....
diff --git a/base/testfiles/tlb-rollback-004-often.luatex.tlg b/base/testfiles/tlb-rollback-004-often.luatex.tlg
index 5fa4be2a..a6b3cafe 100644
--- a/base/testfiles/tlb-rollback-004-often.luatex.tlg
+++ b/base/testfiles/tlb-rollback-004-often.luatex.tlg
@@ -10,6 +10,8 @@ Already applied: [....-..-..] Final dot for extension on input line ....
 Applying: [....-..-..] \MakeRobust  on input line ....
 Already applied: [....-..-..] \MakeRobust  on input line ....
 Already applied: [....-..-..] \MakeRobust  on input line ....
+Skipping: [....-..-..] \LetRobustCommand  on input line ....
+Applying: [....-..-..] \LetRobustCommand  on input line ....
 Applying: [....-..-..] Undo robustness on input line ....
 Applying: [....-..-..] Leave commands undefined in \@ifundefined  on input line ....
 Already applied: [....-..-..] Leave commands undefined in \@ifundefined  on input line ....
diff --git a/base/testfiles/tlb-rollback-004-often.tlg b/base/testfiles/tlb-rollback-004-often.tlg
index 923188b8..586d0c31 100644
--- a/base/testfiles/tlb-rollback-004-often.tlg
+++ b/base/testfiles/tlb-rollback-004-often.tlg
@@ -8,6 +8,8 @@ Already applied: [....-..-..] Final dot for extension on input line ....
 Applying: [....-..-..] \MakeRobust  on input line ....
 Already applied: [....-..-..] \MakeRobust  on input line ....
 Already applied: [....-..-..] \MakeRobust  on input line ....
+Skipping: [....-..-..] \LetRobustCommand  on input line ....
+Applying: [....-..-..] \LetRobustCommand  on input line ....
 Applying: [....-..-..] Undo robustness on input line ....
 Applying: [....-..-..] Leave commands undefined in \@ifundefined  on input line ....
 Already applied: [....-..-..] Leave commands undefined in \@ifundefined  on input line ....
diff --git a/base/testfiles/tlb-rollback-004-often.xetex.tlg b/base/testfiles/tlb-rollback-004-often.xetex.tlg
index 52063867..f37c5333 100644
--- a/base/testfiles/tlb-rollback-004-often.xetex.tlg
+++ b/base/testfiles/tlb-rollback-004-often.xetex.tlg
@@ -8,6 +8,8 @@ Already applied: [....-..-..] Final dot for extension on input line ....
 Applying: [....-..-..] \MakeRobust  on input line ....
 Already applied: [....-..-..] \MakeRobust  on input line ....
 Already applied: [....-..-..] \MakeRobust  on input line ....
+Skipping: [....-..-..] \LetRobustCommand  on input line ....
+Applying: [....-..-..] \LetRobustCommand  on input line ....
 Applying: [....-..-..] Undo robustness on input line ....
 Applying: [....-..-..] Leave commands undefined in \@ifundefined  on input line ....
 Already applied: [....-..-..] Leave commands undefined in \@ifundefined  on input line ....





More information about the latex3-commits mailing list.