summaryrefslogtreecommitdiff
path: root/Master/texmf-dist/source/latex/l3kernel/l3flag.dtx
diff options
context:
space:
mode:
Diffstat (limited to 'Master/texmf-dist/source/latex/l3kernel/l3flag.dtx')
-rw-r--r--Master/texmf-dist/source/latex/l3kernel/l3flag.dtx351
1 files changed, 351 insertions, 0 deletions
diff --git a/Master/texmf-dist/source/latex/l3kernel/l3flag.dtx b/Master/texmf-dist/source/latex/l3kernel/l3flag.dtx
new file mode 100644
index 00000000000..5afe7e646a7
--- /dev/null
+++ b/Master/texmf-dist/source/latex/l3kernel/l3flag.dtx
@@ -0,0 +1,351 @@
+% \iffalse meta-comment
+%
+%% File: l3flag.dtx Copyright (C) 2011-2012,2014-2017 The LaTeX3 Project
+%
+% It may be distributed and/or modified under the conditions of the
+% LaTeX Project Public License (LPPL), either version 1.3c of this
+% license or (at your option) any later version. The latest version
+% of this license is in the file
+%
+% http://www.latex-project.org/lppl.txt
+%
+% This file is part of the "l3kernel bundle" (The Work in LPPL)
+% and all files in that bundle must be distributed together.
+%
+% -----------------------------------------------------------------------
+%
+% The development version of the bundle can be found at
+%
+% https://github.com/latex3/latex3
+%
+% for those people who are interested.
+%
+%<*driver>
+\documentclass[full]{l3doc}
+%</driver>
+%<*driver|package>
+\GetIdInfo$Id: l3flag.dtx 6969 2017-02-20 18:32:23Z bruno $
+ {L3 Flags}
+%</driver|package>
+%<*driver>
+\begin{document}
+ \DocInput{\jobname.dtx}
+\end{document}
+%</driver>
+% \fi
+%
+% \title{^^A
+% The \textsf{l3flag} package: expandable flags^^A
+% \thanks{This file describes v\ExplFileVersion,
+% last revised \ExplFileDate.}^^A
+% }
+%
+% \author{^^A
+% The \LaTeX3 Project\thanks
+% {^^A
+% E-mail:
+% \href{mailto:latex-team@latex-project.org}
+% {latex-team@latex-project.org}^^A
+% }^^A
+% }
+%
+% \date{Released \ExplFileDate}
+%
+% \maketitle
+%
+% \begin{documentation}
+%
+% Flags are the only data-type that can be modified in expansion-only
+% contexts. This module is meant mostly for kernel use: in almost all
+% 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
+% \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{str_missing}. 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.
+%
+% A typical use case of flags would be to keep track of whether an
+% exceptional condition has occured during expandable processing, and
+% produce a meaningful (non-expandable) message after the end of the
+% expandable processing. This is exemplified by \pkg{l3str-convert},
+% which for performance reasons performs conversions of individual
+% characters expandably and for readability reasons produces a single
+% 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.
+%
+% \section{Setting up flags}
+%
+% \begin{function}{\flag_new:n}
+% \begin{syntax}
+% \cs{flag_new:n} \Arg{flag name}
+% \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} will initially have zero height.
+% \end{function}
+%
+% \begin{function}{\flag_clear:n}
+% \begin{syntax}
+% \cs{flag_clear:n} \Arg{flag name}
+% \end{syntax}
+% The \meta{flag}'s height is set to zero. The assignment is local.
+% \end{function}
+%
+% \begin{function}{\flag_clear_new:n}
+% \begin{syntax}
+% \cs{flag_clear_new:n} \Arg{flag name}
+% \end{syntax}
+% Ensures that the \meta{flag} 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{syntax}
+% \cs{flag_show:n} \Arg{flag name}
+% \end{syntax}
+% Displays the \meta{flag}'s height in the terminal.
+% \end{function}
+%
+% \begin{function}{\flag_log:n}
+% \begin{syntax}
+% \cs{flag_log:n} \Arg{flag name}
+% \end{syntax}
+% Writes the \meta{flag}'s height to the log file.
+% \end{function}
+%
+% \section{Expandable flag commands}
+%
+% \begin{function}[EXP,pTF]{\flag_if_exist:n}
+% \begin{syntax}
+% \cs{flag_if_exist:n} \Arg{flag name}
+% \end{syntax}
+% This function returns \texttt{true} if the \meta{flag name}
+% references a flag that has been defined previously, and
+% \texttt{false} otherwise.
+% \end{function}
+%
+% \begin{function}[EXP,pTF]{\flag_if_raised:n}
+% \begin{syntax}
+% \cs{flag_if_raised:n} \Arg{flag name}
+% \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.
+% \end{function}
+%
+% \begin{function}[EXP]{\flag_height:n}
+% \begin{syntax}
+% \cs{flag_height:n} \Arg{flag name}
+% \end{syntax}
+% Expands to the height of the \meta{flag} as an integer denotation.
+% \end{function}
+%
+% \begin{function}[EXP]{\flag_raise:n}
+% \begin{syntax}
+% \cs{flag_raise:n} \Arg{flag name}
+% \end{syntax}
+% The \meta{flag}'s height is increased by $1$ locally.
+% \end{function}
+%
+% \end{documentation}
+%
+% \begin{implementation}
+%
+% \section{\pkg{l3flag} implementation}
+%
+% \begin{macrocode}
+%<*initex|package>
+% \end{macrocode}
+%
+% \begin{macrocode}
+%<@@=flag>
+% \end{macrocode}
+%
+% \TestFiles{m3flag001}
+%
+% \subsection{Non-expandable 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.
+%
+% \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{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: }
+ }
+% \end{macrocode}
+% \end{macro}
+%
+% \begin{macro}{\flag_clear:n}
+% \begin{macro}[aux]{\@@_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.
+% \begin{macrocode}
+\cs_new_protected:Npn \flag_clear:n { \@@_clear:wn 0 ; }
+\cs_new_protected:Npn \@@_clear:wn #1 ; #2
+ {
+ \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
+ \fi:
+ ; {#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,
+% 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} }
+% \end{macrocode}
+% \end{macro}
+%
+% \begin{macro}{\flag_show:n, \flag_log:n}
+% Show the height (terminal or log file) using appropriate \pkg{l3msg}
+% auxiliaries.
+% \begin{macrocode}
+\cs_new_protected:Npn \flag_show:n #1
+ {
+ \exp_args:Nc \__msg_show_variable:NNNnn { flag~#1 } \cs_if_exist:NTF ? { }
+ { > ~ flag ~ #1 ~ height = \flag_height:n {#1} }
+ }
+\cs_new_protected:Npn \flag_log:n
+ { \__msg_log_next: \flag_show:n }
+% \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{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: }
+ }
+% \end{macrocode}
+% \end{macro}
+%
+% \begin{macro}[EXP, pTF]{\flag_if_raised:n}
+% 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 }
+ {
+ \if_cs_exist:w flag~#1~0 \cs_end:
+ \prg_return_true:
+ \else:
+ \prg_return_false:
+ \fi:
+ }
+% \end{macrocode}
+% \end{macro}
+%
+% \begin{macro}[EXP]{\flag_height:n}
+% \begin{macro}[EXP, aux]{\@@_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 { \@@_height_loop:wn 0; }
+\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
+ \fi:
+ #1 ; {#2}
+ }
+\cs_new:Npn \@@_height_end:wn #1 ; #2 {#1}
+% \end{macrocode}
+% \end{macro}
+% \end{macro}
+%
+% \begin{macro}[EXP]{\flag_raise:n}
+% Simply apply the trap to the height, after expanding the latter.
+% \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} ;
+ }
+% \end{macrocode}
+% \end{macro}
+%
+% \subsection{Option check-declarations}
+%
+% \begin{macro}[EXP,aux]{\@@_chk_exist:n}
+% In package mode, there is an option to check all variables used are
+% defined. Since flags are not implemented in terms of other
+% variables, we need to add checks by hand. Not all functions need to
+% be patched because some are defined in terms of others.
+% \begin{macrocode}
+%<*package>
+\tex_ifodd:D \l@expl@check@declarations@bool
+ \cs_set_protected:Npn \flag_clear:n #1
+ {
+ \exp_args:Nc \__chk_if_exist_var:N { flag~#1 }
+ \@@_clear:wn 0 ; {#1}
+ }
+ \cs_set:Npn \@@_chk_exist:n #1
+ {
+ \flag_if_exist:nF {#1}
+ {
+ \__msg_kernel_expandable_error:nnn
+ { kernel } { bad-variable } { flag~#1~ }
+ }
+ }
+ \cs_set:Npn \flag_height:n #1
+ {
+ \@@_chk_exist:n {#1}
+ \@@_height_loop:wn 0; {#1}
+ }
+ \prg_set_conditional:Npnn \flag_if_raised:n #1 { p , T , F , TF }
+ {
+ \@@_chk_exist:n {#1}
+ \if_cs_exist:w flag~#1~0 \cs_end:
+ \prg_return_true:
+ \else:
+ \prg_return_false:
+ \fi:
+ }
+\fi:
+%</package>
+% \end{macrocode}
+% \end{macro}
+%
+% \begin{macrocode}
+%</initex|package>
+% \end{macrocode}
+%
+% \end{implementation}
+%
+% \PrintIndex