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