diff options
Diffstat (limited to 'Master/texmf-dist/source/latex/l3kernel/l3flag.dtx')
-rw-r--r-- | Master/texmf-dist/source/latex/l3kernel/l3flag.dtx | 316 |
1 files changed, 189 insertions, 127 deletions
diff --git a/Master/texmf-dist/source/latex/l3kernel/l3flag.dtx b/Master/texmf-dist/source/latex/l3kernel/l3flag.dtx index 05768ae069d..b0a586d48ba 100644 --- a/Master/texmf-dist/source/latex/l3kernel/l3flag.dtx +++ b/Master/texmf-dist/source/latex/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} |