summaryrefslogtreecommitdiff
path: root/macros/latex/contrib/l3kernel/l3fp-parse.dtx
diff options
context:
space:
mode:
Diffstat (limited to 'macros/latex/contrib/l3kernel/l3fp-parse.dtx')
-rw-r--r--macros/latex/contrib/l3kernel/l3fp-parse.dtx2899
1 files changed, 0 insertions, 2899 deletions
diff --git a/macros/latex/contrib/l3kernel/l3fp-parse.dtx b/macros/latex/contrib/l3kernel/l3fp-parse.dtx
deleted file mode 100644
index 53b85a7cc8..0000000000
--- a/macros/latex/contrib/l3kernel/l3fp-parse.dtx
+++ /dev/null
@@ -1,2899 +0,0 @@
-% \iffalse meta-comment
-%
-%% File: l3fp-parse.dtx
-%
-% Copyright (C) 2011-2024 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{l3fp-parse} module\\
-% Floating point expression parsing^^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 2024-03-14}
-%
-% \maketitle
-%
-% \begin{documentation}
-%
-% \end{documentation}
-%
-% \begin{implementation}
-%
-% \section{\pkg{l3fp-parse} implementation}
-%
-% \begin{macrocode}
-%<*package>
-% \end{macrocode}
-%
-% \begin{macrocode}
-%<@@=fp>
-% \end{macrocode}
-%
-% \subsection{Work plan}
-%
-% The task at hand is non-trivial, and some previous failed attempts
-% show that the code leads to unreadable logs, so we had better get it
-% (almost) right the first time. Let us first describe our goal, then
-% discuss the design precisely before writing any code.
-%
-% In this file at least, a \meta{floating point object} is a floating
-% point number or tuple. This can be extended to anything that starts
-% with \cs{s_@@} or \cs{s_@@_\meta{type}} and ends with |;| with some
-% internal structure that depends on the \meta{type}.
-%
-% \begin{macro}[EXP]{\@@_parse:n}
-% \begin{syntax}
-% \cs{@@_parse:n} \Arg{fp expr}
-% \end{syntax}
-% Evaluates the \meta{fp expr} and leaves the result
-% in the input stream as a floating point object. This
-% function forms the basis of almost all public \pkg{l3fp} functions.
-% During evaluation, each token is fully \texttt{f}-expanded.
-%
-% \cs{@@_parse_o:n} does the same but expands once after its result.
-% \begin{texnote}
-% Registers (integers, toks, etc.) are automatically unpacked,
-% without requiring a function such as \cs{int_use:N}. Invalid
-% tokens remaining after \texttt{f}-expansion lead to
-% unrecoverable low-level \TeX{} errors.
-% \end{texnote}
-% \end{macro}
-%
-% \begin{variable}
-% {
-% \c_@@_prec_func_int,
-% \c_@@_prec_hatii_int,
-% \c_@@_prec_hat_int,
-% \c_@@_prec_not_int,
-% \c_@@_prec_juxt_int,
-% \c_@@_prec_times_int,
-% \c_@@_prec_plus_int,
-% \c_@@_prec_comp_int,
-% \c_@@_prec_and_int,
-% \c_@@_prec_or_int,
-% \c_@@_prec_quest_int,
-% \c_@@_prec_colon_int,
-% \c_@@_prec_comma_int,
-% \c_@@_prec_tuple_int,
-% \c_@@_prec_end_int,
-% }
-% Floating point expressions are composed of numbers, given in various
-% forms, infix operators, such as |+|, |**|, or~|,| (which joins two
-% numbers into a list), and prefix operators, such as the unary~|-|,
-% functions, or opening parentheses. Here is a list of precedences
-% which control the order of evaluation (some distinctions are
-% irrelevant for the order of evaluation, but serve as signals), from
-% the tightest binding to the loosest binding.
-% \begin{itemize}
-% \item[16] Function calls.
-% \item[13/14] Binary |**| and~|^| (right to left).
-% \item[12] Unary |+|, |-|, |!| (right to left).
-% \item[11] Juxtaposition (implicit~|*|) with no parenthesis.
-% \item[10] Binary |*| and~|/|.
-% \item[9] Binary |+| and~|-|.
-% \item[7] Comparisons.
-% \item[6] Logical \texttt{and}, denoted by~|&&|.
-% \item[5] Logical \texttt{or}, denoted by~\verb*+||+.
-% \item[4] Ternary operator |?:|, piece~|?|.
-% \item[3] Ternary operator |?:|, piece~|:|.
-% \item[2] Commas.
-% \item[1] Place where a comma is allowed and generates a tuple.
-% \item[0] Start and end of the expression.
-% \end{itemize}
-% \begin{macrocode}
-\int_const:Nn \c_@@_prec_func_int { 16 }
-\int_const:Nn \c_@@_prec_hatii_int { 14 }
-\int_const:Nn \c_@@_prec_hat_int { 13 }
-\int_const:Nn \c_@@_prec_not_int { 12 }
-\int_const:Nn \c_@@_prec_juxt_int { 11 }
-\int_const:Nn \c_@@_prec_times_int { 10 }
-\int_const:Nn \c_@@_prec_plus_int { 9 }
-\int_const:Nn \c_@@_prec_comp_int { 7 }
-\int_const:Nn \c_@@_prec_and_int { 6 }
-\int_const:Nn \c_@@_prec_or_int { 5 }
-\int_const:Nn \c_@@_prec_quest_int { 4 }
-\int_const:Nn \c_@@_prec_colon_int { 3 }
-\int_const:Nn \c_@@_prec_comma_int { 2 }
-\int_const:Nn \c_@@_prec_tuple_int { 1 }
-\int_const:Nn \c_@@_prec_end_int { 0 }
-% \end{macrocode}
-% \end{variable}
-%
-% \subsubsection{Storing results}
-%
-% The main question in parsing expressions expandably is to decide where
-% to put the intermediate results computed for various subexpressions.
-%
-% One option is to store the values at the start of the expression, and
-% carry them together as the first argument of each macro. However, we
-% want to \texttt{f}-expand tokens one by one in the expression (as
-% \cs{int_eval:n} does), and with this approach, expanding the next
-% unread token forces us to jump with \cs{exp_after:wN} over every value
-% computed earlier in the expression. With this approach, the run-time
-% grows at least quadratically in the length of the expression, if
-% not as its cube (inserting the \cs{exp_after:wN} is tricky and slow).
-%
-% A second option is to place those values at the end of the expression.
-% Then expanding the next unread token is straightforward, but this
-% still hits a performance issue: for long expressions we would be
-% reaching all the way to the end of the expression at every step of the
-% calculation. The run-time is again quadratic.
-%
-% A variation of the above attempts to place the intermediate results
-% which appear when computing a parenthesized expression near the
-% closing parenthesis. This still lets us expand tokens as we go, and
-% avoids performance problems as long as there are enough parentheses.
-% However, it would be better to avoid requiring the closing
-% parenthesis to be present as soon as the corresponding opening
-% parenthesis is read: the closing parenthesis may still be hidden in a
-% macro yet to be expanded.
-%
-% Hence, we need to go for some fine expansion control: the result is
-% stored \emph{before} the start!
-%
-% Let us illustrate this idea in a simple model: adding positive
-% integers which may be resulting from the expansion of macros, or may
-% be values of registers. Assume that one number, say, $12345$, has
-% already been found, and that we want to parse the next number. The
-% current status of the code may look as follows.
-% \begin{syntax}
-% \cs{exp_after:wN} |\add:ww| \cs{int_value:w} 12345 \cs{exp_after:wN} ;
-% \cs{exp:w} |\operand:w| \meta{stuff}
-% \end{syntax}
-% One step of expansion expands \cs{exp_after:wN}, which triggers the
-% primitive \cs{int_value:w}, which reads the five digits we have
-% already found, |12345|. This integer is unfinished, causing the
-% second \cs{exp_after:wN} to expand, and to trigger the construction
-% \cs{exp:w}, which expands |\operand:w|, defined to read
-% what follows and make a number out of it, then leave \cs{exp_end:}, the
-% number, and a semicolon in the input stream. Once |\operand:w| is
-% done expanding, we obtain essentially
-% \begin{syntax}
-% \cs{exp_after:wN} |\add:ww| \cs{int_value:w} 12345 ;
-% \cs{exp:w} \cs{exp_end:} 333444 ;
-% \end{syntax}
-% where in fact \cs{exp_after:wN} has already been expanded,
-% \cs{int_value:w} has already seen |12345|, and
-% \cs{exp:w} is still looking for a number. It finds
-% \cs{exp_end:}, hence expands to nothing. Now, \cs{int_value:w} sees
-% the \texttt{;}, which cannot be part of a number. The expansion
-% stops, and we are left with
-% \begin{syntax}
-% |\add:ww| 12345 ; 333444 ;
-% \end{syntax}
-% which can safely perform the addition by grabbing two arguments
-% delimited by~|;|.
-%
-% If we were to continue parsing the expression, then the following
-% number should also be cleaned up before the next use of a binary
-% operation such as |\add:ww|. Just like \cs{int_value:w} |12345|
-% \cs{exp_after:wN}~|;| expanded what follows once, we need |\add:ww|
-% to do the calculation, and in the process to expand the following
-% once. This is also true in our real application: all the functions of
-% the form \cs[no-index]{@@_\ldots_o:ww} expand what follows once. This comes at the
-% cost of leaving tokens in the input stack, and we need to be
-% careful not to waste this memory. All of our discussion above is nice
-% but simplistic, as operations should not simply be performed in the
-% order they appear.
-%
-% \subsubsection{Precedence and infix operators}
-%
-% The various operators we will encounter have different precedences,
-% which influence the order of calculations: $1+2\times 3 = 1+(2\times
-% 3)$ because $\times$~has a higher precedence than~$+$. The true
-% analog of our macro |\operand:w| must thus take care of that. When
-% looking for an operand, it needs to perform calculations until
-% reaching an operator which has lower precedence than the one which
-% called |\operand:w|. This means that |\operand:w| must know what the
-% previous binary operator is, or rather, its precedence: we thus rename
-% it |\operand:Nw|. Let us describe as an example how we plan to do
-% the calculation |41-2^3*4+5|. More precisely we describe how to
-% perform the first operation in this expression. Here, we abuse
-% notations: the first argument of |\operand:Nw| should be an integer
-% constant (\cs{c_@@_prec_plus_int}, \ldots{}) equal to the precedence
-% of the given operator, not directly the operator itself.
-% \begin{itemize}
-% \item Clean up~|41| and find~|-|. We call |\operand:Nw|~|-| to find
-% the second operand.
-% \item Clean up~|2| and find~|^|.
-% \item Compare the precedences of |-| and~|^|. Since the latter is
-% higher, we need to compute the exponentiation. For this, find the
-% second operand with a nested call to |\operand:Nw|~|^|.
-% \item Clean up~|3| and find~|*|.
-% \item Compare the precedences of |^| and~|*|. Since the former is
-% higher, |\operand:Nw|~|^| has found the second operand of the
-% exponentiation, which is computed: $2^{3} = 8$.
-% \item We now have |41-8*4+5|, and |\operand:Nw|~|-| is still
-% looking for a second operand for the subtraction. Is it~$8$?
-% \item Compare the precedences of |-| and~|*|. Since the latter is
-% higher, we are not done with~$8$. Call |\operand:Nw|~|*| to find
-% the second operand of the multiplication.
-% \item Clean up~|4|, and find~|+|.
-% \item Compare the precedences of |*| and~|+|. Since the former is
-% higher, |\operand:Nw|~|*| has found the second operand of the
-% multiplication, which is computed: $8*4 = 32$.
-% \item We now have |41-32+5|, and |\operand:Nw|~|-| is still looking
-% for a second operand for the subtraction. Is it~$32$?
-% \item Compare the precedences of |-| and~|+|. Since they are equal,
-% |\operand:Nw|~|-| has found the second operand for the
-% subtraction, which is computed: $41-32=9$.
-% \item We now have |9+5|.
-% \end{itemize}
-% The procedure above stops short of performing all computations, but
-% adding a surrounding call to |\operand:Nw| with a very low precedence
-% ensures that all computations are performed before |\operand:Nw|
-% is done. Adding a trailing marker with the same very low precedence
-% prevents the surrounding |\operand:Nw| from going beyond the marker.
-%
-% The pattern above to find an operand for a given operator, is to find
-% one number and the next operator, then compare precedences to know if
-% the next computation should be done. If it should, then perform it
-% after finding its second operand, and look at the next operator, then
-% compare precedences to know if the next computation should be done.
-% This continues until we find that the next computation should not be
-% done. Then, we stop.
-%
-% We are now ready to get a bit more technical and describe which of the
-% \pkg{l3fp-parse} functions correspond to each step above.
-%
-% First, \cs{@@_parse_operand:Nw} is the |\operand:Nw| function above,
-% with small modifications due to expansion issues discussed later. We
-% denote by \meta{precedence} the argument of \cs{@@_parse_operand:Nw},
-% that is, the precedence of the binary operator whose operand we are
-% trying to find. The basic action is to read numbers from the input
-% stream. This is done by \cs{@@_parse_one:Nw}. A first approximation
-% of this function is that it reads one \meta{number}, performing no
-% computation, and finds the following binary \meta{operator}. Then it
-% expands to
-% \begin{quote}
-% \meta{number}\\
-% | \__fp_parse_infix_|\meta{operator}|:N| \meta{precedence}
-% \end{quote}
-% expanding the \texttt{infix} auxiliary before leaving the above in the
-% input stream.
-%
-% We now explain the \texttt{infix} auxiliaries. We need some
-% flexibility in how we treat the case of equal precedences: most often,
-% the first operation encountered should be performed, such as |1-2-3|
-% being computed as |(1-2)-3|, but |2^3^4| should be evaluated as
-% |2^(3^4)| instead. For this reason, and to support the equivalence
-% between |**| and~|^| more easily, each binary operator is converted to
-% a control sequence |\__fp_parse_infix_|\meta{operator}|:N| when it is
-% encountered for the first time. Instead of passing both precedences
-% to a test function to do the comparison steps above, we pass the
-% \meta{precedence} (of the earlier operator) to the \texttt{infix}
-% auxiliary for the following \meta{operator}, to know whether to
-% perform the computation of the \meta{operator}. If it should not be
-% performed, the \texttt{infix} auxiliary expands to
-% \begin{syntax}
-% |@| \cs{use_none:n} |\__fp_parse_infix_|\meta{operator}|:N|
-% \end{syntax}
-% and otherwise it calls \cs{@@_parse_operand:Nw} with the precedence of
-% the \meta{operator} to find its second operand \meta{number_2} and the
-% next \meta{operator_2}, and expands to
-% \begin{syntax}
-% |@| \cs{@@_parse_apply_binary:NwNwN}
-% ~~~~\meta{operator} \meta{number_2}
-% |@| |\__fp_parse_infix_|\meta{operator_2}|:N|
-% \end{syntax}
-% The \texttt{infix} function is responsible for comparing precedences,
-% but cannot directly call the computation functions, because the first
-% operand \meta{number} is before the \texttt{infix} function in the
-% input stream. This is why we stop the expansion here and give control
-% to another function to close the loop.
-%
-% A definition of \cs{@@_parse_operand:Nw} \meta{precedence} with some
-% of the expansion control removed is
-% \begin{syntax}
-% \cs{exp_after:wN} \cs{@@_parse_continue:NwN}
-% \cs{exp_after:wN} \meta{precedence}
-% \cs{exp:w} \cs{exp_end_continue_f:w}
-% ~~\cs{@@_parse_one:Nw} \meta{precedence}
-% \end{syntax}
-% This expands \cs{@@_parse_one:Nw} \meta{precedence} completely, which
-% finds a number, wraps the next \meta{operator} into an \texttt{infix}
-% function, feeds this function the \meta{precedence}, and expands it,
-% yielding either
-% \begin{syntax}
-% \cs{@@_parse_continue:NwN} \meta{precedence}
-% \meta{number} |@|
-% \cs{use_none:n} |\__fp_parse_infix_|\meta{operator}|:N|
-% \end{syntax}
-% or
-% \begin{syntax}
-% \cs{@@_parse_continue:NwN} \meta{precedence}
-% \meta{number} |@|
-% \cs{@@_parse_apply_binary:NwNwN}
-% ~~\meta{operator} \meta{number_2}
-% |@| |\__fp_parse_infix_|\meta{operator_2}|:N|
-% \end{syntax}
-% The definition of \cs{@@_parse_continue:NwN} is then very simple:
-% \begin{syntax}
-% |\cs_new:Npn \__fp_parse_continue:NwN #1#2@#3 { #3 #1 #2 @ }|
-% \end{syntax}
-% In the first case, |#3|~is \cs{use_none:n}, yielding
-% \begin{syntax}
-% \cs{use_none:n} \meta{precedence} \meta{number} |@|
-% |\__fp_parse_infix_|\meta{operator}|:N|
-% \end{syntax}
-% then \meta{number} |@| |\__fp_parse_infix_|\meta{operator}|:N|. In
-% the second case, |#3|~is \cs{@@_parse_apply_binary:NwNwN}, whose role
-% is to compute \meta{number} \meta{operator} \meta{number_2} and to
-% prepare for the next comparison of precedences: first we get
-% \begin{syntax}
-% \cs{@@_parse_apply_binary:NwNwN}
-% ~~\meta{precedence} \meta{number} |@|
-% ~~\meta{operator} \meta{number_2}
-% |@| |\__fp_parse_infix_|\meta{operator_2}|:N|
-% \end{syntax}
-% then
-% \begin{syntax}
-% \cs{exp_after:wN} \cs{@@_parse_continue:NwN}
-% \cs{exp_after:wN} \meta{precedence}
-% \cs{exp:w} \cs{exp_end_continue_f:w}
-% |\__fp_|\meta{operator}|_o:ww| \meta{number} \meta{number_2}
-% \cs{exp:w} \cs{exp_end_continue_f:w}
-% |\__fp_parse_infix_|\meta{operator_2}|:N| \meta{precedence}
-% \end{syntax}
-% where |\__fp_|\meta{operator}|_o:ww| computes \meta{number}
-% \meta{operator} \meta{number_2} and expands after the result, thus
-% triggers the comparison of the precedence of the \meta{operator_2} and
-% the \meta{precedence}, continuing the loop.
-%
-% We have introduced the most important functions here, and the next few
-% paragraphs we describe various subtleties.
-%
-% \subsubsection{Prefix operators, parentheses, and functions}
-%
-% Prefix operators (unary |-|, |+|,~|!|) and parentheses are taken care
-% of by the same mechanism, and functions (\texttt{sin}, \texttt{exp},
-% etc.) as well. Finding the argument of the unary~|-|, for instance,
-% is very similar to grabbing the second operand of a binary infix
-% operator, with a subtle precedence explained below. Once that operand
-% is found, the operator can be applied to it (for the unary~|-|, this
-% simply flips the sign). A left parenthesis is just a prefix operator
-% with a very low precedence equal to that of the closing parenthesis
-% (which is treated as an infix operator, since it normally appears just
-% after numbers), so that all computations are performed until the
-% closing parenthesis. The prefix operator associated to the left
-% parenthesis does not alter its argument, but it removes the closing
-% parenthesis (with some checks).
-%
-% Prefix operators are the reason why we only summarily described the
-% function \cs{@@_parse_one:Nw} earlier. This function is responsible
-% for reading in the input stream the first possible \meta{number} and
-% the next infix \meta{operator}. If what follows \cs{@@_parse_one:Nw}
-% \meta{precedence} is a prefix operator, then we must find the operand
-% of this prefix operator through a nested call to
-% \cs{@@_parse_operand:Nw} with the appropriate precedence, then apply
-% the operator to the operand found to yield the result of
-% \cs{@@_parse_one:Nw}. So far, all is simple.
-%
-% The unary operators |+|, |-|,~|!| complicate things a little bit:
-% |-3**2| should be $-(3^2)=-9$, and not $(-3)^2=9$. This would easily
-% be done by giving~|-| a lower precedence, equal to that of the infix
-% |+| and~|-|. Unfortunately, this fails in cases such as |3**-2*4|,
-% yielding $3^{-2\times 4}$ instead of the correct $3^{-2}\times 4$. A
-% second attempt would be to call \cs{@@_parse_operand:Nw} with the
-% \meta{precedence} of the previous operator, but |0>-2+3| is then
-% parsed as |0>-(2+3)|: the addition is performed because it binds more
-% tightly than the comparision which precedes~|-|. The correct approach
-% is for a unary~|-| to perform operations whose precedence is greater
-% than both that of the previous operation, and that of the unary~|-|
-% itself. The unary~|-| is given a precedence higher than
-% multiplication and division. This does not lead to any surprising
-% result, since $-(x/y) = (-x)/y$ and similarly for multiplication, and
-% it reduces the number of nested calls to \cs{@@_parse_operand:Nw}.
-%
-% Functions are implemented as prefix operators with very high
-% precedence, so that their argument is the first number that can
-% possibly be built.
-%
-% Note that contrarily to the \texttt{infix} functions discussed
-% earlier, the \texttt{prefix} functions do perform tests on the
-% previous \meta{precedence} to decide whether to find an argument or
-% not, since we know that we need a number, and must never stop there.
-%
-% \subsubsection{Numbers and reading tokens one by one}
-%
-% So far, we have glossed over one important point: what is a
-% \enquote{number}? A number is typically given in the form
-% \meta{significand}|e|\meta{exponent}, where the \meta{significand} is
-% any non-empty string composed of decimal digits and at most one
-% decimal separator (a period), the exponent
-% \enquote{\texttt{e}\meta{exponent}} is optional and is composed of an
-% exponent mark~|e| followed by a possibly empty string of signs
-% |+| or~|-| and a non-empty string of decimal digits. The
-% \meta{significand} can also be an integer, dimension, skip, or muskip
-% variable, in which case dimensions are converted from points (or mu
-% units) to floating points, and the \meta{exponent} can also be an
-% integer variable. Numbers can also be given as floating point
-% variables, or as named constants such as |nan|, |inf| or~|pi|. We may
-% add more types in the future.
-%
-% When \cs{@@_parse_one:Nw} is looking for a \enquote{number}, here is
-% what happens.
-% \begin{itemize}
-% \item If the next token is a control sequence with the meaning of
-% \cs{scan_stop:}, it can be: \cs{s_@@}, in which case our job is
-% done, as what follows is an internal floating point number, or
-% \cs{s_@@_expr_mark}, in which case the expression has come to an early
-% end, as we are still looking for a number here, or something else,
-% in which case we consider the control sequence to be a bad
-% variable resulting from \texttt{c}-expansion.
-% \item If the next token is a control sequence with a different
-% meaning, we assume that it is a register, unpack it with
-% \cs{tex_the:D}, and use its value (in \texttt{pt} for dimensions
-% and skips, \texttt{mu} for muskips) as the \meta{significand} of a
-% number: we look for an exponent.
-% \item If the next token is a digit, we remove any leading zeros,
-% then read a significand larger than~$1$ if the next character is a
-% digit, read a significand smaller than~$1$ if the next character
-% is a period, or we have found a significand equal to~$0$
-% otherwise, and look for an exponent.
-% \item If the next token is a letter, we collect more letters until
-% the first non-letter: the resulting word may denote a function
-% such as |asin|, a constant such as |pi| or be unknown. In the
-% first case, we call \cs{@@_parse_operand:Nw} to find the argument
-% of the function, then apply the function, before declaring that we
-% are done. Otherwise, we are done, either with the value of the
-% constant, or with the value |nan| for unknown words.
-% \item If the next token is anything else, we check whether it is a
-% known prefix operator, in which case \cs{@@_parse_operand:Nw}
-% finds its operand. If it is not known, then either a number is
-% missing (if the token is a known infix operator) or the token is
-% simply invalid in floating point expressions.
-% \end{itemize}
-% Once a number is found, \cs{@@_parse_one:Nw} also finds an infix
-% operator. This goes as follows.
-% \begin{itemize}
-% \item If the next token is a control sequence, it could be the
-% special marker \cs{s_@@_expr_mark}, and
-% otherwise it is a case of juxtaposing numbers, such as
-% |2\c_zero_int|, with an implied multiplication.
-% \item If the next token is a letter, it is also a case of
-% juxtaposition, as letters cannot be proper infix operators.
-% \item Otherwise (including in the case of digits), if the token is a
-% known infix operator, the appropriate
-% |\__fp_infix_|\meta{operator}|:N| function is built, and if it
-% does not exist, we complain. In particular, the juxtaposition
-% |\c_zero_int 2| is disallowed.
-% \end{itemize}
-%
-% In the above, we need to test whether a character token~|#1| is a
-% digit:
-% \begin{verbatim}
-% \if_int_compare:w 9 < 1 \token_to_str:N #1 \exp_stop_f:
-% is a digit
-% \else:
-% not a digit
-% \fi:
-% \end{verbatim}
-% To exclude |0|, replace |9| by |10|. The use of
-% \cs{token_to_str:N} ensures that a digit with any catcode is detected.
-% To test if a character token is a letter, we need to work with its
-% character code, testing if |`#1| lies in $[65,90]$ (uppercase letters)
-% or $[97,112]$ (lowercase letters)
-% \begin{verbatim}
-% \if_int_compare:w \__fp_int_eval:w
-% ( `#1 \if_int_compare:w `#1 > `Z - 32 \fi: ) / 26 = 3 \exp_stop_f:
-% is a letter
-% \else:
-% not a letter
-% \fi:
-% \end{verbatim}
-% At all steps, we try to accept all category codes: when |#1|~is kept
-% to be used later, it is almost always converted to category code other
-% through \cs{token_to_str:N}. More precisely, catcodes $\{3, 6, 7, 8,
-% 11, 12\}$ should work without trouble, but not $\{1, 2, 4, 10, 13\}$,
-% and of course $\{0, 5, 9\}$ cannot become tokens.
-%
-% Floating point expressions should behave as much as possible like
-% \eTeX{}-based integer expressions and dimension expressions. In
-% particular, \texttt{f}-expansion should be performed as the expression
-% is read, token by token, forcing the expansion of protected macros,
-% and ignoring spaces. One advantage of expanding at every step is that
-% restricted expandable functions can then be used in floating point
-% expressions just as they can be in other kinds of expressions.
-% Problematically, spaces stop \texttt{f}-expansion: for instance, the
-% macro~|\X| below would not be expanded if we simply performed
-% \texttt{f}-expansion.
-% \begin{verbatim}
-% \DeclareDocumentCommand {\test} {m} { \fp_eval:n {#1} }
-% \ExplSyntaxOff
-% \test { 1 + \X }
-% \end{verbatim}
-% Of course, spaces typically do not appear in a code setting, but may very
-% easily come in document-level input, from which some expressions may
-% come. To avoid this problem, at every step, we do essentially what
-% \cs{use:f} would do: take an argument, put it back in the input
-% stream, then \texttt{f}-expand it. This is not a complete solution,
-% since a macro's expansion could contain leading spaces which would stop
-% the \texttt{f}-expansion before further macro calls are performed.
-% However, in practice it should be enough: in particular, floating
-% point numbers are correctly expanded to the underlying \cs{s_@@}
-% \ldots{} structure. The \texttt{f}-expansion is performed by
-% \cs{@@_parse_expand:w}.
-%
-% ^^A begin[todo]
-%
-% \subsection{Main auxiliary functions}
-%
-% \begin{macro}[rEXP]{\@@_parse_operand:Nw}
-% \begin{syntax}
-% \cs{exp:w} \cs{@@_parse_operand:Nw} \meta{precedence} \cs{@@_parse_expand:w}
-% \end{syntax}
-% Reads the \enquote{\ttfamily\ldots{}}, performing every computation
-% with a precedence higher than \meta{precedence}, then expands to
-% \begin{syntax}
-% \meta{result} |@| |\__fp_parse_infix_|\meta{operation}|:N| \ldots{}
-% \end{syntax}
-% where the \meta{operation} is the first operation with a lower
-% precedence, possibly \texttt{end}, and the
-% \enquote{\ttfamily\ldots{}} start just after the \meta{operation}.
-% \end{macro}
-%
-% \begin{macro}[EXP]{\@@_parse_infix_+:N}
-% \begin{syntax}
-% \cs{@@_parse_infix_+:N} \meta{precedence} \ldots{}
-% \end{syntax}
-% If |+|~has a precedence higher than the \meta{precedence}, cleans up
-% a second \meta{operand} and finds the \meta{operation_2} which
-% follows, and expands to
-% \begin{syntax}
-% |@| \cs{@@_parse_apply_binary:NwNwN} |+| \meta{operand} |@| \cs{@@_parse_infix_\meta{operation_2}:N} \ldots{}
-% \end{syntax}
-% Otherwise expands to
-% \begin{syntax}
-% |@| \cs{use_none:n} \cs{@@_parse_infix_+:N} \ldots{}
-% \end{syntax}
-% A similar function exists for each infix operator.
-% \end{macro}
-%
-% \begin{macro}[EXP]{\@@_parse_one:Nw}
-% \begin{syntax}
-% \cs{@@_parse_one:Nw} \meta{precedence} \ldots{}
-% \end{syntax}
-% Cleans up one or two operands depending on how the precedence of the
-% next operation compares to the \meta{precedence}. If the following
-% \meta{operation} has a precedence higher than \meta{precedence},
-% expands to
-% \begin{syntax}
-% \meta{operand_1} |@| \cs{@@_parse_apply_binary:NwNwN} \meta{operation} \meta{operand_2} |@| |\__fp_parse_infix_|\meta{operation_2}|:N| \ldots{}
-% \end{syntax}
-% and otherwise expands to
-% \begin{syntax}
-% \meta{operand} |@| \cs{use_none:n} |\__fp_parse_infix_|\meta{operation}|:N| \ldots{}
-% \end{syntax}
-% \end{macro}
-%
-% ^^A end[todo]
-%
-% \subsection{Helpers}
-%
-% \begin{macro}[rEXP]{\@@_parse_expand:w}
-% \begin{syntax}
-% \cs{exp:w} \cs{@@_parse_expand:w} \meta{tokens}
-% \end{syntax}
-% This function must always come within a \cs{exp:w} expansion.
-% The \meta{tokens} should be the part of the expression that we have
-% not yet read. This requires in particular closing all conditionals
-% properly before expanding.
-% \begin{macrocode}
-\cs_new:Npn \@@_parse_expand:w #1 { \exp_end_continue_f:w #1 }
-% \end{macrocode}
-% \end{macro}
-%
-% \begin{macro}[EXP]{\@@_parse_return_semicolon:w}
-% This very odd function swaps its position with the following
-% \cs{fi:} and removes \cs{@@_parse_expand:w} normally responsible for
-% expansion. That turns out to be useful.
-% \begin{macrocode}
-\cs_new:Npn \@@_parse_return_semicolon:w
- #1 \fi: \@@_parse_expand:w { \fi: ; #1 }
-% \end{macrocode}
-% \end{macro}
-%
-% \begin{macro}[rEXP]
-% {
-% \@@_parse_digits_vii:N ,
-% \@@_parse_digits_vi:N ,
-% \@@_parse_digits_v:N ,
-% \@@_parse_digits_iv:N ,
-% \@@_parse_digits_iii:N ,
-% \@@_parse_digits_ii:N ,
-% \@@_parse_digits_i:N ,
-% \@@_parse_digits_:N
-% }
-% These functions must be called within an \cs{int_value:w} or
-% \cs{@@_int_eval:w} construction. The first token which follows must
-% be \texttt{f}-expanded prior to calling those functions. The
-% functions read tokens one by one, and output digits into the input
-% stream, until meeting a non-digit, or up to a number of digits equal
-% to their index. The full expansion is
-% \begin{syntax}
-% \meta{digits} |;| \meta{filling 0} |;| \meta{length}
-% \end{syntax}
-% where \meta{filling 0} is a string of zeros such that \meta{digits}
-% \meta{filling 0} has the length given by the index of the function,
-% and \meta{length} is the number of zeros in the \meta{filling 0}
-% string. Each function puts a digit into the input stream and calls
-% the next function, until we find a non-digit. We are careful to
-% pass the tested tokens through \cs{token_to_str:N} to normalize
-% their category code.
-% \begin{macrocode}
-\cs_set_protected:Npn \@@_tmp:w #1 #2 #3
- {
- \cs_new:cpn { @@_parse_digits_ #1 :N } ##1
- {
- \if_int_compare:w 9 < 1 \token_to_str:N ##1 \exp_stop_f:
- \token_to_str:N ##1 \exp_after:wN #2 \exp:w
- \else:
- \@@_parse_return_semicolon:w #3 ##1
- \fi:
- \@@_parse_expand:w
- }
- }
-\@@_tmp:w {vii} \@@_parse_digits_vi:N { 0000000 ; 7 }
-\@@_tmp:w {vi} \@@_parse_digits_v:N { 000000 ; 6 }
-\@@_tmp:w {v} \@@_parse_digits_iv:N { 00000 ; 5 }
-\@@_tmp:w {iv} \@@_parse_digits_iii:N { 0000 ; 4 }
-\@@_tmp:w {iii} \@@_parse_digits_ii:N { 000 ; 3 }
-\@@_tmp:w {ii} \@@_parse_digits_i:N { 00 ; 2 }
-\@@_tmp:w {i} \@@_parse_digits_:N { 0 ; 1 }
-\cs_new:Npn \@@_parse_digits_:N { ; ; 0 }
-% \end{macrocode}
-% \end{macro}
-%
-% \subsection{Parsing one number}
-%
-% \begin{macro}[EXP]{\@@_parse_one:Nw}
-% This function finds one number, and packs the symbol which follows
-% in an \cs[no-index]{@@_parse_infix_\ldots{}} csname.
-% |#1|~is the previous \meta{precedence},
-% and |#2|~the first token of the operand. We distinguish four cases:
-% |#2|~is equal to \cs{scan_stop:} in meaning, |#2|~is a different
-% control sequence, |#2|~is a digit, and |#2|~is something else (this
-% last case is split further later). Despite the earlier
-% \texttt{f}-expansion, |#2|~may still be expandable if it was
-% protected by \cs{exp_not:N}, as may happen with the \LaTeXe{} command
-% \tn{protect}. Using a well placed \cs{reverse_if:N}, this case is
-% sent to \cs{@@_parse_one_fp:NN} which deals with it robustly.
-% \begin{macrocode}
-\cs_new:Npn \@@_parse_one:Nw #1 #2
- {
- \if_catcode:w \scan_stop: \exp_not:N #2
- \exp_after:wN \if_meaning:w \exp_not:N #2 #2 \else:
- \exp_after:wN \reverse_if:N
- \fi:
- \if_meaning:w \scan_stop: #2
- \exp_after:wN \exp_after:wN
- \exp_after:wN \@@_parse_one_fp:NN
- \else:
- \exp_after:wN \exp_after:wN
- \exp_after:wN \@@_parse_one_register:NN
- \fi:
- \else:
- \if_int_compare:w 9 < 1 \token_to_str:N #2 \exp_stop_f:
- \exp_after:wN \exp_after:wN
- \exp_after:wN \@@_parse_one_digit:NN
- \else:
- \exp_after:wN \exp_after:wN
- \exp_after:wN \@@_parse_one_other:NN
- \fi:
- \fi:
- #1 #2
- }
-% \end{macrocode}
-% \end{macro}
-%
-% \begin{macro}[EXP]
-% {
-% \@@_parse_one_fp:NN,
-% \@@_exp_after_expr_mark_f:nw,
-% \@@_exp_after_?_f:nw
-% }
-% This function receives a \meta{precedence} and a control sequence
-% equal to \cs{scan_stop:} in meaning. There are three cases.
-% \begin{itemize}
-% \item \cs{s_@@} starts a floating point number, and we call
-% \cs{@@_exp_after_f:nw}, which |f|-expands after the floating
-% point.
-% \item \cs{s_@@_expr_mark} is a premature end, we call
-% \cs{@@_exp_after_expr_mark_f:nw}, which triggers an |fp-early-end|
-% error.
-% \item For a control sequence not containing \cs[no-index]{s_@@}, we call
-% \cs{@@_exp_after_?_f:nw}, causing a |bad-variable| error.
-% \end{itemize}
-% This scheme is extensible: additional types can be added by starting
-% the variables with a scan mark of the form \cs[no-index]{s_@@_\meta{type}} and
-% defining |\__fp_exp_after_|\meta{type}|_f:nw|. In all cases, we
-% make sure that the second argument of \cs{@@_parse_infix:NN} is
-% correctly expanded.
-% A special case only enabled in \LaTeXe{} is that if \tn{protect} is
-% encountered then the error message mentions the control sequence
-% which follows it rather than \tn{protect} itself. The test for
-% \LaTeXe{} uses \tn{@unexpandable@protect} rather than \tn{protect}
-% because \tn{protect} is often \cs{scan_stop:} hence \enquote{does
-% not exist}.
-% \begin{macrocode}
-\cs_new:Npn \@@_parse_one_fp:NN #1
- {
- \@@_exp_after_any_f:nw
- {
- \exp_after:wN \@@_parse_infix:NN
- \exp_after:wN #1 \exp:w \@@_parse_expand:w
- }
- }
-\cs_new:Npn \@@_exp_after_expr_mark_f:nw #1
- {
- \int_case:nnF { \exp_after:wN \use_i:nnn \use_none:nnn #1 }
- {
- \c_@@_prec_comma_int { }
- \c_@@_prec_tuple_int { }
- \c_@@_prec_end_int
- {
- \exp_after:wN \c_@@_empty_tuple_fp
- \exp:w \exp_end_continue_f:w
- }
- }
- {
- \msg_expandable_error:nn { fp } { early-end }
- \exp_after:wN \c_nan_fp \exp:w \exp_end_continue_f:w
- }
- #1
- }
-\cs_new:cpn { @@_exp_after_?_f:nw } #1#2
- {
- \msg_expandable_error:nnn { kernel } { bad-variable }
- {#2}
- \exp_after:wN \c_nan_fp \exp:w \exp_end_continue_f:w #1
- }
-\cs_set_protected:Npn \@@_tmp:w #1
- {
- \cs_if_exist:NT #1
- {
- \cs_gset:cpn { @@_exp_after_?_f:nw } ##1##2
- {
- \exp_after:wN \c_nan_fp \exp:w \exp_end_continue_f:w ##1
- \str_if_eq:nnTF {##2} { \protect }
- {
- \cs_if_eq:NNTF ##2 #1 { \use_i:nn } { \use:n }
- {
- \msg_expandable_error:nnn { fp }
- { robust-cmd }
- }
- }
- {
- \msg_expandable_error:nnn { kernel }
- { bad-variable } {##2}
- }
- }
- }
- }
-\exp_args:Nc \@@_tmp:w { @unexpandable@protect }
-% \end{macrocode}
-% \end{macro}
-%
-% \begin{macro}[EXP]
-% {
-% \@@_parse_one_register:NN,
-% \@@_parse_one_register_aux:Nw,
-% \@@_parse_one_register_auxii:wwwNw,
-% \@@_parse_one_register_int:www,
-% \@@_parse_one_register_mu:www,
-% \@@_parse_one_register_dim:ww,
-% }
-% This is called whenever~|#2| is a control sequence other than
-% \cs{scan_stop:} in meaning. We special-case \tn{wd}, \tn{ht}, \tn{dp}
-% (see later) and otherwise assume that it is a register, but
-% carefully unpack it with \cs{tex_the:D} within braces. First, we
-% find the exponent following~|#2|. Then we unpack~|#2| with
-% \cs{tex_the:D}, and the \texttt{auxii} auxiliary distinguishes
-% integer registers from dimensions/skips from muskips, according to
-% the presence of a period and/or of |pt|. For integers, simply
-% convert \meta{value}|e|\meta{exponent} to a floating point number
-% with \cs{@@_parse:n} (this is somewhat wasteful). For other
-% registers, the decimal rounding provided by \TeX{} does not
-% accurately represent the binary value that it manipulates, so we
-% extract this binary value as a number of scaled points with
-% \cs{int_value:w} \cs{dim_to_decimal_in_sp:n} |{| \meta{decimal value} |pt| |}|, and
-% use an auxiliary of \cs{dim_to_fp:n}, which performs the
-% multiplication by $2^{-16}$, correctly rounded.
-% \begin{macrocode}
-\cs_new:Npn \@@_parse_one_register:NN #1#2
- {
- \exp_after:wN \@@_parse_infix_after_operand:NwN
- \exp_after:wN #1
- \exp:w \exp_end_continue_f:w
- \@@_parse_one_register_special:N #2
- \exp_after:wN \@@_parse_one_register_aux:Nw
- \exp_after:wN #2
- \int_value:w
- \exp_after:wN \@@_parse_exponent:N
- \exp:w \@@_parse_expand:w
- }
-\cs_new:Npe \@@_parse_one_register_aux:Nw #1
- {
- \exp_not:n
- {
- \exp_after:wN \use:nn
- \exp_after:wN \@@_parse_one_register_auxii:wwwNw
- }
- \exp_not:N \exp_after:wN { \exp_not:N \tex_the:D #1 }
- ; \exp_not:N \@@_parse_one_register_dim:ww
- \tl_to_str:n { pt } ; \exp_not:N \@@_parse_one_register_mu:www
- . \tl_to_str:n { pt } ; \exp_not:N \@@_parse_one_register_int:www
- \s_@@_stop
- }
-\exp_args:Nno \use:nn
- { \cs_new:Npn \@@_parse_one_register_auxii:wwwNw #1 . #2 }
- { \tl_to_str:n { pt } #3 ; #4#5 \s_@@_stop }
- { #4 #1.#2; }
-\exp_args:Nno \use:nn
- { \cs_new:Npn \@@_parse_one_register_mu:www #1 }
- { \tl_to_str:n { mu } ; #2 ; }
- { \@@_parse_one_register_dim:ww #1 ; }
-\cs_new:Npn \@@_parse_one_register_int:www #1; #2.; #3;
- { \@@_parse:n { #1 e #3 } }
-\cs_new:Npn \@@_parse_one_register_dim:ww #1; #2;
- {
- \exp_after:wN \@@_from_dim_test:ww
- \int_value:w #2 \exp_after:wN ,
- \int_value:w \dim_to_decimal_in_sp:n { #1 pt } ;
- }
-% \end{macrocode}
-% \end{macro}
-%
-% \begin{macro}
-% {
-% \@@_parse_one_register_special:N,
-% \@@_parse_one_register_math:NNw,
-% \@@_parse_one_register_wd:w,
-% \@@_parse_one_register_wd:Nw
-% }
-% The \tn{wd}, \tn{dp}, \tn{ht} primitives expect an integer argument.
-% We abuse the exponent parser to find the integer argument: simply
-% include the exponent marker~|e|. Once that \enquote{exponent} is
-% found, use \cs{tex_the:D} to find the box dimension and then copy
-% what we did for dimensions.
-% \begin{macrocode}
-\cs_new:Npn \@@_parse_one_register_special:N #1
- {
- \if_meaning:w \box_wd:N #1 \@@_parse_one_register_wd:w \fi:
- \if_meaning:w \box_ht:N #1 \@@_parse_one_register_wd:w \fi:
- \if_meaning:w \box_dp:N #1 \@@_parse_one_register_wd:w \fi:
- \if_meaning:w \infty #1
- \@@_parse_one_register_math:NNw \infty #1
- \fi:
- \if_meaning:w \pi #1
- \@@_parse_one_register_math:NNw \pi #1
- \fi:
- }
-\cs_new:Npn \@@_parse_one_register_math:NNw
- #1#2#3#4 \@@_parse_expand:w
- {
- #3
- \str_if_eq:nnTF {#1} {#2}
- {
- \msg_expandable_error:nnn
- { fp } { infty-pi } {#1}
- \c_nan_fp
- }
- { #4 \@@_parse_expand:w }
- }
-\cs_new:Npn \@@_parse_one_register_wd:w
- #1#2 \exp_after:wN #3#4 \@@_parse_expand:w
- {
- #1
- \exp_after:wN \@@_parse_one_register_wd:Nw
- #4 \@@_parse_expand:w e
- }
-\cs_new:Npn \@@_parse_one_register_wd:Nw #1#2 ;
- {
- \exp_after:wN \@@_from_dim_test:ww
- \exp_after:wN 0 \exp_after:wN ,
- \int_value:w \dim_to_decimal_in_sp:n { #1 #2 } ;
- }
-% \end{macrocode}
-% \end{macro}
-%
-% \begin{macro}[EXP]{\@@_parse_one_digit:NN}
-% A digit marks the beginning of an explicit floating point number.
-% Once the number is found, we catch the case of overflow and
-% underflow with \cs{@@_sanitize:wN}, then
-% \cs{@@_parse_infix_after_operand:NwN} expands \cs{@@_parse_infix:NN}
-% after the number we find, to wrap the following infix operator as
-% required. Finding the number itself begins by removing leading
-% zeros: further steps are described later.
-% \begin{macrocode}
-\cs_new:Npn \@@_parse_one_digit:NN #1
- {
- \exp_after:wN \@@_parse_infix_after_operand:NwN
- \exp_after:wN #1
- \exp:w \exp_end_continue_f:w
- \exp_after:wN \@@_sanitize:wN
- \int_value:w \@@_int_eval:w 0 \@@_parse_trim_zeros:N
- }
-% \end{macrocode}
-% \end{macro}
-%
-% \begin{macro}[EXP]{\@@_parse_one_other:NN}
-% For this function, |#2|~is a character token which is not a digit.
-% If it is an \textsc{ascii} letter, \cs{@@_parse_letters:N} beyond this one and give
-% the result to \cs{@@_parse_word:Nw}. Otherwise, the character is
-% assumed to be a prefix operator, and we build
-% |\__fp_parse_prefix_|\meta{operator}|:Nw|.
-% \begin{macrocode}
-\cs_new:Npn \@@_parse_one_other:NN #1 #2
- {
- \if_int_compare:w
- \@@_int_eval:w
- ( `#2 \if_int_compare:w `#2 > `Z - 32 \fi: ) / 26
- = 3 \exp_stop_f:
- \exp_after:wN \@@_parse_word:Nw
- \exp_after:wN #1
- \exp_after:wN #2
- \exp:w \exp_after:wN \@@_parse_letters:N
- \exp:w
- \else:
- \exp_after:wN \@@_parse_prefix:NNN
- \exp_after:wN #1
- \exp_after:wN #2
- \cs:w
- @@_parse_prefix_ \token_to_str:N #2 :Nw
- \exp_after:wN
- \cs_end:
- \exp:w
- \fi:
- \@@_parse_expand:w
- }
-% \end{macrocode}
-% \end{macro}
-%
-% \begin{macro}[EXP]{\@@_parse_word:Nw}
-% \begin{macro}[rEXP]{\@@_parse_letters:N}
-% Finding letters is a simple recursion. Once \cs{@@_parse_letters:N}
-% has done its job, we try to build a control sequence from the
-% word~|#2|. If it is a known word, then the corresponding action is
-% taken, and otherwise, we complain about an unknown word, yield
-% \cs{c_nan_fp}, and look for the following infix operator. Note that
-% the unknown word could be a mistyped function as well as a mistyped
-% constant, so there is no way to tell whether to look for arguments;
-% we do not.
-% The standard requires \enquote{inf} and \enquote{infinity} and
-% \enquote{nan} to be recognized regardless of case, but we probably
-% don't want to allow every \pkg{l3fp} word to have an arbitrary
-% mixture of lower and upper case, so we test and use a
-% differently-named control sequence.
-% \begin{macrocode}
-\cs_new:Npn \@@_parse_word:Nw #1#2;
- {
- \cs_if_exist_use:cF { @@_parse_word_#2:N }
- {
- \cs_if_exist_use:cF
- { @@_parse_caseless_ \str_casefold:n {#2} :N }
- {
- \msg_expandable_error:nnn
- { fp } { unknown-fp-word } {#2}
- \exp_after:wN \c_nan_fp \exp:w \exp_end_continue_f:w
- \@@_parse_infix:NN
- }
- }
- #1
- }
-\cs_new:Npn \@@_parse_letters:N #1
- {
- \exp_end_continue_f:w
- \if_int_compare:w
- \if_catcode:w \scan_stop: \exp_not:N #1
- 0
- \else:
- \@@_int_eval:w
- ( `#1 \if_int_compare:w `#1 > `Z - 32 \fi: ) / 26
- \fi:
- = 3 \exp_stop_f:
- \exp_after:wN #1
- \exp:w \exp_after:wN \@@_parse_letters:N
- \exp:w
- \else:
- \@@_parse_return_semicolon:w #1
- \fi:
- \@@_parse_expand:w
- }
-% \end{macrocode}
-% \end{macro}
-% \end{macro}
-%
-% \begin{macro}[EXP]
-% {\@@_parse_prefix:NNN, \@@_parse_prefix_unknown:NNN}
-% For this function, |#1|~is the previous \meta{precedence}, |#2|~is
-% the operator just seen, and |#3|~is a control sequence which
-% implements the operator if it is a known operator. If this control
-% sequence is \cs{scan_stop:}, then the operator is in fact unknown.
-% Either the expression is missing a number there (if the operator is
-% valid as an infix operator), and we put \texttt{nan}, wrapping the
-% infix operator in a csname as appropriate, or the character is
-% simply invalid in floating point expressions, and we continue
-% looking for a number, starting again from \cs{@@_parse_one:Nw}.
-% \begin{macrocode}
-\cs_new:Npn \@@_parse_prefix:NNN #1#2#3
- {
- \if_meaning:w \scan_stop: #3
- \exp_after:wN \@@_parse_prefix_unknown:NNN
- \exp_after:wN #2
- \fi:
- #3 #1
- }
-\cs_new:Npn \@@_parse_prefix_unknown:NNN #1#2#3
- {
- \cs_if_exist:cTF { @@_parse_infix_ \token_to_str:N #1 :N }
- {
- \msg_expandable_error:nnn
- { fp } { missing-number } {#1}
- \exp_after:wN \c_nan_fp \exp:w \exp_end_continue_f:w
- \@@_parse_infix:NN #3 #1
- }
- {
- \msg_expandable_error:nnn
- { fp } { unknown-symbol } {#1}
- \@@_parse_one:Nw #3
- }
- }
-% \end{macrocode}
-% \end{macro}
-%
-% \subsubsection{Numbers: trimming leading zeros}
-%
-% Numbers are parsed as follows: first we trim leading zeros, then
-% if the next character is a digit, start reading a significand $\geq 1$
-% with the set of functions |\__fp_parse_large|\ldots{}; if it is a
-% period, the significand is~$<1$; and otherwise it is zero. In the
-% second case, trim additional zeros after the period, counting them for
-% an exponent shift $\meta{exp_1}<0$, then read the significand with the
-% set of functions |\__fp_parse_small|\ldots{} Once the significand is
-% read, read the exponent if |e|~is present.
-%
-% \begin{macro}[rEXP]{\@@_parse_trim_zeros:N, \@@_parse_trim_end:w}
-% This function expects an already expanded token. It removes any
-% leading zero, then distinguishes three cases: if the first non-zero
-% token is a digit, then call \cs{@@_parse_large:N} (the significand
-% is $\geq 1$); if it is |.|, then continue trimming zeros with
-% \cs{@@_parse_strim_zeros:N}; otherwise, our number is exactly zero,
-% and we call \cs{@@_parse_zero:} to take care of that case.
-% \begin{macrocode}
-\cs_new:Npn \@@_parse_trim_zeros:N #1
- {
- \if:w 0 \exp_not:N #1
- \exp_after:wN \@@_parse_trim_zeros:N
- \exp:w
- \else:
- \if:w . \exp_not:N #1
- \exp_after:wN \@@_parse_strim_zeros:N
- \exp:w
- \else:
- \@@_parse_trim_end:w #1
- \fi:
- \fi:
- \@@_parse_expand:w
- }
-\cs_new:Npn \@@_parse_trim_end:w #1 \fi: \fi: \@@_parse_expand:w
- {
- \fi:
- \fi:
- \if_int_compare:w 9 < 1 \token_to_str:N #1 \exp_stop_f:
- \exp_after:wN \@@_parse_large:N
- \else:
- \exp_after:wN \@@_parse_zero:
- \fi:
- #1
- }
-% \end{macrocode}
-% \end{macro}
-%
-% \begin{macro}[rEXP]
-% {\@@_parse_strim_zeros:N, \@@_parse_strim_end:w}
-% If we have removed all digits until a period (or if the body started
-% with a period), then enter the \enquote{\texttt{small_trim}} loop
-% which outputs $-1$ for each removed~$0$. Those $-1$ are added to an
-% integer expression waiting for the exponent. If the first non-zero
-% token is a digit, call \cs{@@_parse_small:N} (our significand is
-% smaller than~$1$), and otherwise, the number is an exact zero. The
-% name \texttt{strim} stands for \enquote{small trim}.
-% \begin{macrocode}
-\cs_new:Npn \@@_parse_strim_zeros:N #1
- {
- \if:w 0 \exp_not:N #1
- - 1
- \exp_after:wN \@@_parse_strim_zeros:N \exp:w
- \else:
- \@@_parse_strim_end:w #1
- \fi:
- \@@_parse_expand:w
- }
-\cs_new:Npn \@@_parse_strim_end:w #1 \fi: \@@_parse_expand:w
- {
- \fi:
- \if_int_compare:w 9 < 1 \token_to_str:N #1 \exp_stop_f:
- \exp_after:wN \@@_parse_small:N
- \else:
- \exp_after:wN \@@_parse_zero:
- \fi:
- #1
- }
-% \end{macrocode}
-% \end{macro}
-%
-% \begin{macro}[EXP]{\@@_parse_zero:}
-% After reading a significand of~$0$, find any exponent, then put a
-% sign of~|1| for \cs{@@_sanitize:wN}, which removes everything
-% and leaves an exact zero.
-% \begin{macrocode}
-\cs_new:Npn \@@_parse_zero:
- {
- \exp_after:wN ; \exp_after:wN 1
- \int_value:w \@@_parse_exponent:N
- }
-% \end{macrocode}
-% \end{macro}
-%
-% \subsubsection{Number: small significand}
-%
-% \begin{macro}[rEXP]{\@@_parse_small:N}
-% This function is called after we have passed the decimal separator
-% and removed all leading zeros from the significand. It is followed
-% by a non-zero digit (with any catcode). The goal is to read up to
-% $16$ digits. But we can't do that all at once, because
-% \cs{int_value:w} (which allows us to collect digits and continue
-% expanding) can only go up to $9$ digits. Hence we grab digits in
-% two steps of $8$ digits. Since |#1| is a digit, read seven more
-% digits using \cs{@@_parse_digits_vii:N}. The \texttt{small_leading}
-% auxiliary leaves those digits in the \cs{int_value:w}, and
-% grabs some more, or stops if there are no more digits. Then the
-% \texttt{pack_leading} auxiliary puts the various parts in the
-% appropriate order for the processing further up.
-% \begin{macrocode}
-\cs_new:Npn \@@_parse_small:N #1
- {
- \exp_after:wN \@@_parse_pack_leading:NNNNNww
- \int_value:w \@@_int_eval:w 1 \token_to_str:N #1
- \exp_after:wN \@@_parse_small_leading:wwNN
- \int_value:w 1
- \exp_after:wN \@@_parse_digits_vii:N
- \exp:w \@@_parse_expand:w
- }
-% \end{macrocode}
-% \end{macro}
-%
-% \begin{macro}[rEXP]{\@@_parse_small_leading:wwNN}
-% \begin{syntax}
-% \cs{@@_parse_small_leading:wwNN} |1| \meta{digits} |;| \meta{zeros} |;| \meta{number~of~zeros}
-% \end{syntax}
-% We leave \meta{digits} \meta{zeros} in the input stream: the
-% functions used to grab digits are such that this constitutes digits
-% $1$ through~$8$ of the significand. Then prepare to pack $8$~more
-% digits, with an exponent shift of zero (this shift is used in
-% the case of a large significand). If |#4|~is a digit, leave it
-% behind for the packing function, and read $6$~more digits to reach a
-% total of $15$~digits: further digits are involved in the rounding.
-% Otherwise put $8$~zeros in to complete the significand, then look
-% for an exponent.
-% \begin{macrocode}
-\cs_new:Npn \@@_parse_small_leading:wwNN 1 #1 ; #2; #3 #4
- {
- #1 #2
- \exp_after:wN \@@_parse_pack_trailing:NNNNNNww
- \exp_after:wN 0
- \int_value:w \@@_int_eval:w 1
- \if_int_compare:w 9 < 1 \token_to_str:N #4 \exp_stop_f:
- \token_to_str:N #4
- \exp_after:wN \@@_parse_small_trailing:wwNN
- \int_value:w 1
- \exp_after:wN \@@_parse_digits_vi:N
- \exp:w
- \else:
- 0000 0000 \@@_parse_exponent:Nw #4
- \fi:
- \@@_parse_expand:w
- }
-% \end{macrocode}
-% \end{macro}
-%
-% \begin{macro}[rEXP]{\@@_parse_small_trailing:wwNN}
-% \begin{syntax}
-% \cs{@@_parse_small_trailing:wwNN} |1| \meta{digits} |;| \meta{zeros} |;| \meta{number~of~zeros} \meta{next~token}
-% \end{syntax}
-% Leave digits $10$ to~$15$ (arguments |#1| and |#2|) in the input
-% stream. If the \meta{next~token} is a digit, it is the $16$th
-% digit, we keep it, then the \texttt{small_round} auxiliary considers
-% this digit and all further digits to perform the rounding: the
-% function expands to nothing, to |+0| or to |+1|.
-% Otherwise, there is no $16$-th digit, so we put a~$0$, and look for
-% an exponent.
-% \begin{macrocode}
-\cs_new:Npn \@@_parse_small_trailing:wwNN 1 #1 ; #2; #3 #4
- {
- #1 #2
- \if_int_compare:w 9 < 1 \token_to_str:N #4 \exp_stop_f:
- \token_to_str:N #4
- \exp_after:wN \@@_parse_small_round:NN
- \exp_after:wN #4
- \exp:w
- \else:
- 0 \@@_parse_exponent:Nw #4
- \fi:
- \@@_parse_expand:w
- }
-% \end{macrocode}
-% \end{macro}
-%
-% \begin{macro}[rEXP]
-% {
-% \@@_parse_pack_trailing:NNNNNNww ,
-% \@@_parse_pack_leading:NNNNNww ,
-% \@@_parse_pack_carry:w
-% }
-% Those functions are expanded after all the digits are found, we took
-% care of the rounding, as well as the exponent. The last argument is
-% the exponent. The previous five arguments are $8$~digits which we
-% pack in groups of~$4$, and the argument before that is~$1$, except
-% in the rare case where rounding lead to a carry, in which case the
-% argument is~$2$. The \texttt{trailing} function has an exponent
-% shift as its first argument, which we add to the exponent found in
-% the |e...| syntax. If the trailing digits cause a carry, the
-% integer expression for the leading digits is incremented (|+1|
-% in the code below). If the leading digits propagate this carry all
-% the way up, the function \cs{@@_parse_pack_carry:w} increments the
-% exponent, and changes the significand from |0000...| to |1000...|:
-% this is simple because such a carry can only occur to give rise to a
-% power of~$10$.
-% \begin{macrocode}
-\cs_new:Npn \@@_parse_pack_trailing:NNNNNNww #1 #2 #3#4#5#6 #7; #8 ;
- {
- \if_meaning:w 2 #2 + 1 \fi:
- ; #8 + #1 ; {#3#4#5#6} {#7};
- }
-\cs_new:Npn \@@_parse_pack_leading:NNNNNww #1 #2#3#4#5 #6; #7;
- {
- + #7
- \if_meaning:w 2 #1 \@@_parse_pack_carry:w \fi:
- ; 0 {#2#3#4#5} {#6}
- }
-\cs_new:Npn \@@_parse_pack_carry:w \fi: ; 0 #1
- { \fi: + 1 ; 0 {1000} }
-% \end{macrocode}
-% \end{macro}
-%
-% \subsubsection{Number: large significand}
-%
-% Parsing a significand larger than~$1$ is a little bit more difficult
-% than parsing small significands. We need to count the number of
-% digits before the decimal separator, and add that to the final
-% exponent. We also need to test for the presence of a dot each time we
-% run out of digits, and branch to the appropriate \texttt{parse_small}
-% function in those cases.
-%
-% \begin{macro}[EXP]{\@@_parse_large:N}
-% This function is followed by the first non-zero digit of a
-% \enquote{large} significand ($\geq 1$). It is called within an
-% integer expression for the exponent. Grab up to $7$~more digits,
-% for a total of $8$~digits.
-% \begin{macrocode}
-\cs_new:Npn \@@_parse_large:N #1
- {
- \exp_after:wN \@@_parse_large_leading:wwNN
- \int_value:w 1 \token_to_str:N #1
- \exp_after:wN \@@_parse_digits_vii:N
- \exp:w \@@_parse_expand:w
- }
-% \end{macrocode}
-% \end{macro}
-%
-% \begin{macro}[rEXP]{\@@_parse_large_leading:wwNN}
-% \begin{syntax}
-% \cs{@@_parse_large_leading:wwNN} |1| \meta{digits} |;| \meta{zeros} |;| \meta{number~of~zeros} \meta{next~token}
-% \end{syntax}
-% We shift the exponent by the number of digits in~|#1|, namely the
-% target number, $8$, minus the \meta{number of zeros} (number of
-% digits missing). Then prepare to pack the $8$~first digits. If the
-% \meta{next token} is a digit, read up to $6$~more digits (digits
-% $10$ to~$15$). If it is a period, try to grab the end of our
-% $8$~first digits, branching to the \texttt{small} functions since
-% the number of digit does not affect the exponent anymore. Finally,
-% if this is the end of the significand, insert the \meta{zeros} to
-% complete the $8$~first digits, insert $8$~more, and look for an
-% exponent.
-% \begin{macrocode}
-\cs_new:Npn \@@_parse_large_leading:wwNN 1 #1 ; #2; #3 #4
- {
- + \c_@@_half_prec_int - #3
- \exp_after:wN \@@_parse_pack_leading:NNNNNww
- \int_value:w \@@_int_eval:w 1 #1
- \if_int_compare:w 9 < 1 \token_to_str:N #4 \exp_stop_f:
- \exp_after:wN \@@_parse_large_trailing:wwNN
- \int_value:w 1 \token_to_str:N #4
- \exp_after:wN \@@_parse_digits_vi:N
- \exp:w
- \else:
- \if:w . \exp_not:N #4
- \exp_after:wN \@@_parse_small_leading:wwNN
- \int_value:w 1
- \cs:w
- @@_parse_digits_
- \@@_int_to_roman:w #3
- :N \exp_after:wN
- \cs_end:
- \exp:w
- \else:
- #2
- \exp_after:wN \@@_parse_pack_trailing:NNNNNNww
- \exp_after:wN 0
- \int_value:w 1 0000 0000
- \@@_parse_exponent:Nw #4
- \fi:
- \fi:
- \@@_parse_expand:w
- }
-% \end{macrocode}
-% \end{macro}
-%
-% \begin{macro}[EXP]{\@@_parse_large_trailing:wwNN}
-% \begin{syntax}
-% \cs{@@_parse_large_trailing:wwNN} |1| \meta{digits} |;| \meta{zeros} |;| \meta{number~of~zeros} \meta{next~token}
-% \end{syntax}
-% We have just read $15$~digits. If the \meta{next token} is a digit,
-% then the exponent shift caused by this block of $8$~digits is~$8$,
-% first argument to the \texttt{pack_trailing} function. We keep the
-% \meta{digits} and this $16$-th digit, and find how this should be
-% rounded using \cs{@@_parse_large_round:NN}. Otherwise, the exponent
-% shift is the number of \meta{digits}, $7$~minus the \meta{number of
-% zeros}, and we test for a decimal point. This case happens in
-% |123451234512345.67| with exactly $15$ digits before the decimal
-% separator. Then branch to the appropriate \texttt{small} auxiliary,
-% grabbing a few more digits to complement the digits we already
-% grabbed. Finally, if this is truly the end of the significand, look
-% for an exponent after using the \meta{zeros} and providing a $16$-th
-% digit of~$0$.
-% \begin{macrocode}
-\cs_new:Npn \@@_parse_large_trailing:wwNN 1 #1 ; #2; #3 #4
- {
- \if_int_compare:w 9 < 1 \token_to_str:N #4 \exp_stop_f:
- \exp_after:wN \@@_parse_pack_trailing:NNNNNNww
- \exp_after:wN \c_@@_half_prec_int
- \int_value:w \@@_int_eval:w 1 #1 \token_to_str:N #4
- \exp_after:wN \@@_parse_large_round:NN
- \exp_after:wN #4
- \exp:w
- \else:
- \exp_after:wN \@@_parse_pack_trailing:NNNNNNww
- \int_value:w \@@_int_eval:w 7 - #3 \exp_stop_f:
- \int_value:w \@@_int_eval:w 1 #1
- \if:w . \exp_not:N #4
- \exp_after:wN \@@_parse_small_trailing:wwNN
- \int_value:w 1
- \cs:w
- @@_parse_digits_
- \@@_int_to_roman:w #3
- :N \exp_after:wN
- \cs_end:
- \exp:w
- \else:
- #2 0 \@@_parse_exponent:Nw #4
- \fi:
- \fi:
- \@@_parse_expand:w
- }
-% \end{macrocode}
-% \end{macro}
-%
-% \subsubsection{Number: beyond 16 digits, rounding}
-%
-% \begin{macro}[rEXP]{\@@_parse_round_loop:N, \@@_parse_round_up:N}
-% This loop is called when rounding a number (whether the mantissa is
-% small or large). It should appear in an integer expression. This
-% function reads digits one by one, until reaching a non-digit, and
-% adds~$1$ to the integer expression for each digit. If all digits
-% found are~$0$, the function ends the expression by |;0|,
-% otherwise by |;1|. This is done by switching the loop to
-% |round_up| at the first non-zero digit, thus we avoid to test
-% whether digits are~$0$ or not once we see a first non-zero digit.
-% \begin{macrocode}
-\cs_new:Npn \@@_parse_round_loop:N #1
- {
- \if_int_compare:w 9 < 1 \token_to_str:N #1 \exp_stop_f:
- + 1
- \if:w 0 \token_to_str:N #1
- \exp_after:wN \@@_parse_round_loop:N
- \exp:w
- \else:
- \exp_after:wN \@@_parse_round_up:N
- \exp:w
- \fi:
- \else:
- \@@_parse_return_semicolon:w 0 #1
- \fi:
- \@@_parse_expand:w
- }
-\cs_new:Npn \@@_parse_round_up:N #1
- {
- \if_int_compare:w 9 < 1 \token_to_str:N #1 \exp_stop_f:
- + 1
- \exp_after:wN \@@_parse_round_up:N
- \exp:w
- \else:
- \@@_parse_return_semicolon:w 1 #1
- \fi:
- \@@_parse_expand:w
- }
-% \end{macrocode}
-% \end{macro}
-%
-% \begin{macro}[rEXP]{\@@_parse_round_after:wN}
-% After the loop \cs{@@_parse_round_loop:N}, this function fetches an
-% exponent with \cs{@@_parse_exponent:N}, and combines it with the
-% number of digits counted by \cs{@@_parse_round_loop:N}. At the same
-% time, the result |0| or |1| is added to the
-% surrounding integer expression.
-% \begin{macrocode}
-\cs_new:Npn \@@_parse_round_after:wN #1; #2
- {
- + #2 \exp_after:wN ;
- \int_value:w \@@_int_eval:w #1 + \@@_parse_exponent:N
- }
-% \end{macrocode}
-% \end{macro}
-%
-% \begin{macro}[rEXP]
-% {\@@_parse_small_round:NN, \@@_parse_round_after:wN}
-% Here, |#1|~is the digit that we are currently rounding (we only care
-% whether it is even or odd). If |#2|~is not a digit, then fetch an
-% exponent and expand to |;|\meta{exponent} only. Otherwise, we
-% expand to |+0| or |+1|, then |;|\meta{exponent}. To
-% decide which, call \cs{@@_round_s:NNNw} to know whether to round up,
-% giving it as arguments a sign~$0$ (all explicit numbers are
-% positive), the digit |#1|~to round, the first following digit~|#2|,
-% and either |+0| or |+1| depending on whether the
-% following digits are all zero or not. This last argument is
-% obtained by \cs{@@_parse_round_loop:N}, whose number of digits we
-% discard by multiplying it by~$0$. The exponent which follows the
-% number is also fetched by \cs{@@_parse_round_after:wN}.
-% \begin{macrocode}
-\cs_new:Npn \@@_parse_small_round:NN #1#2
- {
- \if_int_compare:w 9 < 1 \token_to_str:N #2 \exp_stop_f:
- +
- \exp_after:wN \@@_round_s:NNNw
- \exp_after:wN 0
- \exp_after:wN #1
- \exp_after:wN #2
- \int_value:w \@@_int_eval:w
- \exp_after:wN \@@_parse_round_after:wN
- \int_value:w \@@_int_eval:w 0 * \@@_int_eval:w 0
- \exp_after:wN \@@_parse_round_loop:N
- \exp:w
- \else:
- \@@_parse_exponent:Nw #2
- \fi:
- \@@_parse_expand:w
- }
-% \end{macrocode}
-% \end{macro}
-%
-%
-% \begin{macro}[rEXP]
-% {
-% \@@_parse_large_round:NN,
-% \@@_parse_large_round_test:NN,
-% \@@_parse_large_round_aux:wNN,
-% }
-% Large numbers are harder to round, as there may be a period in the
-% way. Again, |#1|~is the digit that we are currently rounding (we
-% only care whether it is even or odd). If there are no more digits
-% (|#2|~is not a digit), then we must test for a period: if there is
-% one, then switch to the rounding function for small significands,
-% otherwise fetch an exponent. If there are more digits (|#2|~is a
-% digit), then round, checking with \cs{@@_parse_round_loop:N} if all
-% further digits vanish, or some are non-zero. This loop is not
-% enough, as it is stopped by a period. After the loop, the
-% \texttt{aux} function tests for a period: if it is present, then we
-% must continue looking for digits, this time discarding the number of
-% digits we find.
-% \begin{macrocode}
-\cs_new:Npn \@@_parse_large_round:NN #1#2
- {
- \if_int_compare:w 9 < 1 \token_to_str:N #2 \exp_stop_f:
- +
- \exp_after:wN \@@_round_s:NNNw
- \exp_after:wN 0
- \exp_after:wN #1
- \exp_after:wN #2
- \int_value:w \@@_int_eval:w
- \exp_after:wN \@@_parse_large_round_aux:wNN
- \int_value:w \@@_int_eval:w 1
- \exp_after:wN \@@_parse_round_loop:N
- \else: %^^A could be dot, or e, or other
- \exp_after:wN \@@_parse_large_round_test:NN
- \exp_after:wN #1
- \exp_after:wN #2
- \fi:
- }
-\cs_new:Npn \@@_parse_large_round_test:NN #1#2
- {
- \if:w . \exp_not:N #2
- \exp_after:wN \@@_parse_small_round:NN
- \exp_after:wN #1
- \exp:w
- \else:
- \@@_parse_exponent:Nw #2
- \fi:
- \@@_parse_expand:w
- }
-\cs_new:Npn \@@_parse_large_round_aux:wNN #1 ; #2 #3
- {
- + #2
- \exp_after:wN \@@_parse_round_after:wN
- \int_value:w \@@_int_eval:w #1
- \if:w . \exp_not:N #3
- + 0 * \@@_int_eval:w 0
- \exp_after:wN \@@_parse_round_loop:N
- \exp:w \exp_after:wN \@@_parse_expand:w
- \else:
- \exp_after:wN ;
- \exp_after:wN 0
- \exp_after:wN #3
- \fi:
- }
-% \end{macrocode}
-% \end{macro}
-%
-% \subsubsection{Number: finding the exponent}
-%
-% Expansion is a little bit tricky here, in part because we accept input
-% where multiplication is implicit.
-% \begin{syntax}
-% \cs{@@_parse:n} |{ 3.2 erf(0.1) }|
-% \cs{@@_parse:n} |{ 3.2 e\l_my_int }|
-% \cs{@@_parse:n} |{ 3.2 \c_pi_fp }|
-% \end{syntax}
-% The first case indicates that just looking one character ahead for an
-% \enquote{\texttt{e}} is not enough, since we would mistake the
-% function \texttt{erf} for an exponent of \enquote{\texttt{rf}}. An
-% alternative would be to look two tokens ahead and check if what
-% follows is a sign or a digit, considering in that case that we must be
-% finding an exponent. But taking care of the second case requires that
-% we unpack registers after \texttt{e}. However, blindly expanding the
-% two tokens ahead completely would break the third example (unpacking
-% is even worse). Indeed, in the course of reading $3.2$, \cs{c_pi_fp}
-% is expanded to \cs{s_@@} \cs{@@_chk:w} |1| |0| |{-1}| |{3141}|
-% $\cdots$ |;| and \cs{s_@@} stops the expansion. Expanding two tokens
-% ahead would then force the expansion of \cs{@@_chk:w} (despite it
-% being protected), and that function tries to produce an error.
-%
-% What can we do? Really, the reason why this last case breaks is that
-% just as \TeX{} does, we should read ahead as little as possible.
-% Here, the only case where there may be an exponent is if the first
-% token ahead is |e|. Then we expand (and possibly unpack) the second
-% token.
-%
-% \begin{macro}[rEXP]{\@@_parse_exponent:Nw}
-% This auxiliary is convenient to smuggle some material through
-% \cs{fi:} ending conditional processing. We place those \cs{fi:}
-% (argument~|#2|) at a very odd place because this allows us to insert
-% \cs{@@_int_eval:w} \ldots{} there if needed.
-% \begin{macrocode}
-\cs_new:Npn \@@_parse_exponent:Nw #1 #2 \@@_parse_expand:w
- {
- \exp_after:wN ;
- \int_value:w #2 \@@_parse_exponent:N #1
- }
-% \end{macrocode}
-% \end{macro}
-%
-% \begin{macro}[rEXP]
-% {\@@_parse_exponent:N, \@@_parse_exponent_aux:NN}
-% This function should be called within an \cs{int_value:w}
-% expansion (or within an integer expression). It leaves digits of the
-% exponent behind it in the input stream, and terminates the expansion
-% with a semicolon. If there is no~|e| (or~|E|), leave an exponent of~$0$. If
-% there is an~|e| or~|E|, expand the next token to run some tests on it. The
-% first rough test is that if the character code of~|#1| is greater
-% than that of~|9| (largest code valid for an exponent, less than any
-% code valid for an identifier), there was in fact no exponent;
-% otherwise, we search for the sign of the exponent.
-% \begin{macrocode}
-\cs_new:Npn \@@_parse_exponent:N #1
- {
- \if:w e \if:w E \exp_not:N #1 e \else: \exp_not:N #1 \fi:
- \exp_after:wN \@@_parse_exponent_aux:NN
- \exp_after:wN #1
- \exp:w
- \else:
- 0 \@@_parse_return_semicolon:w #1
- \fi:
- \@@_parse_expand:w
- }
-\cs_new:Npn \@@_parse_exponent_aux:NN #1#2
- {
- \if_int_compare:w \if_catcode:w \scan_stop: \exp_not:N #2
- 0 \else: `#2 \fi: > `9 \exp_stop_f:
- 0 \exp_after:wN ; \exp_after:wN #1
- \else:
- \exp_after:wN \@@_parse_exponent_sign:N
- \fi:
- #2
- }
-% \end{macrocode}
-% \end{macro}
-%
-% \begin{macro}[rEXP]{\@@_parse_exponent_sign:N}
-% Read signs one by one (if there is any).
-% \begin{macrocode}
-\cs_new:Npn \@@_parse_exponent_sign:N #1
- {
- \if:w + \if:w - \exp_not:N #1 + \fi: \token_to_str:N #1
- \exp_after:wN \@@_parse_exponent_sign:N
- \exp:w \exp_after:wN \@@_parse_expand:w
- \else:
- \exp_after:wN \@@_parse_exponent_body:N
- \exp_after:wN #1
- \fi:
- }
-% \end{macrocode}
-% \end{macro}
-%
-% \begin{macro}[rEXP]{\@@_parse_exponent_body:N}
-% An exponent can be an explicit integer (most common case), or
-% various other things (most of which are invalid).
-% \begin{macrocode}
-\cs_new:Npn \@@_parse_exponent_body:N #1
- {
- \if_int_compare:w 9 < 1 \token_to_str:N #1 \exp_stop_f:
- \token_to_str:N #1
- \exp_after:wN \@@_parse_exponent_digits:N
- \exp:w
- \else:
- \@@_parse_exponent_keep:NTF #1
- { \@@_parse_return_semicolon:w #1 }
- {
- \exp_after:wN ;
- \exp:w
- }
- \fi:
- \@@_parse_expand:w
- }
-% \end{macrocode}
-% \end{macro}
-%
-% \begin{macro}[rEXP]{\@@_parse_exponent_digits:N}
-% Read digits one by one, and leave them behind in the input stream.
-% When finding a non-digit, stop, and insert a semicolon. Note that
-% we do not check for overflow of the exponent, hence there can be a
-% \TeX{} error. It is mostly harmless, except when parsing
-% |0e9876543210|, which should be a valid representation of $0$, but
-% is not.
-% \begin{macrocode}
-\cs_new:Npn \@@_parse_exponent_digits:N #1
- {
- \if_int_compare:w 9 < 1 \token_to_str:N #1 \exp_stop_f:
- \token_to_str:N #1
- \exp_after:wN \@@_parse_exponent_digits:N
- \exp:w
- \else:
- \@@_parse_return_semicolon:w #1
- \fi:
- \@@_parse_expand:w
- }
-% \end{macrocode}
-% \end{macro}
-%
-% \begin{macro}[rEXP]{\@@_parse_exponent_keep:NTF}
-% This is the last building block for parsing exponents. The
-% argument~|#1| is already fully expanded, and neither |+| nor~|-| nor
-% a digit. It can be:
-% \begin{itemize}
-% \item \cs{s_@@}, marking the start of an internal floating point,
-% invalid here;
-% \item another control sequence equal to \tn{relax}, probably a bad
-% variable;
-% \item a register: in this case we make sure that it is an integer
-% register, not a dimension;
-% \item a character other than |+|, |-| or digits, again, an error.
-% \end{itemize}
-% \begin{macrocode}
-\prg_new_conditional:Npnn \@@_parse_exponent_keep:N #1 { TF }
- {
- \if_catcode:w \scan_stop: \exp_not:N #1
- \if_meaning:w \scan_stop: #1
- \if:w 0 \@@_str_if_eq:nn { \s_@@ } { \exp_not:N #1 }
- 0
- \msg_expandable_error:nnn
- { fp } { after-e } { floating~point~ }
- \prg_return_true:
- \else:
- 0
- \msg_expandable_error:nnn
- { kernel } { bad-variable } {#1}
- \prg_return_false:
- \fi:
- \else:
- \if:w 0 \@@_str_if_eq:nn { \int_value:w #1 } { \tex_the:D #1 }
- \int_value:w #1
- \else:
- 0
- \msg_expandable_error:nnn
- { fp } { after-e } { dimension~#1 }
- \fi:
- \prg_return_false:
- \fi:
- \else:
- 0
- \msg_expandable_error:nnn
- { fp } { missing } { exponent }
- \prg_return_true:
- \fi:
- }
-% \end{macrocode}
-% \end{macro}
-%
-% \subsection{Constants, functions and prefix operators}
-%
-% \subsubsection{Prefix operators}
-%
-% \begin{macro}[EXP]{\@@_parse_prefix_+:Nw}
-% A unary~|+| does nothing: we should continue looking for a number.
-% \begin{macrocode}
-\cs_new_eq:cN { @@_parse_prefix_+:Nw } \@@_parse_one:Nw
-% \end{macrocode}
-% \end{macro}
-%
-% \begin{macro}[EXP]{\@@_parse_apply_function:NNNwN}
-% Here, |#1| is a precedence, |#2| is some extra data used by some
-% functions, |#3| is \emph{e.g.}, \cs{@@_sin_o:w}, and expands once
-% after the calculation, |#4| is the operand, and |#5| is a
-% \cs[no-index]{@@_parse_infix_\ldots{}:N} function. We feed the data~|#2|, and the
-% argument~|#4|, to the function~|#3|, which expands
-% \cs{exp:w} thus the \texttt{infix} function~|#5|.
-% \begin{macrocode}
-\cs_new:Npn \@@_parse_apply_function:NNNwN #1#2#3#4@#5
- {
- #3 #2 #4 @
- \exp:w \exp_end_continue_f:w #5 #1
- }
-% \end{macrocode}
-% \end{macro}
-%
-% \begin{macro}[EXP]{\@@_parse_apply_unary:NNNwN}
-% \begin{macro}[EXP]{\@@_parse_apply_unary_chk:NwNw, \@@_parse_apply_unary_chk:nNNNw}
-% \begin{macro}[EXP]{\@@_parse_apply_unary_type:NNN, \@@_parse_apply_unary_error:NNw}
-% In contrast to \cs{@@_parse_apply_function:NNNwN}, this checks that
-% the operand |#4| is a single argument (namely there is a single
-% |;|). We use the fact that any floating point starts with a
-% \enquote{safe} token like \cs{s_@@}. If there is no argument
-% produce the |fp-no-arg| error; if there are at least two produce
-% |fp-multi-arg|. For the error message extract the mathematical
-% function name (such as |sin|) from the \pkg{expl3} function that
-% computes it, such as \cs{@@_sin_o:w}.
-%
-% In addition, since there is a single argument we can dispatch on
-% type and check that the resulting function exists. This catches
-% things like |sin((1,2))| where it does not make sense to take the
-% sine of a tuple.
-% \begin{macrocode}
-\cs_new:Npn \@@_parse_apply_unary:NNNwN #1#2#3#4@#5
- {
- \@@_parse_apply_unary_chk:NwNw #4 @ ; . \s_@@_stop
- \@@_parse_apply_unary_type:NNN
- #3 #2 #4 @
- \exp:w \exp_end_continue_f:w #5 #1
- }
-\cs_new:Npn \@@_parse_apply_unary_chk:NwNw #1#2 ; #3#4 \s_@@_stop
- {
- \if_meaning:w @ #3 \else:
- \token_if_eq_meaning:NNTF . #3
- { \@@_parse_apply_unary_chk:nNNNNw { no } }
- { \@@_parse_apply_unary_chk:nNNNNw { multi } }
- \fi:
- }
-\cs_new:Npn \@@_parse_apply_unary_chk:nNNNNw #1#2#3#4#5#6 @
- {
- #2
- \@@_error:nffn { #1-arg } { \@@_func_to_name:N #4 } { } { }
- \exp_after:wN #4 \exp_after:wN #5 \c_nan_fp @
- }
-\cs_new:Npn \@@_parse_apply_unary_type:NNN #1#2#3
- {
- \@@_change_func_type:NNN #3 #1 \@@_parse_apply_unary_error:NNw
- #2 #3
- }
-\cs_new:Npn \@@_parse_apply_unary_error:NNw #1#2#3 @
- { \@@_invalid_operation_o:fw { \@@_func_to_name:N #1 } #3 }
-% \end{macrocode}
-% \end{macro}
-% \end{macro}
-% \end{macro}
-%
-% \begin{macro}[EXP]{\@@_parse_prefix_-:Nw, \@@_parse_prefix_!:Nw}
-% The unary~|-| and boolean not are harder: we parse the operand using
-% a precedence equal to the maximum of the previous precedence~|##1|
-% and the precedence \cs{c_@@_prec_not_int} of the unary operator, then call
-% the appropriate |\__fp_|\meta{operation}|_o:w| function,
-% where the \meta{operation} is |set_sign| or |not|.
-% \begin{macrocode}
-\cs_set_protected:Npn \@@_tmp:w #1#2#3#4
- {
- \cs_new:cpn { @@_parse_prefix_ #1 :Nw } ##1
- {
- \exp_after:wN \@@_parse_apply_unary:NNNwN
- \exp_after:wN ##1
- \exp_after:wN #4
- \exp_after:wN #3
- \exp:w
- \if_int_compare:w #2 < ##1
- \@@_parse_operand:Nw ##1
- \else:
- \@@_parse_operand:Nw #2
- \fi:
- \@@_parse_expand:w
- }
- }
-\@@_tmp:w - \c_@@_prec_not_int \@@_set_sign_o:w 2
-\@@_tmp:w ! \c_@@_prec_not_int \@@_not_o:w ?
-% \end{macrocode}
-% \end{macro}
-%
-% \begin{macro}[EXP]{\@@_parse_prefix_.:Nw}
-% Numbers which start with a decimal separator (a~period) end up here.
-% Of course, we do not look for an operand, but for the rest of the
-% number. This function is very similar to \cs{@@_parse_one_digit:NN}
-% but calls \cs{@@_parse_strim_zeros:N} to trim zeros after the
-% decimal point, rather than the \texttt{trim_zeros} function for
-% zeros before the decimal point.
-% \begin{macrocode}
-\cs_new:cpn { @@_parse_prefix_.:Nw } #1
- {
- \exp_after:wN \@@_parse_infix_after_operand:NwN
- \exp_after:wN #1
- \exp:w \exp_end_continue_f:w
- \exp_after:wN \@@_sanitize:wN
- \int_value:w \@@_int_eval:w 0 \@@_parse_strim_zeros:N
- }
-% \end{macrocode}
-% \end{macro}
-%
-% \begin{macro}[EXP]
-% {\@@_parse_prefix_(:Nw, \@@_parse_lparen_after:NwN}
-% The left parenthesis is treated as a unary prefix operator because
-% it appears in exactly the same settings. If the previous precedence
-% is \cs{c_@@_prec_func_int} we are parsing arguments of a function
-% and commas should not build tuples; otherwise commas should build
-% tuples. We distinguish these cases by precedence:
-% \cs{c_@@_prec_comma_int} for the case of arguments,
-% \cs{c_@@_prec_tuple_int} for the case of tuples.
-% Once the operand is found, the \texttt{lparen_after} auxiliary makes
-% sure that there was a closing parenthesis (otherwise it complains),
-% and leaves in the input stream an operand,
-% fetching the following infix operator.
-% \begin{macrocode}
-\cs_new:cpn { @@_parse_prefix_(:Nw } #1
- {
- \exp_after:wN \@@_parse_lparen_after:NwN
- \exp_after:wN #1
- \exp:w
- \if_int_compare:w #1 = \c_@@_prec_func_int
- \@@_parse_operand:Nw \c_@@_prec_comma_int
- \else:
- \@@_parse_operand:Nw \c_@@_prec_tuple_int
- \fi:
- \@@_parse_expand:w
- }
-\cs_new:Npe \@@_parse_lparen_after:NwN #1#2 @ #3
- {
- \exp_not:N \token_if_eq_meaning:NNTF #3
- \exp_not:c { @@_parse_infix_):N }
- {
- \exp_not:N \@@_exp_after_array_f:w #2 \s_@@_expr_stop
- \exp_not:N \exp_after:wN
- \exp_not:N \@@_parse_infix_after_paren:NN
- \exp_not:N \exp_after:wN #1
- \exp_not:N \exp:w
- \exp_not:N \@@_parse_expand:w
- }
- {
- \exp_not:N \msg_expandable_error:nnn
- { fp } { missing } { ) }
- \exp_not:N \tl_if_empty:nT {#2} \exp_not:N \c_@@_empty_tuple_fp
- #2 @
- \exp_not:N \use_none:n #3
- }
- }
-% \end{macrocode}
-% \end{macro}
-%
-% \begin{macro}[EXP]{\@@_parse_prefix_):Nw}
-% The right parenthesis can appear as a prefix in two similar cases:
-% in an empty tuple or tuple ending with a comma, or in an empty
-% argument list or argument list ending with a comma, such as in
-% |max(1,2,)| or in |rand()|.
-% \begin{macrocode}
-\cs_new:cpn { @@_parse_prefix_):Nw } #1
- {
- \if_int_compare:w #1 = \c_@@_prec_comma_int
- \else:
- \if_int_compare:w #1 = \c_@@_prec_tuple_int
- \exp_after:wN \c_@@_empty_tuple_fp \exp:w
- \else:
- \msg_expandable_error:nnn
- { fp } { missing-number } { ) }
- \exp_after:wN \c_nan_fp \exp:w
- \fi:
- \exp_end_continue_f:w
- \fi:
- \@@_parse_infix_after_paren:NN #1 )
- }
-% \end{macrocode}
-% \end{macro}
-%
-% \subsubsection{Constants}
-%
-% \begin{macro}[EXP]
-% {
-% \@@_parse_word_inf:N , \@@_parse_word_nan:N ,
-% \@@_parse_word_pi:N , \@@_parse_word_deg:N ,
-% \@@_parse_word_true:N , \@@_parse_word_false:N ,
-% }
-% Some words correspond to constant floating points. The floating
-% point constant is left as a result of \cs{@@_parse_one:Nw} after
-% expanding \cs{@@_parse_infix:NN}.
-% \begin{macrocode}
-\cs_set_protected:Npn \@@_tmp:w #1 #2
- {
- \cs_new:cpn { @@_parse_word_#1:N }
- { \exp_after:wN #2 \exp:w \exp_end_continue_f:w \@@_parse_infix:NN }
- }
-\@@_tmp:w { inf } \c_inf_fp
-\@@_tmp:w { nan } \c_nan_fp
-\@@_tmp:w { pi } \c_pi_fp
-\@@_tmp:w { deg } \c_one_degree_fp
-\@@_tmp:w { true } \c_one_fp
-\@@_tmp:w { false } \c_zero_fp
-% \end{macrocode}
-% \end{macro}
-%
-% \begin{macro}[EXP]
-% {
-% \@@_parse_caseless_inf:N,
-% \@@_parse_caseless_infinity:N,
-% \@@_parse_caseless_nan:N
-% }
-% Copies of \cs[no-index]{@@_parse_word_\ldots{}:N} commands, to allow
-% arbitrary case as mandated by the standard.
-% \begin{macrocode}
-\cs_new_eq:NN \@@_parse_caseless_inf:N \@@_parse_word_inf:N
-\cs_new_eq:NN \@@_parse_caseless_infinity:N \@@_parse_word_inf:N
-\cs_new_eq:NN \@@_parse_caseless_nan:N \@@_parse_word_nan:N
-% \end{macrocode}
-% \end{macro}
-%
-% \begin{macro}[EXP]
-% {
-% \@@_parse_word_pt:N , \@@_parse_word_in:N ,
-% \@@_parse_word_pc:N , \@@_parse_word_cm:N , \@@_parse_word_mm:N ,
-% \@@_parse_word_dd:N , \@@_parse_word_cc:N , \@@_parse_word_nd:N ,
-% \@@_parse_word_nc:N , \@@_parse_word_bp:N , \@@_parse_word_sp:N ,
-% }
-% Dimension units are also floating point constants but their value is
-% not stored as a floating point constant. We give the values
-% explicitly here.
-% \begin{macrocode}
-\cs_set_protected:Npn \@@_tmp:w #1 #2
- {
- \cs_new:cpn { @@_parse_word_#1:N }
- {
- \@@_exp_after_f:nw { \@@_parse_infix:NN }
- \s_@@ \@@_chk:w 10 #2 ;
- }
- }
-\@@_tmp:w {pt} { {1} {1000} {0000} {0000} {0000} }
-\@@_tmp:w {in} { {2} {7227} {0000} {0000} {0000} }
-\@@_tmp:w {pc} { {2} {1200} {0000} {0000} {0000} }
-\@@_tmp:w {cm} { {2} {2845} {2755} {9055} {1181} }
-\@@_tmp:w {mm} { {1} {2845} {2755} {9055} {1181} }
-\@@_tmp:w {dd} { {1} {1070} {0085} {6496} {0630} }
-\@@_tmp:w {cc} { {2} {1284} {0102} {7795} {2756} }
-\@@_tmp:w {nd} { {1} {1066} {9783} {4645} {6693} }
-\@@_tmp:w {nc} { {2} {1280} {3740} {1574} {8031} }
-\@@_tmp:w {bp} { {1} {1003} {7500} {0000} {0000} }
-\@@_tmp:w {sp} { {-4} {1525} {8789} {0625} {0000} }
-% \end{macrocode}
-% \end{macro}
-%
-% \begin{macro}[EXP]{\@@_parse_word_em:N, \@@_parse_word_ex:N}
-% The font-dependent units |em| and |ex| must be evaluated on the fly.
-% We reuse an auxiliary of \cs{dim_to_fp:n}.
-% \begin{macrocode}
-\tl_map_inline:nn { {em} {ex} }
- {
- \cs_new:cpn { @@_parse_word_#1:N }
- {
- \exp_after:wN \@@_from_dim_test:ww
- \exp_after:wN 0 \exp_after:wN ,
- \int_value:w \dim_to_decimal_in_sp:n { 1 #1 } \exp_after:wN ;
- \exp:w \exp_end_continue_f:w \@@_parse_infix:NN
- }
- }
-% \end{macrocode}
-% \end{macro}
-%
-% \subsubsection{Functions}
-%
-% ^^A begin[todo]
-%
-% \begin{macro}[EXP]
-% {\@@_parse_unary_function:NNN, \@@_parse_function:NNN}
-% \begin{macrocode}
-\cs_new:Npn \@@_parse_unary_function:NNN #1#2#3
- {
- \exp_after:wN \@@_parse_apply_unary:NNNwN
- \exp_after:wN #3
- \exp_after:wN #2
- \exp_after:wN #1
- \exp:w
- \@@_parse_operand:Nw \c_@@_prec_func_int \@@_parse_expand:w
- }
-\cs_new:Npn \@@_parse_function:NNN #1#2#3
- {
- \exp_after:wN \@@_parse_apply_function:NNNwN
- \exp_after:wN #3
- \exp_after:wN #2
- \exp_after:wN #1
- \exp:w
- \@@_parse_operand:Nw \c_@@_prec_func_int \@@_parse_expand:w
- }
-% \end{macrocode}
-% \end{macro}
-%
-% \subsection{Main functions}
-%
-% \begin{macro}[EXP]{\@@_parse:n, \@@_parse_o:n}
-% \begin{macro}[EXP]{\@@_parse_after:ww}
-% Start an \cs{exp:w} expansion so that \cs{@@_parse:n} expands
-% in two steps. The \cs{@@_parse_operand:Nw} function performs
-% computations until reaching an operation with precedence
-% \cs{c_@@_prec_end_int} or less, namely, the end of the expression. The
-% marker \cs{s_@@_expr_mark} indicates that the next token is an already
-% parsed version of an infix operator, and \cs{@@_parse_infix_end:N}
-% has infinitely negative precedence. Finally, clean up a
-% (well-defined) set of extra tokens and stop the initial expansion
-% with \cs{exp_end:}.
-% \begin{macrocode}
-\cs_new:Npn \@@_parse:n #1
- {
- \exp:w
- \exp_after:wN \@@_parse_after:ww
- \exp:w
- \@@_parse_operand:Nw \c_@@_prec_end_int
- \@@_parse_expand:w #1
- \s_@@_expr_mark \@@_parse_infix_end:N
- \s_@@_expr_stop
- \exp_end:
- }
-\cs_new:Npn \@@_parse_after:ww
- #1@ \@@_parse_infix_end:N \s_@@_expr_stop #2 { #2 #1 }
-\cs_new:Npn \@@_parse_o:n #1
- {
- \exp:w
- \exp_after:wN \@@_parse_after:ww
- \exp:w
- \@@_parse_operand:Nw \c_@@_prec_end_int
- \@@_parse_expand:w #1
- \s_@@_expr_mark \@@_parse_infix_end:N
- \s_@@_expr_stop
- {
- \exp_end_continue_f:w
- \@@_exp_after_any_f:nw { \exp_after:wN \exp_stop_f: }
- }
- }
-% \end{macrocode}
-% \end{macro}
-% \end{macro}
-%
-% \begin{macro}[EXP]{\@@_parse_operand:Nw}
-% \begin{macro}[EXP]{\@@_parse_continue:NwN}
-% This is just a shorthand which sets up both \cs{@@_parse_continue:NwN}
-% and \cs{@@_parse_one:Nw} with the same precedence. Note the
-% trailing \cs{exp:w}.
-% \begin{macrocode}
-\cs_new:Npn \@@_parse_operand:Nw #1
- {
- \exp_end_continue_f:w
- \exp_after:wN \@@_parse_continue:NwN
- \exp_after:wN #1
- \exp:w \exp_end_continue_f:w
- \exp_after:wN \@@_parse_one:Nw
- \exp_after:wN #1
- \exp:w
- }
-\cs_new:Npn \@@_parse_continue:NwN #1 #2 @ #3 { #3 #1 #2 @ }
-% \end{macrocode}
-% \end{macro}
-% \end{macro}
-%
-% \begin{macro}[EXP]{\@@_parse_apply_binary:NwNwN}
-% \begin{macro}[EXP]
-% {\@@_parse_apply_binary_chk:NN, \@@_parse_apply_binary_error:NNN}
-% Receives \meta{precedence} \meta{operand_1} |@| \meta{operation}
-% \meta{operand_2} |@| \meta{infix command}. Builds the appropriate
-% call to the \meta{operation}~|#3|, dispatching on both types.
-% If the resulting control sequence does not exist, the operation is
-% not allowed.
-%
-% This is redefined in \pkg{l3fp-extras}.
-% \begin{macrocode}
-\cs_new:Npn \@@_parse_apply_binary:NwNwN #1 #2#3@ #4 #5#6@ #7
- {
- \exp_after:wN \@@_parse_continue:NwN
- \exp_after:wN #1
- \exp:w \exp_end_continue_f:w
- \exp_after:wN \@@_parse_apply_binary_chk:NN
- \cs:w
- @@
- \@@_type_from_scan:N #2
- _#4
- \@@_type_from_scan:N #5
- _o:ww
- \cs_end:
- #4
- #2#3 #5#6
- \exp:w \exp_end_continue_f:w #7 #1
- }
-\cs_new:Npn \@@_parse_apply_binary_chk:NN #1#2
- {
- \if_meaning:w \scan_stop: #1
- \@@_parse_apply_binary_error:NNN #2
- \fi:
- #1
- }
-\cs_new:Npn \@@_parse_apply_binary_error:NNN #1#2#3
- {
- #2
- \@@_invalid_operation_o:Nww #1
- }
-% \end{macrocode}
-% \end{macro}
-% \end{macro}
-%
-% \begin{macro}[EXP]{\@@_binary_type_o:Nww, \@@_binary_rev_type_o:Nww}
-% Applies the operator |#1| to its two arguments, dispatching
-% according to their types, and expands once after the result.
-% The |rev| version swaps its arguments before doing this.
-% \begin{macrocode}
-\cs_new:Npn \@@_binary_type_o:Nww #1 #2#3 ; #4
- {
- \exp_after:wN \@@_parse_apply_binary_chk:NN
- \cs:w
- @@
- \@@_type_from_scan:N #2
- _ #1
- \@@_type_from_scan:N #4
- _o:ww
- \cs_end:
- #1
- #2 #3 ; #4
- }
-\cs_new:Npn \@@_binary_rev_type_o:Nww #1 #2#3 ; #4#5 ;
- {
- \exp_after:wN \@@_parse_apply_binary_chk:NN
- \cs:w
- @@
- \@@_type_from_scan:N #4
- _ #1
- \@@_type_from_scan:N #2
- _o:ww
- \cs_end:
- #1
- #4 #5 ; #2 #3 ;
- }
-% \end{macrocode}
-% \end{macro}
-%
-% \subsection{Infix operators}
-%
-% \begin{macro}[EXP]{\@@_parse_infix_after_operand:NwN}
-% \begin{macrocode}
-\cs_new:Npn \@@_parse_infix_after_operand:NwN #1 #2;
- {
- \@@_exp_after_f:nw { \@@_parse_infix:NN #1 }
- #2;
- }
-\cs_new:Npn \@@_parse_infix:NN #1 #2
- {
- \if_catcode:w \scan_stop: \exp_not:N #2
- \if:w 0 \@@_str_if_eq:nn { \s_@@_expr_mark } { \exp_not:N #2 }
- \exp_after:wN \exp_after:wN
- \exp_after:wN \@@_parse_infix_mark:NNN
- \else:
- \exp_after:wN \exp_after:wN
- \exp_after:wN \@@_parse_infix_juxt:N
- \fi:
- \else:
- \if_int_compare:w
- \@@_int_eval:w
- ( `#2 \if_int_compare:w `#2 > `Z - 32 \fi: ) / 26
- = 3 \exp_stop_f:
- \exp_after:wN \exp_after:wN
- \exp_after:wN \@@_parse_infix_juxt:N
- \else:
- \exp_after:wN \@@_parse_infix_check:NNN
- \cs:w
- @@_parse_infix_ \token_to_str:N #2 :N
- \exp_after:wN \exp_after:wN \exp_after:wN
- \cs_end:
- \fi:
- \fi:
- #1
- #2
- }
-\cs_new:Npn \@@_parse_infix_check:NNN #1#2#3
- {
- \if_meaning:w \scan_stop: #1
- \msg_expandable_error:nnn
- { fp } { missing } { * }
- \exp_after:wN \@@_parse_infix_mul:N
- \exp_after:wN #2
- \exp_after:wN #3
- \else:
- \exp_after:wN #1
- \exp_after:wN #2
- \exp:w \exp_after:wN \@@_parse_expand:w
- \fi:
- }
-% \end{macrocode}
-% \end{macro}
-%
-% \begin{macro}{\@@_parse_infix_after_paren:NN}
-% Variant of \cs{@@_parse_infix:NN} for use after a closing
-% parenthesis. The only difference is that \cs{@@_parse_infix_juxt:N}
-% is replaced by \cs{@@_parse_infix_mul:N}.
-% \begin{macrocode}
-\cs_new:Npn \@@_parse_infix_after_paren:NN #1 #2
- {
- \if_catcode:w \scan_stop: \exp_not:N #2
- \if:w 0 \@@_str_if_eq:nn { \s_@@_expr_mark } { \exp_not:N #2 }
- \exp_after:wN \exp_after:wN
- \exp_after:wN \@@_parse_infix_mark:NNN
- \else:
- \exp_after:wN \exp_after:wN
- \exp_after:wN \@@_parse_infix_mul:N
- \fi:
- \else:
- \if_int_compare:w
- \@@_int_eval:w
- ( `#2 \if_int_compare:w `#2 > `Z - 32 \fi: ) / 26
- = 3 \exp_stop_f:
- \exp_after:wN \exp_after:wN
- \exp_after:wN \@@_parse_infix_mul:N
- \else:
- \exp_after:wN \@@_parse_infix_check:NNN
- \cs:w
- @@_parse_infix_ \token_to_str:N #2 :N
- \exp_after:wN \exp_after:wN \exp_after:wN
- \cs_end:
- \fi:
- \fi:
- #1
- #2
- }
-% \end{macrocode}
-% \end{macro}
-%
-% \subsubsection{Closing parentheses and commas}
-%
-% \begin{macro}[EXP]{\@@_parse_infix_mark:NNN}
-% As an infix operator, \cs{s_@@_expr_mark} means that the next
-% token~(|#3|) has already gone through \cs{@@_parse_infix:NN} and
-% should be provided the precedence~|#1|. The scan mark~|#2| is
-% discarded.
-% \begin{macrocode}
-\cs_new:Npn \@@_parse_infix_mark:NNN #1#2#3 { #3 #1 }
-% \end{macrocode}
-% \end{macro}
-%
-% \begin{macro}[EXP]{\@@_parse_infix_end:N}
-% This one is a little bit odd: force every previous operator to end,
-% regardless of the precedence.
-% \begin{macrocode}
-\cs_new:Npn \@@_parse_infix_end:N #1
- { @ \use_none:n \@@_parse_infix_end:N }
-% \end{macrocode}
-% \end{macro}
-%
-% \begin{macro}[EXP]+\@@_parse_infix_):N+
-% This is very similar to \cs{@@_parse_infix_end:N}, complaining about
-% an extra closing parenthesis if the previous operator was the
-% beginning of the expression, with precedence \cs{c_@@_prec_end_int}.
-% \begin{macrocode}
-\cs_set_protected:Npn \@@_tmp:w #1
- {
- \cs_new:Npn #1 ##1
- {
- \if_int_compare:w ##1 > \c_@@_prec_end_int
- \exp_after:wN @
- \exp_after:wN \use_none:n
- \exp_after:wN #1
- \else:
- \msg_expandable_error:nnn { fp } { extra } { ) }
- \exp_after:wN \@@_parse_infix:NN
- \exp_after:wN ##1
- \exp:w \exp_after:wN \@@_parse_expand:w
- \fi:
- }
- }
-\exp_args:Nc \@@_tmp:w { @@_parse_infix_):N }
-% \end{macrocode}
-% \end{macro}
-%
-% \begin{macro}[verb, EXP]{\__fp_parse_infix_,:N}
-% \begin{macro}[EXP]{\@@_parse_infix_comma:w, \@@_parse_apply_comma:NwNwN}
-% As for other infix operations, if the previous operations has higher
-% precedence the comma waits. Otherwise we call
-% \cs{@@_parse_operand:Nw} to read more comma-delimited arguments that
-% \cs{@@_parse_infix_comma:w} simply concatenates into a |@|-delimited
-% array. The first comma in a tuple that is not a function argument
-% is distinguished: in that case call \cs{@@_parse_apply_comma:NwNwN}
-% whose job is to convert the first item of the tuple and an array of
-% the remaining items into a tuple. In contrast to
-% \cs{@@_parse_apply_binary:NwNwN} this function's operands are not
-% single-object arrays.
-% \begin{macrocode}
-\cs_set_protected:Npn \@@_tmp:w #1
- {
- \cs_new:Npn #1 ##1
- {
- \if_int_compare:w ##1 > \c_@@_prec_comma_int
- \exp_after:wN @
- \exp_after:wN \use_none:n
- \exp_after:wN #1
- \else:
- \if_int_compare:w ##1 < \c_@@_prec_comma_int
- \exp_after:wN @
- \exp_after:wN \@@_parse_apply_comma:NwNwN
- \exp_after:wN ,
- \exp:w
- \else:
- \exp_after:wN \@@_parse_infix_comma:w
- \exp:w
- \fi:
- \@@_parse_operand:Nw \c_@@_prec_comma_int
- \exp_after:wN \@@_parse_expand:w
- \fi:
- }
- }
-\exp_args:Nc \@@_tmp:w { @@_parse_infix_,:N }
-\cs_new:Npn \@@_parse_infix_comma:w #1 @
- { #1 @ \use_none:n }
-\cs_new:Npn \@@_parse_apply_comma:NwNwN #1 #2@ #3 #4@ #5
- {
- \exp_after:wN \@@_parse_continue:NwN
- \exp_after:wN #1
- \exp:w \exp_end_continue_f:w
- \@@_exp_after_tuple_f:nw { }
- \s_@@_tuple \@@_tuple_chk:w { #2 #4 } ;
- #5 #1
- }
-% \end{macrocode}
-% \end{macro}
-% \end{macro}
-%
-% \subsubsection{Usual infix operators}
-%
-% \begin{macro}[EXP]
-% {
-% \@@_parse_infix_+:N, \@@_parse_infix_-:N,
-% \@@_parse_infix_juxt:N,
-% \@@_parse_infix_/:N, \@@_parse_infix_mul:N,
-% \@@_parse_infix_and:N, \@@_parse_infix_or:N,
-% }
-% \begin{macro}[EXP]+\@@_parse_infix_^:N+
-% As described in the \enquote{work plan}, each infix operator has an
-% associated |\..._infix_...| function, a computing function, and
-% precedence, given as arguments to \cs{@@_tmp:w}. Using the general
-% mechanism for arithmetic operations. The power operation must be
-% associative in the opposite order from all others. For this, we use
-% two distinct precedences.
-% \begin{macrocode}
-\cs_set_protected:Npn \@@_tmp:w #1#2#3#4
- {
- \cs_new:Npn #1 ##1
- {
- \if_int_compare:w ##1 < #3
- \exp_after:wN @
- \exp_after:wN \@@_parse_apply_binary:NwNwN
- \exp_after:wN #2
- \exp:w
- \@@_parse_operand:Nw #4
- \exp_after:wN \@@_parse_expand:w
- \else:
- \exp_after:wN @
- \exp_after:wN \use_none:n
- \exp_after:wN #1
- \fi:
- }
- }
-\exp_args:Nc \@@_tmp:w { @@_parse_infix_^:N } ^
- \c_@@_prec_hatii_int \c_@@_prec_hat_int
-\exp_args:Nc \@@_tmp:w { @@_parse_infix_juxt:N } *
- \c_@@_prec_juxt_int \c_@@_prec_juxt_int
-\exp_args:Nc \@@_tmp:w { @@_parse_infix_/:N } /
- \c_@@_prec_times_int \c_@@_prec_times_int
-\exp_args:Nc \@@_tmp:w { @@_parse_infix_mul:N } *
- \c_@@_prec_times_int \c_@@_prec_times_int
-\exp_args:Nc \@@_tmp:w { @@_parse_infix_-:N } -
- \c_@@_prec_plus_int \c_@@_prec_plus_int
-\exp_args:Nc \@@_tmp:w { @@_parse_infix_+:N } +
- \c_@@_prec_plus_int \c_@@_prec_plus_int
-\exp_args:Nc \@@_tmp:w { @@_parse_infix_and:N } &
- \c_@@_prec_and_int \c_@@_prec_and_int
-\exp_args:Nc \@@_tmp:w { @@_parse_infix_or:N } |
- \c_@@_prec_or_int \c_@@_prec_or_int
-% \end{macrocode}
-% \end{macro}
-% \end{macro}
-%
-% \subsubsection{Juxtaposition}
-%
-% \begin{macro}[EXP]+\@@_parse_infix_(:N+
-% When an opening parenthesis appears where we expect an infix
-% operator, we compute the product of the previous operand and the
-% contents of the parentheses using \cs{@@_parse_infix_mul:N}.
-% \begin{macrocode}
-\cs_new:cpn { @@_parse_infix_(:N } #1
- { \@@_parse_infix_mul:N #1 ( }
-% \end{macrocode}
-% \end{macro}
-%
-% \subsubsection{Multi-character cases}
-%
-% \begin{macro}[EXP]{\@@_parse_infix_*:N}
-% \begin{macrocode}
-\cs_set_protected:Npn \@@_tmp:w #1
- {
- \cs_new:cpn { @@_parse_infix_*:N } ##1##2
- {
- \if:w * \exp_not:N ##2
- \exp_after:wN #1
- \exp_after:wN ##1
- \else:
- \exp_after:wN \@@_parse_infix_mul:N
- \exp_after:wN ##1
- \exp_after:wN ##2
- \fi:
- }
- }
-\exp_args:Nc \@@_tmp:w { @@_parse_infix_^:N }
-% \end{macrocode}
-% \end{macro}
-%
-% \begin{macro}[EXP]+\@@_parse_infix_|:Nw+
-% \begin{macro}[EXP]+\@@_parse_infix_&:Nw+
-% \begin{macrocode}
-\cs_set_protected:Npn \@@_tmp:w #1#2#3
- {
- \cs_new:Npn #1 ##1##2
- {
- \if:w #2 \exp_not:N ##2
- \exp_after:wN #1
- \exp_after:wN ##1
- \exp:w \exp_after:wN \@@_parse_expand:w
- \else:
- \exp_after:wN #3
- \exp_after:wN ##1
- \exp_after:wN ##2
- \fi:
- }
- }
-\exp_args:Nc \@@_tmp:w { @@_parse_infix_|:N } | \@@_parse_infix_or:N
-\exp_args:Nc \@@_tmp:w { @@_parse_infix_&:N } & \@@_parse_infix_and:N
-% \end{macrocode}
-% \end{macro}
-% \end{macro}
-%
-% \subsubsection{Ternary operator}
-%
-% \begin{macro}[EXP]{\@@_parse_infix_?:N, \@@_parse_infix_::N}
-% \begin{macrocode}
-\cs_set_protected:Npn \@@_tmp:w #1#2#3#4
- {
- \cs_new:Npn #1 ##1
- {
- \if_int_compare:w ##1 < \c_@@_prec_quest_int
- #4
- \exp_after:wN @
- \exp_after:wN #2
- \exp:w
- \@@_parse_operand:Nw #3
- \exp_after:wN \@@_parse_expand:w
- \else:
- \exp_after:wN @
- \exp_after:wN \use_none:n
- \exp_after:wN #1
- \fi:
- }
- }
-\exp_args:Nc \@@_tmp:w { @@_parse_infix_?:N }
- \@@_ternary:NwwN \c_@@_prec_quest_int { }
-\exp_args:Nc \@@_tmp:w { @@_parse_infix_::N }
- \@@_ternary_auxii:NwwN \c_@@_prec_colon_int
- {
- \msg_expandable_error:nnnn
- { fp } { missing } { ? } { ~for~?: }
- }
-% \end{macrocode}
-% \end{macro}
-%
-% \subsubsection{Comparisons}
-%
-% \begin{macro}[EXP]
-% {
-% \@@_parse_infix_<:N, \@@_parse_infix_=:N,
-% \@@_parse_infix_>:N, \@@_parse_infix_!:N
-% }
-% \begin{macro}[EXP]
-% {
-% \@@_parse_excl_error:,
-% \@@_parse_compare:NNNNNNN,
-% \@@_parse_compare_auxi:NNNNNNN,
-% \@@_parse_compare_auxii:NNNNN,
-% \@@_parse_compare_end:NNNNw,
-% \@@_compare:wNNNNw,
-% }
-% \begin{macrocode}
-\cs_new:cpn { @@_parse_infix_<:N } #1
- { \@@_parse_compare:NNNNNNN #1 1 0 0 0 0 < }
-\cs_new:cpn { @@_parse_infix_=:N } #1
- { \@@_parse_compare:NNNNNNN #1 1 0 0 0 0 = }
-\cs_new:cpn { @@_parse_infix_>:N } #1
- { \@@_parse_compare:NNNNNNN #1 1 0 0 0 0 > }
-\cs_new:cpn { @@_parse_infix_!:N } #1
- {
- \exp_after:wN \@@_parse_compare:NNNNNNN
- \exp_after:wN #1
- \exp_after:wN 0
- \exp_after:wN 1
- \exp_after:wN 1
- \exp_after:wN 1
- \exp_after:wN 1
- }
-\cs_new:Npn \@@_parse_excl_error:
- {
- \msg_expandable_error:nnnn
- { fp } { missing } { = } { ~after~!. }
- }
-\cs_new:Npn \@@_parse_compare:NNNNNNN #1
- {
- \if_int_compare:w #1 < \c_@@_prec_comp_int
- \exp_after:wN \@@_parse_compare_auxi:NNNNNNN
- \exp_after:wN \@@_parse_excl_error:
- \else:
- \exp_after:wN @
- \exp_after:wN \use_none:n
- \exp_after:wN \@@_parse_compare:NNNNNNN
- \fi:
- }
-\cs_new:Npn \@@_parse_compare_auxi:NNNNNNN #1#2#3#4#5#6#7
- {
- \if_case:w
- \@@_int_eval:w \exp_after:wN ` \token_to_str:N #7 - `<
- \@@_int_eval_end:
- \@@_parse_compare_auxii:NNNNN #2#2#4#5#6
- \or: \@@_parse_compare_auxii:NNNNN #2#3#2#5#6
- \or: \@@_parse_compare_auxii:NNNNN #2#3#4#2#6
- \or: \@@_parse_compare_auxii:NNNNN #2#3#4#5#2
- \else: #1 \@@_parse_compare_end:NNNNw #3#4#5#6#7
- \fi:
- }
-\cs_new:Npn \@@_parse_compare_auxii:NNNNN #1#2#3#4#5
- {
- \exp_after:wN \@@_parse_compare_auxi:NNNNNNN
- \exp_after:wN \prg_do_nothing:
- \exp_after:wN #1
- \exp_after:wN #2
- \exp_after:wN #3
- \exp_after:wN #4
- \exp_after:wN #5
- \exp:w \exp_after:wN \@@_parse_expand:w
- }
-\cs_new:Npn \@@_parse_compare_end:NNNNw #1#2#3#4#5 \fi:
- {
- \fi:
- \exp_after:wN @
- \exp_after:wN \@@_parse_apply_compare:NwNNNNNwN
- \exp_after:wN \c_one_fp
- \exp_after:wN #1
- \exp_after:wN #2
- \exp_after:wN #3
- \exp_after:wN #4
- \exp:w
- \@@_parse_operand:Nw \c_@@_prec_comp_int \@@_parse_expand:w #5
- }
-\cs_new:Npn \@@_parse_apply_compare:NwNNNNNwN
- #1 #2@ #3 #4#5#6#7 #8@ #9
- {
- \if_int_odd:w
- \if_meaning:w \c_zero_fp #3
- 0
- \else:
- \if_case:w \@@_compare_back_any:ww #8 #2 \exp_stop_f:
- #5 \or: #6 \or: #7 \else: #4
- \fi:
- \fi:
- \exp_stop_f:
- \exp_after:wN \@@_parse_apply_compare_aux:NNwN
- \exp_after:wN \c_one_fp
- \else:
- \exp_after:wN \@@_parse_apply_compare_aux:NNwN
- \exp_after:wN \c_zero_fp
- \fi:
- #1 #8 #9
- }
-\cs_new:Npn \@@_parse_apply_compare_aux:NNwN #1 #2 #3; #4
- {
- \if_meaning:w \@@_parse_compare:NNNNNNN #4
- \exp_after:wN \@@_parse_continue_compare:NNwNN
- \exp_after:wN #1
- \exp_after:wN #2
- \exp:w \exp_end_continue_f:w
- \@@_exp_after_o:w #3;
- \exp:w \exp_end_continue_f:w
- \else:
- \exp_after:wN \@@_parse_continue:NwN
- \exp_after:wN #2
- \exp:w \exp_end_continue_f:w
- \exp_after:wN #1
- \exp:w \exp_end_continue_f:w
- \fi:
- #4 #2
- }
-\cs_new:Npn \@@_parse_continue_compare:NNwNN #1#2 #3@ #4#5
- { #4 #2 #3@ #1 }
-% \end{macrocode}
-% \end{macro}
-% \end{macro}
-%
-% \subsection{Tools for functions}
-%
-% \begin{macro}[EXP]{\@@_parse_function_all_fp_o:fnw}
-% Followed by \Arg{function name} \Arg{code} \meta{float array} |@|
-% this checks all floats are floating point numbers (no tuples).
-% \begin{macrocode}
-\cs_new:Npn \@@_parse_function_all_fp_o:fnw #1#2#3 @
- {
- \@@_array_if_all_fp:nTF {#3}
- { #2 #3 @ }
- {
- \@@_error:nffn { bad-args }
- {#1}
- { \fp_to_tl:n { \s_@@_tuple \@@_tuple_chk:w {#3} ; } }
- { }
- \exp_after:wN \c_nan_fp
- }
- }
-% \end{macrocode}
-% \end{macro}
-%
-% \begin{macro}[EXP]{\@@_parse_function_one_two:nnw}
-% \begin{macro}[EXP]
-% {
-% \@@_parse_function_one_two_error_o:w,
-% \@@_parse_function_one_two_aux:nnw,
-% \@@_parse_function_one_two_auxii:nnw
-% }
-% This is followed by \Arg{function name} \Arg{code} \meta{float
-% array} |@|. It checks that the \meta{float array} consists of one
-% or two floating point numbers (not tuples), then leaves the
-% \meta{code} (if there is one float) or its tail (if there are two
-% floats) followed by the \meta{float array}. The \meta{code} should
-% start with a single token such as \cs{@@_atan_default:w} that deals
-% with the single-float case.
-%
-% The first \cs{@@_if_type_fp:NTwFw} test catches the case of no
-% argument and the case of a tuple argument. The next one
-% distinguishes the case of a single argument (no error, just add
-% \cs{c_one_fp}) from a tuple second argument. Finally check there is
-% no further argument.
-% \begin{macrocode}
-\cs_new:Npn \@@_parse_function_one_two:nnw #1#2#3
- {
- \@@_if_type_fp:NTwFw
- #3 { } \s_@@ \@@_parse_function_one_two_error_o:w \s_@@_stop
- \@@_parse_function_one_two_aux:nnw {#1} {#2} #3
- }
-\cs_new:Npn \@@_parse_function_one_two_error_o:w #1#2#3#4 @
- {
- \@@_error:nffn { bad-args }
- {#2}
- { \fp_to_tl:n { \s_@@_tuple \@@_tuple_chk:w {#4} ; } }
- { }
- \exp_after:wN \c_nan_fp
- }
-\cs_new:Npn \@@_parse_function_one_two_aux:nnw #1#2 #3; #4
- {
- \@@_if_type_fp:NTwFw
- #4 { }
- \s_@@
- {
- \if_meaning:w @ #4
- \exp_after:wN \use_iv:nnnn
- \fi:
- \@@_parse_function_one_two_error_o:w
- }
- \s_@@_stop
- \@@_parse_function_one_two_auxii:nnw {#1} {#2} #3; #4
- }
-\cs_new:Npn \@@_parse_function_one_two_auxii:nnw #1#2#3; #4; #5
- {
- \if_meaning:w @ #5 \else:
- \exp_after:wN \@@_parse_function_one_two_error_o:w
- \fi:
- \use_ii:nn {#1} { \use_none:n #2 } #3; #4; #5
- }
-% \end{macrocode}
-% \end{macro}
-% \end{macro}
-%
-% \begin{macro}[EXP]{\@@_tuple_map_o:nw, \@@_tuple_map_loop_o:nw}
-% Apply |#1| to all items in the following tuple and expand once
-% afterwards. The code |#1| should itself expand once after its
-% result.
-% \begin{macrocode}
-\cs_new:Npn \@@_tuple_map_o:nw #1 \s_@@_tuple \@@_tuple_chk:w #2 ;
- {
- \exp_after:wN \s_@@_tuple
- \exp_after:wN \@@_tuple_chk:w
- \exp_after:wN {
- \exp:w \exp_end_continue_f:w
- \@@_tuple_map_loop_o:nw {#1} #2
- { \s_@@ \prg_break: } ;
- \prg_break_point:
- \exp_after:wN } \exp_after:wN ;
- }
-\cs_new:Npn \@@_tuple_map_loop_o:nw #1#2#3 ;
- {
- \use_none:n #2
- #1 #2 #3 ;
- \exp:w \exp_end_continue_f:w
- \@@_tuple_map_loop_o:nw {#1}
- }
-% \end{macrocode}
-% \end{macro}
-%
-% \begin{macro}[EXP]{\@@_tuple_mapthread_o:nww, \@@_tuple_mapthread_loop_o:nw}
-% Apply |#1| to pairs of items in the two following tuples and expand once
-% afterwards.
-% \begin{macrocode}
-\cs_new:Npn \@@_tuple_mapthread_o:nww #1
- \s_@@_tuple \@@_tuple_chk:w #2 ;
- \s_@@_tuple \@@_tuple_chk:w #3 ;
- {
- \exp_after:wN \s_@@_tuple
- \exp_after:wN \@@_tuple_chk:w
- \exp_after:wN {
- \exp:w \exp_end_continue_f:w
- \@@_tuple_mapthread_loop_o:nw {#1}
- #2 { \s_@@ \prg_break: } ; @
- #3 { \s_@@ \prg_break: } ;
- \prg_break_point:
- \exp_after:wN } \exp_after:wN ;
- }
-\cs_new:Npn \@@_tuple_mapthread_loop_o:nw #1#2#3 ; #4 @ #5#6 ;
- {
- \use_none:n #2
- \use_none:n #5
- #1 #2 #3 ; #5 #6 ;
- \exp:w \exp_end_continue_f:w
- \@@_tuple_mapthread_loop_o:nw {#1} #4 @
- }
-% \end{macrocode}
-% \end{macro}
-%
-% ^^A end[todo]
-%
-% \subsection{Messages}
-%
-% \begin{macrocode}
-\msg_new:nnn { fp } { deprecated }
- { '#1'~deprecated;~use~'#2' }
-\msg_new:nnn { fp } { unknown-fp-word }
- { Unknown~fp~word~#1. }
-\msg_new:nnn { fp } { missing }
- { Missing~#1~inserted #2. }
-\msg_new:nnn { fp } { extra }
- { Extra~#1~ignored. }
-\msg_new:nnn { fp } { early-end }
- { Premature~end~in~fp~expression. }
-\msg_new:nnn { fp } { after-e }
- { Cannot~use~#1 after~'e'. }
-\msg_new:nnn { fp } { missing-number }
- { Missing~number~before~'#1'. }
-\msg_new:nnn { fp } { unknown-symbol }
- { Unknown~symbol~#1~ignored. }
-\msg_new:nnn { fp } { extra-comma }
- { Unexpected~comma~turned~to~nan~result. }
-\msg_new:nnn { fp } { no-arg }
- { #1~got~no~argument;~used~nan. }
-\msg_new:nnn { fp } { multi-arg }
- { #1~got~more~than~one~argument;~used~nan. }
-\msg_new:nnn { fp } { num-args }
- { #1~expects~between~#2~and~#3~arguments. }
-\msg_new:nnn { fp } { bad-args }
- { Arguments~in~#1#2~are~invalid. }
-\msg_new:nnn { fp } { infty-pi }
- { Math~command~#1 is~not~an~fp }
-\cs_if_exist:cT { @unexpandable@protect }
- {
- \msg_new:nnn { fp } { robust-cmd }
- { Robust~command~#1 invalid~in~fp~expression! }
- }
-% \end{macrocode}
-%
-% \begin{macrocode}
-%</package>
-% \end{macrocode}
-%
-% \end{implementation}
-%
-% \PrintChanges
-%
-% \PrintIndex