diff options
Diffstat (limited to 'Master/texmf-dist/source/latex/l3kernel/l3tl-build.dtx')
-rw-r--r-- | Master/texmf-dist/source/latex/l3kernel/l3tl-build.dtx | 329 |
1 files changed, 329 insertions, 0 deletions
diff --git a/Master/texmf-dist/source/latex/l3kernel/l3tl-build.dtx b/Master/texmf-dist/source/latex/l3kernel/l3tl-build.dtx new file mode 100644 index 00000000000..08eb31e1b21 --- /dev/null +++ b/Master/texmf-dist/source/latex/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@latex-project.org} +% {latex-team@latex-project.org}^^A +% }^^A +% } +% +% \date{Released 2023-11-01} +% +% \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 + { \__kernel_exp_not:w \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 + { \__kernel_exp_not:w \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 + { + \__kernel_exp_not:w \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 +% adding the \meta{right} material after the \Arg{left} in the +% |e|-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 + { + \__kernel_exp_not:w \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 + { \__kernel_exp_not:w \exp_after:wN { \if_false: } \fi: } +% \end{macrocode} +% \end{macro} +% \end{macro} +% +% \begin{macrocode} +%</package> +% \end{macrocode} +% +% \end{implementation} +% +% \PrintIndex |