summaryrefslogtreecommitdiff
path: root/Master/texmf-dist/source/latex/l3kernel/l3tl-build.dtx
diff options
context:
space:
mode:
authorKarl Berry <karl@freefriends.org>2017-06-05 23:17:08 +0000
committerKarl Berry <karl@freefriends.org>2017-06-05 23:17:08 +0000
commit683004f8a1d94fc432fd8104903a431e27bfba93 (patch)
tree2450b41f4c918810556cbaec853ec48ddc2b949a /Master/texmf-dist/source/latex/l3kernel/l3tl-build.dtx
parentc684ba451bf548bdb24c40ed54caa9f11ac21422 (diff)
latex3 (30may17)
git-svn-id: svn://tug.org/texlive/trunk@44483 c570f23f-e606-0410-a88d-b1316a301751
Diffstat (limited to 'Master/texmf-dist/source/latex/l3kernel/l3tl-build.dtx')
-rw-r--r--Master/texmf-dist/source/latex/l3kernel/l3tl-build.dtx280
1 files changed, 280 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..268c8616a55
--- /dev/null
+++ b/Master/texmf-dist/source/latex/l3kernel/l3tl-build.dtx
@@ -0,0 +1,280 @@
+% \iffalse meta-comment
+%
+%% File: l3tl-build.dtx Copyright (C) 2011-2017 The LaTeX3 Project
+%
+% It may be distributed and/or modified under the conditions of the
+% LaTeX Project Public License (LPPL), either version 1.3c of this
+% license or (at your option) any later version. The latest version
+% of this license is in the file
+%
+% http://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]{l3doc}
+\begin{document}
+ \DocInput{\jobname.dtx}
+\end{document}
+%</driver>
+% \fi
+%
+%
+% \title{^^A
+% The \textsf{l3tl-build} package: building token lists^^A
+% }
+%
+% \author{^^A
+% The \LaTeX3 Project\thanks
+% {^^A
+% E-mail:
+% \href{mailto:latex-team@latex-project.org}
+% {latex-team@latex-project.org}^^A
+% }^^A
+% }
+%
+% \date{Released 2017/05/29}
+%
+% \maketitle
+%
+% \begin{documentation}
+%
+% \section{\pkg{l3tl-build} documentation}
+%
+% This module provides no user function: it is meant for kernel use
+% only.
+%
+% There are two main ways of building token lists from individual
+% tokens. Either in one go within an \texttt{x}-expanding assignment, or
+% by repeatedly using \cs{tl_put_right:Nn}. The first method takes a
+% linear time, but only allows expandable operations. The second method
+% takes a time quadratic in the length of the token list, but allows
+% expandable and non-expandable operations.
+%
+% The goal of this module is to provide functions to build a token list
+% piece by piece in linear time, while allowing non-expandable
+% operations. This is achieved by abusing \tn{toks}: adding some tokens
+% to the token list is done by storing them in a free token register
+% (time $O(1)$ for each such operation). Those token registers are only
+% put together at the end, within an \texttt{x}-expanding assignment,
+% which takes a linear time.\footnote{If we run out of token registers,
+% then the currently filled-up \tn{toks} are put together in a
+% temporary token list, and cleared, and we ultimately use
+% \cs{tl_put_right:Nx} to put those chunks together. Hence the true
+% asymptotic is quadratic, with a very small constant.} Of course,
+% all this must be done in a group: we can't go and clobber the values
+% of legitimate \tn{toks} used by \LaTeXe{}.
+%
+% Since none of the current applications need the ability to insert
+% material on the left of the token list, I have not implemented
+% that. This could be done for instance by using odd-numbered \tn{toks}
+% for the left part, and even-numbered \tn{toks} for the right part.
+%
+% \subsection{Internal functions}
+%
+% \begin{function}
+% {
+% \__tl_build:Nw, \__tl_gbuild:Nw,
+% \__tl_build_x:Nw, \__tl_gbuild_x:Nw
+% }
+% \begin{syntax}
+% \cs{__tl_build:Nw} \meta{tl~var} \texttt{\ldots{}}
+% \cs{__tl_build_one:n} \Arg{tokens_1} \texttt{\ldots{}}
+% \cs{__tl_build_one:n} \Arg{tokens_2} \texttt{\ldots{}}
+% \ldots{}
+% \cs{__tl_build_end:}
+% \end{syntax}
+% Defines the \meta{tl~var} to contain the contents of \meta{tokens1}
+% followed by \meta{tokens2}, \emph{etc.} This is built in such a way
+% to be more efficient than repeatedly using \cs{tl_put_right:Nn}. The
+% code in \enquote{\texttt{\ldots{}}} does not need to be
+% expandable. The commands \cs{__tl_build:Nw} and \cs{__tl_build_end:}
+% start and end a group. The assignment to the \meta{tl~var} occurs
+% just after the end of that group, using \cs{tl_set:Nn},
+% \cs{tl_gset:Nn}, \cs{tl_set:Nx}, or \cs{tl_gset:Nx}.
+% \end{function}
+%
+% \begin{function}{\__tl_build_one:n, \__tl_build_one:o, \__tl_build_one:x}
+% \begin{syntax}
+% \cs{__tl_build_one:n} \Arg{tokens}
+% \end{syntax}
+% This function may only be used within the scope of a
+% \cs{__tl_build:Nw} function. It adds the \meta{tokens} on the
+% right of the current token list.
+% \end{function}
+%
+% \begin{function}{\__tl_build_end:}
+% Ends the scope started by \cs{__tl_build:Nw}, and performs the
+% relevant assignment.
+% \end{function}
+%
+% \end{documentation}
+%
+% \begin{implementation}
+%
+% \section{\pkg{l3tl-build} implementation}
+%
+% \begin{macrocode}
+%<*initex|package>
+% \end{macrocode}
+%
+% \begin{macrocode}
+%<@@=tl_build>
+% \end{macrocode}
+%
+% \subsection{Variables and helper functions}
+%
+% \begin{variable}{\l_@@_start_index_int, \l_@@_index_int}
+% Integers pointing to the starting index (currently always starts at
+% zero), and the current index. The corresponding \tn{toks} are
+% accessed directly by number.
+% \begin{macrocode}
+\int_new:N \l_@@_start_index_int
+\int_new:N \l_@@_index_int
+% \end{macrocode}
+% \end{variable}
+%
+% \begin{variable}{\l_@@_result_tl}
+% The resulting token list is normally built in one go by unpacking
+% all \tn{toks} in some range. In the rare cases where there are too
+% many \cs{@@_one:n} commands, leading to the depletion of
+% registers, the contents of the current set of \tn{toks} is unpacked
+% into \cs{l_@@_result_tl}. This prevents overflow from
+% affecting the end-user (beyond an obvious performance hit).
+% \begin{macrocode}
+\tl_new:N \l_@@_result_tl
+% \end{macrocode}
+% \end{variable}
+%
+% \begin{macro}{\@@_unpack:}
+% \begin{macro}[aux, EXP]{\@@_unpack_loop:w}
+% The various pieces of the token list are built in \tn{toks} from the
+% \texttt{start_index} (inclusive) to the (current) \texttt{index}
+% (excluded). Those \tn{toks} are unpacked and stored in order in the
+% \texttt{result} token list. Optimizations would be possible here,
+% for instance, unpacking $10$ \tn{toks} at a time with a macro
+% expanding to |\the\toks#10...\the\toks#19|, but this should be kept
+% for much later.
+% \begin{macrocode}
+\cs_new_protected:Npn \@@_unpack:
+ {
+ \tl_put_right:Nx \l_@@_result_tl
+ {
+ \exp_after:wN \@@_unpack_loop:w
+ \int_use:N \l_@@_start_index_int ;
+ \__prg_break_point:
+ }
+ }
+\cs_new:Npn \@@_unpack_loop:w #1 ;
+ {
+ \if_int_compare:w #1 = \l_@@_index_int
+ \exp_after:wN \__prg_break:
+ \fi:
+ \tex_the:D \tex_toks:D #1 \exp_stop_f:
+ \exp_after:wN \@@_unpack_loop:w
+ \int_use:N \__int_eval:w #1 + 1 ;
+ }
+% \end{macrocode}
+% \end{macro}
+% \end{macro}
+%
+% \subsection{Building the token list}
+%
+% \begin{macro}
+% {
+% \@@:Nw , \@@_x:Nw ,
+% \__tl_gbuild:Nw , \__tl_gbuild_x:Nw
+% }
+% \begin{macro}[aux]{\@@_aux:NNw}
+% Similar to what is done for coffins: redefine some command, here
+% \cs{@@_end_aux:n} to hold the relevant assignment (see
+% \cs{@@_end:} for details). Then initialize the start index and
+% the current index at zero, and empty the \texttt{result} token list.
+% \begin{macrocode}
+\cs_new_protected:Npn \@@:Nw
+ { \@@_aux:NNw \tl_set:Nn }
+\cs_new_protected:Npn \@@_x:Nw
+ { \@@_aux:NNw \tl_set:Nx }
+\cs_new_protected:Npn \__tl_gbuild:Nw
+ { \@@_aux:NNw \tl_gset:Nn }
+\cs_new_protected:Npn \__tl_gbuild_x:Nw
+ { \@@_aux:NNw \tl_gset:Nx }
+\cs_new_protected:Npn \@@_aux:NNw #1#2
+ {
+ \group_begin:
+ \cs_set:Npn \@@_end_assignment:n
+ { \group_end: #1 #2 }
+ \int_zero:N \l_@@_start_index_int
+ \int_zero:N \l_@@_index_int
+ \tl_clear:N \l_@@_result_tl
+ }
+% \end{macrocode}
+% \end{macro}
+% \end{macro}
+%
+% \begin{macro}{\@@_end:}
+% \begin{macro}[aux]{\@@_end_assignment:n}
+% When we are done building a token list, unpack all \tn{toks} into
+% the \texttt{result} token list, and expand this list before closing
+% the group. The \cs{@@_end_assignment:n} function is defined by
+% \cs{@@_aux:NNw} to end the group and hold the relevant
+% assignment. Its value outside is irrelevant, but just in case, we
+% set it to a function which would clean up the contents of
+% \cs{l_@@_result_tl}.
+% \begin{macrocode}
+\cs_new_protected:Npn \@@_end:
+ {
+ \@@_unpack:
+ \exp_args:No
+ \@@_end_assignment:n \l_@@_result_tl
+ }
+\cs_new_eq:NN \@@_end_assignment:n \use_none:n
+% \end{macrocode}
+% \end{macro}
+% \end{macro}
+%
+% \begin{macro}{\@@_one:n, \@@_one:o, \@@_one:x}
+% Store the tokens in a free \tn{toks}, then move the pointer to the
+% next one. If we overflow, unpack the current \tn{toks}, and reset
+% the current index, preparing to fill more \tn{toks}. This could be
+% optimized by avoiding to read |#1|, using \tn{afterassignment}.
+% \begin{macrocode}
+\cs_new_protected:Npn \@@_one:n #1
+ {
+ \tex_toks:D \l_@@_index_int {#1}
+ \int_incr:N \l_@@_index_int
+ \if_int_compare:w \l_@@_index_int > \c_max_register_int
+ \@@_unpack:
+ \l_@@_index_int \l_@@_start_index_int
+ \fi:
+ }
+\cs_new_protected:Npn \@@_one:o #1
+ {
+ \tex_toks:D \l_@@_index_int \exp_after:wN {#1}
+ \int_incr:N \l_@@_index_int
+ \if_int_compare:w \l_@@_index_int > \c_max_register_int
+ \@@_unpack:
+ \l_@@_index_int \l_@@_start_index_int
+ \fi:
+ }
+\cs_new_protected:Npn \@@_one:x #1
+ { \use:x { \@@_one:n {#1} } }
+% \end{macrocode}
+% \end{macro}
+%
+% \begin{macrocode}
+%</initex|package>
+% \end{macrocode}
+%
+% \end{implementation}
+%
+% \PrintIndex