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