From cde95caf86c78ec9b7641198abfd0a7768f5100e Mon Sep 17 00:00:00 2001
From: Karl Berry <karl@freefriends.org>
Date: Sun, 29 Sep 2019 21:16:44 +0000
Subject: l3 (29sep19)

git-svn-id: svn://tug.org/texlive/trunk@52214 c570f23f-e606-0410-a88d-b1316a301751
---
 .../texmf-dist/source/latex/l3kernel/l3debug.dtx   | 1447 ++++++++++++++++++++
 1 file changed, 1447 insertions(+)
 create mode 100644 Master/texmf-dist/source/latex/l3kernel/l3debug.dtx

(limited to 'Master/texmf-dist/source/latex/l3kernel/l3debug.dtx')

diff --git a/Master/texmf-dist/source/latex/l3kernel/l3debug.dtx b/Master/texmf-dist/source/latex/l3kernel/l3debug.dtx
new file mode 100644
index 00000000000..55b16ec0e21
--- /dev/null
+++ b/Master/texmf-dist/source/latex/l3kernel/l3debug.dtx
@@ -0,0 +1,1447 @@
+% \iffalse meta-comment
+%
+%% File: l3debug.dtx
+%
+% Copyright (C) 2019 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
+%
+%    https://www.latex-project.org/lppl.txt
+%
+% This file is part of the "l3kernel 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>
+\documentclass[full,kernel]{l3doc}
+\begin{document}
+  \DocInput{\jobname.dtx}
+\end{document}
+%</driver>
+% \fi
+%
+% \title{^^A
+%   The \textsf{l3debug} package\\ Debugging support^^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 2019-09-28}
+%
+% \maketitle
+%
+% \begin{documentation}
+%
+% \begin{function}{\__kernel_chk_var_local:N, \__kernel_chk_var_global:N}
+%   \begin{syntax}
+%     \cs{__kernel_chk_var_local:N} \meta{var}
+%     \cs{__kernel_chk_var_global:N} \meta{var}
+%   \end{syntax}
+%   Applies \cs{__kernel_chk_var_exist:N} \meta{var} as well as
+%   \cs{__kernel_chk_var_scope:NN} \meta{scope} \meta{var}, where
+%   \meta{scope} is |l| or~|g|.
+% \end{function}
+%
+% \begin{function}{\__kernel_chk_var_scope:NN}
+%   \begin{syntax}
+%     \cs{__kernel_chk_var_scope:NN} \meta{scope} \meta{var}
+%   \end{syntax}
+%   Checks the \meta{var} has the correct \meta{scope}, and if not
+%   raises a kernel-level error.  This function is only created if
+%   debugging is enabled.  The \meta{scope} is a single letter |l|, |g|,
+%   |c| denoting local variables, global variables, or constants.  More
+%   precisely, if the variable name starts with a letter and an
+%   underscore (normal \pkg{expl3} convention) the function checks that
+%   this single letter matches the \meta{scope}.  Otherwise the function
+%   cannot know the scope \meta{var} the first time: instead, it defines
+%   |\__debug_chk_/|\meta{var name} to store that information for the
+%   next call.  Thus, if a given \meta{var} is subject to assignments of
+%   different scopes a kernel error will result.
+% \end{function}
+%
+% \begin{function}
+%   {
+%     \__kernel_chk_cs_exist:N,
+%     \__kernel_chk_cs_exist:c,
+%     \__kernel_chk_var_exist:N
+%   }
+%   \begin{syntax}
+%     \cs{__kernel_chk_cs_exist:N} \meta{cs}
+%     \cs{__kernel_chk_var_exist:N} \meta{var}
+%   \end{syntax}
+%   These functions are only created if debugging is enabled.  They
+%   check that their argument is defined according to the criteria for
+%   \cs{cs_if_exist_p:N},
+%   and if not raises a kernel-level error.  Error messages are
+%   different.
+% \end{function}
+%
+% \begin{function}[EXP]{\__kernel_chk_flag_exist:n}
+%   \begin{syntax}
+%     \cs{__kernel_chk_flag_exist:n} \Arg{flag}
+%   \end{syntax}
+%   This function is only created if debugging is enabled.  It checks
+%   that the \meta{flag} is defined according to the criterion for
+%   \cs{flag_if_exist_p:n}, and if not raises a kernel-level error.
+% \end{function}
+%
+% \begin{function}{\__kernel_debug_log:x}
+%   \begin{syntax}
+%     \cs{__kernel_debug_log:x} \Arg{message text}
+%   \end{syntax}
+%   If the \texttt{log-functions} option is active, this function writes
+%   the \meta{message text} to the log file using \cs{iow_log:x}.
+%   Otherwise, the \meta{message text} is ignored using \cs{use_none:n}.
+%   This function is only created if debugging is enabled.
+% \end{function}
+%
+% \end{documentation}
+%
+% \begin{implementation}
+%
+% \section{\pkg{l3debug} Implementation}
+%
+%    \begin{macrocode}
+%<*initex|package>
+%    \end{macrocode}
+%
+%    \begin{macrocode}
+%<@@=debug>
+%    \end{macrocode}
+%
+% Standard file identification.
+%    \begin{macrocode}
+\ProvidesExplFile{l3debug.def}{2019-04-06}{}{L3 Debugging support}
+%    \end{macrocode}
+%
+% \begin{macro}{\debug_on:n, \debug_off:n, \@@_all_on:, \@@_all_off:}
+%    \begin{macrocode}
+\cs_set_protected:Npn \debug_on:n #1
+   {
+    \exp_args:No \clist_map_inline:nn { \tl_to_str:n {#1} }
+       {
+        \cs_if_exist_use:cF { @@_ ##1 _on: }
+          { \__kernel_msg_error:nnn { kernel } { debug } {##1} }
+       }
+  }
+\cs_set_protected:Npn \debug_off:n #1
+  {
+    \exp_args:No \clist_map_inline:nn { \tl_to_str:n {#1} }
+      {
+        \cs_if_exist_use:cF { @@_ ##1 _off: }
+          { \__kernel_msg_error:nnn { kernel } { debug } {##1} }
+      }
+  }
+\cs_new_protected:Npn \@@_all_on:
+  {
+    \debug_on:n
+      {
+        check-declarations ,
+        check-expressions ,
+        deprecation ,
+        log-functions ,
+      }
+  }
+\cs_new_protected:Npn \@@_all_off:
+  {
+    \debug_off:n
+      {
+        check-declarations ,
+        check-expressions ,
+        deprecation ,
+        log-functions ,
+      }
+  }
+%    \end{macrocode}
+% \end{macro}
+%
+% \begin{macro}{\debug_suspend:, \debug_resume:}
+% \begin{macro}{\@@_suspended:T}
+% \begin{macro}{\l_@@_suspended_tl}
+%   Suspend and resume locally all debug-related errors and logging
+%   except deprecation errors.  The \cs{debug_suspend:} and \cs{debug_resume:}
+%   pairs can be nested.  We keep track of nesting in a token list
+%   containing a number of periods.  At first begin with the
+%   \enquote{non-suspended} version of \cs{@@_suspended:T}.
+%    \begin{macrocode}
+\tl_new:N \l_@@_suspended_tl { }
+\cs_set_protected:Npn \debug_suspend:
+  {
+    \tl_put_right:Nn \l_@@_suspended_tl { . }
+    \cs_set_eq:NN \@@_suspended:T \use:n
+  }
+\cs_set_protected:Npn \debug_resume:
+  {
+    \tl_set:Nx \l_@@_suspended_tl
+      { \tl_tail:N \l_@@_suspended_tl }
+    \tl_if_empty:NT \l_@@_suspended_tl
+      {
+        \cs_set_eq:NN \@@_suspended:T \use_none:n
+      }
+  }
+\cs_new_eq:NN \@@_suspended:T \use_none:n
+%    \end{macrocode}
+% \end{macro}
+% \end{macro}
+% \end{macro}
+%
+% \begin{macro}
+%   {\@@_check-declarations_on:, \@@_check-declarations_off:}
+% \begin{macro}
+%   {
+%     \__kernel_chk_var_exist:N,
+%     \__kernel_chk_cs_exist:N,
+%     \__kernel_chk_cs_exist:c
+%   }
+% \begin{macro}[EXP]{\__kernel_chk_flag_exist:n}
+% \begin{macro}{\__kernel_chk_var_local:N, \__kernel_chk_var_global:N}
+% \begin{macro}{\__kernel_chk_var_scope:NN}
+%   When debugging is enabled these two functions set up functions that
+%   test their argument (when \texttt{check-declarations} is active)
+%   \begin{itemize}
+%     \item \cs{__kernel_chk_var_exist:N} and \cs{__kernel_chk_cs_exist:N}, two
+%       functions that test that their argument is defined;
+%     \item \cs{__kernel_chk_var_scope:NN} that checks that its argument |#2|
+%       has scope |#1|.
+%     \item \cs{__kernel_chk_var_local:N} and \cs{__kernel_chk_var_global:N} that
+%       perform both checks.
+%   \end{itemize}
+%    \begin{macrocode}
+\cs_new_protected:Npn \__kernel_chk_var_exist:N #1 { }
+\cs_new_protected:Npn \__kernel_chk_cs_exist:N #1 { }
+\cs_generate_variant:Nn \__kernel_chk_cs_exist:N { c }
+\cs_new:Npn \__kernel_chk_flag_exist:n #1 { }
+\cs_new_protected:Npn \__kernel_chk_var_local:N #1 { }
+\cs_new_protected:Npn \__kernel_chk_var_global:N #1 { }
+\cs_new_protected:Npn \__kernel_chk_var_scope:NN #1#2 { }
+\cs_new_protected:cpn { @@_check-declarations_on: }
+  {
+    \cs_set_protected:Npn \__kernel_chk_var_exist:N ##1
+      {
+        \@@_suspended:T \use_none:nnn
+        \cs_if_exist:NF ##1
+          {
+            \__kernel_msg_error:nnx { kernel } { non-declared-variable }
+              { \token_to_str:N ##1 }
+          }
+      }
+    \cs_set_protected:Npn \__kernel_chk_cs_exist:N ##1
+      {
+        \@@_suspended:T \use_none:nnn
+        \cs_if_exist:NF ##1
+          {
+            \__kernel_msg_error:nnx { kernel } { command-not-defined }
+              { \token_to_str:N ##1 }
+          }
+      }
+    \cs_set:Npn \__kernel_chk_flag_exist:n ##1
+      {
+        \@@_suspended:T \use_none:nnn
+        \flag_if_exist:nF {##1}
+          {
+            \__kernel_msg_expandable_error:nnn
+              { kernel } { bad-variable } { flag~##1~ }
+          }
+      }
+    \cs_set_protected:Npn \__kernel_chk_var_scope:NN
+      {
+        \@@_suspended:T \use_none:nnn
+        \@@_chk_var_scope_aux:NN
+      }
+    \cs_set_protected:Npn \__kernel_chk_var_local:N ##1
+      {
+        \@@_suspended:T \use_none:nnnnn
+        \__kernel_chk_var_exist:N ##1
+        \@@_chk_var_scope_aux:NN l ##1
+      }
+    \cs_set_protected:Npn \__kernel_chk_var_global:N ##1
+      {
+        \@@_suspended:T \use_none:nnnnn
+        \__kernel_chk_var_exist:N ##1
+        \@@_chk_var_scope_aux:NN g ##1
+      }
+  }
+\cs_new_protected:cpn { @@_check-declarations_off: }
+  {
+    \cs_set_protected:Npn \__kernel_chk_var_exist:N ##1 { }
+    \cs_set_protected:Npn \__kernel_chk_cs_exist:N ##1 { }
+    \cs_set:Npn \__kernel_chk_flag_exist:N ##1 { }
+    \cs_set_protected:Npn \__kernel_chk_var_local:N ##1 { }
+    \cs_set_protected:Npn \__kernel_chk_var_global:N ##1 { }
+    \cs_set_protected:Npn \__kernel_chk_var_scope:NN ##1##2 { }
+  }
+%    \end{macrocode}
+% \end{macro}
+% \end{macro}
+% \end{macro}
+% \end{macro}
+% \end{macro}
+%
+% \begin{macro}{\@@_chk_var_scope_aux:NN}
+% \begin{macro}{\@@_chk_var_scope_aux:Nn}
+% \begin{macro}{\@@_chk_var_scope_aux:NNn}
+%   First check whether the name of the variable |#2| starts with
+%   \meta{letter}|_|.  If it does then pass that letter, the
+%   \meta{scope}, and the variable name to
+%   \cs{@@_chk_var_scope_aux:NNn}.  That function compares the two
+%   letters and triggers an error if they differ (the \cs{scan_stop:}
+%   case is not reachable here).  If the second character was not |_|
+%   then pass the same data to the same auxiliary, except for its first
+%   argument which is now a control sequence.  That control sequence is
+%   actually a token list (but to avoid triggering the checking code we
+%   manipulate it using \cs{cs_set_nopar:Npn}) containing a single
+%   letter \meta{scope} according to what the first assignment to the
+%   given variable was.
+%    \begin{macrocode}
+\cs_new_protected:Npn \@@_chk_var_scope_aux:NN #1#2
+  { \exp_args:NNf \@@_chk_var_scope_aux:Nn #1 { \cs_to_str:N #2 } }
+\cs_new_protected:Npn \@@_chk_var_scope_aux:Nn #1#2
+  {
+    \if:w _ \use_i:nn \use_i_delimit_by_q_stop:nw #2 ? ? \q_stop
+      \exp_after:wN \@@_chk_var_scope_aux:NNn
+        \use_i_delimit_by_q_stop:nw #2 ? \q_stop
+        #1 {#2}
+    \else:
+      \exp_args:Nc \@@_chk_var_scope_aux:NNn
+        { @@_chk_/ #2 }
+        #1 {#2}
+    \fi:
+  }
+\cs_new_protected:Npn \@@_chk_var_scope_aux:NNn #1#2#3
+  {
+    \if:w #1 #2
+    \else:
+      \if:w #1 \scan_stop:
+        \cs_gset_nopar:Npn #1 {#2}
+      \else:
+        \__kernel_msg_error:nnxxx { kernel } { local-global }
+          {#1} {#2} { \iow_char:N \\ #3 }
+      \fi:
+    \fi:
+  }
+\use:c { @@_check-declarations_off: }
+%    \end{macrocode}
+% \end{macro}
+% \end{macro}
+% \end{macro}
+%
+% \begin{macro}{\@@_log-functions_on:, \@@_log-functions_off:}
+% \begin{macro}{\__kernel_debug_log:x}
+%   These two functions (corresponding to the \pkg{expl3} option
+%   \texttt{log-functions}) control whether \cs{__kernel_debug_log:x}
+%   writes to the log file or not.  By default, logging is off.
+%    \begin{macrocode}
+\cs_new_protected:cpn { @@_log-functions_on: }
+  {
+    \cs_set_protected:Npn \__kernel_debug_log:x
+      { \@@_suspended:T \use_none:nn \iow_log:x }
+  }
+\cs_new_protected:cpn { @@_log-functions_off: }
+  { \cs_set_protected:Npn \__kernel_debug_log:x { \use_none:n } }
+\cs_new_protected:Npn \__kernel_debug_log:x { \use_none:n }
+%    \end{macrocode}
+% \end{macro}
+% \end{macro}
+%
+% \begin{macro}
+%   {\@@_check-expressions_on:, \@@_check-expressions_off:}
+% \begin{macro}{\__kernel_chk_expr:nNnN}
+% \begin{macro}{\@@_chk_expr_aux:nNnN}
+%   When debugging is enabled these two functions set
+%   \cs{__kernel_chk_expr:nNnN} to test or not whether the given
+%   expression is valid.  The idea is to evaluate the expression within
+%   a brace group (to catch trailing \cs{use_none:nn} or similar), then
+%   test that the result is what we expect.  This is done by turning it
+%   to an integer and hitting that with \cs{tex_romannumeral:D} after
+%   replacing the first character by |-0|.  If all goes well, that
+%   primitive finds a non-positive integer and gives an empty output.
+%   If the original expression evaluation stopped early it leaves a
+%   trailing \cs{tex_relax:D}, which stops the second evaluation (used
+%   to convert to integer) before it encounters the final
+%   \cs{tex_relax:D}.  Since \cs{tex_romannumeral:D} does not absorb
+%   \cs{tex_relax:D} the output will be nonempty.  Note that |#3| is
+%   empty except for mu expressions for which it is \cs{tex_mutoglue:D}
+%   to avoid an \enquote{incompatible glue units} error.  Note also that
+%   if we had omitted the first \cs{tex_relax:D} then for instance
+%   |1+2\relax+3| would incorrectly be accepted as a valid integer
+%   expression.
+%    \begin{macrocode}
+\cs_new_protected:cpn { @@_check-expressions_on: }
+  {
+    \cs_set:Npn \__kernel_chk_expr:nNnN ##1##2
+      {
+        \@@_suspended:T { ##1 \use_none:nnnnnnn }
+        \exp_after:wN \@@_chk_expr_aux:nNnN
+        \exp_after:wN { \tex_the:D ##2 ##1 \scan_stop: }
+        ##2
+      }
+  }
+\cs_new_protected:cpn { @@_check-expressions_off: }
+  { \cs_set:Npn \__kernel_chk_expr:nNnN ##1##2##3##4 {##1} }
+\cs_new:Npn \__kernel_chk_expr:nNnN #1#2#3#4 {#1}
+\cs_new:Npn \@@_chk_expr_aux:nNnN #1#2#3#4
+  {
+    \tl_if_empty:oF
+      {
+        \tex_romannumeral:D - 0
+        \exp_after:wN \use_none:n
+        \int_value:w #3 #2 #1 \scan_stop:
+      }
+      {
+        \__kernel_msg_expandable_error:nnnn
+          { kernel } { expr } {#4} {#1}
+      }
+    #1
+  }
+%    \end{macrocode}
+% \end{macro}
+% \end{macro}
+% \end{macro}
+%
+% \begin{macro}{\@@_deprecation_on:, \@@_deprecation_off:}
+%   Some commands were more recently deprecated and not yet removed;
+%   only make these into errors if the user requests it.  This relies on
+%   two token lists, filled up in \pkg{l3deprecation} by calls to
+%   \cs{__kernel_deprecation_code:nn}.
+%    \begin{macrocode}
+\cs_new_protected:Npn \@@_deprecation_on:
+  { \g_@@_deprecation_on_tl }
+\cs_new_protected:Npn \@@_deprecation_off:
+  { \g_@@_deprecation_off_tl }
+%    \end{macrocode}
+% \end{macro}
+%
+% \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,
+%     \__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
+    {
+      \group_begin:
+        \char_set_catcode_other:N \#
+        \__kernel_patch_aux:nnn
+    }
+  \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}
+          {
+            \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
+        {
+          \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
+            {
+              \exp_not:N \exp_args:Nx \exp_not:N \tex_scantokens:D
+                {
+                  \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}
+%
+% Patching the second argument to ensure it exists. This happens before
+% we alter |#1| so the ordering is correct.  For many variable types
+% such as \texttt{int} a low-level error occurs when |#2| is unknown, so
+% adding a check is not needed.
+%    \begin{macrocode}
+  \__kernel_patch:nnn
+    { \__kernel_chk_var_exist:N #2 }
+    { }
+    {
+      \bool_set_eq:NN
+      \bool_gset_eq:NN
+      \clist_set_eq:NN
+      \clist_gset_eq:NN
+      \fp_set_eq:NN
+      \fp_gset_eq:NN
+      \prop_set_eq:NN
+      \prop_gset_eq:NN
+      \seq_set_eq:NN
+      \seq_gset_eq:NN
+      \str_set_eq:NN
+      \str_gset_eq:NN
+      \tl_set_eq:NN
+      \tl_gset_eq:NN
+    }
+%    \end{macrocode}
+%
+% Patching both second and third arguments.
+%    \begin{macrocode}
+% \tracingall
+  \__kernel_patch:nnn
+    {
+      \__kernel_chk_var_exist:N #2
+      \__kernel_chk_var_exist:N #3
+    }
+    { }
+    {
+      \clist_concat:NNN
+      \clist_gconcat:NNN
+      \seq_concat:NNN
+      \seq_gconcat:NNN
+      \str_concat:NNN
+      \str_gconcat:NNN
+      \tl_concat:NNN
+      \tl_gconcat:NNN
+    }
+% \tracingnone
+%    \end{macrocode}
+%
+% Patching where the first argument to a function needs scope-checking:
+% either local or global (so two lists).
+%    \begin{macrocode}
+  \__kernel_patch:nnn
+    { \__kernel_chk_var_local:N #1 }
+    { }
+    {
+      \bool_set:Nn
+      \bool_set_eq:NN
+      \bool_set_true:N
+      \bool_set_false:N
+      \box_set_eq:NN
+      \box_set_eq_drop:NN
+      \box_set_to_last:N
+      \clist_set_eq:NN
+      \dim_zero:N
+      \dim_set:Nn
+      \dim_set_eq:NN
+      \dim_add:Nn
+      \dim_sub:Nn
+      \fp_set_eq:NN
+      \int_zero:N
+      \int_set_eq:NN
+      \int_add:Nn
+      \int_sub:Nn
+      \int_incr:N
+      \int_decr:N
+      \int_set:Nn
+      \hbox_set:Nn
+      \hbox_set_to_wd:Nnn
+      \hbox_set:Nw
+      \hbox_set_to_wd:Nnw
+      \muskip_zero:N
+      \muskip_set:Nn
+      \muskip_add:Nn
+      \muskip_sub:Nn
+      \muskip_set_eq:NN
+      \seq_set_eq:NN
+      \skip_zero:N
+      \skip_set:Nn
+      \skip_set_eq:NN
+      \skip_add:Nn
+      \skip_sub:Nn
+      \tl_set:Nn
+      \tl_set:No
+      \tl_set:Nx
+      \tl_set_eq:NN
+      \tl_put_left:Nn
+      \tl_put_left:NV
+      \tl_put_left:No
+      \tl_put_left:Nx
+      \tl_put_right:Nn
+      \tl_put_right:NV
+      \tl_put_right:No
+      \tl_put_right:Nx
+      \tl_build_begin:N
+      \tl_build_put_right:Nn
+      \tl_build_put_right:Nx
+      \tl_build_put_left:Nn
+      \vbox_set:Nn
+      \vbox_set_top:Nn
+      \vbox_set_to_ht:Nnn
+      \vbox_set:Nw
+      \vbox_set_to_ht:Nnw
+      \vbox_set_split_to_ht:NNn
+    }
+  \__kernel_patch:nnn
+    { \__kernel_chk_var_global:N #1 }
+    { }
+    {
+      \bool_gset:Nn
+      \bool_gset_eq:NN
+      \bool_gset_true:N
+      \bool_gset_false:N
+      \box_gset_eq:NN
+      \box_gset_eq_drop:NN
+      \box_gset_to_last:N
+      \clist_gset_eq:NN
+      \dim_gset_eq:NN
+      \dim_gzero:N
+      \dim_gset:Nn
+      \dim_gadd:Nn
+      \dim_gsub:Nn
+      \fp_gset_eq:NN
+      \int_gzero:N
+      \int_gset_eq:NN
+      \int_gadd:Nn
+      \int_gsub:Nn
+      \int_gincr:N
+      \int_gdecr:N
+      \int_gset:Nn
+      \hbox_gset:Nn
+      \hbox_gset_to_wd:Nnn
+      \hbox_gset:Nw
+      \hbox_gset_to_wd:Nnw
+      \muskip_gzero:N
+      \muskip_gset:Nn
+      \muskip_gadd:Nn
+      \muskip_gsub:Nn
+      \muskip_gset_eq:NN
+      \seq_gset_eq:NN
+      \skip_gzero:N
+      \skip_gset:Nn
+      \skip_gset_eq:NN
+      \skip_gadd:Nn
+      \skip_gsub:Nn
+      \tl_gset:Nn
+      \tl_gset:No
+      \tl_gset:Nx
+      \tl_gset_eq:NN
+      \tl_gput_left:Nn
+      \tl_gput_left:NV
+      \tl_gput_left:No
+      \tl_gput_left:Nx
+      \tl_gput_right:Nn
+      \tl_gput_right:NV
+      \tl_gput_right:No
+      \tl_gput_right:Nx
+      \tl_build_gbegin:N
+      \tl_build_gput_right:Nn
+      \tl_build_gput_right:Nx
+      \tl_build_gput_left:Nn
+      \vbox_gset:Nn
+      \vbox_gset_top:Nn
+      \vbox_gset_to_ht:Nnn
+      \vbox_gset:Nw
+      \vbox_gset_to_ht:Nnw
+      \vbox_gset_split_to_ht:NNn
+    }
+%    \end{macrocode}
+%
+% Scoping for constants.
+%    \begin{macrocode}
+  \__kernel_patch:nnn
+    { \__kernel_chk_var_scope:NN c #1 }
+    { }
+    {
+      \bool_const:Nn
+      \dim_const:Nn
+      \int_const:Nn
+      \intarray_const_from_clist:Nn
+      \muskip_const:Nn
+      \skip_const:Nn
+      \tl_const:Nn
+      \tl_const:Nx
+    }
+%    \end{macrocode}
+%
+% Flag functions.
+%    \begin{macrocode}
+  \__kernel_patch:nnn
+    { \__kernel_chk_flag_exist:n {#1} }
+    { }
+    {
+      \flag_if_raised:nT
+      \flag_if_raised:nF
+      \flag_if_raised:nTF
+      \flag_if_raised_p:n
+      \flag_height:n
+      \flag_raise_if_clear:n
+      \flag_clear:n
+    }
+%    \end{macrocode}
+%
+% Various one-offs.
+%    \begin{macrocode}
+  \__kernel_patch:nnn
+    { \__kernel_chk_cs_exist:N #1 }
+    { }
+    { \cs_generate_variant:Nn }
+  \__kernel_patch:nnn
+    { \__kernel_chk_var_scope:NN g #1 }
+    { }
+    { \intarray_new:Nn }
+  \__kernel_patch:nnn
+    { \__kernel_chk_var_scope:NN q #1 }
+    { }
+    { \quark_new:N }
+  \__kernel_patch:nnn
+    { \__kernel_chk_var_scope:NN s #1 }
+    { }
+    { \scan_new:N }
+%    \end{macrocode}
+%
+% Patch various internal commands to log definitions of functions.
+% First, a kernel internal.  Then internals from the \pkg{cs},
+% \pkg{keys} and \pkg{msg} modules.
+%    \begin{macrocode}
+  \__kernel_patch:nnn
+    { }
+    {
+      \__kernel_debug_log:x
+        { Defining~\token_to_str:N #1~ \msg_line_context: }
+    }
+    { \__kernel_chk_if_free_cs:N }
+%<@@=cs>
+  \__kernel_patch_weird:nnn
+    {
+      \cs_if_free:NF #4
+        {
+          \__kernel_debug_log:x
+            {
+              Variant~\token_to_str:N #4~%
+              already~defined;~ not~ changing~ it~ \msg_line_context:
+            }
+        }
+    }
+    { }
+    { \@@_generate_variant:wwNN  }
+%<@@=keys>
+  \__kernel_patch:nnn
+    {
+      \cs_if_exist:cF { \c_@@_code_root_tl #1 }
+        { \__kernel_debug_log:x { Defining~key~#1~\msg_line_context: } }
+    }
+    { }
+    { \@@_cmd_set:nn }
+%<@@=msg>
+  \__kernel_patch:nnn
+    { }
+    {
+      \__kernel_debug_log:x
+        { Defining~message~ #1 / #2 ~\msg_line_context: }
+    }
+    { \@@_chk_free:nn }
+%    \end{macrocode}
+%
+%    \begin{macrocode}
+%<@@=prg>
+%    \end{macrocode}
+% Internal functions from \pkg{prg} module.
+%    \begin{macrocode}
+  \__kernel_patch_weird:nnn
+    { \__kernel_chk_cs_exist:c { #5 _p : #6 } }
+    { }
+    { \@@_set_eq_conditional_p_form:wNnnnn }
+  \__kernel_patch_weird:nnn
+    { \__kernel_chk_cs_exist:c { #5    : #6 TF } }
+    { }
+    { \@@_set_eq_conditional_TF_form:wNnnnn }
+  \__kernel_patch_weird:nnn
+    { \__kernel_chk_cs_exist:c { #5    : #6 T } }
+    { }
+    { \@@_set_eq_conditional_T_form:wNnnnn }
+  \__kernel_patch_weird:nnn
+    { \__kernel_chk_cs_exist:c { #5    : #6 F } }
+    { }
+    { \@@_set_eq_conditional_F_form:wNnnnn }
+%    \end{macrocode}
+%
+%    \begin{macrocode}
+%<@@=regex>
+%    \end{macrocode}
+% Internal functions from \pkg{regex} module.
+%    \begin{macrocode}
+  \__kernel_patch:nnn
+    {
+      \@@_trace_push:nnN { regex } { 1 } \@@_escape_use:nnnn
+      \group_begin:
+        \tl_set:Nx \l_@@_internal_a_tl
+          { \@@_trace_pop:nnN { regex } { 1 } \@@_escape_use:nnnn }
+        \use_none:nnn
+    }
+    { }
+    { \@@_escape_use:nnn }
+  \__kernel_patch:nnn
+    { \@@_trace_push:nnN { regex } { 1 } \@@_build:N }
+    {
+      \@@_trace_states:n { 2 }
+      \@@_trace_pop:nnN { regex } { 1 } \@@_build:N
+    }
+    { \@@_build:N }
+  \__kernel_patch:nnn
+    { \@@_trace_push:nnN { regex } { 1 } \@@_build_for_cs:n }
+    {
+      \@@_trace_states:n { 2 }
+      \@@_trace_pop:nnN { regex } { 1 } \@@_build_for_cs:n
+    }
+    { \@@_build_for_cs:n }
+  \__kernel_patch:nnn
+    {
+      \@@_trace:nnx { regex } { 2 }
+        {
+          regex~new~state~
+          L=\int_use:N \l_@@_left_state_int ~ -> ~
+          R=\int_use:N \l_@@_right_state_int ~ -> ~
+          M=\int_use:N \l_@@_max_state_int ~ -> ~
+          \int_eval:n { \l_@@_max_state_int + 1 }
+        }
+    }
+    { }
+    { \@@_build_new_state: }
+  \__kernel_patch:nnn
+    { \@@_trace_push:nnN { regex } { 1 } \@@_group_aux:nnnnN }
+    { \@@_trace_pop:nnN { regex } { 1 } \@@_group_aux:nnnnN }
+    { \@@_group_aux:nnnnN }
+  \__kernel_patch:nnn
+    { \@@_trace_push:nnN { regex } { 1 } \@@_branch:n }
+    { \@@_trace_pop:nnN { regex } { 1 } \@@_branch:n }
+    { \@@_branch:n }
+  \__kernel_patch:nnn
+    {
+      \@@_trace_push:nnN { regex } { 1 } \@@_match:n
+      \@@_trace:nnx { regex } { 1 } { analyzing~query~token~list }
+    }
+    { \@@_trace_pop:nnN { regex } { 1 } \@@_match:n }
+    { \@@_match:n }
+  \__kernel_patch:nnn
+    {
+      \@@_trace_push:nnN { regex } { 1 } \@@_match_cs:n
+      \@@_trace:nnx { regex } { 1 } { analyzing~query~token~list }
+    }
+    { \@@_trace_pop:nnN { regex } { 1 } \@@_match_cs:n }
+    { \@@_match_cs:n }
+  \__kernel_patch:nnn
+    { \@@_trace:nnx { regex } { 1 } { initializing } }
+    { }
+    { \@@_match_init: }
+  \__kernel_patch:nnn
+    {
+      \@@_trace:nnx { regex } { 2 }
+        { state~\int_use:N \l_@@_curr_state_int }
+    }
+    { }
+    { \@@_use_state: }
+  \__kernel_patch:nnn
+    { \@@_trace_push:nnN { regex } { 1 } \@@_replacement:n }
+    { \@@_trace_pop:nnN { regex } { 1 } \@@_replacement:n }
+    { \@@_replacement:n }
+%    \end{macrocode}
+%
+%    \begin{macrocode}
+\group_end:
+%    \end{macrocode}
+%
+%    \begin{macrocode}
+%<@@=debug>
+%    \end{macrocode}
+%
+% Patching arguments is a bit more involved: we do these one at a time.
+% The basic idea is the same, using a |#| token that is a string.
+%    \begin{macrocode}
+\group_begin:
+  \cs_set_protected:Npn \__kernel_patch:Nn #1
+    {
+      \group_begin:
+        \char_set_catcode_other:N \#
+        \__kernel_patch_aux:Nn #1
+    }
+  \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
+          {
+            \tex_global:D \cs_prefix_spec:N #1 \tex_def:D \exp_not:N #1
+              \cs_argument_spec:N #1
+              { \exp_args:No \tl_to_str:n { #1 #2 } }
+          }
+      \group_end:
+    }
+%    \end{macrocode}
+%
+% The functions here can get a bit repetitive, so we define a helper
+% which can re-use the same patch code repeatedly. The main part of the
+% patch is the same, so we just have to deal with the part which varies
+% depending on the type of expression.
+%    \begin{macrocode}
+  \cs_set_protected:Npn \__kernel_patch_eval:nn #1#2
+    {
+      \tl_map_inline:nn {#1}
+        {
+          \exp_args:NNx \__kernel_patch:Nn ##1
+            {
+              { \c_hash_str 1 }
+              {
+                \exp_not:N \__kernel_chk_expr:nNnN { \c_hash_str 2 }
+                \exp_not:n {#2}
+                \exp_not:N ##1
+              }
+            }
+        }
+    }
+%<@@=dim>
+  \__kernel_patch_eval:nn
+    {
+      \dim_set:Nn
+      \dim_gset:Nn
+      \dim_add:Nn
+      \dim_gadd:Nn
+      \dim_sub:Nn
+      \dim_gsub:Nn
+      \dim_const:Nn
+    }
+    { \@@_eval:w { } }
+%<@@=int>
+  \__kernel_patch_eval:nn
+    {
+      \int_set:Nn
+      \int_gset:Nn
+      \int_add:Nn
+      \int_gadd:Nn
+      \int_sub:Nn
+      \int_gsub:Nn
+      \int_const:Nn
+    }
+    { \@@_eval:w { } }
+  \__kernel_patch_eval:nn
+    {
+      \muskip_set:Nn
+      \muskip_gset:Nn
+      \muskip_add:Nn
+      \muskip_gadd:Nn
+      \muskip_sub:Nn
+      \muskip_gsub:Nn
+      \muskip_const:Nn
+    }
+    { \tex_muexpr:D { \tex_mutoglue:D } }
+  \__kernel_patch_eval:nn
+    {
+      \skip_set:Nn
+      \skip_gset:Nn
+      \skip_add:Nn
+      \skip_gadd:Nn
+      \skip_sub:Nn
+      \skip_gsub:Nn
+      \skip_const:Nn
+    }
+    { \tex_glueexpr:D { } }
+%    \end{macrocode}
+%
+% Patching expandable expressions, first the one-argument versions,
+% then the two-argument ones.
+%    \begin{macrocode}
+  \cs_set_protected:Npn \__kernel_patch_eval:nn #1#2
+    {
+      \tl_map_inline:nn {#1}
+        {
+          \exp_args:NNx \__kernel_patch:Nn ##1
+            {
+              {
+                \exp_not:N \__kernel_chk_expr:nNnN { \c_hash_str 1 }
+                \exp_not:n {#2}
+                \exp_not:N ##1
+              }
+            }
+        }
+    }
+%<@@=box>
+  \__kernel_patch_eval:nn
+    { \@@_dim_eval:n }
+    { \@@_eval:w { } }
+%<@@=dim>
+  \__kernel_patch_eval:nn
+    {
+      \dim_eval:n
+      \dim_to_decimal:n
+      \dim_to_decimal_in_sp:n
+      \dim_abs:n
+      \dim_sign:n
+    }
+    { \@@_eval:w { } }
+%<@@=int>
+  \__kernel_patch_eval:nn
+    {
+      \int_eval:n
+      \int_abs:n
+      \int_sign:n
+    }
+    { \@@_eval:w { } }
+  \__kernel_patch_eval:nn
+    {
+      \skip_eval:n
+      \skip_horizontal:n
+      \skip_vertical:n
+    }
+    { \tex_glueexpr:D { } }
+  \__kernel_patch_eval:nn
+    {
+      \muskip_eval:n
+    }
+    { \tex_muexpr:D { \tex_mutoglue:D } }
+  \cs_set_protected:Npn \__kernel_patch_eval:nn #1#2
+    {
+      \tl_map_inline:nn {#1}
+        {
+          \exp_args:NNx \__kernel_patch:Nn ##1
+            {
+              {
+                \exp_not:N \__kernel_chk_expr:nNnN { \c_hash_str 1 }
+                \exp_not:n {#2}
+                \exp_not:N ##1
+              }
+              {
+                \exp_not:N \__kernel_chk_expr:nNnN { \c_hash_str 2 }
+                \exp_not:n {#2}
+                \exp_not:N ##1
+              }
+            }
+        }
+    }
+%<@@=dim>
+  \__kernel_patch_eval:nn
+    {
+      \dim_max:nn
+      \dim_min:nn
+    }
+    { \@@_eval:w { } }
+%<@@=int>
+  \__kernel_patch_eval:nn
+    {
+      \int_max:nn
+      \int_min:nn
+      \int_div_truncate:nn
+      \int_mod:nn
+    }
+    { \@@_eval:w { } }
+%    \end{macrocode}
+%
+%  Conditionals: three argument ones then one argument ones
+%    \begin{macrocode}
+  \cs_set_protected:Npn \__kernel_patch_cond:nn #1#2
+    {
+      \clist_map_inline:nn { :nNnT , :nNnF , :nNnTF , _p:nNn }
+        {
+          \exp_args:Ncx \__kernel_patch:Nn { #1 ##1 }
+            {
+              {
+                \exp_not:N \__kernel_chk_expr:nNnN { \c_hash_str 1 }
+                \exp_not:n {#2}
+                \exp_not:c { #1 ##1 }
+              }
+              { \c_hash_str 2 }
+              {
+                \exp_not:N \__kernel_chk_expr:nNnN { \c_hash_str 3 }
+                \exp_not:n {#2}
+                \exp_not:c { #1 ##1 }
+              }
+            }
+        }
+    }
+%<@@=dim>
+  \__kernel_patch_cond:nn { dim_compare } { \@@_eval:w { } }
+%<@@=int>
+  \__kernel_patch_cond:nn { int_compare } { \@@_eval:w { } }
+  \cs_set_protected:Npn \__kernel_patch_cond:nn #1#2
+    {
+      \clist_map_inline:nn { :nT , :nF , :nTF , _p:n }
+        {
+          \exp_args:Ncx \__kernel_patch:Nn { #1 ##1 }
+            {
+              {
+                \exp_not:N \__kernel_chk_expr:nNnN { \c_hash_str 1 }
+                \exp_not:n {#2}
+                \exp_not:c { #1 ##1 }
+              }
+            }
+        }
+    }
+%<@@=int>
+  \__kernel_patch_cond:nn { int_if_even } { \@@_eval:w { } }
+  \__kernel_patch_cond:nn { int_if_odd } { \@@_eval:w { } }
+%    \end{macrocode}
+%
+% Step functions.
+%    \begin{macrocode}
+%<@@=dim>
+  \__kernel_patch:Nn \dim_step_function:nnnN
+    {
+      {
+        \__kernel_chk_expr:nNnN {#1} \@@_eval:w { }
+          \dim_step_function:nnnN
+      }
+      {
+        \__kernel_chk_expr:nNnN {#2} \@@_eval:w { }
+          \dim_step_function:nnnN
+      }
+      {
+        \__kernel_chk_expr:nNnN {#3} \@@_eval:w { }
+          \dim_step_function:nnnN
+      }
+    }
+%<@@=int>
+  \__kernel_patch:Nn \int_step_function:nnnN
+    {
+      {
+        \__kernel_chk_expr:nNnN {#1} \@@_eval:w { }
+          \int_step_function:nnnN
+      }
+      {
+        \__kernel_chk_expr:nNnN {#2} \@@_eval:w { }
+          \int_step_function:nnnN
+      }
+      {
+        \__kernel_chk_expr:nNnN {#3} \@@_eval:w { }
+          \int_step_function:nnnN
+      }
+    }
+%    \end{macrocode}
+%
+%  Odds and ends
+%    \begin{macrocode}
+  \__kernel_patch:Nn \dim_to_fp:n { { (#1) } }
+%    \end{macrocode}
+%
+%    \begin{macrocode}
+\group_end:
+%    \end{macrocode}
+%
+%    \begin{macrocode}
+%<@@=skip>
+%    \end{macrocode}
+% This one has catcode changes so must be done by hand.
+%    \begin{macrocode}
+\cs_set_protected:Npn \@@_tmp:w #1
+  {
+    \prg_set_conditional:Npnn \skip_if_finite:n ##1 { p , T , F , TF }
+      {
+        \exp_after:wN \@@_if_finite:wwNw
+        \skip_use:N \tex_glueexpr:D
+          \__kernel_chk_expr:nNnN
+            {##1} \tex_glueexpr:D { } \skip_if_finite:n
+        ; \prg_return_false:
+        #1 ; \prg_return_true: \q_stop
+      }
+  }
+\exp_args:No \@@_tmp:w { \tl_to_str:n { fil } }
+%    \end{macrocode}
+%
+%    \begin{macrocode}
+%<@@=msg>
+%    \end{macrocode}
+%
+% Messages.
+% \begin{macrocode}
+\__kernel_msg_new:nnnn { kernel } { debug }
+  { The~debugging~option~'#1'~does~not~exist~\msg_line_context:. }
+  {
+    The~functions~'\iow_char:N\\debug_on:n'~and~
+    '\iow_char:N\\debug_off:n'~only~accept~the~arguments~
+    'all',~'check-declarations',~'check-expressions',~
+    'deprecation',~'log-functions',~not~'#1'.
+  }
+\__kernel_msg_new:nnn { kernel } { expr } { '#2'~in~#1 }
+\__kernel_msg_new:nnnn { kernel } { local-global }
+  { Inconsistent~local/global~assignment }
+  {
+    \c_@@_coding_error_text_tl
+    \if:w l #2 Local
+    \else:
+      \if:w g #2 Global \else: Constant \fi:
+    \fi:
+    \ %
+    assignment~to~a~
+    \if:w l #1 local
+    \else:
+      \if:w g #1 global \else: constant \fi:
+    \fi:
+    \ %
+    variable~'#3'.
+  }
+\__kernel_msg_new:nnnn { kernel } { non-declared-variable }
+  { The~variable~#1~has~not~been~declared~\msg_line_context:. }
+  {
+    \c_@@_coding_error_text_tl
+    Checking~is~active,~and~you~have~tried~do~so~something~like: \\
+    \ \ \tl_set:Nn ~ #1 ~ \{ ~ ... ~ \} \\
+    without~first~having: \\
+    \ \ \tl_new:N ~ #1  \\
+    \\
+    LaTeX~will~create~the~variable~and~continue.
+  }
+% \end{macrocode}
+%
+% \begin{macro}{\__kernel_if_debug:TF}
+%   Flip the switch for deprecated code.
+%    \begin{macrocode}
+\cs_set_protected:Npn \__kernel_if_debug:TF #1#2 {#1}
+%    \end{macrocode}
+% \end{macro}
+%
+%    \begin{macrocode}
+%</initex|package>
+%    \end{macrocode}
+%
+% \end{implementation}
+%
+% \PrintIndex
-- 
cgit v1.2.3

