summaryrefslogtreecommitdiff
path: root/Master/texmf-dist/source/latex/l3kernel/l3candidates.dtx
diff options
context:
space:
mode:
authorKarl Berry <karl@freefriends.org>2018-04-30 22:39:09 +0000
committerKarl Berry <karl@freefriends.org>2018-04-30 22:39:09 +0000
commita28e1bfccd6fe522fcd296426e4d89c7fb4f19b6 (patch)
treeb72347e08575b56fcfed87c4d837b48dcfd1e02a /Master/texmf-dist/source/latex/l3kernel/l3candidates.dtx
parentb40c37a9e22b8235ff9c0bc256d00f7af94304c3 (diff)
l3 (30apr18)
git-svn-id: svn://tug.org/texlive/trunk@47516 c570f23f-e606-0410-a88d-b1316a301751
Diffstat (limited to 'Master/texmf-dist/source/latex/l3kernel/l3candidates.dtx')
-rw-r--r--Master/texmf-dist/source/latex/l3kernel/l3candidates.dtx1317
1 files changed, 867 insertions, 450 deletions
diff --git a/Master/texmf-dist/source/latex/l3kernel/l3candidates.dtx b/Master/texmf-dist/source/latex/l3kernel/l3candidates.dtx
index 3208f1ec9bb..cd1e06fd6c2 100644
--- a/Master/texmf-dist/source/latex/l3kernel/l3candidates.dtx
+++ b/Master/texmf-dist/source/latex/l3kernel/l3candidates.dtx
@@ -42,7 +42,7 @@
% }^^A
% }
%
-% \date{Released 2018/03/05}
+% \date{Released 2018-04-30}
%
% \maketitle
%
@@ -136,6 +136,19 @@
% \end{texnote}
% \end{function}
%
+% \begin{function}[EXP, added = 2018-04-17]{\use_x:n}
+% \begin{syntax}
+% \cs{use_x:n} \Arg{token list}
+% \end{syntax}
+% Fully expands the \meta{token list} in an \texttt{x}-type manner,
+% \emph{but} the function remains fully expandable, and parameter
+% character (usually~|#|) need not be doubled.
+% \begin{texnote}
+% \cs{use_x:n} the a wrapper around the primitive \tn{expanded}:
+% it requires two expansions to complete its action.
+% \end{texnote}
+% \end{function}
+%
% \section{Additions to \pkg{l3box}}
%
% \subsection{Viewing part of a box}
@@ -201,8 +214,8 @@
% \cs{clist_rand_item:n} \Arg{comma list}
% \end{syntax}
% Selects a pseudo-random item of the \meta{comma list}. If the
-% \meta{comma list} has no item, the result is empty. This is only
-% available in \pdfTeX{} and \LuaTeX{}.
+% \meta{comma list} has no item, the result is empty. This not
+% yet available in \XeTeX{}.
% \begin{texnote}
% The result is returned within the \tn{unexpanded}
% primitive (\cs{exp_not:n}), which means that the \meta{item}
@@ -255,6 +268,19 @@
% should be defined.
% \end{function}
%
+% \begin{function}[added = 2018-04-04]{\exp_args_generate:n}
+% \begin{syntax}
+% \cs{exp_args_generate:n} \Arg{variant argument specifiers}
+% \end{syntax}
+% Defines \cs[no-index]{exp_args:N\meta{variant}} functions for each
+% \meta{variant} given in the comma list \Arg{variant argument
+% specifiers}. Each \meta{variant} should consist of the letters |N|,
+% |c|, |n|, |V|, |v|, |o|, |f|, |x|, |p| and the resulting function is
+% protected if the letter |x| appears in the \meta{variant}. This is
+% only useful for cases where \cs{cs_generate_variant:Nn} is not
+% applicable.
+% \end{function}
+%
% \section{Additions to \pkg{l3file}}
%
% \begin{function}[added = 2017-07-11]{\file_get_mdfive_hash:nN}
@@ -335,15 +361,14 @@
% \end{texnote}
% \end{function}
%
-% \section{Additions to \pkg{l3int}}
+% \section{Additions to \pkg{l3flag}}
%
-% \begin{function}[EXP, added = 2016-12-06]{\int_rand:nn}
+% \begin{function}[EXP, added = 2018-04-02]{\flag_raise_if_clear:n}
% \begin{syntax}
-% \cs{int_rand:nn} \Arg{intexpr_1} \Arg{intexpr_2}
+% \cs{flag_raise_if_clear:n} \Arg{flag name}
% \end{syntax}
-% Evaluates the two \meta{integer expressions} and produces a
-% pseudo-random number between the two (with bounds included). This
-% is only available in \pdfTeX{} and \LuaTeX{}.
+% Ensures the \meta{flag} is raised by making its height at least~$1$,
+% locally.
% \end{function}
%
% \section{Additions to \pkg{l3msg}}
@@ -478,10 +503,9 @@
% \begin{syntax}
% \cs{prop_rand_key_value:N} \meta{prop~var}
% \end{syntax}
-% Selects a pseudo-random key--value pair in the \meta{property list}
-% and returns \Arg{key}\Arg{value}. If the \meta{property list} is
-% empty the result is empty. This is only available in \pdfTeX{} and
-% \LuaTeX{}.
+% Selects a pseudo-random key--value pair from the \meta{property list}
+% and returns \Arg{key} and \Arg{value}. If the \meta{property list} is
+% empty the result is empty. This is not yet available in \XeTeX{}.
% \begin{texnote}
% The result is returned within the \tn{unexpanded}
% primitive (\cs{exp_not:n}), which means that the \meta{value}
@@ -578,8 +602,8 @@
% \cs{seq_rand_item:N} \meta{seq~var}
% \end{syntax}
% Selects a pseudo-random item of the \meta{sequence}. If the
-% \meta{sequence} is empty the result is empty. This is only
-% available in \pdfTeX{} and \LuaTeX{}.
+% \meta{sequence} is empty the result is empty. This is not yet
+% available in \XeTeX{}.
% \begin{texnote}
% The result is returned within the \tn{unexpanded}
% primitive (\cs{exp_not:n}), which means that the \meta{item}
@@ -598,6 +622,61 @@
% items in the \meta{comma list}.
% \end{function}
%
+% \begin{function}[added = 2018-04-06]
+% {\seq_set_from_function:NnN, \seq_gset_from_function:NnN}
+% \begin{syntax}
+% \cs{seq_set_from_function:NnN} \meta{seq~var} \Arg{loop~code} \meta{function}
+% \end{syntax}
+% Sets the \meta{seq~var} equal to a sequence whose items are obtained
+% by \texttt{x}-expanding \meta{loop~code} \meta{function}. This
+% expansion must result in successive calls to the \meta{function}
+% with no nonexpandable tokens in between. More precisely the
+% \meta{function} is replaced by a wrapper function that inserts the
+% appropriate separators between items in the sequence. The
+% \meta{loop~code} must be expandable; it can be for example
+% \cs{tl_map_function:NN} \meta{tl~var} or \cs{clist_map_function:nN}
+% \Arg{clist} or \cs{int_step_function:nnnN} \Arg{initial value}
+% \Arg{step} \Arg{final value}.
+% \end{function}
+%
+% \begin{function}[added = 2018-04-06]
+% {\seq_set_from_inline_x:Nnn, \seq_gset_from_inline_x:Nnn}
+% \begin{syntax}
+% \cs{seq_set_from_inline_x:Nnn} \meta{seq~var} \Arg{loop~code} \Arg{inline~code}
+% \end{syntax}
+% Sets the \meta{seq~var} equal to a sequence whose items are obtained
+% by \texttt{x}-expanding \meta{loop~code} applied to a
+% \meta{function} derived from the \meta{inline~code}. A
+% \meta{function} is defined, that takes one argument,
+% \texttt{x}-expands the \meta{inline~code} with that argument
+% as~|#1|, then adds appropriate separators to turn the result into an
+% item of the sequence. The \texttt{x}-expansion of \meta{loop~code}
+% \meta{function} must result in successive calls to the
+% \meta{function} with no nonexpandable tokens in between. The
+% \meta{loop~code} must be expandable; it can be for example
+% \cs{tl_map_function:NN} \meta{tl~var} or \cs{clist_map_function:nN}
+% \Arg{clist} or \cs{int_step_function:nnnN} \Arg{initial value}
+% \Arg{step} \Arg{final value}, but not the analogous \enquote{inline}
+% mappings.
+% \end{function}
+%
+% \begin{function}[added = 2018-04-29]{\seq_shuffle:N, \seq_gshuffle:N}
+% \begin{syntax}
+% \cs{seq_shuffle:N} \meta{seq~var}
+% \end{syntax}
+% Sets the \meta{seq~var} to the result of placing the items of the
+% \meta{seq~var} in a random order. Each item is (roughly) as likely
+% to end up in any given position.
+% \begin{texnote}
+% For sequences with more than $13$ items or so, only a small
+% proportion of all possible permutations can be reached, because
+% the random seed \cs{sys_rand_seed:} only has $28$-bits. The use
+% of \tn{toks} internally means that sequences with more than
+% $32767$ or $65535$ items (depending on the engine) cannot be
+% shuffled.
+% \end{texnote}
+% \end{function}
+%
% \section{Additions to \pkg{l3skip}}
%
% \begin{function}{\skip_split_finite_else_action:nnNN}
@@ -622,7 +701,7 @@
% \cs{sys_if_rand_exist:TF} \Arg{true code} \Arg{false code}
% \end{syntax}
% Tests if the engine has a pseudo-random number generator. Currently
-% this is the case in \pdfTeX{} and \LuaTeX{}.
+% this is the case in \pdfTeX{}, \LuaTeX{}, \pTeX{} and \upTeX{}.
% \end{function}
%
% \begin{function}[added = 2017-05-27, EXP]{\sys_rand_seed:}
@@ -638,13 +717,18 @@
% \begin{syntax}
% \cs{sys_gset_rand_seed:n} \Arg{intexpr}
% \end{syntax}
-% Sets the seed for the engine's pseudo-random number generator to the
-% \meta{integer expression}. The assignment is global. This random
-% seed affects all \cs[no-index]{\ldots{}_rand} functions (such as
+% Globally sets the seed for the engine's pseudo-random number
+% generator to the \meta{integer expression}. This random seed
+% affects all \cs[no-index]{\ldots{}_rand} functions (such as
% \cs{int_rand:nn} or \cs{clist_rand_item:n}) as well as other
-% packages relying on the engine's random number generator. Currently
-% only the absolute value of the seed is used. In engines without
-% random number support this produces an error.
+% packages relying on the engine's random number generator. In
+% engines without random number support this produces an error.
+% \begin{texnote}
+% While a $32$-bit (signed) integer can be given as a seed, only the
+% absolute value is used and any number beyond $2^{28}$ is divided
+% by an appropriate power of~$2$. We recommend using an integer in
+% $[0,2^{28}-1]$.
+% \end{texnote}
% \end{function}
%
% \begin{variable}[added = 2017-05-27]{\c_sys_shell_escape_int}
@@ -974,8 +1058,8 @@
% \cs{tl_rand_item:n} \Arg{token list}
% \end{syntax}
% Selects a pseudo-random item of the \meta{token list}. If the
-% \meta{token list} is blank, the result is empty. This is only
-% available in \pdfTeX{} and \LuaTeX{}.
+% \meta{token list} is blank, the result is empty. This is not yet
+% available in \XeTeX{}.
% \begin{texnote}
% The result is returned within the \tn{unexpanded}
% primitive (\cs{exp_not:n}), which means that the \meta{item}
@@ -984,7 +1068,8 @@
% \end{texnote}
% \end{function}
%
-% \begin{function}[EXP, added = 2017-02-17, updated = 2017-07-15]{\tl_range:nnn}
+% \begin{function}[EXP, added = 2017-02-17, updated = 2017-07-15]
+% {\tl_range:Nnn, \tl_range:nnn}
% \begin{syntax}
% \cs{tl_range:Nnn} \meta{tl~var} \Arg{start index} \Arg{end index}
% \cs{tl_range:nnn} \Arg{token list} \Arg{start index} \Arg{end index}
@@ -1067,6 +1152,73 @@
% \end{texnote}
% \end{function}
%
+% \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}
+% \end{syntax}
+% Clears the \meta{tl~var} and sets it up to support other
+% \cs[no-index]{tl_build_\ldots{}} functions. The |clear| and
+% |gclear| 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:Nx,
+% \tl_build_gput_left:Nn, \tl_build_gput_left:Nx,
+% \tl_build_put_right:Nn, \tl_build_put_right:Nx,
+% \tl_build_gput_right:Nn, \tl_build_gput_right:Nx,
+% }
+% \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:N} \meta{tl~var_1} \meta{tl~var_2}
+% \end{syntax}
+% Stores the contents of the \meta{tl~var_1} in the \meta{tl~var_2}.
+% The \meta{tl~var_1} must have been set up with \cs{tl_build_begin:N}
+% or \cs{tl_build_gbegin:N}. The \meta{tl~var_2} is a
+% \enquote{normal} token list variable, assigned locally using
+% \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}. 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}
+%
% \section{Additions to \pkg{l3token}}
%
% \begin{variable}[added = 2017-08-07]{\c_catcode_active_space_tl}
@@ -1074,6 +1226,31 @@
% (\enquote{active}), and character code $32$ (space).
% \end{variable}
%
+% \begin{function}[added = 2018-04-06, EXP]
+% {
+% \char_lower_case:N, \char_upper_case:N,
+% \char_mixed_case:N, \char_fold_case:N
+% }
+% \begin{syntax}
+% \cs{char_lower_case:N} \meta{char}
+% \end{syntax}
+% Converts the \meta{char} to the equivalent case-changed character
+% as detailed by the function name (see \cs{str_fold_case:n}
+% and \cs{tl_mixed_case:n} for details of these terms). The case mapping
+% is carried out with no context-dependence (\emph{cf.}~\cs{tl_upper_case:n},
+% \emph{etc.})
+% \end{function}
+%
+% \begin{function}[added = 2018-04-02]{\char_codepoint_to_bytes:n}
+% \begin{syntax}
+% \cs{char_codepoint_to_bytes:n} \Arg{codepoint}
+% \end{syntax}
+% Converts the (Unicode) \meta{codepoint} to UTF-8 bytes. The expansion
+% of this function comprises a leading integer (|1|--|4|) followed by the
+% appropriate number of brace groups, each of which contains one byte of
+% the UTF-8 sequence for the codepoint.
+% \end{function}
+%
% \begin{function}[TF, updated = 2012-12-20]{\peek_N_type:}
% \begin{syntax}
% \cs{peek_N_type:TF} \Arg{true code} \Arg{false code}
@@ -1159,9 +1336,9 @@
{
\hbox_set:Nn \l_@@_internal_box
{
- \tex_kern:D - \__dim_eval:n {#2}
+ \tex_kern:D - \@@_dim_eval:n {#2}
\box_use:N #1
- \tex_kern:D - \__dim_eval:n {#4}
+ \tex_kern:D - \@@_dim_eval:n {#4}
}
% \end{macrocode}
% For the height and depth, there is a need to watch the baseline is
@@ -1225,9 +1402,9 @@
{
\hbox_set:Nn \l_@@_internal_box
{
- \tex_kern:D - \__dim_eval:n {#2}
+ \tex_kern:D - \@@_dim_eval:n {#2}
\box_use:N #1
- \tex_kern:D \__dim_eval:n { #4 - \box_wd:N #1 }
+ \tex_kern:D \@@_dim_eval:n { #4 - \box_wd:N #1 }
}
\dim_compare:nNnTF {#3} < \c_zero_dim
{
@@ -1236,7 +1413,7 @@
\box_move_down:nn \c_zero_dim
{ \box_use:N \l_@@_internal_box }
}
- \box_set_dp:Nn \l_@@_internal_box { - \__dim_eval:n {#3} }
+ \box_set_dp:Nn \l_@@_internal_box { - \@@_dim_eval:n {#3} }
}
{
\hbox_set:Nn \l_@@_internal_box
@@ -1260,7 +1437,7 @@
{
\hbox_set:Nn \l_@@_internal_box
{
- \box_move_up:nn { - \__dim_eval:n {#5} }
+ \box_move_up:nn { - \@@_dim_eval:n {#5} }
{ \box_use:N \l_@@_internal_box }
}
\box_set_ht:Nn \l_@@_internal_box \c_zero_dim
@@ -1369,9 +1546,9 @@
% The corners and poles of the coffin can now be rotated around the
% origin. This is best achieved using mapping functions.
% \begin{macrocode}
- \prop_map_inline:cn { l_@@_corners_ \__int_value:w #1 _prop }
+ \prop_map_inline:cn { l_@@_corners_ \@@_to_value:N #1 _prop }
{ \@@_rotate_corner:Nnnn #1 {##1} ##2 }
- \prop_map_inline:cn { l_@@_poles_ \__int_value:w #1 _prop }
+ \prop_map_inline:cn { l_@@_poles_ \@@_to_value:N #1 _prop }
{ \@@_rotate_pole:Nnnnnn #1 {##1} ##2 }
% \end{macrocode}
% The bounding box of the coffin needs to be rotated, and to do this
@@ -1400,8 +1577,9 @@
\hbox_set:Nn \l_@@_internal_box
{
\tex_kern:D
- \__dim_eval:n
+ \dim_eval:n
{ \l_@@_bounding_shift_dim - \l_@@_left_corner_dim }
+ \exp_stop_f:
\box_move_down:nn { \l_@@_bottom_corner_dim }
{ \box_use:N #1 }
}
@@ -1423,9 +1601,9 @@
% The final task is to move the poles and corners such that they are
% back in alignment with the box reference point.
% \begin{macrocode}
- \prop_map_inline:cn { l_@@_corners_ \__int_value:w #1 _prop }
+ \prop_map_inline:cn { l_@@_corners_ \@@_to_value:N #1 _prop }
{ \@@_shift_corner:Nnnn #1 {##1} ##2 }
- \prop_map_inline:cn { l_@@_poles_ \__int_value:w #1 _prop }
+ \prop_map_inline:cn { l_@@_poles_ \@@_to_value:N #1 _prop }
{ \@@_shift_pole:Nnnnnn #1 {##1} ##2 }
}
\cs_generate_variant:Nn \coffin_rotate:Nn { c }
@@ -1442,12 +1620,18 @@
\prop_put:Nnx \l_@@_bounding_prop { tl }
{ { 0 pt } { \dim_eval:n { \box_ht:N #1 } } }
\prop_put:Nnx \l_@@_bounding_prop { tr }
- { { \dim_eval:n { \box_wd:N #1 } } { \dim_eval:n { \box_ht:N #1 } } }
+ {
+ { \dim_eval:n { \box_wd:N #1 } }
+ { \dim_eval:n { \box_ht:N #1 } }
+ }
\dim_set:Nn \l_@@_internal_dim { -\box_dp:N #1 }
\prop_put:Nnx \l_@@_bounding_prop { bl }
{ { 0 pt } { \dim_use:N \l_@@_internal_dim } }
\prop_put:Nnx \l_@@_bounding_prop { br }
- { { \dim_eval:n { \box_wd:N #1 } } { \dim_use:N \l_@@_internal_dim } }
+ {
+ { \dim_eval:n { \box_wd:N #1 } }
+ { \dim_use:N \l_@@_internal_dim }
+ }
}
% \end{macrocode}
% \end{macro}
@@ -1468,7 +1652,7 @@
\cs_new_protected:Npn \@@_rotate_corner:Nnnn #1#2#3#4
{
\@@_rotate_vector:nnNN {#3} {#4} \l_@@_x_dim \l_@@_y_dim
- \prop_put:cnx { l_@@_corners_ \__int_value:w #1 _prop } {#2}
+ \prop_put:cnx { l_@@_corners_ \@@_to_value:N #1 _prop } {#2}
{ { \dim_use:N \l_@@_x_dim } { \dim_use:N \l_@@_y_dim } }
}
% \end{macrocode}
@@ -1539,7 +1723,7 @@
\dim_set:Nn \l_@@_right_corner_dim { -\c_max_dim }
\dim_set:Nn \l_@@_bottom_corner_dim { \c_max_dim }
\dim_set:Nn \l_@@_left_corner_dim { \c_max_dim }
- \prop_map_inline:cn { l_@@_corners_ \__int_value:w #1 _prop }
+ \prop_map_inline:cn { l_@@_corners_ \@@_to_value:N #1 _prop }
{ \@@_find_corner_maxima_aux:nn ##2 }
}
\cs_new_protected:Npn \@@_find_corner_maxima_aux:nn #1#2
@@ -1586,7 +1770,7 @@
% \begin{macrocode}
\cs_new_protected:Npn \@@_shift_corner:Nnnn #1#2#3#4
{
- \prop_put:cnx { l_@@_corners_ \__int_value:w #1 _ prop } {#2}
+ \prop_put:cnx { l_@@_corners_ \@@_to_value:N #1 _ prop } {#2}
{
{ \dim_eval:n { #3 - \l_@@_left_corner_dim } }
{ \dim_eval:n { #4 - \l_@@_bottom_corner_dim } }
@@ -1594,7 +1778,7 @@
}
\cs_new_protected:Npn \@@_shift_pole:Nnnnnn #1#2#3#4#5#6
{
- \prop_put:cnx { l_@@_poles_ \__int_value:w #1 _ prop } {#2}
+ \prop_put:cnx { l_@@_poles_ \@@_to_value:N #1 _ prop } {#2}
{
{ \dim_eval:n { #3 - \l_@@_left_corner_dim } }
{ \dim_eval:n { #4 - \l_@@_bottom_corner_dim } }
@@ -1656,9 +1840,9 @@
% \begin{macrocode}
\cs_new_protected:Npn \@@_resize_common:Nnn #1#2#3
{
- \prop_map_inline:cn { l_@@_corners_ \__int_value:w #1 _prop }
+ \prop_map_inline:cn { l_@@_corners_ \@@_to_value:N #1 _prop }
{ \@@_scale_corner:Nnnn #1 {##1} ##2 }
- \prop_map_inline:cn { l_@@_poles_ \__int_value:w #1 _prop }
+ \prop_map_inline:cn { l_@@_poles_ \@@_to_value:N #1 _prop }
{ \@@_scale_pole:Nnnnnn #1 {##1} ##2 }
% \end{macrocode}
% Negative $x$-scaling values place the poles in the wrong
@@ -1666,9 +1850,11 @@
% \begin{macrocode}
\fp_compare:nNnT \l_@@_scale_x_fp < \c_zero_fp
{
- \prop_map_inline:cn { l_@@_corners_ \__int_value:w #1 _prop }
+ \prop_map_inline:cn
+ { l_@@_corners_ \@@_to_value:N #1 _prop }
{ \@@_x_shift_corner:Nnnn #1 {##1} ##2 }
- \prop_map_inline:cn { l_@@_poles_ \__int_value:w #1 _prop }
+ \prop_map_inline:cn
+ { l_@@_poles_ \@@_to_value:N #1 _prop }
{ \@@_x_shift_pole:Nnnnnn #1 {##1} ##2 }
}
}
@@ -1723,7 +1909,7 @@
\cs_new_protected:Npn \@@_scale_corner:Nnnn #1#2#3#4
{
\@@_scale_vector:nnNN {#3} {#4} \l_@@_x_dim \l_@@_y_dim
- \prop_put:cnx { l_@@_corners_ \__int_value:w #1 _prop } {#2}
+ \prop_put:cnx { l_@@_corners_ \@@_to_value:N #1 _prop } {#2}
{ { \dim_use:N \l_@@_x_dim } { \dim_use:N \l_@@_y_dim } }
}
\cs_new_protected:Npn \@@_scale_pole:Nnnnnn #1#2#3#4#5#6
@@ -1746,14 +1932,14 @@
% \begin{macrocode}
\cs_new_protected:Npn \@@_x_shift_corner:Nnnn #1#2#3#4
{
- \prop_put:cnx { l_@@_corners_ \__int_value:w #1 _prop } {#2}
+ \prop_put:cnx { l_@@_corners_ \@@_to_value:N #1 _prop } {#2}
{
{ \dim_eval:n { #3 + \box_wd:N #1 } } {#4}
}
}
\cs_new_protected:Npn \@@_x_shift_pole:Nnnnnn #1#2#3#4#5#6
{
- \prop_put:cnx { l_@@_poles_ \__int_value:w #1 _prop } {#2}
+ \prop_put:cnx { l_@@_poles_ \@@_to_value:N #1 _prop } {#2}
{
{ \dim_eval:n { #3 + \box_wd:N #1 } } {#4}
{#5} {#6}
@@ -1795,7 +1981,7 @@
{ \l_@@_full_name_str }
}
}
-\cs_if_exist:NTF \luatex_directlua:D
+\sys_if_engine_luatex:TF
{
\cs_set_protected:Npn \@@_get_details:nnN #1#2#3
{
@@ -1820,7 +2006,7 @@
{ \l_@@_full_name_str }
}
}
- \cs_if_exist:NT \xetex_XeTeXversion:D
+ \sys_if_engine_xetex:T
{
\cs_set_protected:Npn \@@_get_details:nnN #1#2#3
{
@@ -1869,99 +2055,28 @@
% \end{macrocode}
% \end{macro}
%
-% \subsection{Additions to \pkg{l3int}}
+% \subsection{Additions to \pkg{l3flag}}
%
% \begin{macrocode}
-%<@@=int>
+%<@@=flag>
% \end{macrocode}
%
-% \begin{macro}[EXP]{\int_rand:nn}
-% \begin{macro}[EXP]
-% {
-% \@@_rand:ww, \@@_rand_narrow:n,
-% \@@_rand_narrow:nnn, \@@_rand_narrow:nnnn
-% }
-% Evaluate the argument and filter out the case where the lower
-% bound~|#1| is more than the upper bound~|#2|. Then determine
-% whether the range is narrower than \cs{c__fp_rand_size_int}; |#2-#1|
-% may overflow for very large positive~|#2| and negative~|#1|. If the
-% range is wide, use slower code from \pkg{l3fp}. If the range is
-% narrow, call \cs{@@_rand_narrow:nn} \Arg{choices} |{#1}| where
-% \meta{choices} is the number of possible outcomes. Then
-% \cs{@@_rand_narrow:nnnn} receives a random number reduced modulo
-% \meta{choices}, the random number itself, \meta{choices} and |#1|.
-% To avoid bias, throw away the random number if it lies in the last,
-% incomplete, interval of size \meta{choices} in
-% $[0,\cs{c__fp_rand_size_int}-1]$, and try again.
+% \begin{macro}[EXP]{\flag_raise_if_clear:n}
+% It might be faster to just call the \enquote{trap} function in all
+% cases but conceptually the function name suggests we should only run
+% it if the flag is zero in case the \enquote{trap} made customizable
+% in the future.
% \begin{macrocode}
-\cs_if_exist:NTF \pdftex_uniformdeviate:D
- {
- \__kernel_patch_args:nNNpn
- {
- { \__kernel_chk_expr:nNnN {#1} \@@_eval:w { } \int_rand:nn }
- { \__kernel_chk_expr:nNnN {#2} \@@_eval:w { } \int_rand:nn }
- }
- \cs_new:Npn \int_rand:nn #1#2
- {
- \exp_after:wN \@@_rand:ww
- \@@_value:w \@@_eval:w #1 \exp_after:wN ;
- \@@_value:w \@@_eval:w #2 ;
- }
- \cs_new:Npn \@@_rand:ww #1; #2;
- {
- \int_compare:nNnTF {#1} > {#2}
- {
- \__kernel_msg_expandable_error:nnnn
- { kernel } { backward-range } {#1} {#2}
- \@@_rand:ww #2; #1;
- }
- {
- \int_compare:nNnTF {#1} > 0
- { \int_compare:nNnTF { #2 - #1 } < \c__fp_rand_size_int }
- { \int_compare:nNnTF {#2} < { #1 + \c__fp_rand_size_int } }
- {
- \exp_args:Nf \@@_rand_narrow:nn
- { \int_eval:n { #2 - #1 + 1 } } {#1}
- }
- { \fp_to_int:n { randint(#1,#2) } }
- }
- }
- \cs_new:Npn \@@_rand_narrow:nn
- {
- \exp_args:No \@@_rand_narrow:nnn
- { \pdftex_uniformdeviate:D \c__fp_rand_size_int }
- }
- \cs_new:Npn \@@_rand_narrow:nnn #1#2
- {
- \exp_args:Nf \@@_rand_narrow:nnnn
- { \int_mod:nn {#1} {#2} } {#1} {#2}
- }
- \cs_new:Npn \@@_rand_narrow:nnnn #1#2#3#4
- {
- \int_compare:nNnTF { #2 - #1 + #3 } > \c__fp_rand_size_int
- { \@@_rand_narrow:nn {#3} {#4} }
- { \int_eval:n { #4 + #1 } }
- }
- }
+\__kernel_patch:nnNNpn { \@@_chk_exist:n {#1} } { }
+\cs_new:Npn \flag_raise_if_clear:n #1
{
- \cs_new:Npn \int_rand:nn #1#2
- {
- \__kernel_msg_expandable_error:nn { kernel } { fp-no-random }
- \int_eval:n {#1}
- }
+ \if_cs_exist:w flag~#1~0 \cs_end:
+ \else:
+ \cs:w flag~#1 \cs_end: 0 ;
+ \fi:
}
% \end{macrocode}
% \end{macro}
-% \end{macro}
-%
-% The following must be added to \pkg{l3msg}.
-% \begin{macrocode}
-\cs_if_exist:NT \pdftex_uniformdeviate:D
- {
- \__kernel_msg_new:nnn { kernel } { backward-range }
- { Bounds~ordered~backwards~in~\int_rand:nn {#1}~{#2}. }
- }
-% \end{macrocode}
%
% \subsection{Additions to \pkg{l3msg}}
%
@@ -2075,7 +2190,7 @@
\__kernel_patch:nnNNpn { \__kernel_chk_var_scope:NN c #1 } { }
\cs_new_protected:Npn \bool_const:Nn #1#2
{
- \__chk_if_free_cs:N #1
+ \__kernel_chk_if_free_cs:N #1
\tex_global:D \tex_chardef:D #1 = \bool_if_p:n {#2}
}
\cs_generate_variant:Nn \bool_const:Nn { c }
@@ -2111,25 +2226,23 @@
%
% \begin{macro}[rEXP]{\prop_map_tokens:Nn, \prop_map_tokens:cn}
% \begin{macro}{\@@_map_tokens:nwwn}
-% The mapping is very similar to \cs{prop_map_function:NN}. It grabs
-% one key--value pair at a time, and stops when reaching the marker
-% key \cs{q_recursion_tail}, which cannot appear in normal keys since
-% those are strings. The odd construction |\use:n {#1}| allows |#1|
-% to contain any token without interfering with \cs{prop_map_break:}.
-% Argument |#2| of \cs{@@_map_tokens:nwwn} is \cs{s_@@} the first
-% time, and is otherwise empty.
+% The mapping is very similar to \cs{prop_map_function:NN}. The
+% \cs{use_i:nn} removes the leading \cs{s_@@}. The odd construction
+% |\use:n {#1}| allows |#1| to contain any token without interfering
+% with \cs{prop_map_break:}. The loop stops when the argument
+% delimited by \cs{@@_pair:wn} is \cs{prg_break:} instead of being
+% empty.
% \begin{macrocode}
\cs_new:Npn \prop_map_tokens:Nn #1#2
{
- \exp_last_unbraced:Nno \@@_map_tokens:nwwn {#2} #1
- \@@_pair:wn \q_recursion_tail \s_@@ { }
- \__prg_break_point:Nn \prop_map_break: { }
+ \exp_last_unbraced:Nno
+ \use_i:nn { \@@_map_tokens:nwwn {#2} } #1
+ \prg_break: \@@_pair:wn \s_@@ { } \prg_break_point:
+ \prg_break_point:Nn \prop_map_break: { }
}
\cs_new:Npn \@@_map_tokens:nwwn #1#2 \@@_pair:wn #3 \s_@@ #4
{
- \if_meaning:w \q_recursion_tail #3
- \exp_after:wN \prop_map_break:
- \fi:
+ #2
\use:n {#1} {#3} {#4}
\@@_map_tokens:nwwn {#1}
}
@@ -2140,33 +2253,30 @@
%
% \begin{macro}[EXP]
% {\prop_rand_key_value:N, \prop_rand_key_value:c}
-% \begin{macro}[EXP]{\@@_rand:NN, \@@_rand_item:Nw}
+% \begin{macro}[EXP]{\@@_rand_item:w}
% Contrarily to |clist|, |seq| and |tl|, there is no function to get
% an item of a |prop| given an integer between $1$ and the number of
% items, so we write the appropriate code. There is no bounds
-% checking because \cs{int_rand:nn} is always within bounds. At the
-% end, leave either the key |#3| or the value |#4| in the input
-% stream.
+% checking because \cs{int_rand:nn} is always within bounds. The
+% initial \cs{int_value:w} is stopped by the first \cs{s_@@} in~|#1|.
% \begin{macrocode}
-\cs_new:Npn \prop_rand_key_value:N { \@@_rand:NN \@@_rand:nNn }
-\cs_new:Npn \@@_rand:nNn #1#2#3 { \exp_not:n { {#1} {#3} } }
-\cs_new:Npn \@@_rand:NN #1#2
+\cs_new:Npn \prop_rand_key_value:N #1
{
- \prop_if_empty:NTF #2 { }
+ \prop_if_empty:NF #1
{
- \exp_after:wN \@@_rand_item:Nw \exp_after:wN #1
- \__int_value:w \int_rand:nn { 1 } { \prop_count:N #2 } #2
- \q_stop
+ \exp_after:wN \@@_rand_item:w
+ \int_value:w \int_rand:nn { 1 } { \prop_count:N #1 }
+ #1 \q_stop
}
}
-\cs_new:Npn \@@_rand_item:Nw #1#2 \s_@@ \@@_pair:wn #3 \s_@@ #4
+\cs_generate_variant:Nn \prop_rand_key_value:N { c }
+\cs_new:Npn \@@_rand_item:w #1 \s_@@ \@@_pair:wn #2 \s_@@ #3
{
- \int_compare:nNnF {#2} > 1
- { \use_i_delimit_by_q_stop:nw { #1 {#3} \exp_not:n {#4} } }
- \exp_after:wN \@@_rand_item:Nw \exp_after:wN #1
- \__int_value:w \int_eval:n { #2 - 1 } \s_@@
+ \int_compare:nNnF {#1} > 1
+ { \use_i_delimit_by_q_stop:nw { \exp_not:n { {#2} {#3} } } }
+ \exp_after:wN \@@_rand_item:w
+ \int_value:w \int_eval:n { #1 - 1 } \s_@@
}
-\cs_generate_variant:Nn \prop_rand_key_value:N { c }
% \end{macrocode}
% \end{macro}
% \end{macro}
@@ -2188,7 +2298,7 @@
% \@@_mapthread_function:Nnnwnn
% }
% The idea is to first expand both sequences, adding the
-% usual |{ ? \__prg_break: } { }| to the end of each one. This is
+% usual |{ ? \prg_break: } { }| to the end of each one. This is
% most conveniently done in two steps using an auxiliary function.
% The mapping then throws away the first tokens of |#2| and |#5|,
% which for items in both sequences are \cs{s_@@}
@@ -2203,13 +2313,13 @@
\cs_new:Npn \@@_mapthread_function:wNN \s_@@ #1 \q_stop #2#3
{
\exp_after:wN \@@_mapthread_function:wNw #2 \q_stop #3
- #1 { ? \__prg_break: } { }
- \__prg_break_point:
+ #1 { ? \prg_break: } { }
+ \prg_break_point:
}
\cs_new:Npn \@@_mapthread_function:wNw \s_@@ #1 \q_stop #2
{
\@@_mapthread_function:Nnnwnn #2
- #1 { ? \__prg_break: } { }
+ #1 { ? \prg_break: } { }
\q_stop
}
\cs_new:Npn \@@_mapthread_function:Nnnwnn #1#2#3#4 \q_stop #5#6
@@ -2227,7 +2337,7 @@
% \begin{macro}{\seq_set_filter:NNn, \seq_gset_filter:NNn}
% \begin{macro}{\@@_set_filter:NNNn}
% Similar to \cs{seq_map_inline:Nn}, without a
-% \cs{__prg_break_point:} because the user's code
+% \cs{prg_break_point:} because the user's code
% is performed within the evaluation of a boolean expression,
% and skipping out of that would break horribly.
% The \cs{@@_wrap_item:n} function inserts the relevant
@@ -2268,6 +2378,34 @@
% \end{macro}
% \end{macro}
%
+% \begin{macro}{\seq_set_from_inline_x:Nnn, \seq_gset_from_inline_x:Nnn}
+% \begin{macro}{\@@_set_from_inline_x:NNnn}
+% Set \cs{@@_item:n} then map it using the loop code.
+% \begin{macrocode}
+\cs_new_protected:Npn \seq_set_from_inline_x:Nnn
+ { \@@_set_from_inline_x:NNnn \tl_set:Nx }
+\cs_new_protected:Npn \seq_gset_from_inline_x:Nnn
+ { \@@_set_from_inline_x:NNnn \tl_gset:Nx }
+\cs_new_protected:Npn \@@_set_from_inline_x:NNnn #1#2#3#4
+ {
+ \@@_push_item_def:n { \exp_not:N \@@_item:n {#4} }
+ #1 #2 { \s_@@ #3 \@@_item:n }
+ \@@_pop_item_def:
+ }
+% \end{macrocode}
+% \end{macro}
+% \end{macro}
+%
+% \begin{macro}{\seq_set_from_function:NnN, \seq_gset_from_function:NnN}
+% Reuse \cs{seq_set_from_inline_x:Nnn}.
+% \begin{macrocode}
+\cs_new_protected:Npn \seq_set_from_function:NnN #1#2#3
+ { \seq_set_from_inline_x:Nnn #1 {#2} { #3 {##1} } }
+\cs_new_protected:Npn \seq_gset_from_function:NnN #1#2#3
+ { \seq_gset_from_inline_x:Nnn #1 {#2} { #3 {##1} } }
+% \end{macrocode}
+% \end{macro}
+%
% \begin{macro}{\seq_rand_item:N, \seq_rand_item:c}
% Importantly, \cs{seq_item:Nn} only evaluates its argument once.
% \begin{macrocode}
@@ -2292,6 +2430,70 @@
% \end{macrocode}
% \end{macro}
%
+% \begin{macro}{\seq_shuffle:N, \seq_gshuffle:N, \@@_shuffle:NN, \@@_shuffle_item:n}
+% \begin{variable}{\g_@@_internal_seq, \l_@@_internal_a_int, \l_@@_internal_b_int}
+% We apply the Fisher–Yates shuffle, storing items in \tn{toks}
+% registers. We use the primitive \cs{pdftex_uniformdeviate:D} for
+% speed reasons. Its non-uniformity is of order its argument divided
+% by $2^{28}$, not too bad for small lists. For sequences with more
+% than $13$ elements there are more possible permutations than
+% possible seeds ($13!>2^{28}$) so the question of uniformity is
+% somewhat moot.
+% \begin{macrocode}
+\cs_if_exist:NTF \pdftex_uniformdeviate:D
+ {
+ \int_new:N \l_@@_internal_a_int
+ \int_new:N \l_@@_internal_b_int
+ \seq_new:N \g_@@_internal_seq
+ \cs_new_protected:Npn \seq_shuffle:N { \@@_shuffle:NN \seq_set_eq:NN }
+ \cs_new_protected:Npn \seq_gshuffle:N { \@@_shuffle:NN \seq_gset_eq:NN }
+ \cs_new_protected:Npn \@@_shuffle:NN #1#2
+ {
+ \int_compare:nNnTF { \seq_count:N #2 } > \c_max_register_int
+ {
+ \__kernel_msg_error:nnx { kernel } { shuffle-too-large }
+ { \token_to_str:N #2 }
+ }
+ {
+ \group_begin:
+ \cs_set_eq:NN \@@_item:n \@@_shuffle_item:n
+ \int_zero:N \l_@@_internal_a_int
+ #2
+ \seq_gset_from_inline_x:Nnn \g_@@_internal_seq
+ { \int_step_function:nN { \l_@@_internal_a_int } }
+ { \tex_the:D \tex_toks:D ##1 }
+ \group_end:
+ #1 #2 \g_@@_internal_seq
+ \seq_gclear:N \g_@@_internal_seq
+ }
+ }
+ \cs_new_protected:Npn \@@_shuffle_item:n
+ {
+ \int_incr:N \l_@@_internal_a_int
+ \int_set:Nn \l_@@_internal_b_int
+ { 1 + \pdftex_uniformdeviate:D \l_@@_internal_a_int }
+ \tex_toks:D \l_@@_internal_a_int
+ = \tex_toks:D \l_@@_internal_b_int
+ \tex_toks:D \l_@@_internal_b_int
+ }
+ \__kernel_msg_new:nnnn { kernel } { shuffle-too-large }
+ { The~sequence~#1~is~too~long~to~be~shuffled~by~TeX. }
+ {
+ TeX~has~ \int_eval:n { \c_max_register_int + 1 } ~
+ toks~registers:~this~only~allows~to~shuffle~up~to~
+ \int_use:N \c_max_register_int \ items.~
+ The~list~will~not~be~shuffled.
+ }
+ }
+ {
+ \cs_new_protected:Npn \seq_shuffle:N #1
+ { \__kernel_msg_error:nn { kernel } { fp-no-random } }
+ \cs_new_eq:NN \seq_gshuffle:N \seq_shuffle:N
+ }
+% \end{macrocode}
+% \end{variable}
+% \end{macro}
+%
% \subsection{Additions to \pkg{l3skip}}
%
% \begin{macrocode}
@@ -2329,17 +2531,10 @@
% \end{macrocode}
%
% \begin{macro}[EXP, pTF]{\sys_if_rand_exist:}
-% Currently, randomness exists under \pdfTeX{} and \LuaTeX{}.
+% Currently, randomness exists under \pdfTeX{}, \LuaTeX{}, \pTeX{} and \upTeX{}.
% \begin{macrocode}
-\cs_if_exist:NTF \pdftex_uniformdeviate:D
- {
- \prg_new_conditional:Npnn \sys_if_rand_exist: { p , T , F , TF }
- { \prg_return_true: }
- }
- {
- \prg_new_conditional:Npnn \sys_if_rand_exist: { p , T , F , TF }
- { \prg_return_false: }
- }
+\@@_const:nn { sys_if_rand_exist }
+ { \cs_if_exist_p:N \pdftex_uniformdeviate:D }
% \end{macrocode}
% \end{macro}
%
@@ -2356,7 +2551,7 @@
% The primitive always assigns the seed globally.
% \begin{macrocode}
\cs_new_protected:Npn \sys_gset_rand_seed:n #1
- { \pdftex_setrandomseed:D \__int_eval:n {#1} }
+ { \pdftex_setrandomseed:D \int_eval:n {#1} \exp_stop_f: }
% \end{macrocode}
% \end{macro}
%
@@ -2368,9 +2563,7 @@
\sys_if_engine_luatex:TF
{
\luatex_directlua:D
- {
- tex.sprint((status.shell_escape~or~os.execute()) .. " ")
- }
+ { tex.sprint(status.shell_escape~or~os.execute()) }
}
{
\pdftex_shellescape:D
@@ -2379,52 +2572,18 @@
% \end{macrocode}
% \end{variable}
%
-% \begin{macro}[EXP, pTF]{\sys_if_shell:}
-% Performs a check for whether shell escape is enabled. This
-% returns true if either of restricted or unrestricted shell escape
-% is enabled.
-% \begin{macrocode}
-\prg_new_conditional:Nnn \sys_if_shell: { p , T , F , TF }
- {
- \if_int_compare:w \c_sys_shell_escape_int = 0 ~
- \prg_return_false:
- \else:
- \prg_return_true:
- \fi:
- }
-% \end{macrocode}
-% \end{macro}
-%
-% \begin{macro}[EXP, pTF]{\sys_if_shell_unrestricted:}
-% Performs a check for whether \emph{unrestricted} shell escape is
-% enabled.
-% \begin{macrocode}
-\prg_new_conditional:Nnn \sys_if_shell_unrestricted: { p , T , F , TF }
- {
- \if_int_compare:w \c_sys_shell_escape_int = 1 ~
- \prg_return_true:
- \else:
- \prg_return_false:
- \fi:
- }
-% \end{macrocode}
-% \end{macro}
-%
-% \begin{macro}[EXP, pTF]{\sys_if_shell_restricted:}
-% Performs a check for whether \emph{restricted} shell escape is
-% enabled. This returns false if unrestricted shell escape is
-% enabled. Unrestricted shell escape is not considered a superset
-% of restricted shell escape in this case. To find whether any
-% shell escape is enabled use \cs{sys_if_shell:}.
+% \begin{macro}[EXP, pTF]{\sys_if_shell:, \sys_if_shell_unrestricted:, \sys_if_shell_restricted:}
+% Performs a check for whether shell escape is enabled. The first set
+% of functions returns true if either of restricted or unrestricted
+% shell escape is enabled, while the other two sets of functions
+% return true in only one of these two cases.
% \begin{macrocode}
-\prg_new_conditional:Nnn \sys_if_shell_restricted: { p , T , F , TF }
- {
- \if_int_compare:w \c_sys_shell_escape_int = 2 ~
- \prg_return_true:
- \else:
- \prg_return_false:
- \fi:
- }
+\@@_const:nn { sys_if_shell }
+ { \int_compare_p:nNn \c_sys_shell_escape_int > 0 }
+\@@_const:nn { sys_if_shell_unrestricted }
+ { \int_compare_p:nNn \c_sys_shell_escape_int = 1 }
+\@@_const:nn { sys_if_shell_restricted }
+ { \int_compare_p:nNn \c_sys_shell_escape_int = 2 }
% \end{macrocode}
% \end{macro}
%
@@ -2444,19 +2603,13 @@
{
\cs_new_protected:Npn \sys_shell_now:n #1
{
- \luatex_directlua:D
- {
- os.execute("
- \luatex_luaescapestring:D { \etex_detokenize:D {#1} }
- ")
- }
+ \lua_now_x:n
+ { os.execute(" \lua_escape_x:n { \tl_to_str:n {#1} } ") }
}
}
{
\cs_new_protected:Npn \sys_shell_now:n #1
- {
- \iow_now:Nn \c_@@_shell_stream_int { #1 }
- }
+ { \iow_now:Nn \c_@@_shell_stream_int {#1} }
}
\cs_generate_variant:Nn \sys_shell_now:n { x }
% \end{macrocode}
@@ -2469,19 +2622,13 @@
{
\cs_new_protected:Npn \sys_shell_shipout:n #1
{
- \luatex_latelua:D
- {
- os.execute("
- \luatex_luaescapestring:D { \etex_detokenize:D {#1} }
- ")
- }
+ \lua_shipout_x:n
+ { os.execute(" \lua_escape_x:n { \tl_to_str:n {#1} } ") }
}
}
{
\cs_new_protected:Npn \sys_shell_shipout:n #1
- {
- \iow_shipout:Nn \c_@@_shell_stream_int { #1 }
- }
+ { \iow_shipout:Nn \c_@@_shell_stream_int {#1} }
}
\cs_generate_variant:Nn \sys_shell_shipout:n { x }
% \end{macrocode}
@@ -2521,7 +2668,7 @@
% \begin{macrocode}
\cs_new:Npn \tl_reverse_tokens:n #1
{
- \etex_unexpanded:D \exp_after:wN
+ \__kernel_exp_not:w \exp_after:wN
{
\exp:w
\@@_act:NNNnn
@@ -2605,9 +2752,9 @@
\cs_generate_variant:Nn \tl_gset_from_file:Nnn { c }
\cs_new_protected:Npn \@@_set_from_file:NNnn #1#2#3#4
{
- \file_get_full_name:nN {#4} \l__file_full_name_str
- \str_if_empty:NTF \l__file_full_name_str
- { \__file_missing:n {#4} }
+ \file_get_full_name:nN {#4} \l_@@_file_name_str
+ \str_if_empty:NTF \l_@@_file_name_str
+ { \__kernel_file_missing:n {#4} }
{
\group_begin:
\exp_args:No \etex_everyeof:D
@@ -2615,7 +2762,7 @@
#3 \scan_stop:
\exp_after:wN \@@_from_file_do:w
\exp_after:wN \prg_do_nothing:
- \tex_input:D \l__file_full_name_str \scan_stop:
+ \tex_input:D \l_@@_file_name_str \scan_stop:
\exp_args:NNNo \group_end:
#1 #2 \l_@@_internal_a_tl
}
@@ -2649,15 +2796,15 @@
\cs_generate_variant:Nn \tl_gset_from_file_x:Nnn { c }
\cs_new_protected:Npn \@@_set_from_file_x:NNnn #1#2#3#4
{
- \file_get_full_name:nN {#4} \l__file_full_name_str
- \str_if_empty:NTF \l__file_full_name_str
- { \__file_missing:n {#4} }
+ \file_get_full_name:nN {#4} \l_@@_file_name_str
+ \str_if_empty:NTF \l_@@_file_name_str
+ { \__kernel_file_missing:n {#4} }
{
\group_begin:
\etex_everyeof:D { \exp_not:N }
#3 \scan_stop:
\tl_set:Nx \l_@@_internal_a_tl
- { \tex_input:D \l__file_full_name_str \c_space_token }
+ { \tex_input:D \l_@@_file_name_str \c_space_token }
\exp_args:NNNo \group_end:
#1 #2 \l_@@_internal_a_tl
}
@@ -2665,6 +2812,11 @@
% \end{macrocode}
% \end{macro}
% \end{macro}
+% \begin{variable}{\l_@@_file_name_str}
+% \begin{macrocode}
+\str_new:N \l_@@_file_name_str
+% \end{macrocode}
+% \end{variable}
%
% \subsubsection{Unicode case changing}
%
@@ -2673,6 +2825,119 @@
% appropriate data extracted from the Unicode documentation (either manually
% or automatically).
%
+% First, some code which \enquote{belongs} in \pkg{l3tokens} but has to come
+% here.
+% \begin{macrocode}
+%<@@=char>
+% \end{macrocode}
+%
+% \begin{macro}
+% {
+% \char_lower_case:N, \char_upper_case:N,
+% \char_mixed_case:N, \char_fold_case:N
+% }
+% \begin{macro}{\@@_change_case:nNN}
+% \begin{macro}{\@@_change_case:nN}
+% Expandable character generation is done using a two-part approach.
+% First, see if the current character has a special mapping for the current
+% transformation. If it does, insert that. Otherwise, use the \TeX{} data
+% to look up the one-to-one mapping, and generate the appropriate character
+% with the appropriate category code. Mixed case needs an extra step as it
+% may be special-cased or might be a special upper case outcome. The internal
+% when using non-Unicode engines has to be set up to only do anything
+% with ASCII characters.
+% \begin{macrocode}
+\cs_new:Npn \char_lower_case:N #1
+ { \@@_change_case:nNN { lower } \char_value_lccode:n #1 }
+\cs_new:Npn \char_upper_case:N #1
+ { \@@_change_case:nNN { upper } \char_value_uccode:n #1 }
+\cs_new:Npn \char_mixed_case:N #1
+ {
+ \tl_if_exist:cTF { c_@@_mixed_case_ \token_to_str:N #1 _tl }
+ { \tl_use:c { c_@@_mixed_case_ \token_to_str:N #1 _tl } }
+ { \char_upper_case:N #1 }
+ }
+\cs_new:Npn \char_fold_case:N #1
+ { \@@_change_case:nNN { fold } \char_value_lccode:n #1 }
+\cs_new:Npn \@@_change_case:nNN #1#2#3
+ {
+ \tl_if_exist:cTF { c_@@_ #1 _case_ \token_to_str:N #3 _tl }
+ { \tl_use:c { c_@@_ #1 _case_ \token_to_str:N #3 _tl } }
+ { \exp_args:Nf \@@_change_case:nN { #2 { `#3 } } #3 }
+ }
+\cs_new:Npn \@@_change_case:nN #1#2
+ {
+ \int_compare:nNnTF {#1} = 0
+ {#2}
+ { \char_generate:nn {#1} { \char_value_catcode:n {#1} } }
+ }
+\bool_lazy_or:nnF { \sys_if_engine_luatex_p: } { \sys_if_engine_xetex_p: }
+ {
+ \cs_set_eq:NN \@@_change_case:nN \use_ii:nn
+ }
+% \end{macrocode}
+% \end{macro}
+% \end{macro}
+% \end{macro}
+%
+% \begin{macro}[EXP]{\char_codepoint_to_bytes:n}
+% \begin{macro}[EXP]{\@@_codepoint_to_bytes_auxi:n}
+% \begin{macro}[EXP]{\@@_codepoint_to_bytes_auxii:Nnn}
+% \begin{macro}[EXP]{\@@_codepoint_to_bytes_auxiii:n}
+% This code converts a codepoint into the correct UTF-8 representation.
+% As there are a variable number of octets, the result starts with the
+% numeral |1|--|4| to indicate the nature of the returned value.
+% In terms of the algorithm itself, see
+% \url{https://en.wikipedia.org/wiki/UTF-8} for the octet pattern.
+% \begin{macrocode}
+\cs_new:Npn \char_codepoint_to_bytes:n #1
+ {
+ \exp_args:Nf \@@_codepoint_to_bytes_auxi:n
+ { \int_eval:n {#1} }
+ }
+\cs_new:Npn \@@_codepoint_to_bytes_auxi:n #1
+ {
+ \if_int_compare:w #1 > "80 \exp_stop_f:
+ \if_int_compare:w #1 < "800 \exp_stop_f:
+ 2
+ \@@_codepoint_to_bytes_auxii:Nnn C {#1} { 64 }
+ \@@_codepoint_to_bytes_auxiii:n {#1}
+ \else:
+ \if_int_compare:w #1 < "10000 \exp_stop_f:
+ 3
+ \@@_codepoint_to_bytes_auxii:Nnn E {#1} { 64 * 64 }
+ \@@_codepoint_to_bytes_auxiii:n
+ { \int_div_truncate:nn {#1} { 64 } }
+ \@@_codepoint_to_bytes_auxiii:n {#1}
+ \else:
+ 4
+ \@@_codepoint_to_bytes_auxii:Nnn F
+ {#1} { 64 * 64 * 64 }
+ \@@_codepoint_to_bytes_auxiii:n
+ { \int_div_truncate:nn {#1} { 64 * 64 } }
+ \@@_codepoint_to_bytes_auxiii:n
+ { \int_div_truncate:nn {#1} { 64 } }
+ \@@_codepoint_to_bytes_auxiii:n {#1}
+ \fi:
+ \fi:
+ \else:
+ 1 {#1}
+ \fi:
+ }
+\cs_new:Npn \@@_codepoint_to_bytes_auxii:Nnn #1#2#3
+ { { \int_eval:n { "#10 + \int_div_truncate:nn {#2} {#3} } } }
+\cs_new:Npn \@@_codepoint_to_bytes_auxiii:n #1
+ { { \int_eval:n { \int_mod:nn {#1} { 64 } + 128 } } }
+% \end{macrocode}
+% \end{macro}
+% \end{macro}
+% \end{macro}
+% \end{macro}
+%
+% \begin{macrocode}
+%<@@=tl>
+% \end{macrocode}
+%
% \begin{macro}[EXP, documented-as=\tl_if_head_eq_catcode:nNTF]
% {\tl_if_head_eq_catcode:oNTF}
% Extra variants.
@@ -2731,16 +2996,6 @@
% \@@_change_case_char_mixed:Nnn
% }
% \begin{macro}[EXP]{\@@_change_case_char:nN}
-% \begin{macro}[EXP]
-% {\@@_change_case_char_auxi:nN, \@@_change_case_char_auxii:nN}
-% \begin{macro}[EXP]
-% {
-% \@@_change_case_char_mixed:N,
-% \@@_change_case_char_lower:N,
-% \@@_change_case_char_upper:N
-% }
-% \begin{macro}
-% {\@@_lookup_mixed:N, \@@_lookup_lower:N, \@@_lookup_upper:N}
% \begin{macro}[EXP]{\@@_change_case_char_UTFviii:nNN}
% \begin{macro}[EXP]{\@@_change_case_char_UTFviii:nNNN}
% \begin{macro}[EXP]{\@@_change_case_char_UTFviii:nNNNN}
@@ -2769,7 +3024,7 @@
% \begin{macrocode}
\cs_new:Npn \@@_change_case:nnn #1#2#3
{
- \etex_unexpanded:D \exp_after:wN
+ \__kernel_exp_not:w \exp_after:wN
{
\exp:w
\@@_change_case_aux:nnn {#1} {#2} {#3}
@@ -3005,10 +3260,15 @@
% Unicode character, which is then used in a lookup. (As will become
% obvious below, there is no intention here of covering all of Unicode.)
% \begin{macrocode}
-\cs_if_exist:NTF \utex_char:D
+\bool_lazy_or:nnTF
+ { \sys_if_engine_luatex_p: }
+ { \sys_if_engine_xetex_p: }
{
\cs_new:Npn \@@_change_case_char:nN #1#2
- { \@@_change_case_char_auxi:nN {#1} #2 }
+ {
+ \@@_change_case_output:fwn
+ { \use:c { char_ #1 _case:N } #2 }
+ }
}
{
\cs_new:Npn \@@_change_case_char:nN #1#2
@@ -3023,58 +3283,20 @@
{ \@@_change_case_char_UTFviii:nNNNNN {#1} #2 }
}
}
- { \@@_change_case_char_auxi:nN {#1} #2 }
+ {
+ \@@_change_case_output:fwn
+ { \use:c { char_ #1 _case:N } #2 }
+ }
}
}
% \end{macrocode}
% To allow for the special case of mixed case, we insert here a
% action-dependent auxiliary.
% \begin{macrocode}
-\cs_new:Npn \@@_change_case_char_auxi:nN #1#2
- { \use:c { @@_change_case_char_ #1 :N } #2 }
-\cs_new:Npn \@@_change_case_char_lower:N #1
- {
- \@@_change_case_output:fwn
- {
- \cs_if_exist_use:cF { c__unicode_lower_ \token_to_str:N #1 _tl }
- { \@@_change_case_char_auxii:nN { lower } #1 }
- }
- }
-\cs_new:Npn \@@_change_case_char_upper:N #1
- {
- \@@_change_case_output:fwn
- {
- \cs_if_exist_use:cF { c__unicode_upper_ \token_to_str:N #1 _tl }
- { \@@_change_case_char_auxii:nN { upper } #1 }
- }
- }
-\cs_new:Npn \@@_change_case_char_mixed:N #1
- {
- \cs_if_exist:cTF { c__unicode_mixed_ \token_to_str:N #1 _tl }
- {
- \@@_change_case_output:fwn
- { \tl_use:c { c__unicode_mixed_ \token_to_str:N #1 _tl } }
- }
- { \@@_change_case_char_upper:N #1 }
- }
-\cs_if_exist:NTF \utex_char:D
- {
- \cs_new:Npn \@@_change_case_char_auxii:nN #1#2
- {
- \int_compare:nNnTF { \use:c { @@_lookup_ #1 :N } #2 } = { 0 }
- { \exp_stop_f: #2 }
- {
- \char_generate:nn
- { \use:c { @@_lookup_ #1 :N } #2 }
- { \char_value_catcode:n { \use:c { @@_lookup_ #1 :N } #2 } }
- }
- }
- \cs_new_protected:Npn \@@_lookup_lower:N #1 { \tex_lccode:D `#1 }
- \cs_new_protected:Npn \@@_lookup_upper:N #1 { \tex_uccode:D `#1 }
- \cs_new_eq:NN \@@_lookup_mixed:N \@@_lookup_upper:N
- }
+\bool_lazy_or:nnF
+ { \sys_if_engine_luatex_p: }
+ { \sys_if_engine_xetex_p: }
{
- \cs_new:Npn \@@_change_case_char_auxii:nN #1#2 { \exp_stop_f: #2 }
\cs_new:Npn \@@_change_case_char_UTFviii:nNNN #1#2#3#4
{ \@@_change_case_char_UTFviii:nnN {#1} {#2#4} #3 }
\cs_new:Npn \@@_change_case_char_UTFviii:nNNNN #1#2#3#4#5
@@ -3083,10 +3305,10 @@
{ \@@_change_case_char_UTFviii:nnN {#1} {#2#4#5#6} #3 }
\cs_new:Npn \@@_change_case_char_UTFviii:nnN #1#2#3
{
- \cs_if_exist:cTF { c__unicode_ #1 _ \tl_to_str:n {#2} _tl }
+ \cs_if_exist:cTF { c_@@_ #1 _case_ \tl_to_str:n {#2} _tl }
{
\@@_change_case_output:vwn
- { c__unicode_ #1 _ \tl_to_str:n {#2} _tl }
+ { c_@@_ #1 _case_ \tl_to_str:n {#2} _tl }
}
{ \@@_change_case_output:nwn {#2} }
#3
@@ -3294,9 +3516,6 @@
% \end{macro}
% \end{macro}
% \end{macro}
-% \end{macro}
-% \end{macro}
-% \end{macro}
%
% \begin{macro}[EXP]{\@@_change_case_lower_sigma:Nnw}
% \begin{macro}[EXP]{\@@_change_case_lower_sigma:w}
@@ -3320,7 +3539,7 @@
{
\tl_if_head_is_N_type:nTF {#1}
{ \@@_change_case_lower_sigma:Nw #1 \q_recursion_stop }
- { \c__unicode_final_sigma_tl }
+ { \c_@@_final_sigma_tl }
}
\cs_new:Npn \@@_change_case_lower_sigma:Nw #1#2 \q_recursion_stop
{
@@ -3331,8 +3550,8 @@
}
{
\token_if_letter:NTF #1
- { \c__unicode_std_sigma_tl }
- { \c__unicode_final_sigma_tl }
+ { \c_@@_std_sigma_tl }
+ { \c_@@_final_sigma_tl }
}
}
% \end{macrocode}
@@ -3356,7 +3575,9 @@
% either a dotless-I or a dotted-I. In the latter case the mapping is
% easy, but in the former there is a second stage search.
% \begin{macrocode}
-\cs_if_exist:NTF \utex_char:D
+\bool_lazy_or:nnTF
+ { \sys_if_engine_luatex_p: }
+ { \sys_if_engine_xetex_p: }
{
\cs_new:Npn \@@_change_case_lower_tr:Nnw #1#2
{
@@ -3380,7 +3601,7 @@
{
\tl_if_head_is_N_type:nTF {#2}
{ \@@_change_case_lower_tr_auxii:Nw #2 \q_recursion_stop }
- { \@@_change_case_output:Vwn \c__unicode_dotless_i_tl }
+ { \@@_change_case_output:Vwn \c_@@_dotless_i_tl }
#1 #2 \q_recursion_stop
}
\cs_new:Npn \@@_change_case_lower_tr_auxii:Nw #1#2 \q_recursion_stop
@@ -3394,7 +3615,7 @@
\bool_lazy_or:nnTF
{ \token_if_cs_p:N #1 }
{ ! \int_compare_p:nNn { `#1 } = { "0307 } }
- { \@@_change_case_output:Vwn \c__unicode_dotless_i_tl }
+ { \@@_change_case_output:Vwn \c_@@_dotless_i_tl }
{
\@@_change_case_output:nwn { i }
\use_i:nn
@@ -3412,7 +3633,7 @@
\cs_new:Npn \@@_change_case_lower_tr:Nnw #1#2
{
\int_compare:nNnTF { `#1 } = { "0049 }
- { \@@_change_case_output:Vwn \c__unicode_dotless_i_tl }
+ { \@@_change_case_output:Vwn \c_@@_dotless_i_tl }
{
\int_compare:nNnTF { `#1 } = { 196 }
{ \@@_change_case_lower_tr_auxi:Nw #1 {#2} }
@@ -3438,7 +3659,7 @@
\cs_new:Npn \@@_change_case_upper_tr:Nnw #1#2
{
\int_compare:nNnTF { `#1 } = { "0069 }
- { \@@_change_case_output:Vwn \c__unicode_dotted_I_tl }
+ { \@@_change_case_output:Vwn \c_@@_dotted_I_tl }
{#2}
}
% \end{macrocode}
@@ -3476,7 +3697,7 @@
\cs_new:Npn \@@_change_case_lower_lt:Nnw #1
{
\exp_args:Nf \@@_change_case_lower_lt:nNnw
- { \str_case:nVF #1 \c__unicode_accents_lt_tl \exp_stop_f: }
+ { \str_case:nVF #1 \c_@@_accents_lt_tl \exp_stop_f: }
#1
}
\cs_new:Npn \@@_change_case_lower_lt:nNnw #1#2
@@ -3489,7 +3710,7 @@
{
{ "0049 } i
{ "004A } j
- { "012E } \c__unicode_i_ogonek_tl
+ { "012E } \c_@@_i_ogonek_tl
}
\exp_stop_f:
}
@@ -3536,7 +3757,7 @@
{ \int_compare_p:nNn { `#2 } = { "0303 } }
}
}
- { \@@_change_case_output:Vwn \c__unicode_dot_above_tl }
+ { \@@_change_case_output:Vwn \c_@@_dot_above_tl }
#1 #2#3 \q_recursion_stop
}
}
@@ -3553,7 +3774,7 @@
{
{ "0069 } I
{ "006A } J
- { "012F } \c__unicode_I_ogonek_tl
+ { "012F } \c_@@_I_ogonek_tl
}
\exp_stop_f:
}
@@ -3606,122 +3827,87 @@
\cs_new:cpn { @@_change_case_upper_de-alt:Nnw } #1#2
{
\int_compare:nNnTF { `#1 } = { 223 }
- { \@@_change_case_output:Vwn \c__unicode_upper_Eszett_tl }
+ { \@@_change_case_output:Vwn \c_@@_upper_Eszett_tl }
{#2}
}
% \end{macrocode}
% \end{macro}
%
-% \begin{macro}[EXP]{\__unicode_codepoint_to_UTFviii:n}
-% \begin{macro}[EXP]{\__unicode_codepoint_to_UTFviii_auxi:n}
-% \begin{macro}[EXP]{\__unicode_codepoint_to_UTFviii_auxii:Nnn}
-% \begin{macro}[EXP]{\__unicode_codepoint_to_UTFviii_auxiii:n}
-% This code converts a codepoint into the correct UTF-8 representation.
-% As there are a variable number of octets, the result starts with the
-% numeral |1|--|4| to indicate the nature of the returned value. Note that
-% this code covers the full range even though at this stage it is not
-% required here. Also note that longer-term this is likely to need a public
-% interface and/or moving to \pkg{l3str} (see experimental string
-% conversions). In terms of the algorithm itself, see
-% \url{https://en.wikipedia.org/wiki/UTF-8} for the octet pattern.
-% \begin{macrocode}
-\cs_new:Npn \__unicode_codepoint_to_UTFviii:n #1
- {
- \exp_args:Nf \__unicode_codepoint_to_UTFviii_auxi:n
- { \int_eval:n {#1} }
- }
-\cs_new:Npn \__unicode_codepoint_to_UTFviii_auxi:n #1
- {
- \if_int_compare:w #1 > "80 ~
- \if_int_compare:w #1 < "800 ~
- 2
- \__unicode_codepoint_to_UTFviii_auxii:Nnn C {#1} { 64 }
- \__unicode_codepoint_to_UTFviii_auxiii:n {#1}
- \else:
- \if_int_compare:w #1 < "10000 ~
- 3
- \__unicode_codepoint_to_UTFviii_auxii:Nnn E {#1} { 64 * 64 }
- \__unicode_codepoint_to_UTFviii_auxiii:n {#1}
- \__unicode_codepoint_to_UTFviii_auxiii:n
- { \int_div_truncate:nn {#1} { 64 } }
- \else:
- 4
- \__unicode_codepoint_to_UTFviii_auxii:Nnn F
- {#1} { 64 * 64 * 64 }
- \__unicode_codepoint_to_UTFviii_auxiii:n
- { \int_div_truncate:nn {#1} { 64 * 64 } }
- \__unicode_codepoint_to_UTFviii_auxiii:n
- { \int_div_truncate:nn {#1} { 64 } }
- \__unicode_codepoint_to_UTFviii_auxiii:n {#1}
-
- \fi:
- \fi:
- \else:
- 1 {#1}
- \fi:
- }
-\cs_new:Npn \__unicode_codepoint_to_UTFviii_auxii:Nnn #1#2#3
- { { \int_eval:n { "#10 + \int_div_truncate:nn {#2} {#3} } } }
-\cs_new:Npn \__unicode_codepoint_to_UTFviii_auxiii:n #1
- { { \int_eval:n { \int_mod:nn {#1} { 64 } + 128 } } }
-% \end{macrocode}
-% \end{macro}
-% \end{macro}
-% \end{macro}
-% \end{macro}
-%
% \begin{variable}
% {
-% \c__unicode_std_sigma_tl ,
-% \c__unicode_final_sigma_tl ,
-% \c__unicode_accents_lt_tl ,
-% \c__unicode_dot_above_tl ,
-% \c__unicode_upper_Eszett_tl
+% \c_@@_std_sigma_tl ,
+% \c_@@_final_sigma_tl ,
+% \c_@@_accents_lt_tl ,
+% \c_@@_dot_above_tl ,
+% \c_@@_upper_Eszett_tl
% }
-% The above needs various special token lists containg pre-formed characters.
+% The above needs various special token lists containing pre-formed characters.
% This set are only available in Unicode engines, with no-op definitions
% for $8$-bit use.
% \begin{macrocode}
-\cs_if_exist:NTF \utex_char:D
- {
- \tl_const:Nx \c__unicode_std_sigma_tl { \utex_char:D "03C3 ~ }
- \tl_const:Nx \c__unicode_final_sigma_tl { \utex_char:D "03C2 ~ }
- \tl_const:Nx \c__unicode_accents_lt_tl
- {
- \utex_char:D "00CC ~
- { \utex_char:D "0069 ~ \utex_char:D "0307 ~ \utex_char:D "0300 ~ }
- \utex_char:D "00CD ~
- { \utex_char:D "0069 ~ \utex_char:D "0307 ~ \utex_char:D "0301 ~ }
- \utex_char:D "0128 ~
- { \utex_char:D "0069 ~ \utex_char:D "0307 ~ \utex_char:D "0303 ~ }
- }
- \tl_const:Nx \c__unicode_dot_above_tl { \utex_char:D "0307 ~ }
- \tl_const:Nx \c__unicode_upper_Eszett_tl { \utex_char:D "1E9E ~ }
+\bool_lazy_or:nnTF
+ { \sys_if_engine_luatex_p: }
+ { \sys_if_engine_xetex_p: }
+ {
+ \group_begin:
+ \cs_set:Npn \@@_tmp:n #1
+ { \char_generate:nn {#1} { \char_value_catcode:n {#1} } }
+ \tl_const:Nx \c_@@_std_sigma_tl { \@@_tmp:n { "03C3 } }
+ \tl_const:Nx \c_@@_final_sigma_tl { \@@_tmp:n { "03C2 } }
+ \tl_const:Nx \c_@@_accents_lt_tl
+ {
+ \@@_tmp:n { "00CC }
+ {
+ \@@_tmp:n { "0069 }
+ \@@_tmp:n { "0307 }
+ \@@_tmp:n { "0300 }
+ }
+ \@@_tmp:n { "00CD }
+ {
+ \@@_tmp:n { "0069 }
+ \@@_tmp:n { "0307 }
+ \@@_tmp:n { "0301 }
+ }
+ \@@_tmp:n { "0128 }
+ {
+ \@@_tmp:n { "0069 }
+ \@@_tmp:n { "0307 }
+ \@@_tmp:n { "0303 }
+ }
+ }
+ \tl_const:Nx \c_@@_dot_above_tl { \@@_tmp:n { "0307 } }
+ \tl_const:Nx \c_@@_upper_Eszett_tl { \@@_tmp:n { "1E9E } }
+ \group_end:
}
{
- \tl_const:Nn \c__unicode_std_sigma_tl { }
- \tl_const:Nn \c__unicode_final_sigma_tl { }
- \tl_const:Nn \c__unicode_accents_lt_tl { }
- \tl_const:Nn \c__unicode_dot_above_tl { }
- \tl_const:Nn \c__unicode_upper_Eszett_tl { }
+ \tl_const:Nn \c_@@_std_sigma_tl { }
+ \tl_const:Nn \c_@@_final_sigma_tl { }
+ \tl_const:Nn \c_@@_accents_lt_tl { }
+ \tl_const:Nn \c_@@_dot_above_tl { }
+ \tl_const:Nn \c_@@_upper_Eszett_tl { }
}
% \end{macrocode}
% \end{variable}
% \begin{variable}
% {
-% \c__unicode_dotless_i_tl ,
-% \c__unicode_dotted_I_tl ,
-% \c__unicode_i_ogonek_tl ,
-% \c__unicode_I_ogonek_tl ,
+% \c_@@_dotless_i_tl ,
+% \c_@@_dotted_I_tl ,
+% \c_@@_i_ogonek_tl ,
+% \c_@@_I_ogonek_tl ,
% }
% For cases where there is an $8$-bit option in the |T1| font set up,
% a variant is provided in both cases.
% \begin{macrocode}
\group_begin:
- \cs_if_exist:NTF \utex_char:D
+ \bool_lazy_or:nnTF
+ { \sys_if_engine_luatex_p: }
+ { \sys_if_engine_xetex_p: }
{
\cs_set_protected:Npn \@@_tmp:w #1#2
- { \tl_const:Nx #1 { \utex_char:D "#2 ~ } }
+ {
+ \tl_const:Nx #1
+ { \char_generate:nn {"#2} { \char_value_catcode:n {"#2} } }
+ }
}
{
\cs_set_protected:Npn \@@_tmp:w #1#2
@@ -3732,21 +3918,21 @@
\tl_const:Nx #1
{
\exp_after:wN \exp_after:wN \exp_after:wN
- \exp_not:N \__char_generate:nn {##2} { 13 }
+ \exp_not:N \char_generate:nn {##2} { 13 }
\exp_after:wN \exp_after:wN \exp_after:wN
- \exp_not:N \__char_generate:nn {##3} { 13 }
+ \exp_not:N \char_generate:nn {##3} { 13 }
}
}
\tl_set:Nx \l_@@_internal_a_tl
- { \__unicode_codepoint_to_UTFviii:n {"#2} }
+ { \char_codepoint_to_bytes:n {"#2} }
\exp_after:wN \@@_tmp:w \l_@@_internal_a_tl
\group_end:
}
}
- \@@_tmp:w \c__unicode_dotless_i_tl { 0131 }
- \@@_tmp:w \c__unicode_dotted_I_tl { 0130 }
- \@@_tmp:w \c__unicode_i_ogonek_tl { 012F }
- \@@_tmp:w \c__unicode_I_ogonek_tl { 012E }
+ \@@_tmp:w \c_@@_dotless_i_tl { 0131 }
+ \@@_tmp:w \c_@@_dotted_I_tl { 0130 }
+ \@@_tmp:w \c_@@_i_ogonek_tl { 012F }
+ \@@_tmp:w \c_@@_I_ogonek_tl { 012E }
\group_end:
% \end{macrocode}
% \end{variable}
@@ -3767,8 +3953,8 @@
\quark_if_recursion_tail_stop:n {#1}
\tl_set:Nx \l_@@_internal_a_tl
{
- \__unicode_codepoint_to_UTFviii:n {"#1}
- \__unicode_codepoint_to_UTFviii:n {"#2}
+ \char_codepoint_to_bytes:n {"#1}
+ \char_codepoint_to_bytes:n {"#2}
}
\exp_after:wN \@@_tmp:w \l_@@_internal_a_tl
\@@_loop:nn
@@ -3777,29 +3963,29 @@
{
\tl_const:cx
{
- c__unicode_lower_
+ c_@@_lower_case_
\char_generate:nn {#2} { 12 }
\char_generate:nn {#3} { 12 }
_tl
}
{
\exp_after:wN \exp_after:wN \exp_after:wN
- \exp_not:N \__char_generate:nn {#5} { 13 }
+ \exp_not:N \char_generate:nn {#5} { 13 }
\exp_after:wN \exp_after:wN \exp_after:wN
- \exp_not:N \__char_generate:nn {#6} { 13 }
+ \exp_not:N \char_generate:nn {#6} { 13 }
}
\tl_const:cx
{
- c__unicode_upper_
+ c_@@_upper_case_
\char_generate:nn {#5} { 12 }
\char_generate:nn {#6} { 12 }
_tl
}
{
\exp_after:wN \exp_after:wN \exp_after:wN
- \exp_not:N \__char_generate:nn {#2} { 13 }
+ \exp_not:N \char_generate:nn {#2} { 13 }
\exp_after:wN \exp_after:wN \exp_after:wN
- \exp_not:N \__char_generate:nn {#3} { 13 }
+ \exp_not:N \char_generate:nn {#3} { 13 }
}
}
\@@_loop:nn
@@ -3911,7 +4097,7 @@
{
\tl_const:cx
{
- c__unicode_ #3 _
+ c_@@_ #3 _case_
\char_generate:nn {##2} { 12 }
\char_generate:nn {##3} { 12 }
_tl
@@ -3919,7 +4105,7 @@
{#2}
}
\tl_set:Nx \l_@@_internal_a_tl
- { \__unicode_codepoint_to_UTFviii:n { "#1 } }
+ { \char_codepoint_to_bytes:n { "#1 } }
\exp_after:wN \@@_tmp:w \l_@@_internal_a_tl
\group_end:
}
@@ -3936,8 +4122,10 @@
\cs_set_protected:Npn \@@_change_case_setup:NN #1#2
{
\quark_if_recursion_tail_stop:N #1
- \tl_const:cn { c_@@_change_case_lower_ \token_to_str:N #1 _tl } { #2 }
- \tl_const:cn { c_@@_change_case_upper_ \token_to_str:N #2 _tl } { #1 }
+ \tl_const:cn { c_@@_change_case_lower_ \token_to_str:N #1 _tl }
+ { #2 }
+ \tl_const:cn { c_@@_change_case_upper_ \token_to_str:N #2 _tl }
+ { #1 }
\@@_change_case_setup:NN
}
\@@_change_case_setup:NN
@@ -4058,6 +4246,230 @@
% \end{macrocode}
% \end{variable}
%
+% \subsubsection{Building a token list}
+%
+% 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:Npx} if the variable is local,
+% and \cs{cs_gset_nopar:Npx} 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:Npx} 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}
+\__kernel_patch:nnNNpn { \__kernel_chk_var_local:N #1 } { }
+\cs_new_protected:Npn \tl_build_begin:N #1
+ { \@@_build_begin:NN \cs_set_nopar:Npx #1 }
+\__kernel_patch:nnNNpn { \__kernel_chk_var_global:N #1 } { }
+\cs_new_protected:Npn \tl_build_gbegin:N #1
+ { \@@_build_begin:NN \cs_gset_nopar:Npx #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
+% |gbegin| functions should check that |#1'| is empty or undefined,
+% while the |clear| and |gclear| functions ought to empty |#1'|,
+% |#1''| and so on, similar to \cs{tl_build_end:N}. This only affects
+% memory usage.
+% \begin{macrocode}
+\cs_new_eq:NN \tl_build_clear:N \tl_build_begin:N
+\cs_new_eq:NN \tl_build_gclear:N \tl_build_gbegin:N
+% \end{macrocode}
+% \end{macro}
+%
+% \begin{macro}
+% {
+% \tl_build_put_right:Nn, \tl_build_put_right:Nx,
+% \tl_build_gput_right:Nn, \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:Npx} rather than
+% \cs[no-index]{tl_(g)set:Nx} 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}
+\__kernel_patch:nnNNpn { \__kernel_chk_var_local:N #1 } { }
+\cs_new_protected:Npn \tl_build_put_right:Nn #1#2
+ {
+ \cs_set_nopar:Npx #1
+ { \exp_after:wN \exp_not:n \exp_after:wN { \exp:w #1 #2 } }
+ }
+\__kernel_patch:nnNNpn { \__kernel_chk_var_local:N #1 } { }
+\cs_new_protected:Npn \tl_build_put_right:Nx #1#2
+ {
+ \cs_set_nopar:Npx #1
+ { \exp_after:wN \exp_not:n \exp_after:wN { \exp:w #1 } #2 }
+ }
+\__kernel_patch:nnNNpn { \__kernel_chk_var_global:N #1 } { }
+\cs_new_protected:Npn \tl_build_gput_right:Nn #1#2
+ {
+ \cs_gset_nopar:Npx #1
+ { \exp_after:wN \exp_not:n \exp_after:wN { \exp:w #1 #2 } }
+ }
+\__kernel_patch:nnNNpn { \__kernel_chk_var_global:N #1 } { }
+\cs_new_protected:Npn \tl_build_gput_right:Nx #1#2
+ {
+ \cs_gset_nopar:Npx #1
+ { \exp_after:wN \exp_not:n \exp_after:wN { \exp:w #1 } #2 }
+ }
+\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:Nx,
+% \tl_build_gput_left:Nn, \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}
+\__kernel_patch:nnNNpn { \__kernel_chk_var_local:N #1 } { }
+\cs_new_protected:Npn \tl_build_put_left:Nn #1
+ { \@@_build_put_left:NNn \cs_set_nopar:Npx #1 }
+\cs_generate_variant:Nn \tl_build_put_left:Nn { Nx }
+\__kernel_patch:nnNNpn { \__kernel_chk_var_global:N #1 } { }
+\cs_new_protected:Npn \tl_build_gput_left:Nn #1
+ { \@@_build_put_left:NNn \cs_gset_nopar:Npx #1 }
+\cs_generate_variant:Nn \tl_build_gput_left:Nn { 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 \tl_set:Nx }
+\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_sr:N}. The local/global scope is checked by
+% \cs{tl_set:Nx} or \cs{tl_gset:Nx}.
+% \begin{macrocode}
+\cs_new_protected:Npn \tl_build_end:N #1
+ {
+ \@@_build_get:NNN \tl_set:Nx #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 \tl_gset:Nx #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}
+%
% \subsubsection{Other additions to \pkg{l3tl}}
%
% \begin{macro}{\tl_rand_item:n, \tl_rand_item:N, \tl_rand_item:c}
@@ -4121,9 +4533,11 @@
\cs_new:Npn \tl_range_braced:Nnn { \exp_args:No \tl_range_braced:nnn }
\cs_generate_variant:Nn \tl_range_braced:Nnn { c }
\cs_new:Npn \tl_range_braced:nnn { \@@_range:Nnnn \@@_range_braced:w }
-\cs_new:Npn \tl_range_unbraced:Nnn { \exp_args:No \tl_range_unbraced:nnn }
+\cs_new:Npn \tl_range_unbraced:Nnn
+ { \exp_args:No \tl_range_unbraced:nnn }
\cs_generate_variant:Nn \tl_range_unbraced:Nnn { c }
-\cs_new:Npn \tl_range_unbraced:nnn { \@@_range:Nnnn \@@_range_unbraced:w }
+\cs_new:Npn \tl_range_unbraced:nnn
+ { \@@_range:Nnnn \@@_range_unbraced:w }
\cs_new:Npn \@@_range:Nnnn #1#2#3#4
{
\tl_head:f
@@ -4150,14 +4564,14 @@
\exp_after:wN { \exp_after:wN }
\fi:
\exp_after:wN #3
- \__int_value:w \__int_eval:w #2 - #1 \exp_after:wN ;
+ \int_value:w \int_eval:n { #2 - #1 } \exp_after:wN ;
\exp_after:wN { \exp:w \@@_range_skip:w #1 ; { } #4 }
}
\cs_new:Npn \@@_range_skip:w #1 ; #2
{
\if_int_compare:w #1 > 0 \exp_stop_f:
\exp_after:wN \@@_range_skip:w
- \__int_value:w \__int_eval:w #1 - 1 \exp_after:wN ;
+ \int_value:w \int_eval:n { #1 - 1 } \exp_after:wN ;
\else:
\exp_after:wN \exp_end:
\fi:
@@ -4170,7 +4584,7 @@
{
\if_int_compare:w #1 > 1 \exp_stop_f:
\exp_after:wN \@@_range_collect_braced:w
- \__int_value:w \__int_eval:w #1 - 1 \exp_after:wN ;
+ \int_value:w \int_eval:n { #1 - 1 } \exp_after:wN ;
\fi:
{ #2 {#3} }
}
@@ -4178,7 +4592,7 @@
{
\if_int_compare:w #1 > 1 \exp_stop_f:
\exp_after:wN \@@_range_collect_unbraced:w
- \__int_value:w \__int_eval:w #1 - 1 \exp_after:wN ;
+ \int_value:w \int_eval:n { #1 - 1 } \exp_after:wN ;
\fi:
{ #2 #3 }
}
@@ -4258,7 +4672,7 @@
% \subsection{Additions to \pkg{l3token}}
%
% \begin{variable}{\c_catcode_active_space_tl}
-% While \cs{__char_generate:nn} can produce active characters in some
+% While \cs{char_generate:nn} can produce active characters in some
% engines it cannot in general. It would be possible to simply change
% the catcode of space but then the code would need to avoid all
% spaces, making it quite unreadable. Instead we use the primitive
@@ -4335,7 +4749,10 @@
{ \tl_if_empty:nTF {#2} { \@@_true:w } { \@@_false:w } }
}
\cs_new_protected:Npn \peek_N_type:TF
- { \@@_token_generic:NNTF \@@_execute_branches_N_type: \scan_stop: }
+ {
+ \@@_token_generic:NNTF
+ \@@_execute_branches_N_type: \scan_stop:
+ }
\cs_new_protected:Npn \peek_N_type:T
{ \@@_token_generic:NNT \@@_execute_branches_N_type: \scan_stop: }
\cs_new_protected:Npn \peek_N_type:F