summaryrefslogtreecommitdiff
path: root/Master/texmf-dist/source/latex/expl3/l3prg.dtx
diff options
context:
space:
mode:
Diffstat (limited to 'Master/texmf-dist/source/latex/expl3/l3prg.dtx')
-rw-r--r--Master/texmf-dist/source/latex/expl3/l3prg.dtx433
1 files changed, 179 insertions, 254 deletions
diff --git a/Master/texmf-dist/source/latex/expl3/l3prg.dtx b/Master/texmf-dist/source/latex/expl3/l3prg.dtx
index 43e2e77448a..72084e07132 100644
--- a/Master/texmf-dist/source/latex/expl3/l3prg.dtx
+++ b/Master/texmf-dist/source/latex/expl3/l3prg.dtx
@@ -32,30 +32,26 @@
%%
%% -----------------------------------------------------------------------
%
-%<package>\RequirePackage{l3names}
-%<*dtx>
+%<*driver|package>
+\RequirePackage{l3names}
+%</driver|package>
%\fi
-\def\GetIdInfo$Id: #1.dtx #2 #3-#4-#5 #6 #7$#8{%
- \def\fileversion{#2}%
- \def\filedate{#3/#4/#5}%
- \ProvidesFile{#1.dtx}[#3/#4/#5 v#2 #8]%
-}
-%\iffalse
-%</dtx>
-%\fi
-\GetIdInfo$Id: l3prg.dtx 574 2006-08-21 23:30:10Z morten $
+\GetIdInfo$Id: l3prg.dtx 697 2007-11-27 14:14:54Z morten $
{L3 Experimental control structures}
-%
-% \iffalse
+%\iffalse
%<*driver>
+%\fi
+\ProvidesFile{\filename.\filenameext}
+ [\filedate\space v\fileversion\space\filedescription]
+%\iffalse
\documentclass{l3doc}
-
\begin{document}
-\DocInput{l3prg.dtx}
+\DocInput{\filename.\filenameext}
\end{document}
%</driver>
% \fi
%
+%
% \title{The \textsf{l3prg} package\thanks{This file
% has version number \fileversion, last
% revised \filedate.}\\
@@ -69,25 +65,25 @@
%
% \subsection{Choosing modes}
%
-% \begin{function}{\mode_vertical_p:|
-% \mode_vertical:TF |
-% \mode_vertical:T |
-% \mode_vertical:F
+% \begin{function}{\mode_if_vertical_p:|
+% \mode_if_vertical:TF |
+% \mode_if_vertical:T |
+% \mode_if_vertical:F
% }
% \begin{syntax}
-% "\mode_vertical:TF" "{"<true code>"}" "{"<false code>"}"
+% "\mode_if_vertical:TF" "{"<true code>"}" "{"<false code>"}"
% \end{syntax}
% Determines if \TeX{} is in vertical mode or not and executes either
% <true code> or <false code> accordingly.
% \end{function}
%
-% \begin{function}{\mode_horizontal_p:|
-% \mode_horizontal:TF |
-% \mode_horizontal:T |
-% \mode_horizontal:F
+% \begin{function}{\mode_if_horizontal_p:|
+% \mode_if_horizontal:TF |
+% \mode_if_horizontal:T |
+% \mode_if_horizontal:F
% }
% \begin{syntax}
-% "\mode_horizontal:TF" "{"<true code>"}" "{"<false code>"}"
+% "\mode_if_horizontal:TF" "{"<true code>"}" "{"<false code>"}"
% \end{syntax}
% Determines if \TeX{} is in horizontal mode or not and executes either
% <true code> or <false code> accordingly.
@@ -95,25 +91,25 @@
%
%
% \begin{function}{
-% \mode_inner_p:|
-% \mode_inner:TF|
-% \mode_inner:T|
-% \mode_inner:F
+% \mode_if_inner_p:|
+% \mode_if_inner:TF|
+% \mode_if_inner:T|
+% \mode_if_inner:F
% }
% \begin{syntax}
-% "\mode_inner:TF" "{"<true code>"}" "{"<false code>"}"
+% "\mode_if_inner:TF" "{"<true code>"}" "{"<false code>"}"
% \end{syntax}
% Determines if \TeX{} is in inner mode or not and executes either
% <true code> or <false code> accordingly.
% \end{function}
%
% \begin{function}{
-% \mode_math:TF|
-% \mode_math:T|
-% \mode_math:F|
+% \mode_if_math:TF|
+% \mode_if_math:T|
+% \mode_if_math:F|
% }
% \begin{syntax}
-% "\mode_math:TF" "{"<true code>"}" "{"<false code>"}"
+% "\mode_if_math:TF" "{"<true code>"}" "{"<false code>"}"
% \end{syntax}
% Determines if \TeX{} is in math mode or not and executes either
% <true code> or <false code> accordingly.
@@ -214,14 +210,14 @@
% connected to both parts as sometimes you want to execute some code
% depending on the value of a switch (e.g.,~draft/final) and other
% times you perhaps want to use it as a predicate function in an
-% "\if:w" test. Here \TeX's original concept with "\iffalse" and
-% "\iftrue" is a little difficult to handle so the easiest is simply
-% to let a boolean either be "\c_true" or "\c_false". This also means
-% we get the logical operations And, Or, and Not which can then be
-% used on both the boolean type and predicate functions. All
-% functions by the name |\prg_if_predicate_| are expandable and
-% expect the input to also be fully expandable. More generic
-% constructs do not contain |predicate| in their names.
+% "\if:w" test. Parsing "\iffalse"
+% and "\iftrue" tokens can be quite tricky at times so the easiest is to
+% simply let a boolean either be "\c_true" or "\c_false". This
+% also means we get the logical operations And, Or, and Not which can
+% then be used on both the boolean type and predicate functions. All
+% functions by the name |\predicate| are expandable and expect the
+% input to also be fully expandable. More generic constructs do not
+% contain |predicate| in their names.
%
%
% \subsubsection{The boolean data type}
@@ -324,48 +320,49 @@
%
%
% \begin{function}{%
-% \prg_if_predicate:nTF |
-% \prg_if_predicate:nT |
-% \prg_if_predicate:nF |
+% \predicate_p:n |
+% \predicate:nTF |
+% \predicate:nT |
+% \predicate:nF |
% }
% \begin{syntax}
-% "\prg_if_predicate:nTF" "{"<predicate>"}" "{"<true>"}" "{"<false>"}" \\
+% "\predicate:nTF" "{"<list of predicates>"}" "{"<true>"}"
+% "{"<false>"}"
% \end{syntax}
-% The first argument can either be a predicate function like
-% "\cs_free_p:N \foo" or one of the logic tests below.
+% The functions evaluate the truth value of \m{list of predicates}
+% where each predicate is separated by \verb+&&+ or \verb+||+
+% denoting logical And and Or functions. Minimal evaluation is
+% carried out so that whenever a truth value cannot be changed
+% anymore, the remainding tests are not carried out. Hence
+% \begin{verbatim}
+% \predicate_p:n{
+% \int_compare_p:nNn 1=1 &&
+% \predicate_p:n {
+% \int_compare_p:nNn 2=3 ||
+% \int_compare_p:nNn 4=4 ||
+% \int_compare_p:nNn 1=\error % is skipped
+% } &&
+% \int_compare_p:nNn 2=2
+% }
+% \end{verbatim}
+% returns \meta{true}.
% \end{function}
%
%
%
%
% \begin{function}{%
-% \prg_if_predicate_ors_p:n |
-% \prg_if_predicate_or_p:nn |
-% \prg_if_predicate_ands_p:n |
-% \prg_if_predicate_and_p:nn |
-% \prg_if_predicate_not_p:n |
+% \predicate_not_p:n |
% }
% \begin{syntax}
-% "\prg_if_predicate_ors_p:n" "{"<predicate> <predicate> ..."}" \\
-% "\prg_if_predicate_or_p:nn" "{"<predicate>"}" "{"<predicate>"}" \\
-% "\prg_if_predicate_ands_p:n" "{"<predicate> <predicate> ..."}" \\
-% "\prg_if_predicate_and_p:nn" "{"<predicate>"}" "{"<predicate>"}" \\
-% "\prg_if_predicate_not_p:n" "{"<predicate>"}"
+% "\predicate_not_p:n" "{"<list of predicates>"}"
% \end{syntax}
-% "\prg_if_predicate_or_p:nn" compares the outcome of two predicate
-% functions (or other logic tests) and if either turns out to be
-% \m{true} returns \m{true} itself. "\prg_if_predicate_and_p:nn"
-% works in a similar way but requires both outcomes to be \m{true} in
-% order for it to return \m{true} itself. "\prg_if_predicate_not_p:n"
-% reverses the truth value of a predicate test or a logic
-% operation. Thus
+% "\predicate_not_p:n"
+% reverses the truth value of its argument. Thus
% \begin{quote}
% "\prg_if_predicate_not_p:n {\prg_if_predicate_not_p:n {\c_true}}"
% \end{quote}
-% ultimately returns \m{true}. The argument of the functions
-% "\prg_if_predicate_ors_p:n" and "\prg_if_predicate_ands_p:n" take a
-% list of predicate functions (and their arguments) and return either
-% \m{true} or \m{false}.
+% ultimately returns \m{true}.
% \end{function}
%
% \subsubsection{Generic loops}
@@ -446,6 +443,8 @@
% We start by ensuring that the required packages are loaded.
% \begin{macrocode}
%<*package>
+\ProvidesExplPackage
+ {\filename}{\filedate}{\fileversion}{\filedescription}
\RequirePackage{l3quark}
\RequirePackage{l3toks}
\RequirePackage{l3int}
@@ -456,57 +455,57 @@
%
% \subsubsection{Choosing modes}
%
-% \begin{macro}{\mode_vertical_p:}
-% \begin{macro}{\mode_vertical:TF}
-% \begin{macro}{\mode_vertical:T}
-% \begin{macro}{\mode_vertical:F}
+% \begin{macro}{\mode_if_vertical_p:}
+% \begin{macro}{\mode_if_vertical:TF}
+% \begin{macro}{\mode_if_vertical:T}
+% \begin{macro}{\mode_if_vertical:F}
% For testing vertical mode.
% \begin{macrocode}
-\def_new:Npn \mode_vertical_p: {
+\def_new:Npn \mode_if_vertical_p: {
\if_mode_vertical: \c_true \else: \c_false\fi:}
-\def_test_function_new:npn{mode_vertical:}{\if_mode_vertical:}
+\def_test_function_new:npn{mode_if_vertical:}{\if_mode_vertical:}
% \end{macrocode}
% \end{macro}
% \end{macro}
% \end{macro}
% \end{macro}
%
-% \begin{macro}{\mode_horizontal_p:}
-% \begin{macro}{\mode_horizontal:TF}
-% \begin{macro}{\mode_horizontal:T}
-% \begin{macro}{\mode_horizontal:F}
+% \begin{macro}{\mode_if_horizontal_p:}
+% \begin{macro}{\mode_if_horizontal:TF}
+% \begin{macro}{\mode_if_horizontal:T}
+% \begin{macro}{\mode_if_horizontal:F}
% For testing horizontal mode.
% \begin{macrocode}
-\def_new:Npn \mode_horizontal_p: {
+\def_new:Npn \mode_if_horizontal_p: {
\if_mode_horizontal: \c_true \else: \c_false\fi:}
-\def_test_function_new:npn{mode_horizontal:}{\if_mode_horizontal:}
+\def_test_function_new:npn{mode_if_horizontal:}{\if_mode_horizontal:}
% \end{macrocode}
% \end{macro}
% \end{macro}
% \end{macro}
% \end{macro}
%
-% \begin{macro}{\mode_inner_p:}
-% \begin{macro}{\mode_inner:TF}
-% \begin{macro}{\mode_inner:T}
-% \begin{macro}{\mode_inner:F}
+% \begin{macro}{\mode_if_inner_p:}
+% \begin{macro}{\mode_if_inner:TF}
+% \begin{macro}{\mode_if_inner:T}
+% \begin{macro}{\mode_if_inner:F}
% For testing inner mode.
% \begin{macrocode}
-\def_new:Npn \mode_inner_p: {
+\def_new:Npn \mode_if_inner_p: {
\if_mode_inner: \c_true \else: \c_false\fi:}
-\def_test_function_new:npn{mode_inner:}{\if_mode_inner:}
+\def_test_function_new:npn{mode_if_inner:}{\if_mode_inner:}
% \end{macrocode}
% \end{macro}
% \end{macro}
% \end{macro}
% \end{macro}
%
-% \begin{macro}{\mode_math:TF}
-% \begin{macro}{\mode_math:T}
-% \begin{macro}{\mode_math:F}
+% \begin{macro}{\mode_if_math:TF}
+% \begin{macro}{\mode_if_math:T}
+% \begin{macro}{\mode_if_math:F}
% For testing math mode. Uses the kern-save |\scan_align_safe_stop:|.
% \begin{macrocode}
-\def_test_function_new:npn{mode_math:} {
+\def_test_function_new:npn{mode_if_math:} {
\scan_align_safe_stop: \if_mode_math: }
% \end{macrocode}
% \end{macro}
@@ -535,8 +534,9 @@
% by using code documented only in Appendix~D of
% \emph{The \TeX book}\dots
% \begin{macrocode}
-\def_new:Npn \group_align_safe_begin: {\if_false:{\fi:\if_num:w0=`}\fi:}
-\def_new:Npn \group_align_safe_end: {\if_num:w0=`{\fi:\if_false:}\fi:}
+\def_new:Npn \group_align_safe_begin: {
+ \if_false:{\fi:\if_num:w`}=\c_zero\fi:}
+\def_new:Npn \group_align_safe_end: {\if_num:w`{=\c_zero}\fi:}
% \end{macrocode}
% \end{macro}
% \end{macro}
@@ -797,15 +797,15 @@
% Defining and setting a boolean is easy.
% \begin{macrocode}
\def_new:Npn \bool_new:N #1 { \let_new:NN #1 \c_false }
-\def_new:Npn \bool_new:c #1 { \let_new:cN #1 \c_false }
+\def_new:Npn \bool_new:c #1 { \let_new:cN {#1} \c_false }
\def_new:Npn \bool_set_true:N #1 { \let:NN #1 \c_true }
-\def_new:Npn \bool_set_true:c #1 { \let:cN #1 \c_true }
+\def_new:Npn \bool_set_true:c #1 { \let:cN {#1} \c_true }
\def_new:Npn \bool_set_false:N #1 { \let:NN #1 \c_false }
-\def_new:Npn \bool_set_false:c #1 { \let:cN #1 \c_false }
+\def_new:Npn \bool_set_false:c #1 { \let:cN {#1} \c_false }
\def_new:Npn \bool_gset_true:N #1 { \glet:NN #1 \c_true }
-\def_new:Npn \bool_gset_true:c #1 { \glet:cN #1 \c_true }
+\def_new:Npn \bool_gset_true:c #1 { \glet:cN {#1} \c_true }
\def_new:Npn \bool_gset_false:N #1 { \glet:NN #1 \c_false }
-\def_new:Npn \bool_gset_false:c #1 { \glet:cN #1 \c_false }
+\def_new:Npn \bool_gset_false:c #1 { \glet:cN {#1} \c_false }
% \end{macrocode}
% \end{macro}
% \end{macro}
@@ -995,177 +995,102 @@
% \end{macro}
% \end{macro}
%
-% \begin{macro}{\prg_if_predicate:nTF}
-% \begin{macro}{\prg_if_predicate:nT}
-% \begin{macro}{\prg_if_predicate:nF}
-% As the boolean type is actually a predicate function, the next ones
-% are just aliases.
-% \begin{macrocode}
-\let_new:NN \prg_if_predicate:nTF \bool_if:NTF
-\let_new:NN \prg_if_predicate:nT \bool_if:NT
-\let_new:NN \prg_if_predicate:nF \bool_if:NF
-% \end{macrocode}
-% \end{macro}
-% \end{macro}
-% \end{macro}
-%
-%
-% \begin{macro}{\prg_if_predicate_or_p:nn}
-% \begin{macro}{\prg_if_predicate_and_p:nn}
-% \begin{macro}{\prg_if_predicate_not_p:n}
-% The logic operations require a little more work. The idea is to have
-% the end result of the logic "and" and "or" functions return "00" and
-% "01" resp.\ to be used in an "\if:w" test. The arguments of the
-% functions are always something expanding to "\c_true" or "\c_false"
-% which is usually resulting from a predicate function or from another
-% logical operation. All the functions start with a "0" and depending
-% on the results of the tests return either "0" or "1" to the input
-% stream to form a new true or false statement.
-%
-% The comments in the following is mostly to convince myseld of the
-% validity of the code.
-% \begin{macrocode}
-\def_new:Npn \prg_if_predicate_or_p:nn #1#2{
-% \end{macrocode}
-% Form a number of the input which is one of "0000", "0001", "0100", or
-% "0101". If the truth value of both tests are false we get the "0101"
-% else we get a number less than that. So we check if the number formed
-% is less than $101$.
-% \begin{macrocode}
- \if_num:w #1#2<\c_hundred_one
-% \end{macrocode}
-% If it is we put a "\c_true" back into the input stream.
+% \begin{macro}{\predicate_p:n}
+% \begin{macro}{\predicate:nTF}
+% \begin{macro}{\predicate:nT}
+% \begin{macro}{\predicate:nF}
+% \begin{macro}{\predicate_auxi:NN}
+% \begin{macro}{\predicate_auxii:NNN}
+% \begin{macro}{\predicate_88_0:w}^^A% fix!
+% \begin{macro}{\predicate_88_1:w}^^A% fix!
+% \begin{macro}{\predicate_II_0:w}^^A% fix!
+% \begin{macro}{\predicate_II_1:w}^^A fix!
+% \begin{macro}{\predicate_02_0:w}
+% \begin{macro}{\predicate_02_1:w}
+%
+% 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. The function evaluates predicates from
+% left to right, expanding them to 00 and 01 resp., which leads to
+% six different situations of tokens in the input stream:
+% \begin{itemize}
+% \item[\texttt{00\&\&}] Current truth value is true, logical And
+% seen, continue to see if next is also true.
+% \item[\texttt{01\&\&}] Current truth value is false, logical And
+% seen, break the scanning and return \meta{false}.
+% \item[\texttt{00\char`\|\char`\|}] Current truth value is true,
+% logical Or seen, break the scanning and return \meta{true}.
+% \item[\texttt{01\char`\|\char`\|}] Current truth value is false,
+% logical Or seen, continue to see if a later predicate is true.
+% \item[\texttt{0002}] Current truth value is true, end marker
+% seen, return \meta{true}.
+% \item[\texttt{0102}] Current truth value is false, end marker
+% seen, return \meta{false}.
+% \end{itemize}
+% To accomplish this we pre-expand the predicate list using |f|
+% type expansion which leads to |00| or |01|, possibly with a
+% sequence of unfinished |\else: \c_false \fi:| or similar after
+% it, which we remove using the same trick. We also carry over the
+% truth value of the evaluated predicate. The expansion stops when
+% it sees the end marker or \verb+&&+ or \verb+||+ (assuming these
+% are not active characters at the programming level).
% \begin{macrocode}
- \c_true
- \else:
-% \end{macrocode}
-% Otherwise we insert "\c_false".
-% \begin{macrocode}
- \c_false
- \fi:
+\def_long_new:Npn \predicate_p:n #1{
+ \group_align_safe_begin:
+ \exp_after:NN \predicate_auxi:NN
+ \int_to_roman:w-`\q #1 02\scan_stop:
}
-% \end{macrocode}
-% The "and" function is a little different. Again we can have input of
-% the types "0000", "0001", "0100", or "0101". As we require both
-% values to be \m{true} in order to continue we simply check if the
-% number formed by the input is "0" or not and then put the
-% corresponding "0" or "1" back in the input stream as above. We could
-% use "\if_num:w" for this test as well but that'll require us to read
-% the additional "=\c_zero" which runs a little slower than using
-% "\if_case:w" directly, so we use the latter.
-% \begin{macrocode}
-\def_new:Npn \prg_if_predicate_and_p:nn #1#2{
- \if_case:w #1#2 ~
- \c_true
- \else:
- \c_false
- \fi:
+\def_long_test_function_new:npn {predicate:n}#1{
+ \group_align_safe_begin:
+ \if:w \exp_after:NN \predicate_auxi:NN
+ \int_to_roman:w-`\q #1 02\scan_stop:
+}
+\def_new:Npn \predicate_auxi:NN 0 #1{
+ \exp_after:NN \predicate_auxii:NNN \exp_after:NN #1
+ \int_to_roman:w-`\q
}
% \end{macrocode}
-% The "not" function checks a single truth value and reverses it. Here
-% we either get a "00" or "01". If the input equals "0" we put a "1"
-% in the input stream, else we put a "0". Again we use "\if_case:w"
-% because it's slightly faster.
+% After removing trailing conditionals we call a macro for the case we
+% are in (see list above).
% \begin{macrocode}
-\def_new:Npn \prg_if_predicate_not_p:n #1{
- \if_case:w #1 ~
- \c_false
- \or:
- \c_true
- \fi:
+\def_new:Npn \predicate_auxii:NNN #1#2#3{
+ \cs_use:c{predicate_#2#3_#1:w} }
+\def_new:cpn{predicate_&&_0:w}{
+ \exp_after:NN \predicate_auxi:NN\int_to_roman:w-`\q
+}
+\def_long_new:cpn{predicate_&&_1:w} #1 02\scan_stop:{
+ \group_align_safe_end: 01}
+\def_long_new:cpn{predicate_||_0:w} #1 02\scan_stop:{
+ \group_align_safe_end: 00}
+\def_new:cpn{predicate_||_1:w}{
+ \exp_after:NN \predicate_auxi:NN\int_to_roman:w-`\q
}
+\def_new:cpn{predicate_02_0:w}\scan_stop:{ \group_align_safe_end: 00 }
+\def_new:cpn{predicate_02_1:w}\scan_stop:{ \group_align_safe_end: 01 }
% \end{macrocode}
% \end{macro}
% \end{macro}
% \end{macro}
+% \end{macro}
+% \end{macro}
+% \end{macro}
+% \end{macro}
+% \end{macro}
+% \end{macro}
+% \end{macro}
+% \end{macro}
+% \end{macro}
%
%
-% \begin{macro}{\prg_if_predicate_ors_p:n}
-% \begin{macro}{\prg_if_predicate_ands_p:n}
-% \begin{macro}{\prg_if_predicate_andor_aux:NNN}
-% \begin{macro}{\prg_if_predicate_andor_break:NNN }
-% For longer lists of predicates we can't rely on such structures
-% as above. The "\prg_if_predicate_ands_p:n" would have been easy to
-% program as simply
-% \begin{verbatim}
-% \def_new:Npn \prg_if_predicate_and_p:n #1 {
-% 0\tex_ifcase:D #1 ~ \exp_after:NN 0 \else: \exp_after:NN 1 \fi:
-% }
-% \end{verbatim}
-% but this would fail with a "! Number too big." in case we were
-% testing six predicate functions where the first was false. This
-% would mean we would have to first convert the string from binary
-% into numerical and then check. While challenging and interesting
-% in itself (See \textsf{binhex}) it still imposes a restriction of
-% 15 predicate functions\footnote{We would probably never hit that
-% limit but why create a restriction when we can avoid it?} and we
-% haven't dealt with the "or" case either.
-%
-% The solution below expands a predicate function until |\c_false| or
-% |\c_true| are seen and expanded to |01| or |00| respectively. If
-% we're testing the logical AND operation, all predicate functions
-% must return \meta{true}; if they don't we can exit and return
-% \meta{false}. In an OR operation, we just need one predicate
-% function to return \meta{true}, the rest don't matter. Since every
-% expansion in the internal loop results in a result of either |00|
-% or |01|, we can test against this number to decide what to do.
-%
-% First up is the top level functions.
-% \begin{macrocode}
-\def_long_new:Npn \prg_if_predicate_ands_p:n #1{
- \exp_after:NN \prg_if_predicate_andor_aux:NNN \exp_after:NN \c_true
- \int_to_roman:w -`0 #1 \scan_stop: \scan_stop:
-}
-\def_long_new:Npn \prg_if_predicate_ors_p:n #1{
- \exp_after:NN \prg_if_predicate_andor_aux:NNN \exp_after:NN \c_false
- \int_to_roman:w -`0 #1 \scan_stop: \scan_stop:
-}
-% \end{macrocode}
-% When we reach the inner loop we have already expanded all tokens in
-% the first predicate function as far as possible. This means that
-% either are arguments |#2| and |#3| \emph{both} |\scan_stop:| or else
-% |#2| is |0| and |#3| is |0| if the predicate returned \meta{true} or
-% |1| if it returned \meta{false}. If we reached the end we return
-% \meta{true} for the AND function and \meta{false} for the OR
-% function. If |#3| is |0| and we are doing the OR test, we want to
-% exit and return \meta{true}. If |#3| is |0| and we are in the AND
-% test we must continue to check the remaining predicate functions. If
-% |#3| is |1| and we are in the OR test we continue in case a later
-% predicate function returns \meta{true}. Finally, if |#3| is |1| and
-% we are in the AND test we can exit and return \meta{false} before
-% deciding what to do.
-% \begin{macrocode}
-\def_new:Npn \prg_if_predicate_andor_aux:NNN #1#2#3{
- \token_if_eq_meaning:NNTF \scan_stop: #2
- { #1 }
- {
- \int_compare:nNnTF #3 = #1
- { \exp_after:NN \prg_if_predicate_andor_aux:NNN }
- { \exp_after:NN \prg_if_predicate_andor_break:NNN }
- \exp_after:NN #1 \int_to_roman:w -`0
- }
-}
-% \end{macrocode}
-% The break loop is called when we know what the final outcome
-% is. However we keep expanding because a)~we don't know which tokens
-% we might have left dangling ahead and b)~it also provides error
-% checking on the remaining predicate functions. |#1| is \meta{false}
-% for the OR function and \meta{true} for the AND function so we
-% reverse them here.
+% \begin{macro}{\predicate_not_p:n}
+% The "not" variant just reverses the outcome of |\predicate_p:n|.
% \begin{macrocode}
-\def_new:Npn \prg_if_predicate_andor_break:NNN #1#2#3{
- \token_if_eq_meaning:NNTF \scan_stop: #2
- { \if:w #1\c_false\else:\c_true\fi: }
- {
- \exp_after:NN \prg_if_predicate_andor_break:NNN \exp_after:NN #1
- \int_to_roman:w -`0
- }
+\def_long_new:Npn \predicate_not_p:n #1{
+ \if:w \predicate_p:n{#1} \c_false \else: \c_true \fi:
}
% \end{macrocode}
-% \end{macro}
-% \end{macro}
-% \end{macro}
-% \end{macro}
+% \end{macro}
+%
%
% \subsubsection{Sorting}
%