% \iffalse meta-comment % %% File: l3alloc.dtx Copyright (C) 1990-2012,2014 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 released version of this bundle is available from CTAN. %% %% ----------------------------------------------------------------------- %% %% The development version of the bundle can be found at %% %% http://www.latex-project.org/svnroot/experimental/trunk/ %% %% for those people who are interested. %% %%%%%%%%%%% %% NOTE: %% %%%%%%%%%%% %% %% Snapshots taken from the repository represent work in progress and may %% not work or may contain conflicting material! We therefore ask %% people _not_ to put them into distributions, archives, etc. without %% prior consultation with the LaTeX3 Project. %% %% ----------------------------------------------------------------------- % %<*driver> \documentclass[full]{l3doc} \GetIdInfo$Id: l3alloc.dtx 5363 2014-08-24 19:57:56Z joseph $ {L3 Register allocation} \begin{document} \DocInput{\jobname.dtx} \end{document} % % \fi % % \title{^^A % The \pkg{l3alloc} package\\ Register allocation^^A % \thanks{This file describes v\ExplFileVersion, % last revised \ExplFileDate.}^^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 \ExplFileDate} % % \maketitle % % \begin{documentation} % % Note that this module is only used for generating an \pkg{expl3}-based % format. Under \LaTeX{}, the \pkg{etex} package is used for allocation % management. % % This module provides the basic mechanism for allocating \TeX{}'s % registers. While designing this we have to take into account the % following characteristics: % \begin{itemize} % \item |\box255| is reserved for use in the output routine, so it % should not be allocated otherwise. % \item \TeX{} can load up $256$ hyphenation patterns (registers % \tn{language} $0$ to $255$), % \item \TeX{} can load no more than $16$ math families, % \item \TeX{} supports no more than $16$ I/O streams for reading % (\tn{read}) and $16$ I/O streams for writing (\tn{write}), % \item \TeX{} supports no more than $256$ inserts. % \item The other registers (\tn{count}, \tn{dimen}, \tn{skip}, % \tn{muskip}, \tn{box}, and \tn{toks}) range from $0$ to $32\,767$ % ($65\,535$ for \LuaTeX{}), but registers numbered above $255$ are % accessed somewhat less efficiently (except in \LuaTeX{}, where access % is \enquote[flat}). % \item Registers could be allocated both globally and locally; the % use of registers could also be global or local. Here we % provide support for globally allocated registers for both % global and local use. % \end{itemize} % We also need to allow for some bookkeeping: we need to know which % register was allocated last and which registers can not be % allocated by the standard mechanisms. % % \section{Internal functions} % % Register-based allocation is a low-level process, and is therefore % only to be used as part of kernel code. % % \begin{function}[updated = 2012-11-09]{\__alloc_new:nnnN} % \begin{syntax} % \cs{__alloc_new:nnnN} \Arg{type} \Arg{min} \Arg{max} \meta{function} % \end{syntax} % Shorthand for allocating new registers. Defines \cs{\meta{type}_new:N} as % and allocator function of the specified \meta{type}, indexed up from % \meta{min} to a \meta{max}, and with assignment carried out by % the \meta{function}. This process will create two token lists, % \cs{g_\meta{type}_allocation_tl} and \cs{c_\meta{type}_allocation_max_tl}, % to store the current and maximum allocation numbers, respectively. % \end{function} % % \begin{function}[updated = 2011-09-05]{\__alloc_setup_type:nnn} % \begin{syntax} % \cs{__alloc_setup_type:nnn} \Arg{type} \Arg{min} \Arg{max} % \end{syntax} % Sets up the storage needed for the administration of registers of % \Arg{type}, which will start allocating at \meta{min} and will issue % an error if there is an attempt to allocate past the \meta{max}. % \end{function} % % \begin{function}{\__alloc_reg:nNN} % \begin{syntax} % \cs{__alloc_reg:nNN} \Arg{type} \meta{function} \meta{register} % \end{syntax} % Preforms the allocation for a new \meta{register} of \meta{type}, % using the allocator \meta{function} (which will be either a % primitive \tn{\ldots def} or \tn{chardef}). % \end{function} % % \end{documentation} % % \begin{implementation} % % \section{\pkg{l3alloc} implementation} % % \begin{macrocode} %<*initex> % \end{macrocode} % % \begin{macrocode} %<@@=alloc> % \end{macrocode} % % \begin{macro}[int]{\@@_new:nnnN} % Shorthand for defining new register types and their allocators: creates % the appropriate variables and the allocator function itself. % \begin{macrocode} \cs_new_protected:Npn \@@_new:nnnN #1#2#3#4 { \@@_setup_type:nnn {#1} {#2} {#3} \cs_new_protected:cpn { #1 _new:N } ##1 { \@@_reg:nNN {#1} #4 ##1 } } % \end{macrocode} % \end{macro} % % \begin{macro}[int]{\@@_setup_type:nnn} % For each type of register we need to \enquote{counters} that hold the % last allocated global register, plus a constant for the maximum % allocation. % \begin{macrocode} \cs_new_protected:Npn \@@_setup_type:nnn #1#2#3 { \tl_new:c { g__ #1 _allocation_tl } \tl_gset:cx { g__ #1 _allocation_tl } { \int_eval:n {#2} } \tl_const:cx { c__ #1 _allocation_max_tl } { \int_eval:n {#3} } } % \end{macrocode} % \end{macro} % % \begin{macro}{\int_eval:n} % For bootstrapping purposes, a definition of \cs{int_eval:n} is needed % in terms of primitives. This is replaced in \pkg{l3int} with a clearer % one. % \begin{macrocode} \cs_new:Npn \int_eval:n #1 { \tex_number:D \etex_numexpr:D #1 \scan_stop: } % \end{macrocode} % \end{macro} % % \begin{macro} % {\box_new:N, \dim_new:N, \int_new:N, \muskip_new:N \skip_new:N} % To get everything to work correctly for inserts, some register types % need to have their allocators set up \enquote{early}. It therefore % makes sense to collect most of them together here. % \begin{macrocode} \luatex_if_engine:TF { \@@_new:nnnN { box } \c_zero \c_max_register_int \tex_chardef:D } { \@@_new:nnnN { box } \c_zero \c_max_register_int \tex_mathchardef:D } \@@_new:nnnN { dim } \c_zero \c_max_register_int \tex_dimendef:D \@@_new:nnnN { int } { 11 } \c_max_register_int \tex_countdef:D \@@_new:nnnN { muskip } \c_zero \c_max_register_int \tex_muskipdef:D \@@_new:nnnN { skip } \c_zero \c_max_register_int \tex_skipdef:D % \end{macrocode} % \end{macro} % % \begin{macro}{\insert_new:N} % For inserts, there is a need to reserve space in various other registers. % First, the basic allocation is done. % \begin{macrocode} \@@_new:nnnN { insert } { 221 } { 254 } \tex_chardef:D % \end{macrocode} % Reserve a gap in the \texttt{box}, \texttt{dim}, \texttt{int} and % \texttt{skip} lists. (An inline token list mapping would read better here, % but this does not work until \texttt{int} allocation is available!) Note % that \texttt{box255} is reserved by \TeX{} itself (\LuaTeX{} does make % this alterable, but that doesn't really do much for us so we ignore % that!) % \begin{macrocode} \tl_const:Nn \c__box_allocation_reserve_begin_tl { 221 } \tl_const:Nn \c__box_allocation_reserve_end_tl { 255 } \tl_const:Nn \c__dim_allocation_reserve_begin_tl { 221 } \tl_const:Nn \c__dim_allocation_reserve_end_tl { 254 } \tl_const:Nn \c__int_allocation_reserve_begin_tl { 221 } \tl_const:Nn \c__int_allocation_reserve_end_tl { 254 } \tl_const:Nn \c__skip_allocation_reserve_begin_tl { 221 } \tl_const:Nn \c__skip_allocation_reserve_end_tl { 254 } % \end{macrocode} % \end{macro} % % \begin{macro}[int]{\@@_reg:nNN} % This internal macro performs the actual allocation. % \begin{macrocode} \cs_new_protected:Npn \@@_reg:nNN #1#2#3 { \__chk_if_free_cs:N #3 \int_compare:nNnTF { \tl_use:c { g__ #1 _allocation_tl } } > { \tl_use:c { c__ #1 _allocation_max_tl } } { \__msg_kernel_fatal:nnx { kernel } { out-of-registers } {#1} } { \tex_global:D #2 #3 \tl_use:c { g__ #1 _allocation_tl } \scan_stop: \iow_log:x { \token_to_str:N #3 ~=~ #1 ~register~ \tl_use:c { g__ #1 _allocation_tl } } \@@_next:n {#1} } } % \end{macrocode} % \end{macro} % % \begin{macro}[aux]{\@@_next:n} % Set up the next allocation by adding one to the current number, and if % necessary skipping over a reserved block. % \begin{macrocode} \cs_new_protected:Npn \@@_next:n #1 { \tl_gset:cx { g__ #1 _allocation_tl } { \int_eval:n { \tl_if_exist:cTF { c__ #1 _allocation_reserve_begin_tl } { \int_compare:nNnTF { \tl_use:c { g__ #1 _allocation_tl } + \c_one } = { \tl_use:c { c__ #1 _allocation_reserve_begin_tl } } { \tl_use:c { c__ #1 _allocation_reserve_end_tl } } { \tl_use:c { g__ #1 _allocation_tl } } } { \tl_use:c { g__ #1 _allocation_tl } } + \c_one } } } % \end{macrocode} % \end{macro} % % \begin{macrocode} % % \end{macrocode} % % \end{implementation} % % \PrintIndex