[latex3-commits] [git/LaTeX3-latex3-latex3] debug: Fixed debug patching (#599) (2ae9ce990)

Joseph Wright joseph.wright at morningstar2.co.uk
Tue Jul 2 21:44:57 CEST 2019


Repository : https://github.com/latex3/latex3
On branch  : debug
Link       : https://github.com/latex3/latex3/commit/2ae9ce99022eee0d84699ad736171a91ecd57010

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

commit 2ae9ce99022eee0d84699ad736171a91ecd57010
Author: Phelype Oleinik <phe.h.o1 at gmail.com>
Date:   Tue Jul 2 16:44:57 2019 -0300

    Fixed debug patching (#599)
    
    * Fixed debug patching
    
    Changed the patching scheme to create a wrapper around the function instead of patching its code directly, so functions without arguments can be patched as well. 2 test files changed as well: m3int001 (all four versions) because TeX reports the error in the inner \__debug_int_set:Nn function and m3flag001 because the error message changed to expandable.
    
    * Update m3int001.luatex.tlg
    
    * Update m3int001.tlg
    
    * Update m3int001.uptex.tlg
    
    * Update m3int001.xetex.tlg
    
    * Update m3flag001.tlg


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

2ae9ce99022eee0d84699ad736171a91ecd57010
 l3kernel/l3debug.dtx                   | 274 +++++++++++++++++++++++++++++++--
 l3kernel/testfiles/m3flag001.tlg       |  17 +-
 l3kernel/testfiles/m3int001.luatex.tlg |   6 +-
 l3kernel/testfiles/m3int001.tlg        |   6 +-
 l3kernel/testfiles/m3int001.uptex.tlg  |   6 +-
 l3kernel/testfiles/m3int001.xetex.tlg  |   6 +-
 6 files changed, 277 insertions(+), 38 deletions(-)

diff --git a/l3kernel/l3debug.dtx b/l3kernel/l3debug.dtx
index aca660bc0..03af26948 100644
--- a/l3kernel/l3debug.dtx
+++ b/l3kernel/l3debug.dtx
@@ -428,19 +428,179 @@
 %    \end{macrocode}
 % \end{macro}
 %
-% \begin{variable}{\l_@@_internal_tl}
+% \begin{variable}{
+%     \l_@@_internal_tl,
+%     \l_@@_tmpa_tl,
+%     \l_@@_tmpb_tl,
+%   }
 %   For patching.
 %    \begin{macrocode}
 \tl_new:N \l_@@_internal_tl
+\tl_new:N \l_@@_tmpa_tl
+\tl_new:N \l_@@_tmpb_tl
+%    \end{macrocode}
+% \end{variable}
+%
+% \begin{macro}{
+%     \@@_generate_parameter_list:NNN,
+%     \@@_build_parm_text:n,
+%     \@@_build_arg_list:n,
+%     \@@_arg_list_from_signature:nNN,
+%     \@@_arg_check_invalid:N,
+%     \@@_parm_terminate:w,
+%     \@@_arg_if_braced:n,
+%     \@@_get_base_form:N,
+%     \@@_arg_return:N,
+%   }
+% \begin{macro}[TF]{\@@_arg_if_braced:N}
+%   Some functions don't take the arguments their signature indicates.
+%   For instance, \cs{clist_concat:NNN} doesn't take (directly) any
+%   argument, so patching it with something that uses |#1|, |#2|, or
+%   |#3| results in ``Illegal parameter number in definition of
+%   \cs{clist_concat:NNN}''.
+%
+%   Instead of changing \emph{the} definition of the macros, we'll
+%   create a copy of such macros, say, |__debug_clist_concat:NNN| which
+%   will be defined as
+%   |<debug code with #1, #2 and #3>\clist_concat:NNN#1#2#3|. For that
+%   we need to identify the signature of every function and build the
+%   appropriate parameter list.
+%
+%   \cs{@@_generate_parameter_list:NNN} takes a function in |#1| and
+%   returns teo parameter lists: |#2| contains the simple |#1#2#3| as
+%   would be used in the \meta{parameter~text} of the definition and
+%   |#3| contains the same parameters but with braces where necessary.
+%
+%   With the current implementation the resulting |#3| is, for example
+%   for |\some_function:NnNn|, |#1{#2}#3{#4}|. While this is correct,
+%   it might be unnecessary. Bracing everything will usually have the
+%   same outcome (unless the function was misused in the first place).
+%   What should be done?
+%    \begin{macrocode}
+\cs_new_protected:Npn \@@_generate_parameter_list:NNN #1#2#3
+  {
+    \tl_set:Nx \l_@@_internal_tl
+      { \exp_last_unbraced:Nf \use_ii:nnn \cs_split_function:N #1 }
+    \tl_set:Nx #2
+      { \exp_args:NV \@@_build_parm_text:n \l_@@_internal_tl }
+    \tl_set:Nx #3
+      { \exp_args:NV \@@_build_arg_list:n \l_@@_internal_tl }
+  }
+\cs_new:Npn \@@_build_parm_text:n #1
+  {
+    \@@_arg_list_from_signature:nNN { 1 } \c_false_bool #1
+    \q_recursion_tail \q_recursion_stop
+  }
+\cs_new:Npn \@@_build_arg_list:n #1
+  {
+    \@@_arg_list_from_signature:nNN { 1 } \c_true_bool #1
+    \q_recursion_tail \q_recursion_stop
+  }
+\cs_new:Npn \@@_arg_list_from_signature:nNN #1 #2 #3
+  {
+    \quark_if_recursion_tail_stop:N #3
+    \@@_arg_check_invalid:N #3
+    \bool_if:NT #2 { \@@_arg_if_braced:NT #3 { \use_none:n } }
+    \use:n { \c_hash_str \int_eval:n {#1} }
+    \exp_args:Nf \@@_arg_list_from_signature:nNN
+      { \int_eval:n {#1+1} } #2
+  }
+%    \end{macrocode}
+%   Argument types |w|, |p|, |T|, and |F| shouldn't be included in the
+%   parameter lists, so we abort the loop if either is found.
+%    \begin{macrocode}
+\cs_new:Npn \@@_arg_check_invalid:N #1
+  {
+    \if:w w #1 \@@_parm_terminate:w \else:
+      \if:w p #1 \@@_parm_terminate:w \else:
+        \if:w T #1 \@@_parm_terminate:w \else:
+          \if:w F #1 \@@_parm_terminate:w \else:
+            \exp:w
+          \fi:
+        \fi:
+      \fi:
+    \fi:
+    \exp_end:
+  }
+\cs_new:Npn \@@_parm_terminate:w
+  { \exp_after:wN \use_none_delimit_by_q_recursion_stop:w \exp:w }
+\prg_new_conditional:Npnn \@@_arg_if_braced:N #1 { T }
+  { \exp_args:Nf \@@_arg_if_braced:n { \@@_get_base_form:N #1 } }
+\cs_new:Npn \@@_arg_if_braced:n #1
+  {
+    \if:w n #1 \prg_return_true: \else:
+      \if:w N #1 \prg_return_false: \else:
+        \__kernel_msg_expandable_error:nnn
+          { kernel } { bad-arg-type } {#1}
+      \fi:
+    \fi:
+  }
+\__kernel_msg_new:nnn { kernel } { bad-arg-type }
+  { Wrong~argument~type~#1. }
+%    \end{macrocode}
+%   The macro below is a modifiec copy of
+%   |\__cs_generate_variant_loop_base:N| to get the base form of an
+%   argument type given a variant. It serves only to differentiate
+%   arguments which should be braced from ones which shouldn't. If all
+%   were to be braced this would be unnecessary. I moved the |n| and |N|
+%   variants to the beginning of the test as the are much more common
+%   here.
+%    \begin{macrocode}
+\cs_new:Npn \@@_get_base_form:N #1
+  {
+    \if:w n #1 \@@_arg_return:N n \else:
+      \if:w N #1 \@@_arg_return:N N \else:
+        \if:w c #1 \@@_arg_return:N N \else:
+          \if:w o #1 \@@_arg_return:N n \else:
+            \if:w V #1 \@@_arg_return:N n \else:
+              \if:w v #1 \@@_arg_return:N n \else:
+                \if:w f #1 \@@_arg_return:N n \else:
+                  \if:w e #1 \@@_arg_return:N n \else:
+                    \if:w x #1 \@@_arg_return:N n \else:
+                      \@@_arg_return:N \scan_stop:
+                    \fi:
+                  \fi:
+                \fi:
+              \fi:
+            \fi:
+          \fi:
+        \fi:
+      \fi:
+    \fi:
+    \exp_stop_f:
+  }
+\cs_new:Npn \@@_arg_return:N #1
+  { \exp_after:wN #1 \exp:w \exp_end_continue_f:w }
 %    \end{macrocode}
 % \end{variable}
 %
-% \begin{macro}{\__kernel_patch:nnn}
+% \begin{macro}{
+%     \__kernel_patch:nnn,
+%     \__kernel_patch_aux:nnn,
+%     \@@_setup_debug_code:Nnn,
+%     \@@_add_to_debug_code:Nnn,
+%     \@@_insert_debug_code:Nnn,
+%     \__kernel_patch_weird:nnn,
+%     \__kernel_patch_weird_aux:nnn,
+%     \@@_patch_weird:Nnn,
+%   }
 %   Simple patching by adding material at the start and end of (a
 %   collection of) functions is straight-forward as we know the catcode
 %   set up. The approach is essentially that in \pkg{etoolbox}. Notice
 %   the need to worry about spaces: those are otherwise lost as normally
 %   in \pkg{expl3} code they would be~|~|.
+%
+%   As discussed above, some functions don't take arguments, so we can't
+%   patch something that uses an argument in them. For these functions
+%   \cs{__kernel_patch:nnn} is used. It starts by creating a copy of the
+%   function (say, \cs{clist_concat:NNN}) with a |__debug_| prefix in
+%   the name. This copy won't be changed. The code redefines the
+%   original function to take the exact same arguments as advertised in
+%   its signature (see \cs{@@_generate_parameter_list:NNN} above).
+%   The redefined function also contains the debug code in the proper
+%   position. If a function with the same name and the |__debug_| prefix
+%   was already defined, then the macro patches that definition by
+%   adding more debug code to it.
 %    \begin{macrocode}
 \group_begin:
   \cs_set_protected:Npn \__kernel_patch:nnn
@@ -451,24 +611,101 @@
     }
   \cs_set_protected:Npn \__kernel_patch_aux:nnn #1#2#3
     {
-      \char_set_catcode_parameter:N \#
-      \char_set_catcode_space:N \ %
-      \tex_endlinechar:D -1 \scan_stop:
-      \tl_map_inline:nn {#3}
+        \char_set_catcode_parameter:N \#
+        \char_set_catcode_space:N \ %
+        \tex_endlinechar:D -1 \scan_stop:
+        \tl_map_inline:nn {#3}
+          {
+            \cs_if_exist:cTF { __debug_ \cs_to_str:N ##1 }
+              { \@@_add_to_debug_code:Nnn }
+              { \@@_setup_debug_code:Nnn }
+                ##1 {#1} {#2}
+          }
+      \group_end:
+    }
+  \cs_set_protected:Npn \@@_setup_debug_code:Nnn #1#2#3
+    {
+      \cs_gset_eq:cN { __debug_ \cs_to_str:N #1 } #1
+      \@@_generate_parameter_list:NNN #1 \l_@@_tmpa_tl \l_@@_tmpb_tl
+      \exp_args:Nx \tex_scantokens:D
+        {
+          \tex_global:D \cs_prefix_spec:N #1
+          \tex_def:D \exp_not:N #1
+          \tl_use:N \l_@@_tmpa_tl
+            {
+              \tl_to_str:n {#2}
+              \exp_not:c { __debug_ \cs_to_str:N #1 }
+              \tl_use:N \l_@@_tmpb_tl
+              \tl_to_str:n {#3}
+            }
+        }
+    }
+  \cs_set_protected:Npn \@@_add_to_debug_code:Nnn #1#2#3
+    {
+      \use:x
         {
-          \exp_args:Nx \tex_scantokens:D
+          \cs_set:Npn \exp_not:N \@@_tmp:w
+            ####1 \tl_to_str:n { macro: }
+            ####2 \tl_to_str:n { -> }
+            ####3 \c_backslash_str \tl_to_str:n { __debug_ }
+                    \cs_to_str:N #1
+            ####4 \exp_not:N \q_mark
             {
-              \tex_global:D \cs_prefix_spec:N ##1 \tex_def:D \exp_not:N ##1
-              \cs_argument_spec:N ##1
+              \exp_not:N \exp_args:Nx \exp_not:N \tex_scantokens:D
                 {
-                  \tl_to_str:n {#1}
-                  \cs_replacement_spec:N ##1
-                  \tl_to_str:n {#2}
+                  \tex_global:D ####1
+                  \tex_def:D \exp_not:N #1 ####2
+                    {
+                      ####3 \tl_to_str:n {#2}
+                      \c_backslash_str __debug_ \cs_to_str:N #1
+                      ####4 \tl_to_str:n {#3}
+                    }
                 }
             }
         }
+      \exp_after:wN \@@_tmp:w \cs_meaning:N #1 \q_mark
+    }
+%    \end{macrocode}
+%   Some functions, however, won't work with the signature reading setup
+%   above because their signature contains |w|eird arguments. These
+%   functions need to be patched using \cs{__kernel_patch_weird:nnn},
+%   which won't make a copy of the function, rather it will patch the
+%   debug code directly into it. This means that whatever argument the
+%   debug code uses must be actually used by the patched function.
+%    \begin{macrocode}
+  \cs_set_protected:Npn \__kernel_patch_weird:nnn
+    {
+      \group_begin:
+        \char_set_catcode_other:N \#
+        \__kernel_patch_weird_aux:nnn
+    }
+  \cs_set_protected:Npn \__kernel_patch_weird_aux:nnn #1#2#3
+    {
+        \char_set_catcode_parameter:N \#
+        \char_set_catcode_space:N \ %
+        \tex_endlinechar:D -1 \scan_stop:
+        \tl_map_inline:nn {#3}
+          { \@@_patch_weird:Nnn ##1 {#1} {#2} }
       \group_end:
     }
+  \cs_set_protected:Npn \@@_patch_weird:Nnn #1#2#3
+    {
+      \use:x
+        {
+          \tex_endlinechar:D -1 \scan_stop:
+          \exp_not:N \tex_scantokens:D
+            {
+              \tex_global:D \cs_prefix_spec:N #1
+              \tex_def:D \exp_not:N #1
+              \cs_argument_spec:N #1
+                {
+                  \tl_to_str:n {#2}
+                  \cs_replacement_spec:N #1
+                  \tl_to_str:n {#3}
+                }
+            }
+        }
+    }
 %    \end{macrocode}
 % \end{macro}
 %
@@ -500,6 +737,7 @@
 %
 % Patching both second and third arguments.
 %    \begin{macrocode}
+% \tracingall
   \__kernel_patch:nnn
     {
       \__kernel_chk_var_exist:N #2
@@ -516,6 +754,7 @@
       \tl_concat:NNN
       \tl_gconcat:NNN
     }
+% \tracingnone
 %    \end{macrocode}
 %
 % Patching where the first argument to a function needs scope-checking:
@@ -714,7 +953,7 @@
     }
     { \__kernel_chk_if_free_cs:N }
 %<@@=cs>
-  \__kernel_patch:nnn
+  \__kernel_patch_weird:nnn
     {
       \cs_if_free:NF #4
         {
@@ -750,19 +989,19 @@
 %    \end{macrocode}
 % Internal functions from \pkg{prg} module.
 %    \begin{macrocode}
-  \__kernel_patch:nnn
+  \__kernel_patch_weird:nnn
     { \__kernel_chk_cs_exist:c { #5 _p : #6 } }
     { }
     { \@@_set_eq_conditional_p_form:wNnnnn }
-  \__kernel_patch:nnn
+  \__kernel_patch_weird:nnn
     { \__kernel_chk_cs_exist:c { #5    : #6 TF } }
     { }
     { \@@_set_eq_conditional_TF_form:wNnnnn }
-  \__kernel_patch:nnn
+  \__kernel_patch_weird:nnn
     { \__kernel_chk_cs_exist:c { #5    : #6 T } }
     { }
     { \@@_set_eq_conditional_T_form:wNnnnn }
-  \__kernel_patch:nnn
+  \__kernel_patch_weird:nnn
     { \__kernel_chk_cs_exist:c { #5    : #6 F } }
     { }
     { \@@_set_eq_conditional_F_form:wNnnnn }
@@ -869,6 +1108,7 @@
     }
   \cs_set_protected:Npn \__kernel_patch_aux:Nn #1#2
     {
+        \char_set_catcode_parameter:N \#
         \tex_endlinechar:D -1 \scan_stop:
         \exp_args:Nx \tex_scantokens:D
           {
diff --git a/l3kernel/testfiles/m3flag001.tlg b/l3kernel/testfiles/m3flag001.tlg
index 34ee5fd05..b7dff512f 100644
--- a/l3kernel/testfiles/m3flag001.tlg
+++ b/l3kernel/testfiles/m3flag001.tlg
@@ -54,16 +54,15 @@ defined yet.
 ============================================================
 TEST 5: undefined
 ============================================================
-! LaTeX3 Error: The variable \flag other has not been declared on line ....
-For immediate help type H <return>.
- ...                                              
+! Undefined control sequence.
+<argument> \LaTeX3 error: 
+                           Erroneous variable flag other used!
 l. ...  }
-This is a coding error.
-Checking is active, and you have tried do so something like:
-  \tl_set:Nn \flag other { ... }
-without first having:
-  \tl_new:N \flag other
-LaTeX will create the variable and continue.
+The control sequence at the end of the top line
+of your error message was never \def'ed. If you have
+misspelled it (e.g., `\hobx'), type `I' and the correct
+spelling (e.g., `I\hbox'). Otherwise just continue,
+and I'll forget about whatever was undefined.
 ! Undefined control sequence.
 <argument> \LaTeX3 error: 
                            Erroneous variable flag other used!
diff --git a/l3kernel/testfiles/m3int001.luatex.tlg b/l3kernel/testfiles/m3int001.luatex.tlg
index 62e9431c8..f4d0f2fc7 100644
--- a/l3kernel/testfiles/m3int001.luatex.tlg
+++ b/l3kernel/testfiles/m3int001.luatex.tlg
@@ -73,8 +73,8 @@ TEST 6: incrementing and decrementing: expect -2
 TEST 7: trying invalid variables: expect errors
 ============================================================
 ! You can't use `the character -' after \advance.
-\int_decr:N ...hk_var_local:N #1\tex_advance:D #1-
-                                                  \c_one_int 
+\__debug_int_decr:N #1->\tex_advance:D #1-
+                                          \c_one_int 
 l. ...  }
 I'm forgetting what you said and not changing anything.
 ============================================================
@@ -86,7 +86,7 @@ TEST 8: using num expr
 24
 -30
 ! Arithmetic overflow.
-\int_set:Nn ...l:w {}\int_set:Nn \__int_eval_end: 
+\__debug_int_set:Nn ..._eval:w #2\__int_eval_end: 
 l. ...  }
 I can't evaluate this expression,
 since the result is out of range.
diff --git a/l3kernel/testfiles/m3int001.tlg b/l3kernel/testfiles/m3int001.tlg
index 6cc4d02e7..10abd368a 100644
--- a/l3kernel/testfiles/m3int001.tlg
+++ b/l3kernel/testfiles/m3int001.tlg
@@ -73,8 +73,8 @@ TEST 6: incrementing and decrementing: expect -2
 TEST 7: trying invalid variables: expect errors
 ============================================================
 ! You can't use `the character -' after \advance.
-\int_decr:N ...hk_var_local:N #1\tex_advance:D #1-
-                                                  \c_one_int 
+\__debug_int_decr:N #1->\tex_advance:D #1-
+                                          \c_one_int 
 l. ...  }
 I'm forgetting what you said and not changing anything.
 ! Missing $ inserted.
@@ -105,7 +105,7 @@ TEST 8: using num expr
 24
 -30
 ! Arithmetic overflow.
-\int_set:Nn ...l:w {}\int_set:Nn \__int_eval_end: 
+\__debug_int_set:Nn ..._eval:w #2\__int_eval_end: 
 l. ...  }
 I can't evaluate this expression,
 since the result is out of range.
diff --git a/l3kernel/testfiles/m3int001.uptex.tlg b/l3kernel/testfiles/m3int001.uptex.tlg
index 62e9431c8..f4d0f2fc7 100644
--- a/l3kernel/testfiles/m3int001.uptex.tlg
+++ b/l3kernel/testfiles/m3int001.uptex.tlg
@@ -73,8 +73,8 @@ TEST 6: incrementing and decrementing: expect -2
 TEST 7: trying invalid variables: expect errors
 ============================================================
 ! You can't use `the character -' after \advance.
-\int_decr:N ...hk_var_local:N #1\tex_advance:D #1-
-                                                  \c_one_int 
+\__debug_int_decr:N #1->\tex_advance:D #1-
+                                          \c_one_int 
 l. ...  }
 I'm forgetting what you said and not changing anything.
 ============================================================
@@ -86,7 +86,7 @@ TEST 8: using num expr
 24
 -30
 ! Arithmetic overflow.
-\int_set:Nn ...l:w {}\int_set:Nn \__int_eval_end: 
+\__debug_int_set:Nn ..._eval:w #2\__int_eval_end: 
 l. ...  }
 I can't evaluate this expression,
 since the result is out of range.
diff --git a/l3kernel/testfiles/m3int001.xetex.tlg b/l3kernel/testfiles/m3int001.xetex.tlg
index 62e9431c8..f4d0f2fc7 100644
--- a/l3kernel/testfiles/m3int001.xetex.tlg
+++ b/l3kernel/testfiles/m3int001.xetex.tlg
@@ -73,8 +73,8 @@ TEST 6: incrementing and decrementing: expect -2
 TEST 7: trying invalid variables: expect errors
 ============================================================
 ! You can't use `the character -' after \advance.
-\int_decr:N ...hk_var_local:N #1\tex_advance:D #1-
-                                                  \c_one_int 
+\__debug_int_decr:N #1->\tex_advance:D #1-
+                                          \c_one_int 
 l. ...  }
 I'm forgetting what you said and not changing anything.
 ============================================================
@@ -86,7 +86,7 @@ TEST 8: using num expr
 24
 -30
 ! Arithmetic overflow.
-\int_set:Nn ...l:w {}\int_set:Nn \__int_eval_end: 
+\__debug_int_set:Nn ..._eval:w #2\__int_eval_end: 
 l. ...  }
 I can't evaluate this expression,
 since the result is out of range.





More information about the latex3-commits mailing list