texlive[59345] Master/texmf-dist: l3kernel (25may21)

commits+karl at tug.org commits+karl at tug.org
Tue May 25 22:48:22 CEST 2021


Revision: 59345
          http://tug.org/svn/texlive?view=revision&revision=59345
Author:   karl
Date:     2021-05-25 22:48:22 +0200 (Tue, 25 May 2021)
Log Message:
-----------
l3kernel (25may21)

Modified Paths:
--------------
    trunk/Master/texmf-dist/doc/latex/l3kernel/CHANGELOG.md
    trunk/Master/texmf-dist/doc/latex/l3kernel/README.md
    trunk/Master/texmf-dist/doc/latex/l3kernel/expl3.pdf
    trunk/Master/texmf-dist/doc/latex/l3kernel/interface3.pdf
    trunk/Master/texmf-dist/doc/latex/l3kernel/interface3.tex
    trunk/Master/texmf-dist/doc/latex/l3kernel/l3docstrip.pdf
    trunk/Master/texmf-dist/doc/latex/l3kernel/l3news.pdf
    trunk/Master/texmf-dist/doc/latex/l3kernel/l3news01.pdf
    trunk/Master/texmf-dist/doc/latex/l3kernel/l3news02.pdf
    trunk/Master/texmf-dist/doc/latex/l3kernel/l3news03.pdf
    trunk/Master/texmf-dist/doc/latex/l3kernel/l3news04.pdf
    trunk/Master/texmf-dist/doc/latex/l3kernel/l3news05.pdf
    trunk/Master/texmf-dist/doc/latex/l3kernel/l3news06.pdf
    trunk/Master/texmf-dist/doc/latex/l3kernel/l3news07.pdf
    trunk/Master/texmf-dist/doc/latex/l3kernel/l3news08.pdf
    trunk/Master/texmf-dist/doc/latex/l3kernel/l3news09.pdf
    trunk/Master/texmf-dist/doc/latex/l3kernel/l3news10.pdf
    trunk/Master/texmf-dist/doc/latex/l3kernel/l3news11.pdf
    trunk/Master/texmf-dist/doc/latex/l3kernel/l3news12.pdf
    trunk/Master/texmf-dist/doc/latex/l3kernel/l3prefixes.csv
    trunk/Master/texmf-dist/doc/latex/l3kernel/l3prefixes.pdf
    trunk/Master/texmf-dist/doc/latex/l3kernel/l3styleguide.pdf
    trunk/Master/texmf-dist/doc/latex/l3kernel/l3styleguide.tex
    trunk/Master/texmf-dist/doc/latex/l3kernel/l3syntax-changes.pdf
    trunk/Master/texmf-dist/doc/latex/l3kernel/l3syntax-changes.tex
    trunk/Master/texmf-dist/doc/latex/l3kernel/l3term-glossary.pdf
    trunk/Master/texmf-dist/doc/latex/l3kernel/l3term-glossary.tex
    trunk/Master/texmf-dist/doc/latex/l3kernel/source3.pdf
    trunk/Master/texmf-dist/doc/latex/l3kernel/source3.tex
    trunk/Master/texmf-dist/source/latex/l3kernel/expl3.dtx
    trunk/Master/texmf-dist/source/latex/l3kernel/l3basics.dtx
    trunk/Master/texmf-dist/source/latex/l3kernel/l3bootstrap.dtx
    trunk/Master/texmf-dist/source/latex/l3kernel/l3box.dtx
    trunk/Master/texmf-dist/source/latex/l3kernel/l3candidates.dtx
    trunk/Master/texmf-dist/source/latex/l3kernel/l3cctab.dtx
    trunk/Master/texmf-dist/source/latex/l3kernel/l3clist.dtx
    trunk/Master/texmf-dist/source/latex/l3kernel/l3coffins.dtx
    trunk/Master/texmf-dist/source/latex/l3kernel/l3color.dtx
    trunk/Master/texmf-dist/source/latex/l3kernel/l3debug.dtx
    trunk/Master/texmf-dist/source/latex/l3kernel/l3deprecation.dtx
    trunk/Master/texmf-dist/source/latex/l3kernel/l3doc.dtx
    trunk/Master/texmf-dist/source/latex/l3kernel/l3docstrip.dtx
    trunk/Master/texmf-dist/source/latex/l3kernel/l3expan.dtx
    trunk/Master/texmf-dist/source/latex/l3kernel/l3file.dtx
    trunk/Master/texmf-dist/source/latex/l3kernel/l3flag.dtx
    trunk/Master/texmf-dist/source/latex/l3kernel/l3fp-assign.dtx
    trunk/Master/texmf-dist/source/latex/l3kernel/l3fp-aux.dtx
    trunk/Master/texmf-dist/source/latex/l3kernel/l3fp-basics.dtx
    trunk/Master/texmf-dist/source/latex/l3kernel/l3fp-convert.dtx
    trunk/Master/texmf-dist/source/latex/l3kernel/l3fp-expo.dtx
    trunk/Master/texmf-dist/source/latex/l3kernel/l3fp-extended.dtx
    trunk/Master/texmf-dist/source/latex/l3kernel/l3fp-logic.dtx
    trunk/Master/texmf-dist/source/latex/l3kernel/l3fp-parse.dtx
    trunk/Master/texmf-dist/source/latex/l3kernel/l3fp-random.dtx
    trunk/Master/texmf-dist/source/latex/l3kernel/l3fp-round.dtx
    trunk/Master/texmf-dist/source/latex/l3kernel/l3fp-traps.dtx
    trunk/Master/texmf-dist/source/latex/l3kernel/l3fp-trig.dtx
    trunk/Master/texmf-dist/source/latex/l3kernel/l3fp.dtx
    trunk/Master/texmf-dist/source/latex/l3kernel/l3fparray.dtx
    trunk/Master/texmf-dist/source/latex/l3kernel/l3int.dtx
    trunk/Master/texmf-dist/source/latex/l3kernel/l3intarray.dtx
    trunk/Master/texmf-dist/source/latex/l3kernel/l3kernel-functions.dtx
    trunk/Master/texmf-dist/source/latex/l3kernel/l3keys.dtx
    trunk/Master/texmf-dist/source/latex/l3kernel/l3legacy.dtx
    trunk/Master/texmf-dist/source/latex/l3kernel/l3luatex.dtx
    trunk/Master/texmf-dist/source/latex/l3kernel/l3msg.dtx
    trunk/Master/texmf-dist/source/latex/l3kernel/l3names.dtx
    trunk/Master/texmf-dist/source/latex/l3kernel/l3pdf.dtx
    trunk/Master/texmf-dist/source/latex/l3kernel/l3prg.dtx
    trunk/Master/texmf-dist/source/latex/l3kernel/l3prop.dtx
    trunk/Master/texmf-dist/source/latex/l3kernel/l3quark.dtx
    trunk/Master/texmf-dist/source/latex/l3kernel/l3regex.dtx
    trunk/Master/texmf-dist/source/latex/l3kernel/l3seq.dtx
    trunk/Master/texmf-dist/source/latex/l3kernel/l3skip.dtx
    trunk/Master/texmf-dist/source/latex/l3kernel/l3sort.dtx
    trunk/Master/texmf-dist/source/latex/l3kernel/l3str-convert.dtx
    trunk/Master/texmf-dist/source/latex/l3kernel/l3str.dtx
    trunk/Master/texmf-dist/source/latex/l3kernel/l3sys.dtx
    trunk/Master/texmf-dist/source/latex/l3kernel/l3text-case.dtx
    trunk/Master/texmf-dist/source/latex/l3kernel/l3text-purify.dtx
    trunk/Master/texmf-dist/source/latex/l3kernel/l3text.dtx
    trunk/Master/texmf-dist/source/latex/l3kernel/l3tl-analysis.dtx
    trunk/Master/texmf-dist/source/latex/l3kernel/l3tl.dtx
    trunk/Master/texmf-dist/source/latex/l3kernel/l3token.dtx
    trunk/Master/texmf-dist/source/latex/l3kernel/l3unicode.dtx
    trunk/Master/texmf-dist/tex/latex/l3kernel/expl3-code.tex
    trunk/Master/texmf-dist/tex/latex/l3kernel/expl3-generic.tex
    trunk/Master/texmf-dist/tex/latex/l3kernel/expl3.ltx
    trunk/Master/texmf-dist/tex/latex/l3kernel/expl3.lua
    trunk/Master/texmf-dist/tex/latex/l3kernel/expl3.sty
    trunk/Master/texmf-dist/tex/latex/l3kernel/l3debug.def

Modified: trunk/Master/texmf-dist/doc/latex/l3kernel/CHANGELOG.md
===================================================================
--- trunk/Master/texmf-dist/doc/latex/l3kernel/CHANGELOG.md	2021-05-25 20:47:33 UTC (rev 59344)
+++ trunk/Master/texmf-dist/doc/latex/l3kernel/CHANGELOG.md	2021-05-25 20:48:22 UTC (rev 59345)
@@ -7,6 +7,29 @@
 
 ## [Unreleased]
 
+## [2021-05-25]
+
+### Added
+- `\msg_note:nnnnnn` (issue #911)
+- `\str_compare:nNnTF` (issue #927)
+- `\sys_timer:`
+- `\prop_concat:NNN`, `\prop_put_from_keyval:Nn` (issue #924)
+- Functions to show and log various datatypes (issue #241):
+  `\coffin_show:Nnn`, `\coffin_show:N`, `\coffin_log:Nnn`, `\coffin_log:N`,
+  `\color_log:n`, `\group_show_list:`, `\group_log_list:`,
+  `\ior_show:N`, `\ior_log:N`, `\iow_show:N`, `\iow_log:N`,
+  `\tl_log_analysis:N`, `\tl_log_analysis:n`
+- `\legacy_if_set_true:n`, `\legacy_if_set_false:n`, `\legacy_if_set:nn`
+
+### Fixed
+- Checking brace balance in all regex functions (issue #377)
+- Removing duplicates in clists when items contain commas (issue #917)
+
+### Changed
+- Slight speed up in some elementary int/dim/skip/muskip operations and
+  in setting tl or clist variables equal.
+- Speed up mapping functions in l3clist, l3prop, l3seq, l3tl
+
 ## [2021-05-11]
 
 ### Added
@@ -19,7 +42,7 @@
 - Control sequences and category codes in regex replacements (issue #909)
 
 ### Changed
-- Speed up \group_align_safe_begin: (pull #906)
+- Speed up `\group_align_safe_begin:` (pull #906)
 
 ## [2021-05-07]
 
@@ -897,7 +920,8 @@
 - Step functions have been added for dim variables,
   e.g. `\dim_step_inline:nnnn`
 
-[Unreleased]: https://github.com/latex3/latex3/compare/2021-05-11...HEAD
+[Unreleased]: https://github.com/latex3/latex3/compare/2021-05-25...HEAD
+[2021-05-25]: https://github.com/latex3/latex3/compare/2021-05-11...2021-05-25
 [2021-05-11]: https://github.com/latex3/latex3/compare/2021-05-07...2021-05-11
 [2021-05-07]: https://github.com/latex3/latex3/compare/2021-02-18...2021-05-07
 [2021-02-18]: https://github.com/latex3/latex3/compare/2021-02-06...2021-02-18

Modified: trunk/Master/texmf-dist/doc/latex/l3kernel/README.md
===================================================================
--- trunk/Master/texmf-dist/doc/latex/l3kernel/README.md	2021-05-25 20:47:33 UTC (rev 59344)
+++ trunk/Master/texmf-dist/doc/latex/l3kernel/README.md	2021-05-25 20:48:22 UTC (rev 59345)
@@ -1,7 +1,7 @@
 LaTeX3 Programming Conventions
 ==============================
 
-Release 2021-05-11
+Release 2021-05-25
 
 Overview
 --------

Modified: trunk/Master/texmf-dist/doc/latex/l3kernel/expl3.pdf
===================================================================
(Binary files differ)

Modified: trunk/Master/texmf-dist/doc/latex/l3kernel/interface3.pdf
===================================================================
(Binary files differ)

Modified: trunk/Master/texmf-dist/doc/latex/l3kernel/interface3.tex
===================================================================
--- trunk/Master/texmf-dist/doc/latex/l3kernel/interface3.tex	2021-05-25 20:47:33 UTC (rev 59344)
+++ trunk/Master/texmf-dist/doc/latex/l3kernel/interface3.tex	2021-05-25 20:48:22 UTC (rev 59345)
@@ -54,7 +54,7 @@
          {latex-team at latex-project.org}%
    }%
 }
-\date{Released 2021-05-11}
+\date{Released 2021-05-25}
 
 \pagenumbering{roman}
 \maketitle

Modified: trunk/Master/texmf-dist/doc/latex/l3kernel/l3docstrip.pdf
===================================================================
(Binary files differ)

Modified: trunk/Master/texmf-dist/doc/latex/l3kernel/l3news.pdf
===================================================================
(Binary files differ)

Modified: trunk/Master/texmf-dist/doc/latex/l3kernel/l3news01.pdf
===================================================================
(Binary files differ)

Modified: trunk/Master/texmf-dist/doc/latex/l3kernel/l3news02.pdf
===================================================================
(Binary files differ)

Modified: trunk/Master/texmf-dist/doc/latex/l3kernel/l3news03.pdf
===================================================================
(Binary files differ)

Modified: trunk/Master/texmf-dist/doc/latex/l3kernel/l3news04.pdf
===================================================================
(Binary files differ)

Modified: trunk/Master/texmf-dist/doc/latex/l3kernel/l3news05.pdf
===================================================================
(Binary files differ)

Modified: trunk/Master/texmf-dist/doc/latex/l3kernel/l3news06.pdf
===================================================================
(Binary files differ)

Modified: trunk/Master/texmf-dist/doc/latex/l3kernel/l3news07.pdf
===================================================================
(Binary files differ)

Modified: trunk/Master/texmf-dist/doc/latex/l3kernel/l3news08.pdf
===================================================================
(Binary files differ)

Modified: trunk/Master/texmf-dist/doc/latex/l3kernel/l3news09.pdf
===================================================================
(Binary files differ)

Modified: trunk/Master/texmf-dist/doc/latex/l3kernel/l3news10.pdf
===================================================================
(Binary files differ)

Modified: trunk/Master/texmf-dist/doc/latex/l3kernel/l3news11.pdf
===================================================================
(Binary files differ)

Modified: trunk/Master/texmf-dist/doc/latex/l3kernel/l3news12.pdf
===================================================================
(Binary files differ)

Modified: trunk/Master/texmf-dist/doc/latex/l3kernel/l3prefixes.csv
===================================================================
--- trunk/Master/texmf-dist/doc/latex/l3kernel/l3prefixes.csv	2021-05-25 20:47:33 UTC (rev 59344)
+++ trunk/Master/texmf-dist/doc/latex/l3kernel/l3prefixes.csv	2021-05-25 20:48:22 UTC (rev 59345)
@@ -163,6 +163,7 @@
 peek,l3kernel,The LaTeX Project,https://www.latex-project.org/latex3.html,https://github.com/latex3/latex3.git,https://github.com/latex3/latex3/issues,2012-09-27,2012-09-27,
 percent,l3kernel,The LaTeX Project,https://www.latex-project.org/latex3.html,https://github.com/latex3/latex3.git,https://github.com/latex3/latex3/issues,2018-05-12,2018-05-12,
 pgf,pgf,The PGF/TikZ Team,https://pgf-tikz.github.io,https://github.com/pgf-tikz/pgf,https://github.com/pgf-tikz/pgf/issues,2020-07-03,2020-07-03,
+pgfmxfp,pgfmath-xfp,Jonathan P. Spratte,https://github.com/Skillmon/ltx_pgfmath-xfp,https://github.com/Skillmon/ltx_pgfmath-xfp,https://github.com/Skillmon/ltx_pgfmath-xfp/issues,2021-05-20,2021-05-20,
 pi,l3kernel,The LaTeX Project,https://www.latex-project.org/latex3.html,https://github.com/latex3/latex3.git,https://github.com/latex3/latex3/issues,2018-05-12,2018-05-12,
 pkgploader,pkgploader,Michiel Helvensteijn,,,,2014-02-05,2014-02-05,
 platex,platex,Japanese TeX Development Community,https://github.com/texjporg/platex,https://github.com/texjporg/platex.git,https://github.com/texjporg/platex/issues,2020-09-30,2020-09-30,

Modified: trunk/Master/texmf-dist/doc/latex/l3kernel/l3prefixes.pdf
===================================================================
(Binary files differ)

Modified: trunk/Master/texmf-dist/doc/latex/l3kernel/l3styleguide.pdf
===================================================================
(Binary files differ)

Modified: trunk/Master/texmf-dist/doc/latex/l3kernel/l3styleguide.tex
===================================================================
--- trunk/Master/texmf-dist/doc/latex/l3kernel/l3styleguide.tex	2021-05-25 20:47:33 UTC (rev 59344)
+++ trunk/Master/texmf-dist/doc/latex/l3kernel/l3styleguide.tex	2021-05-25 20:48:22 UTC (rev 59345)
@@ -32,7 +32,7 @@
         {latex-team at latex-project.org}%
     }%
 }
-\date{Released 2021-05-11}
+\date{Released 2021-05-25}
 
 \begin{document}
 

Modified: trunk/Master/texmf-dist/doc/latex/l3kernel/l3syntax-changes.pdf
===================================================================
(Binary files differ)

Modified: trunk/Master/texmf-dist/doc/latex/l3kernel/l3syntax-changes.tex
===================================================================
--- trunk/Master/texmf-dist/doc/latex/l3kernel/l3syntax-changes.tex	2021-05-25 20:47:33 UTC (rev 59344)
+++ trunk/Master/texmf-dist/doc/latex/l3kernel/l3syntax-changes.tex	2021-05-25 20:48:22 UTC (rev 59345)
@@ -32,7 +32,7 @@
         {latex-team at latex-project.org}%
     }%
 }
-\date{Released 2021-05-11}
+\date{Released 2021-05-25}
 
 \newcommand{\TF}{\textit{(TF)}}
 

Modified: trunk/Master/texmf-dist/doc/latex/l3kernel/l3term-glossary.pdf
===================================================================
(Binary files differ)

Modified: trunk/Master/texmf-dist/doc/latex/l3kernel/l3term-glossary.tex
===================================================================
--- trunk/Master/texmf-dist/doc/latex/l3kernel/l3term-glossary.tex	2021-05-25 20:47:33 UTC (rev 59344)
+++ trunk/Master/texmf-dist/doc/latex/l3kernel/l3term-glossary.tex	2021-05-25 20:48:22 UTC (rev 59345)
@@ -32,7 +32,7 @@
         {latex-team at latex-project.org}%
     }%
 }
-\date{Released 2021-05-11}
+\date{Released 2021-05-25}
 
 \newcommand{\TF}{\textit{(TF)}}
 

Modified: trunk/Master/texmf-dist/doc/latex/l3kernel/source3.pdf
===================================================================
(Binary files differ)

Modified: trunk/Master/texmf-dist/doc/latex/l3kernel/source3.tex
===================================================================
--- trunk/Master/texmf-dist/doc/latex/l3kernel/source3.tex	2021-05-25 20:47:33 UTC (rev 59344)
+++ trunk/Master/texmf-dist/doc/latex/l3kernel/source3.tex	2021-05-25 20:48:22 UTC (rev 59345)
@@ -53,7 +53,7 @@
          {latex-team at latex-project.org}%
    }%
 }
-\date{Released 2021-05-11}
+\date{Released 2021-05-25}
 
 \pagenumbering{roman}
 \maketitle

Modified: trunk/Master/texmf-dist/source/latex/l3kernel/expl3.dtx
===================================================================
--- trunk/Master/texmf-dist/source/latex/l3kernel/expl3.dtx	2021-05-25 20:47:33 UTC (rev 59344)
+++ trunk/Master/texmf-dist/source/latex/l3kernel/expl3.dtx	2021-05-25 20:48:22 UTC (rev 59345)
@@ -24,7 +24,7 @@
 %
 %<*driver|generic|package|2ekernel>
 %</driver|generic|package|2ekernel>
-\def\ExplFileDate{2021-05-11}%
+\def\ExplFileDate{2021-05-25}%
 %<*driver>
 \documentclass[full]{l3doc}
 \usepackage{graphicx}
@@ -51,7 +51,7 @@
 %    }^^A
 % }
 %
-% \date{Released 2021-05-11}
+% \date{Released 2021-05-25}
 %
 % \maketitle
 %

Modified: trunk/Master/texmf-dist/source/latex/l3kernel/l3basics.dtx
===================================================================
--- trunk/Master/texmf-dist/source/latex/l3kernel/l3basics.dtx	2021-05-25 20:47:33 UTC (rev 59344)
+++ trunk/Master/texmf-dist/source/latex/l3kernel/l3basics.dtx	2021-05-25 20:48:22 UTC (rev 59345)
@@ -43,7 +43,7 @@
 %    }^^A
 % }
 %
-% \date{Released 2021-05-11}
+% \date{Released 2021-05-25}
 %
 % \maketitle
 %
@@ -108,6 +108,18 @@
 %   |}| if standard category codes apply.
 % \end{function}
 %
+% \begin{function}[added = 2021-05-11]{\group_show_list:, \group_log_list:}
+%   \begin{syntax}
+%     \cs{group_show_list:}
+%     \cs{group_log_list:}
+%   \end{syntax}
+%   Display (to the terminal or log file) a list of the groups that are
+%   currently opened.  This is intended for tracking down problems.
+%   \begin{texnote}
+%     This is a wrapper around the \tn{showgroups} primitive.
+%   \end{texnote}
+% \end{function}
+%
 % \section{Control sequences and functions}
 %
 % As \TeX{} is a macro language, creating new functions means
@@ -2941,11 +2953,12 @@
   {
     \bool_if:NTF #3
       {
-        \str_if_eq:eeF { }
+        \cs_set_nopar:Npx \@@_tmp:w
           { \tl_map_function:nN {#2} \@@_generate_from_signature:n }
+        \tl_if_empty:oF \@@_tmp:w
           {
-            \__kernel_msg_error:nnx { kernel } { non-base-function }
-              { \token_to_str:N #5 }
+            \__kernel_msg_error:nnxxx { kernel } { non-base-function }
+              { \token_to_str:N #5 } {#2} { \@@_tmp:w }
           }
         \cs_generate_from_arg_count:NNnn
           #5 #4 { \tl_count:n {#2} } {#6}
@@ -3152,6 +3165,35 @@
 %    \end{macrocode}
 % \end{macro}
 %
+% \begin{macro}{\group_show_list:, \group_log_list:, \@@_group_show:NN}
+%   Wrapper around \tn{showgroups}.  Getting \TeX{} to write to the log
+%   without interruption the run is done by altering the interaction
+%   mode.
+%    \begin{macrocode}
+\cs_new_protected:Npn \group_show_list:
+  { \@@_group_show:NN \use_none:n 1 }
+\cs_new_protected:Npn \group_log_list:
+  { \@@_group_show:NN \int_zero:N 0 }
+\cs_new_protected:Npn \@@_group_show:NN #1#2
+  {
+    \use:x
+      {
+        #1 \tex_interactionmode:D
+        \int_set:Nn \tex_tracingonline:D  {#2}
+        \int_set:Nn \tex_errorcontextlines:D { -1 }
+        \exp_not:N \exp_after:wN \scan_stop:
+        \tex_showgroups:D
+        \int_set:Nn \tex_interactionmode:D
+          { \int_use:N \tex_interactionmode:D }
+        \int_set:Nn \tex_tracingonline:D
+          { \int_use:N \tex_tracingonline:D }
+        \int_set:Nn \tex_errorcontextlines:D
+          { \int_use:N \tex_errorcontextlines:D }
+      }
+  }
+%    \end{macrocode}
+% \end{macro}
+%
 % \subsection{Decomposing a macro definition}
 %
 % \begin{macro}{\cs_prefix_spec:N}

Modified: trunk/Master/texmf-dist/source/latex/l3kernel/l3bootstrap.dtx
===================================================================
--- trunk/Master/texmf-dist/source/latex/l3kernel/l3bootstrap.dtx	2021-05-25 20:47:33 UTC (rev 59344)
+++ trunk/Master/texmf-dist/source/latex/l3kernel/l3bootstrap.dtx	2021-05-25 20:48:22 UTC (rev 59345)
@@ -43,7 +43,7 @@
 %    }^^A
 % }
 %
-% \date{Released 2021-05-11}
+% \date{Released 2021-05-25}
 %
 % \maketitle
 %

Modified: trunk/Master/texmf-dist/source/latex/l3kernel/l3box.dtx
===================================================================
--- trunk/Master/texmf-dist/source/latex/l3kernel/l3box.dtx	2021-05-25 20:47:33 UTC (rev 59344)
+++ trunk/Master/texmf-dist/source/latex/l3kernel/l3box.dtx	2021-05-25 20:48:22 UTC (rev 59345)
@@ -43,16 +43,38 @@
 %    }^^A
 % }
 %
-% \date{Released 2021-05-11}
+% \date{Released 2021-05-25}
 %
 % \maketitle
 %
 % \begin{documentation}
 %
+% Box variables contain typeset material that can be inserted on the
+% page or in other boxes.  Their contents cannot be converted back to
+% lists of tokens.
 % There are three kinds of box operations: horizontal mode denoted
 % with prefix |\hbox_|, vertical mode with prefix |\vbox_|, and the
 % generic operations working in both modes with prefix |\box_|.
+% For instance, a new box variable containing the words \enquote{Hello,
+% world!} (in a horizontal box) can be obtained by the following code.
+% \begin{verbatim}
+% \box_new:N \l_hello_box
+% \hbox_set:Nn \l_hello_box { Hello, ~ world! }
+% \end{verbatim}
+% The argument is typeset inside a \TeX{} group so that any variables
+% assigned during the construction of this box restores its value
+% afterwards.
 %
+% Box variables from \pkg{l3box} are compatible with those of \LaTeXe{}
+% and plain \TeX{} and can be used interchangeably.  The \pkg{l3box}
+% commands to construct boxes, such as \cs{hbox:n} or \cs{hbox_set:Nn},
+% are \enquote{color-safe}, meaning that
+% \begin{verbatim}
+% \hbox:n { \color_select:n { blue } Hello, } ~ world!
+% \end{verbatim}
+% will result in \enquote{Hello,} taking the color blue, but
+% \enquote{world!} remaining with the prevailing color outside the box.
+%
 % \section{Creating and initialising boxes}
 %
 % \begin{function}{\box_new:N, \box_new:c}

Modified: trunk/Master/texmf-dist/source/latex/l3kernel/l3candidates.dtx
===================================================================
--- trunk/Master/texmf-dist/source/latex/l3kernel/l3candidates.dtx	2021-05-25 20:47:33 UTC (rev 59344)
+++ trunk/Master/texmf-dist/source/latex/l3kernel/l3candidates.dtx	2021-05-25 20:48:22 UTC (rev 59345)
@@ -44,7 +44,7 @@
 %    }^^A
 % }
 %
-% \date{Released 2021-05-11}
+% \date{Released 2021-05-25}
 %
 % \maketitle
 %
@@ -1694,7 +1694,7 @@
   { \@@_range_collect_unbraced:w #1 ; { } #2 }
 \cs_new:Npn \@@_range_collect_braced:w #1 ; #2#3
   {
-    \if_int_compare:w #1 > 1 \exp_stop_f:
+    \if_int_compare:w #1 > \c_one_int
       \exp_after:wN \@@_range_collect_braced:w
       \int_value:w \int_eval:n { #1 - 1 } \exp_after:wN ;
     \fi:
@@ -1702,7 +1702,7 @@
   }
 \cs_new:Npn \@@_range_collect_unbraced:w #1 ; #2#3
   {
-    \if_int_compare:w #1 > 1 \exp_stop_f:
+    \if_int_compare:w #1 > \c_one_int
       \exp_after:wN \@@_range_collect_unbraced:w
       \int_value:w \int_eval:n { #1 - 1 } \exp_after:wN ;
     \fi:

Modified: trunk/Master/texmf-dist/source/latex/l3kernel/l3cctab.dtx
===================================================================
--- trunk/Master/texmf-dist/source/latex/l3kernel/l3cctab.dtx	2021-05-25 20:47:33 UTC (rev 59344)
+++ trunk/Master/texmf-dist/source/latex/l3kernel/l3cctab.dtx	2021-05-25 20:48:22 UTC (rev 59345)
@@ -43,7 +43,7 @@
 %    }^^A
 % }
 %
-% \date{Released 2021-05-11}
+% \date{Released 2021-05-25}
 %
 % \maketitle
 %

Modified: trunk/Master/texmf-dist/source/latex/l3kernel/l3clist.dtx
===================================================================
--- trunk/Master/texmf-dist/source/latex/l3kernel/l3clist.dtx	2021-05-25 20:47:33 UTC (rev 59344)
+++ trunk/Master/texmf-dist/source/latex/l3kernel/l3clist.dtx	2021-05-25 20:48:22 UTC (rev 59345)
@@ -44,14 +44,15 @@
 %    }^^A
 % }
 %
-% \date{Released 2021-05-11}
+% \date{Released 2021-05-25}
 %
 % \maketitle
 %
 % \begin{documentation}
 %
-% Comma lists contain ordered data where items can be added to the left
-% or right end of the list.  This data type allows basic list
+% Comma lists (in short, |clist|) contain ordered data where items can
+% be added to the left or right end of the list.  This data type allows
+% basic list
 % manipulations such as adding/removing items, applying a function to
 % every item, removing duplicate items, extracting a given item, using
 % the comma list with specified separators, and so on.  Sequences
@@ -58,7 +59,7 @@
 % (defined in \pkg{l3seq}) are safer, faster, and provide more features,
 % so they should often be preferred to comma lists.  Comma lists are
 % mostly useful when interfacing with \LaTeXe{} or other code that
-% expects or provides comma list data.
+% expects or provides items separated by commas.
 %
 % Several items can be added at once.  To ease input of comma lists from
 % data provided by a user outside an \cs{ExplSyntaxOn} \ldots{}
@@ -75,10 +76,10 @@
 % \end{verbatim}
 % results in |\l_my_clist| containing |a,b,c~\d,{e~},{{f}}| namely the
 % five items |a|, |b|, |c~\d|, |e~| and~|{f}|.  Comma lists normally do
-% not contain empty items so the following gives an empty comma list:
+% not contain empty or blank items so the following gives an empty comma list:
 % \begin{verbatim}
 %   \clist_clear_new:N \l_my_clist
-%   \clist_put_right:Nn \l_my_clist { , ~ , , }
+%   \clist_set:Nn \l_my_clist { , ~ , , }
 %   \clist_if_empty:NTF \l_my_clist { true } { false }
 % \end{verbatim}
 % and it leaves \texttt{true} in the input stream.  To include an
@@ -86,6 +87,17 @@
 % or ends with a space, or is a single brace group), surround it with
 % braces.
 %
+% Any |n|-type token list is a valid comma list input for \pkg{l3clist}
+% functions, which will split the token list at every comma and process
+% the items as described above.  On the other hand, |N|-type functions
+% expect comma list variables, which are particular token list variables
+% in which this processing of items (and removal of blank items) has
+% already occurred.  Because comma list variables are token list
+% variables, expanding them once yields their items separated by commas,
+% and \pkg{l3tl} functions such as \cs{tl_show:N} can be applied to
+% them.  (These functions often have \pkg{l3clist} analogues, which
+% should be preferred.)
+%
 % Almost all operations on comma lists are
 % noticeably slower than those on sequences so converting the data to
 % sequences using \cs{seq_set_from_clist:Nn} (see \pkg{l3seq}) may be
@@ -156,7 +168,10 @@
 %     \cs{clist_set_eq:NN} \meta{comma list_1} \meta{comma list_2}
 %   \end{syntax}
 %   Sets the content of \meta{comma list_1} equal to that of
-%   \meta{comma list_2}.
+%   \meta{comma list_2}.  To set a token list variable equal to a comma
+%   list variable, use \cs{tl_set_eq:NN}.  Conversely, setting a comma
+%   list variable to a token list is unadvisable unless one checks
+%   space-trimming and related issues.
 % \end{function}
 %
 % \begin{function}[added = 2014-07-17]
@@ -831,22 +846,6 @@
 %    \end{macrocode}
 % \end{macro}
 %
-% \begin{variable}{\q_@@_recursion_tail,\q_@@_recursion_stop}
-%   Internal recursion quarks.
-%    \begin{macrocode}
-\quark_new:N \q_@@_recursion_tail
-\quark_new:N \q_@@_recursion_stop
-%    \end{macrocode}
-% \end{variable}
-%
-% \begin{macro}[EXP]{\@@_if_recursion_tail_break:nN,\@@_if_recursion_tail_stop:n}
-%   Functions to query recursion quarks.
-%    \begin{macrocode}
-\__kernel_quark_new_test:N \@@_if_recursion_tail_break:nN
-\__kernel_quark_new_test:N \@@_if_recursion_tail_stop:n
-%    \end{macrocode}
-% \end{macro}
-%
 % \begin{macro}{\@@_tmp:w}
 %   A temporary function for various purposes.
 %    \begin{macrocode}
@@ -888,11 +887,11 @@
   {
     \exp_after:wN \@@_sanitize:Nn \exp_after:wN \c_empty_tl
     \exp:w \@@_trim_next:w \prg_do_nothing:
-    #1 , \q_@@_recursion_tail , \q_@@_recursion_stop
+    #1 , \s_@@_stop \prg_break: , \prg_break_point:
   }
 \cs_new:Npn \@@_sanitize:Nn #1#2
   {
-    \@@_if_recursion_tail_stop:n {#2}
+    \@@_use_none_delimit_by_s_stop:w #2 \s_@@_stop
     #1 \@@_wrap_item:w #2 ,
     \exp_after:wN \@@_sanitize:Nn \exp_after:wN ,
     \exp:w \@@_trim_next:w \prg_do_nothing:
@@ -910,10 +909,7 @@
 %   \item is empty, or
 %   \item consists of a single braced group.
 %   \end{itemize}
-%   All \pkg{l3clist} functions go through the same test when they need
-%   to determine whether to brace an item, so it is not a problem that
-%   this test has false positives such as \enquote{\cs{s_@@_mark}
-%   \texttt{?}}.  If the argument starts or end with a space or contains
+%   If the argument starts or ends with a space or contains
 %   a comma then one of the three arguments of \cs{@@_if_wrap:w} will
 %   have its end delimiter (partly) in one of the three copies of |#1|
 %   in \cs{@@_if_wrap:nTF}; this has a knock-on effect meaning that the
@@ -1394,7 +1390,13 @@
     \clist_map_inline:Nn #2
       {
         \clist_if_in:NnF \l_@@_internal_remove_clist {##1}
-          { \clist_put_right:Nn \l_@@_internal_remove_clist {##1} }
+          {
+            \tl_put_right:Nx \l_@@_internal_remove_clist
+              {
+                \clist_if_empty:NF \l_@@_internal_remove_clist { , }
+                \@@_if_wrap:nTF {##1} { \exp_not:n { {##1} } } { \exp_not:n {##1} }
+              }
+          }
       }
     #1 #2 \l_@@_internal_remove_clist
   }
@@ -1654,28 +1656,38 @@
 %
 % \begin{macro}{\clist_map_function:NN, \clist_map_function:cN}
 % \UnitTested
-% \begin{macro}{\@@_map_function:nw}
+% \begin{macro}{\@@_map_function:Nw, \@@_map_function_end:w}
 %   If the variable is empty, the mapping is skipped (otherwise,
 %   that comma-list would be seen as consisting of one empty item).
-%   Then loop over the comma-list, grabbing one comma-delimited
-%   item at a time. The end is marked by \cs{q_@@_recursion_tail}.
-%   The auxiliary function \cs{@@_map_function:nw} is also used
-%   in \cs{clist_map_inline:Nn}.
+%   Then loop over the comma-list, grabbing eight comma-delimited items
+%   at a time. The end is marked by \cs{s_@@_stop}, which may not appear
+%   in any of the items.  Once the last group of eight items has been
+%   reached, we go through them more slowly using
+%   \cs{@@_map_function_end:w}.  The auxiliary function
+%   \cs{@@_map_function:Nw} is also used in some other clist mappings.
 %    \begin{macrocode}
 \cs_new:Npn \clist_map_function:NN #1#2
   {
     \clist_if_empty:NF #1
       {
-        \exp_last_unbraced:NNo \@@_map_function:nw #2 #1
-          , \q_@@_recursion_tail ,
+        \exp_after:wN \@@_map_function:Nw \exp_after:wN #2 #1 ,
+          \s_@@_stop , \s_@@_stop , \s_@@_stop , \s_@@_stop ,
+          \s_@@_stop , \s_@@_stop , \s_@@_stop , \s_@@_stop ,
         \prg_break_point:Nn \clist_map_break: { }
       }
   }
-\cs_new:Npn \@@_map_function:nw #1#2 ,
+\cs_new:Npn \@@_map_function:Nw #1 #2, #3, #4, #5, #6, #7, #8, #9,
   {
-    \@@_if_recursion_tail_break:nN {#2} \clist_map_break:
+    \@@_use_none_delimit_by_s_stop:w
+      #9 \@@_map_function_end:w \s_@@_stop
+    #1 {#2} #1 {#3} #1 {#4} #1 {#5} #1 {#6} #1 {#7} #1 {#8} #1 {#9}
+    \@@_map_function:Nw #1
+  }
+\cs_new:Npn \@@_map_function_end:w \s_@@_stop #1#2
+  {
+    \@@_use_none_delimit_by_s_stop:w #2 \clist_map_break: \s_@@_stop
     #1 {#2}
-    \@@_map_function:nw {#1}
+    \@@_map_function_end:w \s_@@_stop
   }
 \cs_generate_variant:Nn \clist_map_function:NN { c }
 %    \end{macrocode}
@@ -1697,12 +1709,13 @@
 \cs_new:Npn \clist_map_function:nN #1#2
   {
     \exp_after:wN \@@_map_function_n:Nn \exp_after:wN #2
-    \exp:w \@@_trim_next:w \prg_do_nothing: #1 , \q_@@_recursion_tail ,
+    \exp:w \@@_trim_next:w \prg_do_nothing: #1 ,
+      \s_@@_stop \clist_map_break: ,
     \prg_break_point:Nn \clist_map_break: { }
   }
 \cs_new:Npn \@@_map_function_n:Nn #1 #2
   {
-    \@@_if_recursion_tail_break:nN {#2} \clist_map_break:
+    \@@_use_none_delimit_by_s_stop:w #2 \s_@@_stop
     \@@_map_unbrace:wn #2 , #1
     \exp_after:wN \@@_map_function_n:Nn \exp_after:wN #1
     \exp:w \@@_trim_next:w \prg_do_nothing:
@@ -1736,9 +1749,11 @@
         \int_gincr:N \g__kernel_prg_map_int
         \cs_gset_protected:cpn
           { @@_map_ \int_use:N \g__kernel_prg_map_int :w } ##1 {#2}
-        \exp_last_unbraced:Nco \@@_map_function:nw
+        \exp_last_unbraced:Nco \@@_map_function:Nw
           { @@_map_ \int_use:N \g__kernel_prg_map_int :w }
-          #1 , \q_@@_recursion_tail ,
+          #1 ,
+          \s_@@_stop , \s_@@_stop , \s_@@_stop , \s_@@_stop ,
+          \s_@@_stop , \s_@@_stop , \s_@@_stop , \s_@@_stop ,
         \prg_break_point:Nn \clist_map_break:
           { \int_gdecr:N \g__kernel_prg_map_int }
       }
@@ -1756,41 +1771,24 @@
 % \begin{macro}{\clist_map_variable:NNn, \clist_map_variable:cNn}
 % \UnitTested
 % \begin{macro}{\clist_map_variable:nNn}
-% \begin{macro}{\@@_map_variable:Nnw}
-%   As for other comma-list mappings, filter out the case of
-%   an empty list. Same approach as \cs{clist_map_function:Nn},
-%   additionally we store each item in the given variable.
-%   As for inline mappings, space trimming for the \texttt{n}
-%   variant is done by storing the comma list in a variable.
-%   The quark test is done before assigning the item to the variable:
-%   this avoids storing a quark which the user wouldn't expect.
-%   The strange \cs{use:n} avoids unlikely problems when |#2| would
-%   contain \cs{q_@@_recursion_stop}.
+% \begin{macro}{\@@_map_variable:Nnn}
+%   The |N|-type version is a straightforward application of
+%   \cs{clist_map_tokens:Nn}, calling \cs{@@_map_variable:Nnn} for each
+%   item to assign the variable and run the user's code.  The |n|-type
+%   version is \emph{not} implemented in terms of the |n|-type function
+%   \cs{clist_map_tokens:Nn}, because here we are allowed to clean up
+%   the |n|-type comma list non-expandably.
 %    \begin{macrocode}
 \cs_new_protected:Npn \clist_map_variable:NNn #1#2#3
-  {
-    \clist_if_empty:NF #1
-      {
-        \exp_args:Nno \use:nn
-          { \@@_map_variable:Nnw #2 {#3} }
-          #1
-          , \q_@@_recursion_tail , \q_@@_recursion_stop
-        \prg_break_point:Nn \clist_map_break: { }
-      }
-  }
+  { \clist_map_tokens:Nn #1 { \@@_map_variable:Nnn #2 {#3} } }
+\cs_generate_variant:Nn \clist_map_variable:NNn { c }
+\cs_new_protected:Npn \@@_map_variable:Nnn #1#2#3
+  { \tl_set:Nn #1 {#3} #2 }
 \cs_new_protected:Npn \clist_map_variable:nNn #1
   {
     \clist_set:Nn \l_@@_internal_clist {#1}
     \clist_map_variable:NNn \l_@@_internal_clist
   }
-\cs_new_protected:Npn \@@_map_variable:Nnw #1#2#3,
-  {
-    \@@_if_recursion_tail_stop:n {#3}
-    \tl_set:Nn #1 {#3}
-    \use:n {#2}
-    \@@_map_variable:Nnw #1 {#2}
-  }
-\cs_generate_variant:Nn \clist_map_variable:NNn { c }
 %    \end{macrocode}
 % \end{macro}
 % \end{macro}
@@ -1797,7 +1795,7 @@
 % \end{macro}
 %
 % \begin{macro}{\clist_map_tokens:Nn, \clist_map_tokens:cn}
-% \begin{macro}{\@@_map_tokens:nw}
+% \begin{macro}{\@@_map_tokens:nw, \@@_map_tokens_end:w}
 %   Essentially a copy of \cs{clist_map_function:NN} with braces added.
 %    \begin{macrocode}
 \cs_new:Npn \clist_map_tokens:Nn #1#2
@@ -1804,17 +1802,32 @@
   {
     \clist_if_empty:NF #1
       {
-        \exp_last_unbraced:Nno \@@_map_function:nw {#2} #1
-          , \q_@@_recursion_tail ,
+        \exp_last_unbraced:Nno \@@_map_tokens:nw {#2} #1 ,
+          \s_@@_stop , \s_@@_stop , \s_@@_stop , \s_@@_stop ,
+          \s_@@_stop , \s_@@_stop , \s_@@_stop , \s_@@_stop ,
         \prg_break_point:Nn \clist_map_break: { }
       }
   }
+\cs_new:Npn \@@_map_tokens:nw #1 #2, #3, #4, #5, #6, #7, #8, #9,
+  {
+    \@@_use_none_delimit_by_s_stop:w
+      #9 \@@_map_tokens_end:w \s_@@_stop
+    \use:n {#1} {#2} \use:n {#1} {#3} \use:n {#1} {#4} \use:n {#1} {#5}
+    \use:n {#1} {#6} \use:n {#1} {#7} \use:n {#1} {#8} \use:n {#1} {#9}
+    \@@_map_tokens:nw {#1}
+  }
+\cs_new:Npn \@@_map_tokens_end:w \s_@@_stop \use:n #1#2
+  {
+    \@@_use_none_delimit_by_s_stop:w #2 \clist_map_break: \s_@@_stop
+    #1 {#2}
+    \@@_map_tokens_end:w \s_@@_stop
+  }
 \cs_generate_variant:Nn \clist_map_tokens:Nn { c }
 %    \end{macrocode}
 % \end{macro}
 % \end{macro}
 %
-% \begin{macro}{\clist_map_tokens:nn, \@@_map_tokens_n:nw, \@@_use_ii_i:nn}
+% \begin{macro}{\clist_map_tokens:nn, \@@_map_tokens_n:nw}
 %   Similar to \cs{clist_map_function:nN} but with a different way of
 %   grabbing items because we cannot use \cs{exp_after:wN} to pass the
 %   \meta{code}.
@@ -1822,7 +1835,7 @@
 \cs_new:Npn \clist_map_tokens:nn #1#2
   {
     \@@_map_tokens_n:nw {#2}
-    \prg_do_nothing: #1 , \q_@@_recursion_tail ,
+    \prg_do_nothing: #1 , \s_@@_stop \clist_map_break: ,
     \prg_break_point:Nn \clist_map_break: { }
   }
 \cs_new:Npn \@@_map_tokens_n:nw #1#2 ,
@@ -1829,13 +1842,12 @@
   {
     \tl_if_empty:oF { \use_none:nn #2 ? }
       {
-        \exp_args:No \@@_if_recursion_tail_break:nN {#2} \clist_map_break:
-        \tl_trim_spaces_apply:oN {#2} \@@_use_ii_i:nn
+        \@@_use_none_delimit_by_s_stop:w #2 \s_@@_stop
+        \tl_trim_spaces_apply:oN {#2} \use_ii_i:nn
         \@@_map_unbrace:wn , {#1}
       }
     \@@_map_tokens_n:nw {#1} \prg_do_nothing:
   }
-\cs_new:Npn \@@_use_ii_i:nn #1#2 { #2 #1 }
 %    \end{macrocode}
 % \end{macro}
 %
@@ -1869,22 +1881,26 @@
       }
   }
 \cs_generate_variant:Nn \clist_count:N { c }
-\cs_new:Npx \clist_count:n #1
+\cs_new:Npn \@@_count:n #1 { + 1 }
+\cs_set_protected:Npn \@@_tmp:w #1
   {
-    \exp_not:N \int_eval:n
+    \cs_new:Npn \clist_count:n ##1
       {
-        0
-        \exp_not:N \@@_count:w \c_space_tl
-        #1 \exp_not:n { , \q_@@_recursion_tail , \q_@@_recursion_stop }
+        \int_eval:n
+          {
+            0
+            \@@_count:w #1
+            ##1 , \s_@@_stop \prg_break: , \prg_break_point:
+          }
       }
+    \cs_new:Npn \@@_count:w ##1 ,
+      {
+        \@@_use_none_delimit_by_s_stop:w ##1 \s_@@_stop
+        \tl_if_blank:nF {##1} { + 1 }
+        \@@_count:w #1
+      }
   }
-\cs_new:Npn \@@_count:n #1 { + 1 }
-\cs_new:Npx \@@_count:w #1 ,
-  {
-    \exp_not:n { \exp_args:Nf \@@_if_recursion_tail_stop:n } {#1}
-    \exp_not:N \tl_if_blank:nF {#1} { + 1 }
-    \exp_not:N \@@_count:w \c_space_tl
-  }
+\exp_args:No \@@_tmp:w \c_space_tl
 %    \end{macrocode}
 % \end{macro}
 % \end{macro}
@@ -1907,15 +1923,15 @@
 %   quarks), 5: the rest of the comma list, 6: a \meta{continuation}
 %   function (\texttt{use_ii} or \texttt{use_iii} with its
 %   \meta{separator} argument), 7: junk, and 8: the temporary result,
-%   which is built in a brace group following \cs{q_@@_stop}.  The
+%   which is built in a brace group following \cs{s_@@_stop}.  The
 %   \meta{separator} and the first of the three items are placed in the
 %   result, then we use the \meta{continuation}, placing the remaining
 %   two items after it.  When we begin this loop, the three items really
-%   belong to the comma list, the first \cs{q_@@_mark} is taken as a
+%   belong to the comma list, the first \cs{s_@@_mark} is taken as a
 %   delimiter to the \texttt{use_ii} function, and the continuation is
 %   \texttt{use_ii} itself.  When we reach the last two items of the
-%   original token list, \cs{q_@@_mark} is taken as a third item, and now
-%   the second \cs{q_@@_mark} serves as a delimiter to \texttt{use_ii},
+%   original token list, \cs{s_@@_mark} is taken as a third item, and now
+%   the second \cs{s_@@_mark} serves as a delimiter to \texttt{use_ii},
 %   switching to the other \meta{continuation}, \texttt{use_iii}, which
 %   uses the \meta{separator between final two}.
 %    \begin{macrocode}
@@ -1993,7 +2009,7 @@
       { \@@_use:Nw #1#2 ; }
       {
         \@@_use_none_delimit_by_s_mark:w #4 #1 \s_@@_mark
-        \tl_trim_spaces_apply:oN {#4} \@@_use_ii_i:nn
+        \tl_trim_spaces_apply:oN {#4} \use_ii_i:nn
         \@@_map_unbrace:wn , { #2 ; }
       }
     #3 ; \prg_do_nothing:

Modified: trunk/Master/texmf-dist/source/latex/l3kernel/l3coffins.dtx
===================================================================
--- trunk/Master/texmf-dist/source/latex/l3kernel/l3coffins.dtx	2021-05-25 20:47:33 UTC (rev 59344)
+++ trunk/Master/texmf-dist/source/latex/l3kernel/l3coffins.dtx	2021-05-25 20:48:22 UTC (rev 59345)
@@ -43,7 +43,7 @@
 %    }^^A
 % }
 %
-% \date{Released 2021-05-11}
+% \date{Released 2021-05-25}
 %
 % \maketitle
 %
@@ -381,6 +381,31 @@
 %   which displays the result in the terminal.
 % \end{function}
 %
+% \begin{function}[added = 2021-05-11]
+%   {\coffin_show:N, \coffin_show:c, \coffin_log:N, \coffin_log:c}
+%   \begin{syntax}
+%     \cs{coffin_show:N} \meta{coffin}
+%     \cs{coffin_log:N} \meta{coffin}
+%   \end{syntax}
+%   Shows full details of poles and contents of the \meta{coffin} in the
+%   terminal or log file.  See \cs{coffin_show_structure:N} and
+%   \cs{box_show:N} to show separately the pole structure and the
+%   contents.
+% \end{function}
+%
+% \begin{function}[added = 2021-05-11]
+%   {\coffin_show:Nnn, \coffin_show:cnn, \coffin_log:Nnn, \coffin_log:cnn}
+%   \begin{syntax}
+%     \cs{coffin_show:Nnn} \meta{coffin} \Arg{intexpr_1} \Arg{intexpr_2}
+%     \cs{coffin_log:Nnn} \meta{coffin} \Arg{intexpr_1} \Arg{intexpr_2}
+%   \end{syntax}
+%   Shows poles and contents of the \meta{coffin} in the terminal or log
+%   file, showing the first \meta{intexpr_1} items in the coffin, and
+%   descending into \meta{intexpr_2} group levels.  See
+%   \cs{coffin_show_structure:N} and \cs{box_show:Nnn} to show
+%   separately the pole structure and the contents.
+% \end{function}
+%
 % \section{Constants and variables}
 %
 % \begin{variable}{\c_empty_coffin}
@@ -2481,6 +2506,40 @@
 %    \end{macrocode}
 % \end{macro}
 %
+% \begin{macro}
+%   {
+%     \coffin_show:N, \coffin_show:c, \coffin_log:N, \coffin_log:c,
+%     \coffin_show:Nnn, \coffin_show:cnn, \coffin_log:Nnn, \coffin_log:cnn,
+%     \@@_show:NNNnn
+%   }
+%   Essentially a combination of \cs{coffin_show_structure:N} and
+%   \cs{box_show:Nnn}, but we need to avoid having two prompts, so we
+%   use \cs{__kernel_msg_term:nnxxxx} instead of
+%   \cs{__kernel_msg_show:nnxxxx} in the |show| case.
+%    \begin{macrocode}
+\cs_new_protected:Npn \coffin_show:N #1
+  { \coffin_show:Nnn #1 \c_max_int \c_max_int }
+\cs_generate_variant:Nn \coffin_show:N { c }
+\cs_new_protected:Npn \coffin_log:N #1
+  { \coffin_log:Nnn #1 \c_max_int \c_max_int }
+\cs_generate_variant:Nn \coffin_log:N { c }
+\cs_new_protected:Npn \coffin_show:Nnn
+  { \@@_show:NNNnn \__kernel_msg_term:nnxxxx \box_show:Nnn }
+\cs_generate_variant:Nn \coffin_show:Nnn { c }
+\cs_new_protected:Npn \coffin_log:Nnn
+  { \@@_show:NNNnn \__kernel_msg_log:nnxxxx \box_show:Nnn }
+\cs_generate_variant:Nn \coffin_log:Nnn { c }
+\cs_new_protected:Npn \@@_show:NNNnn #1#2#3#4#5
+  {
+    \@@_if_exist:NT #3
+      {
+        \@@_show_structure:NN #1 #3
+        #2 #3 {#4} {#5}
+      }
+  }
+%    \end{macrocode}
+% \end{macro}
+%
 % \subsection{Messages}
 %
 %    \begin{macrocode}

Modified: trunk/Master/texmf-dist/source/latex/l3kernel/l3color.dtx
===================================================================
--- trunk/Master/texmf-dist/source/latex/l3kernel/l3color.dtx	2021-05-25 20:47:33 UTC (rev 59344)
+++ trunk/Master/texmf-dist/source/latex/l3kernel/l3color.dtx	2021-05-25 20:48:22 UTC (rev 59345)
@@ -43,7 +43,7 @@
 %    }^^A
 % }
 %
-% \date{Released 2021-05-11}
+% \date{Released 2021-05-25}
 %
 % \maketitle
 %
@@ -235,12 +235,13 @@
 %   it to be saved to a name.
 % \end{function}
 %
-% \begin{function}{\color_show:n}
+% \begin{function}[added = 2021-05-11]{\color_show:n, \color_log:n}
 %   \begin{syntax}
 %     \cs{color_show:n} \Arg{name}
+%     \cs{color_log:n} \Arg{name}
 %   \end{syntax}
 %   Displays the color specification stored in the \meta{name} on the
-%   terminal.
+%   terminal or log file.
 % \end{function}
 %
 % \section{Selecting colors}
@@ -2508,21 +2509,25 @@
 %
 % \subsection{Diagnostics}
 %
-% \begin{macro}{\color_show:n}
-% \begin{macro}{\@@_show:n}
+% \begin{macro}{\color_show:n, \color_log:n, \@@_show:Nn}
+% \begin{macro}[EXP]{\@@_show:n}
 %   Extract the information about a color and format for the user: the approach
 %   is similar to the keys module here.
 %    \begin{macrocode}
-\cs_new_protected:Npn \color_show:n #1
+\cs_new_protected:Npn \color_show:n
+  { \@@_show:Nn \__kernel_msg_show:nnxxxx }
+\cs_new_protected:Npn \color_log:n
+  { \@@_show:Nn \__kernel_msg_log:nnxxxx }
+\cs_new_protected:Npn \@@_show:Nn #1#2
   {
-    \__kernel_msg_show:nnxxxx { color } { show }
-      {#1}
+    #1 { color } { show }
+      {#2}
       {
-        \@@_if_defined:nT {#1}
+        \@@_if_defined:nT {#2}
           {
-            \exp_args:Nv \@@_show:n { l_@@_named_ #1 _tl }
+            \exp_args:Nv \@@_show:n { l_@@_named_ #2 _tl }
             \prop_map_function:cN
-              { l_@@_named_ #1 _prop }
+              { l_@@_named_ #2 _prop }
               \msg_show_item_unbraced:nn
           }
       }

Modified: trunk/Master/texmf-dist/source/latex/l3kernel/l3debug.dtx
===================================================================
--- trunk/Master/texmf-dist/source/latex/l3kernel/l3debug.dtx	2021-05-25 20:47:33 UTC (rev 59344)
+++ trunk/Master/texmf-dist/source/latex/l3kernel/l3debug.dtx	2021-05-25 20:48:22 UTC (rev 59345)
@@ -43,7 +43,7 @@
 %    }^^A
 % }
 %
-% \date{Released 2021-05-11}
+% \date{Released 2021-05-25}
 %
 % \maketitle
 %
@@ -491,7 +491,7 @@
 %   \cs{clist_concat:NNN}''.
 %
 %   Instead of changing \emph{the} definition of the macros, we'll
-%   create a copy of such macros, say, |__debug_clist_concat:NNN| which
+%   create a copy of such macros, say, \cs[no-index]{@@_clist_concat:NNN} which
 %   will be defined as
 %   |<debug code with #1, #2 and #3>\clist_concat:NNN#1#2#3|. For that
 %   we need to identify the signature of every function and build the
@@ -569,8 +569,7 @@
 \__kernel_msg_new:nnn { debug } { bad-arg-type }
   { Wrong~argument~type~#1. }
 %    \end{macrocode}
-%   The macro below is a modifiec copy of
-%   |\__cs_generate_variant_loop_base:N| to get the base form of an
+%   The macro below gets the base form of an
 %   argument type given a variant. It serves only to differentiate
 %   arguments which should be braced from ones which shouldn't. If all
 %   were to be braced this would be unnecessary. I moved the |n| and |N|
@@ -647,7 +646,7 @@
         \tex_endlinechar:D -1 \scan_stop:
         \tl_map_inline:nn {#3}
           {
-            \cs_if_exist:cTF { __debug_ \cs_to_str:N ##1 }
+            \cs_if_exist:cTF { @@_ \cs_to_str:N ##1 }
               { \@@_add_to_debug_code:Nnn }
               { \@@_setup_debug_code:Nnn }
                 ##1 {#1} {#2}
@@ -656,7 +655,7 @@
     }
   \cs_set_protected:Npn \@@_setup_debug_code:Nnn #1#2#3
     {
-      \cs_gset_eq:cN { __debug_ \cs_to_str:N #1 } #1
+      \cs_gset_eq:cN { @@_ \cs_to_str:N #1 } #1
       \@@_generate_parameter_list:NNN #1 \l_@@_tmpa_tl \l_@@_tmpb_tl
       \exp_args:Nx \tex_scantokens:D
         {
@@ -665,7 +664,7 @@
           \tl_use:N \l_@@_tmpa_tl
             {
               \tl_to_str:n {#2}
-              \exp_not:c { __debug_ \cs_to_str:N #1 }
+              \exp_not:c { @@_ \cs_to_str:N #1 }
               \tl_use:N \l_@@_tmpb_tl
               \tl_to_str:n {#3}
             }
@@ -678,7 +677,7 @@
           \cs_set:Npn \exp_not:N \@@_tmp:w
             ####1 \tl_to_str:n { macro: }
             ####2 \tl_to_str:n { -> }
-            ####3 \c_backslash_str \tl_to_str:n { __debug_ }
+            ####3 \c_backslash_str \tl_to_str:n { @@_ }
                     \cs_to_str:N #1
             ####4 \s_@@_stop
             {
@@ -688,7 +687,7 @@
                   \tex_def:D \exp_not:N #1 ####2
                     {
                       ####3 \tl_to_str:n {#2}
-                      \c_backslash_str __debug_ \cs_to_str:N #1
+                      \c_backslash_str @@_ \cs_to_str:N #1
                       ####4 \tl_to_str:n {#3}
                     }
                 }
@@ -808,6 +807,7 @@
       \box_set_eq:NN
       \box_set_eq_drop:NN
       \box_set_to_last:N
+      \clist_clear:N
       \clist_set_eq:NN
       \dim_zero:N
       \dim_set:Nn
@@ -838,6 +838,7 @@
       \skip_add:Nn
       \skip_sub:Nn
       \__kernel_tl_set:Nx
+      \tl_clear:N
       \tl_set_eq:NN
       \tl_put_left:Nn
       \tl_put_left:NV
@@ -870,6 +871,7 @@
       \box_gset_eq_drop:NN
       \box_gset_to_last:N
       \cctab_gset:Nn
+      \clist_gclear:N
       \clist_gset_eq:NN
       \dim_gset_eq:NN
       \dim_gzero:N
@@ -900,6 +902,7 @@
       \skip_gadd:Nn
       \skip_gsub:Nn
       \__kernel_tl_gset:Nx
+      \tl_gclear:N
       \tl_gset_eq:NN
       \tl_gput_left:Nn
       \tl_gput_left:NV

Modified: trunk/Master/texmf-dist/source/latex/l3kernel/l3deprecation.dtx
===================================================================
--- trunk/Master/texmf-dist/source/latex/l3kernel/l3deprecation.dtx	2021-05-25 20:47:33 UTC (rev 59344)
+++ trunk/Master/texmf-dist/source/latex/l3kernel/l3deprecation.dtx	2021-05-25 20:48:22 UTC (rev 59345)
@@ -43,7 +43,7 @@
 %    }^^A
 % }
 %
-% \date{Released 2021-05-11}
+% \date{Released 2021-05-25}
 %
 % \maketitle
 %

Modified: trunk/Master/texmf-dist/source/latex/l3kernel/l3doc.dtx
===================================================================
--- trunk/Master/texmf-dist/source/latex/l3kernel/l3doc.dtx	2021-05-25 20:47:33 UTC (rev 59344)
+++ trunk/Master/texmf-dist/source/latex/l3kernel/l3doc.dtx	2021-05-25 20:48:22 UTC (rev 59345)
@@ -79,7 +79,7 @@
 %
 % \title{The \cls{l3doc} class}
 % \author{\Team}
-% \date{Released 2021-05-11}
+% \date{Released 2021-05-25}
 % \maketitle
 % \tableofcontents
 %

Modified: trunk/Master/texmf-dist/source/latex/l3kernel/l3docstrip.dtx
===================================================================
--- trunk/Master/texmf-dist/source/latex/l3kernel/l3docstrip.dtx	2021-05-25 20:47:33 UTC (rev 59344)
+++ trunk/Master/texmf-dist/source/latex/l3kernel/l3docstrip.dtx	2021-05-25 20:48:22 UTC (rev 59345)
@@ -63,7 +63,7 @@
 %    }^^A
 % }
 %
-% \date{Released 2021-05-11}
+% \date{Released 2021-05-25}
 %
 % \maketitle
 %

Modified: trunk/Master/texmf-dist/source/latex/l3kernel/l3expan.dtx
===================================================================
--- trunk/Master/texmf-dist/source/latex/l3kernel/l3expan.dtx	2021-05-25 20:47:33 UTC (rev 59344)
+++ trunk/Master/texmf-dist/source/latex/l3kernel/l3expan.dtx	2021-05-25 20:48:22 UTC (rev 59345)
@@ -43,7 +43,7 @@
 %    }^^A
 % }
 %
-% \date{Released 2021-05-11}
+% \date{Released 2021-05-25}
 %
 % \maketitle
 %

Modified: trunk/Master/texmf-dist/source/latex/l3kernel/l3file.dtx
===================================================================
--- trunk/Master/texmf-dist/source/latex/l3kernel/l3file.dtx	2021-05-25 20:47:33 UTC (rev 59344)
+++ trunk/Master/texmf-dist/source/latex/l3kernel/l3file.dtx	2021-05-25 20:48:22 UTC (rev 59345)
@@ -44,7 +44,7 @@
 %    }^^A
 % }
 %
-% \date{Released 2021-05-11}
+% \date{Released 2021-05-25}
 %
 % \maketitle
 %
@@ -151,6 +151,21 @@
 %   to other programmers.
 % \end{function}
 %
+% \begin{function}[added = 2021-05-11]
+%   {
+%     \ior_show:N, \ior_show:c, \ior_log:N, \ior_log:c,
+%     \iow_show:N, \iow_show:c, \iow_log:N, \iow_log:c
+%   }
+%   \begin{syntax}
+%     \cs{ior_show:N} \meta{stream}
+%     \cs{ior_log:N} \meta{stream}
+%     \cs{iow_show:N} \meta{stream}
+%     \cs{iow_log:N} \meta{stream}
+%   \end{syntax}
+%   Display (to the terminal or log file) the file name associated to
+%   the (read or write) \meta{stream}.
+% \end{function}
+%
 % \begin{function}[added = 2017-06-27]
 %   {
 %     \ior_show_list:, \ior_log_list:,
@@ -1118,6 +1133,29 @@
 %    \end{macrocode}
 % \end{macro}
 %
+% \begin{macro}{\ior_show:N, \ior_log:N, \@@_show:NN}
+%   Seek the stream in the \cs{g_@@_streams_prop} list, then show the
+%   stream as open or closed accordingly.
+%    \begin{macrocode}
+\cs_new_protected:Npn \ior_show:N { \@@_show:NN \tl_show:n }
+\cs_generate_variant:Nn \ior_show:N { c }
+\cs_new_protected:Npn \ior_log:N { \@@_show:NN \tl_log:n }
+\cs_generate_variant:Nn \ior_log:N { c }
+\cs_new_protected:Npn \@@_show:NN #1#2
+  {
+    \__kernel_chk_defined:NT #2
+      {
+        \prop_get:NVNTF \g_@@_streams_prop #2 \l_@@_internal_tl
+          {
+            \exp_args:Nx #1
+              { \token_to_str:N #2 ~ open: ~ \l_@@_internal_tl }
+          }
+          { \exp_args:Nx #1 { \token_to_str:N #2 ~ closed } }
+      }
+  }
+%    \end{macrocode}
+% \end{macro}
+%
 % \begin{macro}{\ior_show_list:, \ior_log_list:}
 % \begin{macro}{\@@_list:N}
 %   Show the property lists, but with some \enquote{pretty printing}.
@@ -1354,6 +1392,13 @@
 %
 % \subsubsection{Variables and constants}
 %
+% \begin{variable}{\l_@@_internal_tl}
+%   Used as a short-term scratch variable.
+%    \begin{macrocode}
+\tl_new:N  \l_@@_internal_tl
+%    \end{macrocode}
+% \end{variable}
+%
 % \begin{variable}{\c_log_iow, \c_term_iow}
 %   Here we allocate two output streams for writing to the transcript
 %   file only (\cs{c_log_iow}) and to both the terminal and transcript
@@ -1520,6 +1565,29 @@
 %    \end{macrocode}
 % \end{macro}
 %
+% \begin{macro}{\iow_show:N, \iow_log:N, \@@_show:NN}
+%   Seek the stream in the \cs{g_@@_streams_prop} list, then show the
+%   stream as open or closed accordingly.
+%    \begin{macrocode}
+\cs_new_protected:Npn \iow_show:N { \@@_show:NN \tl_show:n }
+\cs_generate_variant:Nn \iow_show:N { c }
+\cs_new_protected:Npn \iow_log:N { \@@_show:NN \tl_log:n }
+\cs_generate_variant:Nn \iow_log:N { c }
+\cs_new_protected:Npn \@@_show:NN #1#2
+  {
+    \__kernel_chk_defined:NT #2
+      {
+        \prop_get:NVNTF \g_@@_streams_prop #2 \l_@@_internal_tl
+          {
+            \exp_args:Nx #1
+              { \token_to_str:N #2 ~ open: ~ \l_@@_internal_tl }
+          }
+          { \exp_args:Nx #1 { \token_to_str:N #2 ~ closed } }
+      }
+  }
+%    \end{macrocode}
+% \end{macro}
+%
 % \begin{macro}{\iow_show_list:, \iow_log_list:}
 % \begin{macro}{\@@_list:N}
 %   Done as for input, but with a copy of the auxiliary so the name is correct.
@@ -3130,7 +3198,7 @@
               \@@_str_cmp:nn
                 { \@@_timestamp:n {#1} }
                 { \@@_timestamp:n {#2} }
-                #3 0 \exp_stop_f:
+                #3 \c_zero_int
               \prg_return_true:
             \else:
               \prg_return_false:

Modified: trunk/Master/texmf-dist/source/latex/l3kernel/l3flag.dtx
===================================================================
--- trunk/Master/texmf-dist/source/latex/l3kernel/l3flag.dtx	2021-05-25 20:47:33 UTC (rev 59344)
+++ trunk/Master/texmf-dist/source/latex/l3kernel/l3flag.dtx	2021-05-25 20:48:22 UTC (rev 59345)
@@ -43,7 +43,7 @@
 %    }^^A
 % }
 %
-% \date{Released 2021-05-11}
+% \date{Released 2021-05-25}
 %
 % \maketitle
 %

Modified: trunk/Master/texmf-dist/source/latex/l3kernel/l3fp-assign.dtx
===================================================================
--- trunk/Master/texmf-dist/source/latex/l3kernel/l3fp-assign.dtx	2021-05-25 20:47:33 UTC (rev 59344)
+++ trunk/Master/texmf-dist/source/latex/l3kernel/l3fp-assign.dtx	2021-05-25 20:48:22 UTC (rev 59345)
@@ -40,7 +40,7 @@
 %          {latex-team at latex-project.org}^^A
 %    }^^A
 % }
-% \date{Released 2021-05-11}
+% \date{Released 2021-05-25}
 % \maketitle
 %
 % \begin{documentation}

Modified: trunk/Master/texmf-dist/source/latex/l3kernel/l3fp-aux.dtx
===================================================================
--- trunk/Master/texmf-dist/source/latex/l3kernel/l3fp-aux.dtx	2021-05-25 20:47:33 UTC (rev 59344)
+++ trunk/Master/texmf-dist/source/latex/l3kernel/l3fp-aux.dtx	2021-05-25 20:48:22 UTC (rev 59345)
@@ -43,7 +43,7 @@
 %    }^^A
 % }
 %
-% \date{Released 2021-05-11}
+% \date{Released 2021-05-25}
 %
 % \maketitle
 %
@@ -1222,7 +1222,7 @@
     \if_meaning:w 0 #1
       \exp_after:wN \@@_small_int_true:wTF
       \int_value:w \if_meaning:w 2 #5 - \fi:
-        \if_int_compare:w #2 > 0 \exp_stop_f:
+        \if_int_compare:w #2 > \c_zero_int
           1 0000 0000
         \else:
           #3

Modified: trunk/Master/texmf-dist/source/latex/l3kernel/l3fp-basics.dtx
===================================================================
--- trunk/Master/texmf-dist/source/latex/l3kernel/l3fp-basics.dtx	2021-05-25 20:47:33 UTC (rev 59344)
+++ trunk/Master/texmf-dist/source/latex/l3kernel/l3fp-basics.dtx	2021-05-25 20:48:22 UTC (rev 59345)
@@ -40,7 +40,7 @@
 %          {latex-team at latex-project.org}^^A
 %    }^^A
 % }
-% \date{Released 2021-05-11}
+% \date{Released 2021-05-25}
 %
 % \maketitle
 %
@@ -1846,15 +1846,15 @@
 \cs_new:Npn \@@_sqrt_auxiii_o:wnnnnnnnn
     #1; #2#3#4#5#6#7#8#9
   {
-    \if_int_compare:w #1 > 1 \exp_stop_f:
+    \if_int_compare:w #1 > \c_one_int
       \exp_after:wN \@@_sqrt_auxiv_o:NNNNNw
       \int_value:w \@@_int_eval:w (#1#2 %)
     \else:
-      \if_int_compare:w #1#2 > 1 \exp_stop_f:
+      \if_int_compare:w #1#2 > \c_one_int
         \exp_after:wN \@@_sqrt_auxv_o:NNNNNw
         \int_value:w \@@_int_eval:w (#1#2#3 %)
       \else:
-        \if_int_compare:w #1#2#3 > 1 \exp_stop_f:
+        \if_int_compare:w #1#2#3 > \c_one_int
           \exp_after:wN \@@_sqrt_auxvi_o:NNNNNw
           \int_value:w \@@_int_eval:w (#1#2#3#4 %)
         \else:
@@ -1872,7 +1872,7 @@
   { \@@_sqrt_auxviii_o:nnnnnnn {0000000#1} {#2#3#4#5#6} }
 \cs_new:Npn \@@_sqrt_auxvii_o:NNNNNw 1#1#2#3#4#5#6;
   {
-    \if_int_compare:w #1#2 = 0 \exp_stop_f:
+    \if_int_compare:w #1#2 = \c_zero_int
       \exp_after:wN \@@_sqrt_auxx_o:Nnnnnnnn
     \fi:
     \@@_sqrt_auxviii_o:nnnnnnn {00000000} {000#1#2#3#4#5}
@@ -1967,11 +1967,11 @@
 %    \begin{macrocode}
 \cs_new:Npn \@@_sqrt_auxxii_o:nnnnnnnnw 0; #1#2#3#4#5#6#7#8 #9;
   {
-    \if_int_compare:w #1#2 > 0 \exp_stop_f:
-      \if_int_compare:w #1#2 = 1 \exp_stop_f:
-        \if_int_compare:w #3#4 = 0 \exp_stop_f:
-          \if_int_compare:w #5#6 = 0 \exp_stop_f:
-            \if_int_compare:w #7#8 = 0 \exp_stop_f:
+    \if_int_compare:w #1#2 > \c_zero_int
+      \if_int_compare:w #1#2 = \c_one_int
+        \if_int_compare:w #3#4 = \c_zero_int
+          \if_int_compare:w #5#6 = \c_zero_int
+            \if_int_compare:w #7#8 = \c_zero_int
               \@@_sqrt_auxxiii_o:w
             \fi:
           \fi:

Modified: trunk/Master/texmf-dist/source/latex/l3kernel/l3fp-convert.dtx
===================================================================
--- trunk/Master/texmf-dist/source/latex/l3kernel/l3fp-convert.dtx	2021-05-25 20:47:33 UTC (rev 59344)
+++ trunk/Master/texmf-dist/source/latex/l3kernel/l3fp-convert.dtx	2021-05-25 20:48:22 UTC (rev 59345)
@@ -43,7 +43,7 @@
 %    }^^A
 % }
 %
-% \date{Released 2021-05-11}
+% \date{Released 2021-05-25}
 %
 % \maketitle
 %
@@ -324,7 +324,7 @@
 \cs_new:Npn \@@_to_decimal_large:Nnnw #1#2#3#4;
   {
     \exp_after:wN \@@_trim_zeros:w \int_value:w
-      \if_int_compare:w #2 > 0 \exp_stop_f:
+      \if_int_compare:w #2 > \c_zero_int
         #2
       \fi:
       \exp_stop_f:

Modified: trunk/Master/texmf-dist/source/latex/l3kernel/l3fp-expo.dtx
===================================================================
--- trunk/Master/texmf-dist/source/latex/l3kernel/l3fp-expo.dtx	2021-05-25 20:47:33 UTC (rev 59344)
+++ trunk/Master/texmf-dist/source/latex/l3kernel/l3fp-expo.dtx	2021-05-25 20:48:22 UTC (rev 59345)
@@ -40,7 +40,7 @@
 %          {latex-team at latex-project.org}^^A
 %    }^^A
 % }
-% \date{Released 2021-05-11}
+% \date{Released 2021-05-25}
 %
 % \maketitle
 %
@@ -182,7 +182,7 @@
   { %^^A todo: ln(1) should be "exact zero", not "underflow"
     \exp_after:wN \@@_sanitize:Nw
     \int_value:w % for the overall sign
-      \if_int_compare:w #1 < 1 \exp_stop_f:
+      \if_int_compare:w #1 < \c_one_int
         2
       \else:
         0
@@ -492,7 +492,7 @@
   { \@@_ln_Taylor_loop:www 21 ; {0000}{0000}{0000}{0000}{0000}{0000} ; }
 \cs_new:Npn \@@_ln_Taylor_loop:www #1; #2; #3;
   {
-    \if_int_compare:w #1 = 1 \exp_stop_f:
+    \if_int_compare:w #1 = \c_one_int
       \@@_ln_Taylor_break:w
     \fi:
     \exp_after:wN \@@_fixed_div_int:wwN \c_@@_one_fixed_tl #1;
@@ -564,7 +564,7 @@
     \or:
       \exp_after:wN \@@_ln_exponent_one:ww \int_value:w
     \else:
-      \if_int_compare:w #2 > 0 \exp_stop_f:
+      \if_int_compare:w #2 > \c_zero_int
         \exp_after:wN \@@_ln_exponent_small:NNww
         \exp_after:wN 0
         \exp_after:wN \@@_fixed_sub:wwn \int_value:w
@@ -655,7 +655,7 @@
       \exp_after:wN \@@_sanitize:Nw
       \exp_after:wN 0
       \int_value:w #1 \@@_int_eval:w
-        \if_int_compare:w #4 < 0 \exp_stop_f:
+        \if_int_compare:w #4 < \c_zero_int
           \exp_after:wN \use_i:nn
         \else:
           \exp_after:wN \use_ii:nn
@@ -707,7 +707,7 @@
   { \@@_exp_Taylor_loop:www 10 ; #1 ; #1 ; \s_@@_stop }
 \cs_new:Npn \@@_exp_Taylor_loop:www #1; #2; #3;
   {
-    \if_int_compare:w #1 = 1 \exp_stop_f:
+    \if_int_compare:w #1 = \c_one_int
       \exp_after:wN \@@_exp_Taylor_break:Nww
     \fi:
     \@@_fixed_div_int:wwN #3 ; #1 ;
@@ -1001,7 +1001,7 @@
     \s_@@ \@@_chk:w 1 #1#2#3; \s_@@ \@@_chk:w #4#5
   {
     \if_int_compare:w \@@_str_if_eq:nn { #2 #3 }
-              { 1 {1000} {0000} {0000} {0000} } = 0 \exp_stop_f:
+              { 1 {1000} {0000} {0000} {0000} } = \c_zero_int
       \if_int_compare:w #4 #1 = 32 \exp_stop_f:
         \exp_after:wN \@@_case_return_ii_o:ww
       \fi:
@@ -1013,7 +1013,7 @@
       \exp_after:wN #5
     \or:
       \if_meaning:w 2 #5 \exp_after:wN \reverse_if:N \fi:
-      \if_int_compare:w #2 > 0 \exp_stop_f:
+      \if_int_compare:w #2 > \c_zero_int
         \exp_after:wN \@@_case_return_o:Nww
         \exp_after:wN \c_inf_fp
       \else:
@@ -1048,7 +1048,7 @@
     \exp_after:wN \@@_sanitize:Nw
     \exp_after:wN 0
     \int_value:w
-      \if:w #1 \if_int_compare:w #3 > 0 \exp_stop_f: 0 \else: 2 \fi:
+      \if:w #1 \if_int_compare:w #3 > \c_zero_int 0 \else: 2 \fi:
         \exp_after:wN \@@_pow_npos_aux:NNnww
         \exp_after:wN +
         \exp_after:wN \@@_fixed_to_float_o:wN
@@ -1080,7 +1080,7 @@
   }
 \cs_new:Npn \@@_pow_exponent:wnN #1; #2
   {
-    \if_int_compare:w #2 > 0 \exp_stop_f:
+    \if_int_compare:w #2 > \c_zero_int
       \exp_after:wN \@@_pow_exponent:Nwnnnnnw % n\ln(10) - (-\ln(x))
       \exp_after:wN +
     \else:
@@ -1112,7 +1112,7 @@
   }
 \cs_new:Npn \@@_pow_B:wwN #1#2#3#4#5#6; #7;
   {
-    \if_int_compare:w #7 < 0 \exp_stop_f:
+    \if_int_compare:w #7 < \c_zero_int
       \exp_after:wN \@@_pow_C_neg:w \int_value:w -
     \else:
       \if_int_compare:w #7 < 22 \exp_stop_f:
@@ -1177,7 +1177,7 @@
     \if_case:w \@@_pow_neg_case:w #4 ;
       \exp_after:wN \@@_pow_neg_aux:wNN
     \or:
-      \if_int_compare:w \@@_int_eval:w #1 / 2 = 1 \exp_stop_f:
+      \if_int_compare:w \@@_int_eval:w #1 / 2 = \c_one_int
         \@@_invalid_operation_o:Nww ^ #3; #4;
         \exp:w \exp_end_continue_f:w
         \exp_after:wN \exp_after:wN

Modified: trunk/Master/texmf-dist/source/latex/l3kernel/l3fp-extended.dtx
===================================================================
--- trunk/Master/texmf-dist/source/latex/l3kernel/l3fp-extended.dtx	2021-05-25 20:47:33 UTC (rev 59344)
+++ trunk/Master/texmf-dist/source/latex/l3kernel/l3fp-extended.dtx	2021-05-25 20:48:22 UTC (rev 59345)
@@ -40,7 +40,7 @@
 %          {latex-team at latex-project.org}^^A
 %    }^^A
 % }
-% \date{Released 2021-05-11}
+% \date{Released 2021-05-25}
 %
 % \maketitle
 %

Modified: trunk/Master/texmf-dist/source/latex/l3kernel/l3fp-logic.dtx
===================================================================
--- trunk/Master/texmf-dist/source/latex/l3kernel/l3fp-logic.dtx	2021-05-25 20:47:33 UTC (rev 59344)
+++ trunk/Master/texmf-dist/source/latex/l3kernel/l3fp-logic.dtx	2021-05-25 20:48:22 UTC (rev 59345)
@@ -40,7 +40,7 @@
 %          {latex-team at latex-project.org}^^A
 %    }^^A
 % }
-% \date{Released 2021-05-11}
+% \date{Released 2021-05-25}
 %
 % \maketitle
 %
@@ -214,7 +214,7 @@
           \if_int_compare:w #4 < #1 - \fi: 1
         \fi:
       \else:
-        \if_int_compare:w #1#4 = 0 \exp_stop_f:
+        \if_int_compare:w #1#4 = \c_zero_int
           0
         \else:
           1
@@ -257,7 +257,7 @@
     \use_none:n #1
     \use_none:n #4
     \if_int_compare:w
-        \@@_compare_back_any:ww #1 #2 ; #4 #5 ; = 0 \exp_stop_f:
+        \@@_compare_back_any:ww #1 #2 ; #4 #5 ; = \c_zero_int
     \else:
       2 \exp_after:wN \prg_break:
     \fi:

Modified: trunk/Master/texmf-dist/source/latex/l3kernel/l3fp-parse.dtx
===================================================================
--- trunk/Master/texmf-dist/source/latex/l3kernel/l3fp-parse.dtx	2021-05-25 20:47:33 UTC (rev 59344)
+++ trunk/Master/texmf-dist/source/latex/l3kernel/l3fp-parse.dtx	2021-05-25 20:48:22 UTC (rev 59345)
@@ -40,7 +40,7 @@
 %          {latex-team at latex-project.org}^^A
 %    }^^A
 % }
-% \date{Released 2021-05-11}
+% \date{Released 2021-05-25}
 %
 % \maketitle
 %
@@ -1757,7 +1757,7 @@
       \if_meaning:w \scan_stop: #1
         \if_int_compare:w
             \@@_str_if_eq:nn { \s_@@ } { \exp_not:N #1 }
-            = 0 \exp_stop_f:
+            = \c_zero_int
           0
           \__kernel_msg_expandable_error:nnn
             { fp } { after-e } { floating~point~ }
@@ -1771,7 +1771,7 @@
       \else:
         \if_int_compare:w
             \@@_str_if_eq:nn { \int_value:w #1 } { \tex_the:D #1 }
-            = 0 \exp_stop_f:
+            = \c_zero_int
           \int_value:w #1
         \else:
           0
@@ -2265,7 +2265,7 @@
     \if_catcode:w \scan_stop: \exp_not:N #2
       \if_int_compare:w
           \@@_str_if_eq:nn { \s_@@_expr_mark } { \exp_not:N #2 }
-          = 0 \exp_stop_f:
+          = \c_zero_int
         \exp_after:wN \exp_after:wN
         \exp_after:wN \@@_parse_infix_mark:NNN
       \else:
@@ -2317,7 +2317,7 @@
     \if_catcode:w \scan_stop: \exp_not:N #2
       \if_int_compare:w
           \@@_str_if_eq:nn { \s_@@_expr_mark } { \exp_not:N #2 }
-          = 0 \exp_stop_f:
+          = \c_zero_int
         \exp_after:wN \exp_after:wN
         \exp_after:wN \@@_parse_infix_mark:NNN
       \else:

Modified: trunk/Master/texmf-dist/source/latex/l3kernel/l3fp-random.dtx
===================================================================
--- trunk/Master/texmf-dist/source/latex/l3kernel/l3fp-random.dtx	2021-05-25 20:47:33 UTC (rev 59344)
+++ trunk/Master/texmf-dist/source/latex/l3kernel/l3fp-random.dtx	2021-05-25 20:48:22 UTC (rev 59345)
@@ -40,7 +40,7 @@
 %          {latex-team at latex-project.org}^^A
 %    }^^A
 % }
-% \date{Released 2021-05-11}
+% \date{Released 2021-05-25}
 %
 % \maketitle
 %
@@ -396,11 +396,11 @@
             \if_meaning:w 1 #1
               \if_int_compare:w
                   \@@_use_i_until_s:nw #3 ; > \c_@@_prec_int
-                1 \exp_stop_f:
+                \c_one_int
               \fi:
             \fi:
           }
-          { 1 \exp_stop_f: }
+          { \c_one_int }
       }
     \cs_new:Npn \@@_randint_o:w #1; #2; @
       {
@@ -407,8 +407,8 @@
         \if_case:w
             \@@_randint_badarg:w #1;
             \@@_randint_badarg:w #2;
-            \if:w 1 \@@_compare_back:ww #2; #1; 1 \exp_stop_f: \fi:
-            0 \exp_stop_f:
+            \if:w 1 \@@_compare_back:ww #2; #1; \c_one_int \fi:
+            \c_zero_int
           \@@_randint_auxi_o:ww #1; #2;
         \or:
           \@@_invalid_operation_tl_o:ff
@@ -632,7 +632,7 @@
       }
     \cs_new:Npn \@@_randint:n #1
       {
-        \if_int_compare:w #1 < 1 \exp_stop_f:
+        \if_int_compare:w #1 < \c_one_int
           \__kernel_msg_expandable_error:nnnn
             { kernel } { randint-backward-range } { 1 } {#1}
           \@@_randint:ww #1; 1;

Modified: trunk/Master/texmf-dist/source/latex/l3kernel/l3fp-round.dtx
===================================================================
--- trunk/Master/texmf-dist/source/latex/l3kernel/l3fp-round.dtx	2021-05-25 20:47:33 UTC (rev 59344)
+++ trunk/Master/texmf-dist/source/latex/l3kernel/l3fp-round.dtx	2021-05-25 20:48:22 UTC (rev 59345)
@@ -43,7 +43,7 @@
 %    }^^A
 % }
 %
-% \date{Released 2021-05-11}
+% \date{Released 2021-05-25}
 %
 % \maketitle
 %
@@ -198,21 +198,21 @@
 \cs_new:Npn \@@_round_to_ninf:NNN #1 #2 #3
   {
     \if_meaning:w 2 #1
-      \if_int_compare:w #3 > 0 \exp_stop_f:
+      \if_int_compare:w #3 > \c_zero_int
         \@@_round_return_one:
       \fi:
     \fi:
-    0 \exp_stop_f:
+    \c_zero_int
   }
-\cs_new:Npn \@@_round_to_zero:NNN #1 #2 #3 { 0 \exp_stop_f: }
+\cs_new:Npn \@@_round_to_zero:NNN #1 #2 #3 { \c_zero_int }
 \cs_new:Npn \@@_round_to_pinf:NNN #1 #2 #3
   {
     \if_meaning:w 0 #1
-      \if_int_compare:w #3 > 0 \exp_stop_f:
+      \if_int_compare:w #3 > \c_zero_int
         \@@_round_return_one:
       \fi:
     \fi:
-    0 \exp_stop_f:
+    \c_zero_int
   }
 \cs_new:Npn \@@_round_to_nearest:NNN #1 #2 #3
   {
@@ -225,7 +225,7 @@
         \fi:
       \fi:
     \fi:
-    0 \exp_stop_f:
+    \c_zero_int
   }
 \cs_new:Npn \@@_round_to_nearest_ninf:NNN #1 #2 #3
   {
@@ -238,7 +238,7 @@
         \fi:
       \fi:
     \fi:
-    0 \exp_stop_f:
+    \c_zero_int
   }
 \cs_new:Npn \@@_round_to_nearest_zero:NNN #1 #2 #3
   {
@@ -245,7 +245,7 @@
     \if_int_compare:w #3 > \c_@@_five_int
       \@@_round_return_one:
     \fi:
-    0 \exp_stop_f:
+    \c_zero_int
   }
 \cs_new:Npn \@@_round_to_nearest_pinf:NNN #1 #2 #3
   {
@@ -258,7 +258,7 @@
         \fi:
       \fi:
     \fi:
-    0 \exp_stop_f:
+    \c_zero_int
   }
 \cs_new_eq:NN \@@_round:NNN \@@_round_to_nearest:NNN
 %    \end{macrocode}
@@ -286,7 +286,7 @@
       \if_int_odd:w 0 \if_meaning:w 0 #3 1 \fi:
                       \if_meaning:w 5 #3 1 \fi:
                 \exp_stop_f:
-        \if_int_compare:w \@@_int_eval:w #4 > 0 \exp_stop_f:
+        \if_int_compare:w \@@_int_eval:w #4 > \c_zero_int
           1 +
         \fi:
       \fi:
@@ -311,7 +311,7 @@
     \if_int_odd:w \if_meaning:w 0 #1 1 \else:
                   \if_meaning:w 5 #1 1 \else:
                   0 \fi: \fi: \exp_stop_f:
-      \if_int_compare:w \@@_int_eval:w #2 > 0 \exp_stop_f:
+      \if_int_compare:w \@@_int_eval:w #2 > \c_zero_int
         \@@_int_eval:w 1 +
       \fi:
     \fi:
@@ -350,10 +350,10 @@
 \cs_new_eq:NN \@@_round_to_ninf_neg:NNN \@@_round_to_pinf:NNN
 \cs_new:Npn \@@_round_to_zero_neg:NNN #1 #2 #3
   {
-    \if_int_compare:w #3 > 0 \exp_stop_f:
+    \if_int_compare:w #3 > \c_zero_int
       \@@_round_return_one:
     \fi:
-    0 \exp_stop_f:
+    \c_zero_int
   }
 \cs_new_eq:NN \@@_round_to_pinf_neg:NNN \@@_round_to_ninf:NNN
 \cs_new_eq:NN \@@_round_to_nearest_neg:NNN \@@_round_to_nearest:NNN
@@ -364,7 +364,7 @@
     \if_int_compare:w #3 < \c_@@_five_int \else:
       \@@_round_return_one:
     \fi:
-    0 \exp_stop_f:
+    \c_zero_int
   }
 \cs_new_eq:NN \@@_round_to_nearest_pinf_neg:NNN
   \@@_round_to_nearest_ninf:NNN
@@ -525,12 +525,12 @@
   {
     \exp_after:wN \@@_round_normal:NNwNnn
     \int_value:w \@@_int_eval:w
-      \if_int_compare:w #2 > 0 \exp_stop_f:
+      \if_int_compare:w #2 > \c_zero_int
         1 \int_value:w #2
         \exp_after:wN \@@_round_pack:Nw
         \int_value:w \@@_int_eval:w 1#3 +
       \else:
-        \if_int_compare:w #3 > 0 \exp_stop_f:
+        \if_int_compare:w #3 > \c_zero_int
           1 \int_value:w #3 +
         \fi:
       \fi:

Modified: trunk/Master/texmf-dist/source/latex/l3kernel/l3fp-traps.dtx
===================================================================
--- trunk/Master/texmf-dist/source/latex/l3kernel/l3fp-traps.dtx	2021-05-25 20:47:33 UTC (rev 59344)
+++ trunk/Master/texmf-dist/source/latex/l3kernel/l3fp-traps.dtx	2021-05-25 20:48:22 UTC (rev 59345)
@@ -40,7 +40,7 @@
 %          {latex-team at latex-project.org}^^A
 %    }^^A
 % }
-% \date{Released 2021-05-11}
+% \date{Released 2021-05-25}
 % \maketitle
 %
 % \begin{documentation}

Modified: trunk/Master/texmf-dist/source/latex/l3kernel/l3fp-trig.dtx
===================================================================
--- trunk/Master/texmf-dist/source/latex/l3kernel/l3fp-trig.dtx	2021-05-25 20:47:33 UTC (rev 59344)
+++ trunk/Master/texmf-dist/source/latex/l3kernel/l3fp-trig.dtx	2021-05-25 20:48:22 UTC (rev 59345)
@@ -40,7 +40,7 @@
 %          {latex-team at latex-project.org}^^A
 %    }^^A
 % }
-% \date{Released 2021-05-11}
+% \date{Released 2021-05-25}
 %
 % \maketitle
 %
@@ -1311,7 +1311,7 @@
         7 - \@@_int_eval:w
       \fi:
       \if_int_compare:w
-          \@@_ep_compare:wwww #2,#3; #5,#6; > 0 \exp_stop_f:
+          \@@_ep_compare:wwww #2,#3; #5,#6; > \c_zero_int
         3 -
         \exp_after:wN \@@_reverse_args:Nww
       \fi:
@@ -1398,7 +1398,7 @@
 %    \begin{macrocode}
 \cs_new:Npn \@@_atan_Taylor_loop:www #1; #2; #3;
   {
-    \if_int_compare:w #1 = -1 \exp_stop_f:
+    \if_int_compare:w #1 = - \c_one_int
       \@@_atan_Taylor_break:w
     \fi:
     \exp_after:wN \@@_fixed_div_int:wwN \c_@@_one_fixed_tl #1;
@@ -1550,7 +1550,7 @@
 \cs_new:Npn \@@_asin_normal_o:NfwNnnnnw
     #1#2#3 \s_@@ \@@_chk:w 1#4#5#6#7#8#9;
   {
-    \if_int_compare:w #5 < 1 \exp_stop_f:
+    \if_int_compare:w #5 < \c_one_int
       \exp_after:wN \@@_use_none_until_s:w
     \fi:
     \if_int_compare:w \@@_int_eval:w #5 + #6#7 + #8#9 = 1000 0001 ~

Modified: trunk/Master/texmf-dist/source/latex/l3kernel/l3fp.dtx
===================================================================
--- trunk/Master/texmf-dist/source/latex/l3kernel/l3fp.dtx	2021-05-25 20:47:33 UTC (rev 59344)
+++ trunk/Master/texmf-dist/source/latex/l3kernel/l3fp.dtx	2021-05-25 20:48:22 UTC (rev 59345)
@@ -49,7 +49,7 @@
 %    }^^A
 % }
 %
-% \date{Released 2021-05-11}
+% \date{Released 2021-05-25}
 %
 % \maketitle
 %

Modified: trunk/Master/texmf-dist/source/latex/l3kernel/l3fparray.dtx
===================================================================
--- trunk/Master/texmf-dist/source/latex/l3kernel/l3fparray.dtx	2021-05-25 20:47:33 UTC (rev 59344)
+++ trunk/Master/texmf-dist/source/latex/l3kernel/l3fparray.dtx	2021-05-25 20:48:22 UTC (rev 59345)
@@ -44,7 +44,7 @@
 %    }^^A
 % }
 %
-% \date{Released 2021-05-11}
+% \date{Released 2021-05-25}
 %
 % \maketitle
 %

Modified: trunk/Master/texmf-dist/source/latex/l3kernel/l3int.dtx
===================================================================
--- trunk/Master/texmf-dist/source/latex/l3kernel/l3int.dtx	2021-05-25 20:47:33 UTC (rev 59344)
+++ trunk/Master/texmf-dist/source/latex/l3kernel/l3int.dtx	2021-05-25 20:48:22 UTC (rev 59345)
@@ -43,7 +43,7 @@
 %    }^^A
 % }
 %
-% \date{Released 2021-05-11}
+% \date{Released 2021-05-25}
 %
 % \maketitle
 %
@@ -1088,13 +1088,14 @@
 %
 % \begin{macro}{\int_eval:n}
 % \begin{macro}{\int_eval:w}
-%   Wrapper for \cs{@@_eval:w}: can be used in an integer expression
-%   or directly in the input stream.
-%   When debugging, use parentheses to catch early termination.
+%   Wrapper for \cs{@@_eval:w}: can be used in an integer expression or
+%   directly in the input stream.  It is very slightly faster to use
+%   \tn{the} rather than \tn{number} to turn the expression to a number.
+%   When debugging, we introduce parentheses to catch early termination (see \pkg{l3debug}).
 %    \begin{macrocode}
 \cs_new:Npn \int_eval:n #1
-  { \int_value:w \@@_eval:w #1 \@@_eval_end: }
-\cs_new:Npn \int_eval:w { \int_value:w \@@_eval:w }
+  { \tex_the:D \@@_eval:w #1 \@@_eval_end: }
+\cs_new:Npn \int_eval:w { \tex_the:D \@@_eval:w }
 %    \end{macrocode}
 % \end{macro}
 % \end{macro}
@@ -1399,15 +1400,17 @@
 % \begin{macro}{\int_gsub:Nn, \int_gsub:cn}
 % \UnitTested
 %    Adding and subtracting to and from a counter.
+%    Including here the optional |by| would slow down these operations
+%    by a few percent.
 %    \begin{macrocode}
 \cs_new_protected:Npn \int_add:Nn #1#2
-  { \tex_advance:D #1 by \@@_eval:w #2 \@@_eval_end: }
+  { \tex_advance:D #1 \@@_eval:w #2 \@@_eval_end: }
 \cs_new_protected:Npn \int_sub:Nn #1#2
-  { \tex_advance:D #1 by - \@@_eval:w #2 \@@_eval_end: }
+  { \tex_advance:D #1 - \@@_eval:w #2 \@@_eval_end: }
 \cs_new_protected:Npn \int_gadd:Nn #1#2
-  { \tex_global:D \tex_advance:D #1 by \@@_eval:w #2 \@@_eval_end: }
+  { \tex_global:D \tex_advance:D #1 \@@_eval:w #2 \@@_eval_end: }
 \cs_new_protected:Npn \int_gsub:Nn #1#2
-  { \tex_global:D \tex_advance:D #1 by - \@@_eval:w #2 \@@_eval_end: }
+  { \tex_global:D \tex_advance:D #1 - \@@_eval:w #2 \@@_eval_end: }
 \cs_generate_variant:Nn \int_add:Nn  { c }
 \cs_generate_variant:Nn \int_gadd:Nn { c }
 \cs_generate_variant:Nn \int_sub:Nn  { c }
@@ -1452,12 +1455,14 @@
 % \begin{macro}{\int_gset:Nn, \int_gset:cn}
 % \UnitTested
 %   As integers are register-based \TeX{} issues an error
-%   if they are not defined.
+%   if they are not defined.  While the |=| sign is optional, this
+%   version with |=| is slightly quicker than without, while adding the
+%   optional space after |=| slows things down minutely.
 %    \begin{macrocode}
 \cs_new_protected:Npn \int_set:Nn #1#2
-  { #1 ~ \@@_eval:w #2 \@@_eval_end: }
+  { #1 = \@@_eval:w #2 \@@_eval_end: }
 \cs_new_protected:Npn \int_gset:Nn #1#2
-  { \tex_global:D #1 ~ \@@_eval:w #2 \@@_eval_end: }
+  { \tex_global:D #1 = \@@_eval:w #2 \@@_eval_end: }
 \cs_generate_variant:Nn \int_set:Nn  { c }
 \cs_generate_variant:Nn \int_gset:Nn { c }
 %    \end{macrocode}
@@ -1468,13 +1473,10 @@
 %
 % \begin{macro}{\int_use:N, \int_use:c}
 % \UnitTested
-%    Here is how counters are accessed:
+%    Here is how counters are accessed.
+%    We hand-code the |c| variant for some speed gain.
 %    \begin{macrocode}
 \cs_new_eq:NN \int_use:N \tex_the:D
-%    \end{macrocode}
-%    We hand-code this for some speed gain:
-%    \begin{macrocode}
-%\cs_generate_variant:Nn \int_use:N { c }
 \cs_new:Npn \int_use:c #1 { \tex_the:D \cs:w #1 \cs_end: }
 %    \end{macrocode}
 % \end{macro}

Modified: trunk/Master/texmf-dist/source/latex/l3kernel/l3intarray.dtx
===================================================================
--- trunk/Master/texmf-dist/source/latex/l3kernel/l3intarray.dtx	2021-05-25 20:47:33 UTC (rev 59344)
+++ trunk/Master/texmf-dist/source/latex/l3kernel/l3intarray.dtx	2021-05-25 20:48:22 UTC (rev 59345)
@@ -44,7 +44,7 @@
 %    }^^A
 % }
 %
-% \date{Released 2021-05-11}
+% \date{Released 2021-05-25}
 %
 % \maketitle
 %

Modified: trunk/Master/texmf-dist/source/latex/l3kernel/l3kernel-functions.dtx
===================================================================
--- trunk/Master/texmf-dist/source/latex/l3kernel/l3kernel-functions.dtx	2021-05-25 20:47:33 UTC (rev 59344)
+++ trunk/Master/texmf-dist/source/latex/l3kernel/l3kernel-functions.dtx	2021-05-25 20:48:22 UTC (rev 59345)
@@ -43,7 +43,7 @@
 %    }^^A
 % }
 %
-% \date{Released 2021-05-11}
+% \date{Released 2021-05-25}
 %
 % \maketitle
 %

Modified: trunk/Master/texmf-dist/source/latex/l3kernel/l3keys.dtx
===================================================================
--- trunk/Master/texmf-dist/source/latex/l3kernel/l3keys.dtx	2021-05-25 20:47:33 UTC (rev 59344)
+++ trunk/Master/texmf-dist/source/latex/l3kernel/l3keys.dtx	2021-05-25 20:48:22 UTC (rev 59345)
@@ -43,7 +43,7 @@
 %    }^^A
 % }
 %
-% \date{Released 2021-05-11}
+% \date{Released 2021-05-25}
 %
 % \maketitle
 %
@@ -1006,7 +1006,7 @@
 %   comma and |#2| will be the active equals sign.
 %    \begin{macrocode}
 \group_begin:
-  \cs_set_protected:Npn \@@_tmp:NN #1#2
+  \cs_set_protected:Npn \@@_tmp:w #1#2
     {
 %    \end{macrocode}
 %
@@ -1016,11 +1016,28 @@
 %   The use of \cs{s_@@_mark} here prevents loss of braces from the key
 %   argument.
 %    \begin{macrocode}
-      \cs_new:Npn \keyval_parse:nnn ##1 ##2 ##3
+      \cs_if_exist:NTF \tex_expanded:D
         {
-          \group_align_safe_begin:
-          \@@_loop_active:nnw {##1} {##2} \s_@@_mark ##3 #1 \s_@@_tail #1
+          \cs_new:Npn \keyval_parse:nnn ##1 ##2 ##3
+            {
+              \__kernel_exp_not:w \tex_expanded:D
+                {
+                  {
+                    \@@_loop_active:nnw {##1} {##2}
+                      \s_@@_mark ##3 #1 \s_@@_tail #1
+                  }
+                }
+            }
         }
+        {
+          \cs_new:Npn \keyval_parse:nnn ##1 ##2 ##3
+            {
+              \group_align_safe_begin:
+              \@@_loop_active:nnw {##1} {##2}
+                \s_@@_mark ##3 #1 \s_@@_tail #1
+              \group_align_safe_end:
+            }
+        }
       \cs_new_eq:NN \keyval_parse:NNn \keyval_parse:nnn
 %    \end{macrocode}
 % \end{macro}
@@ -1258,17 +1275,17 @@
       \cs_new:Npn \@@_end_loop_active:w
           \s_@@_tail
           \@@_loop_other:nnw ##1 \s_@@_mark \s_@@_tail , \s_@@_tail ,
-        { \group_align_safe_end: }
+        { }
 %    \end{macrocode}
 % \end{macro}
 %
-% The parsing loops are done, so here ends the definition of \cs{@@_tmp:NN},
+% The parsing loops are done, so here ends the definition of \cs{@@_tmp:w},
 % which will finally set up the macros.
 %    \begin{macrocode}
     }
   \char_set_catcode_active:n { `\, }
   \char_set_catcode_active:n { `\= }
-  \@@_tmp:NN , =
+  \@@_tmp:w , =
 \group_end:
 %    \end{macrocode}
 %
@@ -1279,24 +1296,32 @@
 %   \cs{exp_not:n} with the correct arguments. Afterwards they insert the next
 %   iteration of the other loop.
 %    \begin{macrocode}
-\cs_new:Npn \@@_pair:nnnn #1 #2 #3 #4
-  {
-    \@@_if_blank:w \s_@@_mark #2 \s_@@_nil \s_@@_stop \@@_blank_key_error:w
-      \s_@@_mark \s_@@_stop
-    \group_align_safe_end:
-    \exp_not:n { #4 { #2 } { #1 } }
-    \group_align_safe_begin:
-    \@@_loop_other:nnw {#3} {#4}
-  }
-\cs_new:Npn \@@_key:nn #1 #2
-  {
-    \@@_if_blank:w \s_@@_mark #1 \s_@@_nil \s_@@_stop \@@_blank_key_error:w
-      \s_@@_mark \s_@@_stop
-    \group_align_safe_end:
-    \exp_not:n { #2 { #1 } }
-    \group_align_safe_begin:
-    \@@_loop_other:nnw {#2}
-  }
+\group_begin:
+  \cs_set_protected:Npn \@@_tmp:w #1#2
+    {
+      \cs_new:Npn \@@_pair:nnnn ##1 ##2 ##3 ##4
+        {
+          \@@_if_blank:w \s_@@_mark ##2 \s_@@_nil \s_@@_stop \@@_blank_key_error:w
+            \s_@@_mark \s_@@_stop
+          #1
+          \exp_not:n { ##4 {##2} {##1} }
+          #2
+          \@@_loop_other:nnw {##3} {##4}
+        }
+      \cs_new:Npn \@@_key:nn ##1 ##2
+        {
+          \@@_if_blank:w \s_@@_mark ##1 \s_@@_nil \s_@@_stop \@@_blank_key_error:w
+            \s_@@_mark \s_@@_stop
+          #1
+          \exp_not:n { ##2 {##1} }
+          #2
+          \@@_loop_other:nnw {##2}
+        }
+    }
+  \cs_if_exist:NTF \tex_expanded:D
+    { \@@_tmp:w { } { } }
+    { \@@_tmp:w \group_align_safe_end: \group_align_safe_begin: }
+\group_end:
 %    \end{macrocode}
 % \end{macro}
 %
@@ -1318,11 +1343,10 @@
 %    \begin{macrocode}
 \cs_new:Npn \@@_blank_true:w \s_@@_mark \s_@@_stop \@@_trim:nN #1 \@@_key:nn
   { \@@_loop_other:nnw }
-\cs_new:Npn \@@_blank_key_error:w
-  \s_@@_mark \s_@@_stop \group_align_safe_end: \exp_not:n #1
+\cs_new:Npn \@@_blank_key_error:w #1 \@@_loop_other:nnw
   {
-    \__kernel_msg_expandable_error:nn
-      { keyval } { blank-key-name }
+    \__kernel_msg_expandable_error:nn { keyval } { blank-key-name }
+    \@@_loop_other:nnw
   }
 %    \end{macrocode}
 % \end{macro}
@@ -1346,7 +1370,7 @@
 % worth it.
 %    \begin{macrocode}
 \group_begin:
-  \cs_set_protected:Npn \@@_tmp:n #1
+  \cs_set_protected:Npn \@@_tmp:w #1
     {
       \cs_new:Npn \@@_trim:nN ##1
         {
@@ -1387,7 +1411,7 @@
           ##2
         { ##2 { ##1 } }
     }
-  \@@_tmp:n { ~ }
+  \@@_tmp:w { ~ }
 \group_end:
 %    \end{macrocode}
 % \end{macro}
@@ -1642,14 +1666,14 @@
 %   Searching for a property means finding the last |.| in the input,
 %   and storing the text before and after it. Everything is turned into
 %   strings, so there is no problem using an \texttt{x}-type expansion. Since
-%   |\__keys_trim_spaces:n| will turn its argument into a string anyway, this
+%   \cs{@@_trim_spaces:n} will turn its argument into a string anyway, this
 %   function uses \cs{cs_set_nopar:Npx} instead of \cs{tl_set:Nx} to gain some
 %   speed.
 %    \begin{macrocode}
 \cs_new_protected:Npn \@@_property_find:n #1
   {
-    \cs_set_nopar:Npx \l__keys_property_str { \__keys_trim_spaces:n { #1 } }
-    \exp_after:wN \@@_property_find_auxi:w \l__keys_property_str
+    \cs_set_nopar:Npx \l_@@_property_str { \@@_trim_spaces:n { #1 } }
+    \exp_after:wN \@@_property_find_auxi:w \l_@@_property_str
       \s_@@_nil \@@_property_find_auxii:w
       . \s_@@_nil \@@_property_find_err:w
   }
@@ -1662,7 +1686,7 @@
     \@@_property_find_err:w
   {
     \cs_set_nopar:Npx \l_keys_path_str
-      { \str_if_empty:NF \l__keys_module_str { \l__keys_module_str / } #1 }
+      { \str_if_empty:NF \l_@@_module_str { \l_@@_module_str / } #1 }
     \@@_property_find_auxi:w #2 \s_@@_nil \@@_property_find_auxiii:w . \s_@@_nil
       \@@_property_find_auxiv:w
   }
@@ -1675,15 +1699,15 @@
     #1 \s_@@_nil \@@_property_find_auxiii:w
     \s_@@_mark \s_@@_nil \@@_property_find_auxiv:w
   {
-    \cs_set_nopar:Npx \l__keys_property_str { . #1 }
+    \cs_set_nopar:Npx \l_@@_property_str { . #1 }
     \cs_set_nopar:Npx \l_keys_path_str
-      { \exp_after:wN \__keys_trim_spaces:n \exp_after:wN { \l_keys_path_str } }
+      { \exp_after:wN \@@_trim_spaces:n \exp_after:wN { \l_keys_path_str } }
     \tl_set_eq:NN \l_keys_path_tl \l_keys_path_str
   }
 \cs_new_protected:Npn \@@_property_find_err:w
     #1 \s_@@_nil #2 \@@_property_find_err:w
   {
-    \str_clear:N \l__keys_property_str
+    \str_clear:N \l_@@_property_str
     \__kernel_msg_error:nnn { keys } { no-property } {#1}
   }
 %    \end{macrocode}
@@ -2753,6 +2777,10 @@
 %    of groups which apply to a key with the list of those which have been
 %    set active. That requires two mappings, and again a different outcome
 %    depending on whether opt-in or opt-out is set.
+%    We cannot replace the clist mapping by \cs{clist_if_in:NnTF} because
+%    catcodes may not be the same; they cannot be normalized easily in the
+%    clist because of the remote possibility that some items need braces
+%    if they involve commas or leading/trailing spaces.
 %    \begin{macrocode}
 \cs_new_protected:Npn \@@_check_groups:
   {
@@ -3060,7 +3088,7 @@
 %   much faster to just directly strip spaces around |/|.
 %    \begin{macrocode}
 \group_begin:
-  \cs_set:Npn \@@_tmp:n #1
+  \cs_set:Npn \@@_tmp:w #1
     {
       \cs_new:Npn \@@_trim_spaces:n ##1
         {
@@ -3072,7 +3100,7 @@
             \s_@@_mark \@@_trim_spaces_auxiii:w
         }
     }
-  \@@_tmp:n { ~ }
+  \@@_tmp:w { ~ }
 \group_end:
 \cs_new:Npn \@@_trim_spaces_auxi:w #1 ~ / #2 \s_@@_nil #3
   {

Modified: trunk/Master/texmf-dist/source/latex/l3kernel/l3legacy.dtx
===================================================================
--- trunk/Master/texmf-dist/source/latex/l3kernel/l3legacy.dtx	2021-05-25 20:47:33 UTC (rev 59344)
+++ trunk/Master/texmf-dist/source/latex/l3kernel/l3legacy.dtx	2021-05-25 20:48:22 UTC (rev 59345)
@@ -43,7 +43,7 @@
 %    }^^A
 % }
 %
-% \date{Released 2021-05-11}
+% \date{Released 2021-05-25}
 %
 % \maketitle
 %
@@ -63,6 +63,28 @@
 %   \meta{name} of the conditional should \emph{omit} the leading \texttt{if}.
 % \end{function}
 %
+% \begin{function}[added = 2021-05-10]
+%   {
+%     \legacy_if_set_true:n, \legacy_if_set_false:n,
+%     \legacy_if_gset_true:n, \legacy_if_gset_false:n
+%   }
+%   \begin{syntax}
+%     \cs{legacy_if_set_true:n} \Arg{name}
+%     \cs{legacy_if_set_false:n} \Arg{name}
+%   \end{syntax}
+%   Sets the \LaTeXe{}/plain \TeX{} conditional |\if|\meta{name}
+%   (generated by \tn{newif}) to be \texttt{true} or \texttt{false}.
+% \end{function}
+%
+% \begin{function}[added = 2021-05-10]{\legacy_if_set:nn, \legacy_if_gset:nn}
+%   \begin{syntax}
+%     \cs{legacy_if_set:nn} \Arg{name} \Arg{boolexpr}
+%   \end{syntax}
+%   Sets the \LaTeXe{}/plain \TeX{} conditional |\if|\meta{name}
+%   (generated by \tn{newif}) to the result of evaluating the
+%   \meta{boolean expression}.
+% \end{function}
+%
 % \end{documentation}
 %
 % \begin{implementation}
@@ -91,7 +113,41 @@
 %    \end{macrocode}
 % \end{macro}
 %
+% \begin{macro}
+%   {
+%     \legacy_if_set_true:n, \legacy_if_set_false:n,
+%     \legacy_if_gset_true:n, \legacy_if_gset_false:n
+%   }
+%   A friendly wrapper.
 %    \begin{macrocode}
+\cs_new_protected:Npn \legacy_if_set_true:n #1
+  { \cs_set_eq:cN { if#1 } \if_true: }
+\cs_new_protected:Npn \legacy_if_set_false:n #1
+  { \cs_set_eq:cN { if#1 } \if_false: }
+\cs_new_protected:Npn \legacy_if_gset_true:n #1
+  { \cs_gset_eq:cN { if#1 } \if_true: }
+\cs_new_protected:Npn \legacy_if_gset_false:n #1
+  { \cs_gset_eq:cN { if#1 } \if_false: }
+%    \end{macrocode}
+% \end{macro}
+%
+% \begin{macro}{\legacy_if_set:nn, \legacy_if_gset:nn}
+%   A more elaborate wrapper.
+%    \begin{macrocode}
+\cs_new_protected:Npn \legacy_if_set:nn #1#2
+  {
+    \bool_if:nTF {#2} \legacy_if_set_true:n \legacy_if_set_false:n
+    {#1}
+  }
+\cs_new_protected:Npn \legacy_if_gset:nn #1#2
+  {
+    \bool_if:nTF {#2} \legacy_if_gset_true:n \legacy_if_gset_false:n
+    {#1}
+  }
+%    \end{macrocode}
+% \end{macro}
+%
+%    \begin{macrocode}
 %</package>
 %    \end{macrocode}
 %

Modified: trunk/Master/texmf-dist/source/latex/l3kernel/l3luatex.dtx
===================================================================
--- trunk/Master/texmf-dist/source/latex/l3kernel/l3luatex.dtx	2021-05-25 20:47:33 UTC (rev 59344)
+++ trunk/Master/texmf-dist/source/latex/l3kernel/l3luatex.dtx	2021-05-25 20:48:22 UTC (rev 59345)
@@ -43,7 +43,7 @@
 %    }^^A
 % }
 %
-% \date{Released 2021-05-11}
+% \date{Released 2021-05-25}
 %
 % \maketitle
 %

Modified: trunk/Master/texmf-dist/source/latex/l3kernel/l3msg.dtx
===================================================================
--- trunk/Master/texmf-dist/source/latex/l3kernel/l3msg.dtx	2021-05-25 20:47:33 UTC (rev 59344)
+++ trunk/Master/texmf-dist/source/latex/l3kernel/l3msg.dtx	2021-05-25 20:48:22 UTC (rev 59345)
@@ -43,7 +43,7 @@
 %    }^^A
 % }
 %
-% \date{Released 2021-05-11}
+% \date{Released 2021-05-25}
 %
 % \maketitle
 %
@@ -274,6 +274,25 @@
 % course the sense of the message may be impaired). The four arguments are
 % converted to strings before being added to the message text: the
 % \texttt{x}-type variants should be used to expand material.
+% Note that this expansion takes place with the standard definitions in
+% effect, which means that shorthands such as |\~| or |\\| are
+% \emph{not} available; instead one should use \cs{iow_char:N} |\~| and
+% \cs{iow_newline:}, respectively.
+% The following message classes exist:
+% \begin{itemize}
+% \item \texttt{fatal}, ending the \TeX{} run;
+% \item \texttt{critical}, ending the file being input;
+% \item \texttt{error}, interrupting the \TeX{} run without ending it;
+% \item \texttt{warning}, written to terminal and log file, for
+%   important messages that may require corrections by the user;
+% \item \texttt{note} (less common than \texttt{info}) for important
+%   information messages written to the terminal and log file;
+% \item \texttt{info} for normal information messages written to the log
+%   file only;
+% \item \texttt{term} and \texttt{log} for un-decorated messages written
+%   to the terminal and log file, or to the log file only;
+% \item \texttt{none} for suppressed messages.
+% \end{itemize}
 %
 % \begin{function}[updated = 2012-08-11]
 %   {
@@ -365,8 +384,17 @@
 %   is not interrupted.
 % \end{function}
 %
-% \begin{function}[updated = 2012-08-11]
+% \begin{function}[added = 2021-05-18]
 %   {
+%     \msg_note:nnnnnn ,
+%     \msg_note:nnnnn  ,
+%     \msg_note:nnnn   ,
+%     \msg_note:nnn    ,
+%     \msg_note:nn     ,
+%     \msg_note:nnxxxx ,
+%     \msg_note:nnxxx  ,
+%     \msg_note:nnxx   ,
+%     \msg_note:nnx    ,
 %     \msg_info:nnnnnn ,
 %     \msg_info:nnnnn  ,
 %     \msg_info:nnnn   ,
@@ -378,15 +406,28 @@
 %     \msg_info:nnx
 %   }
 %   \begin{syntax}
+%     \cs{msg_note:nnnnnn} \Arg{module} \Arg{message} \Arg{arg one} \Arg{arg two} \Arg{arg three} \Arg{arg four}
 %     \cs{msg_info:nnnnnn} \Arg{module} \Arg{message} \Arg{arg one} \Arg{arg two} \Arg{arg three} \Arg{arg four}
 %   \end{syntax}
 %   Issues \meta{module} information \meta{message}, passing
 %   \meta{arg one} to \meta{arg four} to the text-creating functions.
-%   The information text is added to the log file.
+%   For the more common \cs{msg_info:nnnnnn}, the information text is
+%   added to the log file only, while \cs{msg_note:nnnnnn} adds the
+%   info text to both the log file and the terminal.  The \TeX{} run is
+%   not interrupted.
 % \end{function}
 %
 % \begin{function}[updated = 2012-08-11]
 %   {
+%     \msg_term:nnnnnn ,
+%     \msg_term:nnnnn  ,
+%     \msg_term:nnnn   ,
+%     \msg_term:nnn    ,
+%     \msg_term:nn     ,
+%     \msg_term:nnxxxx ,
+%     \msg_term:nnxxx  ,
+%     \msg_term:nnxx   ,
+%     \msg_term:nnx    ,
 %     \msg_log:nnnnnn ,
 %     \msg_log:nnnnn  ,
 %     \msg_log:nnnn   ,
@@ -398,35 +439,17 @@
 %     \msg_log:nnx
 %   }
 %   \begin{syntax}
+%     \cs{msg_term:nnnnnn} \Arg{module} \Arg{message} \Arg{arg one} \Arg{arg two} \Arg{arg three} \Arg{arg four}
 %     \cs{msg_log:nnnnnn} \Arg{module} \Arg{message} \Arg{arg one} \Arg{arg two} \Arg{arg three} \Arg{arg four}
 %   \end{syntax}
 %   Issues \meta{module} information \meta{message}, passing
 %   \meta{arg one} to \meta{arg four} to the text-creating functions.
-%   The information text is added to the log file: the output
-%   is briefer than \cs{msg_info:nnnnnn}.
+%   The output is briefer than \cs{msg_info:nnnnnn}, omitting for
+%   instance the module name.  It is added to the log file by
+%   \cs{msg_log:nnnnnn} while \cs{msg_term:nnnnnn} also prints it on the
+%   terminal.
 % \end{function}
 %
-% \begin{function}[added = 2020-07-16]
-%   {
-%     \msg_term:nnnnnn ,
-%     \msg_term:nnnnn  ,
-%     \msg_term:nnnn   ,
-%     \msg_term:nnn    ,
-%     \msg_term:nn     ,
-%     \msg_term:nnxxxx ,
-%     \msg_term:nnxxx  ,
-%     \msg_term:nnxx   ,
-%     \msg_term:nnx
-%   }
-%   \begin{syntax}
-%     \cs{msg_term:nnnnnn} \Arg{module} \Arg{message} \Arg{arg one} \Arg{arg two} \Arg{arg three} \Arg{arg four}
-%   \end{syntax}
-%   Issues \meta{module} information \meta{message}, passing
-%   \meta{arg one} to \meta{arg four} to the text-creating functions.
-%   The information text is printed on the terminal (and added to the
-%   log file): the output is similar to that of \cs{msg_log:nnnnnn}.
-% \end{function}
-%
 % \begin{function}[updated = 2012-08-11]
 %   {
 %     \msg_none:nnnnnn ,
@@ -557,6 +580,9 @@
 %   \end{syntax}
 %   Changes the behaviour of messages of \meta{class one} so that they
 %   are processed using the code for those of \meta{class two}.
+%   Each \meta{class} can be one of \texttt{fatal}, \texttt{critical},
+%   \texttt{error}, \texttt{warning}, \texttt{note}, \texttt{info},
+%   \texttt{term}, \texttt{log}, \texttt{none}.
 % \end{function}
 %
 % \begin{function}[updated = 2012-04-27]{\msg_redirect_module:nnn}
@@ -968,7 +994,7 @@
 \cs_new:Npn \@@_text:nn #1#2
   {
     \exp_args:Nf \@@_text:n { \msg_module_type:n {#1} }
-    \msg_module_name:n {#1} ~
+    \exp_args:Nf \@@_text:n { \msg_module_name:n {#1} }
     #2
   }
 \cs_new:Npn \@@_text:n #1
@@ -1193,6 +1219,16 @@
 %
 % \begin{macro}
 %   {
+%     \@@_info_aux:Nnn      ,
+%     \msg_note:nnnnnn ,
+%     \msg_note:nnnnn  ,
+%     \msg_note:nnnn   ,
+%     \msg_note:nnn    ,
+%     \msg_note:nn     ,
+%     \msg_note:nnxxxx ,
+%     \msg_note:nnxxx  ,
+%     \msg_note:nnxx   ,
+%     \msg_note:nnx    ,
 %     \msg_info:nnnnnn ,
 %     \msg_info:nnnnn  ,
 %     \msg_info:nnnn   ,
@@ -1203,19 +1239,26 @@
 %     \msg_info:nnxx   ,
 %     \msg_info:nnx
 %   }
-%   Information only goes into the log.
+%   Information has no decoration and goes either to the log or both
+%   log and terminal.
 %    \begin{macrocode}
+  \@@_class_new:nn { note }
+    {
+      \@@_info_aux:Nnn \iow_term:n {#1}
+        { \use:c { \c_@@_text_prefix_tl #1 / #2 } {#3} {#4} {#5} {#6} }
+    }
   \@@_class_new:nn { info }
     {
-      \str_set:Nx \l_@@_text_str { \msg_info_text:n {#1} }
-      \str_set:Nx \l_@@_name_str { \msg_module_name:n {#1} }
-      \iow_log:n { }
-      \iow_wrap:nxnN
+      \@@_info_aux:Nnn \iow_log:n {#1}
+        { \use:c { \c_@@_text_prefix_tl #1 / #2 } {#3} {#4} {#5} {#6} }
+    }
+  \cs_new_protected:Npn \@@_info_aux:Nnn #1#2#3
+    {
+      \str_set:Nx \l_@@_text_str { \msg_info_text:n {#2} }
+      \str_set:Nx \l_@@_name_str { \msg_module_name:n {#2} }
+      #1 { }
+      \iow_wrap:nxnN { \l_@@_text_str : ~ #3 }
         {
-          \l_@@_text_str : ~
-          \use:c { \c_@@_text_prefix_tl #1 / #2 } {#3} {#4} {#5} {#6}
-        }
-        {
           ( \l_@@_name_str )
           \prg_replicate:nn
              {
@@ -1224,8 +1267,8 @@
              }
             { ~ }
          }
-         { } \iow_log:n
-      \iow_log:n { }
+         { } #1
+       #1 { }
     }
 %    \end{macrocode}
 % \end{macro}
@@ -1761,6 +1804,7 @@
 % \begin{macro}
 %   {
 %     \__kernel_msg_log:nnnnnn, \__kernel_msg_log:nnxxxx,
+%     \__kernel_msg_term:nnnnnn, \__kernel_msg_term:nnxxxx,
 %     \__kernel_msg_show:nnnnnn, \__kernel_msg_show:nnxxxx
 %   }
 %   For showing messages.
@@ -1768,6 +1812,9 @@
 \cs_new_protected:Npn \__kernel_msg_log:nnnnnn #1
   { \msg_log:nnnnnn { LaTeX / #1 } }
 \cs_generate_variant:Nn \__kernel_msg_log:nnnnnn { nnxxxx }
+\cs_new_protected:Npn \__kernel_msg_term:nnnnnn #1
+  { \msg_term:nnnnnn { LaTeX / #1 } }
+\cs_generate_variant:Nn \__kernel_msg_term:nnnnnn { nnxxxx }
 \cs_new_protected:Npn \__kernel_msg_show:nnnnnn #1
   { \msg_show:nnnnnn { LaTeX / #1 } }
 \cs_generate_variant:Nn \__kernel_msg_show:nnnnnn { nnxxxx }
@@ -1865,6 +1912,7 @@
     \c_@@_coding_error_text_tl
     Functions~defined~through~\iow_char:N\\cs_new:Nn~must~have~
     a~signature~consisting~of~only~normal~arguments~'N'~and~'n'.~
+    The~signature~'#2'~of~'#1'~contains~other~arguments~'#3'.~
     To~define~variants~use~\iow_char:N\\cs_generate_variant:Nn~
     and~to~define~other~functions~use~\iow_char:N\\cs_new:Npn.
   }
@@ -1986,7 +2034,7 @@
 \__kernel_msg_new:nnnn { quark } { invalid-function }
   { Quark~test~function~'#1'~is~invalid. }
   {
-    \c__msg_coding_error_text_tl
+    \c_@@_coding_error_text_tl
     LaTeX~has~been~asked~to~create~quark~test~function~'#1'~
     \tl_if_empty:nTF {#2}
       { but~that~name~ }

Modified: trunk/Master/texmf-dist/source/latex/l3kernel/l3names.dtx
===================================================================
--- trunk/Master/texmf-dist/source/latex/l3kernel/l3names.dtx	2021-05-25 20:47:33 UTC (rev 59344)
+++ trunk/Master/texmf-dist/source/latex/l3kernel/l3names.dtx	2021-05-25 20:48:22 UTC (rev 59345)
@@ -43,7 +43,7 @@
 %    }^^A
 % }
 %
-% \date{Released 2021-05-11}
+% \date{Released 2021-05-25}
 %
 % \maketitle
 %

Modified: trunk/Master/texmf-dist/source/latex/l3kernel/l3pdf.dtx
===================================================================
--- trunk/Master/texmf-dist/source/latex/l3kernel/l3pdf.dtx	2021-05-25 20:47:33 UTC (rev 59344)
+++ trunk/Master/texmf-dist/source/latex/l3kernel/l3pdf.dtx	2021-05-25 20:48:22 UTC (rev 59345)
@@ -43,7 +43,7 @@
 %    }^^A
 % }
 %
-% \date{Released 2021-05-11}
+% \date{Released 2021-05-25}
 %
 % \maketitle
 %

Modified: trunk/Master/texmf-dist/source/latex/l3kernel/l3prg.dtx
===================================================================
--- trunk/Master/texmf-dist/source/latex/l3kernel/l3prg.dtx	2021-05-25 20:47:33 UTC (rev 59344)
+++ trunk/Master/texmf-dist/source/latex/l3kernel/l3prg.dtx	2021-05-25 20:48:22 UTC (rev 59345)
@@ -43,7 +43,7 @@
 %    }^^A
 % }
 %
-% \date{Released 2021-05-11}
+% \date{Released 2021-05-25}
 %
 % \maketitle
 %

Modified: trunk/Master/texmf-dist/source/latex/l3kernel/l3prop.dtx
===================================================================
--- trunk/Master/texmf-dist/source/latex/l3kernel/l3prop.dtx	2021-05-25 20:47:33 UTC (rev 59344)
+++ trunk/Master/texmf-dist/source/latex/l3kernel/l3prop.dtx	2021-05-25 20:48:22 UTC (rev 59345)
@@ -43,7 +43,7 @@
 %    }^^A
 % }
 %
-% \date{Released 2021-05-11}
+% \date{Released 2021-05-25}
 %
 % \maketitle
 %
@@ -51,10 +51,11 @@
 %
 % \LaTeX3 implements a \enquote{property list} data type, which contain
 % an unordered list of entries each of which consists of a \meta{key} and
-% an associated \meta{value}. The \meta{key} and \meta{value} may both be
-% any \meta{balanced text}. It is possible to map functions to property lists
-% such that the function is applied to every key--value pair within
-% the list.
+% an associated \meta{value}. The \meta{key} and \meta{value} may both
+% be any \meta{balanced text}, but the \meta{key} is processed using
+% \cs{tl_to_str:n}, meaning that category codes are ignored. It is
+% possible to map functions to property lists such that the function is
+% applied to every key--value pair within the list.
 %
 % Each entry in a property list must have a unique \meta{key}: if an entry is
 % added to a property list which already contains the \meta{key} then the new
@@ -63,7 +64,7 @@
 %
 % Property lists are intended for storing key-based information for use within
 % code.  This is in contrast to key--value lists, which are a form of
-% \emph{input} parsed by the \pkg{keys} module.
+% \emph{input} parsed by the \pkg{l3keys} module.
 %
 % \section{Creating and initialising property lists}
 %
@@ -124,6 +125,12 @@
 %   \end{syntax}
 %   Sets \meta{prop~var} to contain key--value pairs given in the second
 %   argument.  If duplicate keys appear only one of the values is kept.
+%
+%   Spaces are trimmed around every \meta{key} and every \meta{value},
+%   and if the result of trimming spaces consists of a single brace
+%   group then a set of outer braces is removed.  This enables both the
+%   \meta{key} and the \meta{value} to contain spaces, commas or equal
+%   signs.  The \meta{key} is then processed by \cs{tl_to_str:n}.
 % \end{function}
 %
 % \begin{function}[added = 2017-11-28, updated = 2019-08-25]
@@ -137,11 +144,12 @@
 %   \end{syntax}
 %   Creates a new constant \meta{prop~var} or raises an error if the
 %   name is already taken. The \meta{prop~var} is set globally to
-%   contain key--value pairs given in the second argument.
-%   If duplicate keys appear only one of the values is kept.
+%   contain key--value pairs given in the second argument, processed in
+%   the way described for \cs{prop_set_from_keyval:Nn}.  If duplicate
+%   keys appear only one of the values is kept.
 % \end{function}
 %
-% \section{Adding entries to property lists}
+% \section{Adding and updating property list entries}
 %
 % \begin{function}[updated = 2012-07-09]
 %   {
@@ -162,12 +170,12 @@
 %     \cs{prop_put:Nnn} \meta{property list} \Arg{key} \Arg{value}
 %   \end{syntax}
 %   Adds an entry to the \meta{property list} which may be accessed
-%   using the \meta{key} and which has \meta{value}. Both the \meta{key}
-%   and \meta{value} may contain any \meta{balanced text}. The \meta{key}
-%   is stored after processing with \cs{tl_to_str:n}, meaning that
-%   category codes are ignored. If the \meta{key} is already present
-%   in the \meta{property list}, the existing entry is overwritten
-%   by the new \meta{value}.
+%   using the \meta{key} and which has \meta{value}. If the \meta{key}
+%   is already present in the \meta{property list}, the existing entry
+%   is overwritten by the new \meta{value}. Both the \meta{key} and
+%   \meta{value} may contain any \meta{balanced text}. The \meta{key} is
+%   stored after processing with \cs{tl_to_str:n}, meaning that category
+%   codes are ignored.
 % \end{function}
 %
 % \begin{function}
@@ -178,14 +186,53 @@
 %   \begin{syntax}
 %     \cs{prop_put_if_new:Nnn} \meta{property list} \Arg{key} \Arg{value}
 %   \end{syntax}
-%   If the \meta{key} is present in the \meta{property list} then
-%   no action is taken. If the \meta{key} is not present in the
-%   \meta{property list} then a new entry is added. Both the \meta{key}
-%   and \meta{value} may contain any \meta{balanced text}. The \meta{key}
-%   is stored after processing with \cs{tl_to_str:n}, meaning that
-%   category codes are ignored.
+%   If the \meta{key} is present in the \meta{property list} then no
+%   action is taken. Otherwise, a new entry is added as described for
+%   \cs{prop_put:Nnn}.
 % \end{function}
 %
+% \begin{function}[added = 2021-05-16]
+%   {
+%     \prop_concat:NNN,  \prop_concat:ccc,
+%     \prop_gconcat:NNN, \prop_gconcat:ccc
+%   }
+%   \begin{syntax}
+%     \cs{prop_concat:NNN} \meta{prop~var_1} \meta{prop~var_2} \meta{prop~var_3}
+%   \end{syntax}
+%   Combines the key--value pairs of \meta{prop~var_2} and
+%   \meta{prop~var_3}, and saves the result in \meta{prop~var_1}.  If a
+%   key appears in both \meta{prop~var_2} and \meta{prop~var_3} then the
+%   last value, namely the value in \meta{prop~var_3} is kept while the
+%   other is discarded.
+% \end{function}
+%
+% \begin{function}[added = 2021-05-16]
+%   {
+%     \prop_put_from_keyval:Nn, \prop_put_from_keyval:cn,
+%     \prop_gput_from_keyval:Nn, \prop_gput_from_keyval:cn,
+%   }
+%   \begin{syntax}
+%     \cs{prop_put_from_keyval:Nn} \meta{prop~var}
+%       \{
+%         \meta{key1} |=| \meta{value1} |,|
+%         \meta{key2} |=| \meta{value2} |,| \ldots{}
+%       \}
+%   \end{syntax}
+%   Updates the \meta{prop~var} by adding entries for each key--value
+%   pair given in the second argument.  The addition is done through
+%   \cs{prop_put:Nnn}, hence if the \meta{prop~var} already contains
+%   some of the keys, the corresponding values are discarded and
+%   replaced by those given in the key--value list.  If duplicate keys
+%   appear in the key--value list then only one of the values is kept.
+%
+%   The function is equivalent to storing the key--value pairs in a
+%   temporary property variable using \cs{prop_set_from_keyval:Nn}, then
+%   combining \meta{prop~var} with the temporary variable using
+%   \cs{prop_concat:NNN}.  In particular, the \meta{keys} and
+%   \meta{values} are space-trimmed and unbraced as described in
+%   \cs{prop_set_from_keyval:Nn}.
+% \end{function}
+%
 % \section{Recovering values from property lists}
 %
 % \begin{function}[updated = 2011-08-28]
@@ -722,15 +769,42 @@
 % \end{variable}
 %
 % \begin{variable}{\l_@@_internal_prop}
-%   Property list used by \cs{prop_set_from_keyval:Nn} and others.
+%   Property list used by \cs{prop_concat:NNN},
+%   \cs{prop_set_from_keyval:Nn} and others.
 %    \begin{macrocode}
 \prop_new:N \l_@@_internal_prop
 %    \end{macrocode}
 % \end{variable}
 %
+% \begin{macro}
+%   {
+%     \prop_concat:NNN, \prop_concat:ccc,
+%     \prop_gconcat:NNN, \prop_gconcat:ccc, \@@_concat:NNNN
+%   }
+%   Combine two property lists.  We cannot use a simple
+%   \cs{tl_concat:NNN} because there may be some duplicate keys between
+%   the two property lists.
+%    \begin{macrocode}
+\cs_new_protected:Npn \prop_concat:NNN
+  { \@@_concat:NNNN \prop_set_eq:NN }
+\cs_generate_variant:Nn \prop_concat:NNN { ccc }
+\cs_new_protected:Npn \prop_gconcat:NNN
+  { \@@_concat:NNNN \prop_gset_eq:NN }
+\cs_generate_variant:Nn \prop_gconcat:NNN { ccc }
+\cs_new_protected:Npn \@@_concat:NNNN #1#2#3#4
+  {
+    \prop_set_eq:NN \l_@@_internal_prop #3
+    \prop_map_tokens:Nn #4 { \prop_put:Nnn \l_@@_internal_prop }
+    #1 #2 \l_@@_internal_prop
+  }
+%    \end{macrocode}
+% \end{macro}
+%
 % \begin{macro}{\prop_set_from_keyval:Nn, \prop_set_from_keyval:cn}
 % \begin{macro}{\prop_gset_from_keyval:Nn, \prop_gset_from_keyval:cn}
 % \begin{macro}{\prop_const_from_keyval:Nn, \prop_const_from_keyval:cn}
+% \begin{macro}{\prop_put_from_keyval:Nn, \prop_put_from_keyval:cn}
+% \begin{macro}{\prop_gput_from_keyval:Nn, \prop_gput_from_keyval:cn}
 % \begin{macro}
 %   {
 %     \@@_from_keyval:n,
@@ -783,6 +857,22 @@
     \prop_clear:N \l_@@_internal_prop
   }
 \cs_generate_variant:Nn \prop_const_from_keyval:Nn { c }
+\cs_new_protected:Npn \prop_put_from_keyval:Nn #1#2
+  {
+    \prop_set_eq:NN \l_@@_internal_prop #1
+    \@@_from_keyval:n {#2}
+    \prop_set_eq:NN #1 \l_@@_internal_prop
+    \prop_clear:N \l_@@_internal_prop
+  }
+\cs_generate_variant:Nn \prop_put_from_keyval:Nn { c }
+\cs_new_protected:Npn \prop_gput_from_keyval:Nn #1#2
+  {
+    \prop_set_eq:NN \l_@@_internal_prop #1
+    \@@_from_keyval:n {#2}
+    \prop_gset_eq:NN #1 \l_@@_internal_prop
+    \prop_clear:N \l_@@_internal_prop
+  }
+\cs_generate_variant:Nn \prop_gput_from_keyval:Nn { c }
 \cs_new_protected:Npn \@@_from_keyval:n #1
   {
     \@@_from_keyval_loop:w \prg_do_nothing: #1 ,
@@ -808,10 +898,10 @@
   { \@@_from_keyval_value:w #1 \s_@@_mark }
 \cs_new_protected:Npn \@@_from_keyval_value:w #1 \s_@@_mark #2 \s_@@_stop #3#4
   {
-    \tl_if_empty:nF { #3 #1 #2 }
+    \tl_if_single:nTF {#2}
+      { \prop_put:Nnn \l_@@_internal_prop {#3} {#1} }
       {
-        \str_if_eq:nnTF {#2} { = }
-          { \prop_put:Nnn \l_@@_internal_prop {#3} {#1} }
+        \tl_if_empty:nF { #3 #1 #2 }
           {
             \__kernel_msg_error:nnx { prop } { prop-keyval }
               { \exp_not:o {#4} }
@@ -823,6 +913,8 @@
 % \end{macro}
 % \end{macro}
 % \end{macro}
+% \end{macro}
+% \end{macro}
 %
 % \subsection{Accessing data in property lists}
 %
@@ -956,29 +1048,22 @@
 % \end{macro}
 %
 % \begin{macro}[EXP]{\prop_item:Nn, \prop_item:cn}
-% \begin{macro}[EXP]{\@@_item_Nn:nwwn}
+% \begin{macro}[EXP]{\@@_item:nnn}
 %   Getting the value corresponding to a key in a property list in an
-%   expandable fashion is similar to mapping some tokens.  Go through
-%   the property list one \meta{key}--\meta{value} pair at a time: the
-%   arguments of \cs{@@_item_Nn:nwn} are the \meta{key} we are looking
-%   for, a \meta{key} of the property list, and its associated value.
-%   The \meta{keys} are compared (as strings).  If they match, the
-%   \meta{value} is returned, within \cs{exp_not:n}.  The loop
-%   terminates even if the \meta{key} is missing, and yields an empty
-%   value, because we have appended the appropriate
-%   \meta{key}--\meta{empty value} pair to the property list.
+%   expandable fashion simply uses \cs{prop_map_tokens:Nn} to go through
+%   the property list.  The auxiliary \cs{@@_item:nnn} receives the
+%   search string~|#1|, the key~|#2| and the value~|#3| and returns as
+%   appropriate.
 %    \begin{macrocode}
 \cs_new:Npn \prop_item:Nn #1#2
   {
-    \exp_last_unbraced:Noo \@@_item_Nn:nwwn { \tl_to_str:n {#2} } #1
-      \@@_pair:wn \tl_to_str:n {#2} \s_@@ { }
-    \prg_break_point:
+    \exp_args:NNo \prop_map_tokens:Nn #1
+      { \exp_after:wN \@@_item:nnn \exp_after:wN { \tl_to_str:n {#2} } }
   }
-\cs_new:Npn \@@_item_Nn:nwwn #1#2 \@@_pair:wn #3 \s_@@ #4
+\cs_new:Npn \@@_item:nnn #1#2#3
   {
-    \str_if_eq:eeTF {#1} {#3}
-      { \prg_break:n { \exp_not:n {#4} } }
-      { \@@_item_Nn:nwwn {#1} }
+    \str_if_eq:eeT {#1} {#2}
+      { \prop_map_break:n { \exp_not:n {#3} } }
   }
 \cs_generate_variant:Nn \prop_item:Nn { c }
 %    \end{macrocode}
@@ -1159,7 +1244,7 @@
 %     \prop_if_in:Nn, \prop_if_in:NV, \prop_if_in:No,
 %     \prop_if_in:cn, \prop_if_in:cV, \prop_if_in:co
 %   }
-% \begin{macro}[EXP]{\@@_if_in:nwwn, \@@_if_in:N}
+% \begin{macro}[EXP]{\@@_if_in:nnn}
 %   Testing expandably if a key is in a property list
 %   requires to go through the key--value pairs one by one.
 %   This is rather slow, and a faster test would be
@@ -1172,45 +1257,20 @@
 %       }
 %   \end{verbatim}
 %   but \cs{@@_split:NnTF} is non-expandable.
-%
-%   Instead, the key is compared to each key in turn using
-%   \cs{str_if_eq:ee}, which is expandable.  To terminate the mapping,
-%   we append to the property list the key that is searched for.  This
-%   second \cs{tl_to_str:n} is not expanded at the start, but only when
-%   included in the \cs{str_if_eq:ee}.  It cannot make the breaking
-%   mechanism choke, because the arbitrary token list material is
-%   enclosed in braces.  The second argument of \cs{@@_if_in:nwwn} is
-%   most often empty.  When the \meta{key} is found in the list,
-%   \cs{@@_if_in:N} receives \cs{@@_pair:wn}, and if it is
-%   found as the extra item, the function receives
-%   \cs{q_@@_recursion_tail}, easily recognizable.
-%
-%   Here, \cs{prop_map_function:NN} is not sufficient for the mapping,
-%   since it can only map a single token, and cannot carry the key that
-%   is searched for.
+%   Instead, we use \cs{prop_map_tokens:Nn} to compare the search key to
+%   each key in turn using \cs{str_if_eq:ee}, which is expandable.
 %    \begin{macrocode}
 \prg_new_conditional:Npnn \prop_if_in:Nn #1#2 { p , T , F , TF }
   {
-    \exp_last_unbraced:Noo \@@_if_in:nwwn { \tl_to_str:n {#2} } #1
-      \@@_pair:wn \tl_to_str:n {#2} \s_@@ { }
-      \q_@@_recursion_tail
-    \prg_break_point:
+    \exp_args:NNo \prop_map_tokens:Nn #1
+      { \exp_after:wN \@@_if_in:nnn \exp_after:wN { \tl_to_str:n {#2} } }
+    \prg_return_false:
   }
-\cs_new:Npn \@@_if_in:nwwn #1#2 \@@_pair:wn #3 \s_@@ #4
+\cs_new:Npn \@@_if_in:nnn #1#2#3
   {
-    \str_if_eq:eeTF {#1} {#3}
-      { \@@_if_in:N }
-      { \@@_if_in:nwwn {#1} }
+    \str_if_eq:eeT {#1} {#2}
+      { \prop_map_break:n { \use_i:nn \prg_return_true: } }
   }
-\cs_new:Npn \@@_if_in:N #1
-  {
-    \if_meaning:w \q_@@_recursion_tail #1
-      \prg_return_false:
-    \else:
-      \prg_return_true:
-    \fi:
-    \prg_break:
-  }
 \prg_generate_conditional_variant:Nnn \prop_if_in:Nn
   { NV , No , c , cV , co } { p , T , F , TF }
 %    \end{macrocode}
@@ -1249,25 +1309,36 @@
 %     \prop_map_function:NN, \prop_map_function:Nc,
 %     \prop_map_function:cN, \prop_map_function:cc
 %   }
-% \begin{macro}{\@@_map_function:Nwwn}
-%   The argument delimited by \cs{@@_pair:wn} is empty except at the end
-%   of the loop where it is \cs{prg_break:}.  No need for any quark
-%   test.
+% \begin{macro}{\@@_map_function:Nw}
+%   The even-numbered arguments of \cs{@@_map_function:Nw} are keys,
+%   hence have string catcodes, except at the end where they are
+%   \cs{fi:} \cs{prop_map_break:}.  The \cs{fi:} ends the \cs{if_false:}
+%   |#|\meta{even} \cs{fi:} construction and we jump out of the loop.
+%   No need for any quark test.
 %    \begin{macrocode}
 \cs_new:Npn \prop_map_function:NN #1#2
   {
     \exp_after:wN \use_i_ii:nnn
-    \exp_after:wN \@@_map_function:Nwwn
+    \exp_after:wN \@@_map_function:Nw
     \exp_after:wN #2
     #1
-    \prg_break: \@@_pair:wn \s_@@ { } \prg_break_point:
+    \@@_pair:wn \fi: \prop_map_break: \s_@@ { }
+    \@@_pair:wn \fi: \prop_map_break: \s_@@ { }
+    \@@_pair:wn \fi: \prop_map_break: \s_@@ { }
+    \@@_pair:wn \fi: \prop_map_break: \s_@@ { }
     \prg_break_point:Nn \prop_map_break: { }
   }
-\cs_new:Npn \@@_map_function:Nwwn #1#2 \@@_pair:wn #3 \s_@@ #4
+\cs_new:Npn \@@_map_function:Nw #1
+    \@@_pair:wn #2 \s_@@ #3
+    \@@_pair:wn #4 \s_@@ #5
+    \@@_pair:wn #6 \s_@@ #7
+    \@@_pair:wn #8 \s_@@ #9
   {
-    #2
-    #1 {#3} {#4}
-    \@@_map_function:Nwwn #1
+    \if_false: #2 \fi: #1 {#2} {#3}
+    \if_false: #4 \fi: #1 {#4} {#5}
+    \if_false: #6 \fi: #1 {#6} {#7}
+    \if_false: #8 \fi: #1 {#8} {#9}
+    \@@_map_function:Nw #1
   }
 \cs_generate_variant:Nn \prop_map_function:NN { Nc , c , cc }
 %    \end{macrocode}
@@ -1303,26 +1374,35 @@
 % \end{macro}
 %
 % \begin{macro}[rEXP]{\prop_map_tokens:Nn, \prop_map_tokens:cn}
-% \begin{macro}{\@@_map_tokens:nwwn}
+% \begin{macro}{\@@_map_tokens:nw}
 %   The mapping is very similar to \cs{prop_map_function:NN}.  The
 %   \cs{use_i:nn} removes the leading \cs{s_@@}.  The odd construction
 %   |\use:n {#1}| allows |#1| to contain any token without interfering
-%   with \cs{prop_map_break:}.  The loop stops when the argument
-%   delimited by \cs{@@_pair:wn} is \cs{prg_break:} instead of being
-%   empty.
+%   with \cs{prop_map_break:}.  The loop stops when the \meta{key}
+%   between \cs{@@_pair:wn} and \cs{s_@@} is \cs{fi:}
+%   \cs{prop_map_break:} instead of being a string.
 %    \begin{macrocode}
 \cs_new:Npn \prop_map_tokens:Nn #1#2
   {
     \exp_last_unbraced:Nno
-      \use_i:nn { \@@_map_tokens:nwwn {#2} } #1
-      \prg_break: \@@_pair:wn \s_@@ { } \prg_break_point:
+      \use_i:nn { \@@_map_tokens:nw {#2} } #1
+    \@@_pair:wn \fi: \prop_map_break: \s_@@ { }
+    \@@_pair:wn \fi: \prop_map_break: \s_@@ { }
+    \@@_pair:wn \fi: \prop_map_break: \s_@@ { }
+    \@@_pair:wn \fi: \prop_map_break: \s_@@ { }
     \prg_break_point:Nn \prop_map_break: { }
   }
-\cs_new:Npn \@@_map_tokens:nwwn #1#2 \@@_pair:wn #3 \s_@@ #4
+\cs_new:Npn \@@_map_tokens:nw #1
+    \@@_pair:wn #2 \s_@@ #3
+    \@@_pair:wn #4 \s_@@ #5
+    \@@_pair:wn #6 \s_@@ #7
+    \@@_pair:wn #8 \s_@@ #9
   {
-    #2
-    \use:n {#1} {#3} {#4}
-    \@@_map_tokens:nwwn {#1}
+    \if_false: #2 \fi: \use:n {#1} {#2} {#3}
+    \if_false: #4 \fi: \use:n {#1} {#4} {#5}
+    \if_false: #6 \fi: \use:n {#1} {#6} {#7}
+    \if_false: #8 \fi: \use:n {#1} {#8} {#9}
+    \@@_map_tokens:nw {#1}
   }
 \cs_generate_variant:Nn \prop_map_tokens:Nn { c }
 %    \end{macrocode}

Modified: trunk/Master/texmf-dist/source/latex/l3kernel/l3quark.dtx
===================================================================
--- trunk/Master/texmf-dist/source/latex/l3kernel/l3quark.dtx	2021-05-25 20:47:33 UTC (rev 59344)
+++ trunk/Master/texmf-dist/source/latex/l3kernel/l3quark.dtx	2021-05-25 20:48:22 UTC (rev 59345)
@@ -43,7 +43,7 @@
 %    }^^A
 % }
 %
-% \date{Released 2021-05-11}
+% \date{Released 2021-05-25}
 %
 % \maketitle
 %
@@ -55,7 +55,8 @@
 %
 % \section{Quarks}
 %
-% Quarks are control sequences that expand to themselves and should
+% Quarks are control sequences (and in fact, token lists) that expand
+% to themselves and should
 % therefore \emph{never} be executed directly in the code.
 % This would result in an endless loop!
 %
@@ -90,8 +91,6 @@
 % \cs{tl_if_eq:NNTF}. A set of special quark testing functions is set up
 % below. All the quark testing functions are expandable although the
 % ones testing only single tokens are much faster.
-% An example of the quark testing functions and their use in recursion
-% can be seen in the implementation of \cs{clist_map_function:NN}.
 %
 % \section{Defining quarks}
 %

Modified: trunk/Master/texmf-dist/source/latex/l3kernel/l3regex.dtx
===================================================================
--- trunk/Master/texmf-dist/source/latex/l3kernel/l3regex.dtx	2021-05-25 20:47:33 UTC (rev 59344)
+++ trunk/Master/texmf-dist/source/latex/l3kernel/l3regex.dtx	2021-05-25 20:48:22 UTC (rev 59345)
@@ -43,7 +43,7 @@
 %    }^^A
 % }
 %
-% \date{Released 2021-05-11}
+% \date{Released 2021-05-25}
 %
 % \maketitle
 %
@@ -1574,7 +1574,7 @@
       \tl_put_right:Nx \l_@@_internal_a_tl
         {
           \exp_after:wN \@@_escape_loop:N \g_@@_internal_tl
-          { break } \prg_break_point:
+          \scan_stop: \prg_break_point:
         }
       \exp_after:wN
     \group_end:
@@ -1620,7 +1620,7 @@
 %
 % \begin{macro}
 %   {
-%     \@@_escape_break:w, \@@_escape_/break:w,
+%     \@@_escape_\scan_stop::w, \@@_escape_/\scan_stop::w,
 %     \@@_escape_/a:w, \@@_escape_/e:w, \@@_escape_/f:w,
 %     \@@_escape_/n:w, \@@_escape_/r:w, \@@_escape_/t:w
 %   }
@@ -1630,8 +1630,8 @@
 %   backslash.  Spaces are ignored, and |\a|, |\e|, |\f|, |\n|, |\r|,
 %   |\t| take their meaning here.
 %    \begin{macrocode}
-\cs_new_eq:NN \@@_escape_break:w \prg_break:
-\cs_new:cpn { @@_escape_/break:w }
+\cs_new_eq:cN { @@_escape_ \iow_char:N\\scan_stop: :w } \prg_break:
+\cs_new:cpn { @@_escape_/ \iow_char:N\\scan_stop: :w }
   {
     \__kernel_msg_expandable_error:nn { regex } { trailing-backslash }
     \prg_break:
@@ -1691,7 +1691,10 @@
 %    \begin{macrocode}
 \cs_new:Npn \@@_escape_x_test:N #1
   {
-    \str_if_eq:nnTF {#1} { break } { ; }
+    \if_meaning:w \scan_stop: #1
+      \exp_after:wN \use_i:nnn \exp_after:wN ;
+    \fi:
+    \use:n
       {
         \if_charcode:w \c_space_token #1
           \exp_after:wN \@@_escape_x_test:N
@@ -1719,7 +1722,10 @@
 %    \begin{macrocode}
 \cs_new:Npn \@@_escape_x:N #1
   {
-    \str_if_eq:nnTF {#1} { break } { ; }
+    \if_meaning:w \scan_stop: #1
+      \exp_after:wN \use_i:nnn \exp_after:wN ;
+    \fi:
+    \use:n
       {
         \@@_hexadecimal_use:NTF #1
           { ; \@@_escape_loop:N }
@@ -1736,7 +1742,10 @@
 %    \begin{macrocode}
 \cs_new:Npn \@@_escape_x_loop:N #1
   {
-    \str_if_eq:nnTF {#1} { break }
+    \if_meaning:w \scan_stop: #1
+      \exp_after:wN \use_ii:nnn
+    \fi:
+    \use_ii:nn
       { ; \@@_escape_x_loop_error:n { } {#1} }
       {
         \@@_hexadecimal_use:NTF #1
@@ -2251,7 +2260,7 @@
           \prg_do_nothing: \prg_do_nothing:
         }
         { }
-      \if_int_compare:w \l_@@_group_level_int > 0 \exp_stop_f:
+      \if_int_compare:w \l_@@_group_level_int > \c_zero_int
         \__kernel_msg_error:nnx { regex } { missing-rparen }
           { \int_use:N \l_@@_group_level_int }
         \prg_replicate:nn
@@ -3017,7 +3026,7 @@
   }
 \cs_new_protected:Npn \@@_compile_group_end:
   {
-    \if_int_compare:w \l_@@_group_level_int > 0 \exp_stop_f:
+    \if_int_compare:w \l_@@_group_level_int > \c_zero_int
         \tl_build_put_right:Nn \l_@@_build_tl { \if_false: { \fi: } }
         \tl_build_end:N \l_@@_build_tl
         \exp_args:NNNx
@@ -3597,7 +3606,7 @@
           {
             \@@_class:NnnnN \c_true_bool
               {
-                \if_int_compare:w "##3 = 0 \exp_stop_f:
+                \if_int_compare:w "##3 = \c_zero_int
                   \@@_item_exact_cs:n
                     { \exp_after:wN \cs_to_str:N ##1 }
                 \else:
@@ -4314,7 +4323,7 @@
 %    \begin{macrocode}
 \cs_new_protected:Npn \@@_class_repeat:nN #1#2
   {
-    \if_int_compare:w #1 = 0 \exp_stop_f:
+    \if_int_compare:w #1 = \c_zero_int
       \@@_build_transitions_lazyness:NNNNN #2
         \@@_action_free:n       \l_@@_right_state_int
         \@@_tests_action_cost:n \l_@@_left_state_int
@@ -4374,9 +4383,8 @@
 %    \begin{macrocode}
 \cs_new_protected:Npn \@@_group_aux:nnnnN #1#2#3#4#5
   {
-      \if_int_compare:w #3 = 0 \exp_stop_f:
+      \if_int_compare:w #3 = \c_zero_int
         \@@_build_new_state:
-%<assert>\assert_int:n { \l_@@_max_state_int = \l_@@_right_state_int + 1 }
         \@@_build_transition_right:nNn \@@_action_free_group:n
           \l_@@_left_state_int \l_@@_right_state_int
       \fi:
@@ -4479,7 +4487,7 @@
 %    \begin{macrocode}
 \cs_new_protected:Npn \@@_group_repeat:nn #1#2
   {
-    \if_int_compare:w #2 = 0 \exp_stop_f:
+    \if_int_compare:w #2 = \c_zero_int
       \int_set:Nn \l_@@_max_state_int
         { \l_@@_left_state_int - 1 }
       \@@_build_new_state:
@@ -4499,7 +4507,7 @@
 %    \begin{macrocode}
 \cs_new_protected:Npn \@@_group_submatches:nNN #1#2#3
   {
-    \if_int_compare:w #1 > - 1 \exp_stop_f:
+    \if_int_compare:w #1 > - \c_one_int
       \@@_toks_put_left:Nx #2 { \@@_action_submatch:nN {#1} < }
       \@@_toks_put_left:Nx #3 { \@@_action_submatch:nN {#1} > }
     \fi:
@@ -4523,7 +4531,7 @@
       \l_@@_right_state_int \l_@@_max_state_int
     \int_set_eq:NN \l_@@_internal_a_int \l_@@_left_state_int
     \int_set_eq:NN \l_@@_internal_b_int \l_@@_max_state_int
-    \if_int_compare:w \int_eval:n {#1} > 1 \exp_stop_f:
+    \if_int_compare:w \int_eval:n {#1} > \c_one_int
       \int_set:Nn \l_@@_internal_c_int
         {
           ( #1 - 1 )
@@ -4562,7 +4570,7 @@
 %    \begin{macrocode}
 \cs_new_protected:Npn \@@_group_repeat:nnN #1#2#3
   {
-    \if_int_compare:w #2 = 0 \exp_stop_f:
+    \if_int_compare:w #2 = \c_zero_int
       \@@_group_submatches:nNN {#1}
         \l_@@_left_state_int \l_@@_right_state_int
       \int_set:Nn \l_@@_internal_a_int
@@ -4633,7 +4641,7 @@
           \@@_build_transition_right:nNn \@@_action_free:n
             \l_@@_right_state_int \l_@@_max_state_int
         }
-      \if_int_compare:w #2 = 0 \exp_stop_f:
+      \if_int_compare:w #2 = \c_zero_int
         \int_set:Nn \l_@@_right_state_int
           { \l_@@_left_state_int - 1 }
       \else:
@@ -5588,7 +5596,7 @@
         { \@@_replacement_normal:n ##1 }
         {#1}
       \prg_do_nothing: \prg_do_nothing:
-      \if_int_compare:w \l_@@_replacement_csnames_int > 0 \exp_stop_f:
+      \if_int_compare:w \l_@@_replacement_csnames_int > \c_zero_int
         \__kernel_msg_error:nnx { regex } { replacement-missing-rbrace }
           { \int_use:N \l_@@_replacement_csnames_int }
         \tl_build_put_right:Nx \l_@@_build_tl
@@ -5747,7 +5755,7 @@
   {
     \tl_build_put_right:Nn \l_@@_build_tl
       { \@@_query_submatch:n { \int_eval:n { #1 + ##1 } } }
-    \if_int_compare:w \l_@@_replacement_csnames_int = 0 \exp_stop_f:
+    \if_int_compare:w \l_@@_replacement_csnames_int = \c_zero_int
       \tl_put_right:Nn \l_@@_balance_tl
         {
           + \@@_submatch_balance:n
@@ -5869,7 +5877,7 @@
 %    \begin{macrocode}
 \cs_new_protected:Npn \@@_replacement_rbrace:N #1
   {
-    \if_int_compare:w \l_@@_replacement_csnames_int > 0 \exp_stop_f:
+    \if_int_compare:w \l_@@_replacement_csnames_int > \c_zero_int
       \tl_build_put_right:Nn \l_@@_build_tl { \cs_end: }
       \int_decr:N \l_@@_replacement_csnames_int
     \else:
@@ -5885,7 +5893,7 @@
 %    \begin{macrocode}
 \cs_new_protected:Npn \@@_replacement_lbrace:N #1
   {
-    \if_int_compare:w \l_@@_replacement_csnames_int > 0 \exp_stop_f:
+    \if_int_compare:w \l_@@_replacement_csnames_int > \c_zero_int
       \__kernel_msg_error:nnn { regex } { cu-lbrace } { u }
     \else:
       \@@_replacement_normal:n {#1}
@@ -5990,7 +5998,7 @@
   \char_set_catcode_group_begin:N \^^@
   \cs_new_protected:Npn \@@_replacement_c_B:w
     {
-      \if_int_compare:w \l_@@_replacement_csnames_int = 0 \exp_stop_f:
+      \if_int_compare:w \l_@@_replacement_csnames_int = \c_zero_int
         \int_incr:N \l_@@_balance_int
       \fi:
       \@@_replacement_char:nNN
@@ -6030,7 +6038,7 @@
   \char_set_catcode_group_end:N \^^@
   \cs_new_protected:Npn \@@_replacement_c_E:w
     {
-      \if_int_compare:w \l_@@_replacement_csnames_int = 0 \exp_stop_f:
+      \if_int_compare:w \l_@@_replacement_csnames_int = \c_zero_int
         \int_decr:N \l_@@_balance_int
       \fi:
       \@@_replacement_char:nNN
@@ -6091,7 +6099,7 @@
 %    \begin{macrocode}
   \cs_new_protected:Npn \@@_replacement_c_S:w #1#2
     {
-      \if_int_compare:w `#2 = 0 \exp_stop_f:
+      \if_int_compare:w `#2 = \c_zero_int
         \__kernel_msg_error:nn { regex } { replacement-null-space }
       \fi:
       \tex_lccode:D `\ = `#2 \scan_stop:
@@ -6298,8 +6306,8 @@
 % \end{variable}
 %
 % \begin{variable}{@@_begin, @@_end}
-%   Those flags are raised to indicate extra begin-group
-%   or end-group tokens when extracting submatches.
+%   Those flags are raised to indicate begin-group or end-group tokens
+%   that had to be added when extracting submatches.
 %    \begin{macrocode}
 \flag_new:n { @@_begin }
 \flag_new:n { @@_end }
@@ -6340,6 +6348,15 @@
 %    \end{macrocode}
 % \end{variable}
 %
+% \begin{variable}{\l_@@_added_begin_int, \l_@@_added_end_int}
+%   Keep track of the number of left/right braces to add when performing
+%   a regex operation such as a replacement.
+%    \begin{macrocode}
+\int_new:N \l_@@_added_begin_int
+\int_new:N \l_@@_added_end_int
+%    \end{macrocode}
+% \end{variable}
+%
 % \begin{macro}{\@@_return:}
 %   This function triggers either \cs{prg_return_false:} or
 %   \cs{prg_return_true:} as appropriate to whether a match was found or
@@ -6512,39 +6529,47 @@
 %
 % \begin{macro}{\@@_group_end_extract_seq:N}
 %   The end-points of submatches are stored as entries of two arrays
-%   from \cs{l_@@_min_submatch_int} to
-%   \cs{l_@@_submatch_int} (exclusive). Extract the relevant ranges
-%   into \cs{l_@@_internal_a_tl}. We detect unbalanced results using
-%   the two flags \texttt{__regex_begin} and \texttt{__regex_end}, raised
-%   whenever we see too many begin-group or end-group tokens in a
-%   submatch.
+%   from \cs{l_@@_min_submatch_int} to \cs{l_@@_submatch_int}
+%   (exclusive). Extract the relevant ranges into \cs{g_@@_internal_tl},
+%   separated by \cs{@@_tmp:w} |{}|. We keep track in the two flags
+%   \texttt{__regex_begin} and \texttt{__regex_end} of the number of
+%   begin-group or end-group tokens added to make each of these items
+%   overall balanced.  At this step, |}{| is counted as being balanced
+%   (same number of begin-group and end-group tokens).  This problem is
+%   caught by \cs{@@_extract_check:w}, explained later.  After
+%   complaining about any begin-group or end-group tokens we had to add,
+%   we are ready to construct the user's sequence outside the group.
 %    \begin{macrocode}
 \cs_new_protected:Npn \@@_group_end_extract_seq:N #1
   {
       \flag_clear:n { @@_begin }
       \flag_clear:n { @@_end }
-      \seq_set_from_function:NnN \l_@@_internal_seq
+      \cs_set_eq:NN \@@_tmp:w \scan_stop:
+      \__kernel_tl_gset:Nx \g_@@_internal_tl
         {
           \int_step_function:nnN { \l_@@_min_submatch_int }
-            { \l_@@_submatch_int - 1 }
+            { \l_@@_submatch_int - 1 } \@@_extract_seq_aux:n
+          \@@_tmp:w
         }
-        \@@_extract_seq_aux:n
-      \int_compare:nNnF
+      \int_set:Nn \l_@@_added_begin_int
+        { \flag_height:n { @@_begin } }
+      \int_set:Nn \l_@@_added_end_int
+        { \flag_height:n { @@_end } }
+      \tex_afterassignment:D \@@_extract_check:w
+      \__kernel_tl_gset:Nx \g_@@_internal_tl
+        { \g_@@_internal_tl \if_false: { \fi: } }
+      \int_compare:nNnT
+        { \l_@@_added_begin_int + \l_@@_added_end_int } > 0
         {
-          \flag_height:n { @@_begin } +
-          \flag_height:n { @@_end }
-        }
-          = 0
-        {
           \__kernel_msg_error:nnxxx { regex } { result-unbalanced }
             { splitting~or~extracting~submatches }
-            { \flag_height:n { @@_end } }
-            { \flag_height:n { @@_begin } }
+            { \int_use:N \l_@@_added_begin_int }
+            { \int_use:N \l_@@_added_end_int }
         }
-      \seq_set_map_x:NNn \l_@@_internal_seq \l_@@_internal_seq {##1}
-      \exp_args:NNNo
-      \group_end:
-      \tl_set:Nn #1 { \l_@@_internal_seq }
+    \group_end:
+    \cs_set_eq:NN \@@_tmp:w \@@_extract_map_loop:w
+    \seq_set_from_function:NnN #1
+      { \@@_extract_map:N } \exp_not:n
   }
 %    \end{macrocode}
 % \end{macro}
@@ -6557,25 +6582,134 @@
 %    \begin{macrocode}
 \cs_new:Npn \@@_extract_seq_aux:n #1
   {
+    \@@_tmp:w { }
     \exp_after:wN \@@_extract_seq_aux:ww
     \int_value:w \@@_submatch_balance:n {#1} ; #1;
   }
 \cs_new:Npn \@@_extract_seq_aux:ww #1; #2;
   {
-    \if_int_compare:w #1 < 0 \exp_stop_f:
-      \flag_raise:n { @@_end }
-      \prg_replicate:nn {-#1} { \exp_not:n { { \if_false: } \fi: } }
+    \if_int_compare:w #1 < \c_zero_int
+      \prg_replicate:nn {-#1}
+        {
+          \flag_raise:n { @@_begin }
+          \exp_not:n { { \if_false: } \fi: }
+        }
     \fi:
     \@@_query_submatch:n {#2}
-    \if_int_compare:w #1 > 0 \exp_stop_f:
-      \flag_raise:n { @@_begin }
-      \prg_replicate:nn {#1} { \exp_not:n { \if_false: { \fi: } } }
+    \if_int_compare:w #1 > \c_zero_int
+      \prg_replicate:nn {#1}
+        {
+          \flag_raise:n { @@_end }
+          \exp_not:n { \if_false: { \fi: } }
+        }
     \fi:
   }
 %    \end{macrocode}
 % \end{macro}
 %
-% \begin{macro}{\@@_extract:}
+% \begin{macro}
+%   {
+%     \@@_extract_check:w, \@@_extract_check:n,
+%     \@@_extract_check_loop:w, \@@_extract_check_end:w
+%   }
+%   In \cs{@@_group_end_extract_seq:N} we had to expand
+%   \cs{g_@@_internal_tl} to turn \cs{if_false:} constructions into
+%   actual begin-group and end-group tokens.  This is done with a
+%   \cs{__kernel_tl_gset:Nx} assignment, and \cs{@@_extract_check:w} is
+%   run immediately after this assignment ends, thanks to the
+%   \tn{afterassignment} primitive.  If all of the items were properly
+%   balanced (enough begin-group tokens before end-group tokens, so |}{|
+%   is not) then \cs{@@_extract_check:w} is called just before the
+%   closing brace of the \cs{__kernel_tl_gset:Nx} (thanks to our sneaky
+%   \cs{if_false:} |{| \cs{fi:} |}| construction), and finds that there
+%   is nothing left to expand.  If any of the items is unbalanced, the
+%   assignment gets ended early by an extra end-group token, and our
+%   check finds more tokens needing to be expanded in a new
+%   \cs{__kernel_tl_gset:Nx} assignment.  We need to add a begin-group
+%   and an end-group tokens to the unbalanced item, namely to the last
+%   item found so far, which we reach through a loop.
+%    \begin{macrocode}
+\cs_new_protected:Npn \@@_extract_check:w
+  {
+    \exp_after:wN \@@_extract_check:n
+    \exp_after:wN { \if_false: } \fi:
+  }
+\cs_new_protected:Npn \@@_extract_check:n #1
+  {
+    \tl_if_empty:nF {#1}
+      {
+        \int_incr:N \l_@@_added_begin_int
+        \int_incr:N \l_@@_added_end_int
+        \tex_afterassignment:D \@@_extract_check:w
+        \__kernel_tl_gset:Nx \g_@@_internal_tl
+          {
+            \exp_after:wN \@@_extract_check_loop:w
+            \g_@@_internal_tl
+            \@@_tmp:w \@@_extract_check_end:w
+            #1
+          }
+      }
+  }
+\cs_new:Npn \@@_extract_check_loop:w #1 \@@_tmp:w #2
+  {
+    #2
+    \exp_not:o {#1}
+    \@@_tmp:w { }
+    \@@_extract_check_loop:w \prg_do_nothing:
+  }
+%    \end{macrocode}
+%   Arguments of \cs{@@_extract_check_end:w} are: |#1| is the part of
+%   the item before the extra end-group token; |#2| is junk; |#3| is
+%   \cs{prg_do_nothing:} followed by the not-yet-expanded part of the
+%   item after the extra end-group token.  In the replacement text, the
+%   first brace and the \cs{if_false:} |{| \cs{fi:} |}| construction are
+%   the added begin-group and end-group tokens (the latter being not-yet
+%   expanded, just like~|#3|), while the closing brace after
+%   \cs{exp_not:o} |{#1}| replaces the extra end-group token that had
+%   ended the assignment early.  In particular this means that the
+%   character code of that end-group token is lost.
+%    \begin{macrocode}
+\cs_new:Npn \@@_extract_check_end:w
+    \exp_not:o #1#2 \@@_extract_check_loop:w #3 \@@_tmp:w
+  {
+    { \exp_not:o {#1} }
+    #3
+    \if_false: { \fi: }
+    \@@_tmp:w
+  }
+%    \end{macrocode}
+% \end{macro}
+%
+% \begin{macro}[EXP]
+%   {
+%     \@@_extract_map:N,
+%     \@@_extract_map_aux:NNn,
+%     \@@_extract_map_loop:w
+%   }
+%   This receives a |seq| internal function and maps it over all items
+%   in \cs{g_@@_internal_tl}.  This token list takes the form
+%   \cs{@@_tmp:w} |{}| \meta{item_1} \cs{@@_tmp:w} |{}| \meta{item_2}
+%   \ldots{} \cs{@@_tmp:w}, and the calling code has set \cs{@@_tmp:w}
+%   equal to \cs{@@_extract_map_loop:w}.  The loop is otherwise pretty
+%   standard, with \cs{prg_do_nothing:} to avoid losing braces.
+%    \begin{macrocode}
+\cs_new:Npn \@@_extract_map:N #1
+  {
+    \exp_after:wN \@@_extract_map_aux:NNn
+    \exp_after:wN #1
+    \g_@@_internal_tl \use_none:nnn
+  }
+\cs_new:Npn \@@_extract_map_aux:NNn #1#2#3
+  { #3 #2 #1 \prg_do_nothing: }
+\cs_new:Npn \@@_extract_map_loop:w #1#2 \@@_tmp:w #3
+  {
+    \exp_after:wN #1 \exp_after:wN {#2}
+    #3 \@@_extract_map_loop:w #1 \prg_do_nothing:
+  }
+%    \end{macrocode}
+% \end{macro}
+%
+% \begin{macro}{\@@_extract:, \@@_extract_aux:w}
 %   Our task here is to store the list of end-points of submatches, and
 %   store them in appropriate array entries, from
 %   \cs{l_@@_zeroth_submatch_int} upwards.  First, we store in
@@ -6598,19 +6732,24 @@
       \__kernel_intarray_gset:Nnn \g_@@_submatch_prev_intarray
         { \l_@@_zeroth_submatch_int } { \l_@@_start_pos_int }
       \int_zero:N \l_@@_internal_a_int
-      \clist_map_inline:Nn \l_@@_success_submatches_tl
-        {
-          \if_int_compare:w \l_@@_internal_a_int < \l_@@_capturing_group_int
-            \__kernel_intarray_gset:Nnn \g_@@_submatch_begin_intarray
-              { \@@_int_eval:w \l_@@_zeroth_submatch_int + \l_@@_internal_a_int } {##1}
-          \else:
-            \__kernel_intarray_gset:Nnn \g_@@_submatch_end_intarray
-              { \@@_int_eval:w \l_@@_zeroth_submatch_int + \l_@@_internal_a_int - \l_@@_capturing_group_int } {##1}
-          \fi:
-          \int_incr:N \l_@@_internal_a_int
-        }
+      \exp_after:wN \@@_extract_aux:w \l_@@_success_submatches_tl
+        \prg_break_point: \@@_use_none_delimit_by_q_recursion_stop:w ,
+        \q_@@_recursion_stop
     \fi:
   }
+\cs_new_protected:Npn \@@_extract_aux:w #1 ,
+  {
+    \prg_break: #1 \prg_break_point:
+    \if_int_compare:w \l_@@_internal_a_int < \l_@@_capturing_group_int
+      \__kernel_intarray_gset:Nnn \g_@@_submatch_begin_intarray
+        { \@@_int_eval:w \l_@@_zeroth_submatch_int + \l_@@_internal_a_int } {#1}
+    \else:
+      \__kernel_intarray_gset:Nnn \g_@@_submatch_end_intarray
+        { \@@_int_eval:w \l_@@_zeroth_submatch_int + \l_@@_internal_a_int - \l_@@_capturing_group_int } {#1}
+    \fi:
+    \int_incr:N \l_@@_internal_a_int
+    \@@_extract_aux:w
+  }
 %    \end{macrocode}
 % \end{macro}
 %
@@ -6708,38 +6847,67 @@
 %    \end{macrocode}
 % \end{macro}
 %
-% \begin{macro}{\@@_group_end_replace:N}
-%   If the brace balance is not $0$, raise an error. Then set the user's
-%   variable |#1| to the \texttt{x}-expansion of
-%   \cs{l_@@_internal_a_tl}, adding the appropriate braces to produce
-%   a balanced result. And end the group.
+% \begin{macro}
+%   {
+%     \@@_group_end_replace:N, \@@_group_end_replace_try:,
+%     \@@_group_end_replace_check:w, \@@_group_end_replace_check:n
+%   }
+%   At this stage \cs{l_@@_internal_a_tl} (|x|-expands to the desired
+%   result).  Guess from \cs{l_@@_balance_int} the number of braces to
+%   add before or after the result then try expanding.  The simplest
+%   case is when \cs{l_@@_internal_a_tl} together with the braces we
+%   insert via \cs{prg_replicate:nn} give a balanced result, and the
+%   assignment ends at the \cs{if_false:} |{| \cs{fi:} |}| construction:
+%   then \cs{@@_group_end_replace_check:w} sees that there is no
+%   material left and we successfully found the result.  The harder case
+%   is that expanding \cs{l_@@_internal_a_tl} may produce extra closing
+%   braces and end the assignment early.  Then we grab the remaining code
+%   using; importantly, what follows has not yet been expanded so that
+%   \cs{@@_group_end_replace_check:n} grabs everything until the last
+%   brace in \cs{@@_group_end_replace_try:}, letting us try again with
+%   an extra surrounding pair of braces.
 %    \begin{macrocode}
 \cs_new_protected:Npn \@@_group_end_replace:N #1
   {
-    \if_int_compare:w \l_@@_balance_int = 0 \exp_stop_f:
-    \else:
-      \__kernel_msg_error:nnxxx { regex } { result-unbalanced }
-        { replacing }
-        { \int_max:nn { - \l_@@_balance_int } { 0 } }
-        { \int_max:nn { \l_@@_balance_int } { 0 } }
-    \fi:
-    \use:x
+    \int_set:Nn \l_@@_added_begin_int
+      { \int_max:nn { - \l_@@_balance_int } { 0 } }
+    \int_set:Nn \l_@@_added_end_int
+      { \int_max:nn { \l_@@_balance_int } { 0 } }
+    \@@_group_end_replace_try:
+    \int_compare:nNnT { \l_@@_added_begin_int + \l_@@_added_end_int } > 0
       {
-        \group_end:
-        \tl_set:Nn \exp_not:N #1
-          {
-            \if_int_compare:w \l_@@_balance_int < 0 \exp_stop_f:
-              \prg_replicate:nn { - \l_@@_balance_int }
-                { { \if_false: } \fi: }
-            \fi:
-            \l_@@_internal_a_tl
-            \if_int_compare:w \l_@@_balance_int > 0 \exp_stop_f:
-              \prg_replicate:nn { \l_@@_balance_int }
-                { \if_false: { \fi: } }
-            \fi:
-          }
+        \__kernel_msg_error:nnxxx { regex } { result-unbalanced }
+          { replacing } { \int_use:N \l_@@_added_begin_int }
+          { \int_use:N \l_@@_added_end_int }
       }
+    \group_end:
+    \tl_set_eq:NN #1 \g_@@_internal_tl
   }
+\cs_new_protected:Npn \@@_group_end_replace_try:
+  {
+    \tex_afterassignment:D \@@_group_end_replace_check:w
+    \__kernel_tl_gset:Nx \g_@@_internal_tl
+      {
+        \prg_replicate:nn { \l_@@_added_begin_int } { { \if_false: } \fi: }
+        \l_@@_internal_a_tl
+        \prg_replicate:nn { \l_@@_added_end_int } { \if_false: { \fi: } }
+        \if_false: { \fi: }
+      }
+  }
+\cs_new_protected:Npn \@@_group_end_replace_check:w
+  {
+    \exp_after:wN \@@_group_end_replace_check:n
+    \exp_after:wN { \if_false: } \fi:
+  }
+\cs_new_protected:Npn \@@_group_end_replace_check:n #1
+  {
+    \tl_if_empty:nF {#1}
+      {
+        \int_incr:N \l_@@_added_begin_int
+        \int_incr:N \l_@@_added_end_int
+        \@@_group_end_replace_try:
+      }
+  }
 %    \end{macrocode}
 % \end{macro}
 %
@@ -7551,6 +7719,7 @@
 %^^A                    recursion condition
 %^^A    (?(DEFINE)...   define subpattern for reference
 %^^A    (?(assert)...   assertion condition
+%^^A    (?(?=..)..|..)  positive/negative look ahead/behind condition
 %^^A    (*ACCEPT)       force successful match
 %^^A    (*FAIL)         force backtrack; synonym (*F)
 %^^A    (*COMMIT)       overall failure, no advance of starting point
@@ -7567,8 +7736,10 @@
 %^^A    +               possessive quantifiers
 %^^A    (?>...)         atomic, non-capturing group
 %^^A    (?#....)        comment (not nestable)
-%^^A    (?JmsUx)        options (duplicate names; multiline; single line;
-%^^A                      ungreedy; extended)
+%^^A    (?Jms-UxX)      options (duplicate names; multiline; single line;
+%^^A                      unset what follows; ungreedy; extended;
+%^^A                      error on bad escapes)
+%^^A    (?i:...|...)    convenient shorthand for (?:(?i)...|...)
 %^^A    (*NO_START_OPT) no start-match optimization (PCRE_NO_START_OPTIMIZE)
 %^^A    (*UTF8)         set UTF-8 mode (PCRE_UTF8)
 %^^A    (*UCP)          set PCRE_UCP (use Unicode properties for \d etc)

Modified: trunk/Master/texmf-dist/source/latex/l3kernel/l3seq.dtx
===================================================================
--- trunk/Master/texmf-dist/source/latex/l3kernel/l3seq.dtx	2021-05-25 20:47:33 UTC (rev 59344)
+++ trunk/Master/texmf-dist/source/latex/l3kernel/l3seq.dtx	2021-05-25 20:48:22 UTC (rev 59345)
@@ -43,7 +43,7 @@
 %    }^^A
 % }
 %
-% \date{Released 2021-05-11}
+% \date{Released 2021-05-25}
 %
 % \maketitle
 %
@@ -1979,10 +1979,11 @@
 %
 % \begin{macro}{\seq_map_function:NN, \seq_map_function:cN}
 % \UnitTested
-% \begin{macro}[rEXP]{\@@_map_function:NNn}
+% \begin{macro}[rEXP]{\@@_map_function:Nw}
 %   The idea here is to apply the code of |#2| to each item in the
 %   sequence without altering the definition of \cs{@@_item:n}.  The
-%   argument delimited by \cs{@@_item:n} is almost always empty, except
+%   even-numbered arguments of \cs{@@_map_function:Nw} delimited by
+%   \cs{@@_item:n} are almost always empty, except
 %   at the end of the loop where it is \cs{prg_break:}.  This allows to
 %   break the loop without needing to do a (relatively-expensive) quark
 %   test.
@@ -1993,13 +1994,21 @@
     \exp_after:wN \@@_map_function:Nw
     \exp_after:wN #2
     #1
-    \prg_break: \@@_item:n { } \prg_break_point:
+    \prg_break:
+    \@@_item:n { } \@@_item:n { } \@@_item:n { } \@@_item:n { }
+    \prg_break_point:
     \prg_break_point:Nn \seq_map_break: { }
   }
-\cs_new:Npn \@@_map_function:Nw #1#2 \@@_item:n #3
+\cs_new:Npn \@@_map_function:Nw #1
+    #2 \@@_item:n #3
+    #4 \@@_item:n #5
+    #6 \@@_item:n #7
+    #8 \@@_item:n #9
   {
-    #2
-    #1 {#3}
+    #2 #1 {#3}
+    #4 #1 {#5}
+    #6 #1 {#7}
+    #8 #1 {#9}
     \@@_map_function:Nw #1
   }
 \cs_generate_variant:Nn \seq_map_function:NN { c }
@@ -2068,14 +2077,22 @@
   {
     \exp_last_unbraced:Nno
       \use_i:nn { \@@_map_tokens:nw {#2} } #1
-    \prg_break: \@@_item:n { } \prg_break_point:
+    \prg_break:
+    \@@_item:n { } \@@_item:n { } \@@_item:n { } \@@_item:n { }
+    \prg_break_point:
     \prg_break_point:Nn \seq_map_break: { }
   }
 \cs_generate_variant:Nn \seq_map_tokens:Nn { c }
-\cs_new:Npn \@@_map_tokens:nw #1#2 \@@_item:n #3
+\cs_new:Npn \@@_map_tokens:nw #1
+    #2 \@@_item:n #3
+    #4 \@@_item:n #5
+    #6 \@@_item:n #7
+    #8 \@@_item:n #9
   {
-    #2
-    \use:n {#1} {#3}
+    #2 \use:n {#1} {#3}
+    #4 \use:n {#1} {#5}
+    #6 \use:n {#1} {#7}
+    #8 \use:n {#1} {#9}
     \@@_map_tokens:nw {#1}
   }
 %    \end{macrocode}

Modified: trunk/Master/texmf-dist/source/latex/l3kernel/l3skip.dtx
===================================================================
--- trunk/Master/texmf-dist/source/latex/l3kernel/l3skip.dtx	2021-05-25 20:47:33 UTC (rev 59344)
+++ trunk/Master/texmf-dist/source/latex/l3kernel/l3skip.dtx	2021-05-25 20:48:22 UTC (rev 59345)
@@ -44,7 +44,7 @@
 %    }^^A
 % }
 %
-% \date{Released 2021-05-11}
+% \date{Released 2021-05-25}
 %
 % \maketitle
 %
@@ -1129,7 +1129,7 @@
 \cs_new_protected:Npn \dim_const:Nn #1#2
   {
     \dim_new:N #1
-    \tex_global:D #1 ~ \dim_eval:n {#2} \scan_stop:
+    \tex_global:D #1 = \dim_eval:n {#2} \scan_stop:
   }
 \cs_generate_variant:Nn \dim_const:Nn { c }
 %    \end{macrocode}
@@ -1139,11 +1139,12 @@
 % \begin{macro}{\dim_gzero:N, \dim_gzero:c}
 %   Reset the register to zero.  Using \cs{c_zero_skip} deals with the
 %   case where the variable passed is incorrectly a skip (for example a
-%   \LaTeXe{} length).
+%   \LaTeXe{} length).  Besides, these functions are then simply copied
+%   for \cs{skip_zero:N} and related functions.
 %    \begin{macrocode}
-\cs_new_protected:Npn \dim_zero:N #1 { #1 \c_zero_skip }
+\cs_new_protected:Npn \dim_zero:N #1 { #1 = \c_zero_skip }
 \cs_new_protected:Npn \dim_gzero:N #1
-  { \tex_global:D #1 \c_zero_skip }
+  { \tex_global:D #1 = \c_zero_skip }
 \cs_generate_variant:Nn \dim_zero:N  { c }
 \cs_generate_variant:Nn \dim_gzero:N { c }
 %    \end{macrocode}
@@ -1184,9 +1185,9 @@
 %   length).
 %    \begin{macrocode}
 \cs_new_protected:Npn \dim_set:Nn #1#2
-  { #1 ~ \@@_eval:w #2 \@@_eval_end: \scan_stop: }
+  { #1 = \@@_eval:w #2 \@@_eval_end: \scan_stop: }
 \cs_new_protected:Npn \dim_gset:Nn #1#2
-  { \tex_global:D #1 ~ \@@_eval:w #2 \@@_eval_end: \scan_stop: }
+  { \tex_global:D #1 = \@@_eval:w #2 \@@_eval_end: \scan_stop: }
 \cs_generate_variant:Nn \dim_set:Nn  { c }
 \cs_generate_variant:Nn \dim_gset:Nn { c }
 %    \end{macrocode}
@@ -1213,27 +1214,27 @@
 % \begin{macro}{\dim_gadd:Nn, \dim_gadd:cn}
 % \begin{macro}{\dim_sub:Nn, \dim_sub:cn}
 % \begin{macro}{\dim_gsub:Nn, \dim_gsub:cn}
-%   Using |by| here deals with the (incorrect) case |\dimen123|.
+%   Using |by| here would slow things down just to detect nonsensical
+%   cases such as passing |\dimen 123| as the first argument.
 %   Using \cs{scan_stop:} deals with skip variables.  Since
 %   debugging checks that the variable is correctly local/global, the
 %   global versions cannot be defined as \cs{tex_global:D} followed by
-%   the local versions.  The debugging code is inserted by
-%   \cs{@@_tmp:w}.
+%   the local versions.
 %    \begin{macrocode}
 \cs_new_protected:Npn \dim_add:Nn #1#2
-  { \tex_advance:D #1 by \@@_eval:w #2 \@@_eval_end: \scan_stop: }
+  { \tex_advance:D #1 \@@_eval:w #2 \@@_eval_end: \scan_stop: }
 \cs_new_protected:Npn \dim_gadd:Nn #1#2
   {
-    \tex_global:D \tex_advance:D #1 by
+    \tex_global:D \tex_advance:D #1
       \@@_eval:w #2 \@@_eval_end: \scan_stop:
   }
 \cs_generate_variant:Nn \dim_add:Nn  { c }
 \cs_generate_variant:Nn \dim_gadd:Nn { c }
 \cs_new_protected:Npn \dim_sub:Nn #1#2
-  { \tex_advance:D #1 by - \@@_eval:w #2 \@@_eval_end: \scan_stop: }
+  { \tex_advance:D #1 - \@@_eval:w #2 \@@_eval_end: \scan_stop: }
 \cs_new_protected:Npn \dim_gsub:Nn #1#2
   {
-    \tex_global:D \tex_advance:D #1 by
+    \tex_global:D \tex_advance:D #1
       -\@@_eval:w #2 \@@_eval_end: \scan_stop:
   }
 \cs_generate_variant:Nn \dim_sub:Nn  { c }
@@ -1642,13 +1643,9 @@
 % \end{macro}
 %
 % \begin{macro}{\dim_use:N, \dim_use:c}
-%   Accessing a \meta{dim}.
+%   Accessing a \meta{dim}.  We hand-code the |c| variant for some speed gain.
 %    \begin{macrocode}
 \cs_new_eq:NN \dim_use:N \tex_the:D
-%    \end{macrocode}
-%    We hand-code this for some speed gain:
-%    \begin{macrocode}
-%\cs_generate_variant:Nn \dim_use:N { c }
 \cs_new:Npn \dim_use:c #1 { \tex_the:D \cs:w #1 \cs_end: }
 %    \end{macrocode}
 % \end{macro}
@@ -1673,7 +1670,7 @@
       ##1 . ##2 \tl_to_str:n { pt }
   }
       {
-        \int_compare:nNnTF {#2} > { 0 }
+        \int_compare:nNnTF {#2} > \c_zero_int
           { #1 . #2 }
           { #1 }
       }
@@ -1808,7 +1805,7 @@
 \cs_new_protected:Npn \skip_const:Nn #1#2
   {
     \skip_new:N #1
-    \tex_global:D #1 ~ \skip_eval:n {#2} \scan_stop:
+    \tex_global:D #1 = \skip_eval:n {#2} \scan_stop:
   }
 \cs_generate_variant:Nn \skip_const:Nn { c }
 %    \end{macrocode}
@@ -1818,8 +1815,8 @@
 % \begin{macro}{\skip_gzero:N, \skip_gzero:c}
 %   Reset the register to zero.
 %    \begin{macrocode}
-\cs_new_protected:Npn \skip_zero:N #1 { #1 \c_zero_skip }
-\cs_new_protected:Npn \skip_gzero:N #1 { \tex_global:D #1 \c_zero_skip }
+\cs_new_eq:NN \skip_zero:N  \dim_zero:N
+\cs_new_eq:NN \skip_gzero:N \dim_gzero:N
 \cs_generate_variant:Nn \skip_zero:N  { c }
 \cs_generate_variant:Nn \skip_gzero:N { c }
 %    \end{macrocode}
@@ -1856,9 +1853,9 @@
 %   Much the same as for dimensions.
 %    \begin{macrocode}
 \cs_new_protected:Npn \skip_set:Nn #1#2
-  { #1 ~ \tex_glueexpr:D #2 \scan_stop: }
+  { #1 = \tex_glueexpr:D #2 \scan_stop: }
 \cs_new_protected:Npn \skip_gset:Nn #1#2
-  { \tex_global:D #1 ~ \tex_glueexpr:D #2 \scan_stop: }
+  { \tex_global:D #1 = \tex_glueexpr:D #2 \scan_stop: }
 \cs_generate_variant:Nn \skip_set:Nn  { c }
 \cs_generate_variant:Nn \skip_gset:Nn { c }
 %    \end{macrocode}
@@ -1886,15 +1883,15 @@
 %   Using |by| here deals with the (incorrect) case |\skip123|.
 %    \begin{macrocode}
 \cs_new_protected:Npn \skip_add:Nn #1#2
-  { \tex_advance:D #1 by \tex_glueexpr:D #2 \scan_stop: }
+  { \tex_advance:D #1 \tex_glueexpr:D #2 \scan_stop: }
 \cs_new_protected:Npn \skip_gadd:Nn #1#2
-  { \tex_global:D \tex_advance:D #1 by \tex_glueexpr:D #2 \scan_stop: }
+  { \tex_global:D \tex_advance:D #1 \tex_glueexpr:D #2 \scan_stop: }
 \cs_generate_variant:Nn \skip_add:Nn  { c }
 \cs_generate_variant:Nn \skip_gadd:Nn { c }
 \cs_new_protected:Npn \skip_sub:Nn #1#2
-  { \tex_advance:D #1 by - \tex_glueexpr:D #2 \scan_stop: }
+  { \tex_advance:D #1 - \tex_glueexpr:D #2 \scan_stop: }
 \cs_new_protected:Npn \skip_gsub:Nn #1#2
-  { \tex_global:D \tex_advance:D #1 by - \tex_glueexpr:D #2 \scan_stop: }
+  { \tex_global:D \tex_advance:D #1 - \tex_glueexpr:D #2 \scan_stop: }
 \cs_generate_variant:Nn \skip_sub:Nn  { c }
 \cs_generate_variant:Nn \skip_gsub:Nn { c }
 %    \end{macrocode}
@@ -1911,7 +1908,7 @@
 %    \begin{macrocode}
 \prg_new_conditional:Npnn \skip_if_eq:nn #1#2 { p , T , F , TF }
   {
-    \str_if_eq:eeTF { \skip_eval:n { #1 } } { \skip_eval:n { #2 } }
+    \str_if_eq:eeTF { \skip_eval:n {#1} } { \skip_eval:n {#2} }
        { \prg_return_true: }
        { \prg_return_false: }
   }
@@ -1956,9 +1953,8 @@
 % \begin{macro}{\skip_use:N, \skip_use:c}
 %   Accessing a \meta{skip}.
 %    \begin{macrocode}
-\cs_new_eq:NN \skip_use:N \tex_the:D
-%\cs_generate_variant:Nn \skip_use:N { c }
-\cs_new:Npn \skip_use:c #1 { \tex_the:D \cs:w #1 \cs_end: }
+\cs_new_eq:NN \skip_use:N \dim_use:N
+\cs_new_eq:NN \skip_use:c \dim_use:c
 %    \end{macrocode}
 % \end{macro}
 %
@@ -2055,7 +2051,7 @@
 \cs_new_protected:Npn \muskip_const:Nn #1#2
   {
     \muskip_new:N #1
-    \tex_global:D #1 ~ \muskip_eval:n {#2} \scan_stop:
+    \tex_global:D #1 = \muskip_eval:n {#2} \scan_stop:
   }
 \cs_generate_variant:Nn \muskip_const:Nn { c }
 %    \end{macrocode}
@@ -2066,9 +2062,9 @@
 %   Reset the register to zero.
 %    \begin{macrocode}
 \cs_new_protected:Npn \muskip_zero:N #1
-  { #1 \c_zero_muskip }
+  { #1 = \c_zero_muskip }
 \cs_new_protected:Npn \muskip_gzero:N #1
-  { \tex_global:D #1 \c_zero_muskip }
+  { \tex_global:D #1 = \c_zero_muskip }
 \cs_generate_variant:Nn \muskip_zero:N  { c }
 \cs_generate_variant:Nn \muskip_gzero:N { c }
 %    \end{macrocode}
@@ -2108,9 +2104,9 @@
 %   This should be pretty familiar.
 %    \begin{macrocode}
 \cs_new_protected:Npn \muskip_set:Nn #1#2
-  { #1 ~ \tex_muexpr:D #2 \scan_stop: }
+  { #1 = \tex_muexpr:D #2 \scan_stop: }
 \cs_new_protected:Npn \muskip_gset:Nn #1#2
-  { \tex_global:D #1 ~ \tex_muexpr:D #2 \scan_stop: }
+  { \tex_global:D #1 = \tex_muexpr:D #2 \scan_stop: }
 \cs_generate_variant:Nn \muskip_set:Nn  { c }
 \cs_generate_variant:Nn \muskip_gset:Nn { c }
 %    \end{macrocode}
@@ -2144,15 +2140,15 @@
 %   Using |by| here deals with the (incorrect) case |\muskip123|.
 %    \begin{macrocode}
 \cs_new_protected:Npn \muskip_add:Nn #1#2
-  { \tex_advance:D #1 by \tex_muexpr:D #2 \scan_stop: }
+  { \tex_advance:D #1 \tex_muexpr:D #2 \scan_stop: }
 \cs_new_protected:Npn \muskip_gadd:Nn #1#2
-  { \tex_global:D \tex_advance:D #1 by \tex_muexpr:D #2 \scan_stop: }
+  { \tex_global:D \tex_advance:D #1 \tex_muexpr:D #2 \scan_stop: }
 \cs_generate_variant:Nn \muskip_add:Nn  { c }
 \cs_generate_variant:Nn \muskip_gadd:Nn { c }
 \cs_new_protected:Npn \muskip_sub:Nn #1#2
-  { \tex_advance:D #1 by - \tex_muexpr:D #2 \scan_stop: }
+  { \tex_advance:D #1 - \tex_muexpr:D #2 \scan_stop: }
 \cs_new_protected:Npn \muskip_gsub:Nn #1#2
-  { \tex_global:D \tex_advance:D #1 by - \tex_muexpr:D #2 \scan_stop: }
+  { \tex_global:D \tex_advance:D #1 - \tex_muexpr:D #2 \scan_stop: }
 \cs_generate_variant:Nn \muskip_sub:Nn  { c }
 \cs_generate_variant:Nn \muskip_gsub:Nn { c }
 %    \end{macrocode}
@@ -2174,8 +2170,8 @@
 % \begin{macro}{\muskip_use:N, \muskip_use:c}
 %   Accessing a \meta{muskip}.
 %    \begin{macrocode}
-\cs_new_eq:NN \muskip_use:N \tex_the:D
-\cs_generate_variant:Nn \muskip_use:N { c }
+\cs_new_eq:NN \muskip_use:N \dim_use:N
+\cs_new_eq:NN \muskip_use:c \dim_use:c
 %    \end{macrocode}
 % \end{macro}
 %

Modified: trunk/Master/texmf-dist/source/latex/l3kernel/l3sort.dtx
===================================================================
--- trunk/Master/texmf-dist/source/latex/l3kernel/l3sort.dtx	2021-05-25 20:47:33 UTC (rev 59344)
+++ trunk/Master/texmf-dist/source/latex/l3kernel/l3sort.dtx	2021-05-25 20:48:22 UTC (rev 59345)
@@ -43,7 +43,7 @@
 %    }^^A
 % }
 %
-% \date{Released 2021-05-11}
+% \date{Released 2021-05-25}
 %
 % \maketitle
 %

Modified: trunk/Master/texmf-dist/source/latex/l3kernel/l3str-convert.dtx
===================================================================
--- trunk/Master/texmf-dist/source/latex/l3kernel/l3str-convert.dtx	2021-05-25 20:47:33 UTC (rev 59344)
+++ trunk/Master/texmf-dist/source/latex/l3kernel/l3str-convert.dtx	2021-05-25 20:48:22 UTC (rev 59345)
@@ -44,7 +44,7 @@
 %    }^^A
 % }
 %
-% \date{Released 2021-05-11}
+% \date{Released 2021-05-25}
 %
 % \maketitle
 %
@@ -824,7 +824,7 @@
             \file_if_exist:nTF { l3str-#2- \l_@@_internal_tl .def }
               {
                 \group_begin:
-                  \@@_load_catcodes:
+                  \cctab_select:N \c_code_cctab
                   \file_input:n { l3str-#2- \l_@@_internal_tl .def }
                 \group_end:
               }
@@ -880,32 +880,6 @@
 % \end{macro}
 % \end{macro}
 %
-% \begin{macro}{\@@_load_catcodes:}
-%   Since encoding files may be loaded at arbitrary places in a \TeX{}
-%   document, including within verbatim mode, we set the catcodes of all
-%   characters appearing in any encoding definition file.
-%    \begin{macrocode}
-\cs_new_protected:Npn \@@_load_catcodes:
-  {
-    \char_set_catcode_escape:N \\
-    \char_set_catcode_group_begin:N \{
-    \char_set_catcode_group_end:N \}
-    \char_set_catcode_math_toggle:N \$
-    \char_set_catcode_alignment:N \&
-    \char_set_catcode_parameter:N \#
-    \char_set_catcode_math_superscript:N \^
-    \char_set_catcode_ignore:N \ %
-    \char_set_catcode_space:N \~
-    \tl_map_function:nN { abcdefghijklmnopqrstuvwxyz_:ABCDEFILNPSTUX }
-      \char_set_catcode_letter:N
-    \tl_map_function:nN { 0123456789"'?*+-.(),`!/<>[];= }
-      \char_set_catcode_other:N
-    \char_set_catcode_comment:N \%
-    \int_set:Nn \tex_endlinechar:D {32}
-  }
-%    \end{macrocode}
-% \end{macro}
-%
 % \subsubsection{Byte unescape and escape}
 %
 % Strings of bytes may need to be stored in auxiliary files in safe
@@ -2589,7 +2563,7 @@
         \exp_after:wN \@@_decode_utf_xxxii_end:w
       \fi:
       #1#2#3#4 \s_@@
-      \if_int_compare:w \@@_tmp:w #1#4 > 0 \exp_stop_f:
+      \if_int_compare:w \@@_tmp:w #1#4 > \c_zero_int
         \flag_raise:n { str_overflow }
         \flag_raise:n { str_error }
         \int_use:N \c_@@_replacement_char_int

Modified: trunk/Master/texmf-dist/source/latex/l3kernel/l3str.dtx
===================================================================
--- trunk/Master/texmf-dist/source/latex/l3kernel/l3str.dtx	2021-05-25 20:47:33 UTC (rev 59344)
+++ trunk/Master/texmf-dist/source/latex/l3kernel/l3str.dtx	2021-05-25 20:48:22 UTC (rev 59345)
@@ -43,7 +43,7 @@
 %    }^^A
 % }
 %
-% \date{Released 2021-05-11}
+% \date{Released 2021-05-25}
 %
 % \maketitle
 %
@@ -401,6 +401,34 @@
 %   not be used within this string.
 % \end{function}
 %
+% \begin{function}[EXP, pTF, added = 2021-05-17]{\str_compare:nNn, \str_compare:eNe}
+%   \begin{syntax}
+%     \cs{str_compare_p:nNn} \Arg{tl_1} \meta{relation} \Arg{tl_2}
+%     \cs{str_compare:nNnTF} \Arg{tl_1} \meta{relation} \Arg{tl_2} \Arg{true code} \Arg{false code}
+%   \end{syntax}
+%   Compares the two \meta{token lists} on a character by character
+%   basis (namely after converting them to strings) in a lexicographic
+%   order according to the character codes of the characters.  The
+%   \meta{relation} can be |<|, |=|, or~|>| and the test is
+%   \texttt{true} under the following conditions:
+%   \begin{itemize}
+%     \item for |<|, if the first string is earlier than the second in lexicographic order;
+%     \item for |=|, if the two strings have exactly the same characters;
+%     \item for |>|, if the first string is later than the second in lexicographic order.
+%   \end{itemize}
+%   Thus for example the following is logically \texttt{true}:
+%   \begin{verbatim}
+%     \str_compare_p:nNn { ab } < { abc }
+%   \end{verbatim}
+%   \begin{texnote}
+%     This is a wrapper around the \TeX{} primitive
+%     \cs[index=pdfstrcmp]{(pdf)strcmp}.  It is meant for programming
+%     and not for sorting textual contents, as it simply considers
+%     character codes and not more elaborate considerations of grapheme
+%     clusters, locale, etc.
+%   \end{texnote}
+% \end{function}
+%
 % \section{Mapping over strings}
 %
 % All mappings are done at the current group level, \emph{i.e.}~any
@@ -1109,6 +1137,25 @@
 %    \end{macrocode}
 % \end{macro}
 %
+% \begin{macro}[pTF, EXP]{\str_compare:nNn, \str_compare:eNe}
+%   Simply rely on \cs{@@_if_eq:nn}, which expands to |-1|, |0|
+%   or~|1|.  The |ee| version is created directly because it is more efficient.
+%    \begin{macrocode}
+\prg_new_conditional:Npnn \str_compare:nNn #1#2#3 { p , T , F , TF }
+  {
+    \if_int_compare:w
+      \@@_if_eq:nn { \exp_not:n {#1} } { \exp_not:n {#3} }
+      #2 \c_zero_int
+      \prg_return_true: \else: \prg_return_false: \fi:
+  }
+\prg_new_conditional:Npnn \str_compare:eNe #1#2#3 { p , T , F , TF }
+  {
+    \if_int_compare:w \@@_if_eq:nn {#1} {#3} #2 \c_zero_int
+      \prg_return_true: \else: \prg_return_false: \fi:
+  }
+%    \end{macrocode}
+% \end{macro}
+%
 % \begin{macro}[pTF, EXP]
 %   {
 %     \str_if_eq:nn, \str_if_eq:Vn, \str_if_eq:on, \str_if_eq:nV,
@@ -1124,7 +1171,7 @@
   {
     \if_int_compare:w
       \@@_if_eq:nn { \exp_not:n {#1} } { \exp_not:n {#2} }
-      = 0 \exp_stop_f:
+      = \c_zero_int
       \prg_return_true: \else: \prg_return_false: \fi:
   }
 \prg_generate_conditional_variant:Nnn \str_if_eq:nn
@@ -1131,7 +1178,7 @@
   { V , v , o , nV , no , VV , nv } { p , T , F , TF }
 \prg_new_conditional:Npnn \str_if_eq:ee #1#2 { p , T , F , TF }
   {
-    \if_int_compare:w \@@_if_eq:nn {#1} {#2} = 0 \exp_stop_f:
+    \if_int_compare:w \@@_if_eq:nn {#1} {#2} = \c_zero_int
       \prg_return_true: \else: \prg_return_false: \fi:
   }
 %    \end{macrocode}
@@ -1146,7 +1193,7 @@
   {
     \if_int_compare:w
       \@@_if_eq:nn { \tl_to_str:N #1 } { \tl_to_str:N #2 }
-      = 0 \exp_stop_f: \prg_return_true: \else: \prg_return_false: \fi:
+      = \c_zero_int \prg_return_true: \else: \prg_return_false: \fi:
   }
 \prg_generate_conditional_variant:Nnn \str_if_eq:NN
   { c , Nc , cc } { T , F , TF , p }
@@ -1620,7 +1667,7 @@
   {
     \int_eval:n
       {
-        \if_int_compare:w #1 < 0 \exp_stop_f:
+        \if_int_compare:w #1 < \c_zero_int
           \if_int_compare:w #1 < -#2 \exp_stop_f:
             0
           \else:
@@ -1673,7 +1720,7 @@
 \cs_new:Npn \@@_collect_end:wn #1 ;
   {
     \exp_after:wN \@@_collect_end:nnnnnnnnw
-    \if_case:w \if_int_compare:w #1 > 0 \exp_stop_f:
+    \if_case:w \if_int_compare:w #1 > \c_zero_int
       #1 \else: 0 \fi: \exp_stop_f:
       \or: \or: \or: \or: \or: \or: \fi:
   }

Modified: trunk/Master/texmf-dist/source/latex/l3kernel/l3sys.dtx
===================================================================
--- trunk/Master/texmf-dist/source/latex/l3kernel/l3sys.dtx	2021-05-25 20:47:33 UTC (rev 59344)
+++ trunk/Master/texmf-dist/source/latex/l3kernel/l3sys.dtx	2021-05-25 20:48:22 UTC (rev 59345)
@@ -43,7 +43,7 @@
 %    }^^A
 % }
 %
-% \date{Released 2021-05-11}
+% \date{Released 2021-05-25}
 %
 % \maketitle
 %
@@ -121,6 +121,17 @@
 %   \tn{fmtname}).
 % \end{variable}
 %
+% \begin{function}[added = 2020-09-24, EXP]{\sys_timer:}
+%   \begin{syntax}
+%     \cs{sys_timer:}
+%   \end{syntax}
+%   Expands to the current value of the engine's timer clock, a
+%   non-negative integer.  This function is only defined for engines with
+%   timer support.  This command measures not just CPU time but
+%   real time (including time waiting for user input).  The unit are
+%   scaled seconds ($2^{-16}$ seconds).
+% \end{function}
+%
 % \section{Output format}
 %
 % \begin{function}[added = 2015-09-19, EXP, pTF]
@@ -863,6 +874,53 @@
 %    \end{macrocode}
 % \end{macro}
 %
+% \begin{macro}[EXP]{\sys_timer:, \@@_elapsedtime:}
+% \begin{macro}[EXP, pTF]{\sys_if_timer_exist:}
+%   In \LuaTeX{}, create a pseudo-primitve, otherwise try to
+%   locate the real primitive.  The elapsed time will be
+%   available if this succeeds.
+%    \begin{macrocode}
+%</tex>
+%<*lua>
+  local gettimeofday = os.gettimeofday
+  local epoch = gettimeofday() - os.clock()
+  local write = tex.write
+  local tointeger = math.tointeger
+  luacmd('@@_elapsedtime:', function()
+    write(tointeger((gettimeofday() - epoch)*65536 // 1))
+  end, 'global')
+%</lua>
+%<*tex>
+\sys_if_engine_luatex:TF
+  {
+    \cs_new:Npn \sys_timer:
+      { \@@_elapsedtime: }
+  }
+  {
+    \cs_if_exist:NTF \tex_elapsedtime:D
+      {
+        \cs_new:Npn \sys_timer:
+          { \int_value:w \tex_elapsedtime:D }
+      }
+      {
+        \__kernel_msg_new:nnnn { kernel } { no-elapsed-time }
+          { No~clock~detected~for~#1. }
+          { The~current~engine~provides~no~way~to~access~the~system~time. }
+        \cs_new:Npn \sys_timer:
+          {
+            \int_value:w
+            \__kernel_msg_expandable_error:nnn { kernel } { no-elapsed-time }
+              { \sys_timer: }
+            \c_zero_int
+          }
+      }
+  }
+\@@_const:nn { sys_if_timer_exist }
+  { \cs_if_exist_p:N \tex_elapsedtime:D || \cs_if_exist_p:N \@@_elapsedtime: }
+%    \end{macrocode}
+% \end{macro}
+% \end{macro}
+%
 % \subsubsection{Access to the shell}
 %
 % \begin{variable}{\c_sys_shell_escape_int}

Modified: trunk/Master/texmf-dist/source/latex/l3kernel/l3text-case.dtx
===================================================================
--- trunk/Master/texmf-dist/source/latex/l3kernel/l3text-case.dtx	2021-05-25 20:47:33 UTC (rev 59344)
+++ trunk/Master/texmf-dist/source/latex/l3kernel/l3text-case.dtx	2021-05-25 20:48:22 UTC (rev 59345)
@@ -43,7 +43,7 @@
 %    }^^A
 % }
 %
-% \date{Released 2021-05-11}
+% \date{Released 2021-05-25}
 %
 % \maketitle
 %

Modified: trunk/Master/texmf-dist/source/latex/l3kernel/l3text-purify.dtx
===================================================================
--- trunk/Master/texmf-dist/source/latex/l3kernel/l3text-purify.dtx	2021-05-25 20:47:33 UTC (rev 59344)
+++ trunk/Master/texmf-dist/source/latex/l3kernel/l3text-purify.dtx	2021-05-25 20:48:22 UTC (rev 59345)
@@ -43,7 +43,7 @@
 %    }^^A
 % }
 %
-% \date{Released 2021-05-11}
+% \date{Released 2021-05-25}
 %
 % \maketitle
 %

Modified: trunk/Master/texmf-dist/source/latex/l3kernel/l3text.dtx
===================================================================
--- trunk/Master/texmf-dist/source/latex/l3kernel/l3text.dtx	2021-05-25 20:47:33 UTC (rev 59344)
+++ trunk/Master/texmf-dist/source/latex/l3kernel/l3text.dtx	2021-05-25 20:48:22 UTC (rev 59345)
@@ -43,7 +43,7 @@
 %    }^^A
 % }
 %
-% \date{Released 2021-05-11}
+% \date{Released 2021-05-25}
 %
 % \maketitle
 %
@@ -955,7 +955,7 @@
   }
 \cs_new:Npn \@@_expand_testopt:N #1
   {
-    \str_if_eq:nnTF {#1} { \@protected at testopt }
+    \token_if_eq_meaning:NNTF #1 \@protected at testopt
       { \@@_expand_testopt:NNn }
       { \@@_expand_encoding:N #1 }
   }

Modified: trunk/Master/texmf-dist/source/latex/l3kernel/l3tl-analysis.dtx
===================================================================
--- trunk/Master/texmf-dist/source/latex/l3kernel/l3tl-analysis.dtx	2021-05-25 20:47:33 UTC (rev 59344)
+++ trunk/Master/texmf-dist/source/latex/l3kernel/l3tl-analysis.dtx	2021-05-25 20:48:22 UTC (rev 59345)
@@ -44,7 +44,7 @@
 %    }^^A
 % }
 %
-% \date{Released 2021-05-11}
+% \date{Released 2021-05-25}
 %
 % \maketitle
 %
@@ -75,11 +75,16 @@
 % In addition, there is a debugging function \cs{tl_analysis_show:n},
 % very similar to the \cs[no-index]{ShowTokens} macro from the \pkg{ted} package.
 %
-% \begin{function}[added = 2018-04-09]{\tl_analysis_show:N, \tl_analysis_show:n}
+% \begin{function}[added = 2021-05-11]
+%   {
+%     \tl_analysis_show:N, \tl_analysis_show:n,
+%     \tl_analysis_log:N, \tl_analysis_log:n
+%   }
 %   \begin{syntax}
 %     \cs{tl_analysis_show:n} \Arg{token list}
+%     \cs{tl_analysis_log:n} \Arg{token list}
 %   \end{syntax}
-%   Displays to the terminal the detailed decomposition of the
+%   Displays to the terminal (or log) the detailed decomposition of the
 %   \meta{token list} into tokens, showing the category code of each
 %   character token, the meaning of control sequences and active
 %   characters, and the value of registers.
@@ -687,7 +692,7 @@
          plus \l_@@_analysis_type_int sp \scan_stop:
     \int_incr:N \l_@@_analysis_index_int
     \int_zero:N \l_@@_analysis_normal_int
-    \if_int_compare:w \l_@@_analysis_nesting_int = -1 \exp_stop_f:
+    \if_int_compare:w \l_@@_analysis_nesting_int = - \c_one_int
       \cs_set_eq:NN \@@_analysis_a_loop:w \scan_stop:
     \fi:
   }
@@ -733,7 +738,7 @@
   }
 \cs_new_protected:Npn \@@_analysis_a_cs:ww #1; #2;
   {
-    \if_int_compare:w #1 > 0 \exp_stop_f:
+    \if_int_compare:w #1 > \c_zero_int
       \tex_skip:D \l_@@_analysis_index_int
         = \int_eval:n { \l_@@_analysis_normal_int + 1 } sp \exp_stop_f:
       \tex_advance:D \l_@@_analysis_index_int #1 \exp_stop_f:
@@ -792,7 +797,7 @@
 %    \begin{macrocode}
 \cs_new:Npn \@@_analysis_b_normals:ww #1;
   {
-    \if_int_compare:w #1 = 0 \exp_stop_f:
+    \if_int_compare:w #1 = \c_zero_int
       \@@_analysis_b_special:w
     \fi:
     \@@_analysis_b_normal:wwN #1;
@@ -863,7 +868,7 @@
   {
     \exp_after:wN \@@_analysis_b_normals:ww
     \int_value:w \int_eval:w
-    \if_int_compare:w #1 = 0 \exp_stop_f:
+    \if_int_compare:w #1 = \c_zero_int
       #3
     \else:
       \tex_skip:D \int_eval:n { #4 + #1 } \exp_stop_f:
@@ -978,26 +983,39 @@
 %
 % \subsection{Showing the results}
 %
-% \begin{macro}{\tl_analysis_show:N, \tl_analysis_show:n}
+% \begin{macro}{\tl_analysis_show:N, \tl_analysis_log:N, \@@_analysis_show:NNN}
 %   Add to \cs{@@_analysis:n} a third pass to display tokens to the terminal.
 %   If the token list variable is not defined, throw the same error
 %   as \cs{tl_show:N} by simply calling that function.
 %    \begin{macrocode}
-\cs_new_protected:Npn \tl_analysis_show:N #1
+\cs_new_protected:Npn \tl_analysis_show:N
+  { \@@_analysis_show:NNN \__kernel_msg_show:nnxxxx \tl_show:N }
+\cs_new_protected:Npn \tl_analysis_log:N
+  { \@@_analysis_show:NNN \__kernel_msg_log:nnxxxx \tl_log:N }
+\cs_new_protected:Npn \@@_analysis_show:NNN #1#2#3
   {
-    \tl_if_exist:NTF #1
+    \tl_if_exist:NTF #3
       {
-        \exp_args:No \@@_analysis:n {#1}
-        \__kernel_msg_show:nnxxxx { tl } { show-analysis }
-          { \token_to_str:N #1 } { \@@_analysis_show: } { } { }
+        \exp_args:No \@@_analysis:n {#3}
+        #1 { tl } { show-analysis }
+          { \token_to_str:N #3 } { \@@_analysis_show: } { } { }
       }
-      { \tl_show:N #1 }
+      { #2 #3 }
   }
-\cs_new_protected:Npn \tl_analysis_show:n #1
+%    \end{macrocode}
+% \end{macro}
+%
+% \begin{macro}{\tl_analysis_show:n, \tl_analysis_log:n, \@@_analysis_show:Nn}
+%   No existence test needed here.
+%    \begin{macrocode}
+\cs_new_protected:Npn \tl_analysis_show:n
+  { \@@_analysis_show:Nn \__kernel_msg_show:nnxxxx }
+\cs_new_protected:Npn \tl_analysis_log:n
+  { \@@_analysis_show:Nn \__kernel_msg_log:nnxxxx }
+\cs_new_protected:Npn \@@_analysis_show:Nn #1#2
   {
-    \@@_analysis:n {#1}
-    \__kernel_msg_show:nnxxxx { tl } { show-analysis }
-      { } { \@@_analysis_show: } { } { }
+    \@@_analysis:n {#2}
+    #1 { tl } { show-analysis } { } { \@@_analysis_show: } { } { }
   }
 %    \end{macrocode}
 % \end{macro}
@@ -1021,7 +1039,7 @@
   {
     \use_none:n #2
     \iow_newline: > \use:nn { ~ } { ~ }
-    \if_int_compare:w "#2 = 0 \exp_stop_f:
+    \if_int_compare:w "#2 = \c_zero_int
       \exp_after:wN \@@_analysis_show_cs:n
     \else:
       \if_int_compare:w "#2 = 13 \exp_stop_f:
@@ -1206,10 +1224,10 @@
 \cs_new_protected:Npn \@@_peek_analysis_test:
   {
     \if_int_odd:w
-      \if_catcode:w \exp_not:N \l_peek_token {   0 \exp_stop_f: \fi:
-      \if_catcode:w \exp_not:N \l_peek_token }   0 \exp_stop_f: \fi:
-      \if_meaning:w \l_peek_token \c_space_token 0 \exp_stop_f: \fi:
-      1 \exp_stop_f:
+      \if_catcode:w \exp_not:N \l_peek_token {   \c_zero_int \fi:
+      \if_catcode:w \exp_not:N \l_peek_token }   \c_zero_int \fi:
+      \if_meaning:w \l_peek_token \c_space_token \c_zero_int \fi:
+      \c_one_int
       \exp_after:wN \exp_after:wN
       \exp_after:wN \@@_peek_analysis_normal:N
       \exp_after:wN \exp_not:N

Modified: trunk/Master/texmf-dist/source/latex/l3kernel/l3tl.dtx
===================================================================
--- trunk/Master/texmf-dist/source/latex/l3kernel/l3tl.dtx	2021-05-25 20:47:33 UTC (rev 59344)
+++ trunk/Master/texmf-dist/source/latex/l3kernel/l3tl.dtx	2021-05-25 20:48:22 UTC (rev 59345)
@@ -43,7 +43,7 @@
 %    }^^A
 % }
 %
-% \date{Released 2021-05-11}
+% \date{Released 2021-05-25}
 %
 % \maketitle
 %
@@ -350,6 +350,11 @@
 %     Otherwise, spaces (and tabs) are retained at both ends of the
 %     single-line string, as if it appeared in the middle of a line
 %     read from a file.
+%
+%     Contrarily to the \tn{scantokens} primitive, \cs{tl_rescan:nn}
+%     tokenizes the whole string in the same category code regime rather
+%     than one token at a time, so that directives such as \tn{verb}
+%     that rely on changing category codes will not function properly.
 %   \end{texnote}
 % \end{function}
 %
@@ -1317,9 +1322,9 @@
 %   Error checking is sorted out by the parent function.
 %    \begin{macrocode}
 \cs_new_protected:Npn \tl_clear:N  #1
-  { \tl_set_eq:NN #1 \c_empty_tl }
+  { \tex_let:D #1 = ~ \c_empty_tl }
 \cs_new_protected:Npn \tl_gclear:N #1
-  { \tl_gset_eq:NN #1 \c_empty_tl }
+  { \tex_global:D \tex_let:D #1 ~ \c_empty_tl }
 \cs_generate_variant:Nn \tl_clear:N  { c }
 \cs_generate_variant:Nn \tl_gclear:N { c }
 %    \end{macrocode}
@@ -1344,10 +1349,13 @@
 % \begin{macro}{\tl_set_eq:NN, \tl_set_eq:Nc, \tl_set_eq:cN, \tl_set_eq:cc}
 % \begin{macro}{\tl_gset_eq:NN, \tl_gset_eq:Nc, \tl_gset_eq:cN, \tl_gset_eq:cc}
 %   For setting token list variables equal to each other.  To allow for
-%   patching, the arguments have to be explicit.
+%   patching, the arguments have to be explicit.  In addition this
+%   ensures that a braced second argument will not cause problems.
 %    \begin{macrocode}
-\cs_new_protected:Npn \tl_set_eq:NN  #1#2 { \cs_set_eq:NN #1 #2 }
-\cs_new_protected:Npn \tl_gset_eq:NN #1#2 { \cs_gset_eq:NN #1 #2 }
+\cs_new_protected:Npn \tl_set_eq:NN  #1#2
+  { \tex_let:D #1 = ~ #2 }
+\cs_new_protected:Npn \tl_gset_eq:NN #1#2
+  { \tex_global:D \tex_let:D #1 = ~ #2 }
 \cs_generate_variant:Nn \tl_set_eq:NN { cN, Nc, cc }
 \cs_generate_variant:Nn \tl_gset_eq:NN { cN, Nc, cc }
 %    \end{macrocode}
@@ -1404,14 +1412,9 @@
 %   created the old-fashioned way.
 %    \begin{macrocode}
 \group_begin:
-\tex_lccode:D `A = `-
-\tex_lccode:D `N = `N
-\tex_lccode:D `V = `V
-\tex_lowercase:D
-  {
-    \group_end:
-    \tl_const:Nn \c_novalue_tl { ANoValue- }
-  }
+\tex_catcode:D `- = 11 ~
+\tl_const:Nx \c_novalue_tl { - NoValue \token_to_str:N - }
+\group_end:
 %    \end{macrocode}
 % \end{variable}
 %
@@ -2304,9 +2307,14 @@
 %
 % \begin{macro}[pTF, EXP]{\tl_if_novalue:n}
 % \begin{macro}[EXP]{\@@_if_novalue:w}
-%   Tests for |-NoValue-|: this is similar to \cs{tl_if_in:nn} but set
-%   up to be expandable and to check the value exactly.  The question
-%   mark prevents the auxiliary from losing braces.
+%   Tests whether |##1| matches |-NoValue-| exactly (with suitable
+%   catcodes): this is similar to \cs{quark_if_nil:nTF}.  The first
+%   argument of \cs{@@_if_novalue:w} is empty if and only if |##1|
+%   starts with |-NoValue-|, while the second argument is empty if |##1|
+%   is exactly |-NoValue-| or if it has a question mark just following
+%   |-NoValue-|.  In this second case, however, the material after the
+%   first |?!| remains and makes the emptyness test return
+%   \texttt{false}.
 %    \begin{macrocode}
 \cs_set_protected:Npn \@@_tmp:w #1
   {
@@ -2313,13 +2321,13 @@
     \prg_new_conditional:Npnn \tl_if_novalue:n ##1
       { p , T ,  F , TF }
       {
-        \str_if_eq:onTF
-          { \@@_if_novalue:w ? ##1 { } #1 }
-          { ? { } #1 }
-          { \prg_return_true: }
-          { \prg_return_false: }
+        \@@_if_empty_if:o { \@@_if_novalue:w {} ##1 {} ? ! #1 ? ? ! }
+          \prg_return_true:
+        \else:
+          \prg_return_false:
+        \fi:
       }
-    \cs_new:Npn \@@_if_novalue:w ##1 #1 {##1}
+    \cs_new:Npn \@@_if_novalue:w ##1 #1 ##2 ? ##3 ? ! { ##1 ##2 }
   }
 \exp_args:No \@@_tmp:w { \c_novalue_tl }
 %    \end{macrocode}
@@ -2460,37 +2468,56 @@
 %
 % \subsection{Mapping over token lists}
 %
-% \begin{macro}{\tl_map_function:nN}
-% \begin{macro}{\tl_map_function:NN, \tl_map_function:cN}
-% \begin{macro}{\@@_map_function:Nn}
-%   Expandable loop macro for token lists. These have the advantage of not
-%   needing to test if the argument is empty, because if it is, the stop
-%   marker is read immediately and the loop terminated.
+% \begin{macro}
+%   {
+%     \tl_map_function:nN, \tl_map_function:NN, \tl_map_function:cN,
+%     \@@_map_function:Nnnnnnnnn, \@@_map_function_end:w,
+%     \@@_use_none_delimit_by_s_stop:w
+%   }
+%   Expandable loop macro for token lists.  We use the internal scan
+%   mark \cs{s_@@_stop} (defined later), which is not allowed to show up
+%   in the token list |#1| since it is internal to \pkg{l3tl}.  This
+%   allows us a very fast test of whether some \meta{item} is the
+%   end-marker \cs{s_@@_stop}, namely call
+%   \cs{@@_use_none_delimit_by_s_stop:w} \meta{item} \meta{function}
+%   \cs{s_@@_stop}, which calls \meta{function} if the \meta{item} is
+%   the end-marker.  To speed up the loop even more, only test one out
+%   of eight items, and once we hit one of the eight end-markers,
+%   go more slowly through the last few items of the list using
+%   \cs{@@_map_function_end:w}.
 %    \begin{macrocode}
 \cs_new:Npn \tl_map_function:nN #1#2
   {
-    \@@_map_function:Nn #2 #1
-      \q_@@_recursion_tail
+    \@@_map_function:Nnnnnnnnn #2 #1
+      \s_@@_stop \s_@@_stop \s_@@_stop \s_@@_stop
+      \s_@@_stop \s_@@_stop \s_@@_stop \s_@@_stop
     \prg_break_point:Nn \tl_map_break: { }
   }
 \cs_new:Npn \tl_map_function:NN
   { \exp_args:No \tl_map_function:nN }
-\cs_new:Npn \@@_map_function:Nn #1#2
+\cs_generate_variant:Nn \tl_map_function:NN { c }
+\cs_new:Npn \@@_map_function:Nnnnnnnnn #1#2#3#4#5#6#7#8#9
   {
-    \@@_if_recursion_tail_break:nN {#2} \tl_map_break:
-    #1 {#2} \@@_map_function:Nn #1
+    \@@_use_none_delimit_by_s_stop:w
+      #9 \@@_map_function_end:w \s_@@_stop
+    #1 {#2} #1 {#3} #1 {#4} #1 {#5} #1 {#6} #1 {#7} #1 {#8} #1 {#9}
+    \@@_map_function:Nnnnnnnnn #1
   }
-\cs_generate_variant:Nn \tl_map_function:NN { c }
+\cs_new:Npn \@@_map_function_end:w \s_@@_stop #1#2
+  {
+    \@@_use_none_delimit_by_s_stop:w #2 \tl_map_break: \s_@@_stop
+    #1 {#2}
+    \@@_map_function_end:w \s_@@_stop
+  }
+\cs_new:Npn \@@_use_none_delimit_by_s_stop:w #1 \s_@@_stop { }
 %    \end{macrocode}
 % \end{macro}
-% \end{macro}
-% \end{macro}
 %
 % \begin{macro}{\tl_map_inline:nn}
 % \begin{macro}{\tl_map_inline:Nn, \tl_map_inline:cn}
 %   The inline functions are straight forward by now. We use a little
 %   trick with the counter \cs{g__kernel_prg_map_int} to make
-%   them nestable. We can also make use of \cs{@@_map_function:Nn}
+%   them nestable. We can also make use of \cs{@@_map_function:Nnnnnnnnn}
 %   from before.
 %    \begin{macrocode}
 \cs_new_protected:Npn \tl_map_inline:nn #1#2
@@ -2498,9 +2525,11 @@
     \int_gincr:N \g__kernel_prg_map_int
     \cs_gset_protected:cpn
       { @@_map_ \int_use:N \g__kernel_prg_map_int :w } ##1 {#2}
-    \exp_args:Nc \@@_map_function:Nn
+    \exp_args:Nc \@@_map_function:Nnnnnnnnn
       { @@_map_ \int_use:N \g__kernel_prg_map_int :w }
-      #1 \q_@@_recursion_tail
+      #1
+      \s_@@_stop \s_@@_stop \s_@@_stop \s_@@_stop
+      \s_@@_stop \s_@@_stop \s_@@_stop \s_@@_stop
     \prg_break_point:Nn \tl_map_break:
       { \int_gdecr:N \g__kernel_prg_map_int }
   }
@@ -2511,54 +2540,54 @@
 % \end{macro}
 % \end{macro}
 %
-% \begin{macro}{\tl_map_tokens:nn}
-% \begin{macro}{\tl_map_tokens:Nn, \tl_map_tokens:cn}
-% \begin{macro}{\@@_map_tokens:nn}
+% \begin{macro}
+%   {
+%     \tl_map_tokens:nn, \tl_map_tokens:Nn, \tl_map_tokens:cn,
+%     \@@_map_tokens:nnnnnnnnn, \@@_map_tokens_end:w
+%   }
 %   Much like the function mapping.
 %    \begin{macrocode}
 \cs_new:Npn \tl_map_tokens:nn #1#2
   {
-    \@@_map_tokens:nn {#2} #1
-      \q_@@_recursion_tail
+    \@@_map_tokens:nnnnnnnnn {#2} #1
+      \s_@@_stop \s_@@_stop \s_@@_stop \s_@@_stop
+      \s_@@_stop \s_@@_stop \s_@@_stop \s_@@_stop
     \prg_break_point:Nn \tl_map_break: { }
   }
 \cs_new:Npn \tl_map_tokens:Nn
   { \exp_args:No \tl_map_tokens:nn }
 \cs_generate_variant:Nn \tl_map_tokens:Nn { c }
-\cs_new:Npn \@@_map_tokens:nn #1#2
+\cs_new:Npn \@@_map_tokens:nnnnnnnnn #1#2#3#4#5#6#7#8#9
   {
-    \@@_if_recursion_tail_break:nN {#2} \tl_map_break:
-    \use:n {#1} {#2}
-    \@@_map_tokens:nn {#1}
+    \@@_use_none_delimit_by_s_stop:w
+      #9 \@@_map_tokens_end:w \s_@@_stop
+    \use:n {#1} {#2} \use:n {#1} {#3} \use:n {#1} {#4} \use:n {#1} {#5}
+    \use:n {#1} {#6} \use:n {#1} {#7} \use:n {#1} {#8} \use:n {#1} {#9}
+    \@@_map_tokens:nnnnnnnnn {#1}
   }
+\cs_new:Npn \@@_map_tokens_end:w \s_@@_stop \use:n #1#2
+  {
+    \@@_use_none_delimit_by_s_stop:w #2 \tl_map_break: \s_@@_stop
+    #1 {#2}
+    \@@_map_tokens_end:w \s_@@_stop
+  }
 %    \end{macrocode}
 % \end{macro}
-% \end{macro}
-% \end{macro}
 %
 % \begin{macro}{\tl_map_variable:nNn}
 % \begin{macro}{\tl_map_variable:NNn, \tl_map_variable:cNn}
 % \begin{macro}{\@@_map_variable:Nnn}
-%   \cs{tl_map_variable:nNn} \meta{token list} \meta{tl~var}
-%   \meta{action} assigns \meta{tl~var} to each element and executes
+%   \cs{tl_map_variable:nNn} \Arg{token list} \meta{tl~var}
+%   \Arg{action} assigns \meta{tl~var} to each element and executes
 %   \meta{action}.  The assignment to \meta{tl~var} is done after the
 %   quark test so that this variable does not get set to a quark.
 %    \begin{macrocode}
 \cs_new_protected:Npn \tl_map_variable:nNn #1#2#3
-  {
-    \@@_map_variable:Nnn #2 {#3} #1
-      \q_@@_recursion_tail
-    \prg_break_point:Nn \tl_map_break: { }
-  }
+  { \tl_map_tokens:nn {#1} { \@@_map_variable:Nnn #2 {#3} } }
+\cs_new_protected:Npn \@@_map_variable:Nnn #1#2#3
+  { \tl_set:Nn #1 {#3} #2 }
 \cs_new_protected:Npn \tl_map_variable:NNn
   { \exp_args:No \tl_map_variable:nNn }
-\cs_new_protected:Npn \@@_map_variable:Nnn #1#2#3
-  {
-    \@@_if_recursion_tail_break:nN {#3} \tl_map_break:
-    \tl_set:Nn #1 {#3}
-    \use:n {#2}
-    \@@_map_variable:Nnn #1 {#2}
-  }
 \cs_generate_variant:Nn \tl_map_variable:NNn { c }
 %    \end{macrocode}
 % \end{macro}
@@ -3439,7 +3468,7 @@
   }
 \cs_new:Npn \@@_range_skip:w #1 ; #2
   {
-    \if_int_compare:w #1 > 0 \exp_stop_f:
+    \if_int_compare:w #1 > \c_zero_int
       \exp_after:wN \@@_range_skip:w
       \int_value:w \int_eval:n { #1 - 1 } \exp_after:wN ;
     \else:
@@ -3499,7 +3528,7 @@
   {
     \int_eval:n
       {
-        \if_int_compare:w #1 < 0 \exp_stop_f:
+        \if_int_compare:w #1 < \c_zero_int
           \if_int_compare:w #1 < -#2 \exp_stop_f:
             0
           \else:

Modified: trunk/Master/texmf-dist/source/latex/l3kernel/l3token.dtx
===================================================================
--- trunk/Master/texmf-dist/source/latex/l3kernel/l3token.dtx	2021-05-25 20:47:33 UTC (rev 59344)
+++ trunk/Master/texmf-dist/source/latex/l3kernel/l3token.dtx	2021-05-25 20:48:22 UTC (rev 59345)
@@ -43,7 +43,7 @@
 %    }^^A
 % }
 %
-% \date{Released 2021-05-11}
+% \date{Released 2021-05-25}
 %
 % \maketitle
 %
@@ -1580,7 +1580,7 @@
 \cs_new:Npn \@@_generate_aux:w #1 ; #2 ;
   {
     \if_int_compare:w #2 = 10 \exp_stop_f:
-      \if_int_compare:w #1 =  0 \exp_stop_f:
+      \if_int_compare:w #1 =  \c_zero_int
         \__kernel_msg_expandable_error:nn { char } { null-space }
       \else:
         \__kernel_msg_expandable_error:nn { char } { space }
@@ -1595,7 +1595,7 @@
           { invalid-catcode }
       \else:
         \if_int_odd:w 0
-          \if_int_compare:w #1 < 0 \exp_stop_f: 1 \fi:
+          \if_int_compare:w #1 < \c_zero_int 1 \fi:
           \if_int_compare:w #1 > \c_max_char_int 1 \fi: \exp_stop_f:
           \__kernel_msg_expandable_error:nn { char }
             { out-of-range }
@@ -3143,10 +3143,10 @@
       \cs_new_protected:Npn \@@_execute_branches_N_type:
         {
           \if_int_odd:w
-              \if_catcode:w \exp_not:N \l_peek_token {   0 \exp_stop_f: \fi:
-              \if_catcode:w \exp_not:N \l_peek_token }   0 \exp_stop_f: \fi:
-              \if_meaning:w \l_peek_token \c_space_token 0 \exp_stop_f: \fi:
-              1 \exp_stop_f:
+              \if_catcode:w \exp_not:N \l_peek_token {   \c_zero_int \fi:
+              \if_catcode:w \exp_not:N \l_peek_token }   \c_zero_int \fi:
+              \if_meaning:w \l_peek_token \c_space_token \c_zero_int \fi:
+              \c_one_int
             \exp_after:wN \@@_N_type:w
               \token_to_meaning:N \l_peek_token
               \s_@@_mark \@@_N_type_aux:nnw

Modified: trunk/Master/texmf-dist/source/latex/l3kernel/l3unicode.dtx
===================================================================
--- trunk/Master/texmf-dist/source/latex/l3kernel/l3unicode.dtx	2021-05-25 20:47:33 UTC (rev 59344)
+++ trunk/Master/texmf-dist/source/latex/l3kernel/l3unicode.dtx	2021-05-25 20:48:22 UTC (rev 59345)
@@ -43,7 +43,7 @@
 %    }^^A
 % }
 %
-% \date{Released 2021-05-11}
+% \date{Released 2021-05-25}
 %
 % \maketitle
 %

Modified: trunk/Master/texmf-dist/tex/latex/l3kernel/expl3-code.tex
===================================================================
--- trunk/Master/texmf-dist/tex/latex/l3kernel/expl3-code.tex	2021-05-25 20:47:33 UTC (rev 59344)
+++ trunk/Master/texmf-dist/tex/latex/l3kernel/expl3-code.tex	2021-05-25 20:48:22 UTC (rev 59345)
@@ -70,7 +70,7 @@
 %% and all files in that bundle must be distributed together.
 %% 
 %% File: expl3.dtx
-\def\ExplFileDate{2021-05-11}%
+\def\ExplFileDate{2021-05-25}%
 \begingroup
   \def\next{\endgroup}%
   \expandafter\ifx\csname PackageError\endcsname\relax
@@ -2112,11 +2112,12 @@
   {
     \bool_if:NTF #3
       {
-        \str_if_eq:eeF { }
+        \cs_set_nopar:Npx \__cs_tmp:w
           { \tl_map_function:nN {#2} \__cs_generate_from_signature:n }
+        \tl_if_empty:oF \__cs_tmp:w
           {
-            \__kernel_msg_error:nnx { kernel } { non-base-function }
-              { \token_to_str:N #5 }
+            \__kernel_msg_error:nnxxx { kernel } { non-base-function }
+              { \token_to_str:N #5 } {#2} { \__cs_tmp:w }
           }
         \cs_generate_from_arg_count:NNnn
           #5 #4 { \tl_count:n {#2} } {#6}
@@ -2245,6 +2246,27 @@
     \group_end:
     #1 { \token_to_str:N #2 = \cs_meaning:N #2 }
   }
+\cs_new_protected:Npn \group_show_list:
+  { \__kernel_group_show:NN \use_none:n 1 }
+\cs_new_protected:Npn \group_log_list:
+  { \__kernel_group_show:NN \int_zero:N 0 }
+\cs_new_protected:Npn \__kernel_group_show:NN #1#2
+  {
+    \use:x
+      {
+        #1 \tex_interactionmode:D
+        \int_set:Nn \tex_tracingonline:D  {#2}
+        \int_set:Nn \tex_errorcontextlines:D { -1 }
+        \exp_not:N \exp_after:wN \scan_stop:
+        \tex_showgroups:D
+        \int_set:Nn \tex_interactionmode:D
+          { \int_use:N \tex_interactionmode:D }
+        \int_set:Nn \tex_tracingonline:D
+          { \int_use:N \tex_tracingonline:D }
+        \int_set:Nn \tex_errorcontextlines:D
+          { \int_use:N \tex_errorcontextlines:D }
+      }
+  }
 \use:x
   {
     \exp_not:n { \cs_new:Npn \__kernel_prefix_arg_replacement:wN #1 }
@@ -3652,9 +3674,9 @@
 \cs_generate_variant:Nn \tl_const:Nn { c }
 \cs_generate_variant:Nn \tl_const:Nx { c }
 \cs_new_protected:Npn \tl_clear:N  #1
-  { \tl_set_eq:NN #1 \c_empty_tl }
+  { \tex_let:D #1 = ~ \c_empty_tl }
 \cs_new_protected:Npn \tl_gclear:N #1
-  { \tl_gset_eq:NN #1 \c_empty_tl }
+  { \tex_global:D \tex_let:D #1 ~ \c_empty_tl }
 \cs_generate_variant:Nn \tl_clear:N  { c }
 \cs_generate_variant:Nn \tl_gclear:N { c }
 \cs_new_protected:Npn \tl_clear_new:N  #1
@@ -3663,8 +3685,10 @@
   { \tl_if_exist:NTF #1 { \tl_gclear:N #1 } { \tl_new:N #1 } }
 \cs_generate_variant:Nn \tl_clear_new:N  { c }
 \cs_generate_variant:Nn \tl_gclear_new:N { c }
-\cs_new_protected:Npn \tl_set_eq:NN  #1#2 { \cs_set_eq:NN #1 #2 }
-\cs_new_protected:Npn \tl_gset_eq:NN #1#2 { \cs_gset_eq:NN #1 #2 }
+\cs_new_protected:Npn \tl_set_eq:NN  #1#2
+  { \tex_let:D #1 = ~ #2 }
+\cs_new_protected:Npn \tl_gset_eq:NN #1#2
+  { \tex_global:D \tex_let:D #1 = ~ #2 }
 \cs_generate_variant:Nn \tl_set_eq:NN { cN, Nc, cc }
 \cs_generate_variant:Nn \tl_gset_eq:NN { cN, Nc, cc }
 \cs_new_protected:Npn \tl_concat:NNN #1#2#3
@@ -3689,14 +3713,9 @@
 \prg_new_eq_conditional:NNn \tl_if_exist:c \cs_if_exist:c { TF , T , F , p }
 \tl_const:Nn \c_empty_tl { }
 \group_begin:
-\tex_lccode:D `A = `-
-\tex_lccode:D `N = `N
-\tex_lccode:D `V = `V
-\tex_lowercase:D
-  {
-    \group_end:
-    \tl_const:Nn \c_novalue_tl { ANoValue- }
-  }
+\tex_catcode:D `- = 11 ~
+\tl_const:Nx \c_novalue_tl { - NoValue \token_to_str:N - }
+\group_end:
 \tl_const:Nn \c_space_tl { ~ }
 \cs_new_protected:Npn \tl_set:Nn #1#2
   { \__kernel_tl_set:Nx #1 { \__kernel_exp_not:w {#2} } }
@@ -4097,13 +4116,13 @@
     \prg_new_conditional:Npnn \tl_if_novalue:n ##1
       { p , T ,  F , TF }
       {
-        \str_if_eq:onTF
-          { \__tl_if_novalue:w ? ##1 { } #1 }
-          { ? { } #1 }
-          { \prg_return_true: }
-          { \prg_return_false: }
+        \__tl_if_empty_if:o { \__tl_if_novalue:w {} ##1 {} ? ! #1 ? ? ! }
+          \prg_return_true:
+        \else:
+          \prg_return_false:
+        \fi:
       }
-    \cs_new:Npn \__tl_if_novalue:w ##1 #1 {##1}
+    \cs_new:Npn \__tl_if_novalue:w ##1 #1 ##2 ? ##3 ? ! { ##1 ##2 }
   }
 \exp_args:No \__tl_tmp:w { \c_novalue_tl }
 \cs_new:Npn \tl_if_single_p:N { \exp_args:No \tl_if_single_p:n }
@@ -4170,26 +4189,38 @@
   { \exp_end: #1 #4 }
 \cs_new:Npn \tl_map_function:nN #1#2
   {
-    \__tl_map_function:Nn #2 #1
-      \q__tl_recursion_tail
+    \__tl_map_function:Nnnnnnnnn #2 #1
+      \s__tl_stop \s__tl_stop \s__tl_stop \s__tl_stop
+      \s__tl_stop \s__tl_stop \s__tl_stop \s__tl_stop
     \prg_break_point:Nn \tl_map_break: { }
   }
 \cs_new:Npn \tl_map_function:NN
   { \exp_args:No \tl_map_function:nN }
-\cs_new:Npn \__tl_map_function:Nn #1#2
+\cs_generate_variant:Nn \tl_map_function:NN { c }
+\cs_new:Npn \__tl_map_function:Nnnnnnnnn #1#2#3#4#5#6#7#8#9
   {
-    \__tl_if_recursion_tail_break:nN {#2} \tl_map_break:
-    #1 {#2} \__tl_map_function:Nn #1
+    \__tl_use_none_delimit_by_s_stop:w
+      #9 \__tl_map_function_end:w \s__tl_stop
+    #1 {#2} #1 {#3} #1 {#4} #1 {#5} #1 {#6} #1 {#7} #1 {#8} #1 {#9}
+    \__tl_map_function:Nnnnnnnnn #1
   }
-\cs_generate_variant:Nn \tl_map_function:NN { c }
+\cs_new:Npn \__tl_map_function_end:w \s__tl_stop #1#2
+  {
+    \__tl_use_none_delimit_by_s_stop:w #2 \tl_map_break: \s__tl_stop
+    #1 {#2}
+    \__tl_map_function_end:w \s__tl_stop
+  }
+\cs_new:Npn \__tl_use_none_delimit_by_s_stop:w #1 \s__tl_stop { }
 \cs_new_protected:Npn \tl_map_inline:nn #1#2
   {
     \int_gincr:N \g__kernel_prg_map_int
     \cs_gset_protected:cpn
       { __tl_map_ \int_use:N \g__kernel_prg_map_int :w } ##1 {#2}
-    \exp_args:Nc \__tl_map_function:Nn
+    \exp_args:Nc \__tl_map_function:Nnnnnnnnn
       { __tl_map_ \int_use:N \g__kernel_prg_map_int :w }
-      #1 \q__tl_recursion_tail
+      #1
+      \s__tl_stop \s__tl_stop \s__tl_stop \s__tl_stop
+      \s__tl_stop \s__tl_stop \s__tl_stop \s__tl_stop
     \prg_break_point:Nn \tl_map_break:
       { \int_gdecr:N \g__kernel_prg_map_int }
   }
@@ -4198,34 +4229,34 @@
 \cs_generate_variant:Nn \tl_map_inline:Nn { c }
 \cs_new:Npn \tl_map_tokens:nn #1#2
   {
-    \__tl_map_tokens:nn {#2} #1
-      \q__tl_recursion_tail
+    \__tl_map_tokens:nnnnnnnnn {#2} #1
+      \s__tl_stop \s__tl_stop \s__tl_stop \s__tl_stop
+      \s__tl_stop \s__tl_stop \s__tl_stop \s__tl_stop
     \prg_break_point:Nn \tl_map_break: { }
   }
 \cs_new:Npn \tl_map_tokens:Nn
   { \exp_args:No \tl_map_tokens:nn }
 \cs_generate_variant:Nn \tl_map_tokens:Nn { c }
-\cs_new:Npn \__tl_map_tokens:nn #1#2
+\cs_new:Npn \__tl_map_tokens:nnnnnnnnn #1#2#3#4#5#6#7#8#9
   {
-    \__tl_if_recursion_tail_break:nN {#2} \tl_map_break:
-    \use:n {#1} {#2}
-    \__tl_map_tokens:nn {#1}
+    \__tl_use_none_delimit_by_s_stop:w
+      #9 \__tl_map_tokens_end:w \s__tl_stop
+    \use:n {#1} {#2} \use:n {#1} {#3} \use:n {#1} {#4} \use:n {#1} {#5}
+    \use:n {#1} {#6} \use:n {#1} {#7} \use:n {#1} {#8} \use:n {#1} {#9}
+    \__tl_map_tokens:nnnnnnnnn {#1}
   }
-\cs_new_protected:Npn \tl_map_variable:nNn #1#2#3
+\cs_new:Npn \__tl_map_tokens_end:w \s__tl_stop \use:n #1#2
   {
-    \__tl_map_variable:Nnn #2 {#3} #1
-      \q__tl_recursion_tail
-    \prg_break_point:Nn \tl_map_break: { }
+    \__tl_use_none_delimit_by_s_stop:w #2 \tl_map_break: \s__tl_stop
+    #1 {#2}
+    \__tl_map_tokens_end:w \s__tl_stop
   }
+\cs_new_protected:Npn \tl_map_variable:nNn #1#2#3
+  { \tl_map_tokens:nn {#1} { \__tl_map_variable:Nnn #2 {#3} } }
+\cs_new_protected:Npn \__tl_map_variable:Nnn #1#2#3
+  { \tl_set:Nn #1 {#3} #2 }
 \cs_new_protected:Npn \tl_map_variable:NNn
   { \exp_args:No \tl_map_variable:nNn }
-\cs_new_protected:Npn \__tl_map_variable:Nnn #1#2#3
-  {
-    \__tl_if_recursion_tail_break:nN {#3} \tl_map_break:
-    \tl_set:Nn #1 {#3}
-    \use:n {#2}
-    \__tl_map_variable:Nnn #1 {#2}
-  }
 \cs_generate_variant:Nn \tl_map_variable:NNn { c }
 \cs_new:Npn \tl_map_break:
   { \prg_map_break:Nn \tl_map_break: { } }
@@ -4663,7 +4694,7 @@
   }
 \cs_new:Npn \__tl_range_skip:w #1 ; #2
   {
-    \if_int_compare:w #1 > 0 \exp_stop_f:
+    \if_int_compare:w #1 > \c_zero_int
       \exp_after:wN \__tl_range_skip:w
       \int_value:w \int_eval:n { #1 - 1 } \exp_after:wN ;
     \else:
@@ -4712,7 +4743,7 @@
   {
     \int_eval:n
       {
-        \if_int_compare:w #1 < 0 \exp_stop_f:
+        \if_int_compare:w #1 < \c_zero_int
           \if_int_compare:w #1 < -#2 \exp_stop_f:
             0
           \else:
@@ -4915,11 +4946,23 @@
 \prg_new_eq_conditional:NNn \str_if_empty:c \tl_if_empty:c
   { p , T , F , TF }
 \cs_new_eq:NN \__str_if_eq:nn \tex_strcmp:D
+\prg_new_conditional:Npnn \str_compare:nNn #1#2#3 { p , T , F , TF }
+  {
+    \if_int_compare:w
+      \__str_if_eq:nn { \exp_not:n {#1} } { \exp_not:n {#3} }
+      #2 \c_zero_int
+      \prg_return_true: \else: \prg_return_false: \fi:
+  }
+\prg_new_conditional:Npnn \str_compare:eNe #1#2#3 { p , T , F , TF }
+  {
+    \if_int_compare:w \__str_if_eq:nn {#1} {#3} #2 \c_zero_int
+      \prg_return_true: \else: \prg_return_false: \fi:
+  }
 \prg_new_conditional:Npnn \str_if_eq:nn #1#2 { p , T , F , TF }
   {
     \if_int_compare:w
       \__str_if_eq:nn { \exp_not:n {#1} } { \exp_not:n {#2} }
-      = 0 \exp_stop_f:
+      = \c_zero_int
       \prg_return_true: \else: \prg_return_false: \fi:
   }
 \prg_generate_conditional_variant:Nnn \str_if_eq:nn
@@ -4926,7 +4969,7 @@
   { V , v , o , nV , no , VV , nv } { p , T , F , TF }
 \prg_new_conditional:Npnn \str_if_eq:ee #1#2 { p , T , F , TF }
   {
-    \if_int_compare:w \__str_if_eq:nn {#1} {#2} = 0 \exp_stop_f:
+    \if_int_compare:w \__str_if_eq:nn {#1} {#2} = \c_zero_int
       \prg_return_true: \else: \prg_return_false: \fi:
   }
 \prg_new_conditional:Npnn \str_if_eq:NN #1#2 { p , TF , T , F }
@@ -4933,7 +4976,7 @@
   {
     \if_int_compare:w
       \__str_if_eq:nn { \tl_to_str:N #1 } { \tl_to_str:N #2 }
-      = 0 \exp_stop_f: \prg_return_true: \else: \prg_return_false: \fi:
+      = \c_zero_int \prg_return_true: \else: \prg_return_false: \fi:
   }
 \prg_generate_conditional_variant:Nnn \str_if_eq:NN
   { c , Nc , cc } { T , F , TF , p }
@@ -5232,7 +5275,7 @@
   {
     \int_eval:n
       {
-        \if_int_compare:w #1 < 0 \exp_stop_f:
+        \if_int_compare:w #1 < \c_zero_int
           \if_int_compare:w #1 < -#2 \exp_stop_f:
             0
           \else:
@@ -5267,7 +5310,7 @@
 \cs_new:Npn \__str_collect_end:wn #1 ;
   {
     \exp_after:wN \__str_collect_end:nnnnnnnnw
-    \if_case:w \if_int_compare:w #1 > 0 \exp_stop_f:
+    \if_case:w \if_int_compare:w #1 > \c_zero_int
       #1 \else: 0 \fi: \exp_stop_f:
       \or: \or: \or: \or: \or: \or: \fi:
   }
@@ -5883,13 +5926,21 @@
     \exp_after:wN \__seq_map_function:Nw
     \exp_after:wN #2
     #1
-    \prg_break: \__seq_item:n { } \prg_break_point:
+    \prg_break:
+    \__seq_item:n { } \__seq_item:n { } \__seq_item:n { } \__seq_item:n { }
+    \prg_break_point:
     \prg_break_point:Nn \seq_map_break: { }
   }
-\cs_new:Npn \__seq_map_function:Nw #1#2 \__seq_item:n #3
+\cs_new:Npn \__seq_map_function:Nw #1
+    #2 \__seq_item:n #3
+    #4 \__seq_item:n #5
+    #6 \__seq_item:n #7
+    #8 \__seq_item:n #9
   {
-    #2
-    #1 {#3}
+    #2 #1 {#3}
+    #4 #1 {#5}
+    #6 #1 {#7}
+    #8 #1 {#9}
     \__seq_map_function:Nw #1
   }
 \cs_generate_variant:Nn \seq_map_function:NN { c }
@@ -5926,14 +5977,22 @@
   {
     \exp_last_unbraced:Nno
       \use_i:nn { \__seq_map_tokens:nw {#2} } #1
-    \prg_break: \__seq_item:n { } \prg_break_point:
+    \prg_break:
+    \__seq_item:n { } \__seq_item:n { } \__seq_item:n { } \__seq_item:n { }
+    \prg_break_point:
     \prg_break_point:Nn \seq_map_break: { }
   }
 \cs_generate_variant:Nn \seq_map_tokens:Nn { c }
-\cs_new:Npn \__seq_map_tokens:nw #1#2 \__seq_item:n #3
+\cs_new:Npn \__seq_map_tokens:nw #1
+    #2 \__seq_item:n #3
+    #4 \__seq_item:n #5
+    #6 \__seq_item:n #7
+    #8 \__seq_item:n #9
   {
-    #2
-    \use:n {#1} {#3}
+    #2 \use:n {#1} {#3}
+    #4 \use:n {#1} {#5}
+    #6 \use:n {#1} {#7}
+    #8 \use:n {#1} {#9}
     \__seq_map_tokens:nw {#1}
   }
 \cs_new_protected:Npn \seq_map_variable:NNn #1#2#3
@@ -6137,8 +6196,8 @@
 \__kernel_quark_new_test:N \__int_if_recursion_tail_stop_do:Nn
 \__kernel_quark_new_test:N \__int_if_recursion_tail_stop:N
 \cs_new:Npn \int_eval:n #1
-  { \int_value:w \__int_eval:w #1 \__int_eval_end: }
-\cs_new:Npn \int_eval:w { \int_value:w \__int_eval:w }
+  { \tex_the:D \__int_eval:w #1 \__int_eval_end: }
+\cs_new:Npn \int_eval:w { \tex_the:D \__int_eval:w }
 \cs_new:Npn \int_sign:n #1
   {
     \int_value:w \exp_after:wN \__int_sign:Nw
@@ -6284,13 +6343,13 @@
 \prg_new_eq_conditional:NNn \int_if_exist:c \cs_if_exist:c
   { TF , T , F , p }
 \cs_new_protected:Npn \int_add:Nn #1#2
-  { \tex_advance:D #1 by \__int_eval:w #2 \__int_eval_end: }
+  { \tex_advance:D #1 \__int_eval:w #2 \__int_eval_end: }
 \cs_new_protected:Npn \int_sub:Nn #1#2
-  { \tex_advance:D #1 by - \__int_eval:w #2 \__int_eval_end: }
+  { \tex_advance:D #1 - \__int_eval:w #2 \__int_eval_end: }
 \cs_new_protected:Npn \int_gadd:Nn #1#2
-  { \tex_global:D \tex_advance:D #1 by \__int_eval:w #2 \__int_eval_end: }
+  { \tex_global:D \tex_advance:D #1 \__int_eval:w #2 \__int_eval_end: }
 \cs_new_protected:Npn \int_gsub:Nn #1#2
-  { \tex_global:D \tex_advance:D #1 by - \__int_eval:w #2 \__int_eval_end: }
+  { \tex_global:D \tex_advance:D #1 - \__int_eval:w #2 \__int_eval_end: }
 \cs_generate_variant:Nn \int_add:Nn  { c }
 \cs_generate_variant:Nn \int_gadd:Nn { c }
 \cs_generate_variant:Nn \int_sub:Nn  { c }
@@ -6308,9 +6367,9 @@
 \cs_generate_variant:Nn \int_gincr:N { c }
 \cs_generate_variant:Nn \int_gdecr:N { c }
 \cs_new_protected:Npn \int_set:Nn #1#2
-  { #1 ~ \__int_eval:w #2 \__int_eval_end: }
+  { #1 = \__int_eval:w #2 \__int_eval_end: }
 \cs_new_protected:Npn \int_gset:Nn #1#2
-  { \tex_global:D #1 ~ \__int_eval:w #2 \__int_eval_end: }
+  { \tex_global:D #1 = \__int_eval:w #2 \__int_eval_end: }
 \cs_generate_variant:Nn \int_set:Nn  { c }
 \cs_generate_variant:Nn \int_gset:Nn { c }
 \cs_new_eq:NN \int_use:N \tex_the:D
@@ -7618,6 +7677,32 @@
           }
       }
   }
+\sys_if_engine_luatex:TF
+  {
+    \cs_new:Npn \sys_timer:
+      { \__sys_elapsedtime: }
+  }
+  {
+    \cs_if_exist:NTF \tex_elapsedtime:D
+      {
+        \cs_new:Npn \sys_timer:
+          { \int_value:w \tex_elapsedtime:D }
+      }
+      {
+        \__kernel_msg_new:nnnn { kernel } { no-elapsed-time }
+          { No~clock~detected~for~#1. }
+          { The~current~engine~provides~no~way~to~access~the~system~time. }
+        \cs_new:Npn \sys_timer:
+          {
+            \int_value:w
+            \__kernel_msg_expandable_error:nnn { kernel } { no-elapsed-time }
+              { \sys_timer: }
+            \c_zero_int
+          }
+      }
+  }
+\__sys_const:nn { sys_if_timer_exist }
+  { \cs_if_exist_p:N \tex_elapsedtime:D || \cs_if_exist_p:N \__sys_elapsedtime: }
 \__sys_everyjob:n
   {
     \int_const:Nn \c_sys_shell_escape_int
@@ -7716,10 +7801,6 @@
 \cs_new:Npn \__clist_use_none_delimit_by_s_mark:w #1 \s__clist_mark { }
 \cs_new:Npn \__clist_use_none_delimit_by_s_stop:w #1 \s__clist_stop { }
 \cs_new:Npn \__clist_use_i_delimit_by_s_stop:nw #1 #2 \s__clist_stop {#1}
-\quark_new:N \q__clist_recursion_tail
-\quark_new:N \q__clist_recursion_stop
-\__kernel_quark_new_test:N \__clist_if_recursion_tail_break:nN
-\__kernel_quark_new_test:N \__clist_if_recursion_tail_stop:n
 \cs_new_protected:Npn \__clist_tmp:w { }
 \cs_new:Npn \__clist_trim_next:w #1 ,
   {
@@ -7731,11 +7812,11 @@
   {
     \exp_after:wN \__clist_sanitize:Nn \exp_after:wN \c_empty_tl
     \exp:w \__clist_trim_next:w \prg_do_nothing:
-    #1 , \q__clist_recursion_tail , \q__clist_recursion_stop
+    #1 , \s__clist_stop \prg_break: , \prg_break_point:
   }
 \cs_new:Npn \__clist_sanitize:Nn #1#2
   {
-    \__clist_if_recursion_tail_stop:n {#2}
+    \__clist_use_none_delimit_by_s_stop:w #2 \s__clist_stop
     #1 \__clist_wrap_item:w #2 ,
     \exp_after:wN \__clist_sanitize:Nn \exp_after:wN ,
     \exp:w \__clist_trim_next:w \prg_do_nothing:
@@ -7955,7 +8036,13 @@
     \clist_map_inline:Nn #2
       {
         \clist_if_in:NnF \l__clist_internal_remove_clist {##1}
-          { \clist_put_right:Nn \l__clist_internal_remove_clist {##1} }
+          {
+            \tl_put_right:Nx \l__clist_internal_remove_clist
+              {
+                \clist_if_empty:NF \l__clist_internal_remove_clist { , }
+                \__clist_if_wrap:nTF {##1} { \exp_not:n { {##1} } } { \exp_not:n {##1} }
+              }
+          }
       }
     #1 #2 \l__clist_internal_remove_clist
   }
@@ -8077,27 +8164,36 @@
   {
     \clist_if_empty:NF #1
       {
-        \exp_last_unbraced:NNo \__clist_map_function:nw #2 #1
-          , \q__clist_recursion_tail ,
+        \exp_after:wN \__clist_map_function:Nw \exp_after:wN #2 #1 ,
+          \s__clist_stop , \s__clist_stop , \s__clist_stop , \s__clist_stop ,
+          \s__clist_stop , \s__clist_stop , \s__clist_stop , \s__clist_stop ,
         \prg_break_point:Nn \clist_map_break: { }
       }
   }
-\cs_new:Npn \__clist_map_function:nw #1#2 ,
+\cs_new:Npn \__clist_map_function:Nw #1 #2, #3, #4, #5, #6, #7, #8, #9,
   {
-    \__clist_if_recursion_tail_break:nN {#2} \clist_map_break:
+    \__clist_use_none_delimit_by_s_stop:w
+      #9 \__clist_map_function_end:w \s__clist_stop
+    #1 {#2} #1 {#3} #1 {#4} #1 {#5} #1 {#6} #1 {#7} #1 {#8} #1 {#9}
+    \__clist_map_function:Nw #1
+  }
+\cs_new:Npn \__clist_map_function_end:w \s__clist_stop #1#2
+  {
+    \__clist_use_none_delimit_by_s_stop:w #2 \clist_map_break: \s__clist_stop
     #1 {#2}
-    \__clist_map_function:nw {#1}
+    \__clist_map_function_end:w \s__clist_stop
   }
 \cs_generate_variant:Nn \clist_map_function:NN { c }
 \cs_new:Npn \clist_map_function:nN #1#2
   {
     \exp_after:wN \__clist_map_function_n:Nn \exp_after:wN #2
-    \exp:w \__clist_trim_next:w \prg_do_nothing: #1 , \q__clist_recursion_tail ,
+    \exp:w \__clist_trim_next:w \prg_do_nothing: #1 ,
+      \s__clist_stop \clist_map_break: ,
     \prg_break_point:Nn \clist_map_break: { }
   }
 \cs_new:Npn \__clist_map_function_n:Nn #1 #2
   {
-    \__clist_if_recursion_tail_break:nN {#2} \clist_map_break:
+    \__clist_use_none_delimit_by_s_stop:w #2 \s__clist_stop
     \__clist_map_unbrace:wn #2 , #1
     \exp_after:wN \__clist_map_function_n:Nn \exp_after:wN #1
     \exp:w \__clist_trim_next:w \prg_do_nothing:
@@ -8110,9 +8206,11 @@
         \int_gincr:N \g__kernel_prg_map_int
         \cs_gset_protected:cpn
           { __clist_map_ \int_use:N \g__kernel_prg_map_int :w } ##1 {#2}
-        \exp_last_unbraced:Nco \__clist_map_function:nw
+        \exp_last_unbraced:Nco \__clist_map_function:Nw
           { __clist_map_ \int_use:N \g__kernel_prg_map_int :w }
-          #1 , \q__clist_recursion_tail ,
+          #1 ,
+          \s__clist_stop , \s__clist_stop , \s__clist_stop , \s__clist_stop ,
+          \s__clist_stop , \s__clist_stop , \s__clist_stop , \s__clist_stop ,
         \prg_break_point:Nn \clist_map_break:
           { \int_gdecr:N \g__kernel_prg_map_int }
       }
@@ -8124,43 +8222,44 @@
   }
 \cs_generate_variant:Nn \clist_map_inline:Nn { c }
 \cs_new_protected:Npn \clist_map_variable:NNn #1#2#3
-  {
-    \clist_if_empty:NF #1
-      {
-        \exp_args:Nno \use:nn
-          { \__clist_map_variable:Nnw #2 {#3} }
-          #1
-          , \q__clist_recursion_tail , \q__clist_recursion_stop
-        \prg_break_point:Nn \clist_map_break: { }
-      }
-  }
+  { \clist_map_tokens:Nn #1 { \__clist_map_variable:Nnn #2 {#3} } }
+\cs_generate_variant:Nn \clist_map_variable:NNn { c }
+\cs_new_protected:Npn \__clist_map_variable:Nnn #1#2#3
+  { \tl_set:Nn #1 {#3} #2 }
 \cs_new_protected:Npn \clist_map_variable:nNn #1
   {
     \clist_set:Nn \l__clist_internal_clist {#1}
     \clist_map_variable:NNn \l__clist_internal_clist
   }
-\cs_new_protected:Npn \__clist_map_variable:Nnw #1#2#3,
-  {
-    \__clist_if_recursion_tail_stop:n {#3}
-    \tl_set:Nn #1 {#3}
-    \use:n {#2}
-    \__clist_map_variable:Nnw #1 {#2}
-  }
-\cs_generate_variant:Nn \clist_map_variable:NNn { c }
 \cs_new:Npn \clist_map_tokens:Nn #1#2
   {
     \clist_if_empty:NF #1
       {
-        \exp_last_unbraced:Nno \__clist_map_function:nw {#2} #1
-          , \q__clist_recursion_tail ,
+        \exp_last_unbraced:Nno \__clist_map_tokens:nw {#2} #1 ,
+          \s__clist_stop , \s__clist_stop , \s__clist_stop , \s__clist_stop ,
+          \s__clist_stop , \s__clist_stop , \s__clist_stop , \s__clist_stop ,
         \prg_break_point:Nn \clist_map_break: { }
       }
   }
+\cs_new:Npn \__clist_map_tokens:nw #1 #2, #3, #4, #5, #6, #7, #8, #9,
+  {
+    \__clist_use_none_delimit_by_s_stop:w
+      #9 \__clist_map_tokens_end:w \s__clist_stop
+    \use:n {#1} {#2} \use:n {#1} {#3} \use:n {#1} {#4} \use:n {#1} {#5}
+    \use:n {#1} {#6} \use:n {#1} {#7} \use:n {#1} {#8} \use:n {#1} {#9}
+    \__clist_map_tokens:nw {#1}
+  }
+\cs_new:Npn \__clist_map_tokens_end:w \s__clist_stop \use:n #1#2
+  {
+    \__clist_use_none_delimit_by_s_stop:w #2 \clist_map_break: \s__clist_stop
+    #1 {#2}
+    \__clist_map_tokens_end:w \s__clist_stop
+  }
 \cs_generate_variant:Nn \clist_map_tokens:Nn { c }
 \cs_new:Npn \clist_map_tokens:nn #1#2
   {
     \__clist_map_tokens_n:nw {#2}
-    \prg_do_nothing: #1 , \q__clist_recursion_tail ,
+    \prg_do_nothing: #1 , \s__clist_stop \clist_map_break: ,
     \prg_break_point:Nn \clist_map_break: { }
   }
 \cs_new:Npn \__clist_map_tokens_n:nw #1#2 ,
@@ -8167,13 +8266,12 @@
   {
     \tl_if_empty:oF { \use_none:nn #2 ? }
       {
-        \exp_args:No \__clist_if_recursion_tail_break:nN {#2} \clist_map_break:
-        \tl_trim_spaces_apply:oN {#2} \__clist_use_ii_i:nn
+        \__clist_use_none_delimit_by_s_stop:w #2 \s__clist_stop
+        \tl_trim_spaces_apply:oN {#2} \use_ii_i:nn
         \__clist_map_unbrace:wn , {#1}
       }
     \__clist_map_tokens_n:nw {#1} \prg_do_nothing:
   }
-\cs_new:Npn \__clist_use_ii_i:nn #1#2 { #2 #1 }
 \cs_new:Npn \clist_map_break:
   { \prg_map_break:Nn \clist_map_break: { } }
 \cs_new:Npn \clist_map_break:n
@@ -8187,22 +8285,26 @@
       }
   }
 \cs_generate_variant:Nn \clist_count:N { c }
-\cs_new:Npx \clist_count:n #1
+\cs_new:Npn \__clist_count:n #1 { + 1 }
+\cs_set_protected:Npn \__clist_tmp:w #1
   {
-    \exp_not:N \int_eval:n
+    \cs_new:Npn \clist_count:n ##1
       {
-        0
-        \exp_not:N \__clist_count:w \c_space_tl
-        #1 \exp_not:n { , \q__clist_recursion_tail , \q__clist_recursion_stop }
+        \int_eval:n
+          {
+            0
+            \__clist_count:w #1
+            ##1 , \s__clist_stop \prg_break: , \prg_break_point:
+          }
       }
+    \cs_new:Npn \__clist_count:w ##1 ,
+      {
+        \__clist_use_none_delimit_by_s_stop:w ##1 \s__clist_stop
+        \tl_if_blank:nF {##1} { + 1 }
+        \__clist_count:w #1
+      }
   }
-\cs_new:Npn \__clist_count:n #1 { + 1 }
-\cs_new:Npx \__clist_count:w #1 ,
-  {
-    \exp_not:n { \exp_args:Nf \__clist_if_recursion_tail_stop:n } {#1}
-    \exp_not:N \tl_if_blank:nF {#1} { + 1 }
-    \exp_not:N \__clist_count:w \c_space_tl
-  }
+\exp_args:No \__clist_tmp:w \c_space_tl
 \cs_new:Npn \clist_use:Nnnn #1#2#3#4
   {
     \clist_if_exist:NTF #1
@@ -8252,7 +8354,7 @@
       { \__clist_use:Nw #1#2 ; }
       {
         \__clist_use_none_delimit_by_s_mark:w #4 #1 \s__clist_mark
-        \tl_trim_spaces_apply:oN {#4} \__clist_use_ii_i:nn
+        \tl_trim_spaces_apply:oN {#4} \use_ii_i:nn
         \__clist_map_unbrace:wn , { #2 ; }
       }
     #3 ; \prg_do_nothing:
@@ -8508,7 +8610,7 @@
 \cs_new:Npn \__char_generate_aux:w #1 ; #2 ;
   {
     \if_int_compare:w #2 = 10 \exp_stop_f:
-      \if_int_compare:w #1 =  0 \exp_stop_f:
+      \if_int_compare:w #1 =  \c_zero_int
         \__kernel_msg_expandable_error:nn { char } { null-space }
       \else:
         \__kernel_msg_expandable_error:nn { char } { space }
@@ -8523,7 +8625,7 @@
           { invalid-catcode }
       \else:
         \if_int_odd:w 0
-          \if_int_compare:w #1 < 0 \exp_stop_f: 1 \fi:
+          \if_int_compare:w #1 < \c_zero_int 1 \fi:
           \if_int_compare:w #1 > \c_max_char_int 1 \fi: \exp_stop_f:
           \__kernel_msg_expandable_error:nn { char }
             { out-of-range }
@@ -9302,10 +9404,10 @@
       \cs_new_protected:Npn \__peek_execute_branches_N_type:
         {
           \if_int_odd:w
-              \if_catcode:w \exp_not:N \l_peek_token {   0 \exp_stop_f: \fi:
-              \if_catcode:w \exp_not:N \l_peek_token }   0 \exp_stop_f: \fi:
-              \if_meaning:w \l_peek_token \c_space_token 0 \exp_stop_f: \fi:
-              1 \exp_stop_f:
+              \if_catcode:w \exp_not:N \l_peek_token {   \c_zero_int \fi:
+              \if_catcode:w \exp_not:N \l_peek_token }   \c_zero_int \fi:
+              \if_meaning:w \l_peek_token \c_space_token \c_zero_int \fi:
+              \c_one_int
             \exp_after:wN \__peek_N_type:w
               \token_to_meaning:N \l_peek_token
               \s__peek_mark \__peek_N_type_aux:nnw
@@ -9380,6 +9482,18 @@
 \prop_new:N \g_tmpa_prop
 \prop_new:N \g_tmpb_prop
 \prop_new:N \l__prop_internal_prop
+\cs_new_protected:Npn \prop_concat:NNN
+  { \__prop_concat:NNNN \prop_set_eq:NN }
+\cs_generate_variant:Nn \prop_concat:NNN { ccc }
+\cs_new_protected:Npn \prop_gconcat:NNN
+  { \__prop_concat:NNNN \prop_gset_eq:NN }
+\cs_generate_variant:Nn \prop_gconcat:NNN { ccc }
+\cs_new_protected:Npn \__prop_concat:NNNN #1#2#3#4
+  {
+    \prop_set_eq:NN \l__prop_internal_prop #3
+    \prop_map_tokens:Nn #4 { \prop_put:Nnn \l__prop_internal_prop }
+    #1 #2 \l__prop_internal_prop
+  }
 \cs_new_protected:Npn \prop_set_from_keyval:Nn #1#2
   {
     \prop_clear:N \l__prop_internal_prop
@@ -9404,6 +9518,22 @@
     \prop_clear:N \l__prop_internal_prop
   }
 \cs_generate_variant:Nn \prop_const_from_keyval:Nn { c }
+\cs_new_protected:Npn \prop_put_from_keyval:Nn #1#2
+  {
+    \prop_set_eq:NN \l__prop_internal_prop #1
+    \__prop_from_keyval:n {#2}
+    \prop_set_eq:NN #1 \l__prop_internal_prop
+    \prop_clear:N \l__prop_internal_prop
+  }
+\cs_generate_variant:Nn \prop_put_from_keyval:Nn { c }
+\cs_new_protected:Npn \prop_gput_from_keyval:Nn #1#2
+  {
+    \prop_set_eq:NN \l__prop_internal_prop #1
+    \__prop_from_keyval:n {#2}
+    \prop_gset_eq:NN #1 \l__prop_internal_prop
+    \prop_clear:N \l__prop_internal_prop
+  }
+\cs_generate_variant:Nn \prop_gput_from_keyval:Nn { c }
 \cs_new_protected:Npn \__prop_from_keyval:n #1
   {
     \__prop_from_keyval_loop:w \prg_do_nothing: #1 ,
@@ -9429,10 +9559,10 @@
   { \__prop_from_keyval_value:w #1 \s__prop_mark }
 \cs_new_protected:Npn \__prop_from_keyval_value:w #1 \s__prop_mark #2 \s__prop_stop #3#4
   {
-    \tl_if_empty:nF { #3 #1 #2 }
+    \tl_if_single:nTF {#2}
+      { \prop_put:Nnn \l__prop_internal_prop {#3} {#1} }
       {
-        \str_if_eq:nnTF {#2} { = }
-          { \prop_put:Nnn \l__prop_internal_prop {#3} {#1} }
+        \tl_if_empty:nF { #3 #1 #2 }
           {
             \__kernel_msg_error:nnx { prop } { prop-keyval }
               { \exp_not:o {#4} }
@@ -9498,15 +9628,13 @@
 \cs_generate_variant:Nn \prop_gpop:NnN { c , co }
 \cs_new:Npn \prop_item:Nn #1#2
   {
-    \exp_last_unbraced:Noo \__prop_item_Nn:nwwn { \tl_to_str:n {#2} } #1
-      \__prop_pair:wn \tl_to_str:n {#2} \s__prop { }
-    \prg_break_point:
+    \exp_args:NNo \prop_map_tokens:Nn #1
+      { \exp_after:wN \__prop_item:nnn \exp_after:wN { \tl_to_str:n {#2} } }
   }
-\cs_new:Npn \__prop_item_Nn:nwwn #1#2 \__prop_pair:wn #3 \s__prop #4
+\cs_new:Npn \__prop_item:nnn #1#2#3
   {
-    \str_if_eq:eeTF {#1} {#3}
-      { \prg_break:n { \exp_not:n {#4} } }
-      { \__prop_item_Nn:nwwn {#1} }
+    \str_if_eq:eeT {#1} {#2}
+      { \prop_map_break:n { \exp_not:n {#3} } }
   }
 \cs_generate_variant:Nn \prop_item:Nn { c }
 \cs_new:Npn \prop_count:N #1
@@ -9592,26 +9720,15 @@
   { c } { p , T , F , TF }
 \prg_new_conditional:Npnn \prop_if_in:Nn #1#2 { p , T , F , TF }
   {
-    \exp_last_unbraced:Noo \__prop_if_in:nwwn { \tl_to_str:n {#2} } #1
-      \__prop_pair:wn \tl_to_str:n {#2} \s__prop { }
-      \q__prop_recursion_tail
-    \prg_break_point:
+    \exp_args:NNo \prop_map_tokens:Nn #1
+      { \exp_after:wN \__prop_if_in:nnn \exp_after:wN { \tl_to_str:n {#2} } }
+    \prg_return_false:
   }
-\cs_new:Npn \__prop_if_in:nwwn #1#2 \__prop_pair:wn #3 \s__prop #4
+\cs_new:Npn \__prop_if_in:nnn #1#2#3
   {
-    \str_if_eq:eeTF {#1} {#3}
-      { \__prop_if_in:N }
-      { \__prop_if_in:nwwn {#1} }
+    \str_if_eq:eeT {#1} {#2}
+      { \prop_map_break:n { \use_i:nn \prg_return_true: } }
   }
-\cs_new:Npn \__prop_if_in:N #1
-  {
-    \if_meaning:w \q__prop_recursion_tail #1
-      \prg_return_false:
-    \else:
-      \prg_return_true:
-    \fi:
-    \prg_break:
-  }
 \prg_generate_conditional_variant:Nnn \prop_if_in:Nn
   { NV , No , c , cV , co } { p , T , F , TF }
 \prg_new_protected_conditional:Npnn \prop_get:NnN #1#2#3 { T , F , TF }
@@ -9628,17 +9745,26 @@
 \cs_new:Npn \prop_map_function:NN #1#2
   {
     \exp_after:wN \use_i_ii:nnn
-    \exp_after:wN \__prop_map_function:Nwwn
+    \exp_after:wN \__prop_map_function:Nw
     \exp_after:wN #2
     #1
-    \prg_break: \__prop_pair:wn \s__prop { } \prg_break_point:
+    \__prop_pair:wn \fi: \prop_map_break: \s__prop { }
+    \__prop_pair:wn \fi: \prop_map_break: \s__prop { }
+    \__prop_pair:wn \fi: \prop_map_break: \s__prop { }
+    \__prop_pair:wn \fi: \prop_map_break: \s__prop { }
     \prg_break_point:Nn \prop_map_break: { }
   }
-\cs_new:Npn \__prop_map_function:Nwwn #1#2 \__prop_pair:wn #3 \s__prop #4
+\cs_new:Npn \__prop_map_function:Nw #1
+    \__prop_pair:wn #2 \s__prop #3
+    \__prop_pair:wn #4 \s__prop #5
+    \__prop_pair:wn #6 \s__prop #7
+    \__prop_pair:wn #8 \s__prop #9
   {
-    #2
-    #1 {#3} {#4}
-    \__prop_map_function:Nwwn #1
+    \if_false: #2 \fi: #1 {#2} {#3}
+    \if_false: #4 \fi: #1 {#4} {#5}
+    \if_false: #6 \fi: #1 {#6} {#7}
+    \if_false: #8 \fi: #1 {#8} {#9}
+    \__prop_map_function:Nw #1
   }
 \cs_generate_variant:Nn \prop_map_function:NN { Nc , c , cc }
 \cs_new_protected:Npn \prop_map_inline:Nn #1#2
@@ -9659,15 +9785,24 @@
 \cs_new:Npn \prop_map_tokens:Nn #1#2
   {
     \exp_last_unbraced:Nno
-      \use_i:nn { \__prop_map_tokens:nwwn {#2} } #1
-      \prg_break: \__prop_pair:wn \s__prop { } \prg_break_point:
+      \use_i:nn { \__prop_map_tokens:nw {#2} } #1
+    \__prop_pair:wn \fi: \prop_map_break: \s__prop { }
+    \__prop_pair:wn \fi: \prop_map_break: \s__prop { }
+    \__prop_pair:wn \fi: \prop_map_break: \s__prop { }
+    \__prop_pair:wn \fi: \prop_map_break: \s__prop { }
     \prg_break_point:Nn \prop_map_break: { }
   }
-\cs_new:Npn \__prop_map_tokens:nwwn #1#2 \__prop_pair:wn #3 \s__prop #4
+\cs_new:Npn \__prop_map_tokens:nw #1
+    \__prop_pair:wn #2 \s__prop #3
+    \__prop_pair:wn #4 \s__prop #5
+    \__prop_pair:wn #6 \s__prop #7
+    \__prop_pair:wn #8 \s__prop #9
   {
-    #2
-    \use:n {#1} {#3} {#4}
-    \__prop_map_tokens:nwwn {#1}
+    \if_false: #2 \fi: \use:n {#1} {#2} {#3}
+    \if_false: #4 \fi: \use:n {#1} {#4} {#5}
+    \if_false: #6 \fi: \use:n {#1} {#6} {#7}
+    \if_false: #8 \fi: \use:n {#1} {#8} {#9}
+    \__prop_map_tokens:nw {#1}
   }
 \cs_generate_variant:Nn \prop_map_tokens:Nn { c }
 \cs_new:Npn \prop_map_break:
@@ -9894,7 +10029,7 @@
 \cs_new:Npn \__msg_text:nn #1#2
   {
     \exp_args:Nf \__msg_text:n { \msg_module_type:n {#1} }
-    \msg_module_name:n {#1} ~
+    \exp_args:Nf \__msg_text:n { \msg_module_name:n {#1} }
     #2
   }
 \cs_new:Npn \__msg_text:n #1
@@ -10012,17 +10147,23 @@
         { } \iow_term:n
       \iow_term:n { }
     }
+  \__msg_class_new:nn { note }
+    {
+      \__msg_info_aux:Nnn \iow_term:n {#1}
+        { \use:c { \c__msg_text_prefix_tl #1 / #2 } {#3} {#4} {#5} {#6} }
+    }
   \__msg_class_new:nn { info }
     {
-      \str_set:Nx \l__msg_text_str { \msg_info_text:n {#1} }
-      \str_set:Nx \l__msg_name_str { \msg_module_name:n {#1} }
-      \iow_log:n { }
-      \iow_wrap:nxnN
+      \__msg_info_aux:Nnn \iow_log:n {#1}
+        { \use:c { \c__msg_text_prefix_tl #1 / #2 } {#3} {#4} {#5} {#6} }
+    }
+  \cs_new_protected:Npn \__msg_info_aux:Nnn #1#2#3
+    {
+      \str_set:Nx \l__msg_text_str { \msg_info_text:n {#2} }
+      \str_set:Nx \l__msg_name_str { \msg_module_name:n {#2} }
+      #1 { }
+      \iow_wrap:nxnN { \l__msg_text_str : ~ #3 }
         {
-          \l__msg_text_str : ~
-          \use:c { \c__msg_text_prefix_tl #1 / #2 } {#3} {#4} {#5} {#6}
-        }
-        {
           ( \l__msg_name_str )
           \prg_replicate:nn
              {
@@ -10031,8 +10172,8 @@
              }
             { ~ }
          }
-         { } \iow_log:n
-      \iow_log:n { }
+         { } #1
+       #1 { }
     }
   \__msg_class_new:nn { log }
     {
@@ -10273,6 +10414,9 @@
 \cs_new_protected:Npn \__kernel_msg_log:nnnnnn #1
   { \msg_log:nnnnnn { LaTeX / #1 } }
 \cs_generate_variant:Nn \__kernel_msg_log:nnnnnn { nnxxxx }
+\cs_new_protected:Npn \__kernel_msg_term:nnnnnn #1
+  { \msg_term:nnnnnn { LaTeX / #1 } }
+\cs_generate_variant:Nn \__kernel_msg_term:nnnnnn { nnxxxx }
 \cs_new_protected:Npn \__kernel_msg_show:nnnnnn #1
   { \msg_show:nnnnnn { LaTeX / #1 } }
 \cs_generate_variant:Nn \__kernel_msg_show:nnnnnn { nnxxxx }
@@ -10355,6 +10499,7 @@
     \c__msg_coding_error_text_tl
     Functions~defined~through~\iow_char:N\\cs_new:Nn~must~have~
     a~signature~consisting~of~only~normal~arguments~'N'~and~'n'.~
+    The~signature~'#2'~of~'#1'~contains~other~arguments~'#3'.~
     To~define~variants~use~\iow_char:N\\cs_generate_variant:Nn~
     and~to~define~other~functions~use~\iow_char:N\\cs_new:Npn.
   }
@@ -10774,6 +10919,22 @@
       }
   }
 \cs_generate_variant:Nn \ior_close:N { c }
+\cs_new_protected:Npn \ior_show:N { \__ior_show:NN \tl_show:n }
+\cs_generate_variant:Nn \ior_show:N { c }
+\cs_new_protected:Npn \ior_log:N { \__ior_show:NN \tl_log:n }
+\cs_generate_variant:Nn \ior_log:N { c }
+\cs_new_protected:Npn \__ior_show:NN #1#2
+  {
+    \__kernel_chk_defined:NT #2
+      {
+        \prop_get:NVNTF \g__ior_streams_prop #2 \l__ior_internal_tl
+          {
+            \exp_args:Nx #1
+              { \token_to_str:N #2 ~ open: ~ \l__ior_internal_tl }
+          }
+          { \exp_args:Nx #1 { \token_to_str:N #2 ~ closed } }
+      }
+  }
 \cs_new_protected:Npn \ior_show_list: { \__ior_list:N \__kernel_msg_show:nnxxxx }
 \cs_new_protected:Npn \ior_log_list: { \__ior_list:N \__kernel_msg_log:nnxxxx }
 \cs_new_protected:Npn \__ior_list:N #1
@@ -10900,6 +11061,7 @@
     #4
     \__ior_map_variable_loop:NNNn #1#2#3 {#4}
   }
+\tl_new:N  \l__iow_internal_tl
 \int_const:Nn \c_log_iow  { -1 }
 \int_const:Nn \c_term_iow
   {
@@ -10970,6 +11132,22 @@
       }
   }
 \cs_generate_variant:Nn \iow_close:N { c }
+\cs_new_protected:Npn \iow_show:N { \__iow_show:NN \tl_show:n }
+\cs_generate_variant:Nn \iow_show:N { c }
+\cs_new_protected:Npn \iow_log:N { \__iow_show:NN \tl_log:n }
+\cs_generate_variant:Nn \iow_log:N { c }
+\cs_new_protected:Npn \__iow_show:NN #1#2
+  {
+    \__kernel_chk_defined:NT #2
+      {
+        \prop_get:NVNTF \g__iow_streams_prop #2 \l__iow_internal_tl
+          {
+            \exp_args:Nx #1
+              { \token_to_str:N #2 ~ open: ~ \l__iow_internal_tl }
+          }
+          { \exp_args:Nx #1 { \token_to_str:N #2 ~ closed } }
+      }
+  }
 \cs_new_protected:Npn \iow_show_list: { \__iow_list:N \__kernel_msg_show:nnxxxx }
 \cs_new_protected:Npn \iow_log_list: { \__iow_list:N \__kernel_msg_log:nnxxxx }
 \cs_new_protected:Npn \__iow_list:N #1
@@ -11831,7 +12009,7 @@
               \__file_str_cmp:nn
                 { \__file_timestamp:n {#1} }
                 { \__file_timestamp:n {#2} }
-                #3 0 \exp_stop_f:
+                #3 \c_zero_int
               \prg_return_true:
             \else:
               \prg_return_false:
@@ -12191,12 +12369,12 @@
 \cs_new_protected:Npn \dim_const:Nn #1#2
   {
     \dim_new:N #1
-    \tex_global:D #1 ~ \dim_eval:n {#2} \scan_stop:
+    \tex_global:D #1 = \dim_eval:n {#2} \scan_stop:
   }
 \cs_generate_variant:Nn \dim_const:Nn { c }
-\cs_new_protected:Npn \dim_zero:N #1 { #1 \c_zero_skip }
+\cs_new_protected:Npn \dim_zero:N #1 { #1 = \c_zero_skip }
 \cs_new_protected:Npn \dim_gzero:N #1
-  { \tex_global:D #1 \c_zero_skip }
+  { \tex_global:D #1 = \c_zero_skip }
 \cs_generate_variant:Nn \dim_zero:N  { c }
 \cs_generate_variant:Nn \dim_gzero:N { c }
 \cs_new_protected:Npn \dim_zero_new:N  #1
@@ -12210,9 +12388,9 @@
 \prg_new_eq_conditional:NNn \dim_if_exist:c \cs_if_exist:c
   { TF , T , F , p }
 \cs_new_protected:Npn \dim_set:Nn #1#2
-  { #1 ~ \__dim_eval:w #2 \__dim_eval_end: \scan_stop: }
+  { #1 = \__dim_eval:w #2 \__dim_eval_end: \scan_stop: }
 \cs_new_protected:Npn \dim_gset:Nn #1#2
-  { \tex_global:D #1 ~ \__dim_eval:w #2 \__dim_eval_end: \scan_stop: }
+  { \tex_global:D #1 = \__dim_eval:w #2 \__dim_eval_end: \scan_stop: }
 \cs_generate_variant:Nn \dim_set:Nn  { c }
 \cs_generate_variant:Nn \dim_gset:Nn { c }
 \cs_new_protected:Npn \dim_set_eq:NN #1#2
@@ -12222,19 +12400,19 @@
   { \tex_global:D #1 = #2 \scan_stop: }
 \cs_generate_variant:Nn \dim_gset_eq:NN { c , Nc , cc }
 \cs_new_protected:Npn \dim_add:Nn #1#2
-  { \tex_advance:D #1 by \__dim_eval:w #2 \__dim_eval_end: \scan_stop: }
+  { \tex_advance:D #1 \__dim_eval:w #2 \__dim_eval_end: \scan_stop: }
 \cs_new_protected:Npn \dim_gadd:Nn #1#2
   {
-    \tex_global:D \tex_advance:D #1 by
+    \tex_global:D \tex_advance:D #1
       \__dim_eval:w #2 \__dim_eval_end: \scan_stop:
   }
 \cs_generate_variant:Nn \dim_add:Nn  { c }
 \cs_generate_variant:Nn \dim_gadd:Nn { c }
 \cs_new_protected:Npn \dim_sub:Nn #1#2
-  { \tex_advance:D #1 by - \__dim_eval:w #2 \__dim_eval_end: \scan_stop: }
+  { \tex_advance:D #1 - \__dim_eval:w #2 \__dim_eval_end: \scan_stop: }
 \cs_new_protected:Npn \dim_gsub:Nn #1#2
   {
-    \tex_global:D \tex_advance:D #1 by
+    \tex_global:D \tex_advance:D #1
       -\__dim_eval:w #2 \__dim_eval_end: \scan_stop:
   }
 \cs_generate_variant:Nn \dim_sub:Nn  { c }
@@ -12493,7 +12671,7 @@
       ##1 . ##2 \tl_to_str:n { pt }
   }
       {
-        \int_compare:nNnTF {#2} > { 0 }
+        \int_compare:nNnTF {#2} > \c_zero_int
           { #1 . #2 }
           { #1 }
       }
@@ -12533,11 +12711,11 @@
 \cs_new_protected:Npn \skip_const:Nn #1#2
   {
     \skip_new:N #1
-    \tex_global:D #1 ~ \skip_eval:n {#2} \scan_stop:
+    \tex_global:D #1 = \skip_eval:n {#2} \scan_stop:
   }
 \cs_generate_variant:Nn \skip_const:Nn { c }
-\cs_new_protected:Npn \skip_zero:N #1 { #1 \c_zero_skip }
-\cs_new_protected:Npn \skip_gzero:N #1 { \tex_global:D #1 \c_zero_skip }
+\cs_new_eq:NN \skip_zero:N  \dim_zero:N
+\cs_new_eq:NN \skip_gzero:N \dim_gzero:N
 \cs_generate_variant:Nn \skip_zero:N  { c }
 \cs_generate_variant:Nn \skip_gzero:N { c }
 \cs_new_protected:Npn \skip_zero_new:N  #1
@@ -12551,9 +12729,9 @@
 \prg_new_eq_conditional:NNn \skip_if_exist:c \cs_if_exist:c
   { TF , T , F , p }
 \cs_new_protected:Npn \skip_set:Nn #1#2
-  { #1 ~ \tex_glueexpr:D #2 \scan_stop: }
+  { #1 = \tex_glueexpr:D #2 \scan_stop: }
 \cs_new_protected:Npn \skip_gset:Nn #1#2
-  { \tex_global:D #1 ~ \tex_glueexpr:D #2 \scan_stop: }
+  { \tex_global:D #1 = \tex_glueexpr:D #2 \scan_stop: }
 \cs_generate_variant:Nn \skip_set:Nn  { c }
 \cs_generate_variant:Nn \skip_gset:Nn { c }
 \cs_new_protected:Npn \skip_set_eq:NN #1#2 { #1 = #2 }
@@ -12561,20 +12739,20 @@
 \cs_new_protected:Npn \skip_gset_eq:NN #1#2 { \tex_global:D #1 = #2 }
 \cs_generate_variant:Nn \skip_gset_eq:NN { c , Nc , cc }
 \cs_new_protected:Npn \skip_add:Nn #1#2
-  { \tex_advance:D #1 by \tex_glueexpr:D #2 \scan_stop: }
+  { \tex_advance:D #1 \tex_glueexpr:D #2 \scan_stop: }
 \cs_new_protected:Npn \skip_gadd:Nn #1#2
-  { \tex_global:D \tex_advance:D #1 by \tex_glueexpr:D #2 \scan_stop: }
+  { \tex_global:D \tex_advance:D #1 \tex_glueexpr:D #2 \scan_stop: }
 \cs_generate_variant:Nn \skip_add:Nn  { c }
 \cs_generate_variant:Nn \skip_gadd:Nn { c }
 \cs_new_protected:Npn \skip_sub:Nn #1#2
-  { \tex_advance:D #1 by - \tex_glueexpr:D #2 \scan_stop: }
+  { \tex_advance:D #1 - \tex_glueexpr:D #2 \scan_stop: }
 \cs_new_protected:Npn \skip_gsub:Nn #1#2
-  { \tex_global:D \tex_advance:D #1 by - \tex_glueexpr:D #2 \scan_stop: }
+  { \tex_global:D \tex_advance:D #1 - \tex_glueexpr:D #2 \scan_stop: }
 \cs_generate_variant:Nn \skip_sub:Nn  { c }
 \cs_generate_variant:Nn \skip_gsub:Nn { c }
 \prg_new_conditional:Npnn \skip_if_eq:nn #1#2 { p , T , F , TF }
   {
-    \str_if_eq:eeTF { \skip_eval:n { #1 } } { \skip_eval:n { #2 } }
+    \str_if_eq:eeTF { \skip_eval:n {#1} } { \skip_eval:n {#2} }
        { \prg_return_true: }
        { \prg_return_false: }
   }
@@ -12591,8 +12769,8 @@
 \exp_args:No \__skip_tmp:w { \tl_to_str:n { fil } }
 \cs_new:Npn \skip_eval:n #1
   { \skip_use:N \tex_glueexpr:D #1 \scan_stop: }
-\cs_new_eq:NN \skip_use:N \tex_the:D
-\cs_new:Npn \skip_use:c #1 { \tex_the:D \cs:w #1 \cs_end: }
+\cs_new_eq:NN \skip_use:N \dim_use:N
+\cs_new_eq:NN \skip_use:c \dim_use:c
 \cs_new_eq:NN  \skip_horizontal:N \tex_hskip:D
 \cs_new:Npn \skip_horizontal:n #1
   { \skip_horizontal:N \tex_glueexpr:D #1 \scan_stop: }
@@ -12624,13 +12802,13 @@
 \cs_new_protected:Npn \muskip_const:Nn #1#2
   {
     \muskip_new:N #1
-    \tex_global:D #1 ~ \muskip_eval:n {#2} \scan_stop:
+    \tex_global:D #1 = \muskip_eval:n {#2} \scan_stop:
   }
 \cs_generate_variant:Nn \muskip_const:Nn { c }
 \cs_new_protected:Npn \muskip_zero:N #1
-  { #1 \c_zero_muskip }
+  { #1 = \c_zero_muskip }
 \cs_new_protected:Npn \muskip_gzero:N #1
-  { \tex_global:D #1 \c_zero_muskip }
+  { \tex_global:D #1 = \c_zero_muskip }
 \cs_generate_variant:Nn \muskip_zero:N  { c }
 \cs_generate_variant:Nn \muskip_gzero:N { c }
 \cs_new_protected:Npn \muskip_zero_new:N  #1
@@ -12644,9 +12822,9 @@
 \prg_new_eq_conditional:NNn \muskip_if_exist:c \cs_if_exist:c
   { TF , T , F , p }
 \cs_new_protected:Npn \muskip_set:Nn #1#2
-  { #1 ~ \tex_muexpr:D #2 \scan_stop: }
+  { #1 = \tex_muexpr:D #2 \scan_stop: }
 \cs_new_protected:Npn \muskip_gset:Nn #1#2
-  { \tex_global:D #1 ~ \tex_muexpr:D #2 \scan_stop: }
+  { \tex_global:D #1 = \tex_muexpr:D #2 \scan_stop: }
 \cs_generate_variant:Nn \muskip_set:Nn  { c }
 \cs_generate_variant:Nn \muskip_gset:Nn { c }
 \cs_new_protected:Npn \muskip_set_eq:NN #1#2 { #1 = #2 }
@@ -12654,21 +12832,21 @@
 \cs_new_protected:Npn \muskip_gset_eq:NN #1#2 { \tex_global:D #1 = #2 }
 \cs_generate_variant:Nn \muskip_gset_eq:NN { c , Nc , cc }
 \cs_new_protected:Npn \muskip_add:Nn #1#2
-  { \tex_advance:D #1 by \tex_muexpr:D #2 \scan_stop: }
+  { \tex_advance:D #1 \tex_muexpr:D #2 \scan_stop: }
 \cs_new_protected:Npn \muskip_gadd:Nn #1#2
-  { \tex_global:D \tex_advance:D #1 by \tex_muexpr:D #2 \scan_stop: }
+  { \tex_global:D \tex_advance:D #1 \tex_muexpr:D #2 \scan_stop: }
 \cs_generate_variant:Nn \muskip_add:Nn  { c }
 \cs_generate_variant:Nn \muskip_gadd:Nn { c }
 \cs_new_protected:Npn \muskip_sub:Nn #1#2
-  { \tex_advance:D #1 by - \tex_muexpr:D #2 \scan_stop: }
+  { \tex_advance:D #1 - \tex_muexpr:D #2 \scan_stop: }
 \cs_new_protected:Npn \muskip_gsub:Nn #1#2
-  { \tex_global:D \tex_advance:D #1 by - \tex_muexpr:D #2 \scan_stop: }
+  { \tex_global:D \tex_advance:D #1 - \tex_muexpr:D #2 \scan_stop: }
 \cs_generate_variant:Nn \muskip_sub:Nn  { c }
 \cs_generate_variant:Nn \muskip_gsub:Nn { c }
 \cs_new:Npn \muskip_eval:n #1
   { \muskip_use:N \tex_muexpr:D #1 \scan_stop: }
-\cs_new_eq:NN \muskip_use:N \tex_the:D
-\cs_generate_variant:Nn \muskip_use:N { c }
+\cs_new_eq:NN \muskip_use:N \dim_use:N
+\cs_new_eq:NN \muskip_use:c \dim_use:c
 \cs_new_eq:NN  \muskip_show:N \__kernel_register_show:N
 \cs_generate_variant:Nn \muskip_show:N { c }
 \cs_new_protected:Npn \muskip_show:n
@@ -12689,13 +12867,30 @@
 \scan_new:N \s__keyval_stop
 \scan_new:N \s__keyval_tail
 \group_begin:
-  \cs_set_protected:Npn \__keyval_tmp:NN #1#2
+  \cs_set_protected:Npn \__keyval_tmp:w #1#2
     {
-      \cs_new:Npn \keyval_parse:nnn ##1 ##2 ##3
+      \cs_if_exist:NTF \tex_expanded:D
         {
-          \group_align_safe_begin:
-          \__keyval_loop_active:nnw {##1} {##2} \s__keyval_mark ##3 #1 \s__keyval_tail #1
+          \cs_new:Npn \keyval_parse:nnn ##1 ##2 ##3
+            {
+              \__kernel_exp_not:w \tex_expanded:D
+                {
+                  {
+                    \__keyval_loop_active:nnw {##1} {##2}
+                      \s__keyval_mark ##3 #1 \s__keyval_tail #1
+                  }
+                }
+            }
         }
+        {
+          \cs_new:Npn \keyval_parse:nnn ##1 ##2 ##3
+            {
+              \group_align_safe_begin:
+              \__keyval_loop_active:nnw {##1} {##2}
+                \s__keyval_mark ##3 #1 \s__keyval_tail #1
+              \group_align_safe_end:
+            }
+        }
       \cs_new_eq:NN \keyval_parse:NNn \keyval_parse:nnn
       \cs_new:Npn \__keyval_loop_active:nnw ##1 ##2 ##3 #1
         {
@@ -12804,40 +12999,47 @@
       \cs_new:Npn \__keyval_end_loop_active:w
           \s__keyval_tail
           \__keyval_loop_other:nnw ##1 \s__keyval_mark \s__keyval_tail , \s__keyval_tail ,
-        { \group_align_safe_end: }
+        { }
     }
   \char_set_catcode_active:n { `\, }
   \char_set_catcode_active:n { `\= }
-  \__keyval_tmp:NN , =
+  \__keyval_tmp:w , =
 \group_end:
-\cs_new:Npn \__keyval_pair:nnnn #1 #2 #3 #4
-  {
-    \__keyval_if_blank:w \s__keyval_mark #2 \s__keyval_nil \s__keyval_stop \__keyval_blank_key_error:w
-      \s__keyval_mark \s__keyval_stop
-    \group_align_safe_end:
-    \exp_not:n { #4 { #2 } { #1 } }
-    \group_align_safe_begin:
-    \__keyval_loop_other:nnw {#3} {#4}
-  }
-\cs_new:Npn \__keyval_key:nn #1 #2
-  {
-    \__keyval_if_blank:w \s__keyval_mark #1 \s__keyval_nil \s__keyval_stop \__keyval_blank_key_error:w
-      \s__keyval_mark \s__keyval_stop
-    \group_align_safe_end:
-    \exp_not:n { #2 { #1 } }
-    \group_align_safe_begin:
-    \__keyval_loop_other:nnw {#2}
-  }
+\group_begin:
+  \cs_set_protected:Npn \__keyval_tmp:w #1#2
+    {
+      \cs_new:Npn \__keyval_pair:nnnn ##1 ##2 ##3 ##4
+        {
+          \__keyval_if_blank:w \s__keyval_mark ##2 \s__keyval_nil \s__keyval_stop \__keyval_blank_key_error:w
+            \s__keyval_mark \s__keyval_stop
+          #1
+          \exp_not:n { ##4 {##2} {##1} }
+          #2
+          \__keyval_loop_other:nnw {##3} {##4}
+        }
+      \cs_new:Npn \__keyval_key:nn ##1 ##2
+        {
+          \__keyval_if_blank:w \s__keyval_mark ##1 \s__keyval_nil \s__keyval_stop \__keyval_blank_key_error:w
+            \s__keyval_mark \s__keyval_stop
+          #1
+          \exp_not:n { ##2 {##1} }
+          #2
+          \__keyval_loop_other:nnw {##2}
+        }
+    }
+  \cs_if_exist:NTF \tex_expanded:D
+    { \__keyval_tmp:w { } { } }
+    { \__keyval_tmp:w \group_align_safe_end: \group_align_safe_begin: }
+\group_end:
 \cs_new:Npn \__keyval_if_empty:w #1 \s__keyval_mark \s__keyval_stop { }
 \cs_new:Npn \__keyval_if_blank:w \s__keyval_mark #1 { \__keyval_if_empty:w \s__keyval_mark }
 \cs_new:Npn \__keyval_if_recursion_tail:w \s__keyval_mark #1 \s__keyval_tail { }
 \cs_new:Npn \__keyval_blank_true:w \s__keyval_mark \s__keyval_stop \__keyval_trim:nN #1 \__keyval_key:nn
   { \__keyval_loop_other:nnw }
-\cs_new:Npn \__keyval_blank_key_error:w
-  \s__keyval_mark \s__keyval_stop \group_align_safe_end: \exp_not:n #1
+\cs_new:Npn \__keyval_blank_key_error:w #1 \__keyval_loop_other:nnw
   {
-    \__kernel_msg_expandable_error:nn
-      { keyval } { blank-key-name }
+    \__kernel_msg_expandable_error:nn { keyval } { blank-key-name }
+    \__keyval_loop_other:nnw
   }
 \__kernel_msg_new:nnn { keyval } { misplaced-equals-sign }
   { Misplaced~equals~sign~in~key-value~input~\msg_line_context: }
@@ -12844,7 +13046,7 @@
 \__kernel_msg_new:nnn { keyval } { blank-key-name }
   { Blank~key~name~in~key-value~input~\msg_line_context: }
 \group_begin:
-  \cs_set_protected:Npn \__keyval_tmp:n #1
+  \cs_set_protected:Npn \__keyval_tmp:w #1
     {
       \cs_new:Npn \__keyval_trim:nN ##1
         {
@@ -12882,7 +13084,7 @@
           ##2
         { ##2 { ##1 } }
     }
-  \__keyval_tmp:n { ~ }
+  \__keyval_tmp:w { ~ }
 \group_end:
 \str_const:Nn \c__keys_code_root_str     { key~code~>~ }
 \str_const:Nn \c__keys_default_root_str  { key~default~>~ }
@@ -13817,7 +14019,7 @@
   {
   }
 \group_begin:
-  \cs_set:Npn \__keys_tmp:n #1
+  \cs_set:Npn \__keys_tmp:w #1
     {
       \cs_new:Npn \__keys_trim_spaces:n ##1
         {
@@ -13829,7 +14031,7 @@
             \s__keys_mark \__keys_trim_spaces_auxiii:w
         }
     }
-  \__keys_tmp:n { ~ }
+  \__keys_tmp:w { ~ }
 \group_end:
 \cs_new:Npn \__keys_trim_spaces_auxi:w #1 ~ / #2 \s__keys_nil #3
   {
@@ -14566,7 +14768,7 @@
     \if_meaning:w 0 #1
       \exp_after:wN \__fp_small_int_true:wTF
       \int_value:w \if_meaning:w 2 #5 - \fi:
-        \if_int_compare:w #2 > 0 \exp_stop_f:
+        \if_int_compare:w #2 > \c_zero_int
           1 0000 0000
         \else:
           #3
@@ -14786,21 +14988,21 @@
 \cs_new:Npn \__fp_round_to_ninf:NNN #1 #2 #3
   {
     \if_meaning:w 2 #1
-      \if_int_compare:w #3 > 0 \exp_stop_f:
+      \if_int_compare:w #3 > \c_zero_int
         \__fp_round_return_one:
       \fi:
     \fi:
-    0 \exp_stop_f:
+    \c_zero_int
   }
-\cs_new:Npn \__fp_round_to_zero:NNN #1 #2 #3 { 0 \exp_stop_f: }
+\cs_new:Npn \__fp_round_to_zero:NNN #1 #2 #3 { \c_zero_int }
 \cs_new:Npn \__fp_round_to_pinf:NNN #1 #2 #3
   {
     \if_meaning:w 0 #1
-      \if_int_compare:w #3 > 0 \exp_stop_f:
+      \if_int_compare:w #3 > \c_zero_int
         \__fp_round_return_one:
       \fi:
     \fi:
-    0 \exp_stop_f:
+    \c_zero_int
   }
 \cs_new:Npn \__fp_round_to_nearest:NNN #1 #2 #3
   {
@@ -14813,7 +15015,7 @@
         \fi:
       \fi:
     \fi:
-    0 \exp_stop_f:
+    \c_zero_int
   }
 \cs_new:Npn \__fp_round_to_nearest_ninf:NNN #1 #2 #3
   {
@@ -14826,7 +15028,7 @@
         \fi:
       \fi:
     \fi:
-    0 \exp_stop_f:
+    \c_zero_int
   }
 \cs_new:Npn \__fp_round_to_nearest_zero:NNN #1 #2 #3
   {
@@ -14833,7 +15035,7 @@
     \if_int_compare:w #3 > \c__fp_five_int
       \__fp_round_return_one:
     \fi:
-    0 \exp_stop_f:
+    \c_zero_int
   }
 \cs_new:Npn \__fp_round_to_nearest_pinf:NNN #1 #2 #3
   {
@@ -14846,7 +15048,7 @@
         \fi:
       \fi:
     \fi:
-    0 \exp_stop_f:
+    \c_zero_int
   }
 \cs_new_eq:NN \__fp_round:NNN \__fp_round_to_nearest:NNN
 \cs_new:Npn \__fp_round_s:NNNw #1 #2 #3 #4;
@@ -14858,7 +15060,7 @@
       \if_int_odd:w 0 \if_meaning:w 0 #3 1 \fi:
                       \if_meaning:w 5 #3 1 \fi:
                 \exp_stop_f:
-        \if_int_compare:w \__fp_int_eval:w #4 > 0 \exp_stop_f:
+        \if_int_compare:w \__fp_int_eval:w #4 > \c_zero_int
           1 +
         \fi:
       \fi:
@@ -14870,7 +15072,7 @@
     \if_int_odd:w \if_meaning:w 0 #1 1 \else:
                   \if_meaning:w 5 #1 1 \else:
                   0 \fi: \fi: \exp_stop_f:
-      \if_int_compare:w \__fp_int_eval:w #2 > 0 \exp_stop_f:
+      \if_int_compare:w \__fp_int_eval:w #2 > \c_zero_int
         \__fp_int_eval:w 1 +
       \fi:
     \fi:
@@ -14879,10 +15081,10 @@
 \cs_new_eq:NN \__fp_round_to_ninf_neg:NNN \__fp_round_to_pinf:NNN
 \cs_new:Npn \__fp_round_to_zero_neg:NNN #1 #2 #3
   {
-    \if_int_compare:w #3 > 0 \exp_stop_f:
+    \if_int_compare:w #3 > \c_zero_int
       \__fp_round_return_one:
     \fi:
-    0 \exp_stop_f:
+    \c_zero_int
   }
 \cs_new_eq:NN \__fp_round_to_pinf_neg:NNN \__fp_round_to_ninf:NNN
 \cs_new_eq:NN \__fp_round_to_nearest_neg:NNN \__fp_round_to_nearest:NNN
@@ -14893,7 +15095,7 @@
     \if_int_compare:w #3 < \c__fp_five_int \else:
       \__fp_round_return_one:
     \fi:
-    0 \exp_stop_f:
+    \c_zero_int
   }
 \cs_new_eq:NN \__fp_round_to_nearest_pinf_neg:NNN
   \__fp_round_to_nearest_ninf:NNN
@@ -14999,12 +15201,12 @@
   {
     \exp_after:wN \__fp_round_normal:NNwNnn
     \int_value:w \__fp_int_eval:w
-      \if_int_compare:w #2 > 0 \exp_stop_f:
+      \if_int_compare:w #2 > \c_zero_int
         1 \int_value:w #2
         \exp_after:wN \__fp_round_pack:Nw
         \int_value:w \__fp_int_eval:w 1#3 +
       \else:
-        \if_int_compare:w #3 > 0 \exp_stop_f:
+        \if_int_compare:w #3 > \c_zero_int
           1 \int_value:w #3 +
         \fi:
       \fi:
@@ -15666,7 +15868,7 @@
       \if_meaning:w \scan_stop: #1
         \if_int_compare:w
             \__fp_str_if_eq:nn { \s__fp } { \exp_not:N #1 }
-            = 0 \exp_stop_f:
+            = \c_zero_int
           0
           \__kernel_msg_expandable_error:nnn
             { fp } { after-e } { floating~point~ }
@@ -15680,7 +15882,7 @@
       \else:
         \if_int_compare:w
             \__fp_str_if_eq:nn { \int_value:w #1 } { \tex_the:D #1 }
-            = 0 \exp_stop_f:
+            = \c_zero_int
           \int_value:w #1
         \else:
           0
@@ -15968,7 +16170,7 @@
     \if_catcode:w \scan_stop: \exp_not:N #2
       \if_int_compare:w
           \__fp_str_if_eq:nn { \s__fp_expr_mark } { \exp_not:N #2 }
-          = 0 \exp_stop_f:
+          = \c_zero_int
         \exp_after:wN \exp_after:wN
         \exp_after:wN \__fp_parse_infix_mark:NNN
       \else:
@@ -16012,7 +16214,7 @@
     \if_catcode:w \scan_stop: \exp_not:N #2
       \if_int_compare:w
           \__fp_str_if_eq:nn { \s__fp_expr_mark } { \exp_not:N #2 }
-          = 0 \exp_stop_f:
+          = \c_zero_int
         \exp_after:wN \exp_after:wN
         \exp_after:wN \__fp_parse_infix_mark:NNN
       \else:
@@ -16569,7 +16771,7 @@
           \if_int_compare:w #4 < #1 - \fi: 1
         \fi:
       \else:
-        \if_int_compare:w #1#4 = 0 \exp_stop_f:
+        \if_int_compare:w #1#4 = \c_zero_int
           0
         \else:
           1
@@ -16601,7 +16803,7 @@
     \use_none:n #1
     \use_none:n #4
     \if_int_compare:w
-        \__fp_compare_back_any:ww #1 #2 ; #4 #5 ; = 0 \exp_stop_f:
+        \__fp_compare_back_any:ww #1 #2 ; #4 #5 ; = \c_zero_int
     \else:
       2 \exp_after:wN \prg_break:
     \fi:
@@ -17547,15 +17749,15 @@
 \cs_new:Npn \__fp_sqrt_auxiii_o:wnnnnnnnn
     #1; #2#3#4#5#6#7#8#9
   {
-    \if_int_compare:w #1 > 1 \exp_stop_f:
+    \if_int_compare:w #1 > \c_one_int
       \exp_after:wN \__fp_sqrt_auxiv_o:NNNNNw
       \int_value:w \__fp_int_eval:w (#1#2 %)
     \else:
-      \if_int_compare:w #1#2 > 1 \exp_stop_f:
+      \if_int_compare:w #1#2 > \c_one_int
         \exp_after:wN \__fp_sqrt_auxv_o:NNNNNw
         \int_value:w \__fp_int_eval:w (#1#2#3 %)
       \else:
-        \if_int_compare:w #1#2#3 > 1 \exp_stop_f:
+        \if_int_compare:w #1#2#3 > \c_one_int
           \exp_after:wN \__fp_sqrt_auxvi_o:NNNNNw
           \int_value:w \__fp_int_eval:w (#1#2#3#4 %)
         \else:
@@ -17573,7 +17775,7 @@
   { \__fp_sqrt_auxviii_o:nnnnnnn {0000000#1} {#2#3#4#5#6} }
 \cs_new:Npn \__fp_sqrt_auxvii_o:NNNNNw 1#1#2#3#4#5#6;
   {
-    \if_int_compare:w #1#2 = 0 \exp_stop_f:
+    \if_int_compare:w #1#2 = \c_zero_int
       \exp_after:wN \__fp_sqrt_auxx_o:Nnnnnnnn
     \fi:
     \__fp_sqrt_auxviii_o:nnnnnnn {00000000} {000#1#2#3#4#5}
@@ -17608,11 +17810,11 @@
   }
 \cs_new:Npn \__fp_sqrt_auxxii_o:nnnnnnnnw 0; #1#2#3#4#5#6#7#8 #9;
   {
-    \if_int_compare:w #1#2 > 0 \exp_stop_f:
-      \if_int_compare:w #1#2 = 1 \exp_stop_f:
-        \if_int_compare:w #3#4 = 0 \exp_stop_f:
-          \if_int_compare:w #5#6 = 0 \exp_stop_f:
-            \if_int_compare:w #7#8 = 0 \exp_stop_f:
+    \if_int_compare:w #1#2 > \c_zero_int
+      \if_int_compare:w #1#2 = \c_one_int
+        \if_int_compare:w #3#4 = \c_zero_int
+          \if_int_compare:w #5#6 = \c_zero_int
+            \if_int_compare:w #7#8 = \c_zero_int
               \__fp_sqrt_auxxiii_o:w
             \fi:
           \fi:
@@ -18196,7 +18398,7 @@
   { %^^A todo: ln(1) should be "exact zero", not "underflow"
     \exp_after:wN \__fp_sanitize:Nw
     \int_value:w % for the overall sign
-      \if_int_compare:w #1 < 1 \exp_stop_f:
+      \if_int_compare:w #1 < \c_one_int
         2
       \else:
         0
@@ -18339,7 +18541,7 @@
   { \__fp_ln_Taylor_loop:www 21 ; {0000}{0000}{0000}{0000}{0000}{0000} ; }
 \cs_new:Npn \__fp_ln_Taylor_loop:www #1; #2; #3;
   {
-    \if_int_compare:w #1 = 1 \exp_stop_f:
+    \if_int_compare:w #1 = \c_one_int
       \__fp_ln_Taylor_break:w
     \fi:
     \exp_after:wN \__fp_fixed_div_int:wwN \c__fp_one_fixed_tl #1;
@@ -18373,7 +18575,7 @@
     \or:
       \exp_after:wN \__fp_ln_exponent_one:ww \int_value:w
     \else:
-      \if_int_compare:w #2 > 0 \exp_stop_f:
+      \if_int_compare:w #2 > \c_zero_int
         \exp_after:wN \__fp_ln_exponent_small:NNww
         \exp_after:wN 0
         \exp_after:wN \__fp_fixed_sub:wwn \int_value:w
@@ -18440,7 +18642,7 @@
       \exp_after:wN \__fp_sanitize:Nw
       \exp_after:wN 0
       \int_value:w #1 \__fp_int_eval:w
-        \if_int_compare:w #4 < 0 \exp_stop_f:
+        \if_int_compare:w #4 < \c_zero_int
           \exp_after:wN \use_i:nn
         \else:
           \exp_after:wN \use_ii:nn
@@ -18480,7 +18682,7 @@
   { \__fp_exp_Taylor_loop:www 10 ; #1 ; #1 ; \s__fp_stop }
 \cs_new:Npn \__fp_exp_Taylor_loop:www #1; #2; #3;
   {
-    \if_int_compare:w #1 = 1 \exp_stop_f:
+    \if_int_compare:w #1 = \c_one_int
       \exp_after:wN \__fp_exp_Taylor_break:Nww
     \fi:
     \__fp_fixed_div_int:wwN #3 ; #1 ;
@@ -18652,7 +18854,7 @@
     \s__fp \__fp_chk:w 1 #1#2#3; \s__fp \__fp_chk:w #4#5
   {
     \if_int_compare:w \__fp_str_if_eq:nn { #2 #3 }
-              { 1 {1000} {0000} {0000} {0000} } = 0 \exp_stop_f:
+              { 1 {1000} {0000} {0000} {0000} } = \c_zero_int
       \if_int_compare:w #4 #1 = 32 \exp_stop_f:
         \exp_after:wN \__fp_case_return_ii_o:ww
       \fi:
@@ -18664,7 +18866,7 @@
       \exp_after:wN #5
     \or:
       \if_meaning:w 2 #5 \exp_after:wN \reverse_if:N \fi:
-      \if_int_compare:w #2 > 0 \exp_stop_f:
+      \if_int_compare:w #2 > \c_zero_int
         \exp_after:wN \__fp_case_return_o:Nww
         \exp_after:wN \c_inf_fp
       \else:
@@ -18682,7 +18884,7 @@
     \exp_after:wN \__fp_sanitize:Nw
     \exp_after:wN 0
     \int_value:w
-      \if:w #1 \if_int_compare:w #3 > 0 \exp_stop_f: 0 \else: 2 \fi:
+      \if:w #1 \if_int_compare:w #3 > \c_zero_int 0 \else: 2 \fi:
         \exp_after:wN \__fp_pow_npos_aux:NNnww
         \exp_after:wN +
         \exp_after:wN \__fp_fixed_to_float_o:wN
@@ -18705,7 +18907,7 @@
   }
 \cs_new:Npn \__fp_pow_exponent:wnN #1; #2
   {
-    \if_int_compare:w #2 > 0 \exp_stop_f:
+    \if_int_compare:w #2 > \c_zero_int
       \exp_after:wN \__fp_pow_exponent:Nwnnnnnw % n\ln(10) - (-\ln(x))
       \exp_after:wN +
     \else:
@@ -18737,7 +18939,7 @@
   }
 \cs_new:Npn \__fp_pow_B:wwN #1#2#3#4#5#6; #7;
   {
-    \if_int_compare:w #7 < 0 \exp_stop_f:
+    \if_int_compare:w #7 < \c_zero_int
       \exp_after:wN \__fp_pow_C_neg:w \int_value:w -
     \else:
       \if_int_compare:w #7 < 22 \exp_stop_f:
@@ -18787,7 +18989,7 @@
     \if_case:w \__fp_pow_neg_case:w #4 ;
       \exp_after:wN \__fp_pow_neg_aux:wNN
     \or:
-      \if_int_compare:w \__fp_int_eval:w #1 / 2 = 1 \exp_stop_f:
+      \if_int_compare:w \__fp_int_eval:w #1 / 2 = \c_one_int
         \__fp_invalid_operation_o:Nww ^ #3; #4;
         \exp:w \exp_end_continue_f:w
         \exp_after:wN \exp_after:wN
@@ -19581,7 +19783,7 @@
         7 - \__fp_int_eval:w
       \fi:
       \if_int_compare:w
-          \__fp_ep_compare:wwww #2,#3; #5,#6; > 0 \exp_stop_f:
+          \__fp_ep_compare:wwww #2,#3; #5,#6; > \c_zero_int
         3 -
         \exp_after:wN \__fp_reverse_args:Nww
       \fi:
@@ -19625,7 +19827,7 @@
   }
 \cs_new:Npn \__fp_atan_Taylor_loop:www #1; #2; #3;
   {
-    \if_int_compare:w #1 = -1 \exp_stop_f:
+    \if_int_compare:w #1 = - \c_one_int
       \__fp_atan_Taylor_break:w
     \fi:
     \exp_after:wN \__fp_fixed_div_int:wwN \c__fp_one_fixed_tl #1;
@@ -19709,7 +19911,7 @@
 \cs_new:Npn \__fp_asin_normal_o:NfwNnnnnw
     #1#2#3 \s__fp \__fp_chk:w 1#4#5#6#7#8#9;
   {
-    \if_int_compare:w #5 < 1 \exp_stop_f:
+    \if_int_compare:w #5 < \c_one_int
       \exp_after:wN \__fp_use_none_until_s:w
     \fi:
     \if_int_compare:w \__fp_int_eval:w #5 + #6#7 + #8#9 = 1000 0001 ~
@@ -19939,7 +20141,7 @@
 \cs_new:Npn \__fp_to_decimal_large:Nnnw #1#2#3#4;
   {
     \exp_after:wN \__fp_trim_zeros:w \int_value:w
-      \if_int_compare:w #2 > 0 \exp_stop_f:
+      \if_int_compare:w #2 > \c_zero_int
         #2
       \fi:
       \exp_stop_f:
@@ -20172,11 +20374,11 @@
             \if_meaning:w 1 #1
               \if_int_compare:w
                   \__fp_use_i_until_s:nw #3 ; > \c__fp_prec_int
-                1 \exp_stop_f:
+                \c_one_int
               \fi:
             \fi:
           }
-          { 1 \exp_stop_f: }
+          { \c_one_int }
       }
     \cs_new:Npn \__fp_randint_o:w #1; #2; @
       {
@@ -20183,8 +20385,8 @@
         \if_case:w
             \__fp_randint_badarg:w #1;
             \__fp_randint_badarg:w #2;
-            \if:w 1 \__fp_compare_back:ww #2; #1; 1 \exp_stop_f: \fi:
-            0 \exp_stop_f:
+            \if:w 1 \__fp_compare_back:ww #2; #1; \c_one_int \fi:
+            \c_zero_int
           \__fp_randint_auxi_o:ww #1; #2;
         \or:
           \__fp_invalid_operation_tl_o:ff
@@ -20368,7 +20570,7 @@
       }
     \cs_new:Npn \__fp_randint:n #1
       {
-        \if_int_compare:w #1 < 1 \exp_stop_f:
+        \if_int_compare:w #1 < \c_one_int
           \__kernel_msg_expandable_error:nnnn
             { kernel } { randint-backward-range } { 1 } {#1}
           \__fp_randint:ww #1; 1;
@@ -21610,7 +21812,7 @@
             \file_if_exist:nTF { l3str-#2- \l__str_internal_tl .def }
               {
                 \group_begin:
-                  \__str_load_catcodes:
+                  \cctab_select:N \c_code_cctab
                   \file_input:n { l3str-#2- \l__str_internal_tl .def }
                 \group_end:
               }
@@ -21653,24 +21855,6 @@
     \fi:
     \__str_convert_lowercase_alphanum_loop:N
   }
-\cs_new_protected:Npn \__str_load_catcodes:
-  {
-    \char_set_catcode_escape:N \\
-    \char_set_catcode_group_begin:N \{
-    \char_set_catcode_group_end:N \}
-    \char_set_catcode_math_toggle:N \$
-    \char_set_catcode_alignment:N \&
-    \char_set_catcode_parameter:N \#
-    \char_set_catcode_math_superscript:N \^
-    \char_set_catcode_ignore:N \ %
-    \char_set_catcode_space:N \~
-    \tl_map_function:nN { abcdefghijklmnopqrstuvwxyz_:ABCDEFILNPSTUX }
-      \char_set_catcode_letter:N
-    \tl_map_function:nN { 0123456789"'?*+-.(),`!/<>[];= }
-      \char_set_catcode_other:N
-    \char_set_catcode_comment:N \%
-    \int_set:Nn \tex_endlinechar:D {32}
-  }
 \bool_lazy_any:nTF
   {
     \sys_if_engine_luatex_p:
@@ -22635,7 +22819,7 @@
         \exp_after:wN \__str_decode_utf_xxxii_end:w
       \fi:
       #1#2#3#4 \s__str
-      \if_int_compare:w \__str_tmp:w #1#4 > 0 \exp_stop_f:
+      \if_int_compare:w \__str_tmp:w #1#4 > \c_zero_int
         \flag_raise:n { str_overflow }
         \flag_raise:n { str_error }
         \int_use:N \c__str_replacement_char_int
@@ -22884,7 +23068,7 @@
          plus \l__tl_analysis_type_int sp \scan_stop:
     \int_incr:N \l__tl_analysis_index_int
     \int_zero:N \l__tl_analysis_normal_int
-    \if_int_compare:w \l__tl_analysis_nesting_int = -1 \exp_stop_f:
+    \if_int_compare:w \l__tl_analysis_nesting_int = - \c_one_int
       \cs_set_eq:NN \__tl_analysis_a_loop:w \scan_stop:
     \fi:
   }
@@ -22907,7 +23091,7 @@
   }
 \cs_new_protected:Npn \__tl_analysis_a_cs:ww #1; #2;
   {
-    \if_int_compare:w #1 > 0 \exp_stop_f:
+    \if_int_compare:w #1 > \c_zero_int
       \tex_skip:D \l__tl_analysis_index_int
         = \int_eval:n { \l__tl_analysis_normal_int + 1 } sp \exp_stop_f:
       \tex_advance:D \l__tl_analysis_index_int #1 \exp_stop_f:
@@ -22931,7 +23115,7 @@
   }
 \cs_new:Npn \__tl_analysis_b_normals:ww #1;
   {
-    \if_int_compare:w #1 = 0 \exp_stop_f:
+    \if_int_compare:w #1 = \c_zero_int
       \__tl_analysis_b_special:w
     \fi:
     \__tl_analysis_b_normal:wwN #1;
@@ -22982,7 +23166,7 @@
   {
     \exp_after:wN \__tl_analysis_b_normals:ww
     \int_value:w \int_eval:w
-    \if_int_compare:w #1 = 0 \exp_stop_f:
+    \if_int_compare:w #1 = \c_zero_int
       #3
     \else:
       \tex_skip:D \int_eval:n { #4 + #1 } \exp_stop_f:
@@ -23053,21 +23237,28 @@
     \prg_break_point:Nn \tl_map_break:
       { \int_gdecr:N \g__kernel_prg_map_int }
   }
-\cs_new_protected:Npn \tl_analysis_show:N #1
+\cs_new_protected:Npn \tl_analysis_show:N
+  { \__tl_analysis_show:NNN \__kernel_msg_show:nnxxxx \tl_show:N }
+\cs_new_protected:Npn \tl_analysis_log:N
+  { \__tl_analysis_show:NNN \__kernel_msg_log:nnxxxx \tl_log:N }
+\cs_new_protected:Npn \__tl_analysis_show:NNN #1#2#3
   {
-    \tl_if_exist:NTF #1
+    \tl_if_exist:NTF #3
       {
-        \exp_args:No \__tl_analysis:n {#1}
-        \__kernel_msg_show:nnxxxx { tl } { show-analysis }
-          { \token_to_str:N #1 } { \__tl_analysis_show: } { } { }
+        \exp_args:No \__tl_analysis:n {#3}
+        #1 { tl } { show-analysis }
+          { \token_to_str:N #3 } { \__tl_analysis_show: } { } { }
       }
-      { \tl_show:N #1 }
+      { #2 #3 }
   }
-\cs_new_protected:Npn \tl_analysis_show:n #1
+\cs_new_protected:Npn \tl_analysis_show:n
+  { \__tl_analysis_show:Nn \__kernel_msg_show:nnxxxx }
+\cs_new_protected:Npn \tl_analysis_log:n
+  { \__tl_analysis_show:Nn \__kernel_msg_log:nnxxxx }
+\cs_new_protected:Npn \__tl_analysis_show:Nn #1#2
   {
-    \__tl_analysis:n {#1}
-    \__kernel_msg_show:nnxxxx { tl } { show-analysis }
-      { } { \__tl_analysis_show: } { } { }
+    \__tl_analysis:n {#2}
+    #1 { tl } { show-analysis } { } { \__tl_analysis_show: } { } { }
   }
 \cs_new:Npn \__tl_analysis_show:
   {
@@ -23079,7 +23270,7 @@
   {
     \use_none:n #2
     \iow_newline: > \use:nn { ~ } { ~ }
-    \if_int_compare:w "#2 = 0 \exp_stop_f:
+    \if_int_compare:w "#2 = \c_zero_int
       \exp_after:wN \__tl_analysis_show_cs:n
     \else:
       \if_int_compare:w "#2 = 13 \exp_stop_f:
@@ -23180,10 +23371,10 @@
 \cs_new_protected:Npn \__tl_peek_analysis_test:
   {
     \if_int_odd:w
-      \if_catcode:w \exp_not:N \l_peek_token {   0 \exp_stop_f: \fi:
-      \if_catcode:w \exp_not:N \l_peek_token }   0 \exp_stop_f: \fi:
-      \if_meaning:w \l_peek_token \c_space_token 0 \exp_stop_f: \fi:
-      1 \exp_stop_f:
+      \if_catcode:w \exp_not:N \l_peek_token {   \c_zero_int \fi:
+      \if_catcode:w \exp_not:N \l_peek_token }   \c_zero_int \fi:
+      \if_meaning:w \l_peek_token \c_space_token \c_zero_int \fi:
+      \c_one_int
       \exp_after:wN \exp_after:wN
       \exp_after:wN \__tl_peek_analysis_normal:N
       \exp_after:wN \exp_not:N
@@ -23651,7 +23842,7 @@
       \tl_put_right:Nx \l__regex_internal_a_tl
         {
           \exp_after:wN \__regex_escape_loop:N \g__regex_internal_tl
-          { break } \prg_break_point:
+          \scan_stop: \prg_break_point:
         }
       \exp_after:wN
     \group_end:
@@ -23673,8 +23864,8 @@
 \cs_new_eq:NN \__regex_escape_unescaped:N ?
 \cs_new_eq:NN \__regex_escape_escaped:N   ?
 \cs_new_eq:NN \__regex_escape_raw:N       ?
-\cs_new_eq:NN \__regex_escape_break:w \prg_break:
-\cs_new:cpn { __regex_escape_/break:w }
+\cs_new_eq:cN { __regex_escape_ \iow_char:N\\scan_stop: :w } \prg_break:
+\cs_new:cpn { __regex_escape_/ \iow_char:N\\scan_stop: :w }
   {
     \__kernel_msg_expandable_error:nn { regex } { trailing-backslash }
     \prg_break:
@@ -23711,7 +23902,10 @@
   }
 \cs_new:Npn \__regex_escape_x_test:N #1
   {
-    \str_if_eq:nnTF {#1} { break } { ; }
+    \if_meaning:w \scan_stop: #1
+      \exp_after:wN \use_i:nnn \exp_after:wN ;
+    \fi:
+    \use:n
       {
         \if_charcode:w \c_space_token #1
           \exp_after:wN \__regex_escape_x_test:N
@@ -23733,7 +23927,10 @@
   }
 \cs_new:Npn \__regex_escape_x:N #1
   {
-    \str_if_eq:nnTF {#1} { break } { ; }
+    \if_meaning:w \scan_stop: #1
+      \exp_after:wN \use_i:nnn \exp_after:wN ;
+    \fi:
+    \use:n
       {
         \__regex_hexadecimal_use:NTF #1
           { ; \__regex_escape_loop:N }
@@ -23742,7 +23939,10 @@
   }
 \cs_new:Npn \__regex_escape_x_loop:N #1
   {
-    \str_if_eq:nnTF {#1} { break }
+    \if_meaning:w \scan_stop: #1
+      \exp_after:wN \use_ii:nnn
+    \fi:
+    \use_ii:nn
       { ; \__regex_escape_x_loop_error:n { } {#1} }
       {
         \__regex_hexadecimal_use:NTF #1
@@ -23975,7 +24175,7 @@
           \prg_do_nothing: \prg_do_nothing:
         }
         { }
-      \if_int_compare:w \l__regex_group_level_int > 0 \exp_stop_f:
+      \if_int_compare:w \l__regex_group_level_int > \c_zero_int
         \__kernel_msg_error:nnx { regex } { missing-rparen }
           { \int_use:N \l__regex_group_level_int }
         \prg_replicate:nn
@@ -24461,7 +24661,7 @@
   }
 \cs_new_protected:Npn \__regex_compile_group_end:
   {
-    \if_int_compare:w \l__regex_group_level_int > 0 \exp_stop_f:
+    \if_int_compare:w \l__regex_group_level_int > \c_zero_int
         \tl_build_put_right:Nn \l__regex_build_tl { \if_false: { \fi: } }
         \tl_build_end:N \l__regex_build_tl
         \exp_args:NNNx
@@ -24857,7 +25057,7 @@
           {
             \__regex_class:NnnnN \c_true_bool
               {
-                \if_int_compare:w "##3 = 0 \exp_stop_f:
+                \if_int_compare:w "##3 = \c_zero_int
                   \__regex_item_exact_cs:n
                     { \exp_after:wN \cs_to_str:N ##1 }
                 \else:
@@ -25276,7 +25476,7 @@
   }
 \cs_new_protected:Npn \__regex_class_repeat:nN #1#2
   {
-    \if_int_compare:w #1 = 0 \exp_stop_f:
+    \if_int_compare:w #1 = \c_zero_int
       \__regex_build_transitions_lazyness:NNNNN #2
         \__regex_action_free:n       \l__regex_right_state_int
         \__regex_tests_action_cost:n \l__regex_left_state_int
@@ -25302,7 +25502,7 @@
   }
 \cs_new_protected:Npn \__regex_group_aux:nnnnN #1#2#3#4#5
   {
-      \if_int_compare:w #3 = 0 \exp_stop_f:
+      \if_int_compare:w #3 = \c_zero_int
         \__regex_build_new_state:
         \__regex_build_transition_right:nNn \__regex_action_free_group:n
           \l__regex_left_state_int \l__regex_right_state_int
@@ -25363,7 +25563,7 @@
   }
 \cs_new_protected:Npn \__regex_group_repeat:nn #1#2
   {
-    \if_int_compare:w #2 = 0 \exp_stop_f:
+    \if_int_compare:w #2 = \c_zero_int
       \int_set:Nn \l__regex_max_state_int
         { \l__regex_left_state_int - 1 }
       \__regex_build_new_state:
@@ -25376,7 +25576,7 @@
   }
 \cs_new_protected:Npn \__regex_group_submatches:nNN #1#2#3
   {
-    \if_int_compare:w #1 > - 1 \exp_stop_f:
+    \if_int_compare:w #1 > - \c_one_int
       \__regex_toks_put_left:Nx #2 { \__regex_action_submatch:nN {#1} < }
       \__regex_toks_put_left:Nx #3 { \__regex_action_submatch:nN {#1} > }
     \fi:
@@ -25387,7 +25587,7 @@
       \l__regex_right_state_int \l__regex_max_state_int
     \int_set_eq:NN \l__regex_internal_a_int \l__regex_left_state_int
     \int_set_eq:NN \l__regex_internal_b_int \l__regex_max_state_int
-    \if_int_compare:w \int_eval:n {#1} > 1 \exp_stop_f:
+    \if_int_compare:w \int_eval:n {#1} > \c_one_int
       \int_set:Nn \l__regex_internal_c_int
         {
           ( #1 - 1 )
@@ -25403,7 +25603,7 @@
   }
 \cs_new_protected:Npn \__regex_group_repeat:nnN #1#2#3
   {
-    \if_int_compare:w #2 = 0 \exp_stop_f:
+    \if_int_compare:w #2 = \c_zero_int
       \__regex_group_submatches:nNN {#1}
         \l__regex_left_state_int \l__regex_right_state_int
       \int_set:Nn \l__regex_internal_a_int
@@ -25454,7 +25654,7 @@
           \__regex_build_transition_right:nNn \__regex_action_free:n
             \l__regex_right_state_int \l__regex_max_state_int
         }
-      \if_int_compare:w #2 = 0 \exp_stop_f:
+      \if_int_compare:w #2 = \c_zero_int
         \int_set:Nn \l__regex_right_state_int
           { \l__regex_left_state_int - 1 }
       \else:
@@ -25882,7 +26082,7 @@
         { \__regex_replacement_normal:n ##1 }
         {#1}
       \prg_do_nothing: \prg_do_nothing:
-      \if_int_compare:w \l__regex_replacement_csnames_int > 0 \exp_stop_f:
+      \if_int_compare:w \l__regex_replacement_csnames_int > \c_zero_int
         \__kernel_msg_error:nnx { regex } { replacement-missing-rbrace }
           { \int_use:N \l__regex_replacement_csnames_int }
         \tl_build_put_right:Nx \l__regex_build_tl
@@ -25993,7 +26193,7 @@
   {
     \tl_build_put_right:Nn \l__regex_build_tl
       { \__regex_query_submatch:n { \int_eval:n { #1 + ##1 } } }
-    \if_int_compare:w \l__regex_replacement_csnames_int = 0 \exp_stop_f:
+    \if_int_compare:w \l__regex_replacement_csnames_int = \c_zero_int
       \tl_put_right:Nn \l__regex_balance_tl
         {
           + \__regex_submatch_balance:n
@@ -26067,7 +26267,7 @@
   }
 \cs_new_protected:Npn \__regex_replacement_rbrace:N #1
   {
-    \if_int_compare:w \l__regex_replacement_csnames_int > 0 \exp_stop_f:
+    \if_int_compare:w \l__regex_replacement_csnames_int > \c_zero_int
       \tl_build_put_right:Nn \l__regex_build_tl { \cs_end: }
       \int_decr:N \l__regex_replacement_csnames_int
     \else:
@@ -26076,7 +26276,7 @@
   }
 \cs_new_protected:Npn \__regex_replacement_lbrace:N #1
   {
-    \if_int_compare:w \l__regex_replacement_csnames_int > 0 \exp_stop_f:
+    \if_int_compare:w \l__regex_replacement_csnames_int > \c_zero_int
       \__kernel_msg_error:nnn { regex } { cu-lbrace } { u }
     \else:
       \__regex_replacement_normal:n {#1}
@@ -26128,7 +26328,7 @@
   \char_set_catcode_group_begin:N \^^@
   \cs_new_protected:Npn \__regex_replacement_c_B:w
     {
-      \if_int_compare:w \l__regex_replacement_csnames_int = 0 \exp_stop_f:
+      \if_int_compare:w \l__regex_replacement_csnames_int = \c_zero_int
         \int_incr:N \l__regex_balance_int
       \fi:
       \__regex_replacement_char:nNN
@@ -26145,7 +26345,7 @@
   \char_set_catcode_group_end:N \^^@
   \cs_new_protected:Npn \__regex_replacement_c_E:w
     {
-      \if_int_compare:w \l__regex_replacement_csnames_int = 0 \exp_stop_f:
+      \if_int_compare:w \l__regex_replacement_csnames_int = \c_zero_int
         \int_decr:N \l__regex_balance_int
       \fi:
       \__regex_replacement_char:nNN
@@ -26168,7 +26368,7 @@
     }
   \cs_new_protected:Npn \__regex_replacement_c_S:w #1#2
     {
-      \if_int_compare:w `#2 = 0 \exp_stop_f:
+      \if_int_compare:w `#2 = \c_zero_int
         \__kernel_msg_error:nn { regex } { replacement-null-space }
       \fi:
       \tex_lccode:D `\ = `#2 \scan_stop:
@@ -26272,6 +26472,8 @@
 \intarray_new:Nn \g__regex_submatch_begin_intarray { 65536 }
 \intarray_new:Nn \g__regex_submatch_end_intarray { 65536 }
 \intarray_new:Nn \g__regex_balance_intarray { 65536 }
+\int_new:N \l__regex_added_begin_int
+\int_new:N \l__regex_added_end_int
 \cs_new_protected:Npn \__regex_return:
   {
     \if_meaning:w \c_true_bool \g__regex_success_bool
@@ -26385,46 +26587,106 @@
   {
       \flag_clear:n { __regex_begin }
       \flag_clear:n { __regex_end }
-      \seq_set_from_function:NnN \l__regex_internal_seq
+      \cs_set_eq:NN \__regex_tmp:w \scan_stop:
+      \__kernel_tl_gset:Nx \g__regex_internal_tl
         {
           \int_step_function:nnN { \l__regex_min_submatch_int }
-            { \l__regex_submatch_int - 1 }
+            { \l__regex_submatch_int - 1 } \__regex_extract_seq_aux:n
+          \__regex_tmp:w
         }
-        \__regex_extract_seq_aux:n
-      \int_compare:nNnF
+      \int_set:Nn \l__regex_added_begin_int
+        { \flag_height:n { __regex_begin } }
+      \int_set:Nn \l__regex_added_end_int
+        { \flag_height:n { __regex_end } }
+      \tex_afterassignment:D \__regex_extract_check:w
+      \__kernel_tl_gset:Nx \g__regex_internal_tl
+        { \g__regex_internal_tl \if_false: { \fi: } }
+      \int_compare:nNnT
+        { \l__regex_added_begin_int + \l__regex_added_end_int } > 0
         {
-          \flag_height:n { __regex_begin } +
-          \flag_height:n { __regex_end }
-        }
-          = 0
-        {
           \__kernel_msg_error:nnxxx { regex } { result-unbalanced }
             { splitting~or~extracting~submatches }
-            { \flag_height:n { __regex_end } }
-            { \flag_height:n { __regex_begin } }
+            { \int_use:N \l__regex_added_begin_int }
+            { \int_use:N \l__regex_added_end_int }
         }
-      \seq_set_map_x:NNn \l__regex_internal_seq \l__regex_internal_seq {##1}
-      \exp_args:NNNo
-      \group_end:
-      \tl_set:Nn #1 { \l__regex_internal_seq }
+    \group_end:
+    \cs_set_eq:NN \__regex_tmp:w \__regex_extract_map_loop:w
+    \seq_set_from_function:NnN #1
+      { \__regex_extract_map:N } \exp_not:n
   }
 \cs_new:Npn \__regex_extract_seq_aux:n #1
   {
+    \__regex_tmp:w { }
     \exp_after:wN \__regex_extract_seq_aux:ww
     \int_value:w \__regex_submatch_balance:n {#1} ; #1;
   }
 \cs_new:Npn \__regex_extract_seq_aux:ww #1; #2;
   {
-    \if_int_compare:w #1 < 0 \exp_stop_f:
-      \flag_raise:n { __regex_end }
-      \prg_replicate:nn {-#1} { \exp_not:n { { \if_false: } \fi: } }
+    \if_int_compare:w #1 < \c_zero_int
+      \prg_replicate:nn {-#1}
+        {
+          \flag_raise:n { __regex_begin }
+          \exp_not:n { { \if_false: } \fi: }
+        }
     \fi:
     \__regex_query_submatch:n {#2}
-    \if_int_compare:w #1 > 0 \exp_stop_f:
-      \flag_raise:n { __regex_begin }
-      \prg_replicate:nn {#1} { \exp_not:n { \if_false: { \fi: } } }
+    \if_int_compare:w #1 > \c_zero_int
+      \prg_replicate:nn {#1}
+        {
+          \flag_raise:n { __regex_end }
+          \exp_not:n { \if_false: { \fi: } }
+        }
     \fi:
   }
+\cs_new_protected:Npn \__regex_extract_check:w
+  {
+    \exp_after:wN \__regex_extract_check:n
+    \exp_after:wN { \if_false: } \fi:
+  }
+\cs_new_protected:Npn \__regex_extract_check:n #1
+  {
+    \tl_if_empty:nF {#1}
+      {
+        \int_incr:N \l__regex_added_begin_int
+        \int_incr:N \l__regex_added_end_int
+        \tex_afterassignment:D \__regex_extract_check:w
+        \__kernel_tl_gset:Nx \g__regex_internal_tl
+          {
+            \exp_after:wN \__regex_extract_check_loop:w
+            \g__regex_internal_tl
+            \__regex_tmp:w \__regex_extract_check_end:w
+            #1
+          }
+      }
+  }
+\cs_new:Npn \__regex_extract_check_loop:w #1 \__regex_tmp:w #2
+  {
+    #2
+    \exp_not:o {#1}
+    \__regex_tmp:w { }
+    \__regex_extract_check_loop:w \prg_do_nothing:
+  }
+\cs_new:Npn \__regex_extract_check_end:w
+    \exp_not:o #1#2 \__regex_extract_check_loop:w #3 \__regex_tmp:w
+  {
+    { \exp_not:o {#1} }
+    #3
+    \if_false: { \fi: }
+    \__regex_tmp:w
+  }
+\cs_new:Npn \__regex_extract_map:N #1
+  {
+    \exp_after:wN \__regex_extract_map_aux:NNn
+    \exp_after:wN #1
+    \g__regex_internal_tl \use_none:nnn
+  }
+\cs_new:Npn \__regex_extract_map_aux:NNn #1#2#3
+  { #3 #2 #1 \prg_do_nothing: }
+\cs_new:Npn \__regex_extract_map_loop:w #1#2 \__regex_tmp:w #3
+  {
+    \exp_after:wN #1 \exp_after:wN {#2}
+    #3 \__regex_extract_map_loop:w #1 \prg_do_nothing:
+  }
 \cs_new_protected:Npn \__regex_extract:
   {
     \if_meaning:w \c_true_bool \g__regex_success_bool
@@ -26438,19 +26700,24 @@
       \__kernel_intarray_gset:Nnn \g__regex_submatch_prev_intarray
         { \l__regex_zeroth_submatch_int } { \l__regex_start_pos_int }
       \int_zero:N \l__regex_internal_a_int
-      \clist_map_inline:Nn \l__regex_success_submatches_tl
-        {
-          \if_int_compare:w \l__regex_internal_a_int < \l__regex_capturing_group_int
-            \__kernel_intarray_gset:Nnn \g__regex_submatch_begin_intarray
-              { \__regex_int_eval:w \l__regex_zeroth_submatch_int + \l__regex_internal_a_int } {##1}
-          \else:
-            \__kernel_intarray_gset:Nnn \g__regex_submatch_end_intarray
-              { \__regex_int_eval:w \l__regex_zeroth_submatch_int + \l__regex_internal_a_int - \l__regex_capturing_group_int } {##1}
-          \fi:
-          \int_incr:N \l__regex_internal_a_int
-        }
+      \exp_after:wN \__regex_extract_aux:w \l__regex_success_submatches_tl
+        \prg_break_point: \__regex_use_none_delimit_by_q_recursion_stop:w ,
+        \q__regex_recursion_stop
     \fi:
   }
+\cs_new_protected:Npn \__regex_extract_aux:w #1 ,
+  {
+    \prg_break: #1 \prg_break_point:
+    \if_int_compare:w \l__regex_internal_a_int < \l__regex_capturing_group_int
+      \__kernel_intarray_gset:Nnn \g__regex_submatch_begin_intarray
+        { \__regex_int_eval:w \l__regex_zeroth_submatch_int + \l__regex_internal_a_int } {#1}
+    \else:
+      \__kernel_intarray_gset:Nnn \g__regex_submatch_end_intarray
+        { \__regex_int_eval:w \l__regex_zeroth_submatch_int + \l__regex_internal_a_int - \l__regex_capturing_group_int } {#1}
+    \fi:
+    \int_incr:N \l__regex_internal_a_int
+    \__regex_extract_aux:w
+  }
 \cs_new_protected:Npn \__regex_replace_once:nnN #1#2#3
   {
     \group_begin:
@@ -26513,30 +26780,45 @@
   }
 \cs_new_protected:Npn \__regex_group_end_replace:N #1
   {
-    \if_int_compare:w \l__regex_balance_int = 0 \exp_stop_f:
-    \else:
-      \__kernel_msg_error:nnxxx { regex } { result-unbalanced }
-        { replacing }
-        { \int_max:nn { - \l__regex_balance_int } { 0 } }
-        { \int_max:nn { \l__regex_balance_int } { 0 } }
-    \fi:
-    \use:x
+    \int_set:Nn \l__regex_added_begin_int
+      { \int_max:nn { - \l__regex_balance_int } { 0 } }
+    \int_set:Nn \l__regex_added_end_int
+      { \int_max:nn { \l__regex_balance_int } { 0 } }
+    \__regex_group_end_replace_try:
+    \int_compare:nNnT { \l__regex_added_begin_int + \l__regex_added_end_int } > 0
       {
-        \group_end:
-        \tl_set:Nn \exp_not:N #1
-          {
-            \if_int_compare:w \l__regex_balance_int < 0 \exp_stop_f:
-              \prg_replicate:nn { - \l__regex_balance_int }
-                { { \if_false: } \fi: }
-            \fi:
-            \l__regex_internal_a_tl
-            \if_int_compare:w \l__regex_balance_int > 0 \exp_stop_f:
-              \prg_replicate:nn { \l__regex_balance_int }
-                { \if_false: { \fi: } }
-            \fi:
-          }
+        \__kernel_msg_error:nnxxx { regex } { result-unbalanced }
+          { replacing } { \int_use:N \l__regex_added_begin_int }
+          { \int_use:N \l__regex_added_end_int }
       }
+    \group_end:
+    \tl_set_eq:NN #1 \g__regex_internal_tl
   }
+\cs_new_protected:Npn \__regex_group_end_replace_try:
+  {
+    \tex_afterassignment:D \__regex_group_end_replace_check:w
+    \__kernel_tl_gset:Nx \g__regex_internal_tl
+      {
+        \prg_replicate:nn { \l__regex_added_begin_int } { { \if_false: } \fi: }
+        \l__regex_internal_a_tl
+        \prg_replicate:nn { \l__regex_added_end_int } { \if_false: { \fi: } }
+        \if_false: { \fi: }
+      }
+  }
+\cs_new_protected:Npn \__regex_group_end_replace_check:w
+  {
+    \exp_after:wN \__regex_group_end_replace_check:n
+    \exp_after:wN { \if_false: } \fi:
+  }
+\cs_new_protected:Npn \__regex_group_end_replace_check:n #1
+  {
+    \tl_if_empty:nF {#1}
+      {
+        \int_incr:N \l__regex_added_begin_int
+        \int_incr:N \l__regex_added_end_int
+        \__regex_group_end_replace_try:
+      }
+  }
 \tl_new:N \l__regex_peek_true_tl
 \tl_new:N \l__regex_peek_false_tl
 \tl_new:N \l__regex_replacement_tl
@@ -29025,16 +29307,20 @@
           #4 \s__color_mark #5 \s__color_stop
       }
   }
-\cs_new_protected:Npn \color_show:n #1
+\cs_new_protected:Npn \color_show:n
+  { \__color_show:Nn \__kernel_msg_show:nnxxxx }
+\cs_new_protected:Npn \color_log:n
+  { \__color_show:Nn \__kernel_msg_log:nnxxxx }
+\cs_new_protected:Npn \__color_show:Nn #1#2
   {
-    \__kernel_msg_show:nnxxxx { color } { show }
-      {#1}
+    #1 { color } { show }
+      {#2}
       {
-        \__color_if_defined:nT {#1}
+        \__color_if_defined:nT {#2}
           {
-            \exp_args:Nv \__color_show:n { l__color_named_ #1 _tl }
+            \exp_args:Nv \__color_show:n { l__color_named_ #2 _tl }
             \prop_map_function:cN
-              { l__color_named_ #1 _prop }
+              { l__color_named_ #2 _prop }
               \msg_show_item_unbraced:nn
           }
       }
@@ -30485,6 +30771,26 @@
           { }
       }
   }
+\cs_new_protected:Npn \coffin_show:N #1
+  { \coffin_show:Nnn #1 \c_max_int \c_max_int }
+\cs_generate_variant:Nn \coffin_show:N { c }
+\cs_new_protected:Npn \coffin_log:N #1
+  { \coffin_log:Nnn #1 \c_max_int \c_max_int }
+\cs_generate_variant:Nn \coffin_log:N { c }
+\cs_new_protected:Npn \coffin_show:Nnn
+  { \__coffin_show:NNNnn \__kernel_msg_term:nnxxxx \box_show:Nnn }
+\cs_generate_variant:Nn \coffin_show:Nnn { c }
+\cs_new_protected:Npn \coffin_log:Nnn
+  { \__coffin_show:NNNnn \__kernel_msg_log:nnxxxx \box_show:Nnn }
+\cs_generate_variant:Nn \coffin_log:Nnn { c }
+\cs_new_protected:Npn \__coffin_show:NNNnn #1#2#3#4#5
+  {
+    \__coffin_if_exist:NT #3
+      {
+        \__coffin_show_structure:NN #1 #3
+        #2 #3 {#4} {#5}
+      }
+  }
 \__kernel_msg_new:nnnn { coffin } { no-pole-intersection }
   { No~intersection~between~coffin~poles. }
   {
@@ -31127,7 +31433,7 @@
   }
 \cs_new:Npn \__text_expand_testopt:N #1
   {
-    \str_if_eq:nnTF {#1} { \@protected at testopt }
+    \token_if_eq_meaning:NNTF #1 \@protected at testopt
       { \__text_expand_testopt:NNn }
       { \__text_expand_encoding:N #1 }
   }
@@ -33922,7 +34228,7 @@
   { \__tl_range_collect_unbraced:w #1 ; { } #2 }
 \cs_new:Npn \__tl_range_collect_braced:w #1 ; #2#3
   {
-    \if_int_compare:w #1 > 1 \exp_stop_f:
+    \if_int_compare:w #1 > \c_one_int
       \exp_after:wN \__tl_range_collect_braced:w
       \int_value:w \int_eval:n { #1 - 1 } \exp_after:wN ;
     \fi:
@@ -33930,7 +34236,7 @@
   }
 \cs_new:Npn \__tl_range_collect_unbraced:w #1 ; #2#3
   {
-    \if_int_compare:w #1 > 1 \exp_stop_f:
+    \if_int_compare:w #1 > \c_one_int
       \exp_after:wN \__tl_range_collect_unbraced:w
       \int_value:w \int_eval:n { #1 - 1 } \exp_after:wN ;
     \fi:
@@ -33997,6 +34303,24 @@
       \prg_return_false:
     \fi:
   }
+\cs_new_protected:Npn \legacy_if_set_true:n #1
+  { \cs_set_eq:cN { if#1 } \if_true: }
+\cs_new_protected:Npn \legacy_if_set_false:n #1
+  { \cs_set_eq:cN { if#1 } \if_false: }
+\cs_new_protected:Npn \legacy_if_gset_true:n #1
+  { \cs_gset_eq:cN { if#1 } \if_true: }
+\cs_new_protected:Npn \legacy_if_gset_false:n #1
+  { \cs_gset_eq:cN { if#1 } \if_false: }
+\cs_new_protected:Npn \legacy_if_set:nn #1#2
+  {
+    \bool_if:nTF {#2} \legacy_if_set_true:n \legacy_if_set_false:n
+    {#1}
+  }
+\cs_new_protected:Npn \legacy_if_gset:nn #1#2
+  {
+    \bool_if:nTF {#2} \legacy_if_gset_true:n \legacy_if_gset_false:n
+    {#1}
+  }
 %% File: l3deprecation.dtx
 \bool_new:N \l__deprecation_grace_period_bool
 \scan_new:N \s__deprecation_mark

Modified: trunk/Master/texmf-dist/tex/latex/l3kernel/expl3-generic.tex
===================================================================
--- trunk/Master/texmf-dist/tex/latex/l3kernel/expl3-generic.tex	2021-05-25 20:47:33 UTC (rev 59344)
+++ trunk/Master/texmf-dist/tex/latex/l3kernel/expl3-generic.tex	2021-05-25 20:48:22 UTC (rev 59345)
@@ -19,7 +19,7 @@
 %% and all files in that bundle must be distributed together.
 %% 
 %% File: expl3.dtx
-\def\ExplFileDate{2021-05-11}%
+\def\ExplFileDate{2021-05-25}%
 \let\ExplLoaderFileDate\ExplFileDate
 \begingroup
   \catcode`\_=11

Modified: trunk/Master/texmf-dist/tex/latex/l3kernel/expl3.ltx
===================================================================
--- trunk/Master/texmf-dist/tex/latex/l3kernel/expl3.ltx	2021-05-25 20:47:33 UTC (rev 59344)
+++ trunk/Master/texmf-dist/tex/latex/l3kernel/expl3.ltx	2021-05-25 20:48:22 UTC (rev 59345)
@@ -19,7 +19,7 @@
 %% and all files in that bundle must be distributed together.
 %% 
 %% File: expl3.dtx
-\def\ExplFileDate{2021-05-11}%
+\def\ExplFileDate{2021-05-25}%
 \let\ExplLoaderFileDate\ExplFileDate
 \begingroup
   \catcode`\_=11

Modified: trunk/Master/texmf-dist/tex/latex/l3kernel/expl3.lua
===================================================================
--- trunk/Master/texmf-dist/tex/latex/l3kernel/expl3.lua	2021-05-25 20:47:33 UTC (rev 59344)
+++ trunk/Master/texmf-dist/tex/latex/l3kernel/expl3.lua	2021-05-25 20:48:22 UTC (rev 59345)
@@ -331,6 +331,13 @@
     node_write(n)
   end, "global", "protected")
 end
+  local gettimeofday = os.gettimeofday
+  local epoch = gettimeofday() - os.clock()
+  local write = tex.write
+  local tointeger = math.tointeger
+  luacmd('__sys_elapsedtime:', function()
+    write(tointeger((gettimeofday() - epoch)*65536 // 1))
+  end, 'global')
 -- File: l3token.dtx
 do
   local get_next = token.get_next

Modified: trunk/Master/texmf-dist/tex/latex/l3kernel/expl3.sty
===================================================================
--- trunk/Master/texmf-dist/tex/latex/l3kernel/expl3.sty	2021-05-25 20:47:33 UTC (rev 59344)
+++ trunk/Master/texmf-dist/tex/latex/l3kernel/expl3.sty	2021-05-25 20:48:22 UTC (rev 59345)
@@ -19,7 +19,7 @@
 %% and all files in that bundle must be distributed together.
 %% 
 %% File: expl3.dtx
-\def\ExplFileDate{2021-05-11}%
+\def\ExplFileDate{2021-05-25}%
 \let\ExplLoaderFileDate\ExplFileDate
 \ProvidesPackage{expl3}
   [%

Modified: trunk/Master/texmf-dist/tex/latex/l3kernel/l3debug.def
===================================================================
--- trunk/Master/texmf-dist/tex/latex/l3kernel/l3debug.def	2021-05-25 20:47:33 UTC (rev 59344)
+++ trunk/Master/texmf-dist/tex/latex/l3kernel/l3debug.def	2021-05-25 20:48:22 UTC (rev 59345)
@@ -436,6 +436,7 @@
       \box_set_eq:NN
       \box_set_eq_drop:NN
       \box_set_to_last:N
+      \clist_clear:N
       \clist_set_eq:NN
       \dim_zero:N
       \dim_set:Nn
@@ -466,6 +467,7 @@
       \skip_add:Nn
       \skip_sub:Nn
       \__kernel_tl_set:Nx
+      \tl_clear:N
       \tl_set_eq:NN
       \tl_put_left:Nn
       \tl_put_left:NV
@@ -498,6 +500,7 @@
       \box_gset_eq_drop:NN
       \box_gset_to_last:N
       \cctab_gset:Nn
+      \clist_gclear:N
       \clist_gset_eq:NN
       \dim_gset_eq:NN
       \dim_gzero:N
@@ -528,6 +531,7 @@
       \skip_gadd:Nn
       \skip_gsub:Nn
       \__kernel_tl_gset:Nx
+      \tl_gclear:N
       \tl_gset_eq:NN
       \tl_gput_left:Nn
       \tl_gput_left:NV



More information about the tex-live-commits mailing list.