summaryrefslogtreecommitdiff
path: root/macros/latex/contrib/l3kernel/l3flag.dtx
diff options
context:
space:
mode:
Diffstat (limited to 'macros/latex/contrib/l3kernel/l3flag.dtx')
-rw-r--r--macros/latex/contrib/l3kernel/l3flag.dtx316
1 files changed, 189 insertions, 127 deletions
diff --git a/macros/latex/contrib/l3kernel/l3flag.dtx b/macros/latex/contrib/l3kernel/l3flag.dtx
index 05768ae069..b0a586d48b 100644
--- a/macros/latex/contrib/l3kernel/l3flag.dtx
+++ b/macros/latex/contrib/l3kernel/l3flag.dtx
@@ -43,7 +43,7 @@
% }^^A
% }
%
-% \date{Released 2024-01-04}
+% \date{Released 2024-01-22}
%
% \maketitle
%
@@ -54,16 +54,13 @@
% cases, booleans or integers should be preferred to flags because they
% are very significantly faster.
%
-% A flag can hold any non-negative value, which we call its
+% A flag can hold any (small) non-negative value, which we call its
% \meta{height}. In expansion-only contexts, a flag can only be
% \enquote{raised}: this increases the \meta{height} by $1$. The \meta{height}
% can also be queried expandably. However, decreasing it, or setting it
% to zero requires non-expandable assignments.
%
-% Flag variables are always local. They are referenced by a \meta{flag
-% name} such as \texttt{fp_overflow}. The \meta{flag name} is used as
-% part of \cs{use:c} constructions hence is expanded at point of use.
-% It must expand to character tokens only, with no spaces.
+% Flag variables are always local.
%
% A typical use case of flags would be to keep track of whether an
% exceptional condition has occurred during expandable processing, and
@@ -74,94 +71,111 @@
% error message describing incorrect inputs that were encountered.
%
% Flags should not be used without carefully considering the fact that
-% raising a flag takes a time and memory proportional to its height.
-% Flags should not be used unless unavoidable.
+% raising a flag takes a time and memory proportional to its height and
+% that the memory cannot be reclaimed even if the flag is cleared.
+% Flags should not be used unless it is unavoidable.
+%
+% In earlier versions, flags were referenced by an \texttt{n}-type
+% \meta{flag name} such as \texttt{fp_overflow}, used as part of
+% \cs{use:c} constructions. All of the commands described below have
+% \texttt{n}-type analogues that can still appear in old code, but the
+% \texttt{N}-type commands are to be preferred moving forward. The
+% \texttt{n}-type \meta{flag name} is simply mapped to
+% \cs[no-index]{l_\meta{flag name}_flag}, which makes it easier for
+% packages using public flags (such as \pkg{l3fp}) to retain backwards
+% compatibility.
%
% \section{Setting up flags}
%
-% \begin{function}{\flag_new:n}
+% \begin{function}[added = 2024-01-12]{\flag_new:N, \flag_new:c}
% \begin{syntax}
-% \cs{flag_new:n} \Arg{flag name}
+% \cs{flag_new:N} \meta{flag~var}
% \end{syntax}
-% Creates a new flag with a name given by \meta{flag name}, or raises
-% an error if the name is already taken. The \meta{flag name} may not
-% contain spaces. The declaration is global, but flags are always
-% local variables. The \meta{flag} initially has zero height.
+% Creates a new \meta{flag~var}, or raises an error if the name is
+% already taken. The declaration is global, but flags are always local
+% variables. The \meta{flag~var} initially has zero height.
% \end{function}
%
-% \begin{function}{\flag_clear:n}
+% \begin{function}[added = 2024-01-12]{\flag_clear:N, \flag_clear:c}
% \begin{syntax}
-% \cs{flag_clear:n} \Arg{flag name}
+% \cs{flag_clear:N} \meta{flag~var}
% \end{syntax}
-% The \meta{flag}'s height is set to zero. The assignment is local.
+% Sets the height of the \meta{flag~var} to zero. The assignment is local.
% \end{function}
%
-% \begin{function}{\flag_clear_new:n}
+% \begin{function}[added = 2024-01-12]{\flag_clear_new:N, \flag_clear_new:c}
% \begin{syntax}
-% \cs{flag_clear_new:n} \Arg{flag name}
+% \cs{flag_clear_new:N} \meta{flag~var}
% \end{syntax}
-% Ensures that the \meta{flag} exists globally by applying
-% \cs{flag_new:n} if necessary, then applies \cs{flag_clear:n}, setting
+% Ensures that the \meta{flag~var} exists globally by applying
+% \cs{flag_new:N} if necessary, then applies \cs{flag_clear:N}, setting
% the height to zero locally.
% \end{function}
%
-% \begin{function}{\flag_show:n}
+% \begin{function}[added = 2024-01-12]{\flag_show:N, \flag_show:c}
% \begin{syntax}
-% \cs{flag_show:n} \Arg{flag name}
+% \cs{flag_show:N} \meta{flag~var}
% \end{syntax}
-% Displays the \meta{flag}'s height in the terminal.
+% Displays the height of the \meta{flag~var} in the terminal.
% \end{function}
%
-% \begin{function}{\flag_log:n}
+% \begin{function}[added = 2024-01-12]{\flag_log:N, \flag_log:c}
% \begin{syntax}
-% \cs{flag_log:n} \Arg{flag name}
+% \cs{flag_log:N} \meta{flag~var}
% \end{syntax}
-% Writes the \meta{flag}'s height to the log file.
+% Writes the height of the \meta{flag~var} in the log file.
% \end{function}
%
% \section{Expandable flag commands}
%
-% \begin{function}[EXP,pTF]{\flag_if_exist:n}
+% \begin{function}[EXP, pTF, added = 2024-01-12]{\flag_if_exist:N, \flag_if_exist:c}
% \begin{syntax}
-% \cs{flag_if_exist_p:n} \Arg{flag name}
-% \cs{flag_if_exist:nTF} \Arg{flag name} \Arg{true code} \Arg{false code}
+% \cs{flag_if_exist_p:N} \meta{flag~var}
+% \cs{flag_if_exist:NTF} \meta{flag~var} \Arg{true code} \Arg{false code}
% \end{syntax}
-% This function returns \texttt{true} if the \meta{flag name}
-% references a flag that has been defined previously, and
-% \texttt{false} otherwise.
+% This function returns \texttt{true} if the \meta{flag~var} is
+% currently defined, and \texttt{false} otherwise. This does not check
+% that the \meta{flag~var} really is a flag variable.
% \end{function}
%
-% \begin{function}[EXP,pTF]{\flag_if_raised:n}
+% \begin{function}[EXP, pTF, added = 2024-01-12]{\flag_if_raised:N, \flag_if_raised:c}
% \begin{syntax}
-% \cs{flag_if_raised_p:n} \Arg{flag name}
-% \cs{flag_if_raised:nTF} \Arg{flag name} \Arg{true code} \Arg{false code}
+% \cs{flag_if_raised_p:N} \meta{flag~var}
+% \cs{flag_if_raised:NTF} \meta{flag~var} \Arg{true code} \Arg{false code}
% \end{syntax}
-% This function returns \texttt{true} if the \meta{flag} has non-zero
-% height, and \texttt{false} if the \meta{flag} has zero height.
+% This function returns \texttt{true} if the \meta{flag~var} has non-zero
+% height, and \texttt{false} if the \meta{flag~var} has zero height.
% \end{function}
%
-% \begin{function}[EXP]{\flag_height:n}
+% \begin{function}[EXP, added = 2024-01-12]{\flag_height:N, \flag_height:c}
% \begin{syntax}
-% \cs{flag_height:n} \Arg{flag name}
+% \cs{flag_height:N} \meta{flag~var}
% \end{syntax}
-% Expands to the height of the \meta{flag} as an integer denotation.
+% Expands to the height of the \meta{flag~var} as an integer denotation.
% \end{function}
%
-% \begin{function}[EXP]{\flag_raise:n}
+% \begin{function}[EXP, added = 2024-01-12]{\flag_raise:N, \flag_raise:c}
% \begin{syntax}
-% \cs{flag_raise:n} \Arg{flag name}
+% \cs{flag_raise:N} \meta{flag~var}
% \end{syntax}
-% The \meta{flag}'s height is increased by $1$ locally.
+% The height of \meta{flag~var} is increased by $1$ locally.
% \end{function}
%
-% \begin{function}[EXP, added = 2023-04-25]{\flag_ensure_raised:n}
+% \begin{function}[EXP, added = 2024-01-12]{\flag_ensure_raised:N, \flag_ensure_raised:c}
% \begin{syntax}
-% \cs{flag_ensure_raised:n} \Arg{flag name}
+% \cs{flag_ensure_raised:N} \meta{flag~var}
% \end{syntax}
-% Ensures the \meta{flag} is raised by making its height at least~$1$,
+% Ensures the \meta{flag~var} is raised by making its height at least~$1$,
% locally.
% \end{function}
%
+% \begin{variable}[added = 2024-01-12]{\l_tmpa_flag, \l_tmpb_flag}
+% Scratch flag for local assignment. These are never used by
+% the kernel code, and so are safe for use with any \LaTeX3-defined
+% function. However, they may be overwritten by other non-kernel
+% code and so should only be used for short-term storage.
+% \end{variable}
+%
% \end{documentation}
%
% \begin{implementation}
@@ -178,149 +192,197 @@
%
% \TestFiles{m3flag001}
%
-% \subsection{Non-expandable flag commands}
+% \subsection{Protected flag commands}
%
-% The height $h$ of a flag (initially zero) is stored by setting control
-% sequences of the form \cs[no-index]{flag \meta{name} \meta{integer}}
-% to \tn{relax} for $0\leq\meta{integer}<h$. When a flag is raised, a
-% \enquote{trap} function \cs[no-index]{flag \meta{name}} is called.
-% The existence of this function is also used to test for the existence
-% of a flag.
+% The height $h$ of a flag (which is initially zero) is stored by
+% setting control sequences of the form \cs[no-index]{\meta{flag
+% name}\meta{integer}} to \tn{relax} for $0\leq\meta{integer}<h$. These
+% control sequences are produced by \cs{cs:w} \meta{flag~var}
+% \meta{integer} \cs{cs_end:}, namely the \meta{flag~var} is actually a
+% (protected) macro expanding to its own csname.
%
-% \begin{macro}{\flag_new:n}
-% For each flag, we define a \enquote{trap} function, which by default
-% simply increases the flag by $1$ by letting the appropriate control
-% sequence to \tn{relax}. This can be done expandably!
+% \begin{macro}{\flag_new:N, \flag_new:c}
+% Evaluate the csname of~|#1| for use in constructing the various
+% indexed macros.
% \begin{macrocode}
-\cs_new_protected:Npn \flag_new:n #1
- {
- \cs_new:cpn { flag~#1 } ##1 ;
- { \exp_after:wN \use_none:n \cs:w flag~#1~##1 \cs_end: }
- }
+\cs_new_protected:Npn \flag_new:N #1
+ { \cs_new_protected:Npe #1 { \cs_to_str:N #1 } }
+\cs_generate_variant:Nn \flag_new:N { c }
% \end{macrocode}
% \end{macro}
%
-% \begin{macro}{\flag_clear:n}
-% \begin{macro}{\@@_clear:wn}
+% \begin{variable}{\l_tmpa_flag, \l_tmpb_flag}
+% Two flag variables for scratch use.
+% \begin{macrocode}
+\flag_new:N \l_tmpa_flag
+\flag_new:N \l_tmpb_flag
+% \end{macrocode}
+% \end{variable}
+%
+% \begin{macro}{\flag_clear:N, \flag_clear:c}
+% \begin{macro}{\@@_clear:wN}
% Undefine control sequences, starting from the |0| flag, upwards,
% until reaching an undefined control sequence. We don't use
% \cs{cs_undefine:c} because that would act globally.
-% When the option \texttt{check-declarations} is used, check for the
-% function defined by \cs{flag_new:n}.
% \begin{macrocode}
-\cs_new_protected:Npn \flag_clear:n #1 { \@@_clear:wn 0 ; {#1} }
-\cs_new_protected:Npn \@@_clear:wn #1 ; #2
+\cs_new_protected:Npn \flag_clear:N #1
{
- \if_cs_exist:w flag~#2~#1 \cs_end:
- \cs_set_eq:cN { flag~#2~#1 } \tex_undefined:D
- \exp_after:wN \@@_clear:wn
- \int_value:w \int_eval:w 1 + #1
- \else:
- \use_i:nnn
+ \@@_clear:wN 0 ; #1
+ \prg_break_point:
+ }
+\cs_generate_variant:Nn \flag_clear:N { c }
+\cs_new_protected:Npn \@@_clear:wN #1 ; #2
+ {
+ \if_cs_exist:w #2 #1 \cs_end: \else:
+ \prg_break:n
\fi:
- ; {#2}
+ \cs_set_eq:cN { #2 #1 } \tex_undefined:D
+ \exp_after:wN \@@_clear:wN
+ \int_value:w \int_eval:w \c_one_int + #1 ; #2
}
% \end{macrocode}
% \end{macro}
% \end{macro}
%
-% \begin{macro}{\flag_clear_new:n}
-% As for other datatypes, clear the \meta{flag} or create a new one,
+% \begin{macro}{\flag_clear_new:N, \flag_clear_new:c}
+% As for other datatypes, clear the \meta{flag~var} or create a new one,
% as appropriate.
% \begin{macrocode}
-\cs_new_protected:Npn \flag_clear_new:n #1
- { \flag_if_exist:nTF {#1} { \flag_clear:n } { \flag_new:n } {#1} }
+\cs_new_protected:Npn \flag_clear_new:N #1
+ { \flag_if_exist:NTF #1 { \flag_clear:N } { \flag_new:N } #1 }
+\cs_generate_variant:Nn \flag_clear_new:N { c }
% \end{macrocode}
% \end{macro}
%
-% \begin{macro}{\flag_show:n, \flag_log:n, \@@_show:Nn}
+% \begin{macro}{\flag_show:N, \flag_show:c, \flag_log:N, \flag_log:c, \@@_show:NN}
% Show the height (terminal or log file) using appropriate \pkg{l3msg}
% auxiliaries.
% \begin{macrocode}
-\cs_new_protected:Npn \flag_show:n { \@@_show:Nn \tl_show:n }
-\cs_new_protected:Npn \flag_log:n { \@@_show:Nn \tl_log:n }
-\cs_new_protected:Npn \@@_show:Nn #1#2
+\cs_new_protected:Npn \flag_show:N { \@@_show:NN \tl_show:n }
+\cs_generate_variant:Nn \flag_show:N { c }
+\cs_new_protected:Npn \flag_log:N { \@@_show:NN \tl_log:n }
+\cs_generate_variant:Nn \flag_log:N { c }
+\cs_new_protected:Npn \@@_show:NN #1#2
{
- \exp_args:Nc \__kernel_chk_defined:NT { flag~#2 }
- {
- \exp_args:Ne #1
- { \tl_to_str:n { flag~#2~height } = \flag_height:n {#2} }
- }
+ \__kernel_chk_defined:NT #2
+ { \exp_args:Ne #1 { \tl_to_str:n { #2 height } = \flag_height:N #2 } }
}
% \end{macrocode}
% \end{macro}
%
% \subsection{Expandable flag commands}
%
-% \begin{macro}[EXP, pTF]{\flag_if_exist:n}
-% A flag exist if the corresponding trap \cs[no-index]{flag \meta{flag
-% name}:n} is defined.
+% \begin{macro}[EXP, pTF]{\flag_if_exist:N, \flag_if_exist:c}
+% Copies of the \texttt{cs} functions defined in \pkg{l3basics}.
% \begin{macrocode}
-\prg_new_conditional:Npnn \flag_if_exist:n #1 { p , T , F , TF }
- {
- \cs_if_exist:cTF { flag~#1 }
- { \prg_return_true: } { \prg_return_false: }
- }
+\prg_new_eq_conditional:NNn \flag_if_exist:N \cs_if_exist:N
+ { TF , T , F , p }
+\prg_new_eq_conditional:NNn \flag_if_exist:c \cs_if_exist:c
+ { TF , T , F , p }
% \end{macrocode}
% \end{macro}
%
-% \begin{macro}[EXP, pTF]{\flag_if_raised:n}
+% \begin{macro}[EXP, pTF]{\flag_if_raised:N, \flag_if_raised:c}
% Test if the flag has a non-zero height, by checking the |0| control sequence.
% \begin{macrocode}
-\prg_new_conditional:Npnn \flag_if_raised:n #1 { p , T , F , TF }
+\prg_new_conditional:Npnn \flag_if_raised:N #1 { p , T , F , TF }
{
- \if_cs_exist:w flag~#1~0 \cs_end:
+ \if_cs_exist:w #1 0 \cs_end:
\prg_return_true:
\else:
\prg_return_false:
\fi:
}
+\prg_generate_conditional_variant:Nnn \flag_if_raised:N
+ { c } { p , T , F , TF }
% \end{macrocode}
% \end{macro}
%
-% \begin{macro}[EXP]{\flag_height:n}
-% \begin{macro}[EXP]{\@@_height_loop:wn, \@@_height_end:wn}
+% \begin{macro}[EXP]{\flag_height:N, \flag_height:c}
+% \begin{macro}[EXP]{\@@_height_loop:wN, \@@_height_end:wN}
% Extract the value of the flag by going through all of the
% control sequences starting from |0|.
% \begin{macrocode}
-\cs_new:Npn \flag_height:n #1 { \@@_height_loop:wn 0; {#1} }
-\cs_new:Npn \@@_height_loop:wn #1 ; #2
+\cs_new:Npn \flag_height:N #1 { \@@_height_loop:wN 0; #1 }
+\cs_new:Npn \@@_height_loop:wN #1 ; #2
{
- \if_cs_exist:w flag~#2~#1 \cs_end:
- \exp_after:wN \@@_height_loop:wn \int_value:w \int_eval:w 1 +
- \else:
- \exp_after:wN \@@_height_end:wn
+ \if_cs_exist:w #2 #1 \cs_end: \else:
+ \exp_after:wN \@@_height_end:wN
\fi:
- #1 ; {#2}
+ \exp_after:wN \@@_height_loop:wN
+ \int_value:w \int_eval:w \c_one_int + #1 ; #2
}
-\cs_new:Npn \@@_height_end:wn #1 ; #2 {#1}
+\cs_new:Npn \@@_height_end:wN #1 + #2 ; #3 {#2}
+\cs_generate_variant:Nn \flag_height:N { c }
% \end{macrocode}
% \end{macro}
% \end{macro}
%
-% \begin{macro}[EXP]{\flag_raise:n}
-% Simply apply the trap to the height, after expanding the latter.
+% \begin{macro}[EXP]{\flag_raise:N, \flag_raise:c}
+% Change the appropriate control sequence to \tn{relax} by expanding a
+% \cs{cs:w} \ldots{} \cs{cs_end:} construction, then pass it to
+% \cs{use_none:n} to avoid leaving anything in the input stream.
% \begin{macrocode}
-\cs_new:Npn \flag_raise:n #1
- {
- \cs:w flag~#1 \exp_after:wN \cs_end:
- \int_value:w \flag_height:n {#1} ;
- }
+\cs_new:Npn \flag_raise:N #1
+ { \exp_after:wN \use_none:n \cs:w #1 \flag_height:N #1 \cs_end: }
+\cs_generate_variant:Nn \flag_raise:N { c }
% \end{macrocode}
% \end{macro}
%
-% \begin{macro}[EXP]{\flag_ensure_raised: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{macro}[EXP]{\flag_ensure_raised:N, \flag_ensure_raised:c}
+% Pass the control sequence with name \meta{flag name}\texttt{0} to
+% \cs{use_none:n}. Constructing the control sequence ensures that it
+% changes from being undefined (if it was so) to being \tn{relax}.
% \begin{macrocode}
-\cs_new:Npn \flag_ensure_raised:n #1
+\cs_new:Npn \flag_ensure_raised:N #1
+ { \exp_after:wN \use_none:n \cs:w #1 0 \cs_end: }
+\cs_generate_variant:Nn \flag_ensure_raised:N { c }
+% \end{macrocode}
+% \end{macro}
+%
+% \subsection{Old \texttt{n}-type flag commands}
+%
+% Here we keep the old flag commands since our policy is to no longer
+% delete deprecated functions. The idea is to simply map \meta{flag
+% name} to \cs[no-index]{l_\meta{flag name}_flag}. When the debugging
+% code is activated, it checks existence of the \texttt{N}-type flag
+% variables that result.
+%
+% \begin{macro}{\flag_new:n, \flag_clear:n, \flag_clear_new:n}
+% \begin{macro}[EXP, pTF]{\flag_if_exist:n, \flag_if_raised:n}
+% \begin{macro}[EXP]{\flag_height:n, \flag_raise:n, \flag_ensure_raised:n}
+% \begin{macrocode}
+\cs_new_protected:Npn \flag_new:n #1 { \flag_new:c { l_#1_flag } }
+\cs_new_protected:Npn \flag_clear:n #1 { \flag_clear:c { l_#1_flag } }
+\cs_new_protected:Npn \flag_clear_new:n #1 { \flag_clear_new:c { l_#1_flag } }
+\cs_new:Npn \flag_if_exist_p:n #1 { \flag_if_exist_p:c { l_#1_flag } }
+\cs_new:Npn \flag_if_exist:nT #1 { \flag_if_exist:cT { l_#1_flag } }
+\cs_new:Npn \flag_if_exist:nF #1 { \flag_if_exist:cF { l_#1_flag } }
+\cs_new:Npn \flag_if_exist:nTF #1 { \flag_if_exist:cTF { l_#1_flag } }
+\cs_new:Npn \flag_if_raised_p:n #1 { \flag_if_raised_p:c { l_#1_flag } }
+\cs_new:Npn \flag_if_raised:nT #1 { \flag_if_raised:cT { l_#1_flag } }
+\cs_new:Npn \flag_if_raised:nF #1 { \flag_if_raised:cF { l_#1_flag } }
+\cs_new:Npn \flag_if_raised:nTF #1 { \flag_if_raised:cTF { l_#1_flag } }
+\cs_new:Npn \flag_height:n #1 { \flag_height:c { l_#1_flag } }
+\cs_new:Npn \flag_raise:n #1 { \flag_raise:c { l_#1_flag } }
+\cs_new:Npn \flag_ensure_raised:n #1 { \flag_ensure_raised:c { l_#1_flag } }
+% \end{macrocode}
+% \end{macro}
+% \end{macro}
+% \end{macro}
+%
+% \begin{macro}{\flag_show:n, \flag_log:n, \@@_show:Nn}
+% To avoid changing the output here we mostly keep the old code.
+% \begin{macrocode}
+\cs_new_protected:Npn \flag_show:n { \@@_show:Nn \tl_show:n }
+\cs_new_protected:Npn \flag_log:n { \@@_show:Nn \tl_log:n }
+\cs_new_protected:Npn \@@_show:Nn #1#2
{
- \if_cs_exist:w flag~#1~0 \cs_end:
- \else:
- \cs:w flag~#1 \cs_end: 0 ;
- \fi:
+ \exp_args:Nc \__kernel_chk_defined:NT { l_#2_flag }
+ {
+ \exp_args:Ne #1
+ { \tl_to_str:n { flag~#2~height } = \flag_height:n {#2} }
+ }
}
% \end{macrocode}
% \end{macro}