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