% \iffalse meta-comment
%
%% File: l3prg.dtx
%
% Copyright (C) 2005-2025 The LaTeX 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
%
%    https://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,kernel]{l3doc}
\begin{document}
  \DocInput{\jobname.dtx}
\end{document}
%</driver>
% \fi
%
% \title{^^A
%   The \pkg{l3prg} module\\ Control structures^^A
% }
%
% \author{^^A
%  The \LaTeX{} Project\thanks
%    {^^A
%      E-mail:
%        \href{mailto:latex-team@latex-project.org}
%          {latex-team@latex-project.org}^^A
%    }^^A
% }
%
% \date{Released 2025-12-29}
%
% \maketitle
%
% \begin{documentation}
%
% Conditional processing in \LaTeX3 is defined as something that
% performs a series of tests, possibly involving assignments and
% calling other functions that do not read further ahead in the input
% stream. After processing the input, a \emph{state} is returned. The
% states returned are \meta{true} and \meta{false}.
%
% \LaTeX3 has two forms of conditional flow processing based
% on these states. The first form is predicate functions that turn the
% returned state into a boolean \meta{true} or \meta{false}. For
% example, the function \cs{cs_if_free_p:N} checks whether the control
% sequence given as its argument is free and then returns the boolean
% \meta{true} or \meta{false} values to be used in testing with
% \cs{if_predicate:w} or in functions to be described below.  The second form
% is the kind of functions choosing a particular argument from the
% input stream based on the result of the testing as in
% \cs{cs_if_free:NTF} which also takes one argument (the |N|) and then
% executes either \texttt{true} or \texttt{false} depending on the
% result.
%
% \begin{texnote}
%   The arguments are executed after exiting the underlying
%   |\if...\fi:| structure.
% \end{texnote}
%
% \section{Defining a set of conditional functions}
% \label{sec:l3prg:new-conditional-functions}
%
% \begin{function}[updated = 2022-11-01]
%   {
%     \prg_new_conditional:Npnn, \prg_set_conditional:Npnn, \prg_gset_conditional:Npnn,
%     \prg_new_protected_conditional:Npnn, \prg_set_protected_conditional:Npnn, \prg_gset_protected_conditional:Npnn,
%     \prg_new_conditional:Nnn,  \prg_set_conditional:Nnn, \prg_gset_conditional:Nnn,
%     \prg_new_protected_conditional:Nnn,  \prg_set_protected_conditional:Nnn, \prg_gset_protected_conditional:Nnn
%    }
%   \begin{syntax}
%     \cs{prg_new_conditional:Npnn} \cs[no-index]{\meta{name}:\meta{arg spec}} \meta{parameters} \Arg{conditions} \Arg{code} \\
%     \cs{prg_new_conditional:Nnn} \cs[no-index]{\meta{name}:\meta{arg spec}} \Arg{conditions} \Arg{code}
%   \end{syntax}
%   These functions create a family of conditionals using the same
%   \meta{code} to perform the test created. Those non-protected
%   conditionals are expandable if \meta{code} is.
%   The \texttt{new} versions check
%   for existing definitions and perform assignments globally
%   (\emph{cf.}~\cs{cs_new:Npn}) whereas the \texttt{set} versions do no
%   check and perform assignments locally (\emph{cf.}~\cs{cs_set:Npn}).
%   The conditionals created are dependent on the comma-separated list
%   of \meta{conditions}, which should be one or more of
%   \texttt{T}, \texttt{F} and \texttt{TF}, and for non-protected conditionals
%   \texttt{p}.
%   For public conditionals, a full set of forms should be provided:
%   this contrasts with strictly internal conditionals, where only the
%   required subset need be defined.
% \end{function}
%
% The conditionals are defined by \cs{prg_new_conditional:Npnn} and
% friends as:
% \begin{itemize}
%   \item \cs[no-index]{\meta{name}_p:\meta{arg spec}} --- a predicate function
%     which will supply either a logical \texttt{true} or logical
%     \texttt{false}. This function is intended for use in cases where
%     one or more logical tests are combined to lead to a final outcome.
%     This function cannot be defined for \texttt{protected}
%     conditionals.
%   \item \cs[no-index]{\meta{name}:\meta{arg spec}T} --- a function with one more
%     argument than the original \meta{arg spec} demands. The \meta{true
%       branch} code in this additional argument will be left on the
%     input stream only if the test is \texttt{true}.
%   \item \cs[no-index]{\meta{name}:\meta{arg spec}F} --- a function with one more
%     argument than the original \meta{arg spec} demands. The
%     \meta{false branch} code in this additional argument will be left
%     on the input stream only if the test is \texttt{false}.
%   \item \cs[no-index]{\meta{name}:\meta{arg spec}TF} --- a function with two
%     more argument than the original \meta{arg spec} demands. The
%     \meta{true branch} code in the first additional argument will be
%     left on the input stream if the test is \texttt{true}, while the
%     \meta{false branch} code in the second argument will be left on
%     the input stream if the test is \texttt{false}.
% \end{itemize}
% The \meta{code} of the test may use \meta{parameters} as specified by
% the second argument to \cs{prg_set_conditional:Npnn}: this should
% match the \meta{argument specification} but this is not enforced.  The
% |Nnn| versions infer the number of arguments from the argument
% specification given (\emph{cf.}~\cs{cs_new:Nn}, etc.).  Within
% the \meta{code}, the functions \cs{prg_return_true:} and
% \cs{prg_return_false:} are used to indicate the logical outcomes of
% the test.
%
% An example can easily clarify matters here:
% \begin{verbatim}
%   \prg_set_conditional:Npnn \foo_if_bar:NN #1#2 { p , T , TF }
%     {
%       \if_meaning:w \l_tmpa_tl #1
%         \prg_return_true:
%       \else:
%         \if_meaning:w \l_tmpa_tl #2
%           \prg_return_true:
%         \else:
%           \prg_return_false:
%         \fi:
%       \fi:
%     }
% \end{verbatim}
% This defines the function |\foo_if_bar_p:NN|, |\foo_if_bar:NNTF| and
% |\foo_if_bar:NNT| but not |\foo_if_bar:NNF| (because |F| is missing
% from the \meta{conditions} list). The return statements take care of
% resolving the remaining \cs{else:} and \cs{fi:} before returning the
% state. There must be a return statement for each branch; failing to do
% so will result in erroneous output if that branch is executed.
%
% The special case where the code of a conditional ends with
% \cs{prg_return_true:} \cs{else:} \cs{prg_return_false:} \cs{fi:} is
% optimized.
%
% \begin{function}[updated = 2023-05-26]
%   {
%     \prg_new_eq_conditional:NNn,
%     \prg_set_eq_conditional:NNn,
%     \prg_gset_eq_conditional:NNn
%   }
%   \begin{syntax}
%     \cs{prg_new_eq_conditional:NNn} \cs[no-index]{\meta{name_1}:\meta{arg spec}} \cs[no-index]{\meta{name_2}:\meta{arg spec}} \Arg{conditions}
%   \end{syntax}
%   These functions copy a family of conditionals. The \texttt{new} version
%   checks for existing definitions (\emph{cf.}~\cs{cs_new_eq:NN}) whereas
%   the \texttt{set} version does not (\emph{cf.}~\cs{cs_set_eq:NN}). The
%   conditionals copied are depended on the comma-separated list of
%   \meta{conditions}, which should be one or more of \texttt{p}, \texttt{T},
%   \texttt{F} and \texttt{TF}.
% \end{function}
%
% \begin{function}[EXP]{\prg_return_true:, \prg_return_false:}
%   \begin{syntax}
%     \cs{prg_return_true:}
%     \cs{prg_return_false:}
%   \end{syntax}
%   These \enquote{return} functions define the logical state of a conditional statement.
%   They appear within the code for a conditional
%   function generated by \cs{prg_set_conditional:Npnn}, \emph{etc}, to indicate
%   when a true or false branch should be taken.
%   While they may appear multiple times each within the code of such conditionals,
%   the execution of the conditional must result in the expansion of one of these
%   two functions \emph{exactly once}.
%
%   The return functions trigger what is internally an \texttt{f}-expansion process to complete
%   the evaluation of the conditional. Therefore, after \cs{prg_return_true:} or \cs{prg_return_false:}
%   there must be no non-expandable material in the input stream for the remainder of
%   the expansion of the conditional code. This includes other instances of either of these functions.
% \end{function}
%
% \begin{function}[added = 2017-12-12]{\prg_generate_conditional_variant:Nnn}
%   \begin{syntax}
%     \cs{prg_generate_conditional_variant:Nnn} \cs[no-index]{\meta{name}:\meta{arg spec}} \Arg{variant argument specifiers} \Arg{condition specifiers}
%   \end{syntax}
%   Defines argument-specifier variants of conditionals.  This is
%   equivalent to running \cs{cs_generate_variant:Nn} \meta{conditional}
%   \Arg{variant argument specifiers} on each \meta{conditional}
%   described by the \meta{condition specifiers}.  These base-form
%   \meta{conditionals} are obtained from the \meta{name} and \meta{arg
%   spec} as described for \cs{prg_new_conditional:Npnn}, and they
%   should be defined.
% \end{function}
%
% \section{The boolean data type}
%
% This section describes a boolean data type which is closely
% connected to conditional processing as sometimes you want to
% execute some code depending on the value of a switch
% (\emph{e.g.},~draft/final) and other times you perhaps want to use it as a
% predicate function in an \cs{if_predicate:w} test. The problem of the
% primitive \cs{if_false:} and \cs{if_true:} tokens is that it is not
% always safe to pass them around as they may interfere with scanning
% for termination of primitive conditional processing. Therefore, we
% employ two canonical booleans: \cs{c_true_bool} or
% \cs{c_false_bool}. Besides preventing problems as described above, it
% also allows us to implement a simple boolean parser supporting the
% logical operations And, Or, Not, etc.\ which can then be used on
% both the boolean type and predicate functions.
%
% All conditional |\bool_| functions except assignments are expandable
% and expect the input to also be fully expandable (which generally
% means being constructed from predicate functions and booleans, possibly nested).
%
% \begin{texnote}
%   The \texttt{bool} data type is not implemented using the
%   \tn{iffalse}/\tn{iftrue} primitives, in contrast to \tn{newif},
%   etc., in plain \TeX{}, \LaTeXe{} and so on. Programmers should
%   not base use of \texttt{bool} switches on any particular expectation
%   of the implementation.
% \end{texnote}
%
% \begin{function}{\bool_new:N, \bool_new:c}
%   \begin{syntax}
%     \cs{bool_new:N} \meta{boolean}
%   \end{syntax}
%   Creates a new \meta{boolean} or raises an error if the
%   name is already taken. The declaration is global. The
%   \meta{boolean} is initially \texttt{false}.
% \end{function}
%
% \begin{function}[added = 2017-11-28]{\bool_const:Nn, \bool_const:cn}
%   \begin{syntax}
%     \cs{bool_const:Nn} \meta{boolean} \Arg{boolexpr}
%   \end{syntax}
%   Creates a new constant \meta{boolean} or raises an error if the name
%   is already taken. The value of the \meta{boolean} is set globally to
%   the result of evaluating the \meta{boolexpr}.
% \end{function}
%
% \begin{function}
%   {
%     \bool_set_false:N , \bool_set_false:c ,
%     \bool_gset_false:N, \bool_gset_false:c
%   }
%   \begin{syntax}
%     \cs{bool_set_false:N} \meta{boolean}
%   \end{syntax}
%   Sets \meta{boolean} logically \texttt{false}.
% \end{function}
%
% \begin{function}
%   {
%     \bool_set_true:N , \bool_set_true:c ,
%     \bool_gset_true:N , \bool_gset_true:c
%   }
%   \begin{syntax}
%     \cs{bool_set_true:N} \meta{boolean}
%   \end{syntax}
%   Sets \meta{boolean} logically \texttt{true}.
% \end{function}
%
% \begin{function}
%   {
%     \bool_set_eq:NN , \bool_set_eq:cN , \bool_set_eq:Nc , \bool_set_eq:cc ,
%     \bool_gset_eq:NN, \bool_gset_eq:cN, \bool_gset_eq:Nc, \bool_gset_eq:cc
%   }
%   \begin{syntax}
%     \cs{bool_set_eq:NN} \meta{boolean_1} \meta{boolean_2}
%   \end{syntax}
%   Sets \meta{boolean_1} to the current value of \meta{boolean_2}.
% \end{function}
%
% \begin{function}[updated = 2017-07-15]
%   {\bool_set:Nn, \bool_set:cn, \bool_gset:Nn, \bool_gset:cn}
%   \begin{syntax}
%     \cs{bool_set:Nn} \meta{boolean} \Arg{boolexpr}
%   \end{syntax}
%   Evaluates the \meta{boolean expression} as described for
%   \cs{bool_if:nTF}, and sets the \meta{boolean} variable to
%   the logical truth of this evaluation.
% \end{function}
%
% \begin{function}[added = 2018-05-10]
%   {
%     \bool_set_inverse:N , \bool_set_inverse:c ,
%     \bool_gset_inverse:N, \bool_gset_inverse:c
%   }
%   \begin{syntax}
%     \cs{bool_set_inverse:N} \meta{boolean}
%   \end{syntax}
%   Toggles the \meta{boolean} from \texttt{true} to \texttt{false} and
%   conversely: sets it to the inverse of its current value.
% \end{function}
%
% \begin{function}[EXP,pTF, updated = 2017-07-15]{\bool_if:N, \bool_if:c}
%   \begin{syntax}
%     \cs{bool_if_p:N} \meta{boolean}
%     \cs{bool_if:NTF} \meta{boolean} \Arg{true code} \Arg{false code}
%   \end{syntax}
%   Tests the current truth of \meta{boolean}, and continues expansion
%   based on this result.
% \end{function}
%
% \begin{function}[EXP, added = 2021-11-01, updated = 2023-11-14]
%   {\bool_to_str:N, \bool_to_str:c, \bool_to_str:n}
%   \begin{syntax}
%     \cs{bool_to_str:N} \meta{boolean}
%     \cs{bool_to_str:n} \Arg{boolean expression}
%   \end{syntax}
%   Expands to the string \texttt{true} or \texttt{false} depending on
%   the logical truth of the \meta{boolean} or \meta{boolean
%   expression}.
% \end{function}
%
% \begin{function}[added = 2012-02-09, updated = 2021-04-29]{\bool_show:N, \bool_show:c}
%   \begin{syntax}
%     \cs{bool_show:N} \meta{boolean}
%   \end{syntax}
%   Displays the logical truth of the \meta{boolean} on the terminal.
% \end{function}
%
% \begin{function}[added = 2012-02-09, updated = 2017-07-15]{\bool_show:n}
%   \begin{syntax}
%     \cs{bool_show:n} \Arg{boolean expression}
%   \end{syntax}
%   Displays the logical truth of the \meta{boolean expression} on the
%   terminal.
% \end{function}
%
% \begin{function}[added = 2014-08-22, updated = 2021-04-29]{\bool_log:N, \bool_log:c}
%   \begin{syntax}
%     \cs{bool_log:N} \meta{boolean}
%   \end{syntax}
%   Writes the logical truth of the \meta{boolean} in the log file.
% \end{function}
%
% \begin{function}[added = 2014-08-22, updated = 2017-07-15]{\bool_log:n}
%   \begin{syntax}
%     \cs{bool_log:n} \Arg{boolean expression}
%   \end{syntax}
%   Writes the logical truth of the \meta{boolean expression} in the log
%   file.
% \end{function}
%
% \begin{function}[EXP, pTF, added=2012-03-03]
%   {\bool_if_exist:N, \bool_if_exist:c}
%   \begin{syntax}
%     \cs{bool_if_exist_p:N} \meta{boolean}
%     \cs{bool_if_exist:NTF} \meta{boolean} \Arg{true code} \Arg{false code}
%   \end{syntax}
%   Tests whether the \meta{boolean} is currently defined.  This does not
%   check that the \meta{boolean} really is a boolean variable.
% \end{function}
%
% \subsection{Constant and scratch booleans}
%
% \begin{variable}{\c_true_bool, \c_false_bool}
%   Constants that represent |true| and |false|, respectively. Used to
%   implement predicates.
% \end{variable}
%
% \begin{variable}{\l_tmpa_bool, \l_tmpb_bool}
%   A scratch boolean for local assignment. It is never used by
%   the kernel code, and so is safe for use with any \LaTeX3-defined
%   function. However, it may be overwritten by other non-kernel
%   code and so should only be used for short-term storage.
% \end{variable}
%
% \begin{variable}{\g_tmpa_bool, \g_tmpb_bool}
%   A scratch boolean for global assignment. It is never used by
%   the kernel code, and so is safe for use with any \LaTeX3-defined
%   function. However, it may be overwritten by other non-kernel
%   code and so should only be used for short-term storage.
% \end{variable}
%
% \section{Boolean expressions}
%
% As we have a boolean datatype and predicate functions returning
% boolean \meta{true} or \meta{false} values, it seems only fitting
% that we also provide a parser for \meta{boolean expressions}.
%
% A boolean expression is an expression which given input in the form
% of predicate functions and boolean variables, return boolean
% \meta{true} or \meta{false}. It supports the logical operations And,
% Or and Not as the well-known infix operators |&&| and \verb"||" and prefix~|!|
% with their usual precedences (namely, |&&| binds more tightly than
% \verb"||"). In addition to this, parentheses can be used to isolate
% sub-expressions. For example,
% \begin{verbatim}
%     \int_compare_p:n { 1 = 1 } &&
%       (
%         \int_compare_p:n { 2 = 3 } ||
%         \int_compare_p:n { 4 <= 4 } ||
%         \str_if_eq_p:nn { abc } { def }
%       ) &&
%     ! \int_compare_p:n { 2 = 4 }
% \end{verbatim}
% is a valid boolean expression.
%
% Contrarily to some other programming languages, the operators |&&| and
% \verb"||" evaluate both operands in all cases, even when the first
% operand is enough to determine the result.  This \enquote{eager}
% evaluation should be contrasted with the \enquote{lazy} evaluation of
% \cs[no-index]{bool_lazy_\ldots{}} functions.
%
% \begin{texnote}
%   The eager evaluation of boolean expressions is unfortunately
%   necessary in \TeX{}.  Indeed, a lazy parser can get confused if |&&|
%   or \verb"||" or parentheses appear as (unbraced) arguments of some
%   predicates.  For instance, the innocuous-looking expression below
%   would break (in a lazy parser) if |#1| were a closing parenthesis
%   and \cs[no-index]{l_tmpa_bool} were \texttt{true}.
%   \begin{verbatim}
%     ( \l_tmpa_bool || \token_if_eq_meaning_p:NN X #1 )
%   \end{verbatim}
% \end{texnote}
%
% Minimal (lazy) evaluation can be obtained using the conditionals
% \cs{bool_lazy_all:nTF}, \cs{bool_lazy_and:nnTF}, \cs{bool_lazy_any:nTF}, or
% \cs{bool_lazy_or:nnTF}, which only evaluate their boolean expression
% arguments when they are needed to determine the resulting truth
% value.  For example, when evaluating the boolean expression
% \begin{verbatim}
%     \bool_lazy_and_p:nn
%       {
%         \bool_lazy_any_p:n
%           {
%             { \int_compare_p:n { 2 = 3 } }
%             { \int_compare_p:n { 4 <= 4 } }
%             { \int_compare_p:n { 1 = \error } } % skipped
%           }
%       }
%       { ! \int_compare_p:n { 2 = 4 } }
% \end{verbatim}
% the line marked with |skipped| is not expanded because the result
% of \cs{bool_lazy_any_p:n} is known once the second boolean expression is
% found to be logically \texttt{true}.  On the other hand, the last
% line is expanded because its logical value is needed to determine the
% result of \cs{bool_lazy_and_p:nn}.
%
% \begin{function}[EXP, pTF, updated = 2017-07-15]{\bool_if:n}
%   \begin{syntax}
%     \cs{bool_if_p:n} \Arg{boolean expression}
%     \cs{bool_if:nTF} \Arg{boolean expression} \Arg{true code} \Arg{false code}
%   \end{syntax}
%   Tests the current truth of \meta{boolean expression}, and
%   continues expansion based on this result. The
%   \meta{boolean expression} should consist of a series of predicates
%   or boolean variables with the logical relationship between these
%   defined using |&&| (\enquote{And}), \verb"||" (\enquote{Or}),
%   |!| (\enquote{Not}) and parentheses.  The logical Not applies to
%   the next predicate or group.
% \end{function}
%
% \begin{function}[EXP, pTF, added = 2015-11-15, updated = 2017-07-15]{\bool_lazy_all:n}
%   \begin{syntax}
%     \cs{bool_lazy_all_p:n} \{ \Arg{boolexpr_1} \Arg{boolexpr_2} $\cdots$ \Arg{boolexpr_N} \}
%     \cs{bool_lazy_all:nTF} \{ \Arg{boolexpr_1} \Arg{boolexpr_2} $\cdots$ \Arg{boolexpr_N} \} \Arg{true code} \Arg{false code}
%   \end{syntax}
%   Implements the \enquote{And} operation on the \meta{boolean
%   expressions}, hence is \texttt{true} if all of them are
%   \texttt{true} and \texttt{false} if any of them is \texttt{false}.
%   Contrarily to the infix operator |&&|, only the \meta{boolean
%   expressions} which are needed to determine the result of
%   \cs{bool_lazy_all:nTF} are evaluated.  See also \cs{bool_lazy_and:nnTF}
%   when there are only two \meta{boolean expressions}.
% \end{function}
%
% \begin{function}[EXP, pTF, added = 2015-11-15, updated = 2017-07-15]{\bool_lazy_and:nn}
%   \begin{syntax}
%     \cs{bool_lazy_and_p:nn} \Arg{boolexpr_1} \Arg{boolexpr_2}
%     \cs{bool_lazy_and:nnTF} \Arg{boolexpr_1} \Arg{boolexpr_2} \Arg{true code} \Arg{false code}
%   \end{syntax}
%   Implements the \enquote{And} operation between two boolean
%   expressions, hence is \texttt{true} if both are \texttt{true}.
%   Contrarily to the infix operator |&&|, the \meta{boolexpr_2} is only
%   evaluated if it is needed to determine the result of
%   \cs{bool_lazy_and:nnTF}.  See also \cs{bool_lazy_all:nTF} when there are more
%   than two \meta{boolean expressions}.
% \end{function}
%
% \begin{function}[EXP, pTF, added = 2015-11-15, updated = 2017-07-15]{\bool_lazy_any:n}
%   \begin{syntax}
%     \cs{bool_lazy_any_p:n} \{ \Arg{boolexpr_1} \Arg{boolexpr_2} $\cdots$ \Arg{boolexpr_N} \}
%     \cs{bool_lazy_any:nTF} \{ \Arg{boolexpr_1} \Arg{boolexpr_2} $\cdots$ \Arg{boolexpr_N} \} \Arg{true code} \Arg{false code}
%   \end{syntax}
%   Implements the \enquote{Or} operation on the \meta{boolean
%   expressions}, hence is \texttt{true} if any of them is
%   \texttt{true} and \texttt{false} if all of them are \texttt{false}.
%   Contrarily to the infix operator \verb"||", only the \meta{boolean
%   expressions} which are needed to determine the result of
%   \cs{bool_lazy_any:nTF} are evaluated.  See also \cs{bool_lazy_or:nnTF}
%   when there are only two \meta{boolean expressions}.
% \end{function}
%
% \begin{function}[EXP, pTF, added = 2015-11-15, updated = 2017-07-15]{\bool_lazy_or:nn}
%   \begin{syntax}
%     \cs{bool_lazy_or_p:nn} \Arg{boolexpr_1} \Arg{boolexpr_2}
%     \cs{bool_lazy_or:nnTF} \Arg{boolexpr_1} \Arg{boolexpr_2} \Arg{true code} \Arg{false code}
%   \end{syntax}
%   Implements the \enquote{Or} operation between two boolean
%   expressions, hence is \texttt{true} if either one is \texttt{true}.
%   Contrarily to the infix operator \verb"||", the \meta{boolexpr_2}
%   is only evaluated if it is needed to determine the result of
%   \cs{bool_lazy_or:nnTF}.  See also \cs{bool_lazy_any:nTF} when there are more
%   than two \meta{boolean expressions}.
% \end{function}
%
% \begin{function}[EXP, updated = 2017-07-15]{\bool_not_p:n}
%   \begin{syntax}
%      \cs{bool_not_p:n} \Arg{boolean expression}
%   \end{syntax}
%   Function version of |!(|\meta{boolean expression}|)| within a boolean
%   expression.
% \end{function}
%
% \begin{function}[EXP, pTF, added = 2018-05-09]{\bool_xor:nn}
%   \begin{syntax}
%     \cs{bool_xor_p:nn} \Arg{boolexpr_1} \Arg{boolexpr_2}
%     \cs{bool_xor:nnTF} \Arg{boolexpr_1} \Arg{boolexpr_2} \Arg{true code} \Arg{false code}
%   \end{syntax}
%   Implements an \enquote{exclusive or} operation between two boolean
%   expressions. There is no infix operation for this logical operation.
% \end{function}
%
% \section{Logical loops}
%
% Loops using either boolean expressions or stored boolean values.
%
% \begin{function}[rEXP, updated = 2017-07-15]{\bool_do_until:Nn, \bool_do_until:cn}
%   \begin{syntax}
%     \cs{bool_do_until:Nn} \meta{boolean} \Arg{code}
%   \end{syntax}
%   Places the \meta{code} in the input stream for \TeX{} to process,
%   and then checks the logical value of the \meta{boolean}.  If it is
%   \texttt{false} then the \meta{code} is inserted into the input
%   stream again and the process loops until the \meta{boolean} is
%   \texttt{true}.
% \end{function}
%
% \begin{function}[rEXP, updated = 2017-07-15]{\bool_do_while:Nn, \bool_do_while:cn}
%   \begin{syntax}
%     \cs{bool_do_while:Nn} \meta{boolean} \Arg{code}
%   \end{syntax}
%   Places the \meta{code} in the input stream for \TeX{} to process,
%   and then checks the logical value of the \meta{boolean}.  If it is
%   \texttt{true} then the \meta{code} is inserted into the input
%   stream again and the process loops until the \meta{boolean} is
%   \texttt{false}.
% \end{function}
%
% \begin{function}[rEXP, updated = 2017-07-15]{\bool_until_do:Nn, \bool_until_do:cn}
%   \begin{syntax}
%     \cs{bool_until_do:Nn} \meta{boolean} \Arg{code}
%   \end{syntax}
%   This function first checks the logical value of the \meta{boolean}.
%   If it is \texttt{false} the \meta{code} is placed in the input stream
%   and expanded. After the completion of the \meta{code} the truth
%   of the \meta{boolean} is re-evaluated. The process then loops
%   until the \meta{boolean} is \texttt{true}.
% \end{function}
%
% \begin{function}[rEXP, updated = 2017-07-15]{\bool_while_do:Nn, \bool_while_do:cn}
%   \begin{syntax}
%     \cs{bool_while_do:Nn} \meta{boolean} \Arg{code}
%   \end{syntax}
%   This function first checks the logical value of the \meta{boolean}.
%   If it is \texttt{true} the \meta{code} is placed in the input stream
%   and expanded. After the completion of the \meta{code} the truth
%   of the \meta{boolean} is re-evaluated. The process then loops
%   until the \meta{boolean} is \texttt{false}.
% \end{function}
%
% \begin{function}[rEXP, updated = 2017-07-15]{\bool_do_until:nn}
%   \begin{syntax}
%     \cs{bool_do_until:nn} \Arg{boolean expression} \Arg{code}
%   \end{syntax}
%   Places the \meta{code} in the input stream for \TeX{} to process,
%   and then checks the logical value of the \meta{boolean expression}
%   as described for \cs{bool_if:nTF}.  If it is \texttt{false} then the
%   \meta{code} is inserted into the input stream again and the
%   process loops until the \meta{boolean expression} evaluates to
%   \texttt{true}.
% \end{function}
%
% \begin{function}[rEXP, updated = 2017-07-15]{\bool_do_while:nn}
%   \begin{syntax}
%     \cs{bool_do_while:nn} \Arg{boolean expression} \Arg{code}
%   \end{syntax}
%   Places the \meta{code} in the input stream for \TeX{} to process,
%   and then checks the logical value of the \meta{boolean expression}
%   as described for \cs{bool_if:nTF}.  If it is \texttt{true} then the
%   \meta{code} is inserted into the input stream again and the
%   process loops until the \meta{boolean expression} evaluates to
%   \texttt{false}.
% \end{function}
%
% \begin{function}[rEXP, updated = 2017-07-15]{\bool_until_do:nn}
%   \begin{syntax}
%     \cs{bool_until_do:nn} \Arg{boolean expression} \Arg{code}
%   \end{syntax}
%   This function first checks the logical value of the
%   \meta{boolean expression} (as described for \cs{bool_if:nTF}).
%   If it is \texttt{false} the \meta{code} is placed in the input stream
%   and expanded. After the completion of the \meta{code} the truth
%   of the \meta{boolean expression} is re-evaluated. The process
%   then loops until the \meta{boolean expression} is \texttt{true}.
% \end{function}
%
% \begin{function}[rEXP, updated = 2017-07-15]{\bool_while_do:nn}
%   \begin{syntax}
%     \cs{bool_while_do:nn} \Arg{boolean expression} \Arg{code}
%   \end{syntax}
%   This function first checks the logical value of the
%   \meta{boolean expression} (as described for \cs{bool_if:nTF}).
%   If it is \texttt{true} the \meta{code} is placed in the input stream
%   and expanded. After the completion of the \meta{code} the truth
%   of the \meta{boolean expression} is re-evaluated. The process
%   then loops until the \meta{boolean expression} is \texttt{false}.
% \end{function}
%
% \begin{function}[added = 2023-05-03, EXP, noTF]{\bool_case:n}
%   \begin{syntax}
%     \cs{bool_case:nTF} \\
%     ~~|{| \\
%     ~~~~\Arg{boolexpr case_1} \Arg{code case_1} \\
%     ~~~~\Arg{boolexpr case_2} \Arg{code case_2} \\
%     ~~~~\ldots \\
%     ~~~~\Arg{boolexpr case_n} \Arg{code case_n} \\
%     ~~|}| \\
%     ~~\Arg{true code}
%     ~~\Arg{false code}
%   \end{syntax}
%   Evaluates in turn each of the \meta{boolean expression case}s until
%   the first one that evaluates to \texttt{true}.
%   The \meta{code} associated to this first case is left in the input
%   stream, followed by the \meta{true code}, and other cases are
%   discarded.  If none of the cases match then only the \meta{false
%   code} is inserted. The function \cs{bool_case:n},
%   which does nothing if there is no match, is
%   also available. For example
%   \begin{verbatim}
%     \bool_case:nF
%       {
%         { \dim_compare_p:n { \l__mypkg_wd_dim <= 10pt } }
%             { Fits }
%         { \int_compare_p:n { \l__mypkg_total_int >= 10 } }
%             { Many }
%         { \l__mypkg_special_bool }
%             { Special }
%       }
%       { No idea! }
%   \end{verbatim}
%   leaves \enquote{\texttt{Fits}} or \enquote{\texttt{Many}} or
%   \enquote{\texttt{Special}} or \enquote{\texttt{No idea!}} in the
%   input stream, in a way similar to some other language's
%   \enquote{\texttt{if} \ldots\ \texttt{elseif} \ldots\ \texttt{elseif} \ldots\
%   \texttt{else} \ldots}.
% \end{function}
%
% \section{Producing multiple copies}
%
% \begin{function}[updated = 2011-07-04, EXP]{\prg_replicate:nn}
%   \begin{syntax}
%     \cs{prg_replicate:nn} \Arg{integer expression} \Arg{tokens}
%   \end{syntax}
%   Evaluates the \meta{integer expression} (which should be
%   zero or positive) and creates the resulting number of copies
%   of the \meta{tokens}. The function is both expandable and safe for
%   nesting. It yields its result after two expansion steps.
% \end{function}
%
% \section{Detecting \TeX{}'s mode}
%
% \begin{function}[EXP,pTF]{\mode_if_horizontal:}
%   \begin{syntax}
%     \cs{mode_if_horizontal_p:}
%     \cs{mode_if_horizontal:TF} \Arg{true code} \Arg{false code}
%   \end{syntax}
%   Detects if \TeX{} is currently in horizontal mode.
% \end{function}
%
% \begin{function}[EXP,pTF]{\mode_if_inner:}
%   \begin{syntax}
%     \cs{mode_if_inner_p:}
%     \cs{mode_if_inner:TF} \Arg{true code} \Arg{false code}
%   \end{syntax}
%   Detects if \TeX{} is currently in inner mode.
% \end{function}
%
% \begin{function}[updated = 2011-09-05, EXP,pTF]{\mode_if_math:}
%   \begin{syntax}
%     \cs{mode_if_math_p:}
%     \cs{mode_if_math:TF} \Arg{true code} \Arg{false code}
%   \end{syntax}
%   Detects if \TeX{} is currently in maths mode.
% \end{function}
%
% \begin{function}[EXP,pTF]{\mode_if_vertical:}
%   \begin{syntax}
%     \cs{mode_if_vertical_p:}
%     \cs{mode_if_vertical:TF} \Arg{true code} \Arg{false code}
%   \end{syntax}
%   Detects if \TeX{} is currently in vertical mode.
% \end{function}
%
% \section{Primitive conditionals}
%
% \begin{function}[EXP]{\if_predicate:w}
%   \begin{syntax}
%     \cs{if_predicate:w} \meta{predicate} \meta{true code} \cs{else:} \meta{false code} \cs{fi:}
%   \end{syntax}
%   This function takes a predicate function and
%   branches according to the result.  (In practice this function would also
%   accept a single boolean variable in place of the \meta{predicate} but to make the
%   coding clearer this should be done through \cs{if_bool:N}.)
% \end{function}
%
% \begin{function}[EXP]{\if_bool:N}
%   \begin{syntax}
%     \cs{if_bool:N} \meta{boolean} \meta{true code} \cs{else:} \meta{false code} \cs{fi:}
%   \end{syntax}
%   This function takes a boolean variable and
%   branches according to the result.
% \end{function}
%
% \section{Nestable recursions and mappings}
%
% There are a number of places where recursion or mapping constructs are used in
% \pkg{expl3}. At a low-level, these typically require insertion of tokens
% at the end of the content to allow \enquote{clean up}. To support such
% mappings in a nestable form, the following functions are provided.
%
% \begin{function}[EXP, added = 2018-03-26]{\prg_break_point:Nn}
%   \begin{syntax}
%     \cs{prg_break_point:Nn} \cs[no-index]{\meta{type}_map_break:} \Arg{code}
%   \end{syntax}
%   Used to mark the end of a recursion or mapping: the functions
%   \cs[no-index]{\meta{type}_map_break:} and
%   \cs[no-index]{\meta{type}_map_break:n} use this to break out of the loop
%   (see \cs{prg_map_break:Nn} for how to set these up).
%   After the loop ends, the \meta{code} is inserted into the input stream. This
%   occurs even if the break functions are \emph{not} applied:
%   \cs{prg_break_point:Nn} is functionally-equivalent in these cases
%   to \cs{use_ii:nn}.
% \end{function}
%
% \begin{function}[EXP, added = 2018-03-26]{\prg_map_break:Nn}
%   \begin{syntax}
%     \cs{prg_map_break:Nn} \cs[no-index]{\meta{type}_map_break:} \Arg{user code}
%     \ldots{}
%     \cs{prg_break_point:Nn} \cs[no-index]{\meta{type}_map_break:} \Arg{ending code}
%   \end{syntax}
%   Breaks a recursion in mapping contexts, inserting in the input
%   stream the \meta{user code} after the \meta{ending code} for the
%   loop.  The function breaks loops, inserting their \meta{ending
%   code}, until reaching a loop with the same \meta{type} as its
%   first argument.  This \cs[no-index]{\meta{type}_map_break:} argument
%   must be defined; it is simply used as a recognizable marker for the \meta{type}.
%
%   For types with mappings defined in the kernel,
%   \cs[no-index]{\meta{type}_map_break:} and \cs[no-index]{\meta{type}_map_break:n}
%   are defined as \cs{prg_map_break:Nn} \cs[no-index]{\meta{type}_map_break:} |{}|
%   and the same with |{}| omitted.
% \end{function}
%
% \subsection{Simple mappings}
%
% In addition to the more complex mappings above, non-nestable mappings are
% used in a number of locations and support is provided for these.
%
% \begin{function}[EXP, added = 2018-03-27]{\prg_break_point:}
%   This copy of \cs{prg_do_nothing:} is used to mark the end of a fast
%   short-term recursion: the function \cs{prg_break:n} uses this to
%   break out of the loop.
% \end{function}
%
% \begin{function}[EXP, added = 2018-03-27]{\prg_break:, \prg_break:n}
%   \begin{syntax}
%     \cs{prg_break:n} \Arg{code} \ldots{} \cs{prg_break_point:}
%   \end{syntax}
%   Breaks a recursion which has no \meta{ending code} and which is not
%   a user-breakable mapping (see for instance
%   implementation of \cs{int_step_function:nnnN}), and
%   inserts the \meta{code} in the input stream.
% \end{function}
%
% \section{Internal programming functions}
%
% \begin{function}[updated = 2011-08-11, EXP]
%   {\group_align_safe_begin:, \group_align_safe_end:}
%   \begin{syntax}
%     \cs{group_align_safe_begin:}
%     \ldots
%     \cs{group_align_safe_end:}
%   \end{syntax}
%   These functions are used to enclose material in a \TeX{} alignment
%   environment within a specially-constructed group. This group is
%   designed in such a way that it does not add brace groups to the
%   output but does act as a group for the |&| token inside
%   \tn{halign}. This is necessary to allow grabbing of tokens
%   for testing purposes, as \TeX{} uses group level to determine the
%   effect of alignment tokens. Without the special grouping, the use of
%   a function such as \cs{peek_after:Nw} would result in a forbidden
%   comparison of the internal \tn{endtemplate} token, yielding a
%    fatal error. Each \cs{group_align_safe_begin:} must be matched by a
%   \cs{group_align_safe_end:}, although this does not have to occur
%   within the same function.
% \end{function}
%
% \end{documentation}
%
% \begin{implementation}
%
% \section{\pkg{l3prg} implementation}
%
% \TestFiles{m3prg001.lvt,m3prg002.lvt,m3prg003.lvt}
%
%    \begin{macrocode}
%<*code>
%    \end{macrocode}
%
% \subsection{Primitive conditionals}
%
% \begin{macro}{\if_bool:N}
% \begin{macro}{\if_predicate:w}
%   Those two primitive \TeX{} conditionals are synonyms.
%   \cs{if_bool:N} is defined in \pkg{l3basics}, as it's needed
%   earlier to define quark test functions.
%    \begin{macrocode}
\cs_new_eq:NN \if_predicate:w \tex_ifodd:D
%    \end{macrocode}
% \end{macro}
% \end{macro}
%
% \subsection{Defining a set of conditional functions}
%
% \begin{macro}
%   {
%     \prg_set_conditional:Npnn,
%     \prg_new_conditional:Npnn,
%     \prg_set_protected_conditional:Npnn,
%     \prg_new_protected_conditional:Npnn
%   }
% \begin{macro}
%   {
%     \prg_set_conditional:Nnn,
%     \prg_new_conditional:Nnn,
%     \prg_set_protected_conditional:Nnn,
%     \prg_new_protected_conditional:Nnn
%   }
% \begin{macro}{\prg_set_eq_conditional:NNn, \prg_new_eq_conditional:NNn}
% \begin{macro}{\prg_return_true:}
% \TestMissing
%   {This function is implicitly tested with all other conditionals!}
% \begin{macro}{\prg_return_false:}
% \TestMissing
%   {This function is also implicitly tested with all other conditionals!}
%   These are all defined in \pkg{l3basics}, as they are needed
%   \enquote{early}. This is just a reminder!
% \end{macro}
% \end{macro}
% \end{macro}
% \end{macro}
% \end{macro}
%
% \subsection{The boolean data type}
%
%    \begin{macrocode}
%<@@=bool>
%    \end{macrocode}
%
% \begin{macro}{\bool_new:N, \bool_new:c}
% \UnitTested
%   Boolean variables have to be initiated when they are created. Other
%   than that there is not much to say here.
%    \begin{macrocode}
\cs_new_protected:Npn \bool_new:N #1 { \cs_new_eq:NN #1 \c_false_bool }
\cs_generate_variant:Nn \bool_new:N { c }
%    \end{macrocode}
% \end{macro}
%
% \begin{macro}[added = 2017-11-28]{\bool_const:Nn, \bool_const:cn}
%   A merger between \cs{tl_const:Nn} and \cs{bool_set:Nn}.
%    \begin{macrocode}
\cs_new_protected:Npn \bool_const:Nn #1#2
  {
    \__kernel_chk_if_free_cs:N #1
    \tex_global:D \tex_chardef:D #1 = \bool_if_p:n {#2}
  }
\cs_generate_variant:Nn \bool_const:Nn { c }
%    \end{macrocode}
% \end{macro}
%
% \begin{macro}
%   {
%     \bool_set_true:N,   \bool_set_true:c,
%     \bool_gset_true:N,  \bool_gset_true:c,
%     \bool_set_false:N,  \bool_set_false:c,
%     \bool_gset_false:N, \bool_gset_false:c
%   }
% \UnitTested
%   Setting is already pretty easy.
%   When \texttt{check-declarations} is active, the definitions are patched to
%   make sure the boolean exists.  This is needed because booleans are
%   not based on token lists nor on \TeX{} registers.
%    \begin{macrocode}
\cs_new_protected:Npn \bool_set_true:N #1
  { \cs_set_eq:NN #1 \c_true_bool }
\cs_new_protected:Npn \bool_set_false:N #1
  { \cs_set_eq:NN #1 \c_false_bool }
\cs_new_protected:Npn \bool_gset_true:N #1
  { \cs_gset_eq:NN #1 \c_true_bool }
\cs_new_protected:Npn \bool_gset_false:N #1
  { \cs_gset_eq:NN #1 \c_false_bool }
\cs_generate_variant:Nn \bool_set_true:N   { c }
\cs_generate_variant:Nn \bool_set_false:N  { c }
\cs_generate_variant:Nn \bool_gset_true:N  { c }
\cs_generate_variant:Nn \bool_gset_false:N { c }
%    \end{macrocode}
% \end{macro}
%
% \begin{macro}
%   {
%     \bool_set_eq:NN,  \bool_set_eq:cN,
%     \bool_set_eq:Nc,  \bool_set_eq:cc,
%     \bool_gset_eq:NN, \bool_gset_eq:cN,
%     \bool_gset_eq:Nc, \bool_gset_eq:cc
%   }
% \UnitTested
%   The usual copy code.  While it would be cleaner semantically to copy
%   the \cs{cs_set_eq:NN} family of functions, we copy \cs{tl_set_eq:NN}
%   because that has the correct checking code.
%    \begin{macrocode}
\cs_new_eq:NN \bool_set_eq:NN  \tl_set_eq:NN
\cs_new_eq:NN \bool_gset_eq:NN \tl_gset_eq:NN
\cs_generate_variant:Nn \bool_set_eq:NN { Nc, cN, cc }
\cs_generate_variant:Nn \bool_gset_eq:NN { Nc, cN, cc }
%    \end{macrocode}
% \end{macro}
%
% \begin{macro}{\bool_set:Nn, \bool_set:cn}
% \begin{macro}{\bool_gset:Nn, \bool_gset:cn}
%   This function evaluates a boolean expression and assigns the first
%   argument the meaning \cs{c_true_bool} or \cs{c_false_bool}.  Again,
%   we include some checking code.  It is important to evaluate the
%   expression before applying the \tn{chardef} primitive, because that
%   primitive sets the left-hand side to \cs{scan_stop:} before looking
%   for the right-hand side.
%    \begin{macrocode}
\cs_new_protected:Npn \bool_set:Nn #1#2
  {
    \exp_last_unbraced:NNNf
      \tex_chardef:D #1 = { \bool_if_p:n {#2} }
  }
\cs_new_protected:Npn \bool_gset:Nn #1#2
  {
    \exp_last_unbraced:NNNNf
      \tex_global:D \tex_chardef:D #1 = { \bool_if_p:n {#2} }
  }
\cs_generate_variant:Nn \bool_set:Nn  { c }
\cs_generate_variant:Nn \bool_gset:Nn { c }
%    \end{macrocode}
% \end{macro}
% \end{macro}
%
% \begin{macro}[added = 2018-05-10]
%   {\bool_set_inverse:N, \bool_set_inverse:c, \bool_gset_inverse:N, \bool_gset_inverse:c}
%   Set to \texttt{false} or \texttt{true} locally or globally.
%    \begin{macrocode}
\cs_new_protected:Npn \bool_set_inverse:N #1
  { \bool_if:NTF #1 { \bool_set_false:N } { \bool_set_true:N } #1 }
\cs_generate_variant:Nn \bool_set_inverse:N { c }
\cs_new_protected:Npn \bool_gset_inverse:N #1
  { \bool_if:NTF #1 { \bool_gset_false:N } { \bool_gset_true:N } #1 }
\cs_generate_variant:Nn \bool_gset_inverse:N { c }
%    \end{macrocode}
% \end{macro}
%
% \subsection{Internal auxiliaries}
%
% \begin{variable}{\q_@@_recursion_tail,\q_@@_recursion_stop}
%   Internal recursion quarks.
%    \begin{macrocode}
\quark_new:N \q_@@_recursion_tail
\quark_new:N \q_@@_recursion_stop
%    \end{macrocode}
% \end{variable}
%
% \begin{macro}[EXP]{\@@_use_i_delimit_by_q_recursion_stop:nw}
%   Functions to gobble up to a quark.
%    \begin{macrocode}
\cs_new:Npn \@@_use_i_delimit_by_q_recursion_stop:nw
  #1 #2 \q_@@_recursion_stop {#1}
%    \end{macrocode}
% \end{macro}
%
% \begin{macro}[EXP]{\@@_if_recursion_tail_stop_do:nn}
%   Functions to query recursion quarks.
%    \begin{macrocode}
\__kernel_quark_new_test:N \@@_if_recursion_tail_stop_do:nn
%    \end{macrocode}
% \end{macro}
%
% \begin{macro}[pTF]{\bool_if:N, \bool_if:c}
% \UnitTested
%  Straight forward here. We could optimize here if we wanted to as
%  the boolean can just be input directly.
%    \begin{macrocode}
\prg_new_conditional:Npnn \bool_if:N #1 { p , T , F , TF }
  {
    \if_bool:N #1
      \prg_return_true:
    \else:
      \prg_return_false:
    \fi:
  }
\prg_generate_conditional_variant:Nnn \bool_if:N { c } { p , T , F , TF }
%    \end{macrocode}
% \end{macro}
%
% \begin{macro}[EXP]{\bool_to_str:N, \bool_to_str:c, \bool_to_str:n}
%   Expands to string literal \texttt{true} or \texttt{false}.
%    \begin{macrocode}
\cs_new:Npe \bool_to_str:N #1
  {
    \exp_not:N \bool_if:NTF #1
      { \tl_to_str:n { true } } { \tl_to_str:n { false } }
  }
\cs_generate_variant:Nn \bool_to_str:N { c }
\cs_new:Npe \bool_to_str:n #1
  {
    \exp_not:N \bool_if:nTF {#1}
      { \tl_to_str:n { true } } { \tl_to_str:n { false } }
  }
%    \end{macrocode}
% \end{macro}
%
% \begin{macro}{\bool_show:n, \bool_log:n}
%   Show the truth value of the boolean.
%    \begin{macrocode}
\cs_new_protected:Npn \bool_show:n
  { \__kernel_msg_show_eval:Nn \bool_to_str:n }
\cs_new_protected:Npn \bool_log:n
  { \__kernel_msg_log_eval:Nn \bool_to_str:n }
%    \end{macrocode}
% \end{macro}
%
% \begin{macro}{\bool_show:N, \bool_show:c, \bool_log:N, \bool_log:c, \@@_show:NN}
%   Show the truth value of the boolean, as \texttt{true} or
%   \texttt{false}.
%    \begin{macrocode}
\cs_new_protected:Npn \bool_show:N { \@@_show:NN \tl_show:n }
\cs_generate_variant:Nn \bool_show:N { c }
\cs_new_protected:Npn \bool_log:N { \@@_show:NN \tl_log:n }
\cs_generate_variant:Nn \bool_log:N { c }
\cs_new_protected:Npn \@@_show:NN #1#2
  {
    \__kernel_chk_defined:NT #2
      {
        \token_case_meaning:NnF #2
          {
            \c_true_bool { \exp_args:Ne #1 { \token_to_str:N #2 = true } }
            \c_false_bool { \exp_args:Ne #1 { \token_to_str:N #2 = false } }
          }
          {
            \msg_error:nneee { kernel } { bad-type }
              { \token_to_str:N #2 } { \token_to_meaning:N #2 } { bool }
          }
      }
  }
%    \end{macrocode}
% \end{macro}
%
% \begin{variable}{\l_tmpa_bool, \l_tmpb_bool, \g_tmpa_bool, \g_tmpb_bool}
%    A few booleans just if you need them.
%    \begin{macrocode}
\bool_new:N \l_tmpa_bool
\bool_new:N \l_tmpb_bool
\bool_new:N \g_tmpa_bool
\bool_new:N \g_tmpb_bool
%    \end{macrocode}
% \end{variable}
%
% \begin{macro}[pTF]{\bool_if_exist:N, \bool_if_exist:c}
%   Copies of the \texttt{cs} functions defined in \pkg{l3basics}.
%    \begin{macrocode}
\prg_new_eq_conditional:NNn \bool_if_exist:N \cs_if_exist:N
  { TF , T , F , p }
\prg_new_eq_conditional:NNn \bool_if_exist:c \cs_if_exist:c
  { TF , T , F , p }
%    \end{macrocode}
% \end{macro}
%
% \subsection{Boolean expressions}
%
% \begin{macro}[pTF]{\bool_if:n}
% \UnitTested
%   Evaluating the truth value of a list of predicates is done using an
%   input syntax somewhat similar to the one found in other programming
%   languages with |(| and |)| for grouping, |!| for logical
%   \enquote{Not}, |&&| for logical \enquote{And} and \verb"||" for
%   logical \enquote{Or}.  However, they perform eager evaluation.
%   We shall use the terms Not, And, Or, Open and
%   Close for these operations.
%
%   Any expression is terminated by a Close operation. Evaluation
%   happens from left to right in the following manner using a GetNext
%   function:
%   \begin{itemize}
%     \item If an Open is seen, start evaluating a new expression using
%       the Eval function and call GetNext again.
%     \item If a Not is seen, remove the |!| and call a GetNext
%       function with the logic reversed.
%     \item If none of the above, reinsert the token found (this is
%       supposed to be a predicate function) in front of an Eval
%       function, which evaluates it to the boolean value \meta{true} or
%       \meta{false}.
%   \end{itemize}
%   The Eval function then contains a post-processing operation which
%   grabs the instruction following the predicate.  This is either And,
%   Or or Close.  In each case the truth value is used to determine
%   where to go next.  The following situations can arise:
%   \begin{description}
%     \item[\meta{true}And] Current truth value is true, logical And
%       seen, continue with GetNext to examine truth value of next
%       boolean (sub-)expression.
%     \item[\meta{false}And] Current truth value is false, logical And
%       seen, stop using the values of predicates within this
%       sub-expression until the next Close. Then return \meta{false}.
%     \item[\meta{true}Or] Current truth value is true, logical Or seen,
%       stop using the values of predicates within this sub-expression
%       until the nearest Close. Then return \meta{true}.
%     \item[\meta{false}Or] Current truth value is false, logical Or
%       seen, continue with GetNext to examine truth value of next
%       boolean (sub-)expression.
%     \item[\meta{true}Close] Current truth value is true, Close
%       seen, return \meta{true}.
%     \item[\meta{false}Close] Current truth value is false, Close
%       seen, return \meta{false}.
%   \end{description}
%    \begin{macrocode}
\prg_new_conditional:Npnn \bool_if:n #1 { T , F , TF }
  {
    \if_predicate:w \bool_if_p:n {#1}
      \prg_return_true:
    \else:
      \prg_return_false:
    \fi:
  }
%    \end{macrocode}
% \end{macro}
%
% \begin{macro}[EXP]{\bool_if_p:n, \@@_if_p:n, \@@_if_p_aux:w}
%   To speed up the case of a single predicate, \texttt{f}-expand and
%   check whether the result is one token (possibly surrounded by
%   spaces), which must be \cs{c_true_bool} or \cs{c_false_bool}.  We
%   use a version of \cs{tl_if_single:nTF} optimized for speed since we
%   know that an empty~|#1| is an error.  The auxiliary
%   \cs{@@_if_p_aux:w} removes the trailing parenthesis and gets rid of
%   any space, then returns \cs{c_true_bool} or \cs{c_false_bool} as
%   appropriate.  This extra work around is because in a
%   \cs{bool_set:Nn}, the underlying \tn{chardef} turns the bool being
%   set temporarily equal to \tn{relax}, thus assigning a boolean to
%   itself would fail (gh/1055).  For the general case, first issue a
%   \cs{group_align_safe_begin:} as we are using |&&| as
%   syntax shorthand for the And operation and we need to hide it for
%   \TeX{}.  This group is closed after \cs{@@_get_next:NN} returns
%   \cs{c_true_bool} or \cs{c_false_bool}.  That function requires the
%   trailing parenthesis to know where the expression ends.
%    \begin{macrocode}
\cs_new:Npn \bool_if_p:n { \exp_args:Nf \@@_if_p:n }
\cs_new:Npn \@@_if_p:n #1
  {
    \tl_if_empty:oT { \use_none:nn #1 . } { \@@_if_p_aux:w }
    \group_align_safe_begin:
    \exp_after:wN
    \group_align_safe_end:
    \exp:w \exp_end_continue_f:w % (
    \@@_get_next:NN \use_i:nnnn #1 )
  }
\cs_new:Npn \@@_if_p_aux:w #1 \use_i:nnnn #2#3
  { \bool_if:NTF #2 \c_true_bool \c_false_bool }
%    \end{macrocode}
% \end{macro}
%
% \begin{macro}{\@@_get_next:NN}
%   The GetNext operation.  Its first argument is \cs{use_i:nnnn},
%   \cs{use_ii:nnnn}, \cs{use_iii:nnnn}, or \cs{use_iv:nnnn} (we call
%   these \enquote{states}).  In the first state, this function
%   eventually expand to the truth value \cs{c_true_bool} or
%   \cs{c_false_bool} of the expression which follows until the next
%   unmatched closing parenthesis.  For instance
%   \enquote{\cs{@@_get_next:NN} \cs{use_i:nnnn} \cs{c_true_bool}
%   \texttt{\&\&} \cs{c_true_bool} \texttt{)}} (including the closing
%   parenthesis) expands to \cs{c_true_bool}.  In the second state
%   (after a |!|) the logic is reversed.  We call these two states
%   \enquote{normal} and the next two \enquote{skipping}.  In the third
%   state (after \cs{c_true_bool}\verb"||") it always returns
%   \cs{c_true_bool}.  In the fourth state (after \cs{c_false_bool}|&&|)
%   it always returns \cs{c_false_bool} and also stops when encountering
%   \verb"||", not only parentheses.  This code itself is a switch: if
%   what follows is neither |!| nor |(|, we assume it is a predicate.
%    \begin{macrocode}
\cs_new:Npn \@@_get_next:NN #1#2
  {
    \use:c
      {
        @@_
        \if_meaning:w !#2 ! \else: \if_meaning:w (#2 ( \else: p \fi: \fi:
        :Nw
      }
      #1 #2
  }
%    \end{macrocode}
% \end{macro}
%
% \begin{macro}{\@@_!:Nw}
%   The Not operation reverses the logic: it discards the |!|~token and
%   calls the GetNext operation with the appropriate first argument.
%   Namely the first and second states are interchanged, but after
%   \cs{c_true_bool}\verb"||" or \cs{c_false_bool}|&&| the |!|~is
%   ignored.
%    \begin{macrocode}
\cs_new:cpn { @@_!:Nw } #1#2
  {
    \exp_after:wN \@@_get_next:NN
    #1 \use_ii:nnnn \use_i:nnnn \use_iii:nnnn \use_iv:nnnn
  }
%    \end{macrocode}
% \end{macro}
%
% \begin{macro}{\@@_(:Nw}
%   The Open operation starts a sub-expression after discarding the open
%   parenthesis.  This is done by calling GetNext (which eventually
%   discards the corresponding closing parenthesis), with a
%   post-processing step which looks for And, Or or Close after the
%   group.
%    \begin{macrocode}
\cs_new:cpn { @@_(:Nw } #1#2
  {
    \exp_after:wN \@@_choose:NNN \exp_after:wN #1
    \int_value:w \@@_get_next:NN \use_i:nnnn
  }
%    \end{macrocode}
% \end{macro}
%
% \begin{macro}{\@@_p:Nw}
%   If what follows GetNext is neither |!| nor |(|, evaluate the
%   predicate using the primitive \cs{int_value:w}.  The canonical
%   \texttt{true} and \texttt{false} values have numerical values $1$
%   and $0$ respectively.  Look for And, Or or Close afterwards.
%    \begin{macrocode}
\cs_new:cpn { @@_p:Nw } #1
  { \exp_after:wN \@@_choose:NNN \exp_after:wN #1 \int_value:w }
%    \end{macrocode}
% \end{macro}
%
% \begin{macro}{\@@_choose:NNN}
% \begin{macro}+\@@_)_0:+
% \begin{macro}+\@@_)_1:+
% \begin{macro}+\@@_)_2:+
% \begin{macro}+\@@_&_0:+
% \begin{macro}+\@@_&_1:+
% \begin{macro}+\@@_&_2:+
% \begin{macro}+\@@_|_0:+
% \begin{macro}+\@@_|_1:+
% \begin{macro}+\@@_|_2:+
%   The arguments are |#1|: a function such as \cs{use_i:nnnn}, |#2|:
%   $0$ or $1$ encoding the current truth value, |#3|: the next
%   operation, And, Or or Close.  We distinguish three cases according
%   to a combination of |#1| and |#2|.  Case~2 is when |#1| is
%   \cs{use_iii:nnnn} (state~3), namely after
%   \cs{c_true_bool}~\verb"||".  Case~1 is when |#1| is \cs{use_i:nnnn}
%   and |#2| is \texttt{true} or when |#1| is \cs{use_ii:nnnn} and |#2|
%   is \texttt{false}, for instance for |!|\cs{c_false_bool}.  Case~0
%   includes the same with \texttt{true}/\texttt{false} interchanged and
%   the case where |#1| is \cs{use_iv:nnnn} namely after
%   \cs{c_false_bool}~|&&|.
%
%   When seeing~|)| the current subexpression is done, leave the
%   appropriate boolean.  When seeing~|&| in case~0 go into state~4,
%   equivalent to having seen \cs{c_false_bool}~|&&|.  In case~1, namely
%   when the argument is \texttt{true} and we are in a normal state
%   continue in the normal state~1.  In case~2, namely when skipping
%   alternatives in an Or, continue in the same state.  When
%   seeing~\verb"|" in case~0, continue in a normal state; in particular
%   stop skipping for \cs{c_false_bool}~|&&| because that binds more
%   tightly than~\verb"||".  In the other two cases start skipping for
%   \cs{c_true_bool}~\verb"||".
%    \begin{macrocode}
\cs_new:Npn \@@_choose:NNN #1#2#3
  {
    \use:c
      {
        @@_ \token_to_str:N #3 _
        #1 #2 { \if_meaning:w 0 #2 1 \else: 0 \fi: } 2 0 :
      }
  }
\cs_new:cpn { @@_)_0: } { \c_false_bool }
\cs_new:cpn { @@_)_1: } { \c_true_bool }
\cs_new:cpn { @@_)_2: } { \c_true_bool }
\cs_new:cpn { @@_&_0: } & { \@@_get_next:NN \use_iv:nnnn }
\cs_new:cpn { @@_&_1: } & { \@@_get_next:NN \use_i:nnnn }
\cs_new:cpn { @@_&_2: } & { \@@_get_next:NN \use_iii:nnnn }
\cs_new:cpn { @@_|_0: } | { \@@_get_next:NN \use_i:nnnn }
\cs_new:cpn { @@_|_1: } | { \@@_get_next:NN \use_iii:nnnn }
\cs_new:cpn { @@_|_2: } | { \@@_get_next:NN \use_iii:nnnn }
%    \end{macrocode}
% \end{macro}
% \end{macro}
% \end{macro}
% \end{macro}
% \end{macro}
% \end{macro}
% \end{macro}
% \end{macro}
% \end{macro}
% \end{macro}
%
% \begin{macro}[pTF]{\bool_lazy_all:n}
% \begin{macro}{\@@_lazy_all:n}
% \UnitTested
%   Go through the list of expressions, stopping whenever an expression
%   is \texttt{false}.  If the end is reached without finding any
%   \texttt{false} expression, then the result is \texttt{true}.
%    \begin{macrocode}
\cs_new:Npn \bool_lazy_all_p:n #1
  { \@@_lazy_all:n #1 \q_@@_recursion_tail \q_@@_recursion_stop }
\prg_new_conditional:Npnn \bool_lazy_all:n #1 { T , F , TF }
  {
    \if_predicate:w \bool_lazy_all_p:n {#1}
      \prg_return_true:
    \else:
      \prg_return_false:
    \fi:
  }
\cs_new:Npn \@@_lazy_all:n #1
  {
    \@@_if_recursion_tail_stop_do:nn {#1} { \c_true_bool }
    \bool_if:nF {#1}
      { \@@_use_i_delimit_by_q_recursion_stop:nw { \c_false_bool } }
    \@@_lazy_all:n
  }
%    \end{macrocode}
% \end{macro}
% \end{macro}
%
% \begin{macro}[pTF]{\bool_lazy_and:nn}
% \UnitTested
%   Only evaluate the second expression if the first is \texttt{true}.
%   Note that |#2| must be removed as an argument, not just by skipping
%   to the \cs{else:} branch of the conditional since |#2| may contain
%   unbalanced \TeX{} conditionals.
%    \begin{macrocode}
\prg_new_conditional:Npnn \bool_lazy_and:nn #1#2 { p , T , F , TF }
  {
    \if_predicate:w
        \bool_if:nTF {#1} { \bool_if_p:n {#2} } { \c_false_bool }
      \prg_return_true:
    \else:
      \prg_return_false:
    \fi:
  }
%    \end{macrocode}
% \end{macro}
%
% \begin{macro}[pTF]{\bool_lazy_any:n}
% \begin{macro}{\@@_lazy_any:n}
% \UnitTested
%   Go through the list of expressions, stopping whenever an expression
%   is \texttt{true}.  If the end is reached without finding any
%   \texttt{true} expression, then the result is \texttt{false}.
%    \begin{macrocode}
\cs_new:Npn \bool_lazy_any_p:n #1
  { \@@_lazy_any:n #1 \q_@@_recursion_tail \q_@@_recursion_stop }
\prg_new_conditional:Npnn \bool_lazy_any:n #1 { T , F , TF }
  {
    \if_predicate:w \bool_lazy_any_p:n {#1}
      \prg_return_true:
    \else:
      \prg_return_false:
    \fi:
  }
\cs_new:Npn \@@_lazy_any:n #1
  {
    \@@_if_recursion_tail_stop_do:nn {#1} { \c_false_bool }
    \bool_if:nT {#1}
      { \@@_use_i_delimit_by_q_recursion_stop:nw { \c_true_bool } }
    \@@_lazy_any:n
  }
%    \end{macrocode}
% \end{macro}
% \end{macro}
%
% \begin{macro}[pTF]{\bool_lazy_or:nn}
% \UnitTested
%   Only evaluate the second expression if the first is \texttt{false}.
%    \begin{macrocode}
\prg_new_conditional:Npnn \bool_lazy_or:nn #1#2 { p , T , F , TF }
  {
    \if_predicate:w
        \bool_if:nTF {#1} { \c_true_bool } { \bool_if_p:n {#2} }
      \prg_return_true:
    \else:
      \prg_return_false:
    \fi:
  }
%    \end{macrocode}
% \end{macro}
%
% \begin{macro}{\bool_not_p:n}
% \UnitTested
%   The Not variant just reverses the outcome of \cs{bool_if_p:n}. Can
%   be optimized but this is nice and simple and according to the
%   implementation plan. Not even particularly useful to have it when
%   the infix notation is easier to use.
%    \begin{macrocode}
\cs_new:Npn \bool_not_p:n #1 { \bool_if_p:n { ! ( #1 ) } }
%    \end{macrocode}
% \end{macro}
%
% \begin{macro}[pTF]{\bool_xor:nn}
% \UnitTested
%    Exclusive or. If the boolean expressions have same truth value,
%    return \texttt{false}, otherwise return \texttt{true}.
%    \begin{macrocode}
\prg_new_conditional:Npnn \bool_xor:nn #1#2 { p , T , F , TF }
  {
    \bool_if:nT {#1} \reverse_if:N
    \if_predicate:w \bool_if_p:n {#2}
      \prg_return_true:
    \else:
      \prg_return_false:
    \fi:
  }
%    \end{macrocode}
% \end{macro}
%
% \subsection{Logical loops}
%
% \begin{macro}{\bool_while_do:Nn, \bool_while_do:cn}
% \UnitTested
% \begin{macro}{\bool_until_do:Nn, \bool_until_do:cn}
% \UnitTested
%   A |while| loop where the boolean is tested before executing the
%   statement. The \enquote{while} version executes the code as long as the
%   boolean is true; the \enquote{until} version executes the code as
%   long as the boolean is false.
%    \begin{macrocode}
\cs_new:Npn \bool_while_do:Nn #1#2
  { \bool_if:NT #1 { #2 \bool_while_do:Nn #1 {#2} } }
\cs_new:Npn \bool_until_do:Nn #1#2
  { \bool_if:NF #1 { #2 \bool_until_do:Nn #1 {#2} } }
\cs_generate_variant:Nn \bool_while_do:Nn { c }
\cs_generate_variant:Nn \bool_until_do:Nn { c }
%    \end{macrocode}
% \end{macro}
% \end{macro}
%
% \begin{macro}{\bool_do_while:Nn, \bool_do_while:cn}
% \UnitTested
% \begin{macro}{\bool_do_until:Nn, \bool_do_until:cn}
% \UnitTested
%   A |do-while| loop where the body is performed at least once and the
%   boolean is tested after executing the body. Otherwise identical to
%   the above functions.
%    \begin{macrocode}
\cs_new:Npn \bool_do_while:Nn #1#2
  { #2 \bool_if:NT #1 { \bool_do_while:Nn #1 {#2} } }
\cs_new:Npn \bool_do_until:Nn #1#2
  { #2 \bool_if:NF #1 { \bool_do_until:Nn #1 {#2} } }
\cs_generate_variant:Nn \bool_do_while:Nn { c }
\cs_generate_variant:Nn \bool_do_until:Nn { c }
%    \end{macrocode}
% \end{macro}
% \end{macro}
%
% \begin{macro}
%   {
%     \bool_while_do:nn, \bool_do_while:nn ,
%     \bool_until_do:nn, \bool_do_until:nn
%   }
%   \UnitTested
%   Loop functions with the test either before or after the first body
%   expansion.
%    \begin{macrocode}
\cs_new:Npn \bool_while_do:nn #1#2
  {
    \bool_if:nT {#1}
      {
        #2
        \bool_while_do:nn {#1} {#2}
      }
  }
\cs_new:Npn \bool_do_while:nn #1#2
  {
    #2
    \bool_if:nT {#1} { \bool_do_while:nn {#1} {#2} }
  }
\cs_new:Npn \bool_until_do:nn #1#2
  {
    \bool_if:nF {#1}
      {
        #2
        \bool_until_do:nn {#1} {#2}
      }
  }
\cs_new:Npn \bool_do_until:nn #1#2
  {
    #2
    \bool_if:nF {#1} { \bool_do_until:nn {#1} {#2}  }
  }
%    \end{macrocode}
% \end{macro}
%
% \begin{variable}{\s_@@_mark,\s_@@_stop}
%   Internal scan marks.
%    \begin{macrocode}
\scan_new:N \s_@@_mark
\scan_new:N \s_@@_stop
%    \end{macrocode}
% \end{variable}
%
% \begin{macro}[EXP, noTF]{\bool_case:n}
% \begin{macro}{\@@_case:NnTF}
% \begin{macro}{\@@_case:w,a\@@_case_end:nw}
%   For boolean cases the overall idea is the same as for
%   \cs{str_case:nnTF} as described in \pkg{l3str}.
%    \begin{macrocode}
\cs_new:Npn \bool_case:nTF
  { \exp:w \@@_case:nTF }
\cs_new:Npn \bool_case:nT #1#2
  { \exp:w \@@_case:nTF {#1} {#2} { } }
\cs_new:Npn \bool_case:nF #1
  { \exp:w \@@_case:nTF {#1} { } }
\cs_new:Npn \bool_case:n #1
  { \exp:w \@@_case:nTF {#1} { } { } }
\cs_new:Npn \@@_case:nTF #1#2#3
  {
    \@@_case:w
    #1 \c_true_bool { } \s_@@_mark {#2} \s_@@_mark {#3} \s_@@_stop
  }
\cs_new:Npn \@@_case:w #1#2
  {
    \bool_if:nTF {#1}
      { \@@_case_end:nw {#2} }
      { \@@_case:w }
  }
\cs_new:Npn \@@_case_end:nw #1#2#3 \s_@@_mark #4#5 \s_@@_stop
  { \exp_end: #1 #4 }
%    \end{macrocode}
% \end{macro}
% \end{macro}
% \end{macro}
%
% \subsection{Producing multiple copies}
%
%    \begin{macrocode}
%<@@=prg>
%    \end{macrocode}
%
% \begin{macro}{\prg_replicate:nn}
% \UnitTested
% \begin{macro}{\@@_replicate:N, \@@_replicate_first:N}
% \begin{macro}{\@@_replicate_}
% \begin{macro}
%   {
%     \@@_replicate_0:n,
%     \@@_replicate_1:n,
%     \@@_replicate_2:n,
%     \@@_replicate_3:n,
%     \@@_replicate_4:n,
%     \@@_replicate_5:n,
%     \@@_replicate_6:n,
%     \@@_replicate_7:n,
%     \@@_replicate_8:n,
%     \@@_replicate_9:n
%   }
% \begin{macro}
%   {
%     \@@_replicate_first_-:n,
%     \@@_replicate_first_0:n,
%     \@@_replicate_first_1:n,
%     \@@_replicate_first_2:n,
%     \@@_replicate_first_3:n,
%     \@@_replicate_first_4:n,
%     \@@_replicate_first_5:n,
%     \@@_replicate_first_6:n,
%     \@@_replicate_first_7:n,
%     \@@_replicate_first_8:n,
%     \@@_replicate_first_9:n
%   }
%   This function uses a cascading csname technique by David Kastrup
%   (who else :-)
%
%   The idea is to make the input |25| result in first adding five, and
%   then 20 copies of the code to be replicated. The technique uses
%   cascading csnames which means that we start building several csnames
%   so we end up with a list of functions to be called in reverse
%   order. This is important here (and other places) because it means
%   that we can for instance make the function that inserts five copies
%   of something to also hand down ten to the next function in
%   line. This is exactly what happens here: in the example with |25|
%   then the next function is the one that inserts two copies but it
%   sees the ten copies handed down by the previous function. In order
%   to avoid the last function to insert say, $100$ copies of the original
%   argument just to gobble them again we define separate functions to
%   be inserted first. These functions also close the expansion of
%   \cs{exp:w}, which ensures that \cs{prg_replicate:nn} only
%   requires two steps of expansion.
%
%   This function has one flaw though: Since it constantly passes down
%   ten copies of its previous argument it severely affects the main
%   memory once you start demanding hundreds of thousands of copies. Now
%   I don't think this is a real limitation for any ordinary use, and if
%   necessary, it is possible to write \cs{prg_replicate:nn} |{1000}|
%   |{| \cs{prg_replicate:nn} |{1000}| \Arg{code}~|}|. An
%   alternative approach is to create a string of |m|'s with
%   \cs{exp:w} which can be done with just four macros but that
%   method has its own problems since it can exhaust the string
%   pool. Also, it is considerably slower than what we use here so the
%   few extra csnames are well spent I would say.
%    \begin{macrocode}
\cs_new:Npn \prg_replicate:nn #1
  {
    \exp:w
      \exp_after:wN \@@_replicate_first:N
      \int_value:w \int_eval:n {#1}
      \cs_end:
  }
\cs_new:Npn \@@_replicate:N #1
  { \cs:w @@_replicate_#1 :n \@@_replicate:N }
\cs_new:Npn \@@_replicate_first:N #1
  { \cs:w @@_replicate_first_ #1 :n \@@_replicate:N }
%    \end{macrocode}
%   Then comes all the functions that do the hard work of inserting all
%   the copies.  The first function takes |:n| as a parameter.
%    \begin{macrocode}
\cs_new:Npn \@@_replicate_ :n #1 { \cs_end: }
\cs_new:cpn { @@_replicate_0:n } #1
  { \cs_end: {#1#1#1#1#1#1#1#1#1#1} }
\cs_new:cpn { @@_replicate_1:n } #1
  { \cs_end: {#1#1#1#1#1#1#1#1#1#1} #1 }
\cs_new:cpn { @@_replicate_2:n } #1
  { \cs_end: {#1#1#1#1#1#1#1#1#1#1} #1#1 }
\cs_new:cpn { @@_replicate_3:n } #1
  { \cs_end: {#1#1#1#1#1#1#1#1#1#1} #1#1#1 }
\cs_new:cpn { @@_replicate_4:n } #1
  { \cs_end: {#1#1#1#1#1#1#1#1#1#1} #1#1#1#1 }
\cs_new:cpn { @@_replicate_5:n } #1
  { \cs_end: {#1#1#1#1#1#1#1#1#1#1} #1#1#1#1#1 }
\cs_new:cpn { @@_replicate_6:n } #1
  { \cs_end: {#1#1#1#1#1#1#1#1#1#1} #1#1#1#1#1#1 }
\cs_new:cpn { @@_replicate_7:n } #1
  { \cs_end: {#1#1#1#1#1#1#1#1#1#1} #1#1#1#1#1#1#1 }
\cs_new:cpn { @@_replicate_8:n } #1
  { \cs_end: {#1#1#1#1#1#1#1#1#1#1} #1#1#1#1#1#1#1#1 }
\cs_new:cpn { @@_replicate_9:n } #1
  { \cs_end: {#1#1#1#1#1#1#1#1#1#1} #1#1#1#1#1#1#1#1#1 }
%    \end{macrocode}
%    Users shouldn't ask for something to be replicated once or even
%    not at all but\dots
%    \begin{macrocode}
\cs_new:cpn { @@_replicate_first_-:n } #1
  {
    \exp_end:
    \msg_expandable_error:nn { prg } { negative-replication }
  }
\cs_new:cpn { @@_replicate_first_0:n } #1 { \exp_end: }
\cs_new:cpn { @@_replicate_first_1:n } #1 { \exp_end: #1 }
\cs_new:cpn { @@_replicate_first_2:n } #1 { \exp_end: #1#1 }
\cs_new:cpn { @@_replicate_first_3:n } #1 { \exp_end: #1#1#1 }
\cs_new:cpn { @@_replicate_first_4:n } #1 { \exp_end: #1#1#1#1 }
\cs_new:cpn { @@_replicate_first_5:n } #1 { \exp_end: #1#1#1#1#1 }
\cs_new:cpn { @@_replicate_first_6:n } #1 { \exp_end: #1#1#1#1#1#1 }
\cs_new:cpn { @@_replicate_first_7:n } #1 { \exp_end: #1#1#1#1#1#1#1 }
\cs_new:cpn { @@_replicate_first_8:n } #1 { \exp_end: #1#1#1#1#1#1#1#1 }
\cs_new:cpn { @@_replicate_first_9:n } #1
  { \exp_end: #1#1#1#1#1#1#1#1#1 }
%    \end{macrocode}
% \end{macro}
% \end{macro}
% \end{macro}
% \end{macro}
% \end{macro}
%
% \subsection{Detecting \TeX{}'s mode}
%
% \begin{macro}[pTF]{\mode_if_vertical:}
% \UnitTested
%   For testing vertical mode. Strikes me here on the bus with David,
%   that as long as we are just talking about returning true and
%   false states, we can just use the primitive conditionals for this
%   and gobbling the \cs{exp_end:} in the input stream. However this
%   requires knowledge of the implementation so we keep things nice
%   and clean and use the return statements.
%    \begin{macrocode}
\prg_new_conditional:Npnn \mode_if_vertical: { p , T , F , TF }
  { \if_mode_vertical: \prg_return_true: \else: \prg_return_false: \fi: }
%    \end{macrocode}
% \end{macro}
%
% \begin{macro}[pTF]{\mode_if_horizontal:}
% \UnitTested
%   For testing horizontal mode.
%    \begin{macrocode}
\prg_new_conditional:Npnn \mode_if_horizontal: { p , T , F , TF }
  { \if_mode_horizontal: \prg_return_true: \else: \prg_return_false: \fi: }
%    \end{macrocode}
% \end{macro}
%
% \begin{macro}[pTF]{\mode_if_inner:}
% \UnitTested
%   For testing inner mode.
%    \begin{macrocode}
\prg_new_conditional:Npnn \mode_if_inner: { p , T , F , TF }
  { \if_mode_inner: \prg_return_true: \else: \prg_return_false: \fi: }
%    \end{macrocode}
% \end{macro}
%
% \begin{macro}[pTF]{\mode_if_math:}
% \UnitTested
%   For testing math mode. At the beginning of an alignment cell,
%   this should be used only inside a non-expandable function.
%    \begin{macrocode}
\prg_new_conditional:Npnn \mode_if_math: { p , T , F , TF }
  { \if_mode_math: \prg_return_true: \else: \prg_return_false: \fi: }
%    \end{macrocode}
% \end{macro}
%
% \subsection{Internal programming functions}
%
% \begin{macro}{\group_align_safe_begin:, \group_align_safe_end:}
%   \TeX{}'s alignment structures present many problems. As Knuth says
%   himself in \emph{\TeX : The Program}: \enquote{It's sort of a miracle
%   whenever \tn{halign} or \tn{valign} work, [\ldots]} One problem relates
%   to commands that internally issue a \tn{cr} but also peek ahead for
%   the next character for use in, say, an optional argument. If the
%   next token happens to be a |&| with category code~4 we get some
%   sort of weird error message because the underlying
%   \tn{futurelet} stores the token at the end of the alignment
%   template. This could be a |&|$_4$ giving a message like
%   |! Misplaced \cr.| or even worse: it could be the \tn{endtemplate}
%   token causing even more trouble! To solve this we have to open a
%   special group so that \TeX{} still thinks it's on safe ground but at
%   the same time we don't want to introduce any brace group that may
%   find its way to the output. The following functions help with this
%   by using behavior documented only in Appendix~D of
%   \emph{The \TeX{}book}\dots
%   In short evaluating |`{| and |`}| as numbers will not change the counter
%   \TeX{} uses to keep track of its state in an alignment, whereas gobbling a
%   brace using \cs{if_false:} will affect \TeX's state without producing any
%   real group.
%   We place the \cs{if_false:} |{| \cs{fi:} part at that place so
%   that the successive expansions of \cs{group_align_safe_begin/end:}
%   are always brace balanced.
%    \begin{macrocode}
\group_begin:
\tex_catcode:D `\^^@ = 2 \exp_stop_f:
\cs_new:Npn \group_align_safe_begin:
  { \exp:w \if_false: { \fi: `^^@ \exp_stop_f: }
\tex_catcode:D `\^^@ = 1 \exp_stop_f:
\cs_new:Npn \group_align_safe_end:
  { \exp:w `^^@ \if_false: } \fi: \exp_stop_f: }
\group_end:
%    \end{macrocode}
% \end{macro}
%
% \begin{variable}{\g__kernel_prg_map_int}
%   A nesting counter for mapping.
%    \begin{macrocode}
\int_new:N \g__kernel_prg_map_int
%    \end{macrocode}
% \end{variable}
%
% \begin{macro}{\prg_break_point:Nn}
% \begin{macro}{\prg_map_break:Nn}
%   These are defined in \pkg{l3basics}, as they are needed
%   \enquote{early}. This is just a reminder that is the case!
% \end{macro}
% \end{macro}
%
% \begin{macro}{\prg_break_point:}
% \begin{macro}{\prg_break:, \prg_break:n}
%   Also done in \pkg{l3basics}.
% \end{macro}
% \end{macro}
%
%    \begin{macrocode}
%</code>
%    \end{macrocode}
%
% \end{implementation}
%
% \PrintIndex
