[latex3-commits] [l3svn] 02/02: Re-write of \keyval_parse:NNn

noreply at latex-project.org noreply at latex-project.org
Wed May 25 11:02:50 CEST 2016


This is an automated email from the git hooks/post-receive script.

joseph pushed a commit to branch master
in repository l3svn.

commit 201a7d6e9f64b682da65e9e2099e158520c37359
Author: Joseph Wright <joseph.wright at morningstar2.co.uk>
Date:   Wed May 25 10:02:41 2016 +0100

    Re-write of \keyval_parse:NNn
    
    This is the first phase of dealing with #294. Whilst the bigger issue
    is the higher-level code (which was largely written ad hoc to solve
    the issue rather than to work efficiently), the code at the low level
    has evolved over time without a proper check over.
    
    Here, the idea is to take the basic keyval implementation (which is the
    fastest the job can be done in TeX) and to extend it for our
    requirements. In particular, there is a need to address some brace
    stripping oddities in keyval that can't be altered there but can for
    us. At the same time, our documented space stripping removes all
    spaces not just one at each end, which requires a little more work.
    
    Making the code 'babel safe' costs some time, but hopefully won't
    be necessary at some stage in the future.
    
    Testing with 10k runs of a setting for 4 keys and 2 blank entries,
    and taking keyval as a baseline, the old version is about 6x while
    the new version is about 2.3x. A non-babel safe version gets down to
    about 2x.
---
 l3kernel/l3keys.dtx                     |  302 +++++++++++++++++--------------
 l3kernel/testfiles/m3expl001.luatex.tlg |   48 ++---
 l3kernel/testfiles/m3expl001.ptex.tlg   |   46 +++--
 l3kernel/testfiles/m3expl001.tlg        |   48 ++---
 l3kernel/testfiles/m3expl001.uptex.tlg  |   46 +++--
 l3kernel/testfiles/m3expl001.xetex.tlg  |   46 +++--
 l3kernel/testfiles/m3expl002.luatex.tlg |   23 ++-
 l3kernel/testfiles/m3expl002.ptex.tlg   |   21 +--
 l3kernel/testfiles/m3expl002.tlg        |   23 ++-
 l3kernel/testfiles/m3expl002.uptex.tlg  |   21 +--
 l3kernel/testfiles/m3expl002.xetex.tlg  |   21 +--
 l3kernel/testfiles/m3expl003.luatex.tlg |   48 ++---
 l3kernel/testfiles/m3expl003.ptex.tlg   |   46 +++--
 l3kernel/testfiles/m3expl003.tlg        |   48 ++---
 l3kernel/testfiles/m3expl003.uptex.tlg  |   46 +++--
 l3kernel/testfiles/m3expl003.xetex.tlg  |   46 +++--
 l3kernel/testfiles/m3expl004.luatex.tlg |   23 ++-
 l3kernel/testfiles/m3expl004.ptex.tlg   |   21 +--
 l3kernel/testfiles/m3expl004.tlg        |   23 ++-
 l3kernel/testfiles/m3expl004.uptex.tlg  |   21 +--
 l3kernel/testfiles/m3expl004.xetex.tlg  |   21 +--
 l3kernel/testfiles/m3expl006.luatex.tlg |   23 ++-
 l3kernel/testfiles/m3expl006.ptex.tlg   |   21 +--
 l3kernel/testfiles/m3expl006.tlg        |   23 ++-
 l3kernel/testfiles/m3expl006.uptex.tlg  |   21 +--
 l3kernel/testfiles/m3expl006.xetex.tlg  |   21 +--
 l3kernel/testfiles/m3int001.tlg         |   16 +-
 l3kernel/testfiles/m3int001.xetex.tlg   |   16 +-
 l3kernel/testfiles/m3int002.luatex.tlg  |   40 ++--
 l3kernel/testfiles/m3int002.tlg         |   40 ++--
 l3kernel/testfiles/m3int002.uptex.tlg   |   40 ++--
 l3kernel/testfiles/m3int002.xetex.tlg   |   40 ++--
 l3kernel/testfiles/m3keys001.lvt        |   12 --
 l3kernel/testfiles/m3keys001.tlg        |    7 -
 l3kernel/testfiles/m3keyval001.lvt      |    2 +
 l3kernel/testfiles/m3keyval001.tlg      |   18 +-
 36 files changed, 705 insertions(+), 623 deletions(-)

diff --git a/l3kernel/l3keys.dtx b/l3kernel/l3keys.dtx
index 9c883a0..4e4d05d 100644
--- a/l3kernel/l3keys.dtx
+++ b/l3kernel/l3keys.dtx
@@ -1,6 +1,6 @@
 % \iffalse meta-comment
 %
-%% File: l3keys.dtx Copyright (C) 2006-2015 The LaTeX3 Project
+%% File: l3keys.dtx Copyright (C) 2006-2016 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
@@ -873,19 +873,17 @@
 %
 % \subsection{Low-level interface}
 %
-%    \begin{macrocode}
-%<@@=keyval>
-%    \end{macrocode}
-%
-% For historical reasons this code uses the `keyval' module prefix.
+% The low-level key parser is based heavily on \pkg{keyval}, but with a number
+% of additional \enquote{safety} requirements and with the idea that the
+% parsed list of key--value pairs can be processed in a variety of ways.
+% The net result is that this code needs around twice the amount of time
+% as \pkg{keyval} to parse the same list of keys. To optimise speed as far
+% as reasonably practical, a number of lower-level approaches are taken
+% rather than using the higher-level \pkg{expl3} interfaces.
 %
-% \begin{variable}{\g_@@_level_int}
-%   To allow nesting of \cs{keyval_parse:NNn}, an integer is needed for
-%   the current level.
 %    \begin{macrocode}
-\int_new:N \g_@@_level_int
+%<@@=keyval>
 %    \end{macrocode}
-% \end{variable}
 %
 % \begin{variable}{\l_@@_key_tl, \l_@@_value_tl}
 %   The current key name and value.
@@ -896,166 +894,206 @@
 % \end{variable}
 %
 % \begin{variable}{\l_@@_sanitise_tl}
-% \begin{variable}{\l_@@_parse_tl}
-%   Token list variables for dealing with awkward category codes in the
+%   A token list variable for dealing with awkward category codes in the
 %   input.
 %    \begin{macrocode}
 \tl_new:N \l_@@_sanitise_tl
-\tl_new:N \l_@@_parse_tl
 %    \end{macrocode}
 % \end{variable}
-% \end{variable}
 %
-% \begin{macro}{\@@_parse:n}
-%   The parsing function first deals with the category codes for
-%   |=| and |,|, so that there are no odd events. The input is then
-%   handed off to the element by element system.
+% \begin{macro}{\keyval_parse:NNn}
+%   The main function starts of by normalising category codes in package mode.
+%   That's relatively \enquote{expensive} so is skipped (hopefully) in format
+%   mode. We then hand off to the parser. The use of |\q_mark| here prevents
+%   loss of braces from the key argument. This particular quark is chosen as
+%   it fits in with |\__tl_trim_spaces:nn| and allows a performance enhancement
+%   as the token can be carried through. Notice that by passing the two
+%   processor commands alone the input stack we avoid the need to track these
+%   at all.
 %    \begin{macrocode}
+\cs_new_protected:Npn \keyval_parse:NNn #1#2#3
+  {
+%<*initex>
+    \@@_loop:NNw #1#2 \q_mark #3 , \q at recursion@tail ,
+%</initex>
+%<*package>
+    \tl_set:Nn \l_@@_sanitise_tl {#3}
+    \@@_sanitise_equals:
+    \@@_sanitise_comma:
+    \exp_after:wN \@@_loop:NNw \exp_after:wN #1 \exp_after:wN #2
+      \exp_after:wN \q_mark \l_@@_sanitise_tl , \q_recursion_tail ,
+%</package>
+  }
+%    \end{macrocode}
+% \end{macro}
+%
+% \begin{macro}[aux]{\@@_sanitise_equals:, \@@_sanitise_comma:}
+% \begin{macro}[aux]
+%   {
+%     \@@_sanitise_equals_auxi:w, \@@_sanitise_equals_auxii:w,
+%     \@@_sanitise_comma_auxi:w, \@@_sanitise_comma_auxii:w,
+%     \@@_sanitise_aux:w
+%   }
+%   A reasonably fast search and replace set up specifically for the active
+%   tokens. The nature of the input is known so everything is hard-coded.
+%   With only two tokens to cover, the speed gain from using dedicated
+%   functions is worth it.
+%    \begin{macrocode}
+%<*package>
 \group_begin:
   \char_set_catcode_active:n { `\= }
   \char_set_catcode_active:n { `\, }
-  \cs_new_protected:Npx \@@_parse:n #1
+  \cs_new_protected_nopar:Npn \@@_sanitise_equals:
+    {
+      \exp_after:wN \@@_sanitise_equals_auxi:w \l_@@_sanitise_tl
+        \q_mark = \q_nil =
+      \exp_after:wN \@@_sanitise_aux:w \l_@@_sanitise_tl
+    }
+    \cs_new_protected:Npn \@@_sanitise_equals_auxi:w #1 =
+      {
+        \tl_set:Nn \l_@@_sanitise_tl {#1}
+        \@@_sanitise_equals_auxii:w
+      }
+    \cs_new_protected:Npn \@@_sanitise_equals_auxii:w #1 =
+      {
+        \if_meaning:w \q_nil #1 \scan_stop:
+        \else:
+          \tl_set:Nx \l_@@_sanitise_tl
+            {
+              \exp_not:o \l_@@_sanitise_tl
+              \token_to_str:N =
+              \exp_not:n {#1}
+            }
+          \exp_after:wN \@@_sanitise_equals_auxii:w
+        \fi:
+      }
+  \cs_new_protected_nopar:Npn \@@_sanitise_comma:
     {
-      \group_begin:
-        \tl_set:Nn \exp_not:N \l_@@_sanitise_tl {#1}
-        \tl_replace_all:Nnn \exp_not:N \l_@@_sanitise_tl
-          { \exp_not:N = } { \token_to_str:N = }
-        \tl_replace_all:Nnn \exp_not:N \l_@@_sanitise_tl
-          { \exp_not:N , } { \token_to_str:N , }
-        \tl_clear:N \exp_not:N \l_@@_parse_tl
-        \exp_not:N \exp_after:wN
-          \exp_not:N \@@_parse_elt:w \exp_not:N \exp_after:wN
-          \exp_not:N \q_nil \exp_not:N \l_@@_sanitise_tl
-          \token_to_str:N , \exp_not:N \q_recursion_tail
-            \token_to_str:N , \exp_not:N \q_recursion_stop
-      \exp_not:N \exp_after:wN \group_end:
-      \exp_not:N \l_@@_parse_tl
+      \exp_after:wN \@@_sanitise_comma_auxi:w \l_@@_sanitise_tl
+        \q_mark , \q_nil ,
+      \exp_after:wN \@@_sanitise_aux:w \l_@@_sanitise_tl
     }
+    \cs_new_protected:Npn \@@_sanitise_comma_auxi:w #1 ,
+      {
+        \tl_set:Nn \l_@@_sanitise_tl {#1}
+        \@@_sanitise_comma_auxii:w
+      }
+    \cs_new_protected:Npn \@@_sanitise_comma_auxii:w #1 ,
+      {
+        \if_meaning:w \q_nil #1 \scan_stop:
+        \else:
+          \tl_set:Nx \l_@@_sanitise_tl
+            {
+              \exp_not:o \l_@@_sanitise_tl
+              \token_to_str:N ,
+              \exp_not:n {#1}
+            }
+          \exp_after:wN \@@_sanitise_comma_auxii:w
+        \fi:
+      }
 \group_end:
+\cs_new_protected:Npn \@@_sanitise_aux:w #1 \q_mark
+  { \tl_set:Nn \l_@@_sanitise_tl {#1} }
+%</package>
 %    \end{macrocode}
 % \end{macro}
+% \end{macro}
 %
-% \begin{macro}{\@@_parse_elt:w}
-%   Each item to be parsed will have \cs{q_nil} added to the front.
-%   Hence the blank test here can always be used to find a totally
-%   empty argument. To allow rapid matching for an |=| while not stripping
-%   any braces, another \cs{q_nil} needed before the next phase of the
-%   parser. Finally, loop around for the next item, adding in the
-%   \cs{q_nil}: this happens whatever the nature of the current argument
-%   as the end-of-recursion will clear up in all cases.
+% \begin{macro}[aux]{\@@_loop:NNw}
+%   A fast test for the end of the loop, remembering to remove the leading
+%   quark first. Assuming that is not the case, look for a key and value then
+%   loop around, re-inserting a leading quark in front of the next position.
 %    \begin{macrocode}
-\cs_new_protected:Npn \@@_parse_elt:w #1 ,
+\cs_new_protected:Npn \@@_loop:NNw #1#2#3 ,
   {
-    \tl_if_blank:oF { \use_none:n #1 }
-      {
-        \quark_if_recursion_tail_stop:o { \use_none:n #1 }
-        \@@_split_key_value:w #1 \q_nil = = \q_stop
-      }
-    \@@_parse_elt:w \q_nil
+    \exp_after:wN \if_meaning:w \exp_after:wN \q_recursion_tail
+      \use_none:n #3 \prg_do_nothing:
+    \else:
+      \@@_split:NNw #1#2#3 == \q_stop
+      \exp_after:wN \@@_loop:NNw \exp_after:wN #1 \exp_after:wN #2
+        \exp_after:wN \q_mark
+    \fi:
   }
 %    \end{macrocode}
 % \end{macro}
 %
-% \begin{macro}{\@@_split_key_value:w}
-% \begin{macro}[aux]{\@@_split_key:w}
-%   Split the key and value using a delimited argument. The \cs{q_nil}
-%   values added earlier ensure that no braces will be stripped as part
-%   of this process. A blank test can then be used on |#3|: it is only
-%   empty if there was no |=| in the original input. In that case, strip
-%   a \cs{q_nil} from the end of the key name then hand on to remove other
-%   things and store as \cs{l_@@_key_tl} before adding to the output token
-%   list. In the case where there is an |=|, first tidy up the key, this time
-%   without a trailing \cs{q_nil}, then do a check to ensure that |#3| is
-%   exactly one token (|=|). With that done, the final stage is to hand off
-%   to tidy up the value.
+% \begin{macro}[aux]{\@@_split:NNw, \@@_split_value:NNw}
+% \begin{macro}[aux]{\@@_split_tidy:w}
+% \begin{macro}[aux]{\@@_action:}
+%   The value is picked up separately from the key so there can be another
+%   quark inserted at the front, keeping braces and allowing both parts to
+%   share the same code paths. The key is found first then there's a check
+%   that there is something there: this is biased to the common case of there
+%   actually being a key. For the value, we first need to see if there is
+%   anything to do: if there is, extract it. The appropriate action is then
+%   inserted in front of the key and value. Doing this using an assignment is
+%   marginally faster than an an expansion chain.
 %    \begin{macrocode}
-\cs_new_protected:Npn \@@_split_key_value:w #1 = #2 = #3 \q_stop
+\cs_new_protected:Npn \@@_split:NNw #1#2#3 =
   {
-    \tl_if_blank:nTF {#3}
-      {
-        \@@_split_key:w #1 \q_stop
-        \tl_put_right:Nx \l_@@_parse_tl
+    \@@_def:Nn \l_@@_key_tl {#3}
+    \if_meaning:w \l_@@_key_tl \c_empty_tl
+      \exp_after:wN \@@_split_tidy:w
+    \else:
+      \exp_after:wN \@@_split_value:NNw \exp_after:wN #1 \exp_after:wN #2
+        \exp_after:wN \q_mark
+    \fi:
+  }
+\cs_new_protected:Npn \@@_split_value:NNw #1#2#3 = #4 \q_stop
+  {
+    \if:w \scan_stop: \tl_to_str:n {#4} \scan_stop:
+      \cs_set_nopar:Npx \@@_action:
+        { \exp_not:N #1 { \exp_not:o \l_@@_key_tl } }
+    \else:
+      \if:w \scan_stop: \etex_detokenize:D \exp_after:wN { \use_none:n #4 }
+        \scan_stop:
+        \@@_def:Nn \l_@@_value_tl {#3}
+        \cs_set_nopar:Npx \@@_action:
           {
-            \exp_not:c
-              {
-                @@_key_no_value_elt_
-                \int_use:N \g_@@_level_int
-                :n
-              }
+            \exp_not:N #2
               { \exp_not:o \l_@@_key_tl }
+              { \exp_not:o \l_@@_value_tl }
           }
-      }
-      {
-        \@@_split:Nn \l_@@_key_tl {#1}
-        \tl_if_blank:oTF { \use_none:n #3 }
-          { \@@_split_value:w \q_nil #2 \q_stop }
+      \else:
+        \cs_set_nopar:Npn \@@_action:
           { \__msg_kernel_error:nn { kernel } { misplaced-equals-sign } }
-      }
+      \fi:
+    \fi:
+    \@@_action:
   }
-\cs_new_protected:Npn \@@_split_key:w #1 \q_nil \q_stop
-  { \@@_split:Nn \l_@@_key_tl {#1} }
-%    \end{macrocode}
-% \end{macro}
-% \end{macro}
-%
-% \begin{macro}{\@@_split:Nn}
-% \begin{macro}[aux]{\@@_split:Nw}
-%   There are two possible cases here. The first case is that |#1| is
-%   surrounded by braces, in which case the |\use_none:nnn #1 \q_nil \q_nil|
-%   will yield \cs{q_nil}. There, we can remove the leading \cs{q_nil}, the
-%   braces and any spaces around the outside with \cs{use_ii:nnn}. On the
-%   other hand, if there are no braces then the second branch removes the
-%   leading \cs{q_nil} and any surrounding spaces.
-%    \begin{macrocode}
-\cs_new_protected:Npn \@@_split:Nn #1#2
+\cs_new_protected:Npn \@@_split_tidy:w #1 \q_stop
   {
-    \quark_if_nil:oTF { \use_none:nnn #2 \q_nil \q_nil }
-      { \tl_set:Nx #1 { \exp_not:o { \use_ii:nnn #2 \q_nil } } }
-      { \@@_split:Nw #1 #2 \q_stop }
+    \if:w \scan_stop: \etex_detokenize:D \exp_after:wN { \use_none:n #1 }
+      \scan_stop:
+    \else:
+      \exp_after:wN \@@_empty_key:
+    \fi:
   }
-\cs_new_protected:Npn \@@_split:Nw #1 \q_nil #2 \q_stop
-  { \tl_set:Nx #1 { \tl_trim_spaces:n {#2} } }
+\cs_new_nopar:Npn \@@_action: { }
+\cs_new_protected_nopar:Npn \@@_empty_key:
+  { \__msg_kernel_error:nn { kernel } { misplaced-equals-sign } }
 %    \end{macrocode}
 % \end{macro}
 % \end{macro}
-%
-% \begin{macro}{\@@_split_value:w}
-%   As this stage there is just the value to deal with. The leading and
-%   trailing \cs{q_nil} tokens are removed in two steps before storing the
-%   value with spaces stripped (see \cs{@@_split:Nn}). Doing the storage
-%   of key and value in one shot will put exactly the right number of
-%   brace groups into the output.
-%    \begin{macrocode}
-\cs_new_protected:Npn \@@_split_value:w #1 \q_nil \q_stop
-  {
-    \@@_split:Nn \l_@@_value_tl {#1}
-    \tl_put_right:Nx \l_@@_parse_tl
-      {
-        \exp_not:c
-          { @@_key_value_elt_ \int_use:N \g_@@_level_int :nn }
-          { \exp_not:o \l_@@_key_tl }
-          { \exp_not:o \l_@@_value_tl }
-      }
-  }
-%    \end{macrocode}
 % \end{macro}
 %
-% \begin{macro}{\keyval_parse:NNn}
-%   The outer parsing routine just sets up the processing functions and
-%   hands off.
+% \begin{macro}[aux]{\@@_def:Nn}
+% \begin{macro}[aux, EXP]{\@@_def_aux:n}
+% \begin{macro}[aux, EXP]{\@@_def_aux:w}
+%   First trim spaces off, then potentially remove a set of braces. By using
+%   the internal interface |\__tl_trim_spaces:nn| we can take advantage of the
+%   fact it needs a leading |\q_mark| in this process. The |\exp_after:wN|
+%   removes the quark, the delimited argument deals with any braces.
 %    \begin{macrocode}
-\cs_new_protected:Npn \keyval_parse:NNn #1#2#3
-  {
-    \int_gincr:N \g_@@_level_int
-    \cs_gset_eq:cN
-      { @@_key_no_value_elt_ \int_use:N \g_@@_level_int :n } #1
-    \cs_gset_eq:cN
-      { @@_key_value_elt_ \int_use:N \g_@@_level_int :nn }   #2
-    \@@_parse:n {#3}
-    \int_gdecr:N \g_@@_level_int
-  }
+\cs_new_protected:Npn \@@_def:Nn #1#2
+  { \tl_set:Nx #1 { \__tl_trim_spaces:nn {#2} \@@_def_aux:n } }
+\cs_new:Npn \@@_def_aux:n #1
+  { \exp_after:wN \@@_def_aux:w #1 \q_stop }
+\cs_new:Npn \@@_def_aux:w #1 \q_stop { \exp_not:n {#1} }
 %    \end{macrocode}
 % \end{macro}
+% \end{macro}
+% \end{macro}
 %
 % One message for the low level parsing system.
 %    \begin{macrocode}
diff --git a/l3kernel/testfiles/m3expl001.luatex.tlg b/l3kernel/testfiles/m3expl001.luatex.tlg
index d34c3ba..15a6a42 100644
--- a/l3kernel/testfiles/m3expl001.luatex.tlg
+++ b/l3kernel/testfiles/m3expl001.luatex.tlg
@@ -3104,26 +3104,32 @@ Defining \g_tmpa_muskip on line ...
 \g_tmpa_muskip=\muskip44
 Defining \g_tmpb_muskip on line ...
 \g_tmpb_muskip=\muskip45
-Defining \g__keyval_level_int on line ...
-\g__keyval_level_int=\count123
 Defining \l__keyval_key_tl on line ...
 Defining \l__keyval_value_tl on line ...
 Defining \l__keyval_sanitise_tl on line ...
-Defining \l__keyval_parse_tl on line ...
-Defining \__keyval_parse:n on line ...
-Defining \__keyval_parse_elt:w on line ...
-Defining \__keyval_split_key_value:w on line ...
-Defining \__keyval_split_key:w on line ...
-Defining \__keyval_split:Nn on line ...
-Defining \__keyval_split:Nw on line ...
-Defining \__keyval_split_value:w on line ...
 Defining \keyval_parse:NNn on line ...
+Defining \__keyval_sanitise_equals: on line ...
+Defining \__keyval_sanitise_equals_auxi:w on line ...
+Defining \__keyval_sanitise_equals_auxii:w on line ...
+Defining \__keyval_sanitise_comma: on line ...
+Defining \__keyval_sanitise_comma_auxi:w on line ...
+Defining \__keyval_sanitise_comma_auxii:w on line ...
+Defining \__keyval_sanitise_aux:w on line ...
+Defining \__keyval_loop:NNw on line ...
+Defining \__keyval_split:NNw on line ...
+Defining \__keyval_split_value:NNw on line ...
+Defining \__keyval_split_tidy:w on line ...
+Defining \__keyval_action: on line ...
+Defining \__keyval_empty_key: on line ...
+Defining \__keyval_def:Nn on line ...
+Defining \__keyval_def_aux:n on line ...
+Defining \__keyval_def_aux:w on line ...
 Defining message LaTeX/kernel/misplaced-equals-sign on line ...
 Defining \c__keys_code_root_tl on line ...
 Defining \c__keys_info_root_tl on line ...
 Defining \c__keys_props_root_tl on line ...
 Defining \l_keys_choice_int on line ...
-\l_keys_choice_int=\count124
+\l_keys_choice_int=\count123
 Defining \l_keys_choice_tl on line ...
 Defining \l__keys_groups_clist on line ...
 Defining \l_keys_key_tl on line ...
@@ -3357,25 +3363,25 @@ Defining \__fp_exp_after_normal:Nwwwww on line ...
 Defining \__fp_exp_after_array_f:w on line ...
 Defining \__fp_exp_after_stop_f:nw on line ...
 Defining \c__fp_leading_shift_int on line ...
-\c__fp_leading_shift_int=\count125
+\c__fp_leading_shift_int=\count124
 Defining \c__fp_middle_shift_int on line ...
-\c__fp_middle_shift_int=\count126
+\c__fp_middle_shift_int=\count125
 Defining \c__fp_trailing_shift_int on line ...
-\c__fp_trailing_shift_int=\count127
+\c__fp_trailing_shift_int=\count126
 Defining \__fp_pack:NNNNNw on line ...
 Defining \c__fp_big_leading_shift_int on line ...
-\c__fp_big_leading_shift_int=\count128
+\c__fp_big_leading_shift_int=\count127
 Defining \c__fp_big_middle_shift_int on line ...
-\c__fp_big_middle_shift_int=\count129
+\c__fp_big_middle_shift_int=\count128
 Defining \c__fp_big_trailing_shift_int on line ...
-\c__fp_big_trailing_shift_int=\count130
+\c__fp_big_trailing_shift_int=\count129
 Defining \__fp_pack_big:NNNNNNw on line ...
 Defining \c__fp_Bigg_leading_shift_int on line ...
-\c__fp_Bigg_leading_shift_int=\count131
+\c__fp_Bigg_leading_shift_int=\count130
 Defining \c__fp_Bigg_middle_shift_int on line ...
-\c__fp_Bigg_middle_shift_int=\count132
+\c__fp_Bigg_middle_shift_int=\count131
 Defining \c__fp_Bigg_trailing_shift_int on line ...
-\c__fp_Bigg_trailing_shift_int=\count133
+\c__fp_Bigg_trailing_shift_int=\count132
 Defining \__fp_pack_Bigg:NNNNNNw on line ...
 Defining \__fp_pack_twice_four:wNNNNNNNN on line ...
 Defining \__fp_pack_eight:wNNNNNNNN on line ...
@@ -4782,7 +4788,7 @@ Defining \__driver_scope_end: on line ...
 Defining \__driver_matrix:n on line ...
 Defining \l__driver_current_color_tl on line ...
 Defining \l__driver_color_stack_int on line ...
-\l__driver_color_stack_int=\count134
+\l__driver_color_stack_int=\count133
 Defining \__driver_color_ensure_current: on line ...
 Defining \__driver_color_reset: on line ...
 Defining \__driver_box_use_clip:N on line ...
diff --git a/l3kernel/testfiles/m3expl001.ptex.tlg b/l3kernel/testfiles/m3expl001.ptex.tlg
index 4e9cb00..6b23366 100644
--- a/l3kernel/testfiles/m3expl001.ptex.tlg
+++ b/l3kernel/testfiles/m3expl001.ptex.tlg
@@ -3095,26 +3095,32 @@ Defining \g_tmpa_muskip on line ...
 \g_tmpa_muskip=\muskip44
 Defining \g_tmpb_muskip on line ...
 \g_tmpb_muskip=\muskip45
-Defining \g__keyval_level_int on line ...
-\g__keyval_level_int=\count124
 Defining \l__keyval_key_tl on line ...
 Defining \l__keyval_value_tl on line ...
 Defining \l__keyval_sanitise_tl on line ...
-Defining \l__keyval_parse_tl on line ...
-Defining \__keyval_parse:n on line ...
-Defining \__keyval_parse_elt:w on line ...
-Defining \__keyval_split_key_value:w on line ...
-Defining \__keyval_split_key:w on line ...
-Defining \__keyval_split:Nn on line ...
-Defining \__keyval_split:Nw on line ...
-Defining \__keyval_split_value:w on line ...
 Defining \keyval_parse:NNn on line ...
+Defining \__keyval_sanitise_equals: on line ...
+Defining \__keyval_sanitise_equals_auxi:w on line ...
+Defining \__keyval_sanitise_equals_auxii:w on line ...
+Defining \__keyval_sanitise_comma: on line ...
+Defining \__keyval_sanitise_comma_auxi:w on line ...
+Defining \__keyval_sanitise_comma_auxii:w on line ...
+Defining \__keyval_sanitise_aux:w on line ...
+Defining \__keyval_loop:NNw on line ...
+Defining \__keyval_split:NNw on line ...
+Defining \__keyval_split_value:NNw on line ...
+Defining \__keyval_split_tidy:w on line ...
+Defining \__keyval_action: on line ...
+Defining \__keyval_empty_key: on line ...
+Defining \__keyval_def:Nn on line ...
+Defining \__keyval_def_aux:n on line ...
+Defining \__keyval_def_aux:w on line ...
 Defining message LaTeX/kernel/misplaced-equals-sign on line ...
 Defining \c__keys_code_root_tl on line ...
 Defining \c__keys_info_root_tl on line ...
 Defining \c__keys_props_root_tl on line ...
 Defining \l_keys_choice_int on line ...
-\l_keys_choice_int=\count125
+\l_keys_choice_int=\count124
 Defining \l_keys_choice_tl on line ...
 Defining \l__keys_groups_clist on line ...
 Defining \l_keys_key_tl on line ...
@@ -3348,25 +3354,25 @@ Defining \__fp_exp_after_normal:Nwwwww on line ...
 Defining \__fp_exp_after_array_f:w on line ...
 Defining \__fp_exp_after_stop_f:nw on line ...
 Defining \c__fp_leading_shift_int on line ...
-\c__fp_leading_shift_int=\count126
+\c__fp_leading_shift_int=\count125
 Defining \c__fp_middle_shift_int on line ...
-\c__fp_middle_shift_int=\count127
+\c__fp_middle_shift_int=\count126
 Defining \c__fp_trailing_shift_int on line ...
-\c__fp_trailing_shift_int=\count128
+\c__fp_trailing_shift_int=\count127
 Defining \__fp_pack:NNNNNw on line ...
 Defining \c__fp_big_leading_shift_int on line ...
-\c__fp_big_leading_shift_int=\count129
+\c__fp_big_leading_shift_int=\count128
 Defining \c__fp_big_middle_shift_int on line ...
-\c__fp_big_middle_shift_int=\count130
+\c__fp_big_middle_shift_int=\count129
 Defining \c__fp_big_trailing_shift_int on line ...
-\c__fp_big_trailing_shift_int=\count131
+\c__fp_big_trailing_shift_int=\count130
 Defining \__fp_pack_big:NNNNNNw on line ...
 Defining \c__fp_Bigg_leading_shift_int on line ...
-\c__fp_Bigg_leading_shift_int=\count132
+\c__fp_Bigg_leading_shift_int=\count131
 Defining \c__fp_Bigg_middle_shift_int on line ...
-\c__fp_Bigg_middle_shift_int=\count133
+\c__fp_Bigg_middle_shift_int=\count132
 Defining \c__fp_Bigg_trailing_shift_int on line ...
-\c__fp_Bigg_trailing_shift_int=\count134
+\c__fp_Bigg_trailing_shift_int=\count133
 Defining \__fp_pack_Bigg:NNNNNNw on line ...
 Defining \__fp_pack_twice_four:wNNNNNNNN on line ...
 Defining \__fp_pack_eight:wNNNNNNNN on line ...
diff --git a/l3kernel/testfiles/m3expl001.tlg b/l3kernel/testfiles/m3expl001.tlg
index d1c273d..a9b709d 100644
--- a/l3kernel/testfiles/m3expl001.tlg
+++ b/l3kernel/testfiles/m3expl001.tlg
@@ -3095,26 +3095,32 @@ Defining \g_tmpa_muskip on line ...
 \g_tmpa_muskip=\muskip44
 Defining \g_tmpb_muskip on line ...
 \g_tmpb_muskip=\muskip45
-Defining \g__keyval_level_int on line ...
-\g__keyval_level_int=\count123
 Defining \l__keyval_key_tl on line ...
 Defining \l__keyval_value_tl on line ...
 Defining \l__keyval_sanitise_tl on line ...
-Defining \l__keyval_parse_tl on line ...
-Defining \__keyval_parse:n on line ...
-Defining \__keyval_parse_elt:w on line ...
-Defining \__keyval_split_key_value:w on line ...
-Defining \__keyval_split_key:w on line ...
-Defining \__keyval_split:Nn on line ...
-Defining \__keyval_split:Nw on line ...
-Defining \__keyval_split_value:w on line ...
 Defining \keyval_parse:NNn on line ...
+Defining \__keyval_sanitise_equals: on line ...
+Defining \__keyval_sanitise_equals_auxi:w on line ...
+Defining \__keyval_sanitise_equals_auxii:w on line ...
+Defining \__keyval_sanitise_comma: on line ...
+Defining \__keyval_sanitise_comma_auxi:w on line ...
+Defining \__keyval_sanitise_comma_auxii:w on line ...
+Defining \__keyval_sanitise_aux:w on line ...
+Defining \__keyval_loop:NNw on line ...
+Defining \__keyval_split:NNw on line ...
+Defining \__keyval_split_value:NNw on line ...
+Defining \__keyval_split_tidy:w on line ...
+Defining \__keyval_action: on line ...
+Defining \__keyval_empty_key: on line ...
+Defining \__keyval_def:Nn on line ...
+Defining \__keyval_def_aux:n on line ...
+Defining \__keyval_def_aux:w on line ...
 Defining message LaTeX/kernel/misplaced-equals-sign on line ...
 Defining \c__keys_code_root_tl on line ...
 Defining \c__keys_info_root_tl on line ...
 Defining \c__keys_props_root_tl on line ...
 Defining \l_keys_choice_int on line ...
-\l_keys_choice_int=\count124
+\l_keys_choice_int=\count123
 Defining \l_keys_choice_tl on line ...
 Defining \l__keys_groups_clist on line ...
 Defining \l_keys_key_tl on line ...
@@ -3348,25 +3354,25 @@ Defining \__fp_exp_after_normal:Nwwwww on line ...
 Defining \__fp_exp_after_array_f:w on line ...
 Defining \__fp_exp_after_stop_f:nw on line ...
 Defining \c__fp_leading_shift_int on line ...
-\c__fp_leading_shift_int=\count125
+\c__fp_leading_shift_int=\count124
 Defining \c__fp_middle_shift_int on line ...
-\c__fp_middle_shift_int=\count126
+\c__fp_middle_shift_int=\count125
 Defining \c__fp_trailing_shift_int on line ...
-\c__fp_trailing_shift_int=\count127
+\c__fp_trailing_shift_int=\count126
 Defining \__fp_pack:NNNNNw on line ...
 Defining \c__fp_big_leading_shift_int on line ...
-\c__fp_big_leading_shift_int=\count128
+\c__fp_big_leading_shift_int=\count127
 Defining \c__fp_big_middle_shift_int on line ...
-\c__fp_big_middle_shift_int=\count129
+\c__fp_big_middle_shift_int=\count128
 Defining \c__fp_big_trailing_shift_int on line ...
-\c__fp_big_trailing_shift_int=\count130
+\c__fp_big_trailing_shift_int=\count129
 Defining \__fp_pack_big:NNNNNNw on line ...
 Defining \c__fp_Bigg_leading_shift_int on line ...
-\c__fp_Bigg_leading_shift_int=\count131
+\c__fp_Bigg_leading_shift_int=\count130
 Defining \c__fp_Bigg_middle_shift_int on line ...
-\c__fp_Bigg_middle_shift_int=\count132
+\c__fp_Bigg_middle_shift_int=\count131
 Defining \c__fp_Bigg_trailing_shift_int on line ...
-\c__fp_Bigg_trailing_shift_int=\count133
+\c__fp_Bigg_trailing_shift_int=\count132
 Defining \__fp_pack_Bigg:NNNNNNw on line ...
 Defining \__fp_pack_twice_four:wNNNNNNNN on line ...
 Defining \__fp_pack_eight:wNNNNNNNN on line ...
@@ -4974,7 +4980,7 @@ Defining \__driver_scope_end: on line ...
 Defining \__driver_matrix:n on line ...
 Defining \l__driver_current_color_tl on line ...
 Defining \l__driver_color_stack_int on line ...
-\l__driver_color_stack_int=\count134
+\l__driver_color_stack_int=\count133
 Defining \__driver_color_ensure_current: on line ...
 Defining \__driver_color_reset: on line ...
 Defining \__driver_box_use_clip:N on line ...
diff --git a/l3kernel/testfiles/m3expl001.uptex.tlg b/l3kernel/testfiles/m3expl001.uptex.tlg
index b8f94e2..79860c4 100644
--- a/l3kernel/testfiles/m3expl001.uptex.tlg
+++ b/l3kernel/testfiles/m3expl001.uptex.tlg
@@ -3095,26 +3095,32 @@ Defining \g_tmpa_muskip on line ...
 \g_tmpa_muskip=\muskip44
 Defining \g_tmpb_muskip on line ...
 \g_tmpb_muskip=\muskip45
-Defining \g__keyval_level_int on line ...
-\g__keyval_level_int=\count124
 Defining \l__keyval_key_tl on line ...
 Defining \l__keyval_value_tl on line ...
 Defining \l__keyval_sanitise_tl on line ...
-Defining \l__keyval_parse_tl on line ...
-Defining \__keyval_parse:n on line ...
-Defining \__keyval_parse_elt:w on line ...
-Defining \__keyval_split_key_value:w on line ...
-Defining \__keyval_split_key:w on line ...
-Defining \__keyval_split:Nn on line ...
-Defining \__keyval_split:Nw on line ...
-Defining \__keyval_split_value:w on line ...
 Defining \keyval_parse:NNn on line ...
+Defining \__keyval_sanitise_equals: on line ...
+Defining \__keyval_sanitise_equals_auxi:w on line ...
+Defining \__keyval_sanitise_equals_auxii:w on line ...
+Defining \__keyval_sanitise_comma: on line ...
+Defining \__keyval_sanitise_comma_auxi:w on line ...
+Defining \__keyval_sanitise_comma_auxii:w on line ...
+Defining \__keyval_sanitise_aux:w on line ...
+Defining \__keyval_loop:NNw on line ...
+Defining \__keyval_split:NNw on line ...
+Defining \__keyval_split_value:NNw on line ...
+Defining \__keyval_split_tidy:w on line ...
+Defining \__keyval_action: on line ...
+Defining \__keyval_empty_key: on line ...
+Defining \__keyval_def:Nn on line ...
+Defining \__keyval_def_aux:n on line ...
+Defining \__keyval_def_aux:w on line ...
 Defining message LaTeX/kernel/misplaced-equals-sign on line ...
 Defining \c__keys_code_root_tl on line ...
 Defining \c__keys_info_root_tl on line ...
 Defining \c__keys_props_root_tl on line ...
 Defining \l_keys_choice_int on line ...
-\l_keys_choice_int=\count125
+\l_keys_choice_int=\count124
 Defining \l_keys_choice_tl on line ...
 Defining \l__keys_groups_clist on line ...
 Defining \l_keys_key_tl on line ...
@@ -3348,25 +3354,25 @@ Defining \__fp_exp_after_normal:Nwwwww on line ...
 Defining \__fp_exp_after_array_f:w on line ...
 Defining \__fp_exp_after_stop_f:nw on line ...
 Defining \c__fp_leading_shift_int on line ...
-\c__fp_leading_shift_int=\count126
+\c__fp_leading_shift_int=\count125
 Defining \c__fp_middle_shift_int on line ...
-\c__fp_middle_shift_int=\count127
+\c__fp_middle_shift_int=\count126
 Defining \c__fp_trailing_shift_int on line ...
-\c__fp_trailing_shift_int=\count128
+\c__fp_trailing_shift_int=\count127
 Defining \__fp_pack:NNNNNw on line ...
 Defining \c__fp_big_leading_shift_int on line ...
-\c__fp_big_leading_shift_int=\count129
+\c__fp_big_leading_shift_int=\count128
 Defining \c__fp_big_middle_shift_int on line ...
-\c__fp_big_middle_shift_int=\count130
+\c__fp_big_middle_shift_int=\count129
 Defining \c__fp_big_trailing_shift_int on line ...
-\c__fp_big_trailing_shift_int=\count131
+\c__fp_big_trailing_shift_int=\count130
 Defining \__fp_pack_big:NNNNNNw on line ...
 Defining \c__fp_Bigg_leading_shift_int on line ...
-\c__fp_Bigg_leading_shift_int=\count132
+\c__fp_Bigg_leading_shift_int=\count131
 Defining \c__fp_Bigg_middle_shift_int on line ...
-\c__fp_Bigg_middle_shift_int=\count133
+\c__fp_Bigg_middle_shift_int=\count132
 Defining \c__fp_Bigg_trailing_shift_int on line ...
-\c__fp_Bigg_trailing_shift_int=\count134
+\c__fp_Bigg_trailing_shift_int=\count133
 Defining \__fp_pack_Bigg:NNNNNNw on line ...
 Defining \__fp_pack_twice_four:wNNNNNNNN on line ...
 Defining \__fp_pack_eight:wNNNNNNNN on line ...
diff --git a/l3kernel/testfiles/m3expl001.xetex.tlg b/l3kernel/testfiles/m3expl001.xetex.tlg
index 0fd0b66..e892c05 100644
--- a/l3kernel/testfiles/m3expl001.xetex.tlg
+++ b/l3kernel/testfiles/m3expl001.xetex.tlg
@@ -3102,26 +3102,32 @@ Defining \g_tmpa_muskip on line ...
 \g_tmpa_muskip=\muskip44
 Defining \g_tmpb_muskip on line ...
 \g_tmpb_muskip=\muskip45
-Defining \g__keyval_level_int on line ...
-\g__keyval_level_int=\count123
 Defining \l__keyval_key_tl on line ...
 Defining \l__keyval_value_tl on line ...
 Defining \l__keyval_sanitise_tl on line ...
-Defining \l__keyval_parse_tl on line ...
-Defining \__keyval_parse:n on line ...
-Defining \__keyval_parse_elt:w on line ...
-Defining \__keyval_split_key_value:w on line ...
-Defining \__keyval_split_key:w on line ...
-Defining \__keyval_split:Nn on line ...
-Defining \__keyval_split:Nw on line ...
-Defining \__keyval_split_value:w on line ...
 Defining \keyval_parse:NNn on line ...
+Defining \__keyval_sanitise_equals: on line ...
+Defining \__keyval_sanitise_equals_auxi:w on line ...
+Defining \__keyval_sanitise_equals_auxii:w on line ...
+Defining \__keyval_sanitise_comma: on line ...
+Defining \__keyval_sanitise_comma_auxi:w on line ...
+Defining \__keyval_sanitise_comma_auxii:w on line ...
+Defining \__keyval_sanitise_aux:w on line ...
+Defining \__keyval_loop:NNw on line ...
+Defining \__keyval_split:NNw on line ...
+Defining \__keyval_split_value:NNw on line ...
+Defining \__keyval_split_tidy:w on line ...
+Defining \__keyval_action: on line ...
+Defining \__keyval_empty_key: on line ...
+Defining \__keyval_def:Nn on line ...
+Defining \__keyval_def_aux:n on line ...
+Defining \__keyval_def_aux:w on line ...
 Defining message LaTeX/kernel/misplaced-equals-sign on line ...
 Defining \c__keys_code_root_tl on line ...
 Defining \c__keys_info_root_tl on line ...
 Defining \c__keys_props_root_tl on line ...
 Defining \l_keys_choice_int on line ...
-\l_keys_choice_int=\count124
+\l_keys_choice_int=\count123
 Defining \l_keys_choice_tl on line ...
 Defining \l__keys_groups_clist on line ...
 Defining \l_keys_key_tl on line ...
@@ -3355,25 +3361,25 @@ Defining \__fp_exp_after_normal:Nwwwww on line ...
 Defining \__fp_exp_after_array_f:w on line ...
 Defining \__fp_exp_after_stop_f:nw on line ...
 Defining \c__fp_leading_shift_int on line ...
-\c__fp_leading_shift_int=\count125
+\c__fp_leading_shift_int=\count124
 Defining \c__fp_middle_shift_int on line ...
-\c__fp_middle_shift_int=\count126
+\c__fp_middle_shift_int=\count125
 Defining \c__fp_trailing_shift_int on line ...
-\c__fp_trailing_shift_int=\count127
+\c__fp_trailing_shift_int=\count126
 Defining \__fp_pack:NNNNNw on line ...
 Defining \c__fp_big_leading_shift_int on line ...
-\c__fp_big_leading_shift_int=\count128
+\c__fp_big_leading_shift_int=\count127
 Defining \c__fp_big_middle_shift_int on line ...
-\c__fp_big_middle_shift_int=\count129
+\c__fp_big_middle_shift_int=\count128
 Defining \c__fp_big_trailing_shift_int on line ...
-\c__fp_big_trailing_shift_int=\count130
+\c__fp_big_trailing_shift_int=\count129
 Defining \__fp_pack_big:NNNNNNw on line ...
 Defining \c__fp_Bigg_leading_shift_int on line ...
-\c__fp_Bigg_leading_shift_int=\count131
+\c__fp_Bigg_leading_shift_int=\count130
 Defining \c__fp_Bigg_middle_shift_int on line ...
-\c__fp_Bigg_middle_shift_int=\count132
+\c__fp_Bigg_middle_shift_int=\count131
 Defining \c__fp_Bigg_trailing_shift_int on line ...
-\c__fp_Bigg_trailing_shift_int=\count133
+\c__fp_Bigg_trailing_shift_int=\count132
 Defining \__fp_pack_Bigg:NNNNNNw on line ...
 Defining \__fp_pack_twice_four:wNNNNNNNN on line ...
 Defining \__fp_pack_eight:wNNNNNNNN on line ...
diff --git a/l3kernel/testfiles/m3expl002.luatex.tlg b/l3kernel/testfiles/m3expl002.luatex.tlg
index 90e997b..4aa1239 100644
--- a/l3kernel/testfiles/m3expl002.luatex.tlg
+++ b/l3kernel/testfiles/m3expl002.luatex.tlg
@@ -32,17 +32,16 @@ Don't change this file in any respect.
 \l_tmpb_muskip=\muskip43
 \g_tmpa_muskip=\muskip44
 \g_tmpb_muskip=\muskip45
-\g__keyval_level_int=\count123
-\l_keys_choice_int=\count124
-\c__fp_leading_shift_int=\count125
-\c__fp_middle_shift_int=\count126
-\c__fp_trailing_shift_int=\count127
-\c__fp_big_leading_shift_int=\count128
-\c__fp_big_middle_shift_int=\count129
-\c__fp_big_trailing_shift_int=\count130
-\c__fp_Bigg_leading_shift_int=\count131
-\c__fp_Bigg_middle_shift_int=\count132
-\c__fp_Bigg_trailing_shift_int=\count133
+\l_keys_choice_int=\count123
+\c__fp_leading_shift_int=\count124
+\c__fp_middle_shift_int=\count125
+\c__fp_trailing_shift_int=\count126
+\c__fp_big_leading_shift_int=\count127
+\c__fp_big_middle_shift_int=\count128
+\c__fp_big_trailing_shift_int=\count129
+\c__fp_Bigg_leading_shift_int=\count130
+\c__fp_Bigg_middle_shift_int=\count131
+\c__fp_Bigg_trailing_shift_int=\count132
 \c_empty_box=\box56
 \l_tmpa_box=\box57
 \l_tmpb_box=\box58
@@ -84,6 +83,6 @@ Don't change this file in any respect.
 \l__coffin_scaled_total_height_dim=\dimen161
 \l__coffin_scaled_width_dim=\dimen162
 ) (l3pdfmode.def
-\l__driver_color_stack_int=\count134
+\l__driver_color_stack_int=\count133
 \l__driver_tmp_box=\box71
 ))
diff --git a/l3kernel/testfiles/m3expl002.ptex.tlg b/l3kernel/testfiles/m3expl002.ptex.tlg
index 39185fa..cd1e5d2 100644
--- a/l3kernel/testfiles/m3expl002.ptex.tlg
+++ b/l3kernel/testfiles/m3expl002.ptex.tlg
@@ -31,17 +31,16 @@ Don't change this file in any respect.
 \l_tmpb_muskip=\muskip43
 \g_tmpa_muskip=\muskip44
 \g_tmpb_muskip=\muskip45
-\g__keyval_level_int=\count124
-\l_keys_choice_int=\count125
-\c__fp_leading_shift_int=\count126
-\c__fp_middle_shift_int=\count127
-\c__fp_trailing_shift_int=\count128
-\c__fp_big_leading_shift_int=\count129
-\c__fp_big_middle_shift_int=\count130
-\c__fp_big_trailing_shift_int=\count131
-\c__fp_Bigg_leading_shift_int=\count132
-\c__fp_Bigg_middle_shift_int=\count133
-\c__fp_Bigg_trailing_shift_int=\count134
+\l_keys_choice_int=\count124
+\c__fp_leading_shift_int=\count125
+\c__fp_middle_shift_int=\count126
+\c__fp_trailing_shift_int=\count127
+\c__fp_big_leading_shift_int=\count128
+\c__fp_big_middle_shift_int=\count129
+\c__fp_big_trailing_shift_int=\count130
+\c__fp_Bigg_leading_shift_int=\count131
+\c__fp_Bigg_middle_shift_int=\count132
+\c__fp_Bigg_trailing_shift_int=\count133
 \c_empty_box=\box56
 \l_tmpa_box=\box57
 \l_tmpb_box=\box58
diff --git a/l3kernel/testfiles/m3expl002.tlg b/l3kernel/testfiles/m3expl002.tlg
index c4c55be..e2cf193 100644
--- a/l3kernel/testfiles/m3expl002.tlg
+++ b/l3kernel/testfiles/m3expl002.tlg
@@ -31,17 +31,16 @@ Don't change this file in any respect.
 \l_tmpb_muskip=\muskip43
 \g_tmpa_muskip=\muskip44
 \g_tmpb_muskip=\muskip45
-\g__keyval_level_int=\count123
-\l_keys_choice_int=\count124
-\c__fp_leading_shift_int=\count125
-\c__fp_middle_shift_int=\count126
-\c__fp_trailing_shift_int=\count127
-\c__fp_big_leading_shift_int=\count128
-\c__fp_big_middle_shift_int=\count129
-\c__fp_big_trailing_shift_int=\count130
-\c__fp_Bigg_leading_shift_int=\count131
-\c__fp_Bigg_middle_shift_int=\count132
-\c__fp_Bigg_trailing_shift_int=\count133
+\l_keys_choice_int=\count123
+\c__fp_leading_shift_int=\count124
+\c__fp_middle_shift_int=\count125
+\c__fp_trailing_shift_int=\count126
+\c__fp_big_leading_shift_int=\count127
+\c__fp_big_middle_shift_int=\count128
+\c__fp_big_trailing_shift_int=\count129
+\c__fp_Bigg_leading_shift_int=\count130
+\c__fp_Bigg_middle_shift_int=\count131
+\c__fp_Bigg_trailing_shift_int=\count132
 \c_empty_box=\box56
 \l_tmpa_box=\box57
 \l_tmpb_box=\box58
@@ -83,6 +82,6 @@ Don't change this file in any respect.
 \l__coffin_scaled_total_height_dim=\dimen161
 \l__coffin_scaled_width_dim=\dimen162
 ) (l3pdfmode.def
-\l__driver_color_stack_int=\count134
+\l__driver_color_stack_int=\count133
 \l__driver_tmp_box=\box71
 ))
diff --git a/l3kernel/testfiles/m3expl002.uptex.tlg b/l3kernel/testfiles/m3expl002.uptex.tlg
index 39185fa..cd1e5d2 100644
--- a/l3kernel/testfiles/m3expl002.uptex.tlg
+++ b/l3kernel/testfiles/m3expl002.uptex.tlg
@@ -31,17 +31,16 @@ Don't change this file in any respect.
 \l_tmpb_muskip=\muskip43
 \g_tmpa_muskip=\muskip44
 \g_tmpb_muskip=\muskip45
-\g__keyval_level_int=\count124
-\l_keys_choice_int=\count125
-\c__fp_leading_shift_int=\count126
-\c__fp_middle_shift_int=\count127
-\c__fp_trailing_shift_int=\count128
-\c__fp_big_leading_shift_int=\count129
-\c__fp_big_middle_shift_int=\count130
-\c__fp_big_trailing_shift_int=\count131
-\c__fp_Bigg_leading_shift_int=\count132
-\c__fp_Bigg_middle_shift_int=\count133
-\c__fp_Bigg_trailing_shift_int=\count134
+\l_keys_choice_int=\count124
+\c__fp_leading_shift_int=\count125
+\c__fp_middle_shift_int=\count126
+\c__fp_trailing_shift_int=\count127
+\c__fp_big_leading_shift_int=\count128
+\c__fp_big_middle_shift_int=\count129
+\c__fp_big_trailing_shift_int=\count130
+\c__fp_Bigg_leading_shift_int=\count131
+\c__fp_Bigg_middle_shift_int=\count132
+\c__fp_Bigg_trailing_shift_int=\count133
 \c_empty_box=\box56
 \l_tmpa_box=\box57
 \l_tmpb_box=\box58
diff --git a/l3kernel/testfiles/m3expl002.xetex.tlg b/l3kernel/testfiles/m3expl002.xetex.tlg
index 0d4902e..d48fc7a 100644
--- a/l3kernel/testfiles/m3expl002.xetex.tlg
+++ b/l3kernel/testfiles/m3expl002.xetex.tlg
@@ -31,17 +31,16 @@ Don't change this file in any respect.
 \l_tmpb_muskip=\muskip43
 \g_tmpa_muskip=\muskip44
 \g_tmpb_muskip=\muskip45
-\g__keyval_level_int=\count123
-\l_keys_choice_int=\count124
-\c__fp_leading_shift_int=\count125
-\c__fp_middle_shift_int=\count126
-\c__fp_trailing_shift_int=\count127
-\c__fp_big_leading_shift_int=\count128
-\c__fp_big_middle_shift_int=\count129
-\c__fp_big_trailing_shift_int=\count130
-\c__fp_Bigg_leading_shift_int=\count131
-\c__fp_Bigg_middle_shift_int=\count132
-\c__fp_Bigg_trailing_shift_int=\count133
+\l_keys_choice_int=\count123
+\c__fp_leading_shift_int=\count124
+\c__fp_middle_shift_int=\count125
+\c__fp_trailing_shift_int=\count126
+\c__fp_big_leading_shift_int=\count127
+\c__fp_big_middle_shift_int=\count128
+\c__fp_big_trailing_shift_int=\count129
+\c__fp_Bigg_leading_shift_int=\count130
+\c__fp_Bigg_middle_shift_int=\count131
+\c__fp_Bigg_trailing_shift_int=\count132
 \c_empty_box=\box56
 \l_tmpa_box=\box57
 \l_tmpb_box=\box58
diff --git a/l3kernel/testfiles/m3expl003.luatex.tlg b/l3kernel/testfiles/m3expl003.luatex.tlg
index ea7baa6..d19149a 100644
--- a/l3kernel/testfiles/m3expl003.luatex.tlg
+++ b/l3kernel/testfiles/m3expl003.luatex.tlg
@@ -3105,26 +3105,32 @@ Defining \g_tmpa_muskip on line ...
 \g_tmpa_muskip=\muskip44
 Defining \g_tmpb_muskip on line ...
 \g_tmpb_muskip=\muskip45
-Defining \g__keyval_level_int on line ...
-\g__keyval_level_int=\count123
 Defining \l__keyval_key_tl on line ...
 Defining \l__keyval_value_tl on line ...
 Defining \l__keyval_sanitise_tl on line ...
-Defining \l__keyval_parse_tl on line ...
-Defining \__keyval_parse:n on line ...
-Defining \__keyval_parse_elt:w on line ...
-Defining \__keyval_split_key_value:w on line ...
-Defining \__keyval_split_key:w on line ...
-Defining \__keyval_split:Nn on line ...
-Defining \__keyval_split:Nw on line ...
-Defining \__keyval_split_value:w on line ...
 Defining \keyval_parse:NNn on line ...
+Defining \__keyval_sanitise_equals: on line ...
+Defining \__keyval_sanitise_equals_auxi:w on line ...
+Defining \__keyval_sanitise_equals_auxii:w on line ...
+Defining \__keyval_sanitise_comma: on line ...
+Defining \__keyval_sanitise_comma_auxi:w on line ...
+Defining \__keyval_sanitise_comma_auxii:w on line ...
+Defining \__keyval_sanitise_aux:w on line ...
+Defining \__keyval_loop:NNw on line ...
+Defining \__keyval_split:NNw on line ...
+Defining \__keyval_split_value:NNw on line ...
+Defining \__keyval_split_tidy:w on line ...
+Defining \__keyval_action: on line ...
+Defining \__keyval_empty_key: on line ...
+Defining \__keyval_def:Nn on line ...
+Defining \__keyval_def_aux:n on line ...
+Defining \__keyval_def_aux:w on line ...
 Defining message LaTeX/kernel/misplaced-equals-sign on line ...
 Defining \c__keys_code_root_tl on line ...
 Defining \c__keys_info_root_tl on line ...
 Defining \c__keys_props_root_tl on line ...
 Defining \l_keys_choice_int on line ...
-\l_keys_choice_int=\count124
+\l_keys_choice_int=\count123
 Defining \l_keys_choice_tl on line ...
 Defining \l__keys_groups_clist on line ...
 Defining \l_keys_key_tl on line ...
@@ -3358,25 +3364,25 @@ Defining \__fp_exp_after_normal:Nwwwww on line ...
 Defining \__fp_exp_after_array_f:w on line ...
 Defining \__fp_exp_after_stop_f:nw on line ...
 Defining \c__fp_leading_shift_int on line ...
-\c__fp_leading_shift_int=\count125
+\c__fp_leading_shift_int=\count124
 Defining \c__fp_middle_shift_int on line ...
-\c__fp_middle_shift_int=\count126
+\c__fp_middle_shift_int=\count125
 Defining \c__fp_trailing_shift_int on line ...
-\c__fp_trailing_shift_int=\count127
+\c__fp_trailing_shift_int=\count126
 Defining \__fp_pack:NNNNNw on line ...
 Defining \c__fp_big_leading_shift_int on line ...
-\c__fp_big_leading_shift_int=\count128
+\c__fp_big_leading_shift_int=\count127
 Defining \c__fp_big_middle_shift_int on line ...
-\c__fp_big_middle_shift_int=\count129
+\c__fp_big_middle_shift_int=\count128
 Defining \c__fp_big_trailing_shift_int on line ...
-\c__fp_big_trailing_shift_int=\count130
+\c__fp_big_trailing_shift_int=\count129
 Defining \__fp_pack_big:NNNNNNw on line ...
 Defining \c__fp_Bigg_leading_shift_int on line ...
-\c__fp_Bigg_leading_shift_int=\count131
+\c__fp_Bigg_leading_shift_int=\count130
 Defining \c__fp_Bigg_middle_shift_int on line ...
-\c__fp_Bigg_middle_shift_int=\count132
+\c__fp_Bigg_middle_shift_int=\count131
 Defining \c__fp_Bigg_trailing_shift_int on line ...
-\c__fp_Bigg_trailing_shift_int=\count133
+\c__fp_Bigg_trailing_shift_int=\count132
 Defining \__fp_pack_Bigg:NNNNNNw on line ...
 Defining \__fp_pack_twice_four:wNNNNNNNN on line ...
 Defining \__fp_pack_eight:wNNNNNNNN on line ...
@@ -4783,7 +4789,7 @@ Defining \__driver_scope_end: on line ...
 Defining \__driver_matrix:n on line ...
 Defining \l__driver_current_color_tl on line ...
 Defining \l__driver_color_stack_int on line ...
-\l__driver_color_stack_int=\count134
+\l__driver_color_stack_int=\count133
 Defining \__driver_color_ensure_current: on line ...
 Defining \__driver_color_reset: on line ...
 Defining \__driver_box_use_clip:N on line ...
diff --git a/l3kernel/testfiles/m3expl003.ptex.tlg b/l3kernel/testfiles/m3expl003.ptex.tlg
index 1ace880..75fdce6 100644
--- a/l3kernel/testfiles/m3expl003.ptex.tlg
+++ b/l3kernel/testfiles/m3expl003.ptex.tlg
@@ -3096,26 +3096,32 @@ Defining \g_tmpa_muskip on line ...
 \g_tmpa_muskip=\muskip44
 Defining \g_tmpb_muskip on line ...
 \g_tmpb_muskip=\muskip45
-Defining \g__keyval_level_int on line ...
-\g__keyval_level_int=\count124
 Defining \l__keyval_key_tl on line ...
 Defining \l__keyval_value_tl on line ...
 Defining \l__keyval_sanitise_tl on line ...
-Defining \l__keyval_parse_tl on line ...
-Defining \__keyval_parse:n on line ...
-Defining \__keyval_parse_elt:w on line ...
-Defining \__keyval_split_key_value:w on line ...
-Defining \__keyval_split_key:w on line ...
-Defining \__keyval_split:Nn on line ...
-Defining \__keyval_split:Nw on line ...
-Defining \__keyval_split_value:w on line ...
 Defining \keyval_parse:NNn on line ...
+Defining \__keyval_sanitise_equals: on line ...
+Defining \__keyval_sanitise_equals_auxi:w on line ...
+Defining \__keyval_sanitise_equals_auxii:w on line ...
+Defining \__keyval_sanitise_comma: on line ...
+Defining \__keyval_sanitise_comma_auxi:w on line ...
+Defining \__keyval_sanitise_comma_auxii:w on line ...
+Defining \__keyval_sanitise_aux:w on line ...
+Defining \__keyval_loop:NNw on line ...
+Defining \__keyval_split:NNw on line ...
+Defining \__keyval_split_value:NNw on line ...
+Defining \__keyval_split_tidy:w on line ...
+Defining \__keyval_action: on line ...
+Defining \__keyval_empty_key: on line ...
+Defining \__keyval_def:Nn on line ...
+Defining \__keyval_def_aux:n on line ...
+Defining \__keyval_def_aux:w on line ...
 Defining message LaTeX/kernel/misplaced-equals-sign on line ...
 Defining \c__keys_code_root_tl on line ...
 Defining \c__keys_info_root_tl on line ...
 Defining \c__keys_props_root_tl on line ...
 Defining \l_keys_choice_int on line ...
-\l_keys_choice_int=\count125
+\l_keys_choice_int=\count124
 Defining \l_keys_choice_tl on line ...
 Defining \l__keys_groups_clist on line ...
 Defining \l_keys_key_tl on line ...
@@ -3349,25 +3355,25 @@ Defining \__fp_exp_after_normal:Nwwwww on line ...
 Defining \__fp_exp_after_array_f:w on line ...
 Defining \__fp_exp_after_stop_f:nw on line ...
 Defining \c__fp_leading_shift_int on line ...
-\c__fp_leading_shift_int=\count126
+\c__fp_leading_shift_int=\count125
 Defining \c__fp_middle_shift_int on line ...
-\c__fp_middle_shift_int=\count127
+\c__fp_middle_shift_int=\count126
 Defining \c__fp_trailing_shift_int on line ...
-\c__fp_trailing_shift_int=\count128
+\c__fp_trailing_shift_int=\count127
 Defining \__fp_pack:NNNNNw on line ...
 Defining \c__fp_big_leading_shift_int on line ...
-\c__fp_big_leading_shift_int=\count129
+\c__fp_big_leading_shift_int=\count128
 Defining \c__fp_big_middle_shift_int on line ...
-\c__fp_big_middle_shift_int=\count130
+\c__fp_big_middle_shift_int=\count129
 Defining \c__fp_big_trailing_shift_int on line ...
-\c__fp_big_trailing_shift_int=\count131
+\c__fp_big_trailing_shift_int=\count130
 Defining \__fp_pack_big:NNNNNNw on line ...
 Defining \c__fp_Bigg_leading_shift_int on line ...
-\c__fp_Bigg_leading_shift_int=\count132
+\c__fp_Bigg_leading_shift_int=\count131
 Defining \c__fp_Bigg_middle_shift_int on line ...
-\c__fp_Bigg_middle_shift_int=\count133
+\c__fp_Bigg_middle_shift_int=\count132
 Defining \c__fp_Bigg_trailing_shift_int on line ...
-\c__fp_Bigg_trailing_shift_int=\count134
+\c__fp_Bigg_trailing_shift_int=\count133
 Defining \__fp_pack_Bigg:NNNNNNw on line ...
 Defining \__fp_pack_twice_four:wNNNNNNNN on line ...
 Defining \__fp_pack_eight:wNNNNNNNN on line ...
diff --git a/l3kernel/testfiles/m3expl003.tlg b/l3kernel/testfiles/m3expl003.tlg
index 1694c7a..e7ee147 100644
--- a/l3kernel/testfiles/m3expl003.tlg
+++ b/l3kernel/testfiles/m3expl003.tlg
@@ -3096,26 +3096,32 @@ Defining \g_tmpa_muskip on line ...
 \g_tmpa_muskip=\muskip44
 Defining \g_tmpb_muskip on line ...
 \g_tmpb_muskip=\muskip45
-Defining \g__keyval_level_int on line ...
-\g__keyval_level_int=\count123
 Defining \l__keyval_key_tl on line ...
 Defining \l__keyval_value_tl on line ...
 Defining \l__keyval_sanitise_tl on line ...
-Defining \l__keyval_parse_tl on line ...
-Defining \__keyval_parse:n on line ...
-Defining \__keyval_parse_elt:w on line ...
-Defining \__keyval_split_key_value:w on line ...
-Defining \__keyval_split_key:w on line ...
-Defining \__keyval_split:Nn on line ...
-Defining \__keyval_split:Nw on line ...
-Defining \__keyval_split_value:w on line ...
 Defining \keyval_parse:NNn on line ...
+Defining \__keyval_sanitise_equals: on line ...
+Defining \__keyval_sanitise_equals_auxi:w on line ...
+Defining \__keyval_sanitise_equals_auxii:w on line ...
+Defining \__keyval_sanitise_comma: on line ...
+Defining \__keyval_sanitise_comma_auxi:w on line ...
+Defining \__keyval_sanitise_comma_auxii:w on line ...
+Defining \__keyval_sanitise_aux:w on line ...
+Defining \__keyval_loop:NNw on line ...
+Defining \__keyval_split:NNw on line ...
+Defining \__keyval_split_value:NNw on line ...
+Defining \__keyval_split_tidy:w on line ...
+Defining \__keyval_action: on line ...
+Defining \__keyval_empty_key: on line ...
+Defining \__keyval_def:Nn on line ...
+Defining \__keyval_def_aux:n on line ...
+Defining \__keyval_def_aux:w on line ...
 Defining message LaTeX/kernel/misplaced-equals-sign on line ...
 Defining \c__keys_code_root_tl on line ...
 Defining \c__keys_info_root_tl on line ...
 Defining \c__keys_props_root_tl on line ...
 Defining \l_keys_choice_int on line ...
-\l_keys_choice_int=\count124
+\l_keys_choice_int=\count123
 Defining \l_keys_choice_tl on line ...
 Defining \l__keys_groups_clist on line ...
 Defining \l_keys_key_tl on line ...
@@ -3349,25 +3355,25 @@ Defining \__fp_exp_after_normal:Nwwwww on line ...
 Defining \__fp_exp_after_array_f:w on line ...
 Defining \__fp_exp_after_stop_f:nw on line ...
 Defining \c__fp_leading_shift_int on line ...
-\c__fp_leading_shift_int=\count125
+\c__fp_leading_shift_int=\count124
 Defining \c__fp_middle_shift_int on line ...
-\c__fp_middle_shift_int=\count126
+\c__fp_middle_shift_int=\count125
 Defining \c__fp_trailing_shift_int on line ...
-\c__fp_trailing_shift_int=\count127
+\c__fp_trailing_shift_int=\count126
 Defining \__fp_pack:NNNNNw on line ...
 Defining \c__fp_big_leading_shift_int on line ...
-\c__fp_big_leading_shift_int=\count128
+\c__fp_big_leading_shift_int=\count127
 Defining \c__fp_big_middle_shift_int on line ...
-\c__fp_big_middle_shift_int=\count129
+\c__fp_big_middle_shift_int=\count128
 Defining \c__fp_big_trailing_shift_int on line ...
-\c__fp_big_trailing_shift_int=\count130
+\c__fp_big_trailing_shift_int=\count129
 Defining \__fp_pack_big:NNNNNNw on line ...
 Defining \c__fp_Bigg_leading_shift_int on line ...
-\c__fp_Bigg_leading_shift_int=\count131
+\c__fp_Bigg_leading_shift_int=\count130
 Defining \c__fp_Bigg_middle_shift_int on line ...
-\c__fp_Bigg_middle_shift_int=\count132
+\c__fp_Bigg_middle_shift_int=\count131
 Defining \c__fp_Bigg_trailing_shift_int on line ...
-\c__fp_Bigg_trailing_shift_int=\count133
+\c__fp_Bigg_trailing_shift_int=\count132
 Defining \__fp_pack_Bigg:NNNNNNw on line ...
 Defining \__fp_pack_twice_four:wNNNNNNNN on line ...
 Defining \__fp_pack_eight:wNNNNNNNN on line ...
@@ -4975,7 +4981,7 @@ Defining \__driver_scope_end: on line ...
 Defining \__driver_matrix:n on line ...
 Defining \l__driver_current_color_tl on line ...
 Defining \l__driver_color_stack_int on line ...
-\l__driver_color_stack_int=\count134
+\l__driver_color_stack_int=\count133
 Defining \__driver_color_ensure_current: on line ...
 Defining \__driver_color_reset: on line ...
 Defining \__driver_box_use_clip:N on line ...
diff --git a/l3kernel/testfiles/m3expl003.uptex.tlg b/l3kernel/testfiles/m3expl003.uptex.tlg
index 586f2e1..d9c400a 100644
--- a/l3kernel/testfiles/m3expl003.uptex.tlg
+++ b/l3kernel/testfiles/m3expl003.uptex.tlg
@@ -3096,26 +3096,32 @@ Defining \g_tmpa_muskip on line ...
 \g_tmpa_muskip=\muskip44
 Defining \g_tmpb_muskip on line ...
 \g_tmpb_muskip=\muskip45
-Defining \g__keyval_level_int on line ...
-\g__keyval_level_int=\count124
 Defining \l__keyval_key_tl on line ...
 Defining \l__keyval_value_tl on line ...
 Defining \l__keyval_sanitise_tl on line ...
-Defining \l__keyval_parse_tl on line ...
-Defining \__keyval_parse:n on line ...
-Defining \__keyval_parse_elt:w on line ...
-Defining \__keyval_split_key_value:w on line ...
-Defining \__keyval_split_key:w on line ...
-Defining \__keyval_split:Nn on line ...
-Defining \__keyval_split:Nw on line ...
-Defining \__keyval_split_value:w on line ...
 Defining \keyval_parse:NNn on line ...
+Defining \__keyval_sanitise_equals: on line ...
+Defining \__keyval_sanitise_equals_auxi:w on line ...
+Defining \__keyval_sanitise_equals_auxii:w on line ...
+Defining \__keyval_sanitise_comma: on line ...
+Defining \__keyval_sanitise_comma_auxi:w on line ...
+Defining \__keyval_sanitise_comma_auxii:w on line ...
+Defining \__keyval_sanitise_aux:w on line ...
+Defining \__keyval_loop:NNw on line ...
+Defining \__keyval_split:NNw on line ...
+Defining \__keyval_split_value:NNw on line ...
+Defining \__keyval_split_tidy:w on line ...
+Defining \__keyval_action: on line ...
+Defining \__keyval_empty_key: on line ...
+Defining \__keyval_def:Nn on line ...
+Defining \__keyval_def_aux:n on line ...
+Defining \__keyval_def_aux:w on line ...
 Defining message LaTeX/kernel/misplaced-equals-sign on line ...
 Defining \c__keys_code_root_tl on line ...
 Defining \c__keys_info_root_tl on line ...
 Defining \c__keys_props_root_tl on line ...
 Defining \l_keys_choice_int on line ...
-\l_keys_choice_int=\count125
+\l_keys_choice_int=\count124
 Defining \l_keys_choice_tl on line ...
 Defining \l__keys_groups_clist on line ...
 Defining \l_keys_key_tl on line ...
@@ -3349,25 +3355,25 @@ Defining \__fp_exp_after_normal:Nwwwww on line ...
 Defining \__fp_exp_after_array_f:w on line ...
 Defining \__fp_exp_after_stop_f:nw on line ...
 Defining \c__fp_leading_shift_int on line ...
-\c__fp_leading_shift_int=\count126
+\c__fp_leading_shift_int=\count125
 Defining \c__fp_middle_shift_int on line ...
-\c__fp_middle_shift_int=\count127
+\c__fp_middle_shift_int=\count126
 Defining \c__fp_trailing_shift_int on line ...
-\c__fp_trailing_shift_int=\count128
+\c__fp_trailing_shift_int=\count127
 Defining \__fp_pack:NNNNNw on line ...
 Defining \c__fp_big_leading_shift_int on line ...
-\c__fp_big_leading_shift_int=\count129
+\c__fp_big_leading_shift_int=\count128
 Defining \c__fp_big_middle_shift_int on line ...
-\c__fp_big_middle_shift_int=\count130
+\c__fp_big_middle_shift_int=\count129
 Defining \c__fp_big_trailing_shift_int on line ...
-\c__fp_big_trailing_shift_int=\count131
+\c__fp_big_trailing_shift_int=\count130
 Defining \__fp_pack_big:NNNNNNw on line ...
 Defining \c__fp_Bigg_leading_shift_int on line ...
-\c__fp_Bigg_leading_shift_int=\count132
+\c__fp_Bigg_leading_shift_int=\count131
 Defining \c__fp_Bigg_middle_shift_int on line ...
-\c__fp_Bigg_middle_shift_int=\count133
+\c__fp_Bigg_middle_shift_int=\count132
 Defining \c__fp_Bigg_trailing_shift_int on line ...
-\c__fp_Bigg_trailing_shift_int=\count134
+\c__fp_Bigg_trailing_shift_int=\count133
 Defining \__fp_pack_Bigg:NNNNNNw on line ...
 Defining \__fp_pack_twice_four:wNNNNNNNN on line ...
 Defining \__fp_pack_eight:wNNNNNNNN on line ...
diff --git a/l3kernel/testfiles/m3expl003.xetex.tlg b/l3kernel/testfiles/m3expl003.xetex.tlg
index a7a36ed..6b0eb9b 100644
--- a/l3kernel/testfiles/m3expl003.xetex.tlg
+++ b/l3kernel/testfiles/m3expl003.xetex.tlg
@@ -3103,26 +3103,32 @@ Defining \g_tmpa_muskip on line ...
 \g_tmpa_muskip=\muskip44
 Defining \g_tmpb_muskip on line ...
 \g_tmpb_muskip=\muskip45
-Defining \g__keyval_level_int on line ...
-\g__keyval_level_int=\count123
 Defining \l__keyval_key_tl on line ...
 Defining \l__keyval_value_tl on line ...
 Defining \l__keyval_sanitise_tl on line ...
-Defining \l__keyval_parse_tl on line ...
-Defining \__keyval_parse:n on line ...
-Defining \__keyval_parse_elt:w on line ...
-Defining \__keyval_split_key_value:w on line ...
-Defining \__keyval_split_key:w on line ...
-Defining \__keyval_split:Nn on line ...
-Defining \__keyval_split:Nw on line ...
-Defining \__keyval_split_value:w on line ...
 Defining \keyval_parse:NNn on line ...
+Defining \__keyval_sanitise_equals: on line ...
+Defining \__keyval_sanitise_equals_auxi:w on line ...
+Defining \__keyval_sanitise_equals_auxii:w on line ...
+Defining \__keyval_sanitise_comma: on line ...
+Defining \__keyval_sanitise_comma_auxi:w on line ...
+Defining \__keyval_sanitise_comma_auxii:w on line ...
+Defining \__keyval_sanitise_aux:w on line ...
+Defining \__keyval_loop:NNw on line ...
+Defining \__keyval_split:NNw on line ...
+Defining \__keyval_split_value:NNw on line ...
+Defining \__keyval_split_tidy:w on line ...
+Defining \__keyval_action: on line ...
+Defining \__keyval_empty_key: on line ...
+Defining \__keyval_def:Nn on line ...
+Defining \__keyval_def_aux:n on line ...
+Defining \__keyval_def_aux:w on line ...
 Defining message LaTeX/kernel/misplaced-equals-sign on line ...
 Defining \c__keys_code_root_tl on line ...
 Defining \c__keys_info_root_tl on line ...
 Defining \c__keys_props_root_tl on line ...
 Defining \l_keys_choice_int on line ...
-\l_keys_choice_int=\count124
+\l_keys_choice_int=\count123
 Defining \l_keys_choice_tl on line ...
 Defining \l__keys_groups_clist on line ...
 Defining \l_keys_key_tl on line ...
@@ -3356,25 +3362,25 @@ Defining \__fp_exp_after_normal:Nwwwww on line ...
 Defining \__fp_exp_after_array_f:w on line ...
 Defining \__fp_exp_after_stop_f:nw on line ...
 Defining \c__fp_leading_shift_int on line ...
-\c__fp_leading_shift_int=\count125
+\c__fp_leading_shift_int=\count124
 Defining \c__fp_middle_shift_int on line ...
-\c__fp_middle_shift_int=\count126
+\c__fp_middle_shift_int=\count125
 Defining \c__fp_trailing_shift_int on line ...
-\c__fp_trailing_shift_int=\count127
+\c__fp_trailing_shift_int=\count126
 Defining \__fp_pack:NNNNNw on line ...
 Defining \c__fp_big_leading_shift_int on line ...
-\c__fp_big_leading_shift_int=\count128
+\c__fp_big_leading_shift_int=\count127
 Defining \c__fp_big_middle_shift_int on line ...
-\c__fp_big_middle_shift_int=\count129
+\c__fp_big_middle_shift_int=\count128
 Defining \c__fp_big_trailing_shift_int on line ...
-\c__fp_big_trailing_shift_int=\count130
+\c__fp_big_trailing_shift_int=\count129
 Defining \__fp_pack_big:NNNNNNw on line ...
 Defining \c__fp_Bigg_leading_shift_int on line ...
-\c__fp_Bigg_leading_shift_int=\count131
+\c__fp_Bigg_leading_shift_int=\count130
 Defining \c__fp_Bigg_middle_shift_int on line ...
-\c__fp_Bigg_middle_shift_int=\count132
+\c__fp_Bigg_middle_shift_int=\count131
 Defining \c__fp_Bigg_trailing_shift_int on line ...
-\c__fp_Bigg_trailing_shift_int=\count133
+\c__fp_Bigg_trailing_shift_int=\count132
 Defining \__fp_pack_Bigg:NNNNNNw on line ...
 Defining \__fp_pack_twice_four:wNNNNNNNN on line ...
 Defining \__fp_pack_eight:wNNNNNNNN on line ...
diff --git a/l3kernel/testfiles/m3expl004.luatex.tlg b/l3kernel/testfiles/m3expl004.luatex.tlg
index 90e997b..4aa1239 100644
--- a/l3kernel/testfiles/m3expl004.luatex.tlg
+++ b/l3kernel/testfiles/m3expl004.luatex.tlg
@@ -32,17 +32,16 @@ Don't change this file in any respect.
 \l_tmpb_muskip=\muskip43
 \g_tmpa_muskip=\muskip44
 \g_tmpb_muskip=\muskip45
-\g__keyval_level_int=\count123
-\l_keys_choice_int=\count124
-\c__fp_leading_shift_int=\count125
-\c__fp_middle_shift_int=\count126
-\c__fp_trailing_shift_int=\count127
-\c__fp_big_leading_shift_int=\count128
-\c__fp_big_middle_shift_int=\count129
-\c__fp_big_trailing_shift_int=\count130
-\c__fp_Bigg_leading_shift_int=\count131
-\c__fp_Bigg_middle_shift_int=\count132
-\c__fp_Bigg_trailing_shift_int=\count133
+\l_keys_choice_int=\count123
+\c__fp_leading_shift_int=\count124
+\c__fp_middle_shift_int=\count125
+\c__fp_trailing_shift_int=\count126
+\c__fp_big_leading_shift_int=\count127
+\c__fp_big_middle_shift_int=\count128
+\c__fp_big_trailing_shift_int=\count129
+\c__fp_Bigg_leading_shift_int=\count130
+\c__fp_Bigg_middle_shift_int=\count131
+\c__fp_Bigg_trailing_shift_int=\count132
 \c_empty_box=\box56
 \l_tmpa_box=\box57
 \l_tmpb_box=\box58
@@ -84,6 +83,6 @@ Don't change this file in any respect.
 \l__coffin_scaled_total_height_dim=\dimen161
 \l__coffin_scaled_width_dim=\dimen162
 ) (l3pdfmode.def
-\l__driver_color_stack_int=\count134
+\l__driver_color_stack_int=\count133
 \l__driver_tmp_box=\box71
 ))
diff --git a/l3kernel/testfiles/m3expl004.ptex.tlg b/l3kernel/testfiles/m3expl004.ptex.tlg
index 39185fa..cd1e5d2 100644
--- a/l3kernel/testfiles/m3expl004.ptex.tlg
+++ b/l3kernel/testfiles/m3expl004.ptex.tlg
@@ -31,17 +31,16 @@ Don't change this file in any respect.
 \l_tmpb_muskip=\muskip43
 \g_tmpa_muskip=\muskip44
 \g_tmpb_muskip=\muskip45
-\g__keyval_level_int=\count124
-\l_keys_choice_int=\count125
-\c__fp_leading_shift_int=\count126
-\c__fp_middle_shift_int=\count127
-\c__fp_trailing_shift_int=\count128
-\c__fp_big_leading_shift_int=\count129
-\c__fp_big_middle_shift_int=\count130
-\c__fp_big_trailing_shift_int=\count131
-\c__fp_Bigg_leading_shift_int=\count132
-\c__fp_Bigg_middle_shift_int=\count133
-\c__fp_Bigg_trailing_shift_int=\count134
+\l_keys_choice_int=\count124
+\c__fp_leading_shift_int=\count125
+\c__fp_middle_shift_int=\count126
+\c__fp_trailing_shift_int=\count127
+\c__fp_big_leading_shift_int=\count128
+\c__fp_big_middle_shift_int=\count129
+\c__fp_big_trailing_shift_int=\count130
+\c__fp_Bigg_leading_shift_int=\count131
+\c__fp_Bigg_middle_shift_int=\count132
+\c__fp_Bigg_trailing_shift_int=\count133
 \c_empty_box=\box56
 \l_tmpa_box=\box57
 \l_tmpb_box=\box58
diff --git a/l3kernel/testfiles/m3expl004.tlg b/l3kernel/testfiles/m3expl004.tlg
index c4c55be..e2cf193 100644
--- a/l3kernel/testfiles/m3expl004.tlg
+++ b/l3kernel/testfiles/m3expl004.tlg
@@ -31,17 +31,16 @@ Don't change this file in any respect.
 \l_tmpb_muskip=\muskip43
 \g_tmpa_muskip=\muskip44
 \g_tmpb_muskip=\muskip45
-\g__keyval_level_int=\count123
-\l_keys_choice_int=\count124
-\c__fp_leading_shift_int=\count125
-\c__fp_middle_shift_int=\count126
-\c__fp_trailing_shift_int=\count127
-\c__fp_big_leading_shift_int=\count128
-\c__fp_big_middle_shift_int=\count129
-\c__fp_big_trailing_shift_int=\count130
-\c__fp_Bigg_leading_shift_int=\count131
-\c__fp_Bigg_middle_shift_int=\count132
-\c__fp_Bigg_trailing_shift_int=\count133
+\l_keys_choice_int=\count123
+\c__fp_leading_shift_int=\count124
+\c__fp_middle_shift_int=\count125
+\c__fp_trailing_shift_int=\count126
+\c__fp_big_leading_shift_int=\count127
+\c__fp_big_middle_shift_int=\count128
+\c__fp_big_trailing_shift_int=\count129
+\c__fp_Bigg_leading_shift_int=\count130
+\c__fp_Bigg_middle_shift_int=\count131
+\c__fp_Bigg_trailing_shift_int=\count132
 \c_empty_box=\box56
 \l_tmpa_box=\box57
 \l_tmpb_box=\box58
@@ -83,6 +82,6 @@ Don't change this file in any respect.
 \l__coffin_scaled_total_height_dim=\dimen161
 \l__coffin_scaled_width_dim=\dimen162
 ) (l3pdfmode.def
-\l__driver_color_stack_int=\count134
+\l__driver_color_stack_int=\count133
 \l__driver_tmp_box=\box71
 ))
diff --git a/l3kernel/testfiles/m3expl004.uptex.tlg b/l3kernel/testfiles/m3expl004.uptex.tlg
index 39185fa..cd1e5d2 100644
--- a/l3kernel/testfiles/m3expl004.uptex.tlg
+++ b/l3kernel/testfiles/m3expl004.uptex.tlg
@@ -31,17 +31,16 @@ Don't change this file in any respect.
 \l_tmpb_muskip=\muskip43
 \g_tmpa_muskip=\muskip44
 \g_tmpb_muskip=\muskip45
-\g__keyval_level_int=\count124
-\l_keys_choice_int=\count125
-\c__fp_leading_shift_int=\count126
-\c__fp_middle_shift_int=\count127
-\c__fp_trailing_shift_int=\count128
-\c__fp_big_leading_shift_int=\count129
-\c__fp_big_middle_shift_int=\count130
-\c__fp_big_trailing_shift_int=\count131
-\c__fp_Bigg_leading_shift_int=\count132
-\c__fp_Bigg_middle_shift_int=\count133
-\c__fp_Bigg_trailing_shift_int=\count134
+\l_keys_choice_int=\count124
+\c__fp_leading_shift_int=\count125
+\c__fp_middle_shift_int=\count126
+\c__fp_trailing_shift_int=\count127
+\c__fp_big_leading_shift_int=\count128
+\c__fp_big_middle_shift_int=\count129
+\c__fp_big_trailing_shift_int=\count130
+\c__fp_Bigg_leading_shift_int=\count131
+\c__fp_Bigg_middle_shift_int=\count132
+\c__fp_Bigg_trailing_shift_int=\count133
 \c_empty_box=\box56
 \l_tmpa_box=\box57
 \l_tmpb_box=\box58
diff --git a/l3kernel/testfiles/m3expl004.xetex.tlg b/l3kernel/testfiles/m3expl004.xetex.tlg
index 0d4902e..d48fc7a 100644
--- a/l3kernel/testfiles/m3expl004.xetex.tlg
+++ b/l3kernel/testfiles/m3expl004.xetex.tlg
@@ -31,17 +31,16 @@ Don't change this file in any respect.
 \l_tmpb_muskip=\muskip43
 \g_tmpa_muskip=\muskip44
 \g_tmpb_muskip=\muskip45
-\g__keyval_level_int=\count123
-\l_keys_choice_int=\count124
-\c__fp_leading_shift_int=\count125
-\c__fp_middle_shift_int=\count126
-\c__fp_trailing_shift_int=\count127
-\c__fp_big_leading_shift_int=\count128
-\c__fp_big_middle_shift_int=\count129
-\c__fp_big_trailing_shift_int=\count130
-\c__fp_Bigg_leading_shift_int=\count131
-\c__fp_Bigg_middle_shift_int=\count132
-\c__fp_Bigg_trailing_shift_int=\count133
+\l_keys_choice_int=\count123
+\c__fp_leading_shift_int=\count124
+\c__fp_middle_shift_int=\count125
+\c__fp_trailing_shift_int=\count126
+\c__fp_big_leading_shift_int=\count127
+\c__fp_big_middle_shift_int=\count128
+\c__fp_big_trailing_shift_int=\count129
+\c__fp_Bigg_leading_shift_int=\count130
+\c__fp_Bigg_middle_shift_int=\count131
+\c__fp_Bigg_trailing_shift_int=\count132
 \c_empty_box=\box56
 \l_tmpa_box=\box57
 \l_tmpb_box=\box58
diff --git a/l3kernel/testfiles/m3expl006.luatex.tlg b/l3kernel/testfiles/m3expl006.luatex.tlg
index 39607a0..49a277e 100644
--- a/l3kernel/testfiles/m3expl006.luatex.tlg
+++ b/l3kernel/testfiles/m3expl006.luatex.tlg
@@ -33,17 +33,16 @@ Author: Bruno Le Floch and Joseph Wright
 \l_tmpb_muskip=\muskip43
 \g_tmpa_muskip=\muskip44
 \g_tmpb_muskip=\muskip45
-\g__keyval_level_int=\count123
-\l_keys_choice_int=\count124
-\c__fp_leading_shift_int=\count125
-\c__fp_middle_shift_int=\count126
-\c__fp_trailing_shift_int=\count127
-\c__fp_big_leading_shift_int=\count128
-\c__fp_big_middle_shift_int=\count129
-\c__fp_big_trailing_shift_int=\count130
-\c__fp_Bigg_leading_shift_int=\count131
-\c__fp_Bigg_middle_shift_int=\count132
-\c__fp_Bigg_trailing_shift_int=\count133
+\l_keys_choice_int=\count123
+\c__fp_leading_shift_int=\count124
+\c__fp_middle_shift_int=\count125
+\c__fp_trailing_shift_int=\count126
+\c__fp_big_leading_shift_int=\count127
+\c__fp_big_middle_shift_int=\count128
+\c__fp_big_trailing_shift_int=\count129
+\c__fp_Bigg_leading_shift_int=\count130
+\c__fp_Bigg_middle_shift_int=\count131
+\c__fp_Bigg_trailing_shift_int=\count132
 \c_empty_box=\box56
 \l_tmpa_box=\box57
 \l_tmpb_box=\box58
@@ -85,6 +84,6 @@ Author: Bruno Le Floch and Joseph Wright
 \l__coffin_scaled_total_height_dim=\dimen161
 \l__coffin_scaled_width_dim=\dimen162
 ) (l3pdfmode.def
-\l__driver_color_stack_int=\count134
+\l__driver_color_stack_int=\count133
 \l__driver_tmp_box=\box71
 ))
diff --git a/l3kernel/testfiles/m3expl006.ptex.tlg b/l3kernel/testfiles/m3expl006.ptex.tlg
index b7f56dd..5337782 100644
--- a/l3kernel/testfiles/m3expl006.ptex.tlg
+++ b/l3kernel/testfiles/m3expl006.ptex.tlg
@@ -32,17 +32,16 @@ Author: Bruno Le Floch and Joseph Wright
 \l_tmpb_muskip=\muskip43
 \g_tmpa_muskip=\muskip44
 \g_tmpb_muskip=\muskip45
-\g__keyval_level_int=\count124
-\l_keys_choice_int=\count125
-\c__fp_leading_shift_int=\count126
-\c__fp_middle_shift_int=\count127
-\c__fp_trailing_shift_int=\count128
-\c__fp_big_leading_shift_int=\count129
-\c__fp_big_middle_shift_int=\count130
-\c__fp_big_trailing_shift_int=\count131
-\c__fp_Bigg_leading_shift_int=\count132
-\c__fp_Bigg_middle_shift_int=\count133
-\c__fp_Bigg_trailing_shift_int=\count134
+\l_keys_choice_int=\count124
+\c__fp_leading_shift_int=\count125
+\c__fp_middle_shift_int=\count126
+\c__fp_trailing_shift_int=\count127
+\c__fp_big_leading_shift_int=\count128
+\c__fp_big_middle_shift_int=\count129
+\c__fp_big_trailing_shift_int=\count130
+\c__fp_Bigg_leading_shift_int=\count131
+\c__fp_Bigg_middle_shift_int=\count132
+\c__fp_Bigg_trailing_shift_int=\count133
 \c_empty_box=\box56
 \l_tmpa_box=\box57
 \l_tmpb_box=\box58
diff --git a/l3kernel/testfiles/m3expl006.tlg b/l3kernel/testfiles/m3expl006.tlg
index 147f281..2c59baa 100644
--- a/l3kernel/testfiles/m3expl006.tlg
+++ b/l3kernel/testfiles/m3expl006.tlg
@@ -32,17 +32,16 @@ Author: Bruno Le Floch and Joseph Wright
 \l_tmpb_muskip=\muskip43
 \g_tmpa_muskip=\muskip44
 \g_tmpb_muskip=\muskip45
-\g__keyval_level_int=\count123
-\l_keys_choice_int=\count124
-\c__fp_leading_shift_int=\count125
-\c__fp_middle_shift_int=\count126
-\c__fp_trailing_shift_int=\count127
-\c__fp_big_leading_shift_int=\count128
-\c__fp_big_middle_shift_int=\count129
-\c__fp_big_trailing_shift_int=\count130
-\c__fp_Bigg_leading_shift_int=\count131
-\c__fp_Bigg_middle_shift_int=\count132
-\c__fp_Bigg_trailing_shift_int=\count133
+\l_keys_choice_int=\count123
+\c__fp_leading_shift_int=\count124
+\c__fp_middle_shift_int=\count125
+\c__fp_trailing_shift_int=\count126
+\c__fp_big_leading_shift_int=\count127
+\c__fp_big_middle_shift_int=\count128
+\c__fp_big_trailing_shift_int=\count129
+\c__fp_Bigg_leading_shift_int=\count130
+\c__fp_Bigg_middle_shift_int=\count131
+\c__fp_Bigg_trailing_shift_int=\count132
 \c_empty_box=\box56
 \l_tmpa_box=\box57
 \l_tmpb_box=\box58
@@ -84,6 +83,6 @@ Author: Bruno Le Floch and Joseph Wright
 \l__coffin_scaled_total_height_dim=\dimen161
 \l__coffin_scaled_width_dim=\dimen162
 ) (l3pdfmode.def
-\l__driver_color_stack_int=\count134
+\l__driver_color_stack_int=\count133
 \l__driver_tmp_box=\box71
 ))
diff --git a/l3kernel/testfiles/m3expl006.uptex.tlg b/l3kernel/testfiles/m3expl006.uptex.tlg
index b7f56dd..5337782 100644
--- a/l3kernel/testfiles/m3expl006.uptex.tlg
+++ b/l3kernel/testfiles/m3expl006.uptex.tlg
@@ -32,17 +32,16 @@ Author: Bruno Le Floch and Joseph Wright
 \l_tmpb_muskip=\muskip43
 \g_tmpa_muskip=\muskip44
 \g_tmpb_muskip=\muskip45
-\g__keyval_level_int=\count124
-\l_keys_choice_int=\count125
-\c__fp_leading_shift_int=\count126
-\c__fp_middle_shift_int=\count127
-\c__fp_trailing_shift_int=\count128
-\c__fp_big_leading_shift_int=\count129
-\c__fp_big_middle_shift_int=\count130
-\c__fp_big_trailing_shift_int=\count131
-\c__fp_Bigg_leading_shift_int=\count132
-\c__fp_Bigg_middle_shift_int=\count133
-\c__fp_Bigg_trailing_shift_int=\count134
+\l_keys_choice_int=\count124
+\c__fp_leading_shift_int=\count125
+\c__fp_middle_shift_int=\count126
+\c__fp_trailing_shift_int=\count127
+\c__fp_big_leading_shift_int=\count128
+\c__fp_big_middle_shift_int=\count129
+\c__fp_big_trailing_shift_int=\count130
+\c__fp_Bigg_leading_shift_int=\count131
+\c__fp_Bigg_middle_shift_int=\count132
+\c__fp_Bigg_trailing_shift_int=\count133
 \c_empty_box=\box56
 \l_tmpa_box=\box57
 \l_tmpb_box=\box58
diff --git a/l3kernel/testfiles/m3expl006.xetex.tlg b/l3kernel/testfiles/m3expl006.xetex.tlg
index 0ef4aeb..c84a661 100644
--- a/l3kernel/testfiles/m3expl006.xetex.tlg
+++ b/l3kernel/testfiles/m3expl006.xetex.tlg
@@ -32,17 +32,16 @@ Author: Bruno Le Floch and Joseph Wright
 \l_tmpb_muskip=\muskip43
 \g_tmpa_muskip=\muskip44
 \g_tmpb_muskip=\muskip45
-\g__keyval_level_int=\count123
-\l_keys_choice_int=\count124
-\c__fp_leading_shift_int=\count125
-\c__fp_middle_shift_int=\count126
-\c__fp_trailing_shift_int=\count127
-\c__fp_big_leading_shift_int=\count128
-\c__fp_big_middle_shift_int=\count129
-\c__fp_big_trailing_shift_int=\count130
-\c__fp_Bigg_leading_shift_int=\count131
-\c__fp_Bigg_middle_shift_int=\count132
-\c__fp_Bigg_trailing_shift_int=\count133
+\l_keys_choice_int=\count123
+\c__fp_leading_shift_int=\count124
+\c__fp_middle_shift_int=\count125
+\c__fp_trailing_shift_int=\count126
+\c__fp_big_leading_shift_int=\count127
+\c__fp_big_middle_shift_int=\count128
+\c__fp_big_trailing_shift_int=\count129
+\c__fp_Bigg_leading_shift_int=\count130
+\c__fp_Bigg_middle_shift_int=\count131
+\c__fp_Bigg_trailing_shift_int=\count132
 \c_empty_box=\box56
 \l_tmpa_box=\box57
 \l_tmpb_box=\box58
diff --git a/l3kernel/testfiles/m3int001.tlg b/l3kernel/testfiles/m3int001.tlg
index 6d93515..90ae00f 100644
--- a/l3kernel/testfiles/m3int001.tlg
+++ b/l3kernel/testfiles/m3int001.tlg
@@ -5,11 +5,11 @@ Author: Frank Mittelbach
 TEST 1: allocating new registers; no worries
 ============================================================
 Defining \l_testa_int on line ...
-\l_testa_int=\count135
+\l_testa_int=\count134
 Defining \g_testa_int on line ...
-\g_testa_int=\count136
+\g_testa_int=\count135
 Defining \g_testb_int on line ...
-\g_testb_int=\count137
+\g_testb_int=\count136
 ============================================================
 ============================================================
 TEST 2: allocating same name: errors expected
@@ -32,10 +32,10 @@ l. ...  }
 | this name has already been used elsewhere.
 | 
 | The current meaning is:
-|   \count135
+|   \count134
 |...............................................
 Defining \l_testa_int on line ...
-\l_testa_int=\count138
+\l_testa_int=\count137
 !!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!
 !
 ! LaTeX error: "kernel/command-already-defined"
@@ -54,16 +54,16 @@ l. ...  }
 | this name has already been used elsewhere.
 | 
 | The current meaning is:
-|   \count136
+|   \count135
 |...............................................
 Defining \g_testa_int on line ...
-\g_testa_int=\count139
+\g_testa_int=\count138
 ============================================================
 ============================================================
 TEST 3: allocate or clear
 ============================================================
 Defining \l_testb_int on line ...
-\l_testb_int=\count140
+\l_testb_int=\count139
 0
 0
 0
diff --git a/l3kernel/testfiles/m3int001.xetex.tlg b/l3kernel/testfiles/m3int001.xetex.tlg
index 90ae00f..1e5d5e4 100644
--- a/l3kernel/testfiles/m3int001.xetex.tlg
+++ b/l3kernel/testfiles/m3int001.xetex.tlg
@@ -5,11 +5,11 @@ Author: Frank Mittelbach
 TEST 1: allocating new registers; no worries
 ============================================================
 Defining \l_testa_int on line ...
-\l_testa_int=\count134
+\l_testa_int=\count133
 Defining \g_testa_int on line ...
-\g_testa_int=\count135
+\g_testa_int=\count134
 Defining \g_testb_int on line ...
-\g_testb_int=\count136
+\g_testb_int=\count135
 ============================================================
 ============================================================
 TEST 2: allocating same name: errors expected
@@ -32,10 +32,10 @@ l. ...  }
 | this name has already been used elsewhere.
 | 
 | The current meaning is:
-|   \count134
+|   \count133
 |...............................................
 Defining \l_testa_int on line ...
-\l_testa_int=\count137
+\l_testa_int=\count136
 !!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!
 !
 ! LaTeX error: "kernel/command-already-defined"
@@ -54,16 +54,16 @@ l. ...  }
 | this name has already been used elsewhere.
 | 
 | The current meaning is:
-|   \count135
+|   \count134
 |...............................................
 Defining \g_testa_int on line ...
-\g_testa_int=\count138
+\g_testa_int=\count137
 ============================================================
 ============================================================
 TEST 3: allocate or clear
 ============================================================
 Defining \l_testb_int on line ...
-\l_testb_int=\count139
+\l_testb_int=\count138
 0
 0
 0
diff --git a/l3kernel/testfiles/m3int002.luatex.tlg b/l3kernel/testfiles/m3int002.luatex.tlg
index 8357dc0..65385be 100644
--- a/l3kernel/testfiles/m3int002.luatex.tlg
+++ b/l3kernel/testfiles/m3int002.luatex.tlg
@@ -164,19 +164,19 @@ TEST 13: Integer division: modulo
 TEST 14: Integer creation
 ============================================================
 Defining \l_A_int on line ...
-\l_A_int=\count136
+\l_A_int=\count135
 Defining \g_A_int on line ...
-\g_A_int=\count137
+\g_A_int=\count136
+\count135
 \count136
-\count137
 Defining \l_B_int on line ...
-\l_B_int=\count138
+\l_B_int=\count137
 Defining \g_B_int on line ...
-\g_B_int=\count139
+\g_B_int=\count138
+\count137
 \count138
-\count139
+\count137
 \count138
-\count139
 ============================================================
 ============================================================
 TEST 15: Integer creation errors
@@ -199,10 +199,10 @@ l. ...}
 | name has already been used elsewhere.
 | 
 | The current meaning is:
-|   \count136
+|   \count135
 |...............................................
 Defining \l_A_int on line ...
-\l_A_int=\count140
+\l_A_int=\count139
 !!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!
 !
 ! LaTeX error: "kernel/command-already-defined"
@@ -221,10 +221,10 @@ l. ...}
 | name has already been used elsewhere.
 | 
 | The current meaning is:
-|   \count137
+|   \count136
 |...............................................
 Defining \g_A_int on line ...
-\g_A_int=\count141
+\g_A_int=\count140
 !!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!
 !
 ! LaTeX error: "kernel/command-already-defined"
@@ -243,10 +243,10 @@ l. ...}
 | name has already been used elsewhere.
 | 
 | The current meaning is:
-|   \count138
+|   \count137
 |...............................................
 Defining \l_B_int on line ...
-\l_B_int=\count142
+\l_B_int=\count141
 !!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!
 !
 ! LaTeX error: "kernel/command-already-defined"
@@ -265,10 +265,10 @@ l. ...}
 | name has already been used elsewhere.
 | 
 | The current meaning is:
-|   \count139
+|   \count138
 |...............................................
 Defining \g_B_int on line ...
-\g_B_int=\count143
+\g_B_int=\count142
 ============================================================
 ============================================================
 TEST 16: Constant integer creation
@@ -277,10 +277,10 @@ Defining \c_A_int on line ...
 \char"5
 5
 Defining \c_B_int on line ...
-\c_B_int=\count144
-\count144
+\c_B_int=\count143
+\count143
 -10
-\count144
+\count143
 -10
 ============================================================
 ============================================================
@@ -325,10 +325,10 @@ l. ...}
 | name has already been used elsewhere.
 | 
 | The current meaning is:
-|   \count144
+|   \count143
 |...............................................
 Defining \c_B_int on line ...
-\c_B_int=\count145
+\c_B_int=\count144
 ============================================================
 ============================================================
 TEST 18: Set integers equal
diff --git a/l3kernel/testfiles/m3int002.tlg b/l3kernel/testfiles/m3int002.tlg
index d40aefb..44e1c2f 100644
--- a/l3kernel/testfiles/m3int002.tlg
+++ b/l3kernel/testfiles/m3int002.tlg
@@ -164,19 +164,19 @@ TEST 13: Integer division: modulo
 TEST 14: Integer creation
 ============================================================
 Defining \l_A_int on line ...
-\l_A_int=\count136
+\l_A_int=\count135
 Defining \g_A_int on line ...
-\g_A_int=\count137
+\g_A_int=\count136
+\count135
 \count136
-\count137
 Defining \l_B_int on line ...
-\l_B_int=\count138
+\l_B_int=\count137
 Defining \g_B_int on line ...
-\g_B_int=\count139
+\g_B_int=\count138
+\count137
 \count138
-\count139
+\count137
 \count138
-\count139
 ============================================================
 ============================================================
 TEST 15: Integer creation errors
@@ -199,10 +199,10 @@ l. ...}
 | name has already been used elsewhere.
 | 
 | The current meaning is:
-|   \count136
+|   \count135
 |...............................................
 Defining \l_A_int on line ...
-\l_A_int=\count140
+\l_A_int=\count139
 !!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!
 !
 ! LaTeX error: "kernel/command-already-defined"
@@ -221,10 +221,10 @@ l. ...}
 | name has already been used elsewhere.
 | 
 | The current meaning is:
-|   \count137
+|   \count136
 |...............................................
 Defining \g_A_int on line ...
-\g_A_int=\count141
+\g_A_int=\count140
 !!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!
 !
 ! LaTeX error: "kernel/command-already-defined"
@@ -243,10 +243,10 @@ l. ...}
 | name has already been used elsewhere.
 | 
 | The current meaning is:
-|   \count138
+|   \count137
 |...............................................
 Defining \l_B_int on line ...
-\l_B_int=\count142
+\l_B_int=\count141
 !!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!
 !
 ! LaTeX error: "kernel/command-already-defined"
@@ -265,10 +265,10 @@ l. ...}
 | name has already been used elsewhere.
 | 
 | The current meaning is:
-|   \count139
+|   \count138
 |...............................................
 Defining \g_B_int on line ...
-\g_B_int=\count143
+\g_B_int=\count142
 ============================================================
 ============================================================
 TEST 16: Constant integer creation
@@ -277,10 +277,10 @@ Defining \c_A_int on line ...
 \mathchar"5
 5
 Defining \c_B_int on line ...
-\c_B_int=\count144
-\count144
+\c_B_int=\count143
+\count143
 -10
-\count144
+\count143
 -10
 ============================================================
 ============================================================
@@ -325,10 +325,10 @@ l. ...}
 | name has already been used elsewhere.
 | 
 | The current meaning is:
-|   \count144
+|   \count143
 |...............................................
 Defining \c_B_int on line ...
-\c_B_int=\count145
+\c_B_int=\count144
 ============================================================
 ============================================================
 TEST 18: Set integers equal
diff --git a/l3kernel/testfiles/m3int002.uptex.tlg b/l3kernel/testfiles/m3int002.uptex.tlg
index 8190425..3bf0ed0 100644
--- a/l3kernel/testfiles/m3int002.uptex.tlg
+++ b/l3kernel/testfiles/m3int002.uptex.tlg
@@ -164,19 +164,19 @@ TEST 13: Integer division: modulo
 TEST 14: Integer creation
 ============================================================
 Defining \l_A_int on line ...
-\l_A_int=\count136
+\l_A_int=\count135
 Defining \g_A_int on line ...
-\g_A_int=\count137
+\g_A_int=\count136
+\count135
 \count136
-\count137
 Defining \l_B_int on line ...
-\l_B_int=\count138
+\l_B_int=\count137
 Defining \g_B_int on line ...
-\g_B_int=\count139
+\g_B_int=\count138
+\count137
 \count138
-\count139
+\count137
 \count138
-\count139
 ============================================================
 ============================================================
 TEST 15: Integer creation errors
@@ -199,10 +199,10 @@ l. ...}
 | name has already been used elsewhere.
 | 
 | The current meaning is:
-|   \count136
+|   \count135
 |...............................................
 Defining \l_A_int on line ...
-\l_A_int=\count140
+\l_A_int=\count139
 !!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!
 !
 ! LaTeX error: "kernel/command-already-defined"
@@ -221,10 +221,10 @@ l. ...}
 | name has already been used elsewhere.
 | 
 | The current meaning is:
-|   \count137
+|   \count136
 |...............................................
 Defining \g_A_int on line ...
-\g_A_int=\count141
+\g_A_int=\count140
 !!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!
 !
 ! LaTeX error: "kernel/command-already-defined"
@@ -243,10 +243,10 @@ l. ...}
 | name has already been used elsewhere.
 | 
 | The current meaning is:
-|   \count138
+|   \count137
 |...............................................
 Defining \l_B_int on line ...
-\l_B_int=\count142
+\l_B_int=\count141
 !!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!
 !
 ! LaTeX error: "kernel/command-already-defined"
@@ -265,10 +265,10 @@ l. ...}
 | name has already been used elsewhere.
 | 
 | The current meaning is:
-|   \count139
+|   \count138
 |...............................................
 Defining \g_B_int on line ...
-\g_B_int=\count143
+\g_B_int=\count142
 ============================================================
 ============================================================
 TEST 16: Constant integer creation
@@ -277,10 +277,10 @@ Defining \c_A_int on line ...
 \kchar"5
 5
 Defining \c_B_int on line ...
-\c_B_int=\count144
-\count144
+\c_B_int=\count143
+\count143
 -10
-\count144
+\count143
 -10
 ============================================================
 ============================================================
@@ -325,10 +325,10 @@ l. ...}
 | name has already been used elsewhere.
 | 
 | The current meaning is:
-|   \count144
+|   \count143
 |...............................................
 Defining \c_B_int on line ...
-\c_B_int=\count145
+\c_B_int=\count144
 ============================================================
 ============================================================
 TEST 18: Set integers equal
diff --git a/l3kernel/testfiles/m3int002.xetex.tlg b/l3kernel/testfiles/m3int002.xetex.tlg
index f1b567d..5b09843 100644
--- a/l3kernel/testfiles/m3int002.xetex.tlg
+++ b/l3kernel/testfiles/m3int002.xetex.tlg
@@ -164,19 +164,19 @@ TEST 13: Integer division: modulo
 TEST 14: Integer creation
 ============================================================
 Defining \l_A_int on line ...
-\l_A_int=\count135
+\l_A_int=\count134
 Defining \g_A_int on line ...
-\g_A_int=\count136
+\g_A_int=\count135
+\count134
 \count135
-\count136
 Defining \l_B_int on line ...
-\l_B_int=\count137
+\l_B_int=\count136
 Defining \g_B_int on line ...
-\g_B_int=\count138
+\g_B_int=\count137
+\count136
 \count137
-\count138
+\count136
 \count137
-\count138
 ============================================================
 ============================================================
 TEST 15: Integer creation errors
@@ -199,10 +199,10 @@ l. ...}
 | name has already been used elsewhere.
 | 
 | The current meaning is:
-|   \count135
+|   \count134
 |...............................................
 Defining \l_A_int on line ...
-\l_A_int=\count139
+\l_A_int=\count138
 !!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!
 !
 ! LaTeX error: "kernel/command-already-defined"
@@ -221,10 +221,10 @@ l. ...}
 | name has already been used elsewhere.
 | 
 | The current meaning is:
-|   \count136
+|   \count135
 |...............................................
 Defining \g_A_int on line ...
-\g_A_int=\count140
+\g_A_int=\count139
 !!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!
 !
 ! LaTeX error: "kernel/command-already-defined"
@@ -243,10 +243,10 @@ l. ...}
 | name has already been used elsewhere.
 | 
 | The current meaning is:
-|   \count137
+|   \count136
 |...............................................
 Defining \l_B_int on line ...
-\l_B_int=\count141
+\l_B_int=\count140
 !!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!
 !
 ! LaTeX error: "kernel/command-already-defined"
@@ -265,10 +265,10 @@ l. ...}
 | name has already been used elsewhere.
 | 
 | The current meaning is:
-|   \count138
+|   \count137
 |...............................................
 Defining \g_B_int on line ...
-\g_B_int=\count142
+\g_B_int=\count141
 ============================================================
 ============================================================
 TEST 16: Constant integer creation
@@ -277,10 +277,10 @@ Defining \c_A_int on line ...
 \char"5
 5
 Defining \c_B_int on line ...
-\c_B_int=\count143
-\count143
+\c_B_int=\count142
+\count142
 -10
-\count143
+\count142
 -10
 ============================================================
 ============================================================
@@ -325,10 +325,10 @@ l. ...}
 | name has already been used elsewhere.
 | 
 | The current meaning is:
-|   \count143
+|   \count142
 |...............................................
 Defining \c_B_int on line ...
-\c_B_int=\count144
+\c_B_int=\count143
 ============================================================
 ============================================================
 TEST 18: Set integers equal
diff --git a/l3kernel/testfiles/m3keys001.lvt b/l3kernel/testfiles/m3keys001.lvt
index 70a0022..d258e7e 100644
--- a/l3kernel/testfiles/m3keys001.lvt
+++ b/l3kernel/testfiles/m3keys001.lvt
@@ -285,16 +285,4 @@
       }
   }
 
-%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%
-
-\TEST { Empty~key~name }
-  {
-    \keys_define:nn { module }
-      {
-        .code:n = { \TYPE { "#1" } }
-      }
-    \keys_set:nn { module }
-      { = foo , = }
-  }
-
 \END
diff --git a/l3kernel/testfiles/m3keys001.tlg b/l3kernel/testfiles/m3keys001.tlg
index b53f291..e4aad1c 100644
--- a/l3kernel/testfiles/m3keys001.tlg
+++ b/l3kernel/testfiles/m3keys001.tlg
@@ -237,10 +237,3 @@ l. ...  }
 | LaTeX did not find a '.' to indicate the start of a property.
 |...............................................
 ============================================================
-============================================================
-TEST 11: Empty key name
-============================================================
-Defining key module/ on line ...
-"foo"
-""
-============================================================
diff --git a/l3kernel/testfiles/m3keyval001.lvt b/l3kernel/testfiles/m3keyval001.lvt
index 553424e..df91d65 100644
--- a/l3kernel/testfiles/m3keyval001.lvt
+++ b/l3kernel/testfiles/m3keyval001.lvt
@@ -60,6 +60,8 @@
   \SEPARATOR
   \keyval_parse:NNn\KV_key_no_value_elt:n  \KV_key_value_elt:nn { a = b c = d }
   \SEPARATOR
+  \keyval_parse:NNn\KV_key_no_value_elt:n  \KV_key_value_elt:nn { = }
+  \SEPARATOR
 }
 
 
diff --git a/l3kernel/testfiles/m3keyval001.tlg b/l3kernel/testfiles/m3keyval001.tlg
index e5e0ab6..0dcf3e8 100644
--- a/l3kernel/testfiles/m3keyval001.tlg
+++ b/l3kernel/testfiles/m3keyval001.tlg
@@ -52,7 +52,23 @@ KEY NO VAL: "a"
 !
 ! LaTeX error: "kernel/misplaced-equals-sign"
 ! 
-! Misplaced equals sign in key-value input 63
+! Misplaced equals sign in key-value input 65
+! 
+! See the LaTeX3 documentation for further information.
+! 
+! For immediate help type H <return>.
+!...............................................  
+l. ...}
+|'''''''''''''''''''''''''''''''''''''''''''''''
+| LaTeX is attempting to parse some key-value input but found two equals signs
+| not separated by a comma.
+|...............................................
+============================================================
+!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!
+!
+! LaTeX error: "kernel/misplaced-equals-sign"
+! 
+! Misplaced equals sign in key-value input 65
 ! 
 ! See the LaTeX3 documentation for further information.
 ! 

-- 
To stop receiving notification emails like this one, please contact
the administrator of this repository.


More information about the latex3-commits mailing list