summaryrefslogtreecommitdiff
path: root/Master/texmf-dist/source/latex/expl3/l3intexpr.dtx
diff options
context:
space:
mode:
authorKarl Berry <karl@freefriends.org>2009-06-09 23:31:15 +0000
committerKarl Berry <karl@freefriends.org>2009-06-09 23:31:15 +0000
commit215b9a864d5829070bdc66ba736986eb72e5143e (patch)
treefe0882c81fc4ec945cee4b512f72eaa21ea5f791 /Master/texmf-dist/source/latex/expl3/l3intexpr.dtx
parentdf90ec06321940c2f066b05e12f1b5ab099105da (diff)
expl3 1407 (9jun09)
git-svn-id: svn://tug.org/texlive/trunk@13686 c570f23f-e606-0410-a88d-b1316a301751
Diffstat (limited to 'Master/texmf-dist/source/latex/expl3/l3intexpr.dtx')
-rw-r--r--Master/texmf-dist/source/latex/expl3/l3intexpr.dtx642
1 files changed, 642 insertions, 0 deletions
diff --git a/Master/texmf-dist/source/latex/expl3/l3intexpr.dtx b/Master/texmf-dist/source/latex/expl3/l3intexpr.dtx
new file mode 100644
index 00000000000..6b454a8ab80
--- /dev/null
+++ b/Master/texmf-dist/source/latex/expl3/l3intexpr.dtx
@@ -0,0 +1,642 @@
+% \iffalse
+%% File: l3intexpr.dtx Copyright (C) 2009 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 ``expl3 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 LaTeX Project Team.
+%%
+%% -----------------------------------------------------------------------
+%
+%<*driver|package>
+\RequirePackage{l3names}
+%</driver|package>
+%\fi
+\GetIdInfo$Id: l3intexpr.dtx 1086 2009-03-20 19:29:35Z morten $
+ {L3 Integer Expressions}
+%\iffalse
+%<*driver>
+%\fi
+\ProvidesFile{\filename.\filenameext}
+ [\filedate\space v\fileversion\space\filedescription]
+%\iffalse
+\documentclass[full]{l3doc}
+\begin{document}
+\DocInput{\filename.\filenameext}
+\end{document}
+%</driver>
+% \fi
+%
+%
+% \title{The \textsf{l3intexpr} package\thanks{This file
+% has version number \fileversion, last
+% revised \filedate.}\\
+% Integer expressions}
+% \author{\Team}
+% \date{\filedate}
+% \maketitle
+%
+% \begin{documentation}
+%
+% This module sets up evaluation of integer expressions and allows
+% mixing |int| and |num| registers.
+%
+% An integer expression is one that contains integers in the form of
+% numbers, registers containg numbers, i.e., |int| and |num| registers
+% plus constants like |\c_one|, standard operators "+", "-", "/" and
+% "*" and parentheses to group sub-expressions.
+%
+% \section{Functions}
+%
+% \begin{function}{%
+% \intexpr_eval:n / (EXP)
+% }
+% \begin{syntax}
+% "\intexpr_eval:n" \Arg{int~expr}
+% \end{syntax}
+% The result of this expansion is a properly terminated <number>,
+% i.e., one that can be used with "\if_case:w" and others. For example,
+% \begin{quote}
+% |\intexpr_eval:n{ 5 + 4*3 - (3+4*5) }|
+% \end{quote}
+% evaluates to $-6$. The result is returned after two expansions so
+% if you find that you need to pass on the result to another function
+% using the expansion engine, the recommendation is to use an "f" type
+% expansion if in an expandable context or "x" otherwise.
+% \end{function}
+%
+%
+% \begin{function}{%
+% \intexpr_compare_p:n / (EXP) |
+% \intexpr_compare:n / (TF)(EXP)
+% }
+% \begin{syntax}
+% "\intexpr_compare_p:n" \Arg{<int~expr1> <rel> <int~expr2>}
+% \end{syntax}
+% Compares <int~expr1> with <int~expr2> using C-like relational
+% operators, i.e.
+% \begin{center}
+% \begin{tabular}{ll@{\hspace{2cm}}ll}
+% Less than & "<" & Less than or equal & "<=" \\
+% Greater than & "<" & Greater than or equal & ">=" \\
+% Equal & "==" or "=" & Not equal & "!="
+% \end{tabular}
+% \end{center}
+% Both integer expressions are evaluated fully in the process. Note
+% the syntax, which allows natural input in the style of
+% \begin{quote}
+% |\intexpr_compare_p:n {5+3 != \l_tmpb_int}|
+% \end{quote}
+% "=" is added for the sake of \TeX\ users accustomed to using a
+% single equal sign.
+% \end{function}
+%
+%
+% \begin{function}{%
+% \intexpr_compare_p:nNn / (EXP) |
+% \intexpr_compare:nNn / (TF)(EXP)
+% }
+% \begin{syntax}
+% "\intexpr_compare_p:nNn" \Arg{int~expr1}<rel>\Arg{int~expr2}
+% \end{syntax}
+% Compares <int~expr1> with <int~expr2> using one of the relations
+% "=", ">" or "<". This is faster than the variant above but at the
+% cost of requiring a little more typing and not supporting the
+% extended set of relational operators. Note that if both expressions
+% are normal integer variables as in
+% \begin{quote}
+% "\intexpr_compare:nNnTF \l_temp_int < \c_zero {negative}{non-negative}"
+% \end{quote}
+% you can safely omit the braces.
+% \end{function}
+%
+%
+% \begin{function}{%
+% \intexpr_max:nn / (EXP)|
+% \intexpr_min:nn / (EXP)|
+% }
+% \begin{syntax}
+% "\intexpr_max:nn" \Arg{int~expr1} \Arg{int~expr2}
+% \end{syntax}
+% Return the largest or smallest of two integer expressions.
+% \end{function}
+%
+% \begin{function}{%
+% \intexpr_abs:n / (EXP)|
+% }
+% \begin{syntax}
+% "\intexpr_abs:n" \Arg{int~expr}
+% \end{syntax}
+% Return the numerical value of an integer expression.
+% \end{function}
+%
+% \begin{function}{%
+% \intexpr_if_odd:n / (EXP)(TF) |
+% \intexpr_if_odd_p:n / (EXP) |
+% \intexpr_if_even:n / (EXP)(TF) |
+% \intexpr_if_even_p:n / (EXP) |
+% }
+% \begin{syntax}
+% "\intexpr_if_odd:nTF" \Arg{int~expr} \Arg{true} \Arg{false}
+% \end{syntax}
+% These functions test if an integer expression is even or odd.
+% \end{function}
+%
+%
+%
+%
+%
+%
+% \begin{function}{%
+% \intexpr_div_truncate:nn / (EXP) |
+% \intexpr_div_round:nn / (EXP) |
+% \intexpr_mod:nn / (EXP) |
+% }
+% \begin{syntax}
+% "\intexpr_div_truncate:n" \Arg{int~expr} \Arg{int~expr} \\
+% "\intexpr_mod:nn" \Arg{int~expr} \Arg{int~expr}
+% \end{syntax}
+% If
+% you want the result of a division to be truncated use
+% "\intexpr_div_truncate:nn". "\intexpr_div_round:nn" is added for
+% completeness. "\intexpr_mod:nn" returns the remainder of a division.
+% \end{function}
+%
+%
+%
+%
+%
+%
+%
+%
+%
+%
+%
+% \section{Primitive functions}
+%
+%
+% \begin{function}{%
+% \intexpr_value:w |
+% }
+% \begin{syntax}
+% "\intexpr_value:w" <integer> \\
+% "\intexpr_value:w" <tokens> <optional space>
+% \end{syntax}
+% Expands <tokens> until an <integer> is formed. One space may be
+% gobbled in the process.
+% \begin{texnote}
+% This is the \TeX{} primitive \tn{number}.
+% \end{texnote}
+% \end{function}
+%
+% \begin{function}{%
+% \intexpr_eval:w |
+% \intexpr_eval_end: |
+% }
+% \begin{syntax}
+% "\intexpr_eval:w" <int expr> "\intexpr_eval_end:"
+% \end{syntax}
+% Evaluates <int expr>. The evaluation stops when an
+% unexpandable token of catcode other than 12 is reached or
+% "\intexpr_end:" is read. The latter is gobbled by the scanner
+% mechanism.
+% \begin{texnote}
+% This is the \eTeX{} primitive \tn{numexpr}.
+% \end{texnote}
+% \end{function}
+%
+% \begin{function}{%
+% \if_intexpr_compare:w |
+% }
+% \begin{syntax}
+% "\if_intexpr_compare:w" <number1> <rel> <number2> <true> "\else:" <false> "\fi:"
+% \end{syntax}
+% Compare two numbers. It is recommended to use "\intexpr_eval:n" to
+% correctly evaluate and terminate these numbers. <rel> is one of
+% "<", "=" or ">" with catcode 12.
+% \begin{texnote}
+% This is the \TeX{} primitive \tn{ifnum}.
+% \end{texnote}
+% \end{function}
+%
+% \begin{function}{%
+% \if_intexpr_odd:w |
+% }
+% \begin{syntax}
+% "\if_intexpr_odd:w" <number> <true> "\else:" <false> "\fi:"
+% \end{syntax}
+% Execute <true> if <number> is odd, <false> otherwise.
+% \begin{texnote}
+% This is the \TeX{} primitive \tn{ifodd}.
+% \end{texnote}
+% \end{function}
+%
+% \begin{function}{%
+% \if_intexpr_case:w |
+% \or: |
+% }
+% \begin{syntax}
+% "\if_intexpr_case:w" <number> <case0> "\or:" <case1> "\or:" "..." "\else:"
+% <default> "\fi:"
+% \end{syntax}
+% Chooses case <number>. If you wish to use negative numbers as well,
+% you can offset them with "\intexpr_eval:n".
+% \begin{texnote}
+% These are the \TeX{} primitives \tn{ifcase} and \tn{or}.
+% \end{texnote}
+% \end{function}
+%
+%
+%
+% \begin{function}{%
+% \intexpr_while_do:nn |
+% \intexpr_until_do:nn |
+% \intexpr_do_while:nn |
+% \intexpr_do_until:nn |
+% }
+% \begin{syntax}
+% "\intexpr_while_do:nn" \Arg{<int~expr1> <rel> <int~expr2>} \Arg{code}
+% \end{syntax}
+% "\intexpr_while_do:nn" tests the integer expressions against each
+% other using a C-like <rel> as in "\intexpr_compare_p:n" and if true
+% performs the <code> until the test fails. "\intexpr_do_while:nn" is
+% similar but executes the <code> first and then performs the check,
+% thus ensuring that the body is executed at least once. The `until'
+% versions are similar but continue the loop as long as the test is
+% false. They could be omitted as it is just a matter of switching the
+% arguments in the test.
+% \end{function}
+%
+% \begin{function}{%
+% \intexpr_while_do:nNnn |
+% \intexpr_until_do:nNnn |
+% \intexpr_do_while:nNnn |
+% \intexpr_do_until:nNnn |
+% }
+% \begin{syntax}
+% "\intexpr_while_do:nNnn" <int expr> <rel> <int~expr> \Arg{code}
+% \end{syntax}
+% Exactly as above but instead using the syntax of
+% "\intexpr_compare_p:nNn".
+% \end{function}
+%
+%
+%
+%
+%
+% \end{documentation}
+%
+% \begin{implementation}
+%
+% \section{\pkg{l3intexpr} implementation}
+%
+%
+% We start by ensuring that the required packages are loaded.
+% \begin{macrocode}
+%<*package>
+\ProvidesExplPackage
+ {\filename}{\filedate}{\fileversion}{\filedescription}
+\package_check_loaded_expl:
+%</package>
+%<*initex|package>
+% \end{macrocode}
+%
+% \begin{macro}{\intexpr_value:w}
+% \begin{macro}{\intexpr_eval:n,\intexpr_eval:w,\intexpr_eval_end:}
+% \begin{macro}{\if_intexpr_compare:w}
+% \begin{macro}{\if_intexpr_odd:w}
+% \begin{macro}{\if_intexpr_case:w}
+% Here are the remaining primitives for number comparisons and
+% expressions.
+% \begin{macrocode}
+\cs_set_eq:NN \intexpr_value:w \tex_number:D
+\cs_set_eq:NN \intexpr_eval:w \etex_numexpr:D
+\cs_set_protected:Npn \intexpr_eval_end: {\tex_relax:D}
+\cs_set_eq:NN \if_intexpr_compare:w \tex_ifnum:D
+\cs_set_eq:NN \if_intexpr_odd:w \tex_ifodd:D
+\cs_set_eq:NN \if_intexpr_case:w \tex_ifcase:D
+\cs_set:Npn \intexpr_eval:n #1{
+ \intexpr_value:w \intexpr_eval:w #1\intexpr_eval_end:
+}
+% \end{macrocode}
+% \end{macro}
+% \end{macro}
+% \end{macro}
+% \end{macro}
+% \end{macro}
+%
+%
+%
+%
+%
+%
+% \begin{macro}{\intexpr_compare_p:n}
+% \begin{macro}[TF]{\intexpr_compare:n}
+% Comparison tests using a simple syntax where only one set of braces
+% is required and additional operators such as "!=" and ">=" are
+% supported. First some notes on the idea behind this. We wish to
+% support writing code like
+% \begin{verbatim}
+% \intexpr_compare_p:n { 5 + \l_tmpa_int != 4 - \l_tmpb_int }
+% \end{verbatim}
+% In other words, we want to somehow add the missing "\intexpr_eval:w"
+% where required. We can start evaluating from the left using
+% "\intexpr:w", and we know that since the relation symbols "<", ">",
+% "=" and "!" are not allowed in such expressions, they will terminate
+% the expression. Therefore, we first let \TeX\ evaluate this left
+% hand side of the (in)equality.
+% \begin{macrocode}
+\prg_set_conditional:Npnn \intexpr_compare:n #1{p,TF,T,F}{
+ \exp_after:wN \intexpr_compare_auxi:w \intexpr_value:w
+ \intexpr_eval:w #1\q_stop
+}
+% \end{macrocode}
+% Then the next step is to figure out which relation we should use, so
+% we have to somehow get rid of the first evaluation so that we can
+% see what stopped it. "\tex_romannumeral:D" is handy here since its
+% expansion given a non-positive number is \m{null}. We therefore
+% simply check if the first token of the left hand side evaluation is
+% a minus. If not, we insert it and issue "\tex_romannumeral:D",
+% thereby ridding us of the left hand side evaluation. We do however
+% save it for later.
+% \begin{macrocode}
+\cs_set:Npn \intexpr_compare_auxi:w #1#2\q_stop{
+ \exp_after:wN \intexpr_compare_auxii:w \tex_romannumeral:D
+ \if:w #1- \else: -\fi: #1#2 \q_stop #1#2 \q_nil
+}
+% \end{macrocode}
+% This leaves the first relation symbol in front and assuming the
+% right hand side has been input, at least one other token as well. We
+% support the following forms: |=|, |<|, |>| and the extended |!=|,
+% |==|, |<=| and |>=|. All the extended forms have an extra |=| so we
+% check if that is present as well. Then use specific function to
+% perform the test.
+% \begin{macrocode}
+\cs_set:Npn \intexpr_compare_auxii:w #1#2#3\q_stop{
+ \use:c{
+ intexpr_compare_
+ #1 \if_meaning:w =#2 = \fi:
+ :w}
+}
+% \end{macrocode}
+% The actual comparisons are then simple function calls, using the
+% relation as delimiter for a delimited argument.
+% Equality is easy:
+% \begin{macrocode}
+\cs_set:cpn {intexpr_compare_=:w} #1=#2\q_nil{
+ \if_intexpr_compare:w #1=\intexpr_eval:w #2 \intexpr_eval_end:
+ \prg_return_true: \else: \prg_return_false: \fi:
+}
+% \end{macrocode}
+% So is the one using |==| -- we just have to use |==| in the
+% parameter text.
+% \begin{macrocode}
+\cs_set:cpn {intexpr_compare_==:w} #1==#2\q_nil{
+ \if_intexpr_compare:w #1=\intexpr_eval:w #2 \intexpr_eval_end:
+ \prg_return_true: \else: \prg_return_false: \fi:
+}
+% \end{macrocode}
+% Not equal is just about reversing the truth value.
+% \begin{macrocode}
+\cs_set:cpn {intexpr_compare_!=:w} #1!=#2\q_nil{
+ \if_intexpr_compare:w #1=\intexpr_eval:w #2 \intexpr_eval_end:
+ \prg_return_false: \else: \prg_return_true: \fi:
+}
+% \end{macrocode}
+% Less than and greater than are also straight forward.
+% \begin{macrocode}
+\cs_set:cpn {intexpr_compare_<:w} #1<#2\q_nil{
+ \if_intexpr_compare:w #1<\intexpr_eval:w #2 \intexpr_eval_end:
+ \prg_return_true: \else: \prg_return_false: \fi:
+}
+\cs_set:cpn {intexpr_compare_>:w} #1>#2\q_nil{
+ \if_intexpr_compare:w #1>\intexpr_eval:w #2 \intexpr_eval_end:
+ \prg_return_true: \else: \prg_return_false: \fi:
+}
+% \end{macrocode}
+% For the less than or equal operation, we simply add $1$ to the right
+% hand side and then use a less than test. A similar trick for the
+% greater than or equal test except there we subtract $1$.
+% \begin{macrocode}
+\cs_set:cpn {intexpr_compare_<=:w} #1<=#2\q_nil{
+ \if_intexpr_compare:w #1<\intexpr_eval:w #2 +\c_one \intexpr_eval_end:
+ \prg_return_true: \else: \prg_return_false: \fi:
+}
+\cs_set:cpn {intexpr_compare_>=:w} #1>=#2\q_nil{
+ \if_intexpr_compare:w #1>\intexpr_eval:w #2 - \c_one \intexpr_eval_end:
+ \prg_return_true: \else: \prg_return_false: \fi:
+}
+% \end{macrocode}
+% \end{macro}
+% \end{macro}
+%
+% \begin{macro}{\intexpr_compare_p:nNn}
+% \begin{macro}[TF]{\intexpr_compare:nNn}
+% More efficient but less natural in typing.
+% \begin{macrocode}
+\prg_set_conditional:Npnn \intexpr_compare:nNn #1#2#3{p,TF,T,F}{
+ \if_intexpr_compare:w \intexpr_eval:w #1 #2 \intexpr_eval:w #3 \intexpr_eval_end:
+ \prg_return_true: \else: \prg_return_false: \fi:
+}
+% \end{macrocode}
+% \end{macro}
+% \end{macro}
+%
+%
+% \begin{macro}{\intexpr_max:nn}
+% \begin{macro}{\intexpr_min:nn}
+% \begin{macro}{\intexpr_abs:n}
+% Functions for $\min$, $\max$, and absolute value.
+% \begin{macrocode}
+\cs_set:Npn \intexpr_abs:n #1{
+ \intexpr_value:w
+ \if_intexpr_compare:w \intexpr_eval:w #1<\c_zero
+ -
+ \fi:
+ \intexpr_eval:w #1\intexpr_eval_end:
+}
+\cs_set:Npn \intexpr_max:nn #1#2{
+ \intexpr_value:w \intexpr_eval:w
+ \if_intexpr_compare:w
+ \intexpr_eval:w #1>\intexpr_eval:w #2\intexpr_eval_end:
+ #1
+ \else:
+ #2
+ \fi:
+ \intexpr_eval_end:
+}
+\cs_set:Npn \intexpr_min:nn #1#2{
+ \intexpr_value:w \intexpr_eval:w
+ \if_intexpr_compare:w
+ \intexpr_eval:w #1<\intexpr_eval:w #2\intexpr_eval_end:
+ #1
+ \else:
+ #2
+ \fi:
+ \intexpr_eval_end:
+}
+% \end{macrocode}
+% \end{macro}
+% \end{macro}
+% \end{macro}
+%
+%
+% \begin{macro}{\intexpr_div_truncate:nn}
+% \begin{macro}{\intexpr_div_round:nn}
+% \begin{macro}{\intexpr_mod:nn}
+% As "\intexpr_eval:w" rounds the result of a division we also
+% provide a version that truncates the result.
+% \begin{macrocode}
+% \end{macrocode}
+% Initial version didn't work correctly with e\TeX's implementation.
+% \begin{macrocode}
+%\cs_set:Npn \intexpr_div_truncate_raw:nn #1#2 {
+% \intexpr_eval:n{ (2*#1 - #2) / (2* #2) }
+%}
+% \end{macrocode}
+% New version by Heiko:
+% \begin{macrocode}
+\cs_set:Npn \intexpr_div_truncate:nn #1#2 {
+ \intexpr_value:w \intexpr_eval:w
+ \if_intexpr_compare:w \intexpr_eval:w #1 = \c_zero
+ 0
+ \else:
+ (#1
+ \if_intexpr_compare:w \intexpr_eval:w #1 < \c_zero
+ \if_intexpr_compare:w \intexpr_eval:w #2 < \c_zero
+ -( #2 +
+ \else:
+ +( #2 -
+ \fi:
+ \else:
+ \if_intexpr_compare:w \intexpr_eval:w #2 < \c_zero
+ +( #2 +
+ \else:
+ -( #2 -
+ \fi:
+ \fi:
+ 1)/2)
+ \fi:
+ /(#2)
+ \intexpr_eval_end:
+}
+% \end{macrocode}
+% For the sake of completeness:
+% \begin{macrocode}
+\cs_set:Npn \intexpr_div_round:nn #1#2 {\intexpr_eval:n{(#1)/(#2)}}
+% \end{macrocode}
+% Finally there's the modulus operation.
+% \begin{macrocode}
+\cs_set:Npn \intexpr_mod:nn #1#2 {
+ \intexpr_value:w
+ \intexpr_eval:w
+ #1 - \intexpr_div_truncate:nn {#1}{#2} * (#2)
+ \intexpr_eval_end:
+}
+% \end{macrocode}
+% \end{macro}
+% \end{macro}
+% \end{macro}
+%
+% \begin{macro}{\intexpr_if_odd_p:n}
+% \begin{macro}[TF]{\intexpr_if_odd:n}
+% \begin{macro}{\intexpr_if_even_p:n}
+% \begin{macro}[TF]{\intexpr_if_even:n}
+% A predicate function.
+% \begin{macrocode}
+\prg_set_conditional:Npnn \intexpr_if_odd:n #1 {p,TF,T,F} {
+ \if_intexpr_odd:w \intexpr_eval:w #1\intexpr_eval_end:
+ \prg_return_true: \else: \prg_return_false: \fi:
+}
+\prg_set_conditional:Npnn \intexpr_if_even:n #1 {p,TF,T,F} {
+ \if_intexpr_odd:w \intexpr_eval:w #1\intexpr_eval_end:
+ \prg_return_false: \else: \prg_return_true: \fi:
+}
+% \end{macrocode}
+% \end{macro}
+% \end{macro}
+% \end{macro}
+% \end{macro}
+%
+% \begin{macro}{\intexpr_while_do:nn}
+% \begin{macro}{\intexpr_until_do:nn}
+% \begin{macro}{\intexpr_do_while:nn}
+% \begin{macro}{\intexpr_do_until:nn}
+% These are quite easy given the above functions. The "while" versions
+% test first and then execute the body. The "do_while" does it the
+% other way round.
+% \begin{macrocode}
+\cs_set:Npn \intexpr_while_do:nn #1#2{
+ \intexpr_compare:nT {#1}{#2 \intexpr_while_do:nn {#1}{#2}}
+}
+\cs_set:Npn \intexpr_until_do:nn #1#2{
+ \intexpr_compare:nF {#1}{#2 \intexpr_until_do:nn {#1}{#2}}
+}
+\cs_set:Npn \intexpr_do_while:nn #1#2{
+ #2 \intexpr_compare:nT {#1}{\intexpr_do_while:nNnn {#1}{#2}}
+}
+\cs_set:Npn \intexpr_do_until:nn #1#2{
+ #2 \intexpr_compare:nF {#1}{\intexpr_do_until:nn {#1}{#2}}
+}
+% \end{macrocode}
+% \end{macro}
+% \end{macro}
+% \end{macro}
+% \end{macro}
+%
+% \begin{macro}{\intexpr_while_do:nNnn}
+% \begin{macro}{\intexpr_until_do:nNnn}
+% \begin{macro}{\intexpr_do_while:nNnn}
+% \begin{macro}{\intexpr_do_until:nNnn}
+% As above but not using the more natural syntax.
+% \begin{macrocode}
+\cs_set:Npn \intexpr_while_do:nNnn #1#2#3#4{
+ \intexpr_compare:nNnT {#1}#2{#3}{#4 \intexpr_while_do:nNnn {#1}#2{#3}{#4}}
+}
+\cs_set:Npn \intexpr_until_do:nNnn #1#2#3#4{
+ \intexpr_compare:nNnF {#1}#2{#3}{#4 \intexpr_until_do:nNnn {#1}#2{#3}{#4}}
+}
+\cs_set:Npn \intexpr_do_while:nNnn #1#2#3#4{
+ #4 \intexpr_compare:nNnT {#1}#2{#3}{\intexpr_do_while:nNnn {#1}#2{#3}{#4}}
+}
+\cs_set:Npn \intexpr_do_until:nNnn #1#2#3#4{
+ #4 \intexpr_compare:nNnF {#1}#2{#3}{\intexpr_do_until:nNnn {#1}#2{#3}{#4}}
+}
+% \end{macrocode}
+% \end{macro}
+% \end{macro}
+% \end{macro}
+% \end{macro}
+%
+% \begin{macrocode}
+%</initex|package>
+% \end{macrocode}
+%
+% \end{implementation}
+% \PrintIndex
+%
+% \endinput