lib.rs (53584B)
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`, <space>, <tab>, 96 //! <line feed>, <carriage return>, 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 /// Unit tests. 125 #[cfg(test)] 126 mod tests; 127 use LangErr::{ 128 DivByZero, ExpDivByZero, ExpIsNotIntOrOneHalf, InvalidAbs, InvalidDec, InvalidPar, InvalidQuit, 129 InvalidRound, InvalidStore, MissingTerm, ModIsNotInt, ModZero, NotEnoughPrevResults, 130 NotNonNegIntFact, SqrtDoesNotExist, TrailingSyms, 131 }; 132 use O::{Empty, Eval, Exit, Store}; 133 use alloc::{ 134 string::{String, ToString as _}, 135 vec, 136 vec::Vec, 137 }; 138 use cache::Cache; 139 #[cfg(not(feature = "rand"))] 140 use core::marker::PhantomData; 141 use core::{ 142 convert, 143 fmt::{self, Display, Formatter}, 144 ops::Index as _, 145 }; 146 pub use num_bigint; 147 use num_bigint::{BigInt, BigUint, Sign}; 148 use num_integer::Integer as _; 149 pub use num_rational; 150 use num_rational::Ratio; 151 #[cfg(feature = "rand")] 152 use num_traits::ToPrimitive as _; 153 use num_traits::{Inv as _, Pow as _}; 154 #[cfg(target_os = "openbsd")] 155 use priv_sep as _; 156 #[cfg(feature = "rand")] 157 pub use rand; 158 #[cfg(feature = "rand")] 159 use 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. 166 pub mod cache; 167 /// Generalizes [`Iterator`] by using 168 /// generic associated types. 169 pub mod lending_iterator; 170 /// Error due to a language violation. 171 #[non_exhaustive] 172 #[cfg_attr(test, derive(Eq, PartialEq))] 173 #[derive(Debug)] 174 pub 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 } 236 impl 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)] 271 pub 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 } 285 impl 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`]. 390 const CACHE_SIZE: usize = 8; 391 /// Evaluates the supplied input. 392 #[derive(Debug)] 393 pub 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 )] 420 impl<'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)] 1147 pub 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")] 1165 impl<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")] 1193 extern crate std; 1194 #[cfg(feature = "std")] 1195 use std::io::{BufRead, Error}; 1196 /// Error returned from [`EvalIter`] when an expression has an error. 1197 #[cfg(feature = "std")] 1198 #[derive(Debug)] 1199 pub 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")] 1209 impl 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")] 1219 use crate::lending_iterator::LendingIterator; 1220 #[cfg(feature = "std")] 1221 impl<R> LendingIterator for EvalIter<R> 1222 where 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 }