[latex3-commits] [latex3/latex3] tl-build: Move core l3tl-build functions to stable (2d0c6b041)

github at latex-project.org github at latex-project.org
Thu Oct 19 11:32:46 CEST 2023


Repository : https://github.com/latex3/latex3
On branch  : tl-build
Link       : https://github.com/latex3/latex3/commit/2d0c6b041033fb880a2925bb0f9a48e73b00c5b9

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

commit 2d0c6b041033fb880a2925bb0f9a48e73b00c5b9
Author: Joseph Wright <joseph.wright at morningstar2.co.uk>
Date:   Wed Oct 18 20:44:17 2023 +0100

    Move core l3tl-build functions to stable
    
    I've gone with a new .dtx:
    if we were starting now, we'd likely do this a lot more!


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

2d0c6b041033fb880a2925bb0f9a48e73b00c5b9
 l3kernel/CHANGELOG.md        |   2 +
 l3kernel/doc/source3body.tex |   1 +
 l3kernel/l3.ins              |   1 +
 l3kernel/l3candidates.dtx    | 234 ------------------------------
 l3kernel/l3tl-build.dtx      | 329 +++++++++++++++++++++++++++++++++++++++++++
 5 files changed, 333 insertions(+), 234 deletions(-)

diff --git a/l3kernel/CHANGELOG.md b/l3kernel/CHANGELOG.md
index 5077c8187..800fef972 100644
--- a/l3kernel/CHANGELOG.md
+++ b/l3kernel/CHANGELOG.md
@@ -14,6 +14,8 @@ this project uses date-based 'snapshot' version identifiers.
 ### Changed
 - Refine action of `\text_titlecase_first:n(n)` to be focussed strictly on
   first (relevant) codepoint in the input
+- Move `\tl_build_(g)begin:N`, `\tl_build_(g)end:N`, `\tl_build_(g)put_left:Nn`
+  and `\tl_build_(g)right:Nn` to stable status
 
 ### Deprecated
 - `\text_titlecase:n(n)` as ambiguous: replaced by `\text_titlecase_all:n(n)`
diff --git a/l3kernel/doc/source3body.tex b/l3kernel/doc/source3body.tex
index b1a536b8a..87bffc0e4 100644
--- a/l3kernel/doc/source3body.tex
+++ b/l3kernel/doc/source3body.tex
@@ -551,6 +551,7 @@ used on top of \LaTeXe{} if \tn{outer} tokens are used in the arguments.
 \part{Data types}
 
 \DocInput{l3tl.dtx}
+\DocInput{l3tl-build.dtx}
 \DocInput{l3str.dtx}
 \DocInput{l3str-convert.dtx}
 \DocInput{l3quark.dtx}
diff --git a/l3kernel/l3.ins b/l3kernel/l3.ins
index 52c65e4c8..d9e61c801 100644
--- a/l3kernel/l3.ins
+++ b/l3kernel/l3.ins
@@ -65,6 +65,7 @@ and all files in that bundle must be distributed together.
         \from{l3expan.dtx}      {package}
         \from{l3quark.dtx}      {package}
         \from{l3tl.dtx}         {package}
+        \from{l3tl-build.dtx}   {package}
         \from{l3str.dtx}        {package}
         \from{l3seq.dtx}        {package}
         \from{l3int.dtx}        {package}
diff --git a/l3kernel/l3candidates.dtx b/l3kernel/l3candidates.dtx
index 6e455b099..9d6b9df65 100644
--- a/l3kernel/l3candidates.dtx
+++ b/l3kernel/l3candidates.dtx
@@ -103,20 +103,6 @@
 %
 % \section{Additions to \pkg{l3tl}}
 %
-% \begin{function}[added = 2018-04-01]{\tl_build_begin:N, \tl_build_gbegin:N}
-%   \begin{syntax}
-%     \cs{tl_build_begin:N} \meta{tl~var}
-%   \end{syntax}
-%   Clears the \meta{tl~var} and sets it up to support other
-%   \cs[no-index]{tl_build_\ldots{}} functions, which allow accumulating
-%   large numbers of tokens piece by piece much more efficiently than
-%   standard \pkg{l3tl} functions.  Until \cs{tl_build_end:N}
-%   \meta{tl~var} is called, applying any function from \pkg{l3tl} other
-%   than \cs[no-index]{tl_build_\ldots{}} will lead to incorrect
-%   results.  The |begin| and |gbegin| functions must be used for local
-%   and global \meta{tl~var} respectively.
-% \end{function}
-%
 % \begin{function}[added = 2018-04-01]{\tl_build_clear:N, \tl_build_gclear:N}
 %   \begin{syntax}
 %     \cs{tl_build_clear:N} \meta{tl~var}
@@ -127,25 +113,6 @@
 %   respectively.
 % \end{function}
 %
-% \begin{function}[added = 2018-04-01]
-%   {
-%     \tl_build_put_left:Nn, \tl_build_put_left:Ne,
-%     \tl_build_gput_left:Nn, \tl_build_gput_left:Ne,
-%     \tl_build_put_right:Nn, \tl_build_put_right:Ne,
-%     \tl_build_gput_right:Nn, \tl_build_gput_right:Ne
-%   }
-%   \begin{syntax}
-%     \cs{tl_build_put_left:Nn} \meta{tl~var} \Arg{tokens}
-%     \cs{tl_build_put_right:Nn} \meta{tl~var} \Arg{tokens}
-%   \end{syntax}
-%   Adds \meta{tokens} to the left or right side of the current contents
-%   of \meta{tl~var}.  The \meta{tl~var} must have been set up with
-%   \cs{tl_build_begin:N} or \cs{tl_build_gbegin:N}.  The |put| and
-%   |gput| functions must be used for local and global \meta{tl~var}
-%   respectively.  The |right| functions are about twice faster than the
-%   |left| functions.
-% \end{function}
-%
 % \begin{function}[added = 2018-04-01]{\tl_build_get:NN}
 %   \begin{syntax}
 %     \cs{tl_build_get:NN} \meta{tl~var_1} \meta{tl~var_2}
@@ -157,20 +124,6 @@
 %   \cs{tl_set:Nn}.
 % \end{function}
 %
-% \begin{function}[added = 2018-04-01]{\tl_build_end:N, \tl_build_gend:N}
-%   \begin{syntax}
-%     \cs{tl_build_end:N} \meta{tl~var}
-%   \end{syntax}
-%   Gets the contents of \meta{tl~var} and stores that into the
-%   \meta{tl~var} using \cs{tl_set:Nn} or \cs{tl_gset:Nn}.
-%   The \meta{tl~var} must have
-%   been set up with \cs{tl_build_begin:N} or \cs{tl_build_gbegin:N}.
-%   The |end| and |gend| functions must be used for local and global
-%   \meta{tl~var} respectively.  These functions completely remove the
-%   setup code that enabled \meta{tl~var} to be used for other
-%   \cs[no-index]{tl_build_\ldots{}} functions.
-% \end{function}
-%
 % \end{documentation}
 %
 % \begin{implementation}
@@ -219,55 +172,6 @@
 %<@@=tl>
 %    \end{macrocode}
 %
-% Between \cs{tl_build_begin:N} \meta{tl~var} and \cs{tl_build_end:N}
-% \meta{tl~var}, the \meta{tl~var} has the structure
-% \begin{quote}
-%   \cs{exp_end:} \ldots{} \cs{exp_end:} \cs{@@_build_last:NNn}
-%   \meta{assignment} \meta{next~tl} \Arg{left} \meta{right}
-% \end{quote}
-% where \meta{right} is not braced.  The \enquote{data} it represents is
-% \meta{left} followed by the \enquote{data} of \meta{next~tl} followed
-% by \meta{right}.  The \meta{next~tl} is a token list variable whose
-% name is that of \meta{tl~var} followed by~|'|.  There are between $0$
-% and $4$ \cs{exp_end:} to keep track of when \meta{left} and
-% \meta{right} should be put into the \meta{next~tl}.  The
-% \meta{assignment} is \cs{cs_set_nopar:Npe} if the variable is local,
-% and \cs{cs_gset_nopar:Npe} if it is global.
-%
-% \begin{macro}{\tl_build_begin:N, \tl_build_gbegin:N}
-% \begin{macro}{\@@_build_begin:NN, \@@_build_begin:NNN}
-%   First construct the \meta{next~tl}: using a prime here conflicts
-%   with the usual \pkg{expl3} convention but we need a name that can be
-%   derived from |#1| without any external data such as a counter.
-%   Empty that \meta{next~tl} and setup the structure.  The local and
-%   global versions only differ by a single function
-%   \cs[no-index]{cs_(g)set_nopar:Npe} used for all assignments: this is
-%   important because only that function is stored in the \meta{tl~var}
-%   and \meta{next~tl} for subsequent assignments.  In principle
-%   \cs{@@_build_begin:NNN} could use \cs[no-index]{tl_(g)clear_new:N}
-%   to empty |#1| and make sure it is defined, but logging the
-%   definition does not seem useful so we just do |#3| |#1| |{}| to
-%   clear it locally or globally as appropriate.
-%    \begin{macrocode}
-\cs_new_protected:Npn \tl_build_begin:N #1
-  { \@@_build_begin:NN \cs_set_nopar:Npe #1 }
-\cs_new_protected:Npn \tl_build_gbegin:N #1
-  { \@@_build_begin:NN \cs_gset_nopar:Npe #1 }
-\cs_new_protected:Npn \@@_build_begin:NN #1#2
-  { \exp_args:Nc \@@_build_begin:NNN { \cs_to_str:N #2 ' } #2 #1 }
-\cs_new_protected:Npn \@@_build_begin:NNN #1#2#3
-  {
-    #3 #1 { }
-    #3 #2
-      {
-        \exp_not:n { \exp_end: \exp_end: \exp_end: \exp_end: }
-        \exp_not:n { \@@_build_last:NNn #3 #1 { } }
-      }
-  }
-%    \end{macrocode}
-% \end{macro}
-% \end{macro}
-%
 % \begin{macro}{\tl_build_clear:N, \tl_build_gclear:N}
 %   The |begin| and |gbegin| functions already clear enough to make the
 %   token list variable effectively empty.  Eventually the |begin| and
@@ -281,148 +185,10 @@
 %    \end{macrocode}
 % \end{macro}
 %
-% \begin{macro}
-%   {
-%     \tl_build_put_right:Nn, \tl_build_put_right:Ne, \tl_build_put_right:Nx,
-%     \tl_build_gput_right:Nn, \tl_build_gput_right:Ne, \tl_build_gput_right:Nx,
-%     \@@_build_last:NNn, \@@_build_put:nn, \@@_build_put:nw
-%   }
-%   Similar to \cs{tl_put_right:Nn}, but apply \cs{exp:w} to |#1|.  Most
-%   of the time this just removes one \cs{exp_end:}.  When there are
-%   none left, \cs{@@_build_last:NNn} is expanded instead.  It resets
-%   the definition of the \meta{tl~var} by ending the \cs{exp_not:n} and
-%   the definition early.  Then it makes sure the \meta{next~tl} (its
-%   argument |#1|) is set-up and starts a new definition.  Then
-%   \cs{@@_build_put:nn} and \cs{@@_build_put:nw} place the \meta{left}
-%   part of the original \meta{tl~var} as appropriate for the definition
-%   of the \meta{next~tl} (the \meta{right} part is left in the right
-%   place without ever becoming a macro argument).  We use
-%   \cs{exp_after:wN} rather than some \cs{exp_args:No} to avoid reading
-%   arguments that are likely very long token lists.  We use
-%   \cs[no-index]{cs_(g)set_nopar:Npe} rather than
-%   \cs[no-index]{tl_(g)set:Ne} partly for the same reason and partly
-%   because the assignments are interrupted by brace tricks, which
-%   implies that the assignment does not simply set the token list to an
-%   |x|-expansion of the second argument.
-%    \begin{macrocode}
-\cs_new_protected:Npn \tl_build_put_right:Nn #1#2
-  {
-    \cs_set_nopar:Npe #1
-      { \exp_after:wN \exp_not:n \exp_after:wN { \exp:w #1 #2 } }
-  }
-\cs_generate_variant:Nn \tl_build_put_right:Nn { Ne , Nx }
-\cs_new_protected:Npn \tl_build_gput_right:Nn #1#2
-  {
-    \cs_gset_nopar:Npe #1
-      { \exp_after:wN \exp_not:n \exp_after:wN { \exp:w #1 #2 } }
-  }
-\cs_generate_variant:Nn \tl_build_gput_right:Nn { Ne , Nx }
-\cs_new_protected:Npn \@@_build_last:NNn #1#2
-  {
-    \if_false: { { \fi:
-          \exp_end: \exp_end: \exp_end: \exp_end: \exp_end:
-          \@@_build_last:NNn #1 #2 { }
-        }
-      }
-    \if_meaning:w \c_empty_tl #2
-      \@@_build_begin:NN #1 #2
-    \fi:
-    #1 #2
-      {
-        \exp_after:wN \exp_not:n \exp_after:wN
-          {
-            \exp:w \if_false: } } \fi:
-            \exp_after:wN \@@_build_put:nn \exp_after:wN {#2}
-  }
-\cs_new_protected:Npn \@@_build_put:nn #1#2 { \@@_build_put:nw {#2} #1 }
-\cs_new_protected:Npn \@@_build_put:nw #1#2 \@@_build_last:NNn #3#4#5
-  { #2 \@@_build_last:NNn #3 #4 { #1 #5 } }
-%    \end{macrocode}
-% \end{macro}
-%
-% \begin{macro}
-%   {
-%     \tl_build_put_left:Nn, \tl_build_put_left:Ne, \tl_build_put_left:Nx,
-%     \tl_build_gput_left:Nn, \tl_build_gput_left:Ne, \tl_build_gput_left:Nx,
-%     \@@_build_put_left:NNn
-%   }
-%   See \cs{tl_build_put_right:Nn} for all the machinery.  We could
-%   easily provide \cs[no-index]{tl_build_put_left_right:Nnn}, by just
-%   add the \meta{right} material after the \Arg{left} in the
-%   |x|-expanding assignment.
-%    \begin{macrocode}
-\cs_new_protected:Npn \tl_build_put_left:Nn #1
-  { \@@_build_put_left:NNn \cs_set_nopar:Npe #1 }
-\cs_generate_variant:Nn \tl_build_put_left:Nn { Ne , Nx }
-\cs_new_protected:Npn \tl_build_gput_left:Nn #1
-  { \@@_build_put_left:NNn \cs_gset_nopar:Npe #1 }
-\cs_generate_variant:Nn \tl_build_gput_left:Nn { Ne , Nx }
-\cs_new_protected:Npn \@@_build_put_left:NNn #1#2#3
-  {
-    #1 #2
-      {
-        \exp_after:wN \exp_not:n \exp_after:wN
-          {
-            \exp:w \exp_after:wN \@@_build_put:nn
-              \exp_after:wN {#2} {#3}
-          }
-      }
-  }
-%    \end{macrocode}
-% \end{macro}
-%
 % \begin{macro}{\tl_build_get:NN}
-% \begin{macro}{\@@_build_get:NNN, \@@_build_get:w, \@@_build_get_end:w}
-%   The idea is to expand the \meta{tl~var} then the \meta{next~tl} and
-%   so on, all within an |x|-expanding assignment, and wrap as
-%   appropriate in \cs{exp_not:n}.  The various \meta{left} parts are
-%   left in the assignment as we go, which enables us to expand the
-%   \meta{next~tl} at the right place.  The various \meta{right} parts
-%   are eventually picked up in one last \cs{exp_not:n}, with a brace
-%   trick to wrap all the \meta{right} parts together.
 %    \begin{macrocode}
 \cs_new_protected:Npn \tl_build_get:NN
   { \@@_build_get:NNN \__kernel_tl_set:Ne }
-\cs_new_protected:Npn \@@_build_get:NNN #1#2#3
-  { #1 #3 { \if_false: { \fi: \exp_after:wN \@@_build_get:w #2 } } }
-\cs_new:Npn \@@_build_get:w #1 \@@_build_last:NNn #2#3#4
-  {
-    \exp_not:n {#4}
-    \if_meaning:w \c_empty_tl #3
-      \exp_after:wN \@@_build_get_end:w
-    \fi:
-    \exp_after:wN \@@_build_get:w #3
-  }
-\cs_new:Npn \@@_build_get_end:w #1#2#3
-  { \exp_after:wN \exp_not:n \exp_after:wN { \if_false: } \fi: }
-%    \end{macrocode}
-% \end{macro}
-% \end{macro}
-%
-% \begin{macro}{\tl_build_end:N, \tl_build_gend:N, \@@_build_end_loop:NN}
-%   Get the data then clear the \meta{next~tl} recursively until finding
-%   an empty one.  It is perhaps wasteful to repeatedly use
-%   \cs{cs_to_str:N}.  The local/global scope is checked by
-%   \cs{tl_set:Ne} or \cs{tl_gset:Ne}.
-%    \begin{macrocode}
-\cs_new_protected:Npn \tl_build_end:N #1
-  {
-    \@@_build_get:NNN \__kernel_tl_set:Ne #1 #1
-    \exp_args:Nc \@@_build_end_loop:NN { \cs_to_str:N #1 ' } \tl_clear:N
-  }
-\cs_new_protected:Npn \tl_build_gend:N #1
-  {
-    \@@_build_get:NNN \__kernel_tl_gset:Ne #1 #1
-    \exp_args:Nc \@@_build_end_loop:NN { \cs_to_str:N #1 ' } \tl_gclear:N
-  }
-\cs_new_protected:Npn \@@_build_end_loop:NN #1#2
-  {
-    \if_meaning:w \c_empty_tl #1
-      \exp_after:wN \use_none:nnnnnn
-    \fi:
-    #2 #1
-    \exp_args:Nc \@@_build_end_loop:NN { \cs_to_str:N #1 ' } #2
-  }
 %    \end{macrocode}
 % \end{macro}
 %
diff --git a/l3kernel/l3tl-build.dtx b/l3kernel/l3tl-build.dtx
new file mode 100644
index 000000000..6929b5d2d
--- /dev/null
+++ b/l3kernel/l3tl-build.dtx
@@ -0,0 +1,329 @@
+% \iffalse meta-comment
+%
+%% File: l3tl-build.dtx
+%
+% Copyright (C) 2018-2023 The LaTeX Project
+%
+% It may be distributed and/or modified under the conditions of the
+% LaTeX Project Public License (LPPL), either version 1.3c of this
+% license or (at your option) any later version.  The latest version
+% of this license is in the file
+%
+%    https://www.latex-project.org/lppl.txt
+%
+% This file is part of the "l3kernel bundle" (The Work in LPPL)
+% and all files in that bundle must be distributed together.
+%
+% -----------------------------------------------------------------------
+%
+% The development version of the bundle can be found at
+%
+%    https://github.com/latex3/latex3
+%
+% for those people who are interested.
+%
+%<*driver>
+\documentclass[full,kernel]{l3doc}
+\begin{document}
+  \DocInput{\jobname.dtx}
+\end{document}
+%</driver>
+% \fi
+%
+% \title{^^A
+%   The \textsf{l3tl-build} package\\ Piecewise \texttt{tl} constructions^^A
+% }
+%
+% \author{^^A
+%  The \LaTeX{} Project\thanks
+%    {^^A
+%      E-mail:
+%        \href{mailto:latex-team at latex-project.org}
+%          {latex-team at latex-project.org}^^A
+%    }^^A
+% }
+%
+% \date{Released 2023-10-10}
+%
+% \maketitle
+%
+% \begin{documentation}
+%
+% \section{Constructing \meta{tl~var} by accumulation}
+%
+% When creating a \meta{tl~var} by accumulation of many tokens, the performance
+% available using a combination of \cs{tl_set:Nn} and \cs{tl_put_right:Nn} or
+% similar begins to become an issue. To address this, a set of functions are
+% available to \enquote{build} a \meta{tl~var}. The performance of this approach
+% is much more efficient than the standard \cs{tl_put_right:Nn}, but the
+% constructed token list cannot be accessed during construction other than
+% by methods provided in this section.
+%
+% \begin{function}[added = 2018-04-01]{\tl_build_begin:N, \tl_build_gbegin:N}
+%   \begin{syntax}
+%     \cs{tl_build_begin:N} \meta{tl~var}
+%   \end{syntax}
+%   Clears the \meta{tl~var} and sets it up to support other
+%   \cs[no-index]{tl_build_\ldots{}} functions.  Until \cs{tl_build_end:N}
+%   \meta{tl~var} is called, applying any function from \pkg{l3tl} other
+%   than \cs[no-index]{tl_build_\ldots{}} will lead to incorrect
+%   results.  The |begin| and |gbegin| functions must be used for local
+%   and global \meta{tl~var} respectively.
+% \end{function}
+%
+% \begin{function}[added = 2018-04-01]
+%   {
+%     \tl_build_put_left:Nn, \tl_build_put_left:Ne,
+%     \tl_build_gput_left:Nn, \tl_build_gput_left:Ne,
+%     \tl_build_put_right:Nn, \tl_build_put_right:Ne,
+%     \tl_build_gput_right:Nn, \tl_build_gput_right:Ne
+%   }
+%   \begin{syntax}
+%     \cs{tl_build_put_left:Nn} \meta{tl~var} \Arg{tokens}
+%     \cs{tl_build_put_right:Nn} \meta{tl~var} \Arg{tokens}
+%   \end{syntax}
+%   Adds \meta{tokens} to the left or right side of the current contents
+%   of \meta{tl~var}.  The \meta{tl~var} must have been set up with
+%   \cs{tl_build_begin:N} or \cs{tl_build_gbegin:N}.  The |put| and
+%   |gput| functions must be used for local and global \meta{tl~var}
+%   respectively.  The |right| functions are about twice faster than the
+%   |left| functions.
+% \end{function}
+%
+% \begin{function}[added = 2018-04-01]{\tl_build_end:N, \tl_build_gend:N}
+%   \begin{syntax}
+%     \cs{tl_build_end:N} \meta{tl~var}
+%   \end{syntax}
+%   Gets the contents of \meta{tl~var} and stores that into the
+%   \meta{tl~var} using \cs{tl_set:Nn} or \cs{tl_gset:Nn}.
+%   The \meta{tl~var} must have
+%   been set up with \cs{tl_build_begin:N} or \cs{tl_build_gbegin:N}.
+%   The |end| and |gend| functions must be used for local and global
+%   \meta{tl~var} respectively.  These functions completely remove the
+%   setup code that enabled \meta{tl~var} to be used for other
+%   \cs[no-index]{tl_build_\ldots{}} functions. After the action of
+%   |end|/|gend|, the \meta{tl~var} may be manipulated using standard
+%   \texttt{tl} functions.
+% \end{function}
+%
+% \end{documentation}
+%
+% \begin{implementation}
+%
+% \section{\pkg{l3tl-build} implementation}
+%
+%    \begin{macrocode}
+%<*package>
+%    \end{macrocode}
+%
+%    \begin{macrocode}
+%<@@=tl>
+%    \end{macrocode}
+%
+% Between \cs{tl_build_begin:N} \meta{tl~var} and \cs{tl_build_end:N}
+% \meta{tl~var}, the \meta{tl~var} has the structure
+% \begin{quote}
+%   \cs{exp_end:} \ldots{} \cs{exp_end:} \cs{@@_build_last:NNn}
+%   \meta{assignment} \meta{next~tl} \Arg{left} \meta{right}
+% \end{quote}
+% where \meta{right} is not braced.  The \enquote{data} it represents is
+% \meta{left} followed by the \enquote{data} of \meta{next~tl} followed
+% by \meta{right}.  The \meta{next~tl} is a token list variable whose
+% name is that of \meta{tl~var} followed by~|'|.  There are between $0$
+% and $4$ \cs{exp_end:} to keep track of when \meta{left} and
+% \meta{right} should be put into the \meta{next~tl}.  The
+% \meta{assignment} is \cs{cs_set_nopar:Npe} if the variable is local,
+% and \cs{cs_gset_nopar:Npe} if it is global.
+%
+% \begin{macro}{\tl_build_begin:N, \tl_build_gbegin:N}
+% \begin{macro}{\@@_build_begin:NN, \@@_build_begin:NNN}
+%   First construct the \meta{next~tl}: using a prime here conflicts
+%   with the usual \pkg{expl3} convention but we need a name that can be
+%   derived from |#1| without any external data such as a counter.
+%   Empty that \meta{next~tl} and setup the structure.  The local and
+%   global versions only differ by a single function
+%   \cs[no-index]{cs_(g)set_nopar:Npe} used for all assignments: this is
+%   important because only that function is stored in the \meta{tl~var}
+%   and \meta{next~tl} for subsequent assignments.  In principle
+%   \cs{@@_build_begin:NNN} could use \cs[no-index]{tl_(g)clear_new:N}
+%   to empty |#1| and make sure it is defined, but logging the
+%   definition does not seem useful so we just do |#3| |#1| |{}| to
+%   clear it locally or globally as appropriate.
+%    \begin{macrocode}
+\cs_new_protected:Npn \tl_build_begin:N #1
+  { \@@_build_begin:NN \cs_set_nopar:Npe #1 }
+\cs_new_protected:Npn \tl_build_gbegin:N #1
+  { \@@_build_begin:NN \cs_gset_nopar:Npe #1 }
+\cs_new_protected:Npn \@@_build_begin:NN #1#2
+  { \exp_args:Nc \@@_build_begin:NNN { \cs_to_str:N #2 ' } #2 #1 }
+\cs_new_protected:Npn \@@_build_begin:NNN #1#2#3
+  {
+    #3 #1 { }
+    #3 #2
+      {
+        \exp_not:n { \exp_end: \exp_end: \exp_end: \exp_end: }
+        \exp_not:n { \@@_build_last:NNn #3 #1 { } }
+      }
+  }
+%    \end{macrocode}
+% \end{macro}
+% \end{macro}
+%
+% \begin{macro}
+%   {
+%     \tl_build_put_right:Nn, \tl_build_put_right:Ne, \tl_build_put_right:Nx,
+%     \tl_build_gput_right:Nn, \tl_build_gput_right:Ne, \tl_build_gput_right:Nx
+%   }
+% \begin{macro}{\@@_build_last:NNn}
+% \begin{macro}{\@@_build_put:nn}
+% \begin{macro}{\@@_build_put:nw}
+%   Similar to \cs{tl_put_right:Nn}, but apply \cs{exp:w} to |#1|.  Most
+%   of the time this just removes one \cs{exp_end:}.  When there are
+%   none left, \cs{@@_build_last:NNn} is expanded instead.  It resets
+%   the definition of the \meta{tl~var} by ending the \cs{exp_not:n} and
+%   the definition early.  Then it makes sure the \meta{next~tl} (its
+%   argument |#1|) is set-up and starts a new definition.  Then
+%   \cs{@@_build_put:nn} and \cs{@@_build_put:nw} place the \meta{left}
+%   part of the original \meta{tl~var} as appropriate for the definition
+%   of the \meta{next~tl} (the \meta{right} part is left in the right
+%   place without ever becoming a macro argument).  We use
+%   \cs{exp_after:wN} rather than some \cs{exp_args:No} to avoid reading
+%   arguments that are likely very long token lists.  We use
+%   \cs[no-index]{cs_(g)set_nopar:Npe} rather than
+%   \cs[no-index]{tl_(g)set:Ne} partly for the same reason and partly
+%   because the assignments are interrupted by brace tricks, which
+%   implies that the assignment does not simply set the token list to an
+%   |e|-expansion of the second argument.
+%    \begin{macrocode}
+\cs_new_protected:Npn \tl_build_put_right:Nn #1#2
+  {
+    \cs_set_nopar:Npe #1
+      { \exp_after:wN \exp_not:n \exp_after:wN { \exp:w #1 #2 } }
+  }
+\cs_generate_variant:Nn \tl_build_put_right:Nn { Ne , Nx }
+\cs_new_protected:Npn \tl_build_gput_right:Nn #1#2
+  {
+    \cs_gset_nopar:Npe #1
+      { \exp_after:wN \exp_not:n \exp_after:wN { \exp:w #1 #2 } }
+  }
+\cs_generate_variant:Nn \tl_build_gput_right:Nn { Ne , Nx }
+\cs_new_protected:Npn \@@_build_last:NNn #1#2
+  {
+    \if_false: { { \fi:
+          \exp_end: \exp_end: \exp_end: \exp_end: \exp_end:
+          \@@_build_last:NNn #1 #2 { }
+        }
+      }
+    \if_meaning:w \c_empty_tl #2
+      \@@_build_begin:NN #1 #2
+    \fi:
+    #1 #2
+      {
+        \exp_after:wN \exp_not:n \exp_after:wN
+          {
+            \exp:w \if_false: } } \fi:
+            \exp_after:wN \@@_build_put:nn \exp_after:wN {#2}
+  }
+\cs_new_protected:Npn \@@_build_put:nn #1#2 { \@@_build_put:nw {#2} #1 }
+\cs_new_protected:Npn \@@_build_put:nw #1#2 \@@_build_last:NNn #3#4#5
+  { #2 \@@_build_last:NNn #3 #4 { #1 #5 } }
+%    \end{macrocode}
+% \end{macro}
+% \end{macro}
+% \end{macro}
+% \end{macro}
+%
+% \begin{macro}
+%   {
+%     \tl_build_put_left:Nn, \tl_build_put_left:Ne, \tl_build_put_left:Nx,
+%     \tl_build_gput_left:Nn, \tl_build_gput_left:Ne, \tl_build_gput_left:Nx
+%   }
+% \begin{macro}{\@@_build_put_left:NNn}
+%   See \cs{tl_build_put_right:Nn} for all the machinery.  We could
+%   easily provide \cs[no-index]{tl_build_put_left_right:Nnn}, by just
+%   add the \meta{right} material after the \Arg{left} in the
+%   |x|-expanding assignment.
+%    \begin{macrocode}
+\cs_new_protected:Npn \tl_build_put_left:Nn #1
+  { \@@_build_put_left:NNn \cs_set_nopar:Npe #1 }
+\cs_generate_variant:Nn \tl_build_put_left:Nn { Ne , Nx }
+\cs_new_protected:Npn \tl_build_gput_left:Nn #1
+  { \@@_build_put_left:NNn \cs_gset_nopar:Npe #1 }
+\cs_generate_variant:Nn \tl_build_gput_left:Nn { Ne , Nx }
+\cs_new_protected:Npn \@@_build_put_left:NNn #1#2#3
+  {
+    #1 #2
+      {
+        \exp_after:wN \exp_not:n \exp_after:wN
+          {
+            \exp:w \exp_after:wN \@@_build_put:nn
+              \exp_after:wN {#2} {#3}
+          }
+      }
+  }
+%    \end{macrocode}
+% \end{macro}
+% \end{macro}
+%
+% \begin{macro}{\tl_build_end:N, \tl_build_gend:N}
+% \begin{macro}{\@@_build_end_loop:NN}
+%   Get the data then clear the \meta{next~tl} recursively until finding
+%   an empty one.  It is perhaps wasteful to repeatedly use
+%   \cs{cs_to_str:N}.  The local/global scope is checked by
+%   \cs{tl_set:Ne} or \cs{tl_gset:Ne}.
+%    \begin{macrocode}
+\cs_new_protected:Npn \tl_build_end:N #1
+  {
+    \@@_build_get:NNN \__kernel_tl_set:Ne #1 #1
+    \exp_args:Nc \@@_build_end_loop:NN { \cs_to_str:N #1 ' } \tl_clear:N
+  }
+\cs_new_protected:Npn \tl_build_gend:N #1
+  {
+    \@@_build_get:NNN \__kernel_tl_gset:Ne #1 #1
+    \exp_args:Nc \@@_build_end_loop:NN { \cs_to_str:N #1 ' } \tl_gclear:N
+  }
+\cs_new_protected:Npn \@@_build_end_loop:NN #1#2
+  {
+    \if_meaning:w \c_empty_tl #1
+      \exp_after:wN \use_none:nnnnnn
+    \fi:
+    #2 #1
+    \exp_args:Nc \@@_build_end_loop:NN { \cs_to_str:N #1 ' } #2
+  }
+%    \end{macrocode}
+% \end{macro}
+% \end{macro}
+%
+% \begin{macro}{\@@_build_get:NNN}
+% \begin{macro}{\@@_build_get:w, \@@_build_get_end:w}
+%   The idea is to expand the \meta{tl~var} then the \meta{next~tl} and
+%   so on, all within an |e|-expanding assignment, and wrap as
+%   appropriate in \cs{exp_not:n}.  The various \meta{left} parts are
+%   left in the assignment as we go, which enables us to expand the
+%   \meta{next~tl} at the right place.  The various \meta{right} parts
+%   are eventually picked up in one last \cs{exp_not:n}, with a brace
+%   trick to wrap all the \meta{right} parts together.
+%    \begin{macrocode}
+\cs_new_protected:Npn \@@_build_get:NNN #1#2#3
+  { #1 #3 { \if_false: { \fi: \exp_after:wN \@@_build_get:w #2 } } }
+\cs_new:Npn \@@_build_get:w #1 \@@_build_last:NNn #2#3#4
+  {
+    \exp_not:n {#4}
+    \if_meaning:w \c_empty_tl #3
+      \exp_after:wN \@@_build_get_end:w
+    \fi:
+    \exp_after:wN \@@_build_get:w #3
+  }
+\cs_new:Npn \@@_build_get_end:w #1#2#3
+  { \exp_after:wN \exp_not:n \exp_after:wN { \if_false: } \fi: }
+%    \end{macrocode}
+% \end{macro}
+% \end{macro}
+%
+%    \begin{macrocode}
+%</package>
+%    \end{macrocode}
+%
+% \end{implementation}
+%
+% \PrintIndex





More information about the latex3-commits mailing list.