% \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 released version of this bundle is available from CTAN.
%%
%% -----------------------------------------------------------------------
%%
%% The development version of the bundle can be found at
%%
%%    http://www.latex-project.org/svnroot/experimental/trunk/
%%
%% for those people who are interested.
%%
%%%%%%%%%%%
%% NOTE: %%
%%%%%%%%%%%
%%
%%   Snapshots taken from the repository represent work in progress and may
%%   not work or may contain conflicting material!  We therefore ask
%%   people _not_ to put them into distributions, archives, etc. without
%%   prior consultation with the LaTeX3 Project.
%%
%% -----------------------------------------------------------------------
%
%<*driver|package>
% The version of expl3 required is tested as early as possible, as
% some really old versions do not define \ProvidesExplPackage.
\RequirePackage{expl3}[2016/01/19]
%<package>\@ifpackagelater{expl3}{2016/01/19}
%<package>  {}
%<package>  {%
%<package>    \PackageError{l3flag}{Support package l3kernel too old}
%<package>      {%
%<package>        Please install an up to date version of l3kernel\MessageBreak
%<package>        using your TeX package manager or from CTAN.\MessageBreak
%<package>        \MessageBreak
%<package>        Loading l3flag will abort!%
%<package>      }%
%<package>    \endinput
%<package>  }
\GetIdInfo$Id: l3flag.dtx 6377 2016-01-19 22:28:13Z joseph $
  {L3 Experimental flags}
%</driver|package>
%<*driver>
\documentclass[full]{l3doc}
\usepackage{amsmath}
\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 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_use:N \__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_use:N \__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}
%</initex|package>
%    \end{macrocode}
%
% \end{implementation}
%
% \PrintIndex
