calc_rational

CLI calculator for rational numbers.
git clone https://git.philomathiclife.com/repos/calc_rational
Log | Files | Refs | README

lib.rs (124663B)


      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))]
    123 extern crate alloc;
    124 use LangErr::{
    125     DivByZero, ExpDivByZero, ExpIsNotIntOrOneHalf, InvalidAbs, InvalidDec, InvalidPar, InvalidQuit,
    126     InvalidRound, InvalidStore, MissingTerm, ModIsNotInt, ModZero, NotEnoughPrevResults,
    127     NotNonNegIntFact, SqrtDoesNotExist, TrailingSyms,
    128 };
    129 use O::{Empty, Eval, Exit, Store};
    130 use alloc::{
    131     string::{String, ToString as _},
    132     vec,
    133     vec::Vec,
    134 };
    135 use cache::Cache;
    136 #[cfg(not(feature = "rand"))]
    137 use core::marker::PhantomData;
    138 use core::{
    139     convert,
    140     fmt::{self, Display, Formatter},
    141     ops::Index as _,
    142 };
    143 pub use num_bigint;
    144 use num_bigint::{BigInt, BigUint, Sign};
    145 use num_integer::Integer as _;
    146 pub use num_rational;
    147 use num_rational::Ratio;
    148 #[cfg(feature = "rand")]
    149 use num_traits::ToPrimitive as _;
    150 use num_traits::{Inv as _, Pow as _};
    151 #[cfg(target_os = "openbsd")]
    152 use priv_sep as _;
    153 #[cfg(feature = "rand")]
    154 pub use rand;
    155 #[cfg(feature = "rand")]
    156 use 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.
    163 pub mod cache;
    164 /// Generalizes [`Iterator`] by using
    165 /// generic associated types.
    166 pub mod lending_iterator;
    167 /// Error due to a language violation.
    168 #[non_exhaustive]
    169 #[cfg_attr(test, derive(Eq, PartialEq))]
    170 #[derive(Debug)]
    171 pub 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 }
    233 impl 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)]
    268 pub 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 }
    282 impl 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`].
    387 const CACHE_SIZE: usize = 8;
    388 /// Evaluates the supplied input.
    389 #[derive(Debug)]
    390 pub 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 )]
    417 impl<'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)]
   1144 pub 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")]
   1162 impl<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")]
   1190 extern crate std;
   1191 #[cfg(feature = "std")]
   1192 use std::io::{BufRead, Error};
   1193 /// Error returned from [`EvalIter`] when an expression has an error.
   1194 #[cfg(feature = "std")]
   1195 #[derive(Debug)]
   1196 pub 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")]
   1206 impl 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")]
   1216 use crate::lending_iterator::LendingIterator;
   1217 #[cfg(feature = "std")]
   1218 impl<R> LendingIterator for EvalIter<R>
   1219 where
   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)]
   1260 mod 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 }