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