Skip to main content

calc_lib/
lib.rs

1//! [![git]](https://git.philomathiclife.com/calc_rational/log.html) [![crates-io]](https://crates.io/crates/calc_rational) [![docs-rs]](crate)
2//!
3//! [git]: https://git.philomathiclife.com/git_badge.svg
4//! [crates-io]: https://img.shields.io/badge/crates.io-fc8d62?style=for-the-badge&labelColor=555555&logo=rust
5//! [docs-rs]: https://img.shields.io/badge/docs.rs-66c2a5?style=for-the-badge&labelColor=555555&logo=docs.rs
6//!
7//! `calc_lib` is a library for performing basic rational number arithmetic using standard operator precedence
8//! and associativity. Internally, it is based on
9//! [`Ratio<T>`] and [`BigInt`].
10//!   
11//! ## Expressions  
12//!   
13//! The following are the list of expressions in descending order of precedence:  
14//!   1. number literals, `@`, `()`, `||`, `round()`, `rand()`  
15//!   2. `!`  
16//!   3. `^`  
17//!   4. `-` (unary negation operator)  
18//!   5. `*`, `/`, `mod`  
19//!   6. `+`, `-`  
20//!   
21//! All binary operators are left-associative sans `^` which is right-associative.  
22//!   
23//! Any expression is allowed to be enclosed in `()`. Note that parentheses are purely for grouping expressions;
24//! in particular, you cannot use them to represent multiplication (e.g., `4(2)` is grammatically incorrect and
25//! will result in an error message).  
26//!   
27//! Any expression is allowed to be enclosed in `||`. This unary operator represents absolute value.  
28//!   
29//! `!` is the factorial operator. Due to its high precedence, something like *-i!^j!* for *i, j ∈ ℕ* is
30//! the same thing as *-((i!)^(j!))*. If the expression preceding it does not evaluate to a non-negative integer,
31//! then an error will be displayed. Spaces  and tabs are *not* ignored; so `1 !` is grammatically incorrect and
32//! will result in an error message.  
33//!   
34//! `^` is the exponentiation operator. The expression left of the operator can evaluate to any rational number;
35//! however the expression right of the operator must evaluate to an integer or ±1/2 unless the expression on
36//! the left evaluates to `0` or `1`. In the event of the former, the expression right of the operator must evaluate
37//! to a non-negative rational number. In the event of the latter, the expression right of the operator can evaluate to
38//! any rational number. Note that `0^0` is defined to be 1. When the operand right of `^` evaluates to ±1/2, then
39//! the left operand must be the square of a rational number.  
40//!   
41//! The unary operator `-` represents negation.  
42//!   
43//! The operators `*` and `/` represent multiplication and division respectively. Expressions right of `/`
44//! must evaluate to any non-zero rational number; otherwise an error will be displayed.  
45//!   
46//! The binary operator `mod` represents modulo such that *n mod m = r = n - m\*q* for *n,q ∈ ℤ, m ∈ ℤ\\{0}, and r ∈ ℕ*
47//! where *r* is the minimum non-negative solution.  
48//!   
49//! The binary operators `+` and `-` represent addition and subtraction respectively.  
50//!   
51//! With the aforementioned exception of `!`, all spaces and tabs before and after operators are ignored.  
52//!   
53//! ## Round expression  
54//!   
55//! `round(expression, digit)` rounds `expression` to `digit`-number of fractional digits. An error will
56//! be displayed if called incorrectly.  
57//!   
58//! ## Rand expression  
59//!   
60//! `rand(expression, expression)` generates a random 64-bit integer inclusively between the passed expressions.
61//! An error will be displayed if called incorrectly. `rand()` generates a random 64-bit integer.  
62//!   
63//! ## Numbers  
64//!   
65//! A number literal is a non-empty sequence of digits or a non-empty sequence of digits immediately followed by `.`
66//! which is immediately followed by a non-empty sequence of digits (e.g., `134.901`). This means that number
67//! literals represent precisely all rational numbers that are equivalent to a ratio of a non-negative integer
68//! to a positive integer whose sole prime factors are 2 or 5. To represent all other rational numbers, the unary
69//! operator `-` and binary operator `/` must be used.  
70//!   
71//! ## Empty expression  
72//!   
73//! The empty expression (i.e., expression that at most only consists of spaces and tabs) will return
74//! the result from the previous non-(empty/store) expression in *decimal* form using the minimum number of digits.
75//! In the event an infinite number of digits is required, it will be rounded to 9 fractional digits using normal rounding
76//! rules first.  
77//!   
78//! ## Store expression  
79//!   
80//! To store the result of the previous non-(empty/store) expression, one simply passes `s`. In addition to storing the
81//! result which will subsequently be available via `@`, it displays the result. At most 8 results can be stored at once;
82//! at which point, results that are stored overwrite the oldest result.  
83//!   
84//! ## Recall expression  
85//!   
86//! `@` is used to recall previously stored results. It can be followed by any *digit* from `1` to `8`.
87//! If such a digit does not immediately follow it, then it will be interpreted as if there were a `1`.
88//! `@i` returns the *i*-th most-previous stored result where *i ∈ {1, 2, 3, 4, 5, 6, 7, 8}*.
89//! Note that spaces and tabs are *not* ignored so `@ 2` is grammatically incorrect and will result in an error message.
90//! As emphasized, it does not work on expressions; so both `@@` and `@(1)` are grammatically incorrect.  
91//!   
92//! ## Character encoding  
93//!   
94//! All inputs must only contain the ASCII encoding of the following Unicode scalar values: `0`-`9`, `.`, `+`, `-`,
95//! `*`, `/`, `^`, `!`, `mod`, `|`, `(`, `)`, `round`, `rand`, `,`, `@`, `s`, &lt;space&gt;, &lt;tab&gt;,
96//! &lt;line feed&gt;, &lt;carriage return&gt;, and `q`. Any other byte sequences are grammatically incorrect and will
97//! lead to an error message.  
98//!   
99//! ## Errors  
100//!   
101//! Errors due to a language violation (e.g., dividing by `0`) manifest into an error message. `panic!`s
102//! and [`io::Error`](https://doc.rust-lang.org/std/io/struct.Error.html)s caused by writing to the global
103//! standard output stream lead to program abortion.  
104//!   
105//! ## Exiting  
106//!   
107//! `q` with any number of spaces and tabs before and after will cause the program to terminate.  
108//!   
109//! ### Formal language specification  
110//!   
111//! For a more precise specification of the “calc language”, one can read the
112//! [calc language specification](https://git.philomathiclife.com/calc_rational/lang.pdf).
113#![expect(
114    clippy::doc_paragraphs_missing_punctuation,
115    reason = "false positive for crate documentation having image links"
116)]
117#![expect(
118    clippy::arithmetic_side_effects,
119    reason = "calculator can't realistically avoid this"
120)]
121#![no_std]
122#![cfg_attr(docsrs, feature(doc_cfg))]
123extern crate alloc;
124use LangErr::{
125    DivByZero, ExpDivByZero, ExpIsNotIntOrOneHalf, InvalidAbs, InvalidDec, InvalidPar, InvalidQuit,
126    InvalidRound, InvalidStore, MissingTerm, ModIsNotInt, ModZero, NotEnoughPrevResults,
127    NotNonNegIntFact, SqrtDoesNotExist, TrailingSyms,
128};
129use O::{Empty, Eval, Exit, Store};
130use alloc::{
131    string::{String, ToString as _},
132    vec,
133    vec::Vec,
134};
135use cache::Cache;
136#[cfg(not(feature = "rand"))]
137use core::marker::PhantomData;
138use core::{
139    convert,
140    fmt::{self, Display, Formatter},
141    ops::Index as _,
142};
143pub use num_bigint;
144use num_bigint::{BigInt, BigUint, Sign};
145use num_integer::Integer as _;
146pub use num_rational;
147use num_rational::Ratio;
148#[cfg(feature = "rand")]
149use num_traits::ToPrimitive as _;
150use num_traits::{Inv as _, Pow as _};
151#[cfg(target_os = "openbsd")]
152use priv_sep as _;
153#[cfg(feature = "rand")]
154pub use rand;
155#[cfg(feature = "rand")]
156use rand::{Rng as _, rngs::ThreadRng};
157/// Fixed-sized cache that automatically overwrites the oldest data
158/// when a new item is added and the cache is full.
159///
160/// One can think of
161/// [`Cache`] as a very limited but more performant [`VecDeque`][alloc::collections::VecDeque] that only
162/// adds new data or reads old data.
163pub mod cache;
164/// Generalizes [`Iterator`] by using
165/// generic associated types.
166pub mod lending_iterator;
167/// Error due to a language violation.
168#[non_exhaustive]
169#[cfg_attr(test, derive(Eq, PartialEq))]
170#[derive(Debug)]
171pub enum LangErr {
172    /// The input began with a `q` but had non-whitespace
173    /// that followed it.
174    InvalidQuit,
175    /// The input began with an `s` but had non-whitespace
176    /// that followed it.
177    InvalidStore,
178    /// A sub-expression in the input would have led
179    /// to a division by zero.
180    DivByZero(usize),
181    /// A sub-expression in the input would have led
182    /// to a rational number that was not 0 or 1 to be
183    /// raised to a non-integer power that is not (+/-) 1/2.
184    ExpIsNotIntOrOneHalf(usize),
185    /// A sub-expression in the input would have led
186    /// to 0 being raised to a negative power which itself
187    /// would have led to a division by zero.
188    ExpDivByZero(usize),
189    /// A sub-expression in the input would have led
190    /// to a number modulo 0.
191    ModZero(usize),
192    /// A sub-expression in the input would have led
193    /// to the mod of two expressions with at least one
194    /// not being an integer.
195    ModIsNotInt(usize),
196    /// A sub-expression in the input would have led
197    /// to a non-integer factorial or a negative integer factorial.
198    NotNonNegIntFact(usize),
199    /// The input contained a non-empty sequence of digits followed
200    /// by `.` which was not followed by a non-empty sequence of digits.
201    InvalidDec(usize),
202    /// A recall expression was used to recall the *i*-th most-recent stored result,
203    /// but there are fewer than *i* stored where
204    /// *i ∈ {1, 2, 3, 4, 5, 6, 7, 8}*.
205    NotEnoughPrevResults(usize),
206    /// The input did not contain a closing `|`.
207    InvalidAbs(usize),
208    /// The input did not contain a closing `)`.
209    InvalidPar(usize),
210    /// The input contained an invalid round expression.
211    InvalidRound(usize),
212    /// A sub-expression in the input had a missing terminal expression
213    /// where a terminal expression is a decimal literal expression,
214    /// recall expression, absolute value expression, parenthetical
215    /// expression, or round expression.
216    MissingTerm(usize),
217    /// The expression that was passed to the square root does not have a solution
218    /// in the field of rational numbers.
219    SqrtDoesNotExist(usize),
220    /// The input started with a valid expression but was immediately followed
221    /// by symbols that could not be chained with the preceding expression.
222    TrailingSyms(usize),
223    /// The input contained an invalid random expression.
224    #[cfg(feature = "rand")]
225    InvalidRand(usize),
226    /// Error when the second argument is less than first in the rand function.
227    #[cfg(feature = "rand")]
228    RandInvalidArgs(usize),
229    /// Error when there are no 64-bit integers in the interval passed to the random function.
230    #[cfg(feature = "rand")]
231    RandNoInts(usize),
232}
233impl Display for LangErr {
234    #[inline]
235    fn fmt(&self, f: &mut Formatter<'_>) -> fmt::Result {
236        match *self {
237            InvalidStore => f.write_str("Invalid store expression. A store expression must be of the extended regex form: ^[ \\t]*s[ \\t]*$."),
238            InvalidQuit => f.write_str("Invalid quit expression. A quit expression must be of the extended regex form: ^[ \\t]*q[ \\t]*$."),
239            DivByZero(u) => write!(f, "Division by zero ending at position {u}."),
240            ExpIsNotIntOrOneHalf(u) => write!(f, "Non-integer exponent that is not (+/-) 1/2 with a base that was not 0 or 1 ending at position {u}."),
241            ExpDivByZero(u) => write!(f, "Non-negative exponent with a base of 0 ending at position {u}."),
242            ModZero(u) => write!(f, "A number modulo 0 ending at position {u}."),
243            ModIsNotInt(u) => write!(f, "The modulo expression was applied to at least one non-integer ending at position {u}."),
244            NotNonNegIntFact(u) => write!(f, "Factorial of a rational number that was not a non-negative integer ending at position {u}."),
245            InvalidDec(u) => write!(f, "Invalid decimal literal expression ending at position {u}. A decimal literal expression must be of the extended regex form: [0-9]+(\\.[0-9]+)?."),
246            NotEnoughPrevResults(len) => write!(f, "There are only {len} previous results."),
247            InvalidAbs(u) => write!(f, "Invalid absolute value expression ending at position {u}. An absolute value expression is an addition expression enclosed in '||'."),
248            InvalidPar(u) => write!(f, "Invalid parenthetical expression ending at position {u}. A parenthetical expression is an addition expression enclosed in '()'."),
249            InvalidRound(u) => write!(f, "Invalid round expression ending at position {u}. A round expression is of the form 'round(<mod expression>, digit)'"),
250            SqrtDoesNotExist(u) => write!(f, "The square root of the passed expression does not have a solution in the field of rational numbers ending at position {u}."),
251            #[cfg(not(feature = "rand"))]
252            MissingTerm(u) => write!(f, "Missing terminal expression at position {u}. A terminal expression is a decimal literal expression, recall expression, absolute value expression, parenthetical expression, or round expression."),
253            #[cfg(feature = "rand")]
254            MissingTerm(u) => write!(f, "Missing terminal expression at position {u}. A terminal expression is a decimal literal expression, recall expression, absolute value expression, parenthetical expression, round expression, or rand expression."),
255            TrailingSyms(u) => write!(f, "Trailing symbols starting at position {u}."),
256            #[cfg(feature = "rand")]
257            Self::InvalidRand(u) => write!(f, "Invalid rand expression ending at position {u}. A rand expression is of the form 'rand()' or 'rand(<mod expression>, <mod expression>)'."),
258            #[cfg(feature = "rand")]
259            Self::RandInvalidArgs(u) => write!(f, "The second expression passed to the random function evaluated to rational number less than the first ending at position {u}."),
260            #[cfg(feature = "rand")]
261            Self::RandNoInts(u) => write!(f, "There are no 64-bit integers within the interval passed to the random function ending at position {u}."),
262        }
263    }
264}
265/// A successful evaluation of an input.
266#[cfg_attr(test, derive(Eq, PartialEq))]
267#[derive(Debug)]
268pub enum O<'a> {
269    /// The input only contained whitespace.
270    /// This returns the previous `Eval`.
271    /// It is `None` iff there have been no
272    /// previous `Eval` results.
273    Empty(&'a Option<Ratio<BigInt>>),
274    /// The quit expression was issued to terminate the program.
275    Exit,
276    /// Result of a "normal" expression.
277    Eval(&'a Ratio<BigInt>),
278    /// The store expression stores and returns the previous `Eval`.
279    /// It is `None` iff there have been no previous `Eval` results.
280    Store(&'a Option<Ratio<BigInt>>),
281}
282impl Display for O<'_> {
283    #[expect(
284        unsafe_code,
285        reason = "manually construct guaranteed UTF-8; thus avoid the needless check"
286    )]
287    #[expect(clippy::indexing_slicing, reason = "comment justifies correctness")]
288    #[inline]
289    fn fmt(&self, f: &mut Formatter<'_>) -> fmt::Result {
290        match *self {
291            Empty(o) => {
292                o.as_ref().map_or(Ok(()), |val| {
293                    if val.is_integer() {
294                        write!(f, "> {val}")
295                    } else {
296                        // If the prime factors of the denominator are only 2 and 5,
297                        // then the number requires a finite number of digits and thus
298                        // will be represented perfectly using the fewest number of digits.
299                        // Any other situation will be rounded to 9 fractional digits.
300                        // max{twos, fives} represents the minimum number of fractional
301                        // digits necessary to represent val.
302                        let mut twos = 0;
303                        let mut fives = 0;
304                        let zero = BigInt::from_biguint(Sign::NoSign, BigUint::new(Vec::new()));
305                        let one = BigInt::from_biguint(Sign::Plus, BigUint::new(vec![1]));
306                        let two = BigInt::from_biguint(Sign::Plus, BigUint::new(vec![2]));
307                        let five = BigInt::from_biguint(Sign::Plus, BigUint::new(vec![5]));
308                        let mut denom = val.denom().clone();
309                        let mut div_rem;
310                        while denom > one {
311                            div_rem = denom.div_rem(&two);
312                            if div_rem.1 == zero {
313                                twos += 1;
314                                denom = div_rem.0;
315                            } else {
316                                break;
317                            }
318                        }
319                        while denom > one {
320                            div_rem = denom.div_rem(&five);
321                            if div_rem.1 == zero {
322                                fives += 1;
323                                denom = div_rem.0;
324                            } else {
325                                break;
326                            }
327                        }
328                        // int < 0 iff val <= -1. frac < 0 iff val is a negative non-integer.
329                        let (int, frac, digits) = if denom == one {
330                            let (int, mut frac) = val.numer().div_rem(val.denom());
331                            while twos > fives {
332                                frac *= &five;
333                                fives += 1;
334                            }
335                            while fives > twos {
336                                frac *= &two;
337                                twos += 1;
338                            }
339                            (int, frac, twos)
340                        } else {
341                            // Requires an infinite number of decimal digits to represent, so we display
342                            // 9 digits after rounding.
343                            let mult =
344                                BigInt::from_biguint(Sign::Plus, BigUint::new(vec![10])).pow(9u8);
345                            let (int, frac) = (val * &mult).round().numer().div_rem(&mult);
346                            (int, frac, 9)
347                        };
348                        let int_str = int.to_string().into_bytes();
349                        let (mut v, frac_str) = if val.numer().sign() == Sign::Minus {
350                            // Guaranteed to be non-empty.
351                            if int_str[0] == b'-' {
352                                (
353                                    Vec::with_capacity(int_str.len() + 1 + digits),
354                                    (-frac).to_string().into_bytes(),
355                                )
356                            } else {
357                                let mut tmp = Vec::with_capacity(int_str.len() + 2 + digits);
358                                tmp.push(b'-');
359                                (tmp, (-frac).to_string().into_bytes())
360                            }
361                        } else {
362                            (
363                                Vec::with_capacity(int_str.len() + 1 + digits),
364                                frac.to_string().into_bytes(),
365                            )
366                        };
367                        v.extend_from_slice(int_str.as_slice());
368                        v.push(b'.');
369                        // digits >= frac_str.len().
370                        v.resize(v.len() + (digits - frac_str.len()), b'0');
371                        v.extend_from_slice(frac_str.as_slice());
372                        // SAFETY:
373                        // v contains precisely the UTF-8 code units returned from Strings
374                        // returned from the to_string function on the integer and fraction part of
375                        // val plus optionally the single byte encodings of ".", "-", and "0".
376                        write!(f, "> {}", unsafe { String::from_utf8_unchecked(v) })
377                    }
378                })
379            }
380            Eval(r) => write!(f, "> {r}"),
381            Exit => Ok(()),
382            Store(o) => o.as_ref().map_or(Ok(()), |val| write!(f, "> {val}")),
383        }
384    }
385}
386/// Size of [`Evaluator::cache`].
387const CACHE_SIZE: usize = 8;
388/// Evaluates the supplied input.
389#[derive(Debug)]
390pub struct Evaluator<'input, 'cache, 'prev, 'scratch, 'rand> {
391    /// The input to be evaluated.
392    utf8: &'input [u8],
393    /// The index within `utf8` that evaluation needs to continue.
394    /// We use this instead of slicing from `utf8` since we want
395    /// to be able to report the position within the input
396    /// that an error occurs.
397    i: usize,
398    /// The cache of previously stored results.
399    cache: &'cache mut Cache<Ratio<BigInt>, CACHE_SIZE>,
400    /// The last result.
401    prev: &'prev mut Option<Ratio<BigInt>>,
402    /// Buffer used to evaluate right-associative sub-expressions.
403    scratch: &'scratch mut Vec<Ratio<BigInt>>,
404    /// Random number generator.
405    #[cfg(feature = "rand")]
406    rng: &'rand mut ThreadRng,
407    /// Need to use `'rand`.
408    #[cfg(not(feature = "rand"))]
409    _rng: PhantomData<fn() -> &'rand ()>,
410}
411#[allow(
412    single_use_lifetimes,
413    clippy::allow_attributes,
414    clippy::elidable_lifetime_names,
415    reason = "unify rand and not rand"
416)]
417impl<'input, 'cache, 'prev, 'scratch, 'rand> Evaluator<'input, 'cache, 'prev, 'scratch, 'rand> {
418    /// Creates an `Evaluator<'input, 'cache, 'prev, 'scratch, 'rand>` based on the supplied arguments.
419    #[cfg(not(feature = "rand"))]
420    #[inline]
421    pub fn new(
422        utf8: &'input [u8],
423        cache: &'cache mut Cache<Ratio<BigInt>, 8>,
424        prev: &'prev mut Option<Ratio<BigInt>>,
425        scratch: &'scratch mut Vec<Ratio<BigInt>>,
426    ) -> Self {
427        Self {
428            utf8,
429            i: 0,
430            cache,
431            prev,
432            scratch,
433            _rng: PhantomData,
434        }
435    }
436    /// Creates an `Evaluator<'input, 'cache, 'prev, 'scratch, 'rand>` based on the supplied arguments.
437    #[cfg(feature = "rand")]
438    #[inline]
439    pub const fn new(
440        utf8: &'input [u8],
441        cache: &'cache mut Cache<Ratio<BigInt>, 8>,
442        prev: &'prev mut Option<Ratio<BigInt>>,
443        scratch: &'scratch mut Vec<Ratio<BigInt>>,
444        rng: &'rand mut ThreadRng,
445    ) -> Self {
446        Self {
447            utf8,
448            i: 0,
449            cache,
450            prev,
451            scratch,
452            rng,
453        }
454    }
455    /// Evaluates the input consuming the `Evaluator<'input, 'cache, 'exp>`.
456    ///
457    /// Requires the input to contain one expression (i.e., if there are
458    /// multiple newlines, it will error).
459    ///
460    /// # Errors
461    ///
462    /// Returns a [`LangErr`] iff the input violates the calc language.
463    #[expect(clippy::indexing_slicing, reason = "correct")]
464    #[inline]
465    pub fn evaluate(mut self) -> Result<O<'prev>, LangErr> {
466        self.utf8 = if self.utf8.last().is_none_or(|b| *b != b'\n') {
467            self.utf8
468        } else {
469            &self.utf8[..self.utf8.len()
470                - self
471                    .utf8
472                    .get(self.utf8.len().wrapping_sub(2))
473                    .map_or(1, |b| if *b == b'\r' { 2 } else { 1 })]
474        };
475        self.consume_ws();
476        let Some(b) = self.utf8.get(self.i) else {
477            return Ok(Empty(self.prev));
478        };
479        if *b == b'q' {
480            self.i += 1;
481            self.consume_ws();
482            if self.i == self.utf8.len() {
483                Ok(Exit)
484            } else {
485                Err(InvalidQuit)
486            }
487        } else if *b == b's' {
488            self.i += 1;
489            self.consume_ws();
490            if self.i == self.utf8.len() {
491                if let Some(ref val) = *self.prev {
492                    self.cache.push(val.clone());
493                }
494                Ok(Store(self.prev))
495            } else {
496                Err(InvalidStore)
497            }
498        } else {
499            self.get_adds().and_then(move |val| {
500                self.consume_ws();
501                if self.i == self.utf8.len() {
502                    Ok(Eval(self.prev.insert(val)))
503                } else {
504                    Err(TrailingSyms(self.i))
505                }
506            })
507        }
508    }
509    /// Reads from the input until the next non-{space/tab} byte value.
510    #[expect(clippy::indexing_slicing, reason = "correct")]
511    fn consume_ws(&mut self) {
512        // ControlFlow makes more sense to use in try_fold; however due to a lack
513        // of a map_or_else function, it is easier to simply return a Result with
514        // Err taking the role of ControlFlow::Break.
515        self.i += self.utf8[self.i..]
516            .iter()
517            .try_fold(0, |val, b| match *b {
518                b' ' | b'\t' => Ok(val + 1),
519                _ => Err(val),
520            })
521            .map_or_else(convert::identity, convert::identity);
522    }
523    /// Evaluates addition expressions as defined in the calc language.
524    /// This function is used for both addition and subtraction operations which
525    /// themselves are based on multiplication expressions.
526    fn get_adds(&mut self) -> Result<Ratio<BigInt>, LangErr> {
527        let mut left = self.get_mults()?;
528        let mut j;
529        self.consume_ws();
530        while let Some(i) = self.utf8.get(self.i) {
531            j = *i;
532            self.consume_ws();
533            if j == b'+' {
534                self.i += 1;
535                self.consume_ws();
536                left += self.get_mults()?;
537            } else if j == b'-' {
538                self.i += 1;
539                self.consume_ws();
540                left -= self.get_mults()?;
541            } else {
542                break;
543            }
544        }
545        Ok(left)
546    }
547    /// Evaluates multiplication expressions as defined in the calc language.
548    /// This function is used for both multiplication and division operations which
549    /// themselves are based on negation expressions.
550    fn get_mults(&mut self) -> Result<Ratio<BigInt>, LangErr> {
551        let mut left = self.get_neg()?;
552        let mut right;
553        let mut j;
554        let mut mod_val;
555        let mut numer;
556        self.consume_ws();
557        while let Some(i) = self.utf8.get(self.i) {
558            j = *i;
559            self.consume_ws();
560            if j == b'*' {
561                self.i += 1;
562                self.consume_ws();
563                left *= self.get_neg()?;
564            } else if j == b'/' {
565                self.i += 1;
566                self.consume_ws();
567                right = self.get_neg()?;
568                if right.numer().sign() == Sign::NoSign {
569                    return Err(DivByZero(self.i));
570                }
571                left /= right;
572            } else if let Some(k) = self.utf8.get(self.i..self.i.saturating_add(3)) {
573                if k == b"mod" {
574                    if !left.is_integer() {
575                        return Err(ModIsNotInt(self.i));
576                    }
577                    self.i += 3;
578                    self.consume_ws();
579                    right = self.get_neg()?;
580                    if !right.is_integer() {
581                        return Err(ModIsNotInt(self.i));
582                    }
583                    numer = right.numer();
584                    if numer.sign() == Sign::NoSign {
585                        return Err(ModZero(self.i));
586                    }
587                    mod_val = left.numer() % numer;
588                    left = Ratio::from_integer(if mod_val.sign() == Sign::Minus {
589                        if numer.sign() == Sign::Minus {
590                            mod_val - numer
591                        } else {
592                            mod_val + numer
593                        }
594                    } else {
595                        mod_val
596                    });
597                } else {
598                    break;
599                }
600            } else {
601                break;
602            }
603        }
604        Ok(left)
605    }
606    /// Evaluates negation expressions as defined in the calc language.
607    /// This function is based on exponentiation expressions.
608    fn get_neg(&mut self) -> Result<Ratio<BigInt>, LangErr> {
609        let mut count = 0usize;
610        while let Some(b) = self.utf8.get(self.i) {
611            if *b == b'-' {
612                self.i += 1;
613                self.consume_ws();
614                count += 1;
615            } else {
616                break;
617            }
618        }
619        self.get_exps()
620            .map(|val| if count & 1 == 0 { val } else { -val })
621    }
622    /// Gets the square root of value so long as a solution exists.
623    #[expect(
624        clippy::unreachable,
625        reason = "code that shouldn't happen did, so we want to crash"
626    )]
627    fn sqrt(val: Ratio<BigInt>) -> Option<Ratio<BigInt>> {
628        /// Returns the square root of `n` if one exists; otherwise
629        /// returns `None`.
630        /// MUST NOT pass 0.
631        #[expect(clippy::suspicious_operation_groupings, reason = "false positive")]
632        fn calc(n: &BigUint) -> Option<BigUint> {
633            let mut shift = n.bits();
634            shift += shift & 1;
635            let mut result = BigUint::new(Vec::new());
636            let one = BigUint::new(vec![1]);
637            let zero = BigUint::new(Vec::new());
638            loop {
639                shift -= 2;
640                result <<= 1u32;
641                result |= &one;
642                result ^= if &result * &result > (n >> shift) {
643                    &one
644                } else {
645                    &zero
646                };
647                if shift == 0 {
648                    break (&result * &result == *n).then_some(result);
649                }
650            }
651        }
652        let numer = val.numer();
653        if numer.sign() == Sign::NoSign {
654            Some(val)
655        } else {
656            numer.try_into().map_or_else(
657                |_| None,
658                |num| {
659                    calc(&num).and_then(|n| {
660                        calc(&val.denom().try_into().unwrap_or_else(|_| {
661                            unreachable!("Ratio must never have a negative denominator")
662                        }))
663                        .map(|d| Ratio::new(n.into(), d.into()))
664                    })
665                },
666            )
667        }
668    }
669    /// Evaluates exponentiation expressions as defined in the calc language.
670    /// This function is based on negation expressions.
671    fn get_exps(&mut self) -> Result<Ratio<BigInt>, LangErr> {
672        let mut t = self.get_fact()?;
673        let ix = self.scratch.len();
674        let mut prev;
675        let mut numer;
676        self.scratch.push(t);
677        self.consume_ws();
678        let mut j;
679        let one = BigInt::new(Sign::Plus, vec![1]);
680        let min_one = BigInt::new(Sign::Minus, vec![1]);
681        let two = BigInt::new(Sign::Plus, vec![2]);
682        while let Some(i) = self.utf8.get(self.i) {
683            j = *i;
684            self.consume_ws();
685            if j == b'^' {
686                self.i += 1;
687                self.consume_ws();
688                t = self.get_neg()?;
689                // Safe since we always push at least one value, and we always
690                // return immediately once we encounter an error.
691                prev = self.scratch.index(self.scratch.len() - 1);
692                numer = prev.numer();
693                // Equiv to checking if prev is 0.
694                if numer.sign() == Sign::NoSign {
695                    if t.numer().sign() == Sign::Minus {
696                        self.scratch.clear();
697                        return Err(ExpDivByZero(self.i));
698                    }
699                    self.scratch.push(t);
700                } else if prev.is_integer() {
701                    let t_numer = t.numer();
702                    // 1 raised to anything is 1, so we don't bother
703                    // storing the exponent.
704                    if *numer == one {
705                    } else if t.is_integer()
706                        || ((*t_numer == one || *t_numer == min_one) && *t.denom() == two)
707                    {
708                        self.scratch.push(t);
709                    } else {
710                        self.scratch.clear();
711                        return Err(ExpIsNotIntOrOneHalf(self.i));
712                    }
713                } else if t.is_integer()
714                    || ((*t.numer() == one || *t.numer() == min_one) && *t.denom() == two)
715                {
716                    self.scratch.push(t);
717                } else {
718                    self.scratch.clear();
719                    return Err(ExpIsNotIntOrOneHalf(self.i));
720                }
721            } else {
722                break;
723            }
724        }
725        self.scratch
726            .drain(ix..)
727            .try_rfold(Ratio::from_integer(one.clone()), |exp, base| {
728                if exp.is_integer() {
729                    Ok(base.pow(exp.numer()))
730                } else if base.numer().sign() == Sign::NoSign {
731                    Ok(base)
732                } else if *exp.denom() == two {
733                    if *exp.numer() == one {
734                        Self::sqrt(base).map_or_else(|| Err(SqrtDoesNotExist(self.i)), Ok)
735                    } else if *exp.numer() == min_one {
736                        Self::sqrt(base)
737                            .map_or_else(|| Err(SqrtDoesNotExist(self.i)), |v| Ok(v.inv()))
738                    } else {
739                        Err(ExpIsNotIntOrOneHalf(self.i))
740                    }
741                } else {
742                    Err(ExpIsNotIntOrOneHalf(self.i))
743                }
744            })
745    }
746    /// Evaluates factorial expressions as defined in the calc language.
747    /// This function is based on terminal expressions.
748    fn get_fact(&mut self) -> Result<Ratio<BigInt>, LangErr> {
749        /// Calculates the factorial of `val`.
750        fn fact(mut val: BigUint) -> BigUint {
751            let zero = BigUint::new(Vec::new());
752            let one = BigUint::new(vec![1]);
753            let mut calc = BigUint::new(vec![1]);
754            while val > zero {
755                calc *= &val;
756                val -= &one;
757            }
758            calc
759        }
760        let t = self.get_term()?;
761        let Some(b) = self.utf8.get(self.i) else {
762            return Ok(t);
763        };
764        if *b == b'!' {
765            self.i += 1;
766            if t.is_integer() {
767                // We can make a copy of self.i here, or call map_or instead
768                // of map_or_else.
769                let i = self.i;
770                t.numer().try_into().map_or_else(
771                    |_| Err(NotNonNegIntFact(i)),
772                    |val| {
773                        let mut factorial = fact(val);
774                        while let Some(b2) = self.utf8.get(self.i) {
775                            if *b2 == b'!' {
776                                self.i += 1;
777                                factorial = fact(factorial);
778                            } else {
779                                break;
780                            }
781                        }
782                        Ok(Ratio::from_integer(BigInt::from_biguint(
783                            Sign::Plus,
784                            factorial,
785                        )))
786                    },
787                )
788            } else {
789                Err(NotNonNegIntFact(self.i))
790            }
791        } else {
792            Ok(t)
793        }
794    }
795    /// Evaluates terminal expressions as defined in the calc language.
796    /// This function is based on number literal expressions, parenthetical expressions,
797    /// recall expressions, absolute value expressions, round expressions, and possibly
798    /// rand expressions if that feature is enabled.
799    fn get_term(&mut self) -> Result<Ratio<BigInt>, LangErr> {
800        self.get_rational().map_or_else(Err, |o| {
801            o.map_or_else(
802                || {
803                    self.get_par().map_or_else(Err, |o2| {
804                        o2.map_or_else(
805                            || {
806                                self.get_recall().map_or_else(Err, |o3| {
807                                    o3.map_or_else(
808                                        || {
809                                            self.get_abs().map_or_else(Err, |o4| {
810                                                o4.map_or_else(
811                                                    || {
812                                                        self.get_round().and_then(|o5| {
813                                                            o5.map_or_else(
814                                                                #[cfg(not(feature = "rand"))]
815                                                                || Err(MissingTerm(self.i)),
816                                                                #[cfg(feature = "rand")]
817                                                                || self.get_rand(),
818                                                                Ok,
819                                                            )
820                                                        })
821                                                    },
822                                                    Ok,
823                                                )
824                                            })
825                                        },
826                                        Ok,
827                                    )
828                                })
829                            },
830                            Ok,
831                        )
832                    })
833                },
834                Ok,
835            )
836        })
837    }
838    /// Generates a random 64-bit integer. This function is based on add expressions. This is the last terminal
839    /// expression attempted when needing a terminal expression; as a result, it is the only terminal expression
840    /// that does not return an `Option`.
841    #[cfg(feature = "rand")]
842    fn get_rand(&mut self) -> Result<Ratio<BigInt>, LangErr> {
843        /// Generates a random 64-bit integer.
844        #[expect(clippy::host_endian_bytes, reason = "must keep platform endianness")]
845        fn rand(rng: &mut ThreadRng) -> i64 {
846            let mut bytes = [0; 8];
847            // `ThreadRng::try_fill_bytes` is infallible, so easier to call `fill_bytes`.
848            rng.fill_bytes(&mut bytes);
849            i64::from_ne_bytes(bytes)
850        }
851        /// Generates a random 64-bit integer inclusively between the passed arguments.
852        #[expect(
853            clippy::integer_division_remainder_used,
854            reason = "need for uniform randomness"
855        )]
856        #[expect(
857            clippy::as_conversions,
858            clippy::cast_possible_truncation,
859            clippy::cast_possible_wrap,
860            clippy::cast_sign_loss,
861            reason = "lossless conversions between signed integers"
862        )]
863        fn rand_range(
864            rng: &mut ThreadRng,
865            lower: &Ratio<BigInt>,
866            upper: &Ratio<BigInt>,
867            i: usize,
868        ) -> Result<i64, LangErr> {
869            if lower > upper {
870                return Err(LangErr::RandInvalidArgs(i));
871            }
872            let lo = lower.ceil();
873            let up = upper.floor();
874            let lo_int = lo.numer();
875            let up_int = up.numer();
876            if lo_int > &BigInt::from(i64::MAX) || up_int < &BigInt::from(i64::MIN) {
877                return Err(LangErr::RandNoInts(i));
878            }
879            let lo_min = lo_int.to_i64().unwrap_or(i64::MIN);
880            let up_max = up_int.to_i64().unwrap_or(i64::MAX);
881            if up_max > lo_min || upper.is_integer() || lower.is_integer() {
882                let low = i128::from(lo_min);
883                // `i64::MAX >= up_max >= low`; so underflow and overflow cannot happen.
884                // range is [1, 2^64] so casting to a u128 is fine.
885                let modulus = (i128::from(up_max) - low + 1) as u128;
886                // range is [0, i64::MAX] so converting to a `u64` is fine.
887                // rem represents how many values need to be removed
888                // when generating a random i64 in order for uniformity.
889                let rem = (0x0001_0000_0000_0000_0000 % modulus) as u64;
890                let mut low_adj;
891                loop {
892                    low_adj = rand(rng) as u64;
893                    // Since rem is in [0, i64::MAX], this is the same as low_adj < 0 || low_adj >= rem.
894                    if low_adj >= rem {
895                        return Ok(
896                            // range is [i64::MIN, i64::MAX]; thus casts are safe.
897                            // modulus is up_max - low + 1; so as low grows,
898                            // % shrinks by the same factor. i64::MAX happens
899                            // when low = up_max = i64::MAX or when low = 0,
900                            // up_max = i64::MAX and low_adj is i64::MAX.
901                            ((u128::from(low_adj) % modulus) as i128 + low) as i64,
902                        );
903                    }
904                }
905            } else {
906                Err(LangErr::RandNoInts(i))
907            }
908        }
909        // This is the last kind of terminal expression that is attempted.
910        // If there is no more data, then we have a missing terminal expression.
911        let Some(b) = self.utf8.get(self.i..self.i.saturating_add(5)) else {
912            return Err(MissingTerm(self.i));
913        };
914        if b == b"rand(" {
915            self.i += 5;
916            self.consume_ws();
917            let i = self.i;
918            self.utf8.get(self.i).map_or_else(
919                || Err(LangErr::InvalidRand(i)),
920                |p| {
921                    if *p == b')' {
922                        self.i += 1;
923                        Ok(Ratio::from_integer(BigInt::from(rand(self.rng))))
924                    } else {
925                        let add = self.get_adds()?;
926                        let Some(b2) = self.utf8.get(self.i) else {
927                            return Err(LangErr::InvalidRand(self.i));
928                        };
929                        if *b2 == b',' {
930                            self.i += 1;
931                            self.consume_ws();
932                            let add2 = self.get_adds()?;
933                            self.consume_ws();
934                            let Some(b3) = self.utf8.get(self.i) else {
935                                return Err(LangErr::InvalidRand(self.i));
936                            };
937                            if *b3 == b')' {
938                                self.i += 1;
939                                rand_range(self.rng, &add, &add2, self.i)
940                                    .map(|v| Ratio::from_integer(BigInt::from(v)))
941                            } else {
942                                Err(LangErr::InvalidRand(self.i))
943                            }
944                        } else {
945                            Err(LangErr::InvalidRand(self.i))
946                        }
947                    }
948                },
949            )
950        } else {
951            Err(MissingTerm(self.i))
952        }
953    }
954    /// Rounds a value to the specified number of fractional digits.
955    /// This function is based on add expressions.
956    fn get_round(&mut self) -> Result<Option<Ratio<BigInt>>, LangErr> {
957        let Some(b) = self.utf8.get(self.i..self.i.saturating_add(6)) else {
958            return Ok(None);
959        };
960        if b == b"round(" {
961            self.i += 6;
962            self.consume_ws();
963            let val = self.get_adds()?;
964            self.consume_ws();
965            let Some(b2) = self.utf8.get(self.i) else {
966                return Err(InvalidRound(self.i));
967            };
968            let b3 = *b2;
969            if b3 == b',' {
970                self.i += 1;
971                self.consume_ws();
972                let Some(b4) = self.utf8.get(self.i) else {
973                    return Err(InvalidRound(self.i));
974                };
975                let r = if b4.is_ascii_digit() {
976                    self.i += 1;
977                    *b4 - b'0'
978                } else {
979                    return Err(InvalidRound(self.i));
980                };
981                self.consume_ws();
982                let i = self.i;
983                self.utf8.get(self.i).map_or_else(
984                    || Err(InvalidRound(i)),
985                    |p| {
986                        if *p == b')' {
987                            self.i += 1;
988                            let mult =
989                                BigInt::from_biguint(Sign::Plus, BigUint::new(vec![10])).pow(r);
990                            Ok(Some((val * &mult).round() / &mult))
991                        } else {
992                            Err(InvalidRound(self.i))
993                        }
994                    },
995                )
996            } else {
997                Err(InvalidRound(self.i))
998            }
999        } else {
1000            Ok(None)
1001        }
1002    }
1003    /// Evaluates absolute value expressions as defined in the calc language.
1004    /// This function is based on add expressions.
1005    fn get_abs(&mut self) -> Result<Option<Ratio<BigInt>>, LangErr> {
1006        let Some(b) = self.utf8.get(self.i) else {
1007            return Ok(None);
1008        };
1009        if *b == b'|' {
1010            self.i += 1;
1011            self.consume_ws();
1012            let r = self.get_adds()?;
1013            self.consume_ws();
1014            let Some(b2) = self.utf8.get(self.i) else {
1015                return Err(InvalidAbs(self.i));
1016            };
1017            let b3 = *b2;
1018            if b3 == b'|' {
1019                self.i += 1;
1020                Ok(Some(if r.numer().sign() == Sign::Minus {
1021                    -r
1022                } else {
1023                    r
1024                }))
1025            } else {
1026                Err(InvalidAbs(self.i))
1027            }
1028        } else {
1029            Ok(None)
1030        }
1031    }
1032    /// Evaluates recall expressions as defined in the calc language.
1033    // This does not return a Result<Option<&Ratio<BigInt>>, LangErr>
1034    // since the only place this function is called is in get_term which
1035    // would end up needing to clone the Ratio anyway. By not forcing
1036    // get_term to clone, it can rely on map_or_else over match expressions.
1037    fn get_recall(&mut self) -> Result<Option<Ratio<BigInt>>, LangErr> {
1038        let Some(b) = self.utf8.get(self.i) else {
1039            return Ok(None);
1040        };
1041        if *b == b'@' {
1042            self.i += 1;
1043            self.cache
1044                .get(self.utf8.get(self.i).map_or(0, |b2| {
1045                    if (b'1'..b'9').contains(b2) {
1046                        self.i += 1;
1047                        usize::from(*b2 - b'1')
1048                    } else {
1049                        0
1050                    }
1051                }))
1052                .map_or_else(
1053                    || Err(NotEnoughPrevResults(self.cache.len())),
1054                    |p| Ok(Some(p.clone())),
1055                )
1056        } else {
1057            Ok(None)
1058        }
1059    }
1060    /// Evaluates parenthetical expressions as defined in the calc language.
1061    /// This function is based on add expressions.
1062    fn get_par(&mut self) -> Result<Option<Ratio<BigInt>>, LangErr> {
1063        let Some(b) = self.utf8.get(self.i) else {
1064            return Ok(None);
1065        };
1066        if *b == b'(' {
1067            self.i += 1;
1068            self.consume_ws();
1069            let r = self.get_adds()?;
1070            self.consume_ws();
1071            let Some(b2) = self.utf8.get(self.i) else {
1072                return Err(InvalidPar(self.i));
1073            };
1074            let b3 = *b2;
1075            if b3 == b')' {
1076                self.i += 1;
1077                Ok(Some(r))
1078            } else {
1079                Err(InvalidPar(self.i))
1080            }
1081        } else {
1082            Ok(None)
1083        }
1084    }
1085    /// Evaluates number literal expressions as defined in the calc language.
1086    #[expect(clippy::indexing_slicing, reason = "correct")]
1087    fn get_rational(&mut self) -> Result<Option<Ratio<BigInt>>, LangErr> {
1088        // ControlFlow makes more sense to use in try_fold; however due to a lack
1089        // of a map_or_else function, it is easier to simply return a Result with
1090        // Err taking the role of ControlFlow::Break.
1091        /// Used to parse a sequence of digits into an unsigned integer.
1092        fn to_biguint(v: &[u8]) -> (BigUint, usize) {
1093            v.iter()
1094                .try_fold((BigUint::new(Vec::new()), 0), |mut prev, d| {
1095                    if d.is_ascii_digit() {
1096                        prev.1 += 1;
1097                        // `*d - b'0'` is guaranteed to return a integer between 0 and 9.
1098                        prev.0 = prev.0 * 10u8 + (*d - b'0');
1099                        Ok(prev)
1100                    } else {
1101                        Err(prev)
1102                    }
1103                })
1104                .map_or_else(convert::identity, convert::identity)
1105        }
1106        let (int, len) = to_biguint(&self.utf8[self.i..]);
1107        if len == 0 {
1108            return Ok(None);
1109        }
1110        self.i += len;
1111        if let Some(b) = self.utf8.get(self.i) {
1112            if *b == b'.' {
1113                self.i += 1;
1114                let (numer, len2) = to_biguint(&self.utf8[self.i..]);
1115                if len2 == 0 {
1116                    Err(InvalidDec(self.i))
1117                } else {
1118                    self.i += len2;
1119                    Ok(Some(
1120                        Ratio::from_integer(BigInt::from_biguint(Sign::Plus, int))
1121                            + Ratio::new(
1122                                BigInt::from_biguint(Sign::Plus, numer),
1123                                BigInt::from_biguint(Sign::Plus, BigUint::new(vec![10]).pow(len2)),
1124                            ),
1125                    ))
1126                }
1127            } else {
1128                Ok(Some(Ratio::from_integer(BigInt::from_biguint(
1129                    Sign::Plus,
1130                    int,
1131                ))))
1132            }
1133        } else {
1134            Ok(Some(Ratio::from_integer(BigInt::from_biguint(
1135                Sign::Plus,
1136                int,
1137            ))))
1138        }
1139    }
1140}
1141/// Reads data from `R` passing each line to an [`Evaluator`] to be evaluated.
1142#[cfg(feature = "std")]
1143#[derive(Debug)]
1144pub struct EvalIter<R> {
1145    /// Reader that contains input data.
1146    reader: R,
1147    /// Buffer that is used by `reader` to read
1148    /// data into.
1149    input_buffer: Vec<u8>,
1150    /// Cache of stored results.
1151    cache: Cache<Ratio<BigInt>, 8>,
1152    /// Result of the previous expression.
1153    prev: Option<Ratio<BigInt>>,
1154    /// Buffer used by [`Evaluator`] to process
1155    /// sub-expressions.
1156    exp_buffer: Vec<Ratio<BigInt>>,
1157    /// Random number generator.
1158    #[cfg(feature = "rand")]
1159    rng: ThreadRng,
1160}
1161#[cfg(feature = "std")]
1162impl<R> EvalIter<R> {
1163    /// Creates a new `EvalIter`.
1164    #[cfg(feature = "rand")]
1165    #[inline]
1166    pub fn new(reader: R) -> Self {
1167        Self {
1168            reader,
1169            input_buffer: Vec::new(),
1170            cache: Cache::new(),
1171            prev: None,
1172            exp_buffer: Vec::new(),
1173            rng: rand::rng(),
1174        }
1175    }
1176    /// Creates a new `EvalIter`.
1177    #[cfg(any(doc, not(feature = "rand")))]
1178    #[inline]
1179    pub fn new(reader: R) -> Self {
1180        Self {
1181            reader,
1182            input_buffer: Vec::new(),
1183            cache: Cache::new(),
1184            prev: None,
1185            exp_buffer: Vec::new(),
1186        }
1187    }
1188}
1189#[cfg(feature = "std")]
1190extern crate std;
1191#[cfg(feature = "std")]
1192use std::io::{BufRead, Error};
1193/// Error returned from [`EvalIter`] when an expression has an error.
1194#[cfg(feature = "std")]
1195#[derive(Debug)]
1196pub enum E {
1197    /// Error containing [`Error`] which is returned
1198    /// from [`EvalIter`] when reading from the supplied
1199    /// [`BufRead`]er.
1200    Error(Error),
1201    /// Error containing [`LangErr`] which is returned
1202    /// from [`EvalIter`] when evaluating a single expression.
1203    LangErr(LangErr),
1204}
1205#[cfg(feature = "std")]
1206impl Display for E {
1207    #[inline]
1208    fn fmt(&self, f: &mut Formatter<'_>) -> fmt::Result {
1209        match *self {
1210            Self::Error(ref e) => e.fmt(f),
1211            Self::LangErr(ref e) => e.fmt(f),
1212        }
1213    }
1214}
1215#[cfg(feature = "std")]
1216use crate::lending_iterator::LendingIterator;
1217#[cfg(feature = "std")]
1218impl<R> LendingIterator for EvalIter<R>
1219where
1220    R: BufRead,
1221{
1222    type Item<'a>
1223        = Result<O<'a>, E>
1224    where
1225        Self: 'a;
1226    #[inline]
1227    fn lend_next(&mut self) -> Option<Result<O<'_>, E>> {
1228        self.input_buffer.clear();
1229        self.exp_buffer.clear();
1230        self.reader
1231            .read_until(b'\n', &mut self.input_buffer)
1232            .map_or_else(
1233                |e| Some(Err(E::Error(e))),
1234                |c| {
1235                    if c == 0 {
1236                        None
1237                    } else {
1238                        Evaluator::new(
1239                            self.input_buffer.as_slice(),
1240                            &mut self.cache,
1241                            &mut self.prev,
1242                            &mut self.exp_buffer,
1243                            #[cfg(feature = "rand")]
1244                            &mut self.rng,
1245                        )
1246                        .evaluate()
1247                        .map_or_else(
1248                            |e| Some(Err(E::LangErr(e))),
1249                            |o| match o {
1250                                Empty(_) | Eval(_) | Store(_) => Some(Ok(o)),
1251                                Exit => None,
1252                            },
1253                        )
1254                    }
1255                },
1256            )
1257    }
1258}
1259#[cfg(test)]
1260mod tests {
1261    use super::{
1262        BigInt, BigUint, Cache, Evaluator,
1263        LangErr::MissingTerm,
1264        O::{Empty, Eval, Store},
1265        Sign, Vec, vec,
1266    };
1267    #[cfg(feature = "rand")]
1268    use super::{BufRead, E, EvalIter, LangErr, LendingIterator as _};
1269    #[cfg(not(feature = "rand"))]
1270    use super::{
1271        LangErr::{
1272            DivByZero, ExpDivByZero, ExpIsNotIntOrOneHalf, InvalidAbs, InvalidDec, InvalidPar,
1273            InvalidQuit, InvalidRound, InvalidStore, ModIsNotInt, ModZero, NotEnoughPrevResults,
1274            NotNonNegIntFact, SqrtDoesNotExist, TrailingSyms,
1275        },
1276        O::Exit,
1277        Ratio,
1278    };
1279    #[cfg(not(feature = "rand"))]
1280    use alloc::{borrow::ToOwned as _, string::ToString as _};
1281    #[cfg(not(feature = "rand"))]
1282    use num_traits::Pow as _;
1283    #[cfg(feature = "rand")]
1284    use num_traits::ToPrimitive as _;
1285    #[cfg(feature = "rand")]
1286    use std::io::{self, Error, Read};
1287    #[expect(clippy::too_many_lines, reason = "a lot to test")]
1288    #[cfg(not(feature = "rand"))]
1289    #[test]
1290    fn empty() {
1291        // Empty expressions without a previous result return nothing.
1292        assert_eq!(
1293            Evaluator::new(b"\n", &mut Cache::new(), &mut None, &mut Vec::new()).evaluate(),
1294            Ok(Empty(&None))
1295        );
1296        assert_eq!(
1297            Evaluator::new(
1298                b"  \t  \t \n",
1299                &mut Cache::new(),
1300                &mut Some(Ratio::from_integer(BigInt::from_biguint(
1301                    Sign::Minus,
1302                    BigUint::new(vec![12])
1303                ))),
1304                &mut Vec::new()
1305            )
1306            .evaluate()
1307            .map(|a| a.to_string()),
1308            Ok("> -12".to_owned())
1309        );
1310        assert_eq!(
1311            Evaluator::new(
1312                b"\t\n",
1313                &mut Cache::new(),
1314                &mut Some(Ratio::new(
1315                    BigInt::from_biguint(Sign::Minus, BigUint::new(vec![4])),
1316                    BigInt::from_biguint(Sign::Plus, BigUint::new(vec![6]))
1317                )),
1318                &mut Vec::new()
1319            )
1320            .evaluate()
1321            .map(|a| a.to_string()),
1322            Ok("> -0.666666667".to_owned())
1323        );
1324        assert_eq!(
1325            Evaluator::new(
1326                b"\t\n",
1327                &mut Cache::new(),
1328                &mut Some(Ratio::new(
1329                    BigInt::from_biguint(Sign::Plus, BigUint::new(vec![1])),
1330                    BigInt::from_biguint(Sign::Plus, BigUint::new(vec![4_230_196_224, 6]))
1331                )),
1332                &mut Vec::new()
1333            )
1334            .evaluate()
1335            .map(|a| a.to_string()),
1336            Ok("> 0.000000000".to_owned())
1337        );
1338        assert_eq!(
1339            Evaluator::new(
1340                b"\t\n",
1341                &mut Cache::new(),
1342                &mut Some(Ratio::new(
1343                    BigInt::from_biguint(Sign::Plus, BigUint::new(vec![17])),
1344                    BigInt::from_biguint(Sign::Plus, BigUint::new(vec![4_230_196_224, 6]))
1345                )),
1346                &mut Vec::new()
1347            )
1348            .evaluate()
1349            .map(|a| a.to_string()),
1350            Ok("> 0.000000001".to_owned())
1351        );
1352        assert_eq!(
1353            Evaluator::new(
1354                b"\t\n",
1355                &mut Cache::new(),
1356                &mut Some(Ratio::new(
1357                    BigInt::from_biguint(Sign::Plus, BigUint::new(vec![3])),
1358                    BigInt::from_biguint(Sign::Plus, BigUint::new(vec![10]))
1359                )),
1360                &mut Vec::new()
1361            )
1362            .evaluate()
1363            .map(|a| a.to_string()),
1364            Ok("> 0.3".to_owned())
1365        );
1366        assert_eq!(
1367            Evaluator::new(
1368                b"\t\n",
1369                &mut Cache::new(),
1370                &mut Some(Ratio::new(
1371                    BigInt::from_biguint(Sign::Minus, BigUint::new(vec![203])),
1372                    BigInt::from_biguint(Sign::Plus, BigUint::new(vec![10]))
1373                )),
1374                &mut Vec::new()
1375            )
1376            .evaluate()
1377            .map(|a| a.to_string()),
1378            Ok("> -20.3".to_owned())
1379        );
1380        assert_eq!(
1381            Evaluator::new(
1382                &[0u8; 0],
1383                &mut Cache::new(),
1384                &mut Some(Ratio::new(
1385                    BigInt::from_biguint(Sign::Minus, BigUint::new(vec![203])),
1386                    BigInt::from_biguint(Sign::Plus, BigUint::new(vec![10]))
1387                )),
1388                &mut Vec::new()
1389            )
1390            .evaluate()
1391            .map(|a| a.to_string()),
1392            Ok("> -20.3".to_owned())
1393        );
1394    }
1395    #[expect(clippy::unreachable, reason = "want to crash when there is a bug")]
1396    #[cfg(not(feature = "rand"))]
1397    #[test]
1398    fn number_literal() {
1399        // Normal 0 is fine.
1400        assert_eq!(
1401            Evaluator::new(b"0", &mut Cache::new(), &mut None, &mut Vec::new()).get_rational(),
1402            Ok(Some(Ratio::from_integer(BigInt::from_biguint(
1403                Sign::NoSign,
1404                BigUint::new(Vec::new())
1405            ))))
1406        );
1407        // Leading 0s and trailing 0s are fine.
1408        assert_eq!(
1409            Evaluator::new(b"0000.00000", &mut Cache::new(), &mut None, &mut Vec::new())
1410                .get_rational(),
1411            Ok(Some(Ratio::from_integer(BigInt::from_biguint(
1412                Sign::NoSign,
1413                BigUint::new(Vec::new())
1414            ))))
1415        );
1416        // Parsing stops at first non-(digit/period).
1417        assert_eq!(
1418            Evaluator::new(b"1 0", &mut Cache::new(), &mut None, &mut Vec::new()).get_rational(),
1419            Ok(Some(Ratio::from_integer(BigInt::from_biguint(
1420                Sign::Plus,
1421                BigUint::new(vec![1])
1422            ))))
1423        );
1424        let int = b"3397450981271938475135134759823759835414";
1425        let frac = b"913759810573549872354897210539127530981570";
1426        let left = Ratio::from_integer(
1427            BigInt::parse_bytes(int, 10)
1428                .unwrap_or_else(|| unreachable!("bug in BigInt::parse_bytes")),
1429        );
1430        let right = Ratio::new(
1431            BigInt::parse_bytes(frac, 10)
1432                .unwrap_or_else(|| unreachable!("bug in BigInt::parse_bytes")),
1433            BigInt::from_biguint(Sign::Plus, BigUint::new(vec![10]).pow(frac.len() + 1)),
1434        );
1435        let mut vec = Vec::new();
1436        vec.extend_from_slice(int);
1437        vec.push(b'.');
1438        vec.push(b'0');
1439        vec.extend_from_slice(frac);
1440        // Test a number whose integer and fraction portions are larger than u128::MAX.
1441        assert_eq!(
1442            Evaluator::new(
1443                vec.as_slice(),
1444                &mut Cache::new(),
1445                &mut None,
1446                &mut Vec::new()
1447            )
1448            .get_rational(),
1449            Ok(Some(left + right))
1450        );
1451        // Leading 0s and trailing 0s for a non-zero value are fine.
1452        assert_eq!(
1453            Evaluator::new(
1454                b"000000014.0000000000000",
1455                &mut Cache::new(),
1456                &mut None,
1457                &mut Vec::new()
1458            )
1459            .get_rational(),
1460            Ok(Some(Ratio::from_integer(BigInt::from_biguint(
1461                Sign::Plus,
1462                BigUint::new(vec![14])
1463            ))))
1464        );
1465        // A sequence of digits followed immediately by a decimal point but no digits after is invalid.
1466        assert_eq!(
1467            Evaluator::new(b"1.", &mut Cache::new(), &mut None, &mut Vec::new()).get_rational(),
1468            Err(InvalidDec(2))
1469        );
1470        // A sequence of digits followed immediately by a decimal point but no digits after is invalid.
1471        // This just shows that spaces are not ignored in number literals.
1472        assert_eq!(
1473            Evaluator::new(b"1. 2", &mut Cache::new(), &mut None, &mut Vec::new()).get_rational(),
1474            Err(InvalidDec(2))
1475        );
1476        // Non-whitespace starting the input is valid but produces no value.
1477        // This also shows that an invalid byte sequence does not produce an error here.
1478        assert_eq!(
1479            Evaluator::new(b"a1", &mut Cache::new(), &mut None, &mut Vec::new()).get_rational(),
1480            Ok(None)
1481        );
1482        // A space starting the input is valid but produces no value.
1483        assert_eq!(
1484            Evaluator::new(b" 1", &mut Cache::new(), &mut None, &mut Vec::new()).get_rational(),
1485            Ok(None)
1486        );
1487        // A tab starting the input is valid but produces no value.
1488        assert_eq!(
1489            Evaluator::new(b"\t1", &mut Cache::new(), &mut None, &mut Vec::new()).get_rational(),
1490            Ok(None)
1491        );
1492        // Negative literals don't exist, so this should succeed but produce nothing.
1493        assert_eq!(
1494            Evaluator::new(b"-1", &mut Cache::new(), &mut None, &mut Vec::new()).get_rational(),
1495            Ok(None)
1496        );
1497        // '/' is division and not part of a number literal so only the "numerator" is parsed.
1498        assert_eq!(
1499            Evaluator::new(b"1/2", &mut Cache::new(), &mut None, &mut Vec::new()).get_rational(),
1500            Ok(Some(Ratio::from_integer(BigInt::from_biguint(
1501                Sign::Plus,
1502                BigUint::new(vec![1])
1503            ))))
1504        );
1505        // A sequence of digits followed by invalid bytes is valid and produces a number equal to the digits before the invalid bytes.
1506        assert_eq!(
1507            Evaluator::new(b"130alj", &mut Cache::new(), &mut None, &mut Vec::new()).get_rational(),
1508            Ok(Some(Ratio::from_integer(BigInt::from_biguint(
1509                Sign::Plus,
1510                BigUint::new(vec![130])
1511            ))))
1512        );
1513    }
1514    #[cfg(not(feature = "rand"))]
1515    #[test]
1516    fn par() {
1517        // Missing closing ')'
1518        assert_eq!(
1519            Evaluator::new(b"(1", &mut Cache::new(), &mut None, &mut Vec::new()).get_par(),
1520            Err(InvalidPar(2))
1521        );
1522        assert_eq!(
1523            Evaluator::new(b"((1\t + 2)", &mut Cache::new(), &mut None, &mut Vec::new()).get_par(),
1524            Err(InvalidPar(9))
1525        );
1526        assert_eq!(
1527            Evaluator::new(b"(  0 \t )", &mut Cache::new(), &mut None, &mut Vec::new()).get_par(),
1528            Ok(Some(Ratio::from_integer(BigInt::from_biguint(
1529                Sign::NoSign,
1530                BigUint::new(Vec::new())
1531            ))))
1532        );
1533        assert_eq!(
1534            Evaluator::new(b"( - \t 5 )", &mut Cache::new(), &mut None, &mut Vec::new()).get_par(),
1535            Ok(Some(Ratio::from_integer(BigInt::from_biguint(
1536                Sign::Minus,
1537                BigUint::new(vec![5])
1538            ))))
1539        );
1540        assert_eq!(
1541            Evaluator::new(
1542                b"( ( 2 -\t  5) * 9 )",
1543                &mut Cache::new(),
1544                &mut None,
1545                &mut Vec::new()
1546            )
1547            .get_par(),
1548            Ok(Some(Ratio::from_integer(BigInt::from_biguint(
1549                Sign::Minus,
1550                BigUint::new(vec![27])
1551            ))))
1552        );
1553    }
1554    #[expect(clippy::too_many_lines, reason = "a lot to test")]
1555    #[expect(
1556        clippy::indexing_slicing,
1557        clippy::unwrap_used,
1558        reason = "comments justify correctness"
1559    )]
1560    #[cfg(not(feature = "rand"))]
1561    #[test]
1562    fn recall_expression() {
1563        // If the input does not start with '@', then it's valid but produces nothing.
1564        assert_eq!(
1565            Evaluator::new(b"1", &mut Cache::new(), &mut None, &mut Vec::new()).get_recall(),
1566            Ok(None)
1567        );
1568        assert_eq!(
1569            Evaluator::new(b"a", &mut Cache::new(), &mut None, &mut Vec::new()).get_recall(),
1570            Ok(None)
1571        );
1572        assert_eq!(
1573            Evaluator::new(b" @", &mut Cache::new(), &mut None, &mut Vec::new()).get_recall(),
1574            Ok(None)
1575        );
1576        assert_eq!(
1577            Evaluator::new(b"\t@", &mut Cache::new(), &mut None, &mut Vec::new()).get_recall(),
1578            Ok(None)
1579        );
1580        // Invalid recall expression since there are no previous results.
1581        assert_eq!(
1582            Evaluator::new(b"@", &mut Cache::new(), &mut None, &mut Vec::new()).get_recall(),
1583            Err(NotEnoughPrevResults(0))
1584        );
1585        // Invalid recall expression since there are no previous results.
1586        assert_eq!(
1587            Evaluator::new(b"@4", &mut Cache::new(), &mut None, &mut Vec::new()).get_recall(),
1588            Err(NotEnoughPrevResults(0))
1589        );
1590        // Invalid recall expression since there are no previous results.
1591        // The input violates our grammar, but this error happens before that.
1592        assert_eq!(
1593            Evaluator::new(b"@0", &mut Cache::new(), &mut None, &mut Vec::new()).get_recall(),
1594            Err(NotEnoughPrevResults(0))
1595        );
1596        // Successfully extract previous expression.
1597        let mut prev = None;
1598        let mut cache = Cache::new();
1599        // Quick check that `Ok` is returned.
1600        _ = Evaluator::new(b"1\n", &mut cache, &mut prev, &mut Vec::new())
1601            .evaluate()
1602            .unwrap();
1603        // Quick check that `Ok` is returned.
1604        _ = Evaluator::new(b"   s   \r\n", &mut cache, &mut prev, &mut Vec::new())
1605            .evaluate()
1606            .unwrap();
1607        assert_eq!(
1608            Evaluator::new(b"@", &mut cache, &mut prev, &mut Vec::new()).get_recall(),
1609            Ok(Some(Ratio::from_integer(BigInt::from_biguint(
1610                Sign::Plus,
1611                BigUint::new(vec![1])
1612            ))))
1613        );
1614        // Invalid characters are ignored at this stage.
1615        assert_eq!(
1616            Evaluator::new(b"@&", &mut cache, &mut prev, &mut Vec::new()).get_recall(),
1617            Ok(Some(Ratio::from_integer(BigInt::from_biguint(
1618                Sign::Plus,
1619                BigUint::new(vec![1])
1620            ))))
1621        );
1622        // 0 is not a valid stored value only 1-8 are.
1623        assert_eq!(
1624            Evaluator::new(b"@0", &mut cache, &mut prev, &mut Vec::new()).get_recall(),
1625            Ok(Some(Ratio::from_integer(BigInt::from_biguint(
1626                Sign::Plus,
1627                BigUint::new(vec![1])
1628            ))))
1629        );
1630        // 9 is not a valid stored value only 1-8 are.
1631        assert_eq!(
1632            Evaluator::new(b"@9", &mut cache, &mut prev, &mut Vec::new()).get_recall(),
1633            Ok(Some(Ratio::from_integer(BigInt::from_biguint(
1634                Sign::Plus,
1635                BigUint::new(vec![1])
1636            ))))
1637        );
1638        // Spaces are not cleaned; otherwise this would error since we only have 1 stored value.
1639        assert_eq!(
1640            Evaluator::new(b"@ 2", &mut cache, &mut prev, &mut Vec::new()).get_recall(),
1641            Ok(Some(Ratio::from_integer(BigInt::from_biguint(
1642                Sign::Plus,
1643                BigUint::new(vec![1])
1644            ))))
1645        );
1646        // Tabs are not cleaned; otherwise this would error since we only have 1 stored value.
1647        assert_eq!(
1648            Evaluator::new(b"@\t2", &mut cache, &mut prev, &mut Vec::new()).get_recall(),
1649            Ok(Some(Ratio::from_integer(BigInt::from_biguint(
1650                Sign::Plus,
1651                BigUint::new(vec![1])
1652            ))))
1653        );
1654        // One digits are looked at so this is not @<ten>.
1655        assert_eq!(
1656            Evaluator::new(b"@10", &mut cache, &mut prev, &mut Vec::new()).get_recall(),
1657            Ok(Some(Ratio::from_integer(BigInt::from_biguint(
1658                Sign::Plus,
1659                BigUint::new(vec![1])
1660            ))))
1661        );
1662        // Invalid recall expression since there is only one stored result.
1663        assert_eq!(
1664            Evaluator::new(b"@2", &mut cache, &mut prev, &mut Vec::new()).get_recall(),
1665            Err(NotEnoughPrevResults(1))
1666        );
1667        // Quick check that `Ok` is returned.
1668        _ = Evaluator::new(b"2\r\n", &mut cache, &mut prev, &mut Vec::new())
1669            .evaluate()
1670            .unwrap();
1671        // Quick check that `Ok` is returned.
1672        _ = Evaluator::new(b"s\n", &mut cache, &mut prev, &mut Vec::new())
1673            .evaluate()
1674            .unwrap();
1675        // Stored values correct.
1676        assert_eq!(
1677            Evaluator::new(b"@", &mut cache, &mut prev, &mut Vec::new()).get_recall(),
1678            Ok(Some(Ratio::from_integer(BigInt::from_biguint(
1679                Sign::Plus,
1680                BigUint::new(vec![2])
1681            ))))
1682        );
1683        assert_eq!(
1684            Evaluator::new(b"@2", &mut cache, &mut prev, &mut Vec::new()).get_recall(),
1685            Ok(Some(Ratio::from_integer(BigInt::from_biguint(
1686                Sign::Plus,
1687                BigUint::new(vec![1])
1688            ))))
1689        );
1690        // Invalid recall expression since there are only three stored results.
1691        assert_eq!(
1692            Evaluator::new(b"@3", &mut cache, &mut prev, &mut Vec::new()).get_recall(),
1693            Err(NotEnoughPrevResults(2))
1694        );
1695        let mut v = vec![0, b'\n'];
1696        for i in b'3'..=b'8' {
1697            // `v.len() > 0`.
1698            v[0] = i;
1699            _ = Evaluator::new(v.as_slice(), &mut cache, &mut prev, &mut Vec::new())
1700                .evaluate()
1701                .unwrap();
1702            _ = Evaluator::new(b"s\n", &mut cache, &mut prev, &mut Vec::new())
1703                .evaluate()
1704                .unwrap();
1705        }
1706        v[0] = b'@';
1707        for i in b'1'..=b'8' {
1708            // `v.len() > 1`.
1709            v[1] = i;
1710            // Cache is filled up correctly storing all previous values.
1711            assert_eq!(
1712                Evaluator::new(v.as_slice(), &mut cache, &mut prev, &mut Vec::new()).get_recall(),
1713                Ok(Some(Ratio::from_integer(BigInt::from_biguint(
1714                    Sign::Plus,
1715                    BigUint::new(vec![u32::from(b'9' - i)])
1716                ))))
1717            );
1718        }
1719        // Only parses the first @ since the second @ is not a digit between 1 and 8.
1720        assert_eq!(
1721            Evaluator::new(b"@@", &mut cache, &mut prev, &mut Vec::new()).get_recall(),
1722            Ok(Some(Ratio::from_integer(BigInt::from_biguint(
1723                Sign::Plus,
1724                BigUint::new(vec![8])
1725            ))))
1726        );
1727        // Quick check that `Ok` is returned.
1728        _ = Evaluator::new(b"9\r\n", &mut cache, &mut prev, &mut Vec::new())
1729            .evaluate()
1730            .unwrap();
1731        // Quick check that `Ok` is returned.
1732        _ = Evaluator::new(b"s\n", &mut cache, &mut prev, &mut Vec::new())
1733            .evaluate()
1734            .unwrap();
1735        // Oldest value is overwritten; all others remain.
1736        for i in b'1'..=b'8' {
1737            // `v.len() > 1`.
1738            v[1] = i;
1739            assert_eq!(
1740                Evaluator::new(v.as_slice(), &mut cache, &mut prev, &mut Vec::new()).get_recall(),
1741                Ok(Some(Ratio::from_integer(BigInt::from_biguint(
1742                    Sign::Plus,
1743                    BigUint::new(vec![u32::from((b'9' + 1) - i)])
1744                ))))
1745            );
1746        }
1747    }
1748    #[cfg(not(feature = "rand"))]
1749    #[test]
1750    fn abs() {
1751        // Missing closing '|'
1752        assert_eq!(
1753            Evaluator::new(b"|1", &mut Cache::new(), &mut None, &mut Vec::new()).get_abs(),
1754            Err(InvalidAbs(2))
1755        );
1756        assert_eq!(
1757            Evaluator::new(b"||1 + 2|", &mut Cache::new(), &mut None, &mut Vec::new()).get_abs(),
1758            Err(InvalidAbs(8))
1759        );
1760        assert_eq!(
1761            Evaluator::new(
1762                b"|  0\t \t |",
1763                &mut Cache::new(),
1764                &mut None,
1765                &mut Vec::new()
1766            )
1767            .get_abs(),
1768            Ok(Some(Ratio::from_integer(BigInt::from_biguint(
1769                Sign::NoSign,
1770                BigUint::new(Vec::new())
1771            ))))
1772        );
1773        assert_eq!(
1774            Evaluator::new(b"| -  5 |", &mut Cache::new(), &mut None, &mut Vec::new()).get_abs(),
1775            Ok(Some(Ratio::from_integer(BigInt::from_biguint(
1776                Sign::Plus,
1777                BigUint::new(vec![5])
1778            ))))
1779        );
1780        assert_eq!(
1781            Evaluator::new(
1782                b"| \t| 2 -  5| * 9 |",
1783                &mut Cache::new(),
1784                &mut None,
1785                &mut Vec::new()
1786            )
1787            .get_abs(),
1788            Ok(Some(Ratio::from_integer(BigInt::from_biguint(
1789                Sign::Plus,
1790                BigUint::new(vec![27])
1791            ))))
1792        );
1793        // If the input does not start with '|', then it's valid but produces nothing.
1794        assert_eq!(
1795            Evaluator::new(b" \t|9|", &mut Cache::new(), &mut None, &mut Vec::new()).get_abs(),
1796            Ok(None)
1797        );
1798    }
1799    #[cfg(not(feature = "rand"))]
1800    #[test]
1801    fn round() {
1802        // Missing ',<digit>)'
1803        assert_eq!(
1804            Evaluator::new(b"round(1", &mut Cache::new(), &mut None, &mut Vec::new()).get_round(),
1805            Err(InvalidRound(7))
1806        );
1807        assert_eq!(
1808            Evaluator::new(b"round(1,", &mut Cache::new(), &mut None, &mut Vec::new()).get_round(),
1809            Err(InvalidRound(8))
1810        );
1811        assert_eq!(
1812            Evaluator::new(b"round(1,2", &mut Cache::new(), &mut None, &mut Vec::new()).get_round(),
1813            Err(InvalidRound(9))
1814        );
1815        assert_eq!(
1816            Evaluator::new(
1817                b"round(1,10)",
1818                &mut Cache::new(),
1819                &mut None,
1820                &mut Vec::new()
1821            )
1822            .get_round(),
1823            Err(InvalidRound(9))
1824        );
1825        assert_eq!(
1826            Evaluator::new(b"round(1,a)", &mut Cache::new(), &mut None, &mut Vec::new())
1827                .get_round(),
1828            Err(InvalidRound(8))
1829        );
1830        assert_eq!(
1831            Evaluator::new(
1832                b"round(2, 7)",
1833                &mut Cache::new(),
1834                &mut None,
1835                &mut Vec::new()
1836            )
1837            .get_round(),
1838            Ok(Some(Ratio::from_integer(BigInt::from_biguint(
1839                Sign::Plus,
1840                BigUint::new(vec![2])
1841            ))))
1842        );
1843        assert_eq!(
1844            Evaluator::new(
1845                b"round(2.677, 1)",
1846                &mut Cache::new(),
1847                &mut None,
1848                &mut Vec::new()
1849            )
1850            .get_round(),
1851            Ok(Some(Ratio::new(
1852                BigInt::from_biguint(Sign::Plus, BigUint::new(vec![27])),
1853                BigInt::from_biguint(Sign::Plus, BigUint::new(vec![10]))
1854            )))
1855        );
1856    }
1857    #[expect(clippy::too_many_lines, reason = "a lot to test")]
1858    #[cfg(feature = "rand")]
1859    #[test]
1860    fn rand() {
1861        assert_eq!(
1862            Evaluator::new(
1863                b"rand(1",
1864                &mut Cache::new(),
1865                &mut None,
1866                &mut Vec::new(),
1867                &mut rand::rng()
1868            )
1869            .get_rand(),
1870            Err(LangErr::InvalidRand(6))
1871        );
1872        assert_eq!(
1873            Evaluator::new(
1874                b"rand(1,2",
1875                &mut Cache::new(),
1876                &mut None,
1877                &mut Vec::new(),
1878                &mut rand::rng()
1879            )
1880            .get_rand(),
1881            Err(LangErr::InvalidRand(8))
1882        );
1883        assert_eq!(
1884            Evaluator::new(
1885                b"rand(1/2,3/4)",
1886                &mut Cache::new(),
1887                &mut None,
1888                &mut Vec::new(),
1889                &mut rand::rng(),
1890            )
1891            .get_rand(),
1892            Err(LangErr::RandNoInts(13))
1893        );
1894        assert_eq!(
1895            Evaluator::new(
1896                b"rand(-100000000000000000000000,-1000000000000000000000)",
1897                &mut Cache::new(),
1898                &mut None,
1899                &mut Vec::new(),
1900                &mut rand::rng(),
1901            )
1902            .get_rand(),
1903            Err(LangErr::RandNoInts(55))
1904        );
1905        assert_eq!(
1906            Evaluator::new(
1907                b"rand(2/3,1/3)",
1908                &mut Cache::new(),
1909                &mut None,
1910                &mut Vec::new(),
1911                &mut rand::rng(),
1912            )
1913            .get_rand(),
1914            Err(LangErr::RandInvalidArgs(13))
1915        );
1916        // If the input does not start with 'rand(', then it's invalid since get_rand must only be called as the last terminal expression which means whitespace must be consumed already.
1917        assert_eq!(
1918            Evaluator::new(
1919                b" rand(2/3,2)",
1920                &mut Cache::new(),
1921                &mut None,
1922                &mut Vec::new(),
1923                &mut rand::rng(),
1924            )
1925            .get_rand(),
1926            Err(MissingTerm(0))
1927        );
1928        assert!(
1929            Evaluator::new(
1930                b"rand(2, 7)",
1931                &mut Cache::new(),
1932                &mut None,
1933                &mut Vec::new(),
1934                &mut rand::rng()
1935            )
1936            .get_rand()
1937            .is_ok_and(|r| {
1938                let int = r.numer();
1939                int >= &BigInt::from_biguint(Sign::Plus, BigUint::new(vec![2]))
1940                    && *int <= BigInt::from_biguint(Sign::Plus, BigUint::new(vec![7]))
1941            })
1942        );
1943        assert!(
1944            Evaluator::new(
1945                b"rand()",
1946                &mut Cache::new(),
1947                &mut None,
1948                &mut Vec::new(),
1949                &mut rand::rng()
1950            )
1951            .get_rand()
1952            .is_ok_and(|r| {
1953                let int = r.numer();
1954                int >= &BigInt::from(i64::MIN) && *int <= BigInt::from(i64::MAX)
1955            })
1956        );
1957        for _ in 0..100u8 {
1958            assert!(
1959                Evaluator::new(
1960                    b"rand(2, 2)",
1961                    &mut Cache::new(),
1962                    &mut None,
1963                    &mut Vec::new(),
1964                    &mut rand::rng()
1965                )
1966                .get_rand()
1967                .is_ok_and(
1968                    |r| *r.numer() == BigInt::from_biguint(Sign::Plus, BigUint::new(vec![2]))
1969                )
1970            );
1971        }
1972    }
1973    #[expect(
1974        clippy::indexing_slicing,
1975        clippy::unwrap_used,
1976        reason = "comment justifies correctness"
1977    )]
1978    #[cfg(feature = "rand")]
1979    #[test]
1980    #[ignore = "slow"]
1981    fn rand_uni() {
1982        const COUNT: u32 = 999_999;
1983        #[expect(
1984            clippy::integer_division,
1985            clippy::integer_division_remainder_used,
1986            reason = "correct"
1987        )]
1988        const LOWER: u32 = COUNT * 33 / 100;
1989        #[expect(
1990            clippy::integer_division,
1991            clippy::integer_division_remainder_used,
1992            reason = "correct"
1993        )]
1994        const UPPER: u32 = COUNT * 101 / 300;
1995        // Test rand on an interval that is not a power of 2 in size.
1996        // This causes rand to adjust the interval to enforce uniformity.
1997        let mut vals = [0u32; 3];
1998        let mut vec = Vec::new();
1999        let mut cache = Cache::new();
2000        let mut none = None;
2001        for _ in 1..COUNT {
2002            // We want to `panic` if `rand` does not work correctly.
2003            vals[usize::try_from(
2004                Evaluator::new(
2005                    b"rand(-1, 1)",
2006                    &mut cache,
2007                    &mut none,
2008                    &mut vec,
2009                    &mut rand::rng(),
2010                )
2011                .get_rand()
2012                .unwrap()
2013                .numer()
2014                .to_i32()
2015                .unwrap()
2016                    + 1i32,
2017            )
2018            .unwrap()] += 1;
2019        }
2020        // Test that the distribution is within 1% of what is expected.
2021        assert_eq!(
2022            vals.into_iter().try_fold(false, |_, r| {
2023                if (LOWER..=UPPER).contains(&r) {
2024                    Ok(true)
2025                } else {
2026                    Err(false)
2027                }
2028            }),
2029            Ok(true)
2030        );
2031    }
2032    #[allow(
2033        clippy::allow_attributes,
2034        reason = "unwrap_used only fires when rand is not enabled"
2035    )]
2036    #[allow(clippy::unwrap_used, reason = "comments justify correctness")]
2037    #[test]
2038    fn term() {
2039        #[cfg(not(feature = "rand"))]
2040        assert_eq!(
2041            Evaluator::new(b"0000.00000", &mut Cache::new(), &mut None, &mut Vec::new()).get_term(),
2042            Ok(Ratio::from_integer(BigInt::from_biguint(
2043                Sign::NoSign,
2044                BigUint::new(Vec::new())
2045            )))
2046        );
2047        #[cfg(not(feature = "rand"))]
2048        assert_eq!(
2049            Evaluator::new(b"(4)", &mut Cache::new(), &mut None, &mut Vec::new()).get_term(),
2050            Ok(Ratio::from_integer(BigInt::from_biguint(
2051                Sign::Plus,
2052                BigUint::new(vec![4])
2053            )))
2054        );
2055        #[cfg(not(feature = "rand"))]
2056        assert_eq!(
2057            Evaluator::new(
2058                b"round(-2/3,2)",
2059                &mut Cache::new(),
2060                &mut None,
2061                &mut Vec::new()
2062            )
2063            .get_term(),
2064            Ok(Ratio::new(
2065                BigInt::from_biguint(Sign::Minus, BigUint::new(vec![67])),
2066                BigInt::from_biguint(Sign::Plus, BigUint::new(vec![100]))
2067            ))
2068        );
2069        #[cfg(feature = "rand")]
2070        drop(
2071            Evaluator::new(
2072                b"rand()",
2073                &mut Cache::new(),
2074                &mut None,
2075                &mut Vec::new(),
2076                &mut rand::rng(),
2077            )
2078            .get_term()
2079            .unwrap(),
2080        );
2081        #[cfg(feature = "rand")]
2082        drop(
2083            Evaluator::new(
2084                b"rand(-13/93, 833)",
2085                &mut Cache::new(),
2086                &mut None,
2087                &mut Vec::new(),
2088                &mut rand::rng(),
2089            )
2090            .get_term()
2091            .unwrap(),
2092        );
2093        #[cfg(not(feature = "rand"))]
2094        assert_eq!(
2095            Evaluator::new(b"rand()", &mut Cache::new(), &mut None, &mut Vec::new()).get_term(),
2096            Err(MissingTerm(0))
2097        );
2098        #[cfg(not(feature = "rand"))]
2099        assert_eq!(
2100            Evaluator::new(b"|4|", &mut Cache::new(), &mut None, &mut Vec::new()).get_term(),
2101            Ok(Ratio::from_integer(BigInt::from_biguint(
2102                Sign::Plus,
2103                BigUint::new(vec![4])
2104            )))
2105        );
2106        // Terminal expressions do no clean up before or after.
2107        #[cfg(not(feature = "rand"))]
2108        assert_eq!(
2109            Evaluator::new(b" 2", &mut Cache::new(), &mut None, &mut Vec::new()).get_term(),
2110            Err(MissingTerm(0))
2111        );
2112        #[cfg(not(feature = "rand"))]
2113        let mut prev = None;
2114        #[cfg(not(feature = "rand"))]
2115        let mut cache = Cache::new();
2116        #[cfg(not(feature = "rand"))]
2117        {
2118            // Quick check that `Ok` is returned.
2119            _ = Evaluator::new(b"1\n", &mut cache, &mut prev, &mut Vec::new())
2120                .evaluate()
2121                .unwrap();
2122            // Quick check that `Ok` is returned.
2123            _ = Evaluator::new(b"s\n", &mut cache, &mut prev, &mut Vec::new())
2124                .evaluate()
2125                .unwrap();
2126        }
2127        #[cfg(not(feature = "rand"))]
2128        assert_eq!(
2129            Evaluator::new(b"@", &mut cache, &mut prev, &mut Vec::new()).get_term(),
2130            Ok(Ratio::from_integer(BigInt::from_biguint(
2131                Sign::Plus,
2132                BigUint::new(vec![1])
2133            )))
2134        );
2135    }
2136    #[expect(clippy::unwrap_used, reason = "comments justify correctness")]
2137    #[cfg(not(feature = "rand"))]
2138    #[test]
2139    fn factorial() {
2140        // Negative integer is not allowed.
2141        assert_eq!(
2142            Evaluator::new(b"(-1)!", &mut Cache::new(), &mut None, &mut Vec::new()).get_fact(),
2143            Err(NotNonNegIntFact(5))
2144        );
2145        // Non-integer is not allowed.
2146        assert_eq!(
2147            Evaluator::new(b"2.5!", &mut Cache::new(), &mut None, &mut Vec::new()).get_fact(),
2148            Err(NotNonNegIntFact(4))
2149        );
2150        // factorials always become terminal expressions eventually.
2151        assert_eq!(
2152            Evaluator::new(b"7", &mut Cache::new(), &mut None, &mut Vec::new()).get_fact(),
2153            Ok(Ratio::from_integer(BigInt::from_biguint(
2154                Sign::Plus,
2155                BigUint::new(vec![7])
2156            )))
2157        );
2158        assert_eq!(
2159            Evaluator::new(b"(7)", &mut Cache::new(), &mut None, &mut Vec::new()).get_fact(),
2160            Ok(Ratio::from_integer(BigInt::from_biguint(
2161                Sign::Plus,
2162                BigUint::new(vec![7])
2163            )))
2164        );
2165        assert_eq!(
2166            Evaluator::new(b"|7|", &mut Cache::new(), &mut None, &mut Vec::new()).get_fact(),
2167            Ok(Ratio::from_integer(BigInt::from_biguint(
2168                Sign::Plus,
2169                BigUint::new(vec![7])
2170            )))
2171        );
2172        let mut prev = None;
2173        let mut cache = Cache::new();
2174        // Quick check that `Ok` is returned.
2175        _ = Evaluator::new(b"3\n", &mut cache, &mut prev, &mut Vec::new())
2176            .evaluate()
2177            .unwrap();
2178        // Quick check that `Ok` is returned.
2179        _ = Evaluator::new(b"s\n", &mut cache, &mut prev, &mut Vec::new())
2180            .evaluate()
2181            .unwrap();
2182        assert_eq!(
2183            Evaluator::new(b"@!", &mut cache, &mut prev, &mut Vec::new()).get_fact(),
2184            Ok(Ratio::from_integer(BigInt::from_biguint(
2185                Sign::Plus,
2186                BigUint::new(vec![6])
2187            )))
2188        );
2189        assert_eq!(
2190            Evaluator::new(b"@", &mut cache, &mut prev, &mut Vec::new()).get_fact(),
2191            Ok(Ratio::from_integer(BigInt::from_biguint(
2192                Sign::Plus,
2193                BigUint::new(vec![3])
2194            )))
2195        );
2196        // 0! = 1.
2197        assert_eq!(
2198            Evaluator::new(b"0.0!", &mut Cache::new(), &mut None, &mut Vec::new()).get_fact(),
2199            Ok(Ratio::from_integer(BigInt::from_biguint(
2200                Sign::Plus,
2201                BigUint::new(vec![1])
2202            )))
2203        );
2204        // 1! = 1.
2205        assert_eq!(
2206            Evaluator::new(b"1!", &mut Cache::new(), &mut None, &mut Vec::new()).get_fact(),
2207            Ok(Ratio::from_integer(BigInt::from_biguint(
2208                Sign::Plus,
2209                BigUint::new(vec![1])
2210            )))
2211        );
2212        // 4! = 24, and whitespace is not consumed.
2213        assert_eq!(
2214            Evaluator::new(b"4! \t", &mut Cache::new(), &mut None, &mut Vec::new()).get_fact(),
2215            Ok(Ratio::from_integer(BigInt::from_biguint(
2216                Sign::Plus,
2217                BigUint::new(vec![24])
2218            )))
2219        );
2220        // Factorials can be chained.
2221        assert_eq!(
2222            Evaluator::new(b"3!! ", &mut Cache::new(), &mut None, &mut Vec::new()).get_fact(),
2223            Ok(Ratio::from_integer(BigInt::from_biguint(
2224                Sign::Plus,
2225                BigUint::new(vec![720])
2226            )))
2227        );
2228        // only factorial is consumed.
2229        assert_eq!(
2230            Evaluator::new(b"2!+3", &mut Cache::new(), &mut None, &mut Vec::new()).get_fact(),
2231            Ok(Ratio::from_integer(BigInt::from_biguint(
2232                Sign::Plus,
2233                BigUint::new(vec![2])
2234            )))
2235        );
2236        // Error since leading/trailing whitespace is not consumed by factorial or higher precedence expressions.
2237        assert_eq!(
2238            Evaluator::new(b" 2!", &mut Cache::new(), &mut None, &mut Vec::new()).get_fact(),
2239            Err(MissingTerm(0))
2240        );
2241        assert_eq!(
2242            Evaluator::new(b"\t2!", &mut Cache::new(), &mut None, &mut Vec::new()).get_fact(),
2243            Err(MissingTerm(0))
2244        );
2245        // Error since negation is not consumed by factorial or higher precedence expressions.
2246        assert_eq!(
2247            Evaluator::new(b"-2!", &mut Cache::new(), &mut None, &mut Vec::new()).get_fact(),
2248            Err(MissingTerm(0))
2249        );
2250    }
2251    #[expect(
2252        clippy::cognitive_complexity,
2253        clippy::too_many_lines,
2254        reason = "a lot to test"
2255    )]
2256    #[cfg(not(feature = "rand"))]
2257    #[test]
2258    fn exp() {
2259        // 1 can be raised to anything and return 1.
2260        // Also white space is ignored between operator.
2261        assert_eq!(
2262            Evaluator::new(b"1  ^\t  0", &mut Cache::new(), &mut None, &mut Vec::new()).get_exps(),
2263            Ok(Ratio::from_integer(BigInt::from_biguint(
2264                Sign::Plus,
2265                BigUint::new(vec![1])
2266            )))
2267        );
2268        assert_eq!(
2269            Evaluator::new(b"1^0.5", &mut Cache::new(), &mut None, &mut Vec::new()).get_exps(),
2270            Ok(Ratio::from_integer(BigInt::from_biguint(
2271                Sign::Plus,
2272                BigUint::new(vec![1])
2273            )))
2274        );
2275        assert_eq!(
2276            Evaluator::new(b"1^(-1/2)", &mut Cache::new(), &mut None, &mut Vec::new()).get_exps(),
2277            Ok(Ratio::from_integer(BigInt::from_biguint(
2278                Sign::Plus,
2279                BigUint::new(vec![1])
2280            )))
2281        );
2282        assert_eq!(
2283            Evaluator::new(b"1.0^(-2)", &mut Cache::new(), &mut None, &mut Vec::new()).get_exps(),
2284            Ok(Ratio::from_integer(BigInt::from_biguint(
2285                Sign::Plus,
2286                BigUint::new(vec![1])
2287            )))
2288        );
2289        // 0 can be raised to any non-negative value and will always return 0 unless raised to 0 which will return 1.
2290        assert_eq!(
2291            Evaluator::new(b"0^0", &mut Cache::new(), &mut None, &mut Vec::new()).get_exps(),
2292            Ok(Ratio::from_integer(BigInt::from_biguint(
2293                Sign::Plus,
2294                BigUint::new(vec![1])
2295            )))
2296        );
2297        assert_eq!(
2298            Evaluator::new(b"0^1", &mut Cache::new(), &mut None, &mut Vec::new()).get_exps(),
2299            Ok(Ratio::from_integer(BigInt::from_biguint(
2300                Sign::NoSign,
2301                BigUint::new(vec![0])
2302            )))
2303        );
2304        assert_eq!(
2305            Evaluator::new(b"0^0.5", &mut Cache::new(), &mut None, &mut Vec::new()).get_exps(),
2306            Ok(Ratio::from_integer(BigInt::from_biguint(
2307                Sign::NoSign,
2308                BigUint::new(vec![0])
2309            )))
2310        );
2311        // Anything else can only be raised to integers.
2312        assert_eq!(
2313            Evaluator::new(b"4^0", &mut Cache::new(), &mut None, &mut Vec::new()).get_exps(),
2314            Ok(Ratio::from_integer(BigInt::from_biguint(
2315                Sign::Plus,
2316                BigUint::new(vec![1])
2317            )))
2318        );
2319        assert_eq!(
2320            Evaluator::new(b"4^1", &mut Cache::new(), &mut None, &mut Vec::new()).get_exps(),
2321            Ok(Ratio::from_integer(BigInt::from_biguint(
2322                Sign::Plus,
2323                BigUint::new(vec![4])
2324            )))
2325        );
2326        assert_eq!(
2327            Evaluator::new(b"4^(-2)", &mut Cache::new(), &mut None, &mut Vec::new()).get_exps(),
2328            Ok(Ratio::new(
2329                BigInt::from_biguint(Sign::Plus, BigUint::new(vec![1])),
2330                BigInt::from_biguint(Sign::Plus, BigUint::new(vec![16]))
2331            ))
2332        );
2333        assert_eq!(
2334            Evaluator::new(b"(-4)^0", &mut Cache::new(), &mut None, &mut Vec::new()).get_exps(),
2335            Ok(Ratio::from_integer(BigInt::from_biguint(
2336                Sign::Plus,
2337                BigUint::new(vec![1])
2338            )))
2339        );
2340        assert_eq!(
2341            Evaluator::new(b"(-4)^1", &mut Cache::new(), &mut None, &mut Vec::new()).get_exps(),
2342            Ok(Ratio::from_integer(BigInt::from_biguint(
2343                Sign::Minus,
2344                BigUint::new(vec![4])
2345            )))
2346        );
2347        assert_eq!(
2348            Evaluator::new(b"(-4)^2", &mut Cache::new(), &mut None, &mut Vec::new()).get_exps(),
2349            Ok(Ratio::from_integer(BigInt::from_biguint(
2350                Sign::Plus,
2351                BigUint::new(vec![16])
2352            )))
2353        );
2354        assert_eq!(
2355            Evaluator::new(b"(-4)^(-2)", &mut Cache::new(), &mut None, &mut Vec::new()).get_exps(),
2356            Ok(Ratio::new(
2357                BigInt::from_biguint(Sign::Plus, BigUint::new(vec![1])),
2358                BigInt::from_biguint(Sign::Plus, BigUint::new(vec![16]))
2359            ))
2360        );
2361        assert_eq!(
2362            Evaluator::new(b"(-4)^(-3)", &mut Cache::new(), &mut None, &mut Vec::new()).get_exps(),
2363            Ok(Ratio::new(
2364                BigInt::from_biguint(Sign::Minus, BigUint::new(vec![1])),
2365                BigInt::from_biguint(Sign::Plus, BigUint::new(vec![64]))
2366            ))
2367        );
2368        assert_eq!(
2369            Evaluator::new(b"(2/3)^0", &mut Cache::new(), &mut None, &mut Vec::new()).get_exps(),
2370            Ok(Ratio::from_integer(BigInt::from_biguint(
2371                Sign::Plus,
2372                BigUint::new(vec![1])
2373            )))
2374        );
2375        assert_eq!(
2376            Evaluator::new(b"(2/3)^(2)", &mut Cache::new(), &mut None, &mut Vec::new()).get_exps(),
2377            Ok(Ratio::new(
2378                BigInt::from_biguint(Sign::Plus, BigUint::new(vec![4])),
2379                BigInt::from_biguint(Sign::Plus, BigUint::new(vec![9]))
2380            ))
2381        );
2382        assert_eq!(
2383            Evaluator::new(b"(2/3)^(-3)", &mut Cache::new(), &mut None, &mut Vec::new()).get_exps(),
2384            Ok(Ratio::new(
2385                BigInt::from_biguint(Sign::Plus, BigUint::new(vec![27])),
2386                BigInt::from_biguint(Sign::Plus, BigUint::new(vec![8]))
2387            ))
2388        );
2389        assert_eq!(
2390            Evaluator::new(b"(-2/3)^0", &mut Cache::new(), &mut None, &mut Vec::new()).get_exps(),
2391            Ok(Ratio::from_integer(BigInt::from_biguint(
2392                Sign::Plus,
2393                BigUint::new(vec![1])
2394            )))
2395        );
2396        assert_eq!(
2397            Evaluator::new(b"(-2/3)^(2)", &mut Cache::new(), &mut None, &mut Vec::new()).get_exps(),
2398            Ok(Ratio::new(
2399                BigInt::from_biguint(Sign::Plus, BigUint::new(vec![4])),
2400                BigInt::from_biguint(Sign::Plus, BigUint::new(vec![9]))
2401            ))
2402        );
2403        assert_eq!(
2404            Evaluator::new(b"(-2/3)^(3)", &mut Cache::new(), &mut None, &mut Vec::new()).get_exps(),
2405            Ok(Ratio::new(
2406                BigInt::from_biguint(Sign::Minus, BigUint::new(vec![8])),
2407                BigInt::from_biguint(Sign::Plus, BigUint::new(vec![27]))
2408            ))
2409        );
2410        assert_eq!(
2411            Evaluator::new(
2412                b"(-2/3)^(-2)",
2413                &mut Cache::new(),
2414                &mut None,
2415                &mut Vec::new()
2416            )
2417            .get_exps(),
2418            Ok(Ratio::new(
2419                BigInt::from_biguint(Sign::Plus, BigUint::new(vec![9])),
2420                BigInt::from_biguint(Sign::Plus, BigUint::new(vec![4]))
2421            ))
2422        );
2423        assert_eq!(
2424            Evaluator::new(
2425                b"(-2/3)^(-3)",
2426                &mut Cache::new(),
2427                &mut None,
2428                &mut Vec::new()
2429            )
2430            .get_exps(),
2431            Ok(Ratio::new(
2432                BigInt::from_biguint(Sign::Minus, BigUint::new(vec![27])),
2433                BigInt::from_biguint(Sign::Plus, BigUint::new(vec![8]))
2434            ))
2435        );
2436        assert_eq!(
2437            Evaluator::new(
2438                b"(4/9)^(-1/2)",
2439                &mut Cache::new(),
2440                &mut None,
2441                &mut Vec::new()
2442            )
2443            .get_exps(),
2444            Ok(Ratio::new(
2445                BigInt::from_biguint(Sign::Plus, BigUint::new(vec![3])),
2446                BigInt::from_biguint(Sign::Plus, BigUint::new(vec![2]))
2447            ))
2448        );
2449        // Error since 0 cannot be raised to a negative power.
2450        assert_eq!(
2451            Evaluator::new(b"0^(-1)", &mut Cache::new(), &mut None, &mut Vec::new()).get_exps(),
2452            Err(ExpDivByZero(6))
2453        );
2454        // Error since anything other than 0 or 1 cannot be raised to a non-integer power or (+/-) 1/2.
2455        assert_eq!(
2456            Evaluator::new(b"2^(1/3)", &mut Cache::new(), &mut None, &mut Vec::new()).get_exps(),
2457            Err(ExpIsNotIntOrOneHalf(7))
2458        );
2459        // When exponent is (+/-) 1/2, base has to be the square of a rational number.
2460        assert_eq!(
2461            Evaluator::new(b"2^(1/2)", &mut Cache::new(), &mut None, &mut Vec::new()).get_exps(),
2462            Err(SqrtDoesNotExist(7))
2463        );
2464        // exps always become factorials eventually.
2465        assert_eq!(
2466            Evaluator::new(b"3!", &mut Cache::new(), &mut None, &mut Vec::new()).get_exps(),
2467            Ok(Ratio::from_integer(BigInt::from_biguint(
2468                Sign::Plus,
2469                BigUint::new(vec![6])
2470            )))
2471        );
2472        // exponentiation has lower precedence than factorials.
2473        assert_eq!(
2474            Evaluator::new(b"2^3!", &mut Cache::new(), &mut None, &mut Vec::new()).get_exps(),
2475            Ok(Ratio::from_integer(BigInt::from_biguint(
2476                Sign::Plus,
2477                BigUint::new(vec![64])
2478            )))
2479        );
2480        assert_eq!(
2481            Evaluator::new(b"3!^2", &mut Cache::new(), &mut None, &mut Vec::new()).get_exps(),
2482            Ok(Ratio::from_integer(BigInt::from_biguint(
2483                Sign::Plus,
2484                BigUint::new(vec![36])
2485            )))
2486        );
2487        // Error since leading/trailing whitespace is not consumed by exponentiation or higher precedence expressions.
2488        assert_eq!(
2489            Evaluator::new(b" 2^2", &mut Cache::new(), &mut None, &mut Vec::new()).get_exps(),
2490            Err(MissingTerm(0))
2491        );
2492        assert_eq!(
2493            Evaluator::new(b"\t2^2", &mut Cache::new(), &mut None, &mut Vec::new()).get_exps(),
2494            Err(MissingTerm(0))
2495        );
2496    }
2497    #[cfg(not(feature = "rand"))]
2498    #[test]
2499    fn neg() {
2500        assert_eq!(
2501            Evaluator::new(b"-1", &mut Cache::new(), &mut None, &mut Vec::new()).get_neg(),
2502            Ok(Ratio::from_integer(BigInt::from_biguint(
2503                Sign::Minus,
2504                BigUint::new(vec![1])
2505            )))
2506        );
2507        assert_eq!(
2508            Evaluator::new(b"- \t  -  1", &mut Cache::new(), &mut None, &mut Vec::new()).get_neg(),
2509            Ok(Ratio::from_integer(BigInt::from_biguint(
2510                Sign::Plus,
2511                BigUint::new(vec![1])
2512            )))
2513        );
2514        assert_eq!(
2515            Evaluator::new(b"-0", &mut Cache::new(), &mut None, &mut Vec::new()).get_neg(),
2516            Ok(Ratio::from_integer(BigInt::from_biguint(
2517                Sign::NoSign,
2518                BigUint::new(Vec::new())
2519            )))
2520        );
2521        // negation has lower precedence than exponentiation.
2522        assert_eq!(
2523            Evaluator::new(b"-2^2", &mut Cache::new(), &mut None, &mut Vec::new()).get_neg(),
2524            Ok(Ratio::from_integer(BigInt::from_biguint(
2525                Sign::Minus,
2526                BigUint::new(vec![4])
2527            )))
2528        );
2529        // negation always becomes exponentiation eventually.
2530        assert_eq!(
2531            Evaluator::new(b"2.0^2.0", &mut Cache::new(), &mut None, &mut Vec::new()).get_neg(),
2532            Ok(Ratio::from_integer(BigInt::from_biguint(
2533                Sign::Plus,
2534                BigUint::new(vec![4])
2535            )))
2536        );
2537        // Error since leading/trailing whitespace is not consumed by exponentiation or higher precedence expressions.
2538        assert_eq!(
2539            Evaluator::new(b" -2", &mut Cache::new(), &mut None, &mut Vec::new()).get_neg(),
2540            Err(MissingTerm(0))
2541        );
2542        assert_eq!(
2543            Evaluator::new(b"\t-2", &mut Cache::new(), &mut None, &mut Vec::new()).get_neg(),
2544            Err(MissingTerm(0))
2545        );
2546    }
2547    #[expect(
2548        clippy::cognitive_complexity,
2549        clippy::too_many_lines,
2550        reason = "a lot to test"
2551    )]
2552    #[cfg(not(feature = "rand"))]
2553    #[test]
2554    fn mult() {
2555        assert_eq!(
2556            Evaluator::new(b"2  *   3", &mut Cache::new(), &mut None, &mut Vec::new()).get_mults(),
2557            Ok(Ratio::from_integer(BigInt::from_biguint(
2558                Sign::Plus,
2559                BigUint::new(vec![6])
2560            )))
2561        );
2562        assert_eq!(
2563            Evaluator::new(
2564                b"-2  * \t  3",
2565                &mut Cache::new(),
2566                &mut None,
2567                &mut Vec::new()
2568            )
2569            .get_mults(),
2570            Ok(Ratio::from_integer(BigInt::from_biguint(
2571                Sign::Minus,
2572                BigUint::new(vec![6])
2573            )))
2574        );
2575        assert_eq!(
2576            Evaluator::new(
2577                b"2\t  *   -3.0",
2578                &mut Cache::new(),
2579                &mut None,
2580                &mut Vec::new()
2581            )
2582            .get_mults(),
2583            Ok(Ratio::from_integer(BigInt::from_biguint(
2584                Sign::Minus,
2585                BigUint::new(vec![6])
2586            )))
2587        );
2588        assert_eq!(
2589            Evaluator::new(b"-2.5*-3.5", &mut Cache::new(), &mut None, &mut Vec::new()).get_mults(),
2590            Ok(Ratio::new(
2591                BigInt::from_biguint(Sign::Plus, BigUint::new(vec![35])),
2592                BigInt::from_biguint(Sign::Plus, BigUint::new(vec![4]))
2593            ))
2594        );
2595        assert_eq!(
2596            Evaluator::new(b"4.0\t /  6", &mut Cache::new(), &mut None, &mut Vec::new())
2597                .get_mults(),
2598            Ok(Ratio::new(
2599                BigInt::from_biguint(Sign::Plus, BigUint::new(vec![2])),
2600                BigInt::from_biguint(Sign::Plus, BigUint::new(vec![3]))
2601            ))
2602        );
2603        assert_eq!(
2604            Evaluator::new(b"6/3", &mut Cache::new(), &mut None, &mut Vec::new()).get_mults(),
2605            Ok(Ratio::from_integer(BigInt::from_biguint(
2606                Sign::Plus,
2607                BigUint::new(vec![2])
2608            )))
2609        );
2610        assert_eq!(
2611            Evaluator::new(b"-6/3", &mut Cache::new(), &mut None, &mut Vec::new()).get_mults(),
2612            Ok(Ratio::from_integer(BigInt::from_biguint(
2613                Sign::Minus,
2614                BigUint::new(vec![2])
2615            )))
2616        );
2617        assert_eq!(
2618            Evaluator::new(b"6/-3", &mut Cache::new(), &mut None, &mut Vec::new()).get_mults(),
2619            Ok(Ratio::from_integer(BigInt::from_biguint(
2620                Sign::Minus,
2621                BigUint::new(vec![2])
2622            )))
2623        );
2624        assert_eq!(
2625            Evaluator::new(
2626                b"-  6 /\t -  3",
2627                &mut Cache::new(),
2628                &mut None,
2629                &mut Vec::new()
2630            )
2631            .get_mults(),
2632            Ok(Ratio::from_integer(BigInt::from_biguint(
2633                Sign::Plus,
2634                BigUint::new(vec![2])
2635            )))
2636        );
2637        // Number literals are not strictly equivalent to "ratios" as "ratios" don't exist (i.e., 2/3 is not the ratio of 2 to 3 but is the rational number two divided by the rational number 3).
2638        assert!(
2639            Evaluator::new(b"1/1.5", &mut Cache::new(), &mut None, &mut Vec::new())
2640                .get_mults()
2641                .is_ok_and(|r| {
2642                    Evaluator::new(b"1/3/2", &mut Cache::new(), &mut None, &mut Vec::new())
2643                        .get_mults()
2644                        .is_ok_and(|r2| r != r2)
2645                })
2646        );
2647        assert!(
2648            Evaluator::new(b"1/1.5", &mut Cache::new(), &mut None, &mut Vec::new())
2649                .get_mults()
2650                .is_ok_and(|r| {
2651                    Evaluator::new(b"1/(3/2)", &mut Cache::new(), &mut None, &mut Vec::new())
2652                        .get_mults()
2653                        .is_ok_and(|r2| r == r2)
2654                })
2655        );
2656        // multiplication always becomes negation eventually.
2657        assert_eq!(
2658            Evaluator::new(b"-2.0", &mut Cache::new(), &mut None, &mut Vec::new()).get_mults(),
2659            Ok(Ratio::from_integer(BigInt::from_biguint(
2660                Sign::Minus,
2661                BigUint::new(vec![2])
2662            )))
2663        );
2664        // Error since leading/trailing whitespace is not consumed by multiplication or higher precedence expressions.
2665        assert_eq!(
2666            Evaluator::new(b" 2*2", &mut Cache::new(), &mut None, &mut Vec::new()).get_mults(),
2667            Err(MissingTerm(0))
2668        );
2669        assert_eq!(
2670            Evaluator::new(b"\t2/2", &mut Cache::new(), &mut None, &mut Vec::new()).get_mults(),
2671            Err(MissingTerm(0))
2672        );
2673        assert_eq!(
2674            Evaluator::new(
2675                b"4.0\t mod  6",
2676                &mut Cache::new(),
2677                &mut None,
2678                &mut Vec::new()
2679            )
2680            .get_mults(),
2681            Ok(Ratio::from_integer(BigInt::from_biguint(
2682                Sign::Plus,
2683                BigUint::new(vec![4])
2684            ),))
2685        );
2686        assert_eq!(
2687            Evaluator::new(b"5 mod 3", &mut Cache::new(), &mut None, &mut Vec::new()).get_mults(),
2688            Ok(Ratio::from_integer(BigInt::from_biguint(
2689                Sign::Plus,
2690                BigUint::new(vec![2])
2691            )))
2692        );
2693        assert_eq!(
2694            Evaluator::new(b"-5 mod 3", &mut Cache::new(), &mut None, &mut Vec::new()).get_mults(),
2695            Ok(Ratio::from_integer(BigInt::from_biguint(
2696                Sign::Plus,
2697                BigUint::new(vec![1])
2698            )))
2699        );
2700        assert_eq!(
2701            Evaluator::new(b"5 mod -3", &mut Cache::new(), &mut None, &mut Vec::new()).get_mults(),
2702            Ok(Ratio::from_integer(BigInt::from_biguint(
2703                Sign::Plus,
2704                BigUint::new(vec![2])
2705            )))
2706        );
2707        assert_eq!(
2708            Evaluator::new(
2709                b"-5   mod\t -3",
2710                &mut Cache::new(),
2711                &mut None,
2712                &mut Vec::new()
2713            )
2714            .get_mults(),
2715            Ok(Ratio::from_integer(BigInt::from_biguint(
2716                Sign::Plus,
2717                BigUint::new(vec![1])
2718            )))
2719        );
2720        // Cannot divide by 0.
2721        assert_eq!(
2722            Evaluator::new(b"2/0", &mut Cache::new(), &mut None, &mut Vec::new()).get_mults(),
2723            Err(DivByZero(3))
2724        );
2725        assert_eq!(
2726            Evaluator::new(b"2 mod 0", &mut Cache::new(), &mut None, &mut Vec::new()).get_mults(),
2727            Err(ModZero(7))
2728        );
2729        // Right and left operands of mod must be integers.
2730        assert_eq!(
2731            Evaluator::new(b"3.2 mod 1", &mut Cache::new(), &mut None, &mut Vec::new()).get_mults(),
2732            Err(ModIsNotInt(4))
2733        );
2734        assert_eq!(
2735            Evaluator::new(b"3 mod 3.2", &mut Cache::new(), &mut None, &mut Vec::new()).get_mults(),
2736            Err(ModIsNotInt(9))
2737        );
2738        // multiplication has lower precedence than exponentiation.
2739        assert_eq!(
2740            Evaluator::new(b"2*2^2", &mut Cache::new(), &mut None, &mut Vec::new()).get_mults(),
2741            Ok(Ratio::from_integer(BigInt::from_biguint(
2742                Sign::Plus,
2743                BigUint::new(vec![8])
2744            )))
2745        );
2746        assert_eq!(
2747            Evaluator::new(b"8/2^2", &mut Cache::new(), &mut None, &mut Vec::new()).get_mults(),
2748            Ok(Ratio::from_integer(BigInt::from_biguint(
2749                Sign::Plus,
2750                BigUint::new(vec![2])
2751            )))
2752        );
2753        assert_eq!(
2754            Evaluator::new(b"8 mod 3^2", &mut Cache::new(), &mut None, &mut Vec::new()).get_mults(),
2755            Ok(Ratio::from_integer(BigInt::from_biguint(
2756                Sign::Plus,
2757                BigUint::new(vec![8])
2758            )))
2759        );
2760    }
2761    #[expect(clippy::too_many_lines, reason = "a lot to test")]
2762    #[cfg(not(feature = "rand"))]
2763    #[test]
2764    fn add() {
2765        assert_eq!(
2766            Evaluator::new(b"2  +   3", &mut Cache::new(), &mut None, &mut Vec::new()).get_adds(),
2767            Ok(Ratio::from_integer(BigInt::from_biguint(
2768                Sign::Plus,
2769                BigUint::new(vec![5])
2770            )))
2771        );
2772        assert_eq!(
2773            Evaluator::new(b"-2  +   3", &mut Cache::new(), &mut None, &mut Vec::new()).get_adds(),
2774            Ok(Ratio::from_integer(BigInt::from_biguint(
2775                Sign::Plus,
2776                BigUint::new(vec![1])
2777            )))
2778        );
2779        assert_eq!(
2780            Evaluator::new(
2781                b"2  +  \t -3.0",
2782                &mut Cache::new(),
2783                &mut None,
2784                &mut Vec::new()
2785            )
2786            .get_adds(),
2787            Ok(Ratio::from_integer(BigInt::from_biguint(
2788                Sign::Minus,
2789                BigUint::new(vec![1])
2790            )))
2791        );
2792        assert_eq!(
2793            Evaluator::new(b"-2.5+-3.5", &mut Cache::new(), &mut None, &mut Vec::new()).get_adds(),
2794            Ok(Ratio::from_integer(BigInt::from_biguint(
2795                Sign::Minus,
2796                BigUint::new(vec![6])
2797            )))
2798        );
2799        assert_eq!(
2800            Evaluator::new(b"4.0\t -  6", &mut Cache::new(), &mut None, &mut Vec::new()).get_adds(),
2801            Ok(Ratio::from_integer(BigInt::from_biguint(
2802                Sign::Minus,
2803                BigUint::new(vec![2])
2804            )))
2805        );
2806        assert_eq!(
2807            Evaluator::new(b"6-3", &mut Cache::new(), &mut None, &mut Vec::new()).get_adds(),
2808            Ok(Ratio::from_integer(BigInt::from_biguint(
2809                Sign::Plus,
2810                BigUint::new(vec![3])
2811            )))
2812        );
2813        assert_eq!(
2814            Evaluator::new(b"-6-3", &mut Cache::new(), &mut None, &mut Vec::new()).get_adds(),
2815            Ok(Ratio::from_integer(BigInt::from_biguint(
2816                Sign::Minus,
2817                BigUint::new(vec![9])
2818            )))
2819        );
2820        assert_eq!(
2821            Evaluator::new(b"6--3", &mut Cache::new(), &mut None, &mut Vec::new()).get_adds(),
2822            Ok(Ratio::from_integer(BigInt::from_biguint(
2823                Sign::Plus,
2824                BigUint::new(vec![9])
2825            )))
2826        );
2827        assert_eq!(
2828            Evaluator::new(
2829                b"-  6 -\t -  3",
2830                &mut Cache::new(),
2831                &mut None,
2832                &mut Vec::new()
2833            )
2834            .get_adds(),
2835            Ok(Ratio::from_integer(BigInt::from_biguint(
2836                Sign::Minus,
2837                BigUint::new(vec![3])
2838            )))
2839        );
2840        // addition always becomes multiplication eventually.
2841        assert_eq!(
2842            Evaluator::new(b"2 * 8", &mut Cache::new(), &mut None, &mut Vec::new()).get_adds(),
2843            Ok(Ratio::from_integer(BigInt::from_biguint(
2844                Sign::Plus,
2845                BigUint::new(vec![16])
2846            )))
2847        );
2848        assert_eq!(
2849            Evaluator::new(b"8 /\t 2", &mut Cache::new(), &mut None, &mut Vec::new()).get_adds(),
2850            Ok(Ratio::from_integer(BigInt::from_biguint(
2851                Sign::Plus,
2852                BigUint::new(vec![4])
2853            )))
2854        );
2855        // Error since leading/trailing whitespace is not consumed by addition or higher precedence expressions.
2856        assert_eq!(
2857            Evaluator::new(b" 2+2", &mut Cache::new(), &mut None, &mut Vec::new()).get_adds(),
2858            Err(MissingTerm(0))
2859        );
2860        assert_eq!(
2861            Evaluator::new(b" 2-2", &mut Cache::new(), &mut None, &mut Vec::new()).get_adds(),
2862            Err(MissingTerm(0))
2863        );
2864        // addition has lower precedence than multiplication.
2865        assert_eq!(
2866            Evaluator::new(b"2+2*2", &mut Cache::new(), &mut None, &mut Vec::new()).get_adds(),
2867            Ok(Ratio::from_integer(BigInt::from_biguint(
2868                Sign::Plus,
2869                BigUint::new(vec![6])
2870            )))
2871        );
2872        assert_eq!(
2873            Evaluator::new(b"2+2/2", &mut Cache::new(), &mut None, &mut Vec::new()).get_adds(),
2874            Ok(Ratio::from_integer(BigInt::from_biguint(
2875                Sign::Plus,
2876                BigUint::new(vec![3])
2877            )))
2878        );
2879        assert_eq!(
2880            Evaluator::new(b"2-2*2", &mut Cache::new(), &mut None, &mut Vec::new()).get_adds(),
2881            Ok(Ratio::from_integer(BigInt::from_biguint(
2882                Sign::Minus,
2883                BigUint::new(vec![2])
2884            )))
2885        );
2886        assert_eq!(
2887            Evaluator::new(b"2-2/2", &mut Cache::new(), &mut None, &mut Vec::new()).get_adds(),
2888            Ok(Ratio::from_integer(BigInt::from_biguint(
2889                Sign::Plus,
2890                BigUint::new(vec![1])
2891            )))
2892        );
2893    }
2894    #[cfg(not(feature = "rand"))]
2895    #[test]
2896    fn exit() {
2897        assert_eq!(
2898            Evaluator::new(b"  q    \n", &mut Cache::new(), &mut None, &mut Vec::new()).evaluate(),
2899            Ok(Exit)
2900        );
2901        assert_eq!(
2902            Evaluator::new(
2903                b"  q    \r\n",
2904                &mut Cache::new(),
2905                &mut None,
2906                &mut Vec::new()
2907            )
2908            .evaluate(),
2909            Ok(Exit)
2910        );
2911        assert_eq!(
2912            Evaluator::new(b"q\n", &mut Cache::new(), &mut None, &mut Vec::new()).evaluate(),
2913            Ok(Exit)
2914        );
2915        assert_eq!(
2916            Evaluator::new(b"q\r\n", &mut Cache::new(), &mut None, &mut Vec::new()).evaluate(),
2917            Ok(Exit)
2918        );
2919        assert_eq!(
2920            Evaluator::new(b"\rq\n", &mut Cache::new(), &mut None, &mut Vec::new()).evaluate(),
2921            Err(MissingTerm(0))
2922        );
2923        assert_eq!(
2924            Evaluator::new(b"\tq\n", &mut Cache::new(), &mut None, &mut Vec::new()).evaluate(),
2925            Ok(Exit)
2926        );
2927        assert_eq!(
2928            Evaluator::new(b"q\n\n", &mut Cache::new(), &mut None, &mut Vec::new()).evaluate(),
2929            Err(InvalidQuit)
2930        );
2931        assert_eq!(
2932            Evaluator::new(b"\nq\n", &mut Cache::new(), &mut None, &mut Vec::new()).evaluate(),
2933            Err(MissingTerm(0))
2934        );
2935        assert_eq!(
2936            Evaluator::new(b"q", &mut Cache::new(), &mut None, &mut Vec::new()).evaluate(),
2937            Ok(Exit)
2938        );
2939    }
2940    #[expect(clippy::unwrap_used, reason = "comment justifies correctness")]
2941    #[cfg(not(feature = "rand"))]
2942    #[test]
2943    fn store() {
2944        let mut prev = None;
2945        let mut cache = Cache::new();
2946        // Quick check that `Ok` is returned.
2947        _ = Evaluator::new(b"1\n", &mut cache, &mut prev, &mut Vec::new())
2948            .evaluate()
2949            .unwrap();
2950        assert!(cache.is_empty());
2951        assert_eq!(
2952            Evaluator::new(b"s\n", &mut cache, &mut prev, &mut Vec::new()).evaluate(),
2953            Ok(Store(&Some(Ratio::from_integer(BigInt::from_biguint(
2954                Sign::Plus,
2955                BigUint::new(vec![1])
2956            )))))
2957        );
2958        assert_eq!(cache.len(), 1);
2959        assert_eq!(
2960            Evaluator::new(b"s2\n", &mut Cache::new(), &mut None, &mut Vec::new()).evaluate(),
2961            Err(InvalidStore)
2962        );
2963    }
2964    #[expect(clippy::too_many_lines, reason = "a lot to test")]
2965    #[cfg(not(feature = "rand"))]
2966    #[test]
2967    fn eval() {
2968        use core::str::FromStr as _;
2969        let mut prev = None;
2970        let mut cache = Cache::new();
2971        let mut exp = Vec::new();
2972        assert_eq!(
2973            Evaluator::new(b"1+2\n", &mut cache, &mut prev, &mut exp).evaluate(),
2974            Ok(Eval(&Ratio::from_integer(BigInt::from_biguint(
2975                Sign::Plus,
2976                BigUint::new(vec![3])
2977            ))))
2978        );
2979        assert_eq!(
2980            Evaluator::new(b"\t  s  \n", &mut cache, &mut prev, &mut exp).evaluate(),
2981            Ok(Store(&Some(Ratio::from_integer(BigInt::from_biguint(
2982                Sign::Plus,
2983                BigUint::new(vec![3])
2984            )))))
2985        );
2986        assert_eq!(
2987            Evaluator::new(b"-1/2+2*@\n", &mut cache, &mut prev, &mut exp).evaluate(),
2988            Ok(Eval(&Ratio::new(
2989                BigInt::from_biguint(Sign::Plus, BigUint::new(vec![11])),
2990                BigInt::from_biguint(Sign::Plus, BigUint::new(vec![2]))
2991            )))
2992        );
2993        assert_eq!(
2994            Evaluator::new(b"s\n", &mut cache, &mut prev, &mut exp).evaluate(),
2995            Ok(Store(&Some(Ratio::new(
2996                BigInt::from_biguint(Sign::Plus, BigUint::new(vec![11])),
2997                BigInt::from_biguint(Sign::Plus, BigUint::new(vec![2]))
2998            ))))
2999        );
3000        assert_eq!(
3001            Evaluator::new(b"@^@2!\r\n", &mut cache, &mut prev, &mut exp).evaluate(),
3002            Ok(Eval(&Ratio::new(
3003                BigInt::from_biguint(Sign::Plus, BigUint::new(vec![1_771_561])),
3004                BigInt::from_biguint(Sign::Plus, BigUint::new(vec![64]))
3005            )))
3006        );
3007        assert_eq!(
3008            Evaluator::new(b"s\n", &mut cache, &mut prev, &mut exp).evaluate(),
3009            Ok(Store(&Some(Ratio::new(
3010                BigInt::from_biguint(Sign::Plus, BigUint::new(vec![1_771_561])),
3011                BigInt::from_biguint(Sign::Plus, BigUint::new(vec![64]))
3012            ))))
3013        );
3014        // Verified with Wolfram Alpha.
3015        assert!(
3016            Evaluator::new(
3017                b" \t 1 + (2 * |(7.98\t - 12/7)|) / 4!^@3!^|1-3|\t  \n",
3018                &mut cache,
3019                &mut prev,
3020                &mut exp
3021            )
3022            .evaluate().is_ok_and(|r| {
3023                Ratio::from_str("2841328814244153299237884950647090899374680152474331/2841328814244153299237884950647090899374680152473600").is_ok_and(|r2| {
3024                    r == Eval(&r2)
3025                })
3026            })
3027        );
3028        assert_eq!(
3029            Evaluator::new(
3030                b" \t round(19/6,0)!\t  \r\n",
3031                &mut cache,
3032                &mut prev,
3033                &mut exp
3034            )
3035            .evaluate(),
3036            Ok(Eval(&Ratio::from_integer(BigInt::from_biguint(
3037                Sign::Plus,
3038                BigUint::new(vec![6])
3039            ))))
3040        );
3041        assert_eq!(
3042            Evaluator::new(
3043                b" \t 2^round(19/6,0)!\t  \r\n",
3044                &mut cache,
3045                &mut prev,
3046                &mut exp
3047            )
3048            .evaluate(),
3049            Ok(Eval(&Ratio::from_integer(BigInt::from_biguint(
3050                Sign::Plus,
3051                BigUint::new(vec![64])
3052            ))))
3053        );
3054        assert_eq!(
3055            Evaluator::new(b"round(19/6,0)^2\t\n", &mut cache, &mut prev, &mut exp).evaluate(),
3056            Ok(Eval(&Ratio::from_integer(BigInt::from_biguint(
3057                Sign::Plus,
3058                BigUint::new(vec![9])
3059            ))))
3060        );
3061        // Invalid UTF-8 does not cause a panic!.
3062        assert_eq!(
3063            Evaluator::new(&[255, 255, 255, b'\n'], &mut cache, &mut prev, &mut exp).evaluate(),
3064            Err(MissingTerm(0))
3065        );
3066        assert_eq!(
3067            Evaluator::new(&[b'2', 255, b'\n'], &mut cache, &mut prev, &mut exp).evaluate(),
3068            Err(TrailingSyms(1))
3069        );
3070        // Exactly one newline is required.
3071        assert_eq!(
3072            Evaluator::new(b"2\n\n", &mut cache, &mut prev, &mut exp).evaluate(),
3073            Err(TrailingSyms(1))
3074        );
3075        assert_eq!(
3076            prev,
3077            Some(Ratio::from_integer(BigInt::from_biguint(
3078                Sign::Plus,
3079                BigUint::new(vec![9])
3080            )))
3081        );
3082        assert_eq!(
3083            Evaluator::new(b"\n", &mut cache, &mut prev.clone(), &mut exp).evaluate(),
3084            Ok(Empty(&Some(Ratio::from_integer(BigInt::from_biguint(
3085                Sign::Plus,
3086                BigUint::new(vec![9])
3087            )))))
3088        );
3089        assert_eq!(
3090            prev,
3091            Some(Ratio::from_integer(BigInt::from_biguint(
3092                Sign::Plus,
3093                BigUint::new(vec![9])
3094            )))
3095        );
3096        assert_eq!(
3097            Evaluator::new(b"\r\n", &mut cache, &mut prev.clone(), &mut exp).evaluate(),
3098            Ok(Empty(&prev))
3099        );
3100        assert_eq!(
3101            Evaluator::new(&[0u8; 0], &mut cache, &mut prev.clone(), &mut exp).evaluate(),
3102            Ok(Empty(&prev))
3103        );
3104    }
3105    #[cfg(feature = "rand")]
3106    #[test]
3107    fn eval_iter() {
3108        struct Reader<'a> {
3109            data: &'a [u8],
3110            err: bool,
3111        }
3112        impl<'a> Reader<'a> {
3113            fn new(data: &'a [u8]) -> Self {
3114                Self { data, err: true }
3115            }
3116        }
3117        impl Read for Reader<'_> {
3118            #[expect(clippy::indexing_slicing, reason = "comment justifies correctness")]
3119            fn read(&mut self, buf: &mut [u8]) -> io::Result<usize> {
3120                if self.err {
3121                    self.err = false;
3122                    Err(Error::other(""))
3123                } else {
3124                    let len = usize::min(buf.len(), self.data.len());
3125                    // `len <= buf.len()` and `len <= `self.data.len()`.
3126                    buf[..len].copy_from_slice(&self.data[..len]);
3127                    Ok(len)
3128                }
3129            }
3130        }
3131        impl BufRead for Reader<'_> {
3132            fn fill_buf(&mut self) -> io::Result<&[u8]> {
3133                if self.err {
3134                    self.err = false;
3135                    Err(Error::other(""))
3136                } else {
3137                    Ok(self.data)
3138                }
3139            }
3140            #[expect(clippy::indexing_slicing, reason = "comment justifies correctness")]
3141            fn consume(&mut self, amount: usize) {
3142                // This is just a test, so calling code passing in an invalid `amount` is fine.
3143                self.data = &self.data[amount..];
3144            }
3145        }
3146        let mut iter = EvalIter::new(Reader::new(
3147            b"1+2\n4\n\nq\n5\ns\nrand() + rand(-139/@, 2984/134)\nab",
3148        ));
3149        assert!(
3150            iter.lend_next()
3151                .is_some_and(|res| res.map_or_else(|e| matches!(e, E::Error(_)), |_| false))
3152        );
3153        assert!(iter.lend_next().is_some_and(|res| {
3154            res.is_ok_and(|e| matches!(e, Eval(r) if r.numer().to_i32() == Some(3i32)))
3155        }));
3156        assert!(iter.lend_next().is_some_and(|res| {
3157            res.is_ok_and(|e| matches!(e, Eval(r) if r.numer().to_i32() == Some(4i32)))
3158        }));
3159        assert!(iter.lend_next().is_some_and(|res| {
3160            res.is_ok_and(
3161                |e| matches!(e, Empty(r) if r.as_ref().is_some_and(|val| val.numer().to_i32() == Some(4i32))),
3162            )
3163        }));
3164        assert!(iter.lend_next().is_none());
3165        assert!(iter.lend_next().is_some_and(|res| {
3166            res.is_ok_and(|e| matches!(e, Eval(r) if r.numer().to_i32() == Some(5i32)))
3167        }));
3168        assert!(iter.lend_next().is_some_and(|res| {
3169            res.is_ok_and(
3170                |e| matches!(e, Store(r) if r.as_ref().is_some_and(|val| val.numer().to_i32() == Some(5i32))),
3171            )
3172        }));
3173        assert!(
3174            iter.lend_next()
3175                .is_some_and(|res| res.is_ok_and(|e| matches!(e, Eval(r) if r.is_integer())))
3176        );
3177        assert!(iter.lend_next().is_some_and(|res| {
3178            res.is_err_and(|err| matches!(err, E::LangErr(ref e) if matches!(*e, MissingTerm(_))))
3179        }));
3180        assert!(iter.lend_next().is_none());
3181        assert!(iter.lend_next().is_none());
3182        assert!(iter.lend_next().is_none());
3183    }
3184}