% \iffalse meta-comment % %% File: l3cctab.dtx % % Copyright (C) 2018,2019 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 "l3experimental 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|package> \RequirePackage{expl3} % %<*driver> \documentclass[full]{l3doc} \begin{document} \DocInput{\jobname.dtx} \end{document} % % \fi % % \title{^^A % The \pkg{l3cctab} package\\ Experimental category code tables^^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 2019-08-25} % % \maketitle % % \begin{documentation} % % \section{\pkg{l3cctab} documentation} % % A category code table enables rapid switching of all category codes in % one operation. For \LuaTeX{}, this is possible over the entire Unicode % range. For other engines, only the $8$-bit range ($0$-$255$) is covered by % such tables. % % \begin{function}{\cctab_new:N} % \begin{syntax} % \cs{cctab_new:N} \meta{category code table} % \end{syntax} % Creates a new category code table, initially with the codes as % used by \IniTeX{}. % \end{function} % % \begin{function}{\cctab_const:Nn} % \begin{syntax} % \cs{cctab_const:Nn} \meta{category code table} \Arg{category code set up} % \end{syntax} % Creates a new category code table and applies the % \meta{category code set up} on top of prevailing settings, then saves % as a constant table. % \end{function} % % \begin{function}{\cctab_gset:Nn} % \begin{syntax} % \cs{cctab_gset:Nn} \meta{category code table} \Arg{category code set up} % \end{syntax} % Sets the \meta{category code table} to apply the category codes % which apply when the prevailing régime is modified by the % \meta{category code set up}. Thus within a standard code block % the starting point will be the code applied by \cs{c_code_cctab}. % The assignment of the table is global: the underlying primitive does % not respect grouping. % \end{function} % % \begin{function}{\cctab_begin:N} % \begin{syntax} % \cs{cctab_begin:N} \meta{category code table} % \end{syntax} % Switches the category codes in force to those stored in the % \meta{category code table}. The prevailing codes before the % function is called are added to a stack, for use with % \cs{cctab_end:}. % \end{function} % % \begin{function}{\cctab_end:} % \begin{syntax} % \cs{cctab_end:} % \end{syntax} % Ends the scope of a \meta{category code table} started using % \cs{cctab_begin:N}, retuning the codes to those in force before the % matching \cs{cctab_begin:N} was used. % \end{function} % % \begin{variable}{\c_code_cctab} % Category code table for the code environment. This does not include % setting the behaviour of the line-end character, which is only % altered by \cs{ExplSyntaxOn}. % \end{variable} % % \begin{variable}{\c_document_cctab} % Category code table for a standard \LaTeX{} document. This does not % include setting the behaviour of the line-end character, which is % only altered by \cs{ExplSyntaxOff}. % \end{variable} % % \begin{variable}{\c_initex_cctab} % Category code table as set up by \IniTeX{}. % \end{variable} % % \begin{variable}{\c_other_cctab} % Category code table where all characters have category code $12$ % (other). % \end{variable} % % \begin{variable}{\c_str_cctab} % Category code table where all characters have category code $12$ % (other) with the exception of spaces, which have category code % $10$ (space). % \end{variable} % % \end{documentation} % % \begin{implementation} % % \section{\pkg{l3cctab} implementation} % % \begin{macrocode} %<*initex|package> % \end{macrocode} % % \begin{macrocode} %<@@=cctab> % \end{macrocode} % % \begin{macrocode} %<*package> \ProvidesExplPackage{l3cctab}{2019-08-25}{} {L3 Experimental category code tables} % % \end{macrocode} % % \begin{variable}{\g_@@_allocate_int} % \begin{variable}{\g_@@_stack_int} % \begin{variable}{\g_@@_stack_seq} % To allocate category code tables, both the read-only and stack % tables need to be followed. There is also a sequence stack for the % dynamic tables themselves. % \begin{macrocode} \int_new:N \g_@@_allocate_int \int_gset:Nn \g_@@_allocate_int { -1 } \int_new:N \g_@@_stack_int \seq_new:N \g_@@_stack_seq % \end{macrocode} % \end{variable} % \end{variable} % \end{variable} % % \begin{variable}{\l_@@_tmp_tl} % Scratch space. % \begin{macrocode} \tl_new:N \l_@@_tmp_tl % \end{macrocode} % \end{variable} % % \begin{macro}{\cctab_new:N} % \begin{macro}{\cctab_begin:N} % \begin{macro}{\cctab_end:} % \begin{macro}{\cctab_gset:Nn} % As \LuaTeX{} offers engine support for category code tables, and this is % entirely lacking from the other engines, we need two complementary % approaches here. Rather than intermix them, we split the set up based on % engine. (Some future \XeTeX{} may add support, at which point the % conditional here would be subtly different.) % % First, the \LuaTeX{} case. % \begin{macrocode} \sys_if_engine_luatex:TF { % \end{macrocode} % Creating a new category code table is done slightly differently % from other registers. Low-numbered tables are more efficiently-stored % than high-numbered ones. There is also a need to have a stack of % flexible tables as well as the set of read-only ones. To satisfy both % of these requirements, odd numbered tables are used for read-only % tables, and even ones for the stack. Here, therefore, the odd numbers % are allocated. % \begin{macrocode} \cs_new_protected:Npn \cctab_new:N #1 { \__kernel_chk_if_free_cs:N #1 %<*initex> \int_gadd:Nn \g_@@_allocate_int { 2 } \int_compare:nNnTF \g_@@_allocate_int < { \c_max_register_int + 1 } { \tex_global:D \tex_chardef:D #1 \g_@@_allocate_int \tex_initcatcodetable:D #1 } { \__kernel_msg_fatal:nnx { kernel } { out-of-registers } { cctab } } % %<*package> \newcatcodetable #1 % } % \end{macrocode} % The aim here is to ensure that the saved tables are read-only. This is % done by using a stack of tables which are not read only, and actually % having them as \enquote{in use} copies. % \begin{macrocode} \cs_new_protected:Npn \cctab_begin:N #1 { \seq_gpush:Nx \g_@@_stack_seq { \tex_the:D \tex_catcodetable:D } \tex_catcodetable:D #1 \int_gadd:Nn \g_@@_stack_int { 2 } \int_compare:nNnT \g_@@_stack_int > \c_max_register_int { \__kernel_msg_fatal:nn { kernel } { cctab-stack-full } } \tex_savecatcodetable:D \g_@@_stack_int \tex_catcodetable:D \g_@@_stack_int } \cs_new_protected:Npn \cctab_end: { \int_gsub:Nn \g_@@_stack_int { 2 } \seq_if_empty:NTF \g_@@_stack_seq { \tl_set:Nn \l_@@_tmp_tl { 0 } } { \seq_gpop:NN \g_@@_stack_seq \l_@@_tmp_tl } \tex_catcodetable:D \l_@@_tmp_tl \scan_stop: } % \end{macrocode} % Category code tables are always global, so only one version is needed. % The set up here is simple, and means that at the point of use there is % no need to worry about escaping category codes. % \begin{macrocode} \cs_new_protected:Npn \cctab_gset:Nn #1#2 { \group_begin: #2 \tex_savecatcodetable:D #1 \group_end: } } % \end{macrocode} % Now the case for other engines. Here, we use an integer array for each % table. The index base is out-by-one, so we have an internal function to % handle that. The rest of the approach here is pretty simple: use a stack % of tables, and save to them at each |begin|. Unlike the \LuaTeX{} case, % we can't accidentally alter a saved table, which makes life a little % easier. % \begin{macrocode} { \cs_new_protected:Npn \@@_gstore:Nnn #1#2#3 { \intarray_gset:cnn { g_@@_ \int_use:N #1 _cctab } { #2 + 1 } {#3} } % \end{macrocode} % Following the \LuaTeX{} pattern, a new table starts with \IniTeX{} codes. % \begin{macrocode} \cs_new_protected:Npn \cctab_new:N #1 { \int_gadd:Nn \g_@@_allocate_int { 2 } \int_const:Nn #1 { \g_@@_allocate_int } \intarray_new:cn { g_@@_ \int_use:N #1 _cctab } { 256 } \int_step_inline:nn { 256 } { \intarray_gset:cnn { g_@@_ \int_use:N #1 _cctab } {##1} { 12 } } \@@_gstore:Nnn #1 { 0 } { 9 } \@@_gstore:Nnn #1 { 13 } { 5 } \@@_gstore:Nnn #1 { 32 } { 10 } \@@_gstore:Nnn #1 { 37 } { 14 } \int_step_inline:nnn { 64 } { 89 } { \@@_gstore:Nnn #1 {##1} { 11 } } \@@_gstore:Nnn #1 { 92 } { 0 } \int_step_inline:nnn { 97 } { 122 } { \@@_gstore:Nnn #1 {##1} { 11 } } \@@_gstore:Nnn #1 { 127 } { 15 } } \cs_new_protected:Npn \cctab_begin:N #1 { \int_gadd:Nn \g_@@_stack_int { 2 } \int_compare:nNnT \g_@@_stack_int > \c_max_register_int { \__kernel_msg_fatal:nn { kernel } { cctab-stack-full } } \cs_if_exist:cF { g_@@_ \int_use:N \g_@@_stack_int _cctab } { \intarray_new:cn { g_@@_ \int_use:N \g_@@_stack_int _cctab } { 256 } } \int_step_inline:nn { 256 } { \intarray_gset:cnn { g_@@_ \int_use:N \g_@@_stack_int _cctab } {##1} { \char_value_catcode:n { ##1 - 1 } } } \int_step_inline:nn { 256 } { \char_set_catcode:nn { ##1 - 1 } { \intarray_item:cn { g_@@_ \int_use:N #1 _cctab } {##1} } } } \cs_generate_variant:Nn \intarray_new:Nn { c } \cs_generate_variant:Nn \intarray_gset:Nnn { c } \cs_new_protected:Npn \cctab_end: { \int_step_inline:nn { 256 } { \char_set_catcode:nn { ##1 - 1 } { \intarray_item:cn { g_@@_ \int_use:N \g_@@_stack_int _cctab } {##1} } } \int_gsub:Nn \g_@@_stack_int { 1 } } \cs_generate_variant:Nn \intarray_item:Nn { c } \cs_new_protected:Npn \cctab_gset:Nn #1#2 { \group_begin: #2 \int_step_inline:nn { 256 } { \intarray_gset:cnn { g_@@_ \int_use:N #1 _cctab } {##1} { \char_value_catcode:n { ##1 - 1 } } } \group_end: } } % \end{macrocode} % \end{macro} % \end{macro} % \end{macro} % \end{macro} % % \begin{macro}{\cctab_const:Nn} % \begin{macrocode} \cs_new_protected:Npn \cctab_const:Nn #1#2 { \cctab_new:N #1 \cctab_gset:Nn #1 {#2} } % \end{macrocode} % \end{macro} % % \begin{variable} % { % \c_initex_cctab , % \c_code_cctab , % \c_document_cctab , % \c_initex_cctab , % \c_other_cctab , % \c_str_cctab % } % Creating category code tables is easy using the function above. % The \texttt{other} and \texttt{string} ones are done by completely % ignoring the existing codes as this makes life a lot less complex. % \begin{macrocode} \cctab_const:Nn \c_code_cctab { } \cctab_const:Nn \c_document_cctab { \char_set_catcode_space:n { 9 } \char_set_catcode_space:n { 32 } \char_set_catcode_other:n { 58 } \char_set_catcode_math_subscript:n { 95 } \char_set_catcode_active:n { 126 } } \cctab_const:Nn \c_other_cctab { \int_step_inline:nnn { 0 } { 127 } { \char_set_catcode_other:n {#1} } } \cctab_const:Nn \c_str_cctab { \int_step_inline:nnn { 0 } { 127 } { \char_set_catcode_other:n {#1} } \char_set_catcode_space:n { 32 } } % \end{macrocode} % \end{variable} % % \subsection{Messages} % % \begin{macrocode} \__kernel_msg_new:nnnn { kernel } { cctab-stack-full } { The~category~code~table~stack~is~exhausted. } { LaTeX~has~been~asked~to~switch~to~a~new~category~code~table,~ but~there~is~no~more~space~to~do~this! } % \end{macrocode} % % \begin{macrocode} % % \end{macrocode} % %\end{implementation} % %\PrintIndex