% \iffalse meta-comment % %% File: l3flag.dtx Copyright (C) 2011-2012,2014-2016 The LaTeX3 Project % % It may be distributed and/or modified under the conditions of the % LaTeX Project Public License (LPPL), either version 1.3c of this % license or (at your option) any later version. The latest version % of this license is in the file % % http://www.latex-project.org/lppl.txt % % This file is part of the "l3experimental bundle" (The Work in LPPL) % and all files in that bundle must be distributed together. % % ----------------------------------------------------------------------- % % The development version of the bundle can be found at % % https://github.com/latex3/latex3 % % for those people who are interested. % %<*driver|package> % The version of expl3 required is tested as early as possible, as % some really old versions do not define \ProvidesExplPackage. \RequirePackage{expl3}[2017/02/07] %\@ifpackagelater{expl3}{2017/02/07} % {} % {% % \PackageError{l3flag}{Support package l3kernel too old} % {% % Please install an up to date version of l3kernel\MessageBreak % using your TeX package manager or from CTAN.\MessageBreak % \MessageBreak % Loading l3flag will abort!% % }% % \endinput % } \GetIdInfo$Id: l3flag.dtx 6846 2017-02-07 07:04:19Z joseph $ {L3 Experimental flags} % %<*driver> \documentclass[full]{l3doc} \usepackage{amsmath} \begin{document} \DocInput{\jobname.dtx} \end{document} % % \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 on which \TeX{} can perform % assignments 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 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 normally increases the \meta{height} by $1$, % but can be configured by defining specific traps. 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{name} % of the form \meta{package}\texttt{_}\meta{flag name}, for instance, % \texttt{str_missing}. % % \section{Setting up flags} % % \begin{function}{\flag_new:n} % \begin{syntax} % \cs{flag_new:n} \Arg{flag name} % \end{syntax} % Creates a new \meta{flag} with a name given by \meta{flag name}, or % raises an error if the name is already taken. The \meta{flag name} % must consist of character tokens only. 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_zero:n}, setting % the height to zero locally. % \end{function} % % \begin{function}{\flag_set_trap:nn} % \begin{syntax} % \cs{flag_set_trap:nn} \Arg{flag name} \Arg{inline function} % \end{syntax} % Changes the action that is taken when the \meta{flag} is raised % using \cs{flag_raise:n}. Instead of the default action which is to % increase the \meta{flag}'s height by $1$, the \meta{inline function} % will be called, receiving the current flag's height as |#1|. The % \meta{inline function} should expand to nothing; \emph{e.g.}, it % could call \cs{msg_expandable_error:n}. This function is very % experimental. % \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 trap is performed, taking the current height as % its argument. The default behaviour is to increase the \meta{flag}'s % height by $1$ locally. This function is expandable, as long as the % trap is expandable (the default trap is expandable, despite being an % assignment). % \end{function} % % \end{documentation} % % \begin{implementation} % % \section{\pkg{l3flag} implementation} % % \begin{macrocode} %<*initex|package> % \end{macrocode} % % \begin{macrocode} %<@@=flag> % \end{macrocode} % % \begin{macrocode} \ProvidesExplPackage {\ExplFileName}{\ExplFileDate}{\ExplFileVersion}{\ExplFileDescription} % \end{macrocode} % % \subsection{Non-expandable flag commands} % % \begin{macro}{\flag_new:n} % For each flag, we define a \enquote{trap} function, which by default % simply increases the flag by $1$. % \begin{macrocode} \cs_new_protected:Npn \flag_new:n #1 { \cs_new:cpn { @@_trap_#1:w } ##1 ; { \exp_after:wN \use_none:n \cs:w @@_#1_##1: \cs_end: } } % \end{macrocode} % \end{macro} % % \begin{macro}{\flag_clear:n} % \begin{macro}[aux]{\@@_clear:ww} % Undefine control sequences, starting from the |_0| flag, upwards, % until reaching an undefined control sequence. % \begin{macrocode} \cs_new_protected:Npn \flag_clear:n #1 { \@@_clear:ww 0 ; #1 \q_stop } \cs_new_protected:Npn \@@_clear:ww #1 ; #2 \q_stop { \if_cs_exist:w @@_#2_#1: \cs_end: \else: \exp_after:wN \use_none_delimit_by_q_stop:w \fi: \cs_set_eq:cN { @@_#2_#1: } \tex_undefined:D \exp_after:wN \@@_clear:ww \__int_value:w \__int_eval:w \c_one + #1 ; #2 \q_stop } % \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_set_trap:nn} % ^^A todo: check that the flag exists. % Redefine the trap. % \begin{macrocode} \cs_new_protected:Npn \flag_set_trap:nn #1#2 { \cs_set:cpn { @@_trap_#1:w } ##1 ; {#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{@@_trap_\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 { @@_trap_#1:w } { \prg_return_true: } { \prg_return_false: } } % \end{macrocode} % \end{macro} % % \begin{macro}[EXP, pTF]{\flag_if_raised:n} % Test if the flag is non-zero, 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 @@_#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:ww, \@@_height_end:ww} % Extract the value of the flag by going through all of the % |_|\meta{integer} control sequences starting from $0$. % \begin{macrocode} \cs_new:Npn \flag_height:n #1 { \@@_height_loop:ww 0; #1 \q_stop } \cs_new:Npn \@@_height_loop:ww #1 ; #2 \q_stop { \if_cs_exist:w @@_#2_#1: \cs_end: \exp_after:wN \@@_height_loop:ww \__int_value:w \__int_eval:w \c_one + \else: \exp_after:wN \@@_height_end:ww \fi: #1 ; #2 \q_stop } \cs_new:Npn \@@_height_end:ww #1 ; #2 \q_stop { #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 @@_trap_#1:w \exp_after:wN \cs_end: \__int_value:w \flag_height:n {#1} ; } % \end{macrocode} % \end{macro} % % \begin{macrocode} % % \end{macrocode} % % \end{implementation} % % \PrintIndex