Skip to main content

calc_lib/
lib.rs

1//! [![git]](https://git.philomathiclife.com/calc_rational/log.html) [![crates-io]](https://crates.io/crates/calc_rational) [![docs-rs]](crate)
2//!
3//! [git]: https://git.philomathiclife.com/git_badge.svg
4//! [crates-io]: https://img.shields.io/badge/crates.io-fc8d62?style=for-the-badge&labelColor=555555&logo=rust
5//! [docs-rs]: https://img.shields.io/badge/docs.rs-66c2a5?style=for-the-badge&labelColor=555555&logo=docs.rs
6//!
7//! `calc_lib` is a library for performing basic rational number arithmetic using standard operator precedence
8//! and associativity. Internally, it is based on
9//! [`Ratio<T>`] and [`BigInt`].
10//!   
11//! ## Expressions  
12//!   
13//! The following are the list of expressions in descending order of precedence:  
14//!   1. number literals, `@`, `()`, `||`, `round()`, `rand()`  
15//!   2. `!`  
16//!   3. `^`  
17//!   4. `-` (unary negation operator)  
18//!   5. `*`, `/`, `mod`  
19//!   6. `+`, `-`  
20//!   
21//! All binary operators are left-associative sans `^` which is right-associative.  
22//!   
23//! Any expression is allowed to be enclosed in `()`. Note that parentheses are purely for grouping expressions;
24//! in particular, you cannot use them to represent multiplication (e.g., `4(2)` is grammatically incorrect and
25//! will result in an error message).  
26//!   
27//! Any expression is allowed to be enclosed in `||`. This unary operator represents absolute value.  
28//!   
29//! `!` is the factorial operator. Due to its high precedence, something like *-i!^j!* for *i, j ∈ ℕ* is
30//! the same thing as *-((i!)^(j!))*. If the expression preceding it does not evaluate to a non-negative integer,
31//! then an error will be displayed. Spaces  and tabs are *not* ignored; so `1 !` is grammatically incorrect and
32//! will result in an error message.  
33//!   
34//! `^` is the exponentiation operator. The expression left of the operator can evaluate to any rational number;
35//! however the expression right of the operator must evaluate to an integer or ±1/2 unless the expression on
36//! the left evaluates to `0` or `1`. In the event of the former, the expression right of the operator must evaluate
37//! to a non-negative rational number. In the event of the latter, the expression right of the operator can evaluate to
38//! any rational number. Note that `0^0` is defined to be 1. When the operand right of `^` evaluates to ±1/2, then
39//! the left operand must be the square of a rational number.  
40//!   
41//! The unary operator `-` represents negation.  
42//!   
43//! The operators `*` and `/` represent multiplication and division respectively. Expressions right of `/`
44//! must evaluate to any non-zero rational number; otherwise an error will be displayed.  
45//!   
46//! The binary operator `mod` represents modulo such that *n mod m = r = n - m\*q* for *n,q ∈ ℤ, m ∈ ℤ\\{0}, and r ∈ ℕ*
47//! where *r* is the minimum non-negative solution.  
48//!   
49//! The binary operators `+` and `-` represent addition and subtraction respectively.  
50//!   
51//! With the aforementioned exception of `!`, all spaces and tabs before and after operators are ignored.  
52//!   
53//! ## Round expression  
54//!   
55//! `round(expression, digit)` rounds `expression` to `digit`-number of fractional digits. An error will
56//! be displayed if called incorrectly.  
57//!   
58//! ## Rand expression  
59//!   
60//! `rand(expression, expression)` generates a random 64-bit integer inclusively between the passed expressions.
61//! An error will be displayed if called incorrectly. `rand()` generates a random 64-bit integer.  
62//!   
63//! ## Numbers  
64//!   
65//! A number literal is a non-empty sequence of digits or a non-empty sequence of digits immediately followed by `.`
66//! which is immediately followed by a non-empty sequence of digits (e.g., `134.901`). This means that number
67//! literals represent precisely all rational numbers that are equivalent to a ratio of a non-negative integer
68//! to a positive integer whose sole prime factors are 2 or 5. To represent all other rational numbers, the unary
69//! operator `-` and binary operator `/` must be used.  
70//!   
71//! ## Empty expression  
72//!   
73//! The empty expression (i.e., expression that at most only consists of spaces and tabs) will return
74//! the result from the previous non-(empty/store) expression in *decimal* form using the minimum number of digits.
75//! In the event an infinite number of digits is required, it will be rounded to 9 fractional digits using normal rounding
76//! rules first.  
77//!   
78//! ## Store expression  
79//!   
80//! To store the result of the previous non-(empty/store) expression, one simply passes `s`. In addition to storing the
81//! result which will subsequently be available via `@`, it displays the result. At most 8 results can be stored at once;
82//! at which point, results that are stored overwrite the oldest result.  
83//!   
84//! ## Recall expression  
85//!   
86//! `@` is used to recall previously stored results. It can be followed by any *digit* from `1` to `8`.
87//! If such a digit does not immediately follow it, then it will be interpreted as if there were a `1`.
88//! `@i` returns the *i*-th most-previous stored result where *i ∈ {1, 2, 3, 4, 5, 6, 7, 8}*.
89//! Note that spaces and tabs are *not* ignored so `@ 2` is grammatically incorrect and will result in an error message.
90//! As emphasized, it does not work on expressions; so both `@@` and `@(1)` are grammatically incorrect.  
91//!   
92//! ## Character encoding  
93//!   
94//! All inputs must only contain the ASCII encoding of the following Unicode scalar values: `0`-`9`, `.`, `+`, `-`,
95//! `*`, `/`, `^`, `!`, `mod`, `|`, `(`, `)`, `round`, `rand`, `,`, `@`, `s`, &lt;space&gt;, &lt;tab&gt;,
96//! &lt;line feed&gt;, &lt;carriage return&gt;, and `q`. Any other byte sequences are grammatically incorrect and will
97//! lead to an error message.  
98//!   
99//! ## Errors  
100//!   
101//! Errors due to a language violation (e.g., dividing by `0`) manifest into an error message. `panic!`s
102//! and [`io::Error`](https://doc.rust-lang.org/std/io/struct.Error.html)s caused by writing to the global
103//! standard output stream lead to program abortion.  
104//!   
105//! ## Exiting  
106//!   
107//! `q` with any number of spaces and tabs before and after will cause the program to terminate.  
108//!   
109//! ### Formal language specification  
110//!   
111//! For a more precise specification of the “calc language”, one can read the
112//! [calc language specification](https://git.philomathiclife.com/calc_rational/lang.pdf).
113#![expect(
114    clippy::doc_paragraphs_missing_punctuation,
115    reason = "false positive for crate documentation having image links"
116)]
117#![expect(
118    clippy::arithmetic_side_effects,
119    reason = "calculator can't realistically avoid this"
120)]
121#![no_std]
122#![cfg_attr(docsrs, feature(doc_cfg))]
123extern crate alloc;
124/// Unit tests.
125#[cfg(test)]
126mod tests;
127use LangErr::{
128    DivByZero, ExpDivByZero, ExpIsNotIntOrOneHalf, InvalidAbs, InvalidDec, InvalidPar, InvalidQuit,
129    InvalidRound, InvalidStore, MissingTerm, ModIsNotInt, ModZero, NotEnoughPrevResults,
130    NotNonNegIntFact, SqrtDoesNotExist, TrailingSyms,
131};
132use O::{Empty, Eval, Exit, Store};
133use alloc::{
134    string::{String, ToString as _},
135    vec,
136    vec::Vec,
137};
138use cache::Cache;
139#[cfg(not(feature = "rand"))]
140use core::marker::PhantomData;
141use core::{
142    convert,
143    fmt::{self, Display, Formatter},
144    ops::Index as _,
145};
146pub use num_bigint;
147use num_bigint::{BigInt, BigUint, Sign};
148use num_integer::Integer as _;
149pub use num_rational;
150use num_rational::Ratio;
151#[cfg(feature = "rand")]
152use num_traits::ToPrimitive as _;
153use num_traits::{Inv as _, Pow as _};
154#[cfg(target_os = "openbsd")]
155use priv_sep as _;
156#[cfg(feature = "rand")]
157pub use rand;
158#[cfg(feature = "rand")]
159use rand::{Rng as _, rngs::ThreadRng};
160/// Fixed-sized cache that automatically overwrites the oldest data
161/// when a new item is added and the cache is full.
162///
163/// One can think of
164/// [`Cache`] as a very limited but more performant [`VecDeque`][alloc::collections::VecDeque] that only
165/// adds new data or reads old data.
166pub mod cache;
167/// Generalizes [`Iterator`] by using
168/// generic associated types.
169pub mod lending_iterator;
170/// Error due to a language violation.
171#[non_exhaustive]
172#[cfg_attr(test, derive(Eq, PartialEq))]
173#[derive(Debug)]
174pub enum LangErr {
175    /// The input began with a `q` but had non-whitespace
176    /// that followed it.
177    InvalidQuit,
178    /// The input began with an `s` but had non-whitespace
179    /// that followed it.
180    InvalidStore,
181    /// A sub-expression in the input would have led
182    /// to a division by zero.
183    DivByZero(usize),
184    /// A sub-expression in the input would have led
185    /// to a rational number that was not 0 or 1 to be
186    /// raised to a non-integer power that is not (+/-) 1/2.
187    ExpIsNotIntOrOneHalf(usize),
188    /// A sub-expression in the input would have led
189    /// to 0 being raised to a negative power which itself
190    /// would have led to a division by zero.
191    ExpDivByZero(usize),
192    /// A sub-expression in the input would have led
193    /// to a number modulo 0.
194    ModZero(usize),
195    /// A sub-expression in the input would have led
196    /// to the mod of two expressions with at least one
197    /// not being an integer.
198    ModIsNotInt(usize),
199    /// A sub-expression in the input would have led
200    /// to a non-integer factorial or a negative integer factorial.
201    NotNonNegIntFact(usize),
202    /// The input contained a non-empty sequence of digits followed
203    /// by `.` which was not followed by a non-empty sequence of digits.
204    InvalidDec(usize),
205    /// A recall expression was used to recall the *i*-th most-recent stored result,
206    /// but there are fewer than *i* stored where
207    /// *i ∈ {1, 2, 3, 4, 5, 6, 7, 8}*.
208    NotEnoughPrevResults(usize),
209    /// The input did not contain a closing `|`.
210    InvalidAbs(usize),
211    /// The input did not contain a closing `)`.
212    InvalidPar(usize),
213    /// The input contained an invalid round expression.
214    InvalidRound(usize),
215    /// A sub-expression in the input had a missing terminal expression
216    /// where a terminal expression is a decimal literal expression,
217    /// recall expression, absolute value expression, parenthetical
218    /// expression, or round expression.
219    MissingTerm(usize),
220    /// The expression that was passed to the square root does not have a solution
221    /// in the field of rational numbers.
222    SqrtDoesNotExist(usize),
223    /// The input started with a valid expression but was immediately followed
224    /// by symbols that could not be chained with the preceding expression.
225    TrailingSyms(usize),
226    /// The input contained an invalid random expression.
227    #[cfg(feature = "rand")]
228    InvalidRand(usize),
229    /// Error when the second argument is less than first in the rand function.
230    #[cfg(feature = "rand")]
231    RandInvalidArgs(usize),
232    /// Error when there are no 64-bit integers in the interval passed to the random function.
233    #[cfg(feature = "rand")]
234    RandNoInts(usize),
235}
236impl Display for LangErr {
237    #[inline]
238    fn fmt(&self, f: &mut Formatter<'_>) -> fmt::Result {
239        match *self {
240            InvalidStore => f.write_str("Invalid store expression. A store expression must be of the extended regex form: ^[ \\t]*s[ \\t]*$."),
241            InvalidQuit => f.write_str("Invalid quit expression. A quit expression must be of the extended regex form: ^[ \\t]*q[ \\t]*$."),
242            DivByZero(u) => write!(f, "Division by zero ending at position {u}."),
243            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}."),
244            ExpDivByZero(u) => write!(f, "Non-negative exponent with a base of 0 ending at position {u}."),
245            ModZero(u) => write!(f, "A number modulo 0 ending at position {u}."),
246            ModIsNotInt(u) => write!(f, "The modulo expression was applied to at least one non-integer ending at position {u}."),
247            NotNonNegIntFact(u) => write!(f, "Factorial of a rational number that was not a non-negative integer ending at position {u}."),
248            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]+)?."),
249            NotEnoughPrevResults(len) => write!(f, "There are only {len} previous results."),
250            InvalidAbs(u) => write!(f, "Invalid absolute value expression ending at position {u}. An absolute value expression is an addition expression enclosed in '||'."),
251            InvalidPar(u) => write!(f, "Invalid parenthetical expression ending at position {u}. A parenthetical expression is an addition expression enclosed in '()'."),
252            InvalidRound(u) => write!(f, "Invalid round expression ending at position {u}. A round expression is of the form 'round(<mod expression>, digit)'"),
253            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}."),
254            #[cfg(not(feature = "rand"))]
255            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."),
256            #[cfg(feature = "rand")]
257            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."),
258            TrailingSyms(u) => write!(f, "Trailing symbols starting at position {u}."),
259            #[cfg(feature = "rand")]
260            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>)'."),
261            #[cfg(feature = "rand")]
262            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}."),
263            #[cfg(feature = "rand")]
264            Self::RandNoInts(u) => write!(f, "There are no 64-bit integers within the interval passed to the random function ending at position {u}."),
265        }
266    }
267}
268/// A successful evaluation of an input.
269#[cfg_attr(test, derive(Eq, PartialEq))]
270#[derive(Debug)]
271pub enum O<'a> {
272    /// The input only contained whitespace.
273    /// This returns the previous `Eval`.
274    /// It is `None` iff there have been no
275    /// previous `Eval` results.
276    Empty(&'a Option<Ratio<BigInt>>),
277    /// The quit expression was issued to terminate the program.
278    Exit,
279    /// Result of a "normal" expression.
280    Eval(&'a Ratio<BigInt>),
281    /// The store expression stores and returns the previous `Eval`.
282    /// It is `None` iff there have been no previous `Eval` results.
283    Store(&'a Option<Ratio<BigInt>>),
284}
285impl Display for O<'_> {
286    #[expect(
287        unsafe_code,
288        reason = "manually construct guaranteed UTF-8; thus avoid the needless check"
289    )]
290    #[expect(clippy::indexing_slicing, reason = "comment justifies correctness")]
291    #[inline]
292    fn fmt(&self, f: &mut Formatter<'_>) -> fmt::Result {
293        match *self {
294            Empty(o) => {
295                o.as_ref().map_or(Ok(()), |val| {
296                    if val.is_integer() {
297                        write!(f, "> {val}")
298                    } else {
299                        // If the prime factors of the denominator are only 2 and 5,
300                        // then the number requires a finite number of digits and thus
301                        // will be represented perfectly using the fewest number of digits.
302                        // Any other situation will be rounded to 9 fractional digits.
303                        // max{twos, fives} represents the minimum number of fractional
304                        // digits necessary to represent val.
305                        let mut twos = 0;
306                        let mut fives = 0;
307                        let zero = BigInt::from_biguint(Sign::NoSign, BigUint::new(Vec::new()));
308                        let one = BigInt::from_biguint(Sign::Plus, BigUint::new(vec![1]));
309                        let two = BigInt::from_biguint(Sign::Plus, BigUint::new(vec![2]));
310                        let five = BigInt::from_biguint(Sign::Plus, BigUint::new(vec![5]));
311                        let mut denom = val.denom().clone();
312                        let mut div_rem;
313                        while denom > one {
314                            div_rem = denom.div_rem(&two);
315                            if div_rem.1 == zero {
316                                twos += 1;
317                                denom = div_rem.0;
318                            } else {
319                                break;
320                            }
321                        }
322                        while denom > one {
323                            div_rem = denom.div_rem(&five);
324                            if div_rem.1 == zero {
325                                fives += 1;
326                                denom = div_rem.0;
327                            } else {
328                                break;
329                            }
330                        }
331                        // int < 0 iff val <= -1. frac < 0 iff val is a negative non-integer.
332                        let (int, frac, digits) = if denom == one {
333                            let (int, mut frac) = val.numer().div_rem(val.denom());
334                            while twos > fives {
335                                frac *= &five;
336                                fives += 1;
337                            }
338                            while fives > twos {
339                                frac *= &two;
340                                twos += 1;
341                            }
342                            (int, frac, twos)
343                        } else {
344                            // Requires an infinite number of decimal digits to represent, so we display
345                            // 9 digits after rounding.
346                            let mult =
347                                BigInt::from_biguint(Sign::Plus, BigUint::new(vec![10])).pow(9u8);
348                            let (int, frac) = (val * &mult).round().numer().div_rem(&mult);
349                            (int, frac, 9)
350                        };
351                        let int_str = int.to_string().into_bytes();
352                        let (mut v, frac_str) = if val.numer().sign() == Sign::Minus {
353                            // Guaranteed to be non-empty.
354                            if int_str[0] == b'-' {
355                                (
356                                    Vec::with_capacity(int_str.len() + 1 + digits),
357                                    (-frac).to_string().into_bytes(),
358                                )
359                            } else {
360                                let mut tmp = Vec::with_capacity(int_str.len() + 2 + digits);
361                                tmp.push(b'-');
362                                (tmp, (-frac).to_string().into_bytes())
363                            }
364                        } else {
365                            (
366                                Vec::with_capacity(int_str.len() + 1 + digits),
367                                frac.to_string().into_bytes(),
368                            )
369                        };
370                        v.extend_from_slice(int_str.as_slice());
371                        v.push(b'.');
372                        // digits >= frac_str.len().
373                        v.resize(v.len() + (digits - frac_str.len()), b'0');
374                        v.extend_from_slice(frac_str.as_slice());
375                        // SAFETY:
376                        // v contains precisely the UTF-8 code units returned from Strings
377                        // returned from the to_string function on the integer and fraction part of
378                        // val plus optionally the single byte encodings of ".", "-", and "0".
379                        write!(f, "> {}", unsafe { String::from_utf8_unchecked(v) })
380                    }
381                })
382            }
383            Eval(r) => write!(f, "> {r}"),
384            Exit => Ok(()),
385            Store(o) => o.as_ref().map_or(Ok(()), |val| write!(f, "> {val}")),
386        }
387    }
388}
389/// Size of [`Evaluator::cache`].
390const CACHE_SIZE: usize = 8;
391/// Evaluates the supplied input.
392#[derive(Debug)]
393pub struct Evaluator<'input, 'cache, 'prev, 'scratch, 'rand> {
394    /// The input to be evaluated.
395    utf8: &'input [u8],
396    /// The index within `utf8` that evaluation needs to continue.
397    /// We use this instead of slicing from `utf8` since we want
398    /// to be able to report the position within the input
399    /// that an error occurs.
400    i: usize,
401    /// The cache of previously stored results.
402    cache: &'cache mut Cache<Ratio<BigInt>, CACHE_SIZE>,
403    /// The last result.
404    prev: &'prev mut Option<Ratio<BigInt>>,
405    /// Buffer used to evaluate right-associative sub-expressions.
406    scratch: &'scratch mut Vec<Ratio<BigInt>>,
407    /// Random number generator.
408    #[cfg(feature = "rand")]
409    rng: &'rand mut ThreadRng,
410    /// Need to use `'rand`.
411    #[cfg(not(feature = "rand"))]
412    _rng: PhantomData<fn() -> &'rand ()>,
413}
414#[allow(
415    single_use_lifetimes,
416    clippy::allow_attributes,
417    clippy::elidable_lifetime_names,
418    reason = "unify rand and not rand"
419)]
420impl<'input, 'cache, 'prev, 'scratch, 'rand> Evaluator<'input, 'cache, 'prev, 'scratch, 'rand> {
421    /// Creates an `Evaluator<'input, 'cache, 'prev, 'scratch, 'rand>` based on the supplied arguments.
422    #[cfg(not(feature = "rand"))]
423    #[inline]
424    pub fn new(
425        utf8: &'input [u8],
426        cache: &'cache mut Cache<Ratio<BigInt>, 8>,
427        prev: &'prev mut Option<Ratio<BigInt>>,
428        scratch: &'scratch mut Vec<Ratio<BigInt>>,
429    ) -> Self {
430        Self {
431            utf8,
432            i: 0,
433            cache,
434            prev,
435            scratch,
436            _rng: PhantomData,
437        }
438    }
439    /// Creates an `Evaluator<'input, 'cache, 'prev, 'scratch, 'rand>` based on the supplied arguments.
440    #[cfg(feature = "rand")]
441    #[inline]
442    pub const fn new(
443        utf8: &'input [u8],
444        cache: &'cache mut Cache<Ratio<BigInt>, 8>,
445        prev: &'prev mut Option<Ratio<BigInt>>,
446        scratch: &'scratch mut Vec<Ratio<BigInt>>,
447        rng: &'rand mut ThreadRng,
448    ) -> Self {
449        Self {
450            utf8,
451            i: 0,
452            cache,
453            prev,
454            scratch,
455            rng,
456        }
457    }
458    /// Evaluates the input consuming the `Evaluator<'input, 'cache, 'exp>`.
459    ///
460    /// Requires the input to contain one expression (i.e., if there are
461    /// multiple newlines, it will error).
462    ///
463    /// # Errors
464    ///
465    /// Returns a [`LangErr`] iff the input violates the calc language.
466    #[expect(clippy::indexing_slicing, reason = "correct")]
467    #[inline]
468    pub fn evaluate(mut self) -> Result<O<'prev>, LangErr> {
469        self.utf8 = if self.utf8.last().is_none_or(|b| *b != b'\n') {
470            self.utf8
471        } else {
472            &self.utf8[..self.utf8.len()
473                - self
474                    .utf8
475                    .get(self.utf8.len().wrapping_sub(2))
476                    .map_or(1, |b| if *b == b'\r' { 2 } else { 1 })]
477        };
478        self.consume_ws();
479        let Some(b) = self.utf8.get(self.i) else {
480            return Ok(Empty(self.prev));
481        };
482        if *b == b'q' {
483            self.i += 1;
484            self.consume_ws();
485            if self.i == self.utf8.len() {
486                Ok(Exit)
487            } else {
488                Err(InvalidQuit)
489            }
490        } else if *b == b's' {
491            self.i += 1;
492            self.consume_ws();
493            if self.i == self.utf8.len() {
494                if let Some(ref val) = *self.prev {
495                    self.cache.push(val.clone());
496                }
497                Ok(Store(self.prev))
498            } else {
499                Err(InvalidStore)
500            }
501        } else {
502            self.get_adds().and_then(move |val| {
503                self.consume_ws();
504                if self.i == self.utf8.len() {
505                    Ok(Eval(self.prev.insert(val)))
506                } else {
507                    Err(TrailingSyms(self.i))
508                }
509            })
510        }
511    }
512    /// Reads from the input until the next non-{space/tab} byte value.
513    #[expect(clippy::indexing_slicing, reason = "correct")]
514    fn consume_ws(&mut self) {
515        // ControlFlow makes more sense to use in try_fold; however due to a lack
516        // of a map_or_else function, it is easier to simply return a Result with
517        // Err taking the role of ControlFlow::Break.
518        self.i += self.utf8[self.i..]
519            .iter()
520            .try_fold(0, |val, b| match *b {
521                b' ' | b'\t' => Ok(val + 1),
522                _ => Err(val),
523            })
524            .unwrap_or_else(convert::identity);
525    }
526    /// Evaluates addition expressions as defined in the calc language.
527    /// This function is used for both addition and subtraction operations which
528    /// themselves are based on multiplication expressions.
529    fn get_adds(&mut self) -> Result<Ratio<BigInt>, LangErr> {
530        let mut left = self.get_mults()?;
531        let mut j;
532        self.consume_ws();
533        while let Some(i) = self.utf8.get(self.i) {
534            j = *i;
535            self.consume_ws();
536            if j == b'+' {
537                self.i += 1;
538                self.consume_ws();
539                left += self.get_mults()?;
540            } else if j == b'-' {
541                self.i += 1;
542                self.consume_ws();
543                left -= self.get_mults()?;
544            } else {
545                break;
546            }
547        }
548        Ok(left)
549    }
550    /// Evaluates multiplication expressions as defined in the calc language.
551    /// This function is used for both multiplication and division operations which
552    /// themselves are based on negation expressions.
553    fn get_mults(&mut self) -> Result<Ratio<BigInt>, LangErr> {
554        let mut left = self.get_neg()?;
555        let mut right;
556        let mut j;
557        let mut mod_val;
558        let mut numer;
559        self.consume_ws();
560        while let Some(i) = self.utf8.get(self.i) {
561            j = *i;
562            self.consume_ws();
563            if j == b'*' {
564                self.i += 1;
565                self.consume_ws();
566                left *= self.get_neg()?;
567            } else if j == b'/' {
568                self.i += 1;
569                self.consume_ws();
570                right = self.get_neg()?;
571                if right.numer().sign() == Sign::NoSign {
572                    return Err(DivByZero(self.i));
573                }
574                left /= right;
575            } else if let Some(k) = self.utf8.get(self.i..self.i.saturating_add(3)) {
576                if k == b"mod" {
577                    if !left.is_integer() {
578                        return Err(ModIsNotInt(self.i));
579                    }
580                    self.i += 3;
581                    self.consume_ws();
582                    right = self.get_neg()?;
583                    if !right.is_integer() {
584                        return Err(ModIsNotInt(self.i));
585                    }
586                    numer = right.numer();
587                    if numer.sign() == Sign::NoSign {
588                        return Err(ModZero(self.i));
589                    }
590                    mod_val = left.numer() % numer;
591                    left = Ratio::from_integer(if mod_val.sign() == Sign::Minus {
592                        if numer.sign() == Sign::Minus {
593                            mod_val - numer
594                        } else {
595                            mod_val + numer
596                        }
597                    } else {
598                        mod_val
599                    });
600                } else {
601                    break;
602                }
603            } else {
604                break;
605            }
606        }
607        Ok(left)
608    }
609    /// Evaluates negation expressions as defined in the calc language.
610    /// This function is based on exponentiation expressions.
611    fn get_neg(&mut self) -> Result<Ratio<BigInt>, LangErr> {
612        let mut count = 0usize;
613        while let Some(b) = self.utf8.get(self.i) {
614            if *b == b'-' {
615                self.i += 1;
616                self.consume_ws();
617                count += 1;
618            } else {
619                break;
620            }
621        }
622        self.get_exps()
623            .map(|val| if count & 1 == 0 { val } else { -val })
624    }
625    /// Gets the square root of value so long as a solution exists.
626    #[expect(
627        clippy::unreachable,
628        reason = "code that shouldn't happen did, so we want to crash"
629    )]
630    fn sqrt(val: Ratio<BigInt>) -> Option<Ratio<BigInt>> {
631        /// Returns the square root of `n` if one exists; otherwise
632        /// returns `None`.
633        /// MUST NOT pass 0.
634        #[expect(clippy::suspicious_operation_groupings, reason = "false positive")]
635        fn calc(n: &BigUint) -> Option<BigUint> {
636            let mut shift = n.bits();
637            shift += shift & 1;
638            let mut result = BigUint::new(Vec::new());
639            let one = BigUint::new(vec![1]);
640            let zero = BigUint::new(Vec::new());
641            loop {
642                shift -= 2;
643                result <<= 1u32;
644                result |= &one;
645                result ^= if &result * &result > (n >> shift) {
646                    &one
647                } else {
648                    &zero
649                };
650                if shift == 0 {
651                    break (&result * &result == *n).then_some(result);
652                }
653            }
654        }
655        let numer = val.numer();
656        if numer.sign() == Sign::NoSign {
657            Some(val)
658        } else {
659            numer.try_into().map_or_else(
660                |_| None,
661                |num| {
662                    calc(&num).and_then(|n| {
663                        calc(&val.denom().try_into().unwrap_or_else(|_| {
664                            unreachable!("Ratio must never have a negative denominator")
665                        }))
666                        .map(|d| Ratio::new(n.into(), d.into()))
667                    })
668                },
669            )
670        }
671    }
672    /// Evaluates exponentiation expressions as defined in the calc language.
673    /// This function is based on negation expressions.
674    fn get_exps(&mut self) -> Result<Ratio<BigInt>, LangErr> {
675        let mut t = self.get_fact()?;
676        let ix = self.scratch.len();
677        let mut prev;
678        let mut numer;
679        self.scratch.push(t);
680        self.consume_ws();
681        let mut j;
682        let one = BigInt::new(Sign::Plus, vec![1]);
683        let min_one = BigInt::new(Sign::Minus, vec![1]);
684        let two = BigInt::new(Sign::Plus, vec![2]);
685        while let Some(i) = self.utf8.get(self.i) {
686            j = *i;
687            self.consume_ws();
688            if j == b'^' {
689                self.i += 1;
690                self.consume_ws();
691                t = self.get_neg()?;
692                // Safe since we always push at least one value, and we always
693                // return immediately once we encounter an error.
694                prev = self.scratch.index(self.scratch.len() - 1);
695                numer = prev.numer();
696                // Equiv to checking if prev is 0.
697                if numer.sign() == Sign::NoSign {
698                    if t.numer().sign() == Sign::Minus {
699                        self.scratch.clear();
700                        return Err(ExpDivByZero(self.i));
701                    }
702                    self.scratch.push(t);
703                } else if prev.is_integer() {
704                    let t_numer = t.numer();
705                    // 1 raised to anything is 1, so we don't bother
706                    // storing the exponent.
707                    if *numer == one {
708                    } else if t.is_integer()
709                        || ((*t_numer == one || *t_numer == min_one) && *t.denom() == two)
710                    {
711                        self.scratch.push(t);
712                    } else {
713                        self.scratch.clear();
714                        return Err(ExpIsNotIntOrOneHalf(self.i));
715                    }
716                } else if t.is_integer()
717                    || ((*t.numer() == one || *t.numer() == min_one) && *t.denom() == two)
718                {
719                    self.scratch.push(t);
720                } else {
721                    self.scratch.clear();
722                    return Err(ExpIsNotIntOrOneHalf(self.i));
723                }
724            } else {
725                break;
726            }
727        }
728        self.scratch
729            .drain(ix..)
730            .try_rfold(Ratio::from_integer(one.clone()), |exp, base| {
731                if exp.is_integer() {
732                    Ok(base.pow(exp.numer()))
733                } else if base.numer().sign() == Sign::NoSign {
734                    Ok(base)
735                } else if *exp.denom() == two {
736                    if *exp.numer() == one {
737                        Self::sqrt(base).map_or_else(|| Err(SqrtDoesNotExist(self.i)), Ok)
738                    } else if *exp.numer() == min_one {
739                        Self::sqrt(base)
740                            .map_or_else(|| Err(SqrtDoesNotExist(self.i)), |v| Ok(v.inv()))
741                    } else {
742                        Err(ExpIsNotIntOrOneHalf(self.i))
743                    }
744                } else {
745                    Err(ExpIsNotIntOrOneHalf(self.i))
746                }
747            })
748    }
749    /// Evaluates factorial expressions as defined in the calc language.
750    /// This function is based on terminal expressions.
751    fn get_fact(&mut self) -> Result<Ratio<BigInt>, LangErr> {
752        /// Calculates the factorial of `val`.
753        fn fact(mut val: BigUint) -> BigUint {
754            let zero = BigUint::new(Vec::new());
755            let one = BigUint::new(vec![1]);
756            let mut calc = BigUint::new(vec![1]);
757            while val > zero {
758                calc *= &val;
759                val -= &one;
760            }
761            calc
762        }
763        let t = self.get_term()?;
764        let Some(b) = self.utf8.get(self.i) else {
765            return Ok(t);
766        };
767        if *b == b'!' {
768            self.i += 1;
769            if t.is_integer() {
770                // We can make a copy of self.i here, or call map_or instead
771                // of map_or_else.
772                let i = self.i;
773                t.numer().try_into().map_or_else(
774                    |_| Err(NotNonNegIntFact(i)),
775                    |val| {
776                        let mut factorial = fact(val);
777                        while let Some(b2) = self.utf8.get(self.i) {
778                            if *b2 == b'!' {
779                                self.i += 1;
780                                factorial = fact(factorial);
781                            } else {
782                                break;
783                            }
784                        }
785                        Ok(Ratio::from_integer(BigInt::from_biguint(
786                            Sign::Plus,
787                            factorial,
788                        )))
789                    },
790                )
791            } else {
792                Err(NotNonNegIntFact(self.i))
793            }
794        } else {
795            Ok(t)
796        }
797    }
798    /// Evaluates terminal expressions as defined in the calc language.
799    /// This function is based on number literal expressions, parenthetical expressions,
800    /// recall expressions, absolute value expressions, round expressions, and possibly
801    /// rand expressions if that feature is enabled.
802    fn get_term(&mut self) -> Result<Ratio<BigInt>, LangErr> {
803        self.get_rational().map_or_else(Err, |o| {
804            o.map_or_else(
805                || {
806                    self.get_par().map_or_else(Err, |o2| {
807                        o2.map_or_else(
808                            || {
809                                self.get_recall().map_or_else(Err, |o3| {
810                                    o3.map_or_else(
811                                        || {
812                                            self.get_abs().map_or_else(Err, |o4| {
813                                                o4.map_or_else(
814                                                    || {
815                                                        self.get_round().and_then(|o5| {
816                                                            o5.map_or_else(
817                                                                #[cfg(not(feature = "rand"))]
818                                                                || Err(MissingTerm(self.i)),
819                                                                #[cfg(feature = "rand")]
820                                                                || self.get_rand(),
821                                                                Ok,
822                                                            )
823                                                        })
824                                                    },
825                                                    Ok,
826                                                )
827                                            })
828                                        },
829                                        Ok,
830                                    )
831                                })
832                            },
833                            Ok,
834                        )
835                    })
836                },
837                Ok,
838            )
839        })
840    }
841    /// Generates a random 64-bit integer. This function is based on add expressions. This is the last terminal
842    /// expression attempted when needing a terminal expression; as a result, it is the only terminal expression
843    /// that does not return an `Option`.
844    #[cfg(feature = "rand")]
845    fn get_rand(&mut self) -> Result<Ratio<BigInt>, LangErr> {
846        /// Generates a random 64-bit integer.
847        #[expect(clippy::host_endian_bytes, reason = "must keep platform endianness")]
848        fn rand(rng: &mut ThreadRng) -> i64 {
849            let mut bytes = [0; 8];
850            // `ThreadRng::try_fill_bytes` is infallible, so easier to call `fill_bytes`.
851            rng.fill_bytes(&mut bytes);
852            i64::from_ne_bytes(bytes)
853        }
854        /// Generates a random 64-bit integer inclusively between the passed arguments.
855        #[expect(
856            clippy::integer_division_remainder_used,
857            reason = "need for uniform randomness"
858        )]
859        #[expect(
860            clippy::as_conversions,
861            clippy::cast_possible_truncation,
862            clippy::cast_possible_wrap,
863            clippy::cast_sign_loss,
864            reason = "lossless conversions between signed integers"
865        )]
866        fn rand_range(
867            rng: &mut ThreadRng,
868            lower: &Ratio<BigInt>,
869            upper: &Ratio<BigInt>,
870            i: usize,
871        ) -> Result<i64, LangErr> {
872            if lower > upper {
873                return Err(LangErr::RandInvalidArgs(i));
874            }
875            let lo = lower.ceil();
876            let up = upper.floor();
877            let lo_int = lo.numer();
878            let up_int = up.numer();
879            if lo_int > &BigInt::from(i64::MAX) || up_int < &BigInt::from(i64::MIN) {
880                return Err(LangErr::RandNoInts(i));
881            }
882            let lo_min = lo_int.to_i64().unwrap_or(i64::MIN);
883            let up_max = up_int.to_i64().unwrap_or(i64::MAX);
884            if up_max > lo_min || upper.is_integer() || lower.is_integer() {
885                let low = i128::from(lo_min);
886                // `i64::MAX >= up_max >= low`; so underflow and overflow cannot happen.
887                // range is [1, 2^64] so casting to a u128 is fine.
888                let modulus = (i128::from(up_max) - low + 1) as u128;
889                // range is [0, i64::MAX] so converting to a `u64` is fine.
890                // rem represents how many values need to be removed
891                // when generating a random i64 in order for uniformity.
892                let rem = (0x0001_0000_0000_0000_0000 % modulus) as u64;
893                let mut low_adj;
894                loop {
895                    low_adj = rand(rng) as u64;
896                    // Since rem is in [0, i64::MAX], this is the same as low_adj < 0 || low_adj >= rem.
897                    if low_adj >= rem {
898                        return Ok(
899                            // range is [i64::MIN, i64::MAX]; thus casts are safe.
900                            // modulus is up_max - low + 1; so as low grows,
901                            // % shrinks by the same factor. i64::MAX happens
902                            // when low = up_max = i64::MAX or when low = 0,
903                            // up_max = i64::MAX and low_adj is i64::MAX.
904                            ((u128::from(low_adj) % modulus) as i128 + low) as i64,
905                        );
906                    }
907                }
908            } else {
909                Err(LangErr::RandNoInts(i))
910            }
911        }
912        // This is the last kind of terminal expression that is attempted.
913        // If there is no more data, then we have a missing terminal expression.
914        let Some(b) = self.utf8.get(self.i..self.i.saturating_add(5)) else {
915            return Err(MissingTerm(self.i));
916        };
917        if b == b"rand(" {
918            self.i += 5;
919            self.consume_ws();
920            let i = self.i;
921            self.utf8.get(self.i).map_or_else(
922                || Err(LangErr::InvalidRand(i)),
923                |p| {
924                    if *p == b')' {
925                        self.i += 1;
926                        Ok(Ratio::from_integer(BigInt::from(rand(self.rng))))
927                    } else {
928                        let add = self.get_adds()?;
929                        let Some(b2) = self.utf8.get(self.i) else {
930                            return Err(LangErr::InvalidRand(self.i));
931                        };
932                        if *b2 == b',' {
933                            self.i += 1;
934                            self.consume_ws();
935                            let add2 = self.get_adds()?;
936                            self.consume_ws();
937                            let Some(b3) = self.utf8.get(self.i) else {
938                                return Err(LangErr::InvalidRand(self.i));
939                            };
940                            if *b3 == b')' {
941                                self.i += 1;
942                                rand_range(self.rng, &add, &add2, self.i)
943                                    .map(|v| Ratio::from_integer(BigInt::from(v)))
944                            } else {
945                                Err(LangErr::InvalidRand(self.i))
946                            }
947                        } else {
948                            Err(LangErr::InvalidRand(self.i))
949                        }
950                    }
951                },
952            )
953        } else {
954            Err(MissingTerm(self.i))
955        }
956    }
957    /// Rounds a value to the specified number of fractional digits.
958    /// This function is based on add expressions.
959    fn get_round(&mut self) -> Result<Option<Ratio<BigInt>>, LangErr> {
960        let Some(b) = self.utf8.get(self.i..self.i.saturating_add(6)) else {
961            return Ok(None);
962        };
963        if b == b"round(" {
964            self.i += 6;
965            self.consume_ws();
966            let val = self.get_adds()?;
967            self.consume_ws();
968            let Some(b2) = self.utf8.get(self.i) else {
969                return Err(InvalidRound(self.i));
970            };
971            let b3 = *b2;
972            if b3 == b',' {
973                self.i += 1;
974                self.consume_ws();
975                let Some(b4) = self.utf8.get(self.i) else {
976                    return Err(InvalidRound(self.i));
977                };
978                let r = if b4.is_ascii_digit() {
979                    self.i += 1;
980                    *b4 - b'0'
981                } else {
982                    return Err(InvalidRound(self.i));
983                };
984                self.consume_ws();
985                let i = self.i;
986                self.utf8.get(self.i).map_or_else(
987                    || Err(InvalidRound(i)),
988                    |p| {
989                        if *p == b')' {
990                            self.i += 1;
991                            let mult =
992                                BigInt::from_biguint(Sign::Plus, BigUint::new(vec![10])).pow(r);
993                            Ok(Some((val * &mult).round() / &mult))
994                        } else {
995                            Err(InvalidRound(self.i))
996                        }
997                    },
998                )
999            } else {
1000                Err(InvalidRound(self.i))
1001            }
1002        } else {
1003            Ok(None)
1004        }
1005    }
1006    /// Evaluates absolute value expressions as defined in the calc language.
1007    /// This function is based on add expressions.
1008    fn get_abs(&mut self) -> Result<Option<Ratio<BigInt>>, LangErr> {
1009        let Some(b) = self.utf8.get(self.i) else {
1010            return Ok(None);
1011        };
1012        if *b == b'|' {
1013            self.i += 1;
1014            self.consume_ws();
1015            let r = self.get_adds()?;
1016            self.consume_ws();
1017            let Some(b2) = self.utf8.get(self.i) else {
1018                return Err(InvalidAbs(self.i));
1019            };
1020            let b3 = *b2;
1021            if b3 == b'|' {
1022                self.i += 1;
1023                Ok(Some(if r.numer().sign() == Sign::Minus {
1024                    -r
1025                } else {
1026                    r
1027                }))
1028            } else {
1029                Err(InvalidAbs(self.i))
1030            }
1031        } else {
1032            Ok(None)
1033        }
1034    }
1035    /// Evaluates recall expressions as defined in the calc language.
1036    // This does not return a Result<Option<&Ratio<BigInt>>, LangErr>
1037    // since the only place this function is called is in get_term which
1038    // would end up needing to clone the Ratio anyway. By not forcing
1039    // get_term to clone, it can rely on map_or_else over match expressions.
1040    fn get_recall(&mut self) -> Result<Option<Ratio<BigInt>>, LangErr> {
1041        let Some(b) = self.utf8.get(self.i) else {
1042            return Ok(None);
1043        };
1044        if *b == b'@' {
1045            self.i += 1;
1046            self.cache
1047                .get(self.utf8.get(self.i).map_or(0, |b2| {
1048                    if (b'1'..b'9').contains(b2) {
1049                        self.i += 1;
1050                        usize::from(*b2 - b'1')
1051                    } else {
1052                        0
1053                    }
1054                }))
1055                .map_or_else(
1056                    || Err(NotEnoughPrevResults(self.cache.len())),
1057                    |p| Ok(Some(p.clone())),
1058                )
1059        } else {
1060            Ok(None)
1061        }
1062    }
1063    /// Evaluates parenthetical expressions as defined in the calc language.
1064    /// This function is based on add expressions.
1065    fn get_par(&mut self) -> Result<Option<Ratio<BigInt>>, LangErr> {
1066        let Some(b) = self.utf8.get(self.i) else {
1067            return Ok(None);
1068        };
1069        if *b == b'(' {
1070            self.i += 1;
1071            self.consume_ws();
1072            let r = self.get_adds()?;
1073            self.consume_ws();
1074            let Some(b2) = self.utf8.get(self.i) else {
1075                return Err(InvalidPar(self.i));
1076            };
1077            let b3 = *b2;
1078            if b3 == b')' {
1079                self.i += 1;
1080                Ok(Some(r))
1081            } else {
1082                Err(InvalidPar(self.i))
1083            }
1084        } else {
1085            Ok(None)
1086        }
1087    }
1088    /// Evaluates number literal expressions as defined in the calc language.
1089    #[expect(clippy::indexing_slicing, reason = "correct")]
1090    fn get_rational(&mut self) -> Result<Option<Ratio<BigInt>>, LangErr> {
1091        // ControlFlow makes more sense to use in try_fold; however due to a lack
1092        // of a map_or_else function, it is easier to simply return a Result with
1093        // Err taking the role of ControlFlow::Break.
1094        /// Used to parse a sequence of digits into an unsigned integer.
1095        fn to_biguint(v: &[u8]) -> (BigUint, usize) {
1096            v.iter()
1097                .try_fold((BigUint::new(Vec::new()), 0), |mut prev, d| {
1098                    if d.is_ascii_digit() {
1099                        prev.1 += 1;
1100                        // `*d - b'0'` is guaranteed to return a integer between 0 and 9.
1101                        prev.0 = prev.0 * 10u8 + (*d - b'0');
1102                        Ok(prev)
1103                    } else {
1104                        Err(prev)
1105                    }
1106                })
1107                .unwrap_or_else(convert::identity)
1108        }
1109        let (int, len) = to_biguint(&self.utf8[self.i..]);
1110        if len == 0 {
1111            return Ok(None);
1112        }
1113        self.i += len;
1114        if let Some(b) = self.utf8.get(self.i) {
1115            if *b == b'.' {
1116                self.i += 1;
1117                let (numer, len2) = to_biguint(&self.utf8[self.i..]);
1118                if len2 == 0 {
1119                    Err(InvalidDec(self.i))
1120                } else {
1121                    self.i += len2;
1122                    Ok(Some(
1123                        Ratio::from_integer(BigInt::from_biguint(Sign::Plus, int))
1124                            + Ratio::new(
1125                                BigInt::from_biguint(Sign::Plus, numer),
1126                                BigInt::from_biguint(Sign::Plus, BigUint::new(vec![10]).pow(len2)),
1127                            ),
1128                    ))
1129                }
1130            } else {
1131                Ok(Some(Ratio::from_integer(BigInt::from_biguint(
1132                    Sign::Plus,
1133                    int,
1134                ))))
1135            }
1136        } else {
1137            Ok(Some(Ratio::from_integer(BigInt::from_biguint(
1138                Sign::Plus,
1139                int,
1140            ))))
1141        }
1142    }
1143}
1144/// Reads data from `R` passing each line to an [`Evaluator`] to be evaluated.
1145#[cfg(feature = "std")]
1146#[derive(Debug)]
1147pub struct EvalIter<R> {
1148    /// Reader that contains input data.
1149    reader: R,
1150    /// Buffer that is used by `reader` to read
1151    /// data into.
1152    input_buffer: Vec<u8>,
1153    /// Cache of stored results.
1154    cache: Cache<Ratio<BigInt>, 8>,
1155    /// Result of the previous expression.
1156    prev: Option<Ratio<BigInt>>,
1157    /// Buffer used by [`Evaluator`] to process
1158    /// sub-expressions.
1159    exp_buffer: Vec<Ratio<BigInt>>,
1160    /// Random number generator.
1161    #[cfg(feature = "rand")]
1162    rng: ThreadRng,
1163}
1164#[cfg(feature = "std")]
1165impl<R> EvalIter<R> {
1166    /// Creates a new `EvalIter`.
1167    #[cfg(feature = "rand")]
1168    #[inline]
1169    pub fn new(reader: R) -> Self {
1170        Self {
1171            reader,
1172            input_buffer: Vec::new(),
1173            cache: Cache::new(),
1174            prev: None,
1175            exp_buffer: Vec::new(),
1176            rng: rand::rng(),
1177        }
1178    }
1179    /// Creates a new `EvalIter`.
1180    #[cfg(any(doc, not(feature = "rand")))]
1181    #[inline]
1182    pub fn new(reader: R) -> Self {
1183        Self {
1184            reader,
1185            input_buffer: Vec::new(),
1186            cache: Cache::new(),
1187            prev: None,
1188            exp_buffer: Vec::new(),
1189        }
1190    }
1191}
1192#[cfg(feature = "std")]
1193extern crate std;
1194#[cfg(feature = "std")]
1195use std::io::{BufRead, Error};
1196/// Error returned from [`EvalIter`] when an expression has an error.
1197#[cfg(feature = "std")]
1198#[derive(Debug)]
1199pub enum E {
1200    /// Error containing [`Error`] which is returned
1201    /// from [`EvalIter`] when reading from the supplied
1202    /// [`BufRead`]er.
1203    Error(Error),
1204    /// Error containing [`LangErr`] which is returned
1205    /// from [`EvalIter`] when evaluating a single expression.
1206    LangErr(LangErr),
1207}
1208#[cfg(feature = "std")]
1209impl Display for E {
1210    #[inline]
1211    fn fmt(&self, f: &mut Formatter<'_>) -> fmt::Result {
1212        match *self {
1213            Self::Error(ref e) => e.fmt(f),
1214            Self::LangErr(ref e) => e.fmt(f),
1215        }
1216    }
1217}
1218#[cfg(feature = "std")]
1219use crate::lending_iterator::LendingIterator;
1220#[cfg(feature = "std")]
1221impl<R> LendingIterator for EvalIter<R>
1222where
1223    R: BufRead,
1224{
1225    type Item<'a>
1226        = Result<O<'a>, E>
1227    where
1228        Self: 'a;
1229    #[inline]
1230    fn lend_next(&mut self) -> Option<Result<O<'_>, E>> {
1231        self.input_buffer.clear();
1232        self.exp_buffer.clear();
1233        self.reader
1234            .read_until(b'\n', &mut self.input_buffer)
1235            .map_or_else(
1236                |e| Some(Err(E::Error(e))),
1237                |c| {
1238                    if c == 0 {
1239                        None
1240                    } else {
1241                        Evaluator::new(
1242                            self.input_buffer.as_slice(),
1243                            &mut self.cache,
1244                            &mut self.prev,
1245                            &mut self.exp_buffer,
1246                            #[cfg(feature = "rand")]
1247                            &mut self.rng,
1248                        )
1249                        .evaluate()
1250                        .map_or_else(
1251                            |e| Some(Err(E::LangErr(e))),
1252                            |o| match o {
1253                                Empty(_) | Eval(_) | Store(_) => Some(Ok(o)),
1254                                Exit => None,
1255                            },
1256                        )
1257                    }
1258                },
1259            )
1260    }
1261}