1#![expect(
114 clippy::doc_paragraphs_missing_punctuation,
115 reason = "false positive for crate documentation having image links"
116)]
117#![expect(
118 clippy::arithmetic_side_effects,
119 reason = "calculator can't realistically avoid this"
120)]
121#![no_std]
122#![cfg_attr(docsrs, feature(doc_cfg))]
123extern crate alloc;
124use LangErr::{
125 DivByZero, ExpDivByZero, ExpIsNotIntOrOneHalf, InvalidAbs, InvalidDec, InvalidPar, InvalidQuit,
126 InvalidRound, InvalidStore, MissingTerm, ModIsNotInt, ModZero, NotEnoughPrevResults,
127 NotNonNegIntFact, SqrtDoesNotExist, TrailingSyms,
128};
129use O::{Empty, Eval, Exit, Store};
130use alloc::{
131 string::{String, ToString as _},
132 vec,
133 vec::Vec,
134};
135use cache::Cache;
136#[cfg(not(feature = "rand"))]
137use core::marker::PhantomData;
138use core::{
139 convert,
140 fmt::{self, Display, Formatter},
141 ops::Index as _,
142};
143pub use num_bigint;
144use num_bigint::{BigInt, BigUint, Sign};
145use num_integer::Integer as _;
146pub use num_rational;
147use num_rational::Ratio;
148#[cfg(feature = "rand")]
149use num_traits::ToPrimitive as _;
150use num_traits::{Inv as _, Pow as _};
151#[cfg(target_os = "openbsd")]
152use priv_sep as _;
153#[cfg(feature = "rand")]
154pub use rand;
155#[cfg(feature = "rand")]
156use rand::{Rng as _, rngs::ThreadRng};
157pub mod cache;
164pub mod lending_iterator;
167#[non_exhaustive]
169#[cfg_attr(test, derive(Eq, PartialEq))]
170#[derive(Debug)]
171pub enum LangErr {
172 InvalidQuit,
175 InvalidStore,
178 DivByZero(usize),
181 ExpIsNotIntOrOneHalf(usize),
185 ExpDivByZero(usize),
189 ModZero(usize),
192 ModIsNotInt(usize),
196 NotNonNegIntFact(usize),
199 InvalidDec(usize),
202 NotEnoughPrevResults(usize),
206 InvalidAbs(usize),
208 InvalidPar(usize),
210 InvalidRound(usize),
212 MissingTerm(usize),
217 SqrtDoesNotExist(usize),
220 TrailingSyms(usize),
223 #[cfg(feature = "rand")]
225 InvalidRand(usize),
226 #[cfg(feature = "rand")]
228 RandInvalidArgs(usize),
229 #[cfg(feature = "rand")]
231 RandNoInts(usize),
232}
233impl Display for LangErr {
234 #[inline]
235 fn fmt(&self, f: &mut Formatter<'_>) -> fmt::Result {
236 match *self {
237 InvalidStore => f.write_str("Invalid store expression. A store expression must be of the extended regex form: ^[ \\t]*s[ \\t]*$."),
238 InvalidQuit => f.write_str("Invalid quit expression. A quit expression must be of the extended regex form: ^[ \\t]*q[ \\t]*$."),
239 DivByZero(u) => write!(f, "Division by zero ending at position {u}."),
240 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}."),
241 ExpDivByZero(u) => write!(f, "Non-negative exponent with a base of 0 ending at position {u}."),
242 ModZero(u) => write!(f, "A number modulo 0 ending at position {u}."),
243 ModIsNotInt(u) => write!(f, "The modulo expression was applied to at least one non-integer ending at position {u}."),
244 NotNonNegIntFact(u) => write!(f, "Factorial of a rational number that was not a non-negative integer ending at position {u}."),
245 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]+)?."),
246 NotEnoughPrevResults(len) => write!(f, "There are only {len} previous results."),
247 InvalidAbs(u) => write!(f, "Invalid absolute value expression ending at position {u}. An absolute value expression is an addition expression enclosed in '||'."),
248 InvalidPar(u) => write!(f, "Invalid parenthetical expression ending at position {u}. A parenthetical expression is an addition expression enclosed in '()'."),
249 InvalidRound(u) => write!(f, "Invalid round expression ending at position {u}. A round expression is of the form 'round(<mod expression>, digit)'"),
250 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}."),
251 #[cfg(not(feature = "rand"))]
252 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."),
253 #[cfg(feature = "rand")]
254 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."),
255 TrailingSyms(u) => write!(f, "Trailing symbols starting at position {u}."),
256 #[cfg(feature = "rand")]
257 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>)'."),
258 #[cfg(feature = "rand")]
259 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}."),
260 #[cfg(feature = "rand")]
261 Self::RandNoInts(u) => write!(f, "There are no 64-bit integers within the interval passed to the random function ending at position {u}."),
262 }
263 }
264}
265#[cfg_attr(test, derive(Eq, PartialEq))]
267#[derive(Debug)]
268pub enum O<'a> {
269 Empty(&'a Option<Ratio<BigInt>>),
274 Exit,
276 Eval(&'a Ratio<BigInt>),
278 Store(&'a Option<Ratio<BigInt>>),
281}
282impl Display for O<'_> {
283 #[expect(
284 unsafe_code,
285 reason = "manually construct guaranteed UTF-8; thus avoid the needless check"
286 )]
287 #[expect(clippy::indexing_slicing, reason = "comment justifies correctness")]
288 #[inline]
289 fn fmt(&self, f: &mut Formatter<'_>) -> fmt::Result {
290 match *self {
291 Empty(o) => {
292 o.as_ref().map_or(Ok(()), |val| {
293 if val.is_integer() {
294 write!(f, "> {val}")
295 } else {
296 let mut twos = 0;
303 let mut fives = 0;
304 let zero = BigInt::from_biguint(Sign::NoSign, BigUint::new(Vec::new()));
305 let one = BigInt::from_biguint(Sign::Plus, BigUint::new(vec![1]));
306 let two = BigInt::from_biguint(Sign::Plus, BigUint::new(vec![2]));
307 let five = BigInt::from_biguint(Sign::Plus, BigUint::new(vec![5]));
308 let mut denom = val.denom().clone();
309 let mut div_rem;
310 while denom > one {
311 div_rem = denom.div_rem(&two);
312 if div_rem.1 == zero {
313 twos += 1;
314 denom = div_rem.0;
315 } else {
316 break;
317 }
318 }
319 while denom > one {
320 div_rem = denom.div_rem(&five);
321 if div_rem.1 == zero {
322 fives += 1;
323 denom = div_rem.0;
324 } else {
325 break;
326 }
327 }
328 let (int, frac, digits) = if denom == one {
330 let (int, mut frac) = val.numer().div_rem(val.denom());
331 while twos > fives {
332 frac *= &five;
333 fives += 1;
334 }
335 while fives > twos {
336 frac *= &two;
337 twos += 1;
338 }
339 (int, frac, twos)
340 } else {
341 let mult =
344 BigInt::from_biguint(Sign::Plus, BigUint::new(vec![10])).pow(9u8);
345 let (int, frac) = (val * &mult).round().numer().div_rem(&mult);
346 (int, frac, 9)
347 };
348 let int_str = int.to_string().into_bytes();
349 let (mut v, frac_str) = if val.numer().sign() == Sign::Minus {
350 if int_str[0] == b'-' {
352 (
353 Vec::with_capacity(int_str.len() + 1 + digits),
354 (-frac).to_string().into_bytes(),
355 )
356 } else {
357 let mut tmp = Vec::with_capacity(int_str.len() + 2 + digits);
358 tmp.push(b'-');
359 (tmp, (-frac).to_string().into_bytes())
360 }
361 } else {
362 (
363 Vec::with_capacity(int_str.len() + 1 + digits),
364 frac.to_string().into_bytes(),
365 )
366 };
367 v.extend_from_slice(int_str.as_slice());
368 v.push(b'.');
369 v.resize(v.len() + (digits - frac_str.len()), b'0');
371 v.extend_from_slice(frac_str.as_slice());
372 write!(f, "> {}", unsafe { String::from_utf8_unchecked(v) })
377 }
378 })
379 }
380 Eval(r) => write!(f, "> {r}"),
381 Exit => Ok(()),
382 Store(o) => o.as_ref().map_or(Ok(()), |val| write!(f, "> {val}")),
383 }
384 }
385}
386const CACHE_SIZE: usize = 8;
388#[derive(Debug)]
390pub struct Evaluator<'input, 'cache, 'prev, 'scratch, 'rand> {
391 utf8: &'input [u8],
393 i: usize,
398 cache: &'cache mut Cache<Ratio<BigInt>, CACHE_SIZE>,
400 prev: &'prev mut Option<Ratio<BigInt>>,
402 scratch: &'scratch mut Vec<Ratio<BigInt>>,
404 #[cfg(feature = "rand")]
406 rng: &'rand mut ThreadRng,
407 #[cfg(not(feature = "rand"))]
409 _rng: PhantomData<fn() -> &'rand ()>,
410}
411#[allow(
412 single_use_lifetimes,
413 clippy::allow_attributes,
414 clippy::elidable_lifetime_names,
415 reason = "unify rand and not rand"
416)]
417impl<'input, 'cache, 'prev, 'scratch, 'rand> Evaluator<'input, 'cache, 'prev, 'scratch, 'rand> {
418 #[cfg(not(feature = "rand"))]
420 #[inline]
421 pub fn new(
422 utf8: &'input [u8],
423 cache: &'cache mut Cache<Ratio<BigInt>, 8>,
424 prev: &'prev mut Option<Ratio<BigInt>>,
425 scratch: &'scratch mut Vec<Ratio<BigInt>>,
426 ) -> Self {
427 Self {
428 utf8,
429 i: 0,
430 cache,
431 prev,
432 scratch,
433 _rng: PhantomData,
434 }
435 }
436 #[cfg(feature = "rand")]
438 #[inline]
439 pub const fn new(
440 utf8: &'input [u8],
441 cache: &'cache mut Cache<Ratio<BigInt>, 8>,
442 prev: &'prev mut Option<Ratio<BigInt>>,
443 scratch: &'scratch mut Vec<Ratio<BigInt>>,
444 rng: &'rand mut ThreadRng,
445 ) -> Self {
446 Self {
447 utf8,
448 i: 0,
449 cache,
450 prev,
451 scratch,
452 rng,
453 }
454 }
455 #[expect(clippy::indexing_slicing, reason = "correct")]
464 #[inline]
465 pub fn evaluate(mut self) -> Result<O<'prev>, LangErr> {
466 self.utf8 = if self.utf8.last().is_none_or(|b| *b != b'\n') {
467 self.utf8
468 } else {
469 &self.utf8[..self.utf8.len()
470 - self
471 .utf8
472 .get(self.utf8.len().wrapping_sub(2))
473 .map_or(1, |b| if *b == b'\r' { 2 } else { 1 })]
474 };
475 self.consume_ws();
476 let Some(b) = self.utf8.get(self.i) else {
477 return Ok(Empty(self.prev));
478 };
479 if *b == b'q' {
480 self.i += 1;
481 self.consume_ws();
482 if self.i == self.utf8.len() {
483 Ok(Exit)
484 } else {
485 Err(InvalidQuit)
486 }
487 } else if *b == b's' {
488 self.i += 1;
489 self.consume_ws();
490 if self.i == self.utf8.len() {
491 if let Some(ref val) = *self.prev {
492 self.cache.push(val.clone());
493 }
494 Ok(Store(self.prev))
495 } else {
496 Err(InvalidStore)
497 }
498 } else {
499 self.get_adds().and_then(move |val| {
500 self.consume_ws();
501 if self.i == self.utf8.len() {
502 Ok(Eval(self.prev.insert(val)))
503 } else {
504 Err(TrailingSyms(self.i))
505 }
506 })
507 }
508 }
509 #[expect(clippy::indexing_slicing, reason = "correct")]
511 fn consume_ws(&mut self) {
512 self.i += self.utf8[self.i..]
516 .iter()
517 .try_fold(0, |val, b| match *b {
518 b' ' | b'\t' => Ok(val + 1),
519 _ => Err(val),
520 })
521 .map_or_else(convert::identity, convert::identity);
522 }
523 fn get_adds(&mut self) -> Result<Ratio<BigInt>, LangErr> {
527 let mut left = self.get_mults()?;
528 let mut j;
529 self.consume_ws();
530 while let Some(i) = self.utf8.get(self.i) {
531 j = *i;
532 self.consume_ws();
533 if j == b'+' {
534 self.i += 1;
535 self.consume_ws();
536 left += self.get_mults()?;
537 } else if j == b'-' {
538 self.i += 1;
539 self.consume_ws();
540 left -= self.get_mults()?;
541 } else {
542 break;
543 }
544 }
545 Ok(left)
546 }
547 fn get_mults(&mut self) -> Result<Ratio<BigInt>, LangErr> {
551 let mut left = self.get_neg()?;
552 let mut right;
553 let mut j;
554 let mut mod_val;
555 let mut numer;
556 self.consume_ws();
557 while let Some(i) = self.utf8.get(self.i) {
558 j = *i;
559 self.consume_ws();
560 if j == b'*' {
561 self.i += 1;
562 self.consume_ws();
563 left *= self.get_neg()?;
564 } else if j == b'/' {
565 self.i += 1;
566 self.consume_ws();
567 right = self.get_neg()?;
568 if right.numer().sign() == Sign::NoSign {
569 return Err(DivByZero(self.i));
570 }
571 left /= right;
572 } else if let Some(k) = self.utf8.get(self.i..self.i.saturating_add(3)) {
573 if k == b"mod" {
574 if !left.is_integer() {
575 return Err(ModIsNotInt(self.i));
576 }
577 self.i += 3;
578 self.consume_ws();
579 right = self.get_neg()?;
580 if !right.is_integer() {
581 return Err(ModIsNotInt(self.i));
582 }
583 numer = right.numer();
584 if numer.sign() == Sign::NoSign {
585 return Err(ModZero(self.i));
586 }
587 mod_val = left.numer() % numer;
588 left = Ratio::from_integer(if mod_val.sign() == Sign::Minus {
589 if numer.sign() == Sign::Minus {
590 mod_val - numer
591 } else {
592 mod_val + numer
593 }
594 } else {
595 mod_val
596 });
597 } else {
598 break;
599 }
600 } else {
601 break;
602 }
603 }
604 Ok(left)
605 }
606 fn get_neg(&mut self) -> Result<Ratio<BigInt>, LangErr> {
609 let mut count = 0usize;
610 while let Some(b) = self.utf8.get(self.i) {
611 if *b == b'-' {
612 self.i += 1;
613 self.consume_ws();
614 count += 1;
615 } else {
616 break;
617 }
618 }
619 self.get_exps()
620 .map(|val| if count & 1 == 0 { val } else { -val })
621 }
622 #[expect(
624 clippy::unreachable,
625 reason = "code that shouldn't happen did, so we want to crash"
626 )]
627 fn sqrt(val: Ratio<BigInt>) -> Option<Ratio<BigInt>> {
628 #[expect(clippy::suspicious_operation_groupings, reason = "false positive")]
632 fn calc(n: &BigUint) -> Option<BigUint> {
633 let mut shift = n.bits();
634 shift += shift & 1;
635 let mut result = BigUint::new(Vec::new());
636 let one = BigUint::new(vec![1]);
637 let zero = BigUint::new(Vec::new());
638 loop {
639 shift -= 2;
640 result <<= 1u32;
641 result |= &one;
642 result ^= if &result * &result > (n >> shift) {
643 &one
644 } else {
645 &zero
646 };
647 if shift == 0 {
648 break (&result * &result == *n).then_some(result);
649 }
650 }
651 }
652 let numer = val.numer();
653 if numer.sign() == Sign::NoSign {
654 Some(val)
655 } else {
656 numer.try_into().map_or_else(
657 |_| None,
658 |num| {
659 calc(&num).and_then(|n| {
660 calc(&val.denom().try_into().unwrap_or_else(|_| {
661 unreachable!("Ratio must never have a negative denominator")
662 }))
663 .map(|d| Ratio::new(n.into(), d.into()))
664 })
665 },
666 )
667 }
668 }
669 fn get_exps(&mut self) -> Result<Ratio<BigInt>, LangErr> {
672 let mut t = self.get_fact()?;
673 let ix = self.scratch.len();
674 let mut prev;
675 let mut numer;
676 self.scratch.push(t);
677 self.consume_ws();
678 let mut j;
679 let one = BigInt::new(Sign::Plus, vec![1]);
680 let min_one = BigInt::new(Sign::Minus, vec![1]);
681 let two = BigInt::new(Sign::Plus, vec![2]);
682 while let Some(i) = self.utf8.get(self.i) {
683 j = *i;
684 self.consume_ws();
685 if j == b'^' {
686 self.i += 1;
687 self.consume_ws();
688 t = self.get_neg()?;
689 prev = self.scratch.index(self.scratch.len() - 1);
692 numer = prev.numer();
693 if numer.sign() == Sign::NoSign {
695 if t.numer().sign() == Sign::Minus {
696 self.scratch.clear();
697 return Err(ExpDivByZero(self.i));
698 }
699 self.scratch.push(t);
700 } else if prev.is_integer() {
701 let t_numer = t.numer();
702 if *numer == one {
705 } else if t.is_integer()
706 || ((*t_numer == one || *t_numer == min_one) && *t.denom() == two)
707 {
708 self.scratch.push(t);
709 } else {
710 self.scratch.clear();
711 return Err(ExpIsNotIntOrOneHalf(self.i));
712 }
713 } else if t.is_integer()
714 || ((*t.numer() == one || *t.numer() == min_one) && *t.denom() == two)
715 {
716 self.scratch.push(t);
717 } else {
718 self.scratch.clear();
719 return Err(ExpIsNotIntOrOneHalf(self.i));
720 }
721 } else {
722 break;
723 }
724 }
725 self.scratch
726 .drain(ix..)
727 .try_rfold(Ratio::from_integer(one.clone()), |exp, base| {
728 if exp.is_integer() {
729 Ok(base.pow(exp.numer()))
730 } else if base.numer().sign() == Sign::NoSign {
731 Ok(base)
732 } else if *exp.denom() == two {
733 if *exp.numer() == one {
734 Self::sqrt(base).map_or_else(|| Err(SqrtDoesNotExist(self.i)), Ok)
735 } else if *exp.numer() == min_one {
736 Self::sqrt(base)
737 .map_or_else(|| Err(SqrtDoesNotExist(self.i)), |v| Ok(v.inv()))
738 } else {
739 Err(ExpIsNotIntOrOneHalf(self.i))
740 }
741 } else {
742 Err(ExpIsNotIntOrOneHalf(self.i))
743 }
744 })
745 }
746 fn get_fact(&mut self) -> Result<Ratio<BigInt>, LangErr> {
749 fn fact(mut val: BigUint) -> BigUint {
751 let zero = BigUint::new(Vec::new());
752 let one = BigUint::new(vec![1]);
753 let mut calc = BigUint::new(vec![1]);
754 while val > zero {
755 calc *= &val;
756 val -= &one;
757 }
758 calc
759 }
760 let t = self.get_term()?;
761 let Some(b) = self.utf8.get(self.i) else {
762 return Ok(t);
763 };
764 if *b == b'!' {
765 self.i += 1;
766 if t.is_integer() {
767 let i = self.i;
770 t.numer().try_into().map_or_else(
771 |_| Err(NotNonNegIntFact(i)),
772 |val| {
773 let mut factorial = fact(val);
774 while let Some(b2) = self.utf8.get(self.i) {
775 if *b2 == b'!' {
776 self.i += 1;
777 factorial = fact(factorial);
778 } else {
779 break;
780 }
781 }
782 Ok(Ratio::from_integer(BigInt::from_biguint(
783 Sign::Plus,
784 factorial,
785 )))
786 },
787 )
788 } else {
789 Err(NotNonNegIntFact(self.i))
790 }
791 } else {
792 Ok(t)
793 }
794 }
795 fn get_term(&mut self) -> Result<Ratio<BigInt>, LangErr> {
800 self.get_rational().map_or_else(Err, |o| {
801 o.map_or_else(
802 || {
803 self.get_par().map_or_else(Err, |o2| {
804 o2.map_or_else(
805 || {
806 self.get_recall().map_or_else(Err, |o3| {
807 o3.map_or_else(
808 || {
809 self.get_abs().map_or_else(Err, |o4| {
810 o4.map_or_else(
811 || {
812 self.get_round().and_then(|o5| {
813 o5.map_or_else(
814 #[cfg(not(feature = "rand"))]
815 || Err(MissingTerm(self.i)),
816 #[cfg(feature = "rand")]
817 || self.get_rand(),
818 Ok,
819 )
820 })
821 },
822 Ok,
823 )
824 })
825 },
826 Ok,
827 )
828 })
829 },
830 Ok,
831 )
832 })
833 },
834 Ok,
835 )
836 })
837 }
838 #[cfg(feature = "rand")]
842 fn get_rand(&mut self) -> Result<Ratio<BigInt>, LangErr> {
843 #[expect(clippy::host_endian_bytes, reason = "must keep platform endianness")]
845 fn rand(rng: &mut ThreadRng) -> i64 {
846 let mut bytes = [0; 8];
847 rng.fill_bytes(&mut bytes);
849 i64::from_ne_bytes(bytes)
850 }
851 #[expect(
853 clippy::integer_division_remainder_used,
854 reason = "need for uniform randomness"
855 )]
856 #[expect(
857 clippy::as_conversions,
858 clippy::cast_possible_truncation,
859 clippy::cast_possible_wrap,
860 clippy::cast_sign_loss,
861 reason = "lossless conversions between signed integers"
862 )]
863 fn rand_range(
864 rng: &mut ThreadRng,
865 lower: &Ratio<BigInt>,
866 upper: &Ratio<BigInt>,
867 i: usize,
868 ) -> Result<i64, LangErr> {
869 if lower > upper {
870 return Err(LangErr::RandInvalidArgs(i));
871 }
872 let lo = lower.ceil();
873 let up = upper.floor();
874 let lo_int = lo.numer();
875 let up_int = up.numer();
876 if lo_int > &BigInt::from(i64::MAX) || up_int < &BigInt::from(i64::MIN) {
877 return Err(LangErr::RandNoInts(i));
878 }
879 let lo_min = lo_int.to_i64().unwrap_or(i64::MIN);
880 let up_max = up_int.to_i64().unwrap_or(i64::MAX);
881 if up_max > lo_min || upper.is_integer() || lower.is_integer() {
882 let low = i128::from(lo_min);
883 let modulus = (i128::from(up_max) - low + 1) as u128;
886 let rem = (0x0001_0000_0000_0000_0000 % modulus) as u64;
890 let mut low_adj;
891 loop {
892 low_adj = rand(rng) as u64;
893 if low_adj >= rem {
895 return Ok(
896 ((u128::from(low_adj) % modulus) as i128 + low) as i64,
902 );
903 }
904 }
905 } else {
906 Err(LangErr::RandNoInts(i))
907 }
908 }
909 let Some(b) = self.utf8.get(self.i..self.i.saturating_add(5)) else {
912 return Err(MissingTerm(self.i));
913 };
914 if b == b"rand(" {
915 self.i += 5;
916 self.consume_ws();
917 let i = self.i;
918 self.utf8.get(self.i).map_or_else(
919 || Err(LangErr::InvalidRand(i)),
920 |p| {
921 if *p == b')' {
922 self.i += 1;
923 Ok(Ratio::from_integer(BigInt::from(rand(self.rng))))
924 } else {
925 let add = self.get_adds()?;
926 let Some(b2) = self.utf8.get(self.i) else {
927 return Err(LangErr::InvalidRand(self.i));
928 };
929 if *b2 == b',' {
930 self.i += 1;
931 self.consume_ws();
932 let add2 = self.get_adds()?;
933 self.consume_ws();
934 let Some(b3) = self.utf8.get(self.i) else {
935 return Err(LangErr::InvalidRand(self.i));
936 };
937 if *b3 == b')' {
938 self.i += 1;
939 rand_range(self.rng, &add, &add2, self.i)
940 .map(|v| Ratio::from_integer(BigInt::from(v)))
941 } else {
942 Err(LangErr::InvalidRand(self.i))
943 }
944 } else {
945 Err(LangErr::InvalidRand(self.i))
946 }
947 }
948 },
949 )
950 } else {
951 Err(MissingTerm(self.i))
952 }
953 }
954 fn get_round(&mut self) -> Result<Option<Ratio<BigInt>>, LangErr> {
957 let Some(b) = self.utf8.get(self.i..self.i.saturating_add(6)) else {
958 return Ok(None);
959 };
960 if b == b"round(" {
961 self.i += 6;
962 self.consume_ws();
963 let val = self.get_adds()?;
964 self.consume_ws();
965 let Some(b2) = self.utf8.get(self.i) else {
966 return Err(InvalidRound(self.i));
967 };
968 let b3 = *b2;
969 if b3 == b',' {
970 self.i += 1;
971 self.consume_ws();
972 let Some(b4) = self.utf8.get(self.i) else {
973 return Err(InvalidRound(self.i));
974 };
975 let r = if b4.is_ascii_digit() {
976 self.i += 1;
977 *b4 - b'0'
978 } else {
979 return Err(InvalidRound(self.i));
980 };
981 self.consume_ws();
982 let i = self.i;
983 self.utf8.get(self.i).map_or_else(
984 || Err(InvalidRound(i)),
985 |p| {
986 if *p == b')' {
987 self.i += 1;
988 let mult =
989 BigInt::from_biguint(Sign::Plus, BigUint::new(vec![10])).pow(r);
990 Ok(Some((val * &mult).round() / &mult))
991 } else {
992 Err(InvalidRound(self.i))
993 }
994 },
995 )
996 } else {
997 Err(InvalidRound(self.i))
998 }
999 } else {
1000 Ok(None)
1001 }
1002 }
1003 fn get_abs(&mut self) -> Result<Option<Ratio<BigInt>>, LangErr> {
1006 let Some(b) = self.utf8.get(self.i) else {
1007 return Ok(None);
1008 };
1009 if *b == b'|' {
1010 self.i += 1;
1011 self.consume_ws();
1012 let r = self.get_adds()?;
1013 self.consume_ws();
1014 let Some(b2) = self.utf8.get(self.i) else {
1015 return Err(InvalidAbs(self.i));
1016 };
1017 let b3 = *b2;
1018 if b3 == b'|' {
1019 self.i += 1;
1020 Ok(Some(if r.numer().sign() == Sign::Minus {
1021 -r
1022 } else {
1023 r
1024 }))
1025 } else {
1026 Err(InvalidAbs(self.i))
1027 }
1028 } else {
1029 Ok(None)
1030 }
1031 }
1032 fn get_recall(&mut self) -> Result<Option<Ratio<BigInt>>, LangErr> {
1038 let Some(b) = self.utf8.get(self.i) else {
1039 return Ok(None);
1040 };
1041 if *b == b'@' {
1042 self.i += 1;
1043 self.cache
1044 .get(self.utf8.get(self.i).map_or(0, |b2| {
1045 if (b'1'..b'9').contains(b2) {
1046 self.i += 1;
1047 usize::from(*b2 - b'1')
1048 } else {
1049 0
1050 }
1051 }))
1052 .map_or_else(
1053 || Err(NotEnoughPrevResults(self.cache.len())),
1054 |p| Ok(Some(p.clone())),
1055 )
1056 } else {
1057 Ok(None)
1058 }
1059 }
1060 fn get_par(&mut self) -> Result<Option<Ratio<BigInt>>, LangErr> {
1063 let Some(b) = self.utf8.get(self.i) else {
1064 return Ok(None);
1065 };
1066 if *b == b'(' {
1067 self.i += 1;
1068 self.consume_ws();
1069 let r = self.get_adds()?;
1070 self.consume_ws();
1071 let Some(b2) = self.utf8.get(self.i) else {
1072 return Err(InvalidPar(self.i));
1073 };
1074 let b3 = *b2;
1075 if b3 == b')' {
1076 self.i += 1;
1077 Ok(Some(r))
1078 } else {
1079 Err(InvalidPar(self.i))
1080 }
1081 } else {
1082 Ok(None)
1083 }
1084 }
1085 #[expect(clippy::indexing_slicing, reason = "correct")]
1087 fn get_rational(&mut self) -> Result<Option<Ratio<BigInt>>, LangErr> {
1088 fn to_biguint(v: &[u8]) -> (BigUint, usize) {
1093 v.iter()
1094 .try_fold((BigUint::new(Vec::new()), 0), |mut prev, d| {
1095 if d.is_ascii_digit() {
1096 prev.1 += 1;
1097 prev.0 = prev.0 * 10u8 + (*d - b'0');
1099 Ok(prev)
1100 } else {
1101 Err(prev)
1102 }
1103 })
1104 .map_or_else(convert::identity, convert::identity)
1105 }
1106 let (int, len) = to_biguint(&self.utf8[self.i..]);
1107 if len == 0 {
1108 return Ok(None);
1109 }
1110 self.i += len;
1111 if let Some(b) = self.utf8.get(self.i) {
1112 if *b == b'.' {
1113 self.i += 1;
1114 let (numer, len2) = to_biguint(&self.utf8[self.i..]);
1115 if len2 == 0 {
1116 Err(InvalidDec(self.i))
1117 } else {
1118 self.i += len2;
1119 Ok(Some(
1120 Ratio::from_integer(BigInt::from_biguint(Sign::Plus, int))
1121 + Ratio::new(
1122 BigInt::from_biguint(Sign::Plus, numer),
1123 BigInt::from_biguint(Sign::Plus, BigUint::new(vec![10]).pow(len2)),
1124 ),
1125 ))
1126 }
1127 } else {
1128 Ok(Some(Ratio::from_integer(BigInt::from_biguint(
1129 Sign::Plus,
1130 int,
1131 ))))
1132 }
1133 } else {
1134 Ok(Some(Ratio::from_integer(BigInt::from_biguint(
1135 Sign::Plus,
1136 int,
1137 ))))
1138 }
1139 }
1140}
1141#[cfg(feature = "std")]
1143#[derive(Debug)]
1144pub struct EvalIter<R> {
1145 reader: R,
1147 input_buffer: Vec<u8>,
1150 cache: Cache<Ratio<BigInt>, 8>,
1152 prev: Option<Ratio<BigInt>>,
1154 exp_buffer: Vec<Ratio<BigInt>>,
1157 #[cfg(feature = "rand")]
1159 rng: ThreadRng,
1160}
1161#[cfg(feature = "std")]
1162impl<R> EvalIter<R> {
1163 #[cfg(feature = "rand")]
1165 #[inline]
1166 pub fn new(reader: R) -> Self {
1167 Self {
1168 reader,
1169 input_buffer: Vec::new(),
1170 cache: Cache::new(),
1171 prev: None,
1172 exp_buffer: Vec::new(),
1173 rng: rand::rng(),
1174 }
1175 }
1176 #[cfg(any(doc, not(feature = "rand")))]
1178 #[inline]
1179 pub fn new(reader: R) -> Self {
1180 Self {
1181 reader,
1182 input_buffer: Vec::new(),
1183 cache: Cache::new(),
1184 prev: None,
1185 exp_buffer: Vec::new(),
1186 }
1187 }
1188}
1189#[cfg(feature = "std")]
1190extern crate std;
1191#[cfg(feature = "std")]
1192use std::io::{BufRead, Error};
1193#[cfg(feature = "std")]
1195#[derive(Debug)]
1196pub enum E {
1197 Error(Error),
1201 LangErr(LangErr),
1204}
1205#[cfg(feature = "std")]
1206impl Display for E {
1207 #[inline]
1208 fn fmt(&self, f: &mut Formatter<'_>) -> fmt::Result {
1209 match *self {
1210 Self::Error(ref e) => e.fmt(f),
1211 Self::LangErr(ref e) => e.fmt(f),
1212 }
1213 }
1214}
1215#[cfg(feature = "std")]
1216use crate::lending_iterator::LendingIterator;
1217#[cfg(feature = "std")]
1218impl<R> LendingIterator for EvalIter<R>
1219where
1220 R: BufRead,
1221{
1222 type Item<'a>
1223 = Result<O<'a>, E>
1224 where
1225 Self: 'a;
1226 #[inline]
1227 fn lend_next(&mut self) -> Option<Result<O<'_>, E>> {
1228 self.input_buffer.clear();
1229 self.exp_buffer.clear();
1230 self.reader
1231 .read_until(b'\n', &mut self.input_buffer)
1232 .map_or_else(
1233 |e| Some(Err(E::Error(e))),
1234 |c| {
1235 if c == 0 {
1236 None
1237 } else {
1238 Evaluator::new(
1239 self.input_buffer.as_slice(),
1240 &mut self.cache,
1241 &mut self.prev,
1242 &mut self.exp_buffer,
1243 #[cfg(feature = "rand")]
1244 &mut self.rng,
1245 )
1246 .evaluate()
1247 .map_or_else(
1248 |e| Some(Err(E::LangErr(e))),
1249 |o| match o {
1250 Empty(_) | Eval(_) | Store(_) => Some(Ok(o)),
1251 Exit => None,
1252 },
1253 )
1254 }
1255 },
1256 )
1257 }
1258}
1259#[cfg(test)]
1260mod tests {
1261 use super::{
1262 BigInt, BigUint, Cache, Evaluator,
1263 LangErr::MissingTerm,
1264 O::{Empty, Eval, Store},
1265 Sign, Vec, vec,
1266 };
1267 #[cfg(feature = "rand")]
1268 use super::{BufRead, E, EvalIter, LangErr, LendingIterator as _};
1269 #[cfg(not(feature = "rand"))]
1270 use super::{
1271 LangErr::{
1272 DivByZero, ExpDivByZero, ExpIsNotIntOrOneHalf, InvalidAbs, InvalidDec, InvalidPar,
1273 InvalidQuit, InvalidRound, InvalidStore, ModIsNotInt, ModZero, NotEnoughPrevResults,
1274 NotNonNegIntFact, SqrtDoesNotExist, TrailingSyms,
1275 },
1276 O::Exit,
1277 Ratio,
1278 };
1279 #[cfg(not(feature = "rand"))]
1280 use alloc::{borrow::ToOwned as _, string::ToString as _};
1281 #[cfg(not(feature = "rand"))]
1282 use num_traits::Pow as _;
1283 #[cfg(feature = "rand")]
1284 use num_traits::ToPrimitive as _;
1285 #[cfg(feature = "rand")]
1286 use std::io::{self, Error, Read};
1287 #[expect(clippy::too_many_lines, reason = "a lot to test")]
1288 #[cfg(not(feature = "rand"))]
1289 #[test]
1290 fn empty() {
1291 assert_eq!(
1293 Evaluator::new(b"\n", &mut Cache::new(), &mut None, &mut Vec::new()).evaluate(),
1294 Ok(Empty(&None))
1295 );
1296 assert_eq!(
1297 Evaluator::new(
1298 b" \t \t \n",
1299 &mut Cache::new(),
1300 &mut Some(Ratio::from_integer(BigInt::from_biguint(
1301 Sign::Minus,
1302 BigUint::new(vec![12])
1303 ))),
1304 &mut Vec::new()
1305 )
1306 .evaluate()
1307 .map(|a| a.to_string()),
1308 Ok("> -12".to_owned())
1309 );
1310 assert_eq!(
1311 Evaluator::new(
1312 b"\t\n",
1313 &mut Cache::new(),
1314 &mut Some(Ratio::new(
1315 BigInt::from_biguint(Sign::Minus, BigUint::new(vec![4])),
1316 BigInt::from_biguint(Sign::Plus, BigUint::new(vec![6]))
1317 )),
1318 &mut Vec::new()
1319 )
1320 .evaluate()
1321 .map(|a| a.to_string()),
1322 Ok("> -0.666666667".to_owned())
1323 );
1324 assert_eq!(
1325 Evaluator::new(
1326 b"\t\n",
1327 &mut Cache::new(),
1328 &mut Some(Ratio::new(
1329 BigInt::from_biguint(Sign::Plus, BigUint::new(vec![1])),
1330 BigInt::from_biguint(Sign::Plus, BigUint::new(vec![4_230_196_224, 6]))
1331 )),
1332 &mut Vec::new()
1333 )
1334 .evaluate()
1335 .map(|a| a.to_string()),
1336 Ok("> 0.000000000".to_owned())
1337 );
1338 assert_eq!(
1339 Evaluator::new(
1340 b"\t\n",
1341 &mut Cache::new(),
1342 &mut Some(Ratio::new(
1343 BigInt::from_biguint(Sign::Plus, BigUint::new(vec![17])),
1344 BigInt::from_biguint(Sign::Plus, BigUint::new(vec![4_230_196_224, 6]))
1345 )),
1346 &mut Vec::new()
1347 )
1348 .evaluate()
1349 .map(|a| a.to_string()),
1350 Ok("> 0.000000001".to_owned())
1351 );
1352 assert_eq!(
1353 Evaluator::new(
1354 b"\t\n",
1355 &mut Cache::new(),
1356 &mut Some(Ratio::new(
1357 BigInt::from_biguint(Sign::Plus, BigUint::new(vec![3])),
1358 BigInt::from_biguint(Sign::Plus, BigUint::new(vec![10]))
1359 )),
1360 &mut Vec::new()
1361 )
1362 .evaluate()
1363 .map(|a| a.to_string()),
1364 Ok("> 0.3".to_owned())
1365 );
1366 assert_eq!(
1367 Evaluator::new(
1368 b"\t\n",
1369 &mut Cache::new(),
1370 &mut Some(Ratio::new(
1371 BigInt::from_biguint(Sign::Minus, BigUint::new(vec![203])),
1372 BigInt::from_biguint(Sign::Plus, BigUint::new(vec![10]))
1373 )),
1374 &mut Vec::new()
1375 )
1376 .evaluate()
1377 .map(|a| a.to_string()),
1378 Ok("> -20.3".to_owned())
1379 );
1380 assert_eq!(
1381 Evaluator::new(
1382 &[0u8; 0],
1383 &mut Cache::new(),
1384 &mut Some(Ratio::new(
1385 BigInt::from_biguint(Sign::Minus, BigUint::new(vec![203])),
1386 BigInt::from_biguint(Sign::Plus, BigUint::new(vec![10]))
1387 )),
1388 &mut Vec::new()
1389 )
1390 .evaluate()
1391 .map(|a| a.to_string()),
1392 Ok("> -20.3".to_owned())
1393 );
1394 }
1395 #[expect(clippy::unreachable, reason = "want to crash when there is a bug")]
1396 #[cfg(not(feature = "rand"))]
1397 #[test]
1398 fn number_literal() {
1399 assert_eq!(
1401 Evaluator::new(b"0", &mut Cache::new(), &mut None, &mut Vec::new()).get_rational(),
1402 Ok(Some(Ratio::from_integer(BigInt::from_biguint(
1403 Sign::NoSign,
1404 BigUint::new(Vec::new())
1405 ))))
1406 );
1407 assert_eq!(
1409 Evaluator::new(b"0000.00000", &mut Cache::new(), &mut None, &mut Vec::new())
1410 .get_rational(),
1411 Ok(Some(Ratio::from_integer(BigInt::from_biguint(
1412 Sign::NoSign,
1413 BigUint::new(Vec::new())
1414 ))))
1415 );
1416 assert_eq!(
1418 Evaluator::new(b"1 0", &mut Cache::new(), &mut None, &mut Vec::new()).get_rational(),
1419 Ok(Some(Ratio::from_integer(BigInt::from_biguint(
1420 Sign::Plus,
1421 BigUint::new(vec![1])
1422 ))))
1423 );
1424 let int = b"3397450981271938475135134759823759835414";
1425 let frac = b"913759810573549872354897210539127530981570";
1426 let left = Ratio::from_integer(
1427 BigInt::parse_bytes(int, 10)
1428 .unwrap_or_else(|| unreachable!("bug in BigInt::parse_bytes")),
1429 );
1430 let right = Ratio::new(
1431 BigInt::parse_bytes(frac, 10)
1432 .unwrap_or_else(|| unreachable!("bug in BigInt::parse_bytes")),
1433 BigInt::from_biguint(Sign::Plus, BigUint::new(vec![10]).pow(frac.len() + 1)),
1434 );
1435 let mut vec = Vec::new();
1436 vec.extend_from_slice(int);
1437 vec.push(b'.');
1438 vec.push(b'0');
1439 vec.extend_from_slice(frac);
1440 assert_eq!(
1442 Evaluator::new(
1443 vec.as_slice(),
1444 &mut Cache::new(),
1445 &mut None,
1446 &mut Vec::new()
1447 )
1448 .get_rational(),
1449 Ok(Some(left + right))
1450 );
1451 assert_eq!(
1453 Evaluator::new(
1454 b"000000014.0000000000000",
1455 &mut Cache::new(),
1456 &mut None,
1457 &mut Vec::new()
1458 )
1459 .get_rational(),
1460 Ok(Some(Ratio::from_integer(BigInt::from_biguint(
1461 Sign::Plus,
1462 BigUint::new(vec![14])
1463 ))))
1464 );
1465 assert_eq!(
1467 Evaluator::new(b"1.", &mut Cache::new(), &mut None, &mut Vec::new()).get_rational(),
1468 Err(InvalidDec(2))
1469 );
1470 assert_eq!(
1473 Evaluator::new(b"1. 2", &mut Cache::new(), &mut None, &mut Vec::new()).get_rational(),
1474 Err(InvalidDec(2))
1475 );
1476 assert_eq!(
1479 Evaluator::new(b"a1", &mut Cache::new(), &mut None, &mut Vec::new()).get_rational(),
1480 Ok(None)
1481 );
1482 assert_eq!(
1484 Evaluator::new(b" 1", &mut Cache::new(), &mut None, &mut Vec::new()).get_rational(),
1485 Ok(None)
1486 );
1487 assert_eq!(
1489 Evaluator::new(b"\t1", &mut Cache::new(), &mut None, &mut Vec::new()).get_rational(),
1490 Ok(None)
1491 );
1492 assert_eq!(
1494 Evaluator::new(b"-1", &mut Cache::new(), &mut None, &mut Vec::new()).get_rational(),
1495 Ok(None)
1496 );
1497 assert_eq!(
1499 Evaluator::new(b"1/2", &mut Cache::new(), &mut None, &mut Vec::new()).get_rational(),
1500 Ok(Some(Ratio::from_integer(BigInt::from_biguint(
1501 Sign::Plus,
1502 BigUint::new(vec![1])
1503 ))))
1504 );
1505 assert_eq!(
1507 Evaluator::new(b"130alj", &mut Cache::new(), &mut None, &mut Vec::new()).get_rational(),
1508 Ok(Some(Ratio::from_integer(BigInt::from_biguint(
1509 Sign::Plus,
1510 BigUint::new(vec![130])
1511 ))))
1512 );
1513 }
1514 #[cfg(not(feature = "rand"))]
1515 #[test]
1516 fn par() {
1517 assert_eq!(
1519 Evaluator::new(b"(1", &mut Cache::new(), &mut None, &mut Vec::new()).get_par(),
1520 Err(InvalidPar(2))
1521 );
1522 assert_eq!(
1523 Evaluator::new(b"((1\t + 2)", &mut Cache::new(), &mut None, &mut Vec::new()).get_par(),
1524 Err(InvalidPar(9))
1525 );
1526 assert_eq!(
1527 Evaluator::new(b"( 0 \t )", &mut Cache::new(), &mut None, &mut Vec::new()).get_par(),
1528 Ok(Some(Ratio::from_integer(BigInt::from_biguint(
1529 Sign::NoSign,
1530 BigUint::new(Vec::new())
1531 ))))
1532 );
1533 assert_eq!(
1534 Evaluator::new(b"( - \t 5 )", &mut Cache::new(), &mut None, &mut Vec::new()).get_par(),
1535 Ok(Some(Ratio::from_integer(BigInt::from_biguint(
1536 Sign::Minus,
1537 BigUint::new(vec![5])
1538 ))))
1539 );
1540 assert_eq!(
1541 Evaluator::new(
1542 b"( ( 2 -\t 5) * 9 )",
1543 &mut Cache::new(),
1544 &mut None,
1545 &mut Vec::new()
1546 )
1547 .get_par(),
1548 Ok(Some(Ratio::from_integer(BigInt::from_biguint(
1549 Sign::Minus,
1550 BigUint::new(vec![27])
1551 ))))
1552 );
1553 }
1554 #[expect(clippy::too_many_lines, reason = "a lot to test")]
1555 #[expect(
1556 clippy::indexing_slicing,
1557 clippy::unwrap_used,
1558 reason = "comments justify correctness"
1559 )]
1560 #[cfg(not(feature = "rand"))]
1561 #[test]
1562 fn recall_expression() {
1563 assert_eq!(
1565 Evaluator::new(b"1", &mut Cache::new(), &mut None, &mut Vec::new()).get_recall(),
1566 Ok(None)
1567 );
1568 assert_eq!(
1569 Evaluator::new(b"a", &mut Cache::new(), &mut None, &mut Vec::new()).get_recall(),
1570 Ok(None)
1571 );
1572 assert_eq!(
1573 Evaluator::new(b" @", &mut Cache::new(), &mut None, &mut Vec::new()).get_recall(),
1574 Ok(None)
1575 );
1576 assert_eq!(
1577 Evaluator::new(b"\t@", &mut Cache::new(), &mut None, &mut Vec::new()).get_recall(),
1578 Ok(None)
1579 );
1580 assert_eq!(
1582 Evaluator::new(b"@", &mut Cache::new(), &mut None, &mut Vec::new()).get_recall(),
1583 Err(NotEnoughPrevResults(0))
1584 );
1585 assert_eq!(
1587 Evaluator::new(b"@4", &mut Cache::new(), &mut None, &mut Vec::new()).get_recall(),
1588 Err(NotEnoughPrevResults(0))
1589 );
1590 assert_eq!(
1593 Evaluator::new(b"@0", &mut Cache::new(), &mut None, &mut Vec::new()).get_recall(),
1594 Err(NotEnoughPrevResults(0))
1595 );
1596 let mut prev = None;
1598 let mut cache = Cache::new();
1599 _ = Evaluator::new(b"1\n", &mut cache, &mut prev, &mut Vec::new())
1601 .evaluate()
1602 .unwrap();
1603 _ = Evaluator::new(b" s \r\n", &mut cache, &mut prev, &mut Vec::new())
1605 .evaluate()
1606 .unwrap();
1607 assert_eq!(
1608 Evaluator::new(b"@", &mut cache, &mut prev, &mut Vec::new()).get_recall(),
1609 Ok(Some(Ratio::from_integer(BigInt::from_biguint(
1610 Sign::Plus,
1611 BigUint::new(vec![1])
1612 ))))
1613 );
1614 assert_eq!(
1616 Evaluator::new(b"@&", &mut cache, &mut prev, &mut Vec::new()).get_recall(),
1617 Ok(Some(Ratio::from_integer(BigInt::from_biguint(
1618 Sign::Plus,
1619 BigUint::new(vec![1])
1620 ))))
1621 );
1622 assert_eq!(
1624 Evaluator::new(b"@0", &mut cache, &mut prev, &mut Vec::new()).get_recall(),
1625 Ok(Some(Ratio::from_integer(BigInt::from_biguint(
1626 Sign::Plus,
1627 BigUint::new(vec![1])
1628 ))))
1629 );
1630 assert_eq!(
1632 Evaluator::new(b"@9", &mut cache, &mut prev, &mut Vec::new()).get_recall(),
1633 Ok(Some(Ratio::from_integer(BigInt::from_biguint(
1634 Sign::Plus,
1635 BigUint::new(vec![1])
1636 ))))
1637 );
1638 assert_eq!(
1640 Evaluator::new(b"@ 2", &mut cache, &mut prev, &mut Vec::new()).get_recall(),
1641 Ok(Some(Ratio::from_integer(BigInt::from_biguint(
1642 Sign::Plus,
1643 BigUint::new(vec![1])
1644 ))))
1645 );
1646 assert_eq!(
1648 Evaluator::new(b"@\t2", &mut cache, &mut prev, &mut Vec::new()).get_recall(),
1649 Ok(Some(Ratio::from_integer(BigInt::from_biguint(
1650 Sign::Plus,
1651 BigUint::new(vec![1])
1652 ))))
1653 );
1654 assert_eq!(
1656 Evaluator::new(b"@10", &mut cache, &mut prev, &mut Vec::new()).get_recall(),
1657 Ok(Some(Ratio::from_integer(BigInt::from_biguint(
1658 Sign::Plus,
1659 BigUint::new(vec![1])
1660 ))))
1661 );
1662 assert_eq!(
1664 Evaluator::new(b"@2", &mut cache, &mut prev, &mut Vec::new()).get_recall(),
1665 Err(NotEnoughPrevResults(1))
1666 );
1667 _ = Evaluator::new(b"2\r\n", &mut cache, &mut prev, &mut Vec::new())
1669 .evaluate()
1670 .unwrap();
1671 _ = Evaluator::new(b"s\n", &mut cache, &mut prev, &mut Vec::new())
1673 .evaluate()
1674 .unwrap();
1675 assert_eq!(
1677 Evaluator::new(b"@", &mut cache, &mut prev, &mut Vec::new()).get_recall(),
1678 Ok(Some(Ratio::from_integer(BigInt::from_biguint(
1679 Sign::Plus,
1680 BigUint::new(vec![2])
1681 ))))
1682 );
1683 assert_eq!(
1684 Evaluator::new(b"@2", &mut cache, &mut prev, &mut Vec::new()).get_recall(),
1685 Ok(Some(Ratio::from_integer(BigInt::from_biguint(
1686 Sign::Plus,
1687 BigUint::new(vec![1])
1688 ))))
1689 );
1690 assert_eq!(
1692 Evaluator::new(b"@3", &mut cache, &mut prev, &mut Vec::new()).get_recall(),
1693 Err(NotEnoughPrevResults(2))
1694 );
1695 let mut v = vec![0, b'\n'];
1696 for i in b'3'..=b'8' {
1697 v[0] = i;
1699 _ = Evaluator::new(v.as_slice(), &mut cache, &mut prev, &mut Vec::new())
1700 .evaluate()
1701 .unwrap();
1702 _ = Evaluator::new(b"s\n", &mut cache, &mut prev, &mut Vec::new())
1703 .evaluate()
1704 .unwrap();
1705 }
1706 v[0] = b'@';
1707 for i in b'1'..=b'8' {
1708 v[1] = i;
1710 assert_eq!(
1712 Evaluator::new(v.as_slice(), &mut cache, &mut prev, &mut Vec::new()).get_recall(),
1713 Ok(Some(Ratio::from_integer(BigInt::from_biguint(
1714 Sign::Plus,
1715 BigUint::new(vec![u32::from(b'9' - i)])
1716 ))))
1717 );
1718 }
1719 assert_eq!(
1721 Evaluator::new(b"@@", &mut cache, &mut prev, &mut Vec::new()).get_recall(),
1722 Ok(Some(Ratio::from_integer(BigInt::from_biguint(
1723 Sign::Plus,
1724 BigUint::new(vec![8])
1725 ))))
1726 );
1727 _ = Evaluator::new(b"9\r\n", &mut cache, &mut prev, &mut Vec::new())
1729 .evaluate()
1730 .unwrap();
1731 _ = Evaluator::new(b"s\n", &mut cache, &mut prev, &mut Vec::new())
1733 .evaluate()
1734 .unwrap();
1735 for i in b'1'..=b'8' {
1737 v[1] = i;
1739 assert_eq!(
1740 Evaluator::new(v.as_slice(), &mut cache, &mut prev, &mut Vec::new()).get_recall(),
1741 Ok(Some(Ratio::from_integer(BigInt::from_biguint(
1742 Sign::Plus,
1743 BigUint::new(vec![u32::from((b'9' + 1) - i)])
1744 ))))
1745 );
1746 }
1747 }
1748 #[cfg(not(feature = "rand"))]
1749 #[test]
1750 fn abs() {
1751 assert_eq!(
1753 Evaluator::new(b"|1", &mut Cache::new(), &mut None, &mut Vec::new()).get_abs(),
1754 Err(InvalidAbs(2))
1755 );
1756 assert_eq!(
1757 Evaluator::new(b"||1 + 2|", &mut Cache::new(), &mut None, &mut Vec::new()).get_abs(),
1758 Err(InvalidAbs(8))
1759 );
1760 assert_eq!(
1761 Evaluator::new(
1762 b"| 0\t \t |",
1763 &mut Cache::new(),
1764 &mut None,
1765 &mut Vec::new()
1766 )
1767 .get_abs(),
1768 Ok(Some(Ratio::from_integer(BigInt::from_biguint(
1769 Sign::NoSign,
1770 BigUint::new(Vec::new())
1771 ))))
1772 );
1773 assert_eq!(
1774 Evaluator::new(b"| - 5 |", &mut Cache::new(), &mut None, &mut Vec::new()).get_abs(),
1775 Ok(Some(Ratio::from_integer(BigInt::from_biguint(
1776 Sign::Plus,
1777 BigUint::new(vec![5])
1778 ))))
1779 );
1780 assert_eq!(
1781 Evaluator::new(
1782 b"| \t| 2 - 5| * 9 |",
1783 &mut Cache::new(),
1784 &mut None,
1785 &mut Vec::new()
1786 )
1787 .get_abs(),
1788 Ok(Some(Ratio::from_integer(BigInt::from_biguint(
1789 Sign::Plus,
1790 BigUint::new(vec![27])
1791 ))))
1792 );
1793 assert_eq!(
1795 Evaluator::new(b" \t|9|", &mut Cache::new(), &mut None, &mut Vec::new()).get_abs(),
1796 Ok(None)
1797 );
1798 }
1799 #[cfg(not(feature = "rand"))]
1800 #[test]
1801 fn round() {
1802 assert_eq!(
1804 Evaluator::new(b"round(1", &mut Cache::new(), &mut None, &mut Vec::new()).get_round(),
1805 Err(InvalidRound(7))
1806 );
1807 assert_eq!(
1808 Evaluator::new(b"round(1,", &mut Cache::new(), &mut None, &mut Vec::new()).get_round(),
1809 Err(InvalidRound(8))
1810 );
1811 assert_eq!(
1812 Evaluator::new(b"round(1,2", &mut Cache::new(), &mut None, &mut Vec::new()).get_round(),
1813 Err(InvalidRound(9))
1814 );
1815 assert_eq!(
1816 Evaluator::new(
1817 b"round(1,10)",
1818 &mut Cache::new(),
1819 &mut None,
1820 &mut Vec::new()
1821 )
1822 .get_round(),
1823 Err(InvalidRound(9))
1824 );
1825 assert_eq!(
1826 Evaluator::new(b"round(1,a)", &mut Cache::new(), &mut None, &mut Vec::new())
1827 .get_round(),
1828 Err(InvalidRound(8))
1829 );
1830 assert_eq!(
1831 Evaluator::new(
1832 b"round(2, 7)",
1833 &mut Cache::new(),
1834 &mut None,
1835 &mut Vec::new()
1836 )
1837 .get_round(),
1838 Ok(Some(Ratio::from_integer(BigInt::from_biguint(
1839 Sign::Plus,
1840 BigUint::new(vec![2])
1841 ))))
1842 );
1843 assert_eq!(
1844 Evaluator::new(
1845 b"round(2.677, 1)",
1846 &mut Cache::new(),
1847 &mut None,
1848 &mut Vec::new()
1849 )
1850 .get_round(),
1851 Ok(Some(Ratio::new(
1852 BigInt::from_biguint(Sign::Plus, BigUint::new(vec![27])),
1853 BigInt::from_biguint(Sign::Plus, BigUint::new(vec![10]))
1854 )))
1855 );
1856 }
1857 #[expect(clippy::too_many_lines, reason = "a lot to test")]
1858 #[cfg(feature = "rand")]
1859 #[test]
1860 fn rand() {
1861 assert_eq!(
1862 Evaluator::new(
1863 b"rand(1",
1864 &mut Cache::new(),
1865 &mut None,
1866 &mut Vec::new(),
1867 &mut rand::rng()
1868 )
1869 .get_rand(),
1870 Err(LangErr::InvalidRand(6))
1871 );
1872 assert_eq!(
1873 Evaluator::new(
1874 b"rand(1,2",
1875 &mut Cache::new(),
1876 &mut None,
1877 &mut Vec::new(),
1878 &mut rand::rng()
1879 )
1880 .get_rand(),
1881 Err(LangErr::InvalidRand(8))
1882 );
1883 assert_eq!(
1884 Evaluator::new(
1885 b"rand(1/2,3/4)",
1886 &mut Cache::new(),
1887 &mut None,
1888 &mut Vec::new(),
1889 &mut rand::rng(),
1890 )
1891 .get_rand(),
1892 Err(LangErr::RandNoInts(13))
1893 );
1894 assert_eq!(
1895 Evaluator::new(
1896 b"rand(-100000000000000000000000,-1000000000000000000000)",
1897 &mut Cache::new(),
1898 &mut None,
1899 &mut Vec::new(),
1900 &mut rand::rng(),
1901 )
1902 .get_rand(),
1903 Err(LangErr::RandNoInts(55))
1904 );
1905 assert_eq!(
1906 Evaluator::new(
1907 b"rand(2/3,1/3)",
1908 &mut Cache::new(),
1909 &mut None,
1910 &mut Vec::new(),
1911 &mut rand::rng(),
1912 )
1913 .get_rand(),
1914 Err(LangErr::RandInvalidArgs(13))
1915 );
1916 assert_eq!(
1918 Evaluator::new(
1919 b" rand(2/3,2)",
1920 &mut Cache::new(),
1921 &mut None,
1922 &mut Vec::new(),
1923 &mut rand::rng(),
1924 )
1925 .get_rand(),
1926 Err(MissingTerm(0))
1927 );
1928 assert!(
1929 Evaluator::new(
1930 b"rand(2, 7)",
1931 &mut Cache::new(),
1932 &mut None,
1933 &mut Vec::new(),
1934 &mut rand::rng()
1935 )
1936 .get_rand()
1937 .is_ok_and(|r| {
1938 let int = r.numer();
1939 int >= &BigInt::from_biguint(Sign::Plus, BigUint::new(vec![2]))
1940 && *int <= BigInt::from_biguint(Sign::Plus, BigUint::new(vec![7]))
1941 })
1942 );
1943 assert!(
1944 Evaluator::new(
1945 b"rand()",
1946 &mut Cache::new(),
1947 &mut None,
1948 &mut Vec::new(),
1949 &mut rand::rng()
1950 )
1951 .get_rand()
1952 .is_ok_and(|r| {
1953 let int = r.numer();
1954 int >= &BigInt::from(i64::MIN) && *int <= BigInt::from(i64::MAX)
1955 })
1956 );
1957 for _ in 0..100u8 {
1958 assert!(
1959 Evaluator::new(
1960 b"rand(2, 2)",
1961 &mut Cache::new(),
1962 &mut None,
1963 &mut Vec::new(),
1964 &mut rand::rng()
1965 )
1966 .get_rand()
1967 .is_ok_and(
1968 |r| *r.numer() == BigInt::from_biguint(Sign::Plus, BigUint::new(vec![2]))
1969 )
1970 );
1971 }
1972 }
1973 #[expect(
1974 clippy::indexing_slicing,
1975 clippy::unwrap_used,
1976 reason = "comment justifies correctness"
1977 )]
1978 #[cfg(feature = "rand")]
1979 #[test]
1980 #[ignore = "slow"]
1981 fn rand_uni() {
1982 const COUNT: u32 = 999_999;
1983 #[expect(
1984 clippy::integer_division,
1985 clippy::integer_division_remainder_used,
1986 reason = "correct"
1987 )]
1988 const LOWER: u32 = COUNT * 33 / 100;
1989 #[expect(
1990 clippy::integer_division,
1991 clippy::integer_division_remainder_used,
1992 reason = "correct"
1993 )]
1994 const UPPER: u32 = COUNT * 101 / 300;
1995 let mut vals = [0u32; 3];
1998 let mut vec = Vec::new();
1999 let mut cache = Cache::new();
2000 let mut none = None;
2001 for _ in 1..COUNT {
2002 vals[usize::try_from(
2004 Evaluator::new(
2005 b"rand(-1, 1)",
2006 &mut cache,
2007 &mut none,
2008 &mut vec,
2009 &mut rand::rng(),
2010 )
2011 .get_rand()
2012 .unwrap()
2013 .numer()
2014 .to_i32()
2015 .unwrap()
2016 + 1i32,
2017 )
2018 .unwrap()] += 1;
2019 }
2020 assert_eq!(
2022 vals.into_iter().try_fold(false, |_, r| {
2023 if (LOWER..=UPPER).contains(&r) {
2024 Ok(true)
2025 } else {
2026 Err(false)
2027 }
2028 }),
2029 Ok(true)
2030 );
2031 }
2032 #[allow(
2033 clippy::allow_attributes,
2034 reason = "unwrap_used only fires when rand is not enabled"
2035 )]
2036 #[allow(clippy::unwrap_used, reason = "comments justify correctness")]
2037 #[test]
2038 fn term() {
2039 #[cfg(not(feature = "rand"))]
2040 assert_eq!(
2041 Evaluator::new(b"0000.00000", &mut Cache::new(), &mut None, &mut Vec::new()).get_term(),
2042 Ok(Ratio::from_integer(BigInt::from_biguint(
2043 Sign::NoSign,
2044 BigUint::new(Vec::new())
2045 )))
2046 );
2047 #[cfg(not(feature = "rand"))]
2048 assert_eq!(
2049 Evaluator::new(b"(4)", &mut Cache::new(), &mut None, &mut Vec::new()).get_term(),
2050 Ok(Ratio::from_integer(BigInt::from_biguint(
2051 Sign::Plus,
2052 BigUint::new(vec![4])
2053 )))
2054 );
2055 #[cfg(not(feature = "rand"))]
2056 assert_eq!(
2057 Evaluator::new(
2058 b"round(-2/3,2)",
2059 &mut Cache::new(),
2060 &mut None,
2061 &mut Vec::new()
2062 )
2063 .get_term(),
2064 Ok(Ratio::new(
2065 BigInt::from_biguint(Sign::Minus, BigUint::new(vec![67])),
2066 BigInt::from_biguint(Sign::Plus, BigUint::new(vec![100]))
2067 ))
2068 );
2069 #[cfg(feature = "rand")]
2070 drop(
2071 Evaluator::new(
2072 b"rand()",
2073 &mut Cache::new(),
2074 &mut None,
2075 &mut Vec::new(),
2076 &mut rand::rng(),
2077 )
2078 .get_term()
2079 .unwrap(),
2080 );
2081 #[cfg(feature = "rand")]
2082 drop(
2083 Evaluator::new(
2084 b"rand(-13/93, 833)",
2085 &mut Cache::new(),
2086 &mut None,
2087 &mut Vec::new(),
2088 &mut rand::rng(),
2089 )
2090 .get_term()
2091 .unwrap(),
2092 );
2093 #[cfg(not(feature = "rand"))]
2094 assert_eq!(
2095 Evaluator::new(b"rand()", &mut Cache::new(), &mut None, &mut Vec::new()).get_term(),
2096 Err(MissingTerm(0))
2097 );
2098 #[cfg(not(feature = "rand"))]
2099 assert_eq!(
2100 Evaluator::new(b"|4|", &mut Cache::new(), &mut None, &mut Vec::new()).get_term(),
2101 Ok(Ratio::from_integer(BigInt::from_biguint(
2102 Sign::Plus,
2103 BigUint::new(vec![4])
2104 )))
2105 );
2106 #[cfg(not(feature = "rand"))]
2108 assert_eq!(
2109 Evaluator::new(b" 2", &mut Cache::new(), &mut None, &mut Vec::new()).get_term(),
2110 Err(MissingTerm(0))
2111 );
2112 #[cfg(not(feature = "rand"))]
2113 let mut prev = None;
2114 #[cfg(not(feature = "rand"))]
2115 let mut cache = Cache::new();
2116 #[cfg(not(feature = "rand"))]
2117 {
2118 _ = Evaluator::new(b"1\n", &mut cache, &mut prev, &mut Vec::new())
2120 .evaluate()
2121 .unwrap();
2122 _ = Evaluator::new(b"s\n", &mut cache, &mut prev, &mut Vec::new())
2124 .evaluate()
2125 .unwrap();
2126 }
2127 #[cfg(not(feature = "rand"))]
2128 assert_eq!(
2129 Evaluator::new(b"@", &mut cache, &mut prev, &mut Vec::new()).get_term(),
2130 Ok(Ratio::from_integer(BigInt::from_biguint(
2131 Sign::Plus,
2132 BigUint::new(vec![1])
2133 )))
2134 );
2135 }
2136 #[expect(clippy::unwrap_used, reason = "comments justify correctness")]
2137 #[cfg(not(feature = "rand"))]
2138 #[test]
2139 fn factorial() {
2140 assert_eq!(
2142 Evaluator::new(b"(-1)!", &mut Cache::new(), &mut None, &mut Vec::new()).get_fact(),
2143 Err(NotNonNegIntFact(5))
2144 );
2145 assert_eq!(
2147 Evaluator::new(b"2.5!", &mut Cache::new(), &mut None, &mut Vec::new()).get_fact(),
2148 Err(NotNonNegIntFact(4))
2149 );
2150 assert_eq!(
2152 Evaluator::new(b"7", &mut Cache::new(), &mut None, &mut Vec::new()).get_fact(),
2153 Ok(Ratio::from_integer(BigInt::from_biguint(
2154 Sign::Plus,
2155 BigUint::new(vec![7])
2156 )))
2157 );
2158 assert_eq!(
2159 Evaluator::new(b"(7)", &mut Cache::new(), &mut None, &mut Vec::new()).get_fact(),
2160 Ok(Ratio::from_integer(BigInt::from_biguint(
2161 Sign::Plus,
2162 BigUint::new(vec![7])
2163 )))
2164 );
2165 assert_eq!(
2166 Evaluator::new(b"|7|", &mut Cache::new(), &mut None, &mut Vec::new()).get_fact(),
2167 Ok(Ratio::from_integer(BigInt::from_biguint(
2168 Sign::Plus,
2169 BigUint::new(vec![7])
2170 )))
2171 );
2172 let mut prev = None;
2173 let mut cache = Cache::new();
2174 _ = Evaluator::new(b"3\n", &mut cache, &mut prev, &mut Vec::new())
2176 .evaluate()
2177 .unwrap();
2178 _ = Evaluator::new(b"s\n", &mut cache, &mut prev, &mut Vec::new())
2180 .evaluate()
2181 .unwrap();
2182 assert_eq!(
2183 Evaluator::new(b"@!", &mut cache, &mut prev, &mut Vec::new()).get_fact(),
2184 Ok(Ratio::from_integer(BigInt::from_biguint(
2185 Sign::Plus,
2186 BigUint::new(vec![6])
2187 )))
2188 );
2189 assert_eq!(
2190 Evaluator::new(b"@", &mut cache, &mut prev, &mut Vec::new()).get_fact(),
2191 Ok(Ratio::from_integer(BigInt::from_biguint(
2192 Sign::Plus,
2193 BigUint::new(vec![3])
2194 )))
2195 );
2196 assert_eq!(
2198 Evaluator::new(b"0.0!", &mut Cache::new(), &mut None, &mut Vec::new()).get_fact(),
2199 Ok(Ratio::from_integer(BigInt::from_biguint(
2200 Sign::Plus,
2201 BigUint::new(vec![1])
2202 )))
2203 );
2204 assert_eq!(
2206 Evaluator::new(b"1!", &mut Cache::new(), &mut None, &mut Vec::new()).get_fact(),
2207 Ok(Ratio::from_integer(BigInt::from_biguint(
2208 Sign::Plus,
2209 BigUint::new(vec![1])
2210 )))
2211 );
2212 assert_eq!(
2214 Evaluator::new(b"4! \t", &mut Cache::new(), &mut None, &mut Vec::new()).get_fact(),
2215 Ok(Ratio::from_integer(BigInt::from_biguint(
2216 Sign::Plus,
2217 BigUint::new(vec![24])
2218 )))
2219 );
2220 assert_eq!(
2222 Evaluator::new(b"3!! ", &mut Cache::new(), &mut None, &mut Vec::new()).get_fact(),
2223 Ok(Ratio::from_integer(BigInt::from_biguint(
2224 Sign::Plus,
2225 BigUint::new(vec![720])
2226 )))
2227 );
2228 assert_eq!(
2230 Evaluator::new(b"2!+3", &mut Cache::new(), &mut None, &mut Vec::new()).get_fact(),
2231 Ok(Ratio::from_integer(BigInt::from_biguint(
2232 Sign::Plus,
2233 BigUint::new(vec![2])
2234 )))
2235 );
2236 assert_eq!(
2238 Evaluator::new(b" 2!", &mut Cache::new(), &mut None, &mut Vec::new()).get_fact(),
2239 Err(MissingTerm(0))
2240 );
2241 assert_eq!(
2242 Evaluator::new(b"\t2!", &mut Cache::new(), &mut None, &mut Vec::new()).get_fact(),
2243 Err(MissingTerm(0))
2244 );
2245 assert_eq!(
2247 Evaluator::new(b"-2!", &mut Cache::new(), &mut None, &mut Vec::new()).get_fact(),
2248 Err(MissingTerm(0))
2249 );
2250 }
2251 #[expect(
2252 clippy::cognitive_complexity,
2253 clippy::too_many_lines,
2254 reason = "a lot to test"
2255 )]
2256 #[cfg(not(feature = "rand"))]
2257 #[test]
2258 fn exp() {
2259 assert_eq!(
2262 Evaluator::new(b"1 ^\t 0", &mut Cache::new(), &mut None, &mut Vec::new()).get_exps(),
2263 Ok(Ratio::from_integer(BigInt::from_biguint(
2264 Sign::Plus,
2265 BigUint::new(vec![1])
2266 )))
2267 );
2268 assert_eq!(
2269 Evaluator::new(b"1^0.5", &mut Cache::new(), &mut None, &mut Vec::new()).get_exps(),
2270 Ok(Ratio::from_integer(BigInt::from_biguint(
2271 Sign::Plus,
2272 BigUint::new(vec![1])
2273 )))
2274 );
2275 assert_eq!(
2276 Evaluator::new(b"1^(-1/2)", &mut Cache::new(), &mut None, &mut Vec::new()).get_exps(),
2277 Ok(Ratio::from_integer(BigInt::from_biguint(
2278 Sign::Plus,
2279 BigUint::new(vec![1])
2280 )))
2281 );
2282 assert_eq!(
2283 Evaluator::new(b"1.0^(-2)", &mut Cache::new(), &mut None, &mut Vec::new()).get_exps(),
2284 Ok(Ratio::from_integer(BigInt::from_biguint(
2285 Sign::Plus,
2286 BigUint::new(vec![1])
2287 )))
2288 );
2289 assert_eq!(
2291 Evaluator::new(b"0^0", &mut Cache::new(), &mut None, &mut Vec::new()).get_exps(),
2292 Ok(Ratio::from_integer(BigInt::from_biguint(
2293 Sign::Plus,
2294 BigUint::new(vec![1])
2295 )))
2296 );
2297 assert_eq!(
2298 Evaluator::new(b"0^1", &mut Cache::new(), &mut None, &mut Vec::new()).get_exps(),
2299 Ok(Ratio::from_integer(BigInt::from_biguint(
2300 Sign::NoSign,
2301 BigUint::new(vec![0])
2302 )))
2303 );
2304 assert_eq!(
2305 Evaluator::new(b"0^0.5", &mut Cache::new(), &mut None, &mut Vec::new()).get_exps(),
2306 Ok(Ratio::from_integer(BigInt::from_biguint(
2307 Sign::NoSign,
2308 BigUint::new(vec![0])
2309 )))
2310 );
2311 assert_eq!(
2313 Evaluator::new(b"4^0", &mut Cache::new(), &mut None, &mut Vec::new()).get_exps(),
2314 Ok(Ratio::from_integer(BigInt::from_biguint(
2315 Sign::Plus,
2316 BigUint::new(vec![1])
2317 )))
2318 );
2319 assert_eq!(
2320 Evaluator::new(b"4^1", &mut Cache::new(), &mut None, &mut Vec::new()).get_exps(),
2321 Ok(Ratio::from_integer(BigInt::from_biguint(
2322 Sign::Plus,
2323 BigUint::new(vec![4])
2324 )))
2325 );
2326 assert_eq!(
2327 Evaluator::new(b"4^(-2)", &mut Cache::new(), &mut None, &mut Vec::new()).get_exps(),
2328 Ok(Ratio::new(
2329 BigInt::from_biguint(Sign::Plus, BigUint::new(vec![1])),
2330 BigInt::from_biguint(Sign::Plus, BigUint::new(vec![16]))
2331 ))
2332 );
2333 assert_eq!(
2334 Evaluator::new(b"(-4)^0", &mut Cache::new(), &mut None, &mut Vec::new()).get_exps(),
2335 Ok(Ratio::from_integer(BigInt::from_biguint(
2336 Sign::Plus,
2337 BigUint::new(vec![1])
2338 )))
2339 );
2340 assert_eq!(
2341 Evaluator::new(b"(-4)^1", &mut Cache::new(), &mut None, &mut Vec::new()).get_exps(),
2342 Ok(Ratio::from_integer(BigInt::from_biguint(
2343 Sign::Minus,
2344 BigUint::new(vec![4])
2345 )))
2346 );
2347 assert_eq!(
2348 Evaluator::new(b"(-4)^2", &mut Cache::new(), &mut None, &mut Vec::new()).get_exps(),
2349 Ok(Ratio::from_integer(BigInt::from_biguint(
2350 Sign::Plus,
2351 BigUint::new(vec![16])
2352 )))
2353 );
2354 assert_eq!(
2355 Evaluator::new(b"(-4)^(-2)", &mut Cache::new(), &mut None, &mut Vec::new()).get_exps(),
2356 Ok(Ratio::new(
2357 BigInt::from_biguint(Sign::Plus, BigUint::new(vec![1])),
2358 BigInt::from_biguint(Sign::Plus, BigUint::new(vec![16]))
2359 ))
2360 );
2361 assert_eq!(
2362 Evaluator::new(b"(-4)^(-3)", &mut Cache::new(), &mut None, &mut Vec::new()).get_exps(),
2363 Ok(Ratio::new(
2364 BigInt::from_biguint(Sign::Minus, BigUint::new(vec![1])),
2365 BigInt::from_biguint(Sign::Plus, BigUint::new(vec![64]))
2366 ))
2367 );
2368 assert_eq!(
2369 Evaluator::new(b"(2/3)^0", &mut Cache::new(), &mut None, &mut Vec::new()).get_exps(),
2370 Ok(Ratio::from_integer(BigInt::from_biguint(
2371 Sign::Plus,
2372 BigUint::new(vec![1])
2373 )))
2374 );
2375 assert_eq!(
2376 Evaluator::new(b"(2/3)^(2)", &mut Cache::new(), &mut None, &mut Vec::new()).get_exps(),
2377 Ok(Ratio::new(
2378 BigInt::from_biguint(Sign::Plus, BigUint::new(vec![4])),
2379 BigInt::from_biguint(Sign::Plus, BigUint::new(vec![9]))
2380 ))
2381 );
2382 assert_eq!(
2383 Evaluator::new(b"(2/3)^(-3)", &mut Cache::new(), &mut None, &mut Vec::new()).get_exps(),
2384 Ok(Ratio::new(
2385 BigInt::from_biguint(Sign::Plus, BigUint::new(vec![27])),
2386 BigInt::from_biguint(Sign::Plus, BigUint::new(vec![8]))
2387 ))
2388 );
2389 assert_eq!(
2390 Evaluator::new(b"(-2/3)^0", &mut Cache::new(), &mut None, &mut Vec::new()).get_exps(),
2391 Ok(Ratio::from_integer(BigInt::from_biguint(
2392 Sign::Plus,
2393 BigUint::new(vec![1])
2394 )))
2395 );
2396 assert_eq!(
2397 Evaluator::new(b"(-2/3)^(2)", &mut Cache::new(), &mut None, &mut Vec::new()).get_exps(),
2398 Ok(Ratio::new(
2399 BigInt::from_biguint(Sign::Plus, BigUint::new(vec![4])),
2400 BigInt::from_biguint(Sign::Plus, BigUint::new(vec![9]))
2401 ))
2402 );
2403 assert_eq!(
2404 Evaluator::new(b"(-2/3)^(3)", &mut Cache::new(), &mut None, &mut Vec::new()).get_exps(),
2405 Ok(Ratio::new(
2406 BigInt::from_biguint(Sign::Minus, BigUint::new(vec![8])),
2407 BigInt::from_biguint(Sign::Plus, BigUint::new(vec![27]))
2408 ))
2409 );
2410 assert_eq!(
2411 Evaluator::new(
2412 b"(-2/3)^(-2)",
2413 &mut Cache::new(),
2414 &mut None,
2415 &mut Vec::new()
2416 )
2417 .get_exps(),
2418 Ok(Ratio::new(
2419 BigInt::from_biguint(Sign::Plus, BigUint::new(vec![9])),
2420 BigInt::from_biguint(Sign::Plus, BigUint::new(vec![4]))
2421 ))
2422 );
2423 assert_eq!(
2424 Evaluator::new(
2425 b"(-2/3)^(-3)",
2426 &mut Cache::new(),
2427 &mut None,
2428 &mut Vec::new()
2429 )
2430 .get_exps(),
2431 Ok(Ratio::new(
2432 BigInt::from_biguint(Sign::Minus, BigUint::new(vec![27])),
2433 BigInt::from_biguint(Sign::Plus, BigUint::new(vec![8]))
2434 ))
2435 );
2436 assert_eq!(
2437 Evaluator::new(
2438 b"(4/9)^(-1/2)",
2439 &mut Cache::new(),
2440 &mut None,
2441 &mut Vec::new()
2442 )
2443 .get_exps(),
2444 Ok(Ratio::new(
2445 BigInt::from_biguint(Sign::Plus, BigUint::new(vec![3])),
2446 BigInt::from_biguint(Sign::Plus, BigUint::new(vec![2]))
2447 ))
2448 );
2449 assert_eq!(
2451 Evaluator::new(b"0^(-1)", &mut Cache::new(), &mut None, &mut Vec::new()).get_exps(),
2452 Err(ExpDivByZero(6))
2453 );
2454 assert_eq!(
2456 Evaluator::new(b"2^(1/3)", &mut Cache::new(), &mut None, &mut Vec::new()).get_exps(),
2457 Err(ExpIsNotIntOrOneHalf(7))
2458 );
2459 assert_eq!(
2461 Evaluator::new(b"2^(1/2)", &mut Cache::new(), &mut None, &mut Vec::new()).get_exps(),
2462 Err(SqrtDoesNotExist(7))
2463 );
2464 assert_eq!(
2466 Evaluator::new(b"3!", &mut Cache::new(), &mut None, &mut Vec::new()).get_exps(),
2467 Ok(Ratio::from_integer(BigInt::from_biguint(
2468 Sign::Plus,
2469 BigUint::new(vec![6])
2470 )))
2471 );
2472 assert_eq!(
2474 Evaluator::new(b"2^3!", &mut Cache::new(), &mut None, &mut Vec::new()).get_exps(),
2475 Ok(Ratio::from_integer(BigInt::from_biguint(
2476 Sign::Plus,
2477 BigUint::new(vec![64])
2478 )))
2479 );
2480 assert_eq!(
2481 Evaluator::new(b"3!^2", &mut Cache::new(), &mut None, &mut Vec::new()).get_exps(),
2482 Ok(Ratio::from_integer(BigInt::from_biguint(
2483 Sign::Plus,
2484 BigUint::new(vec![36])
2485 )))
2486 );
2487 assert_eq!(
2489 Evaluator::new(b" 2^2", &mut Cache::new(), &mut None, &mut Vec::new()).get_exps(),
2490 Err(MissingTerm(0))
2491 );
2492 assert_eq!(
2493 Evaluator::new(b"\t2^2", &mut Cache::new(), &mut None, &mut Vec::new()).get_exps(),
2494 Err(MissingTerm(0))
2495 );
2496 }
2497 #[cfg(not(feature = "rand"))]
2498 #[test]
2499 fn neg() {
2500 assert_eq!(
2501 Evaluator::new(b"-1", &mut Cache::new(), &mut None, &mut Vec::new()).get_neg(),
2502 Ok(Ratio::from_integer(BigInt::from_biguint(
2503 Sign::Minus,
2504 BigUint::new(vec![1])
2505 )))
2506 );
2507 assert_eq!(
2508 Evaluator::new(b"- \t - 1", &mut Cache::new(), &mut None, &mut Vec::new()).get_neg(),
2509 Ok(Ratio::from_integer(BigInt::from_biguint(
2510 Sign::Plus,
2511 BigUint::new(vec![1])
2512 )))
2513 );
2514 assert_eq!(
2515 Evaluator::new(b"-0", &mut Cache::new(), &mut None, &mut Vec::new()).get_neg(),
2516 Ok(Ratio::from_integer(BigInt::from_biguint(
2517 Sign::NoSign,
2518 BigUint::new(Vec::new())
2519 )))
2520 );
2521 assert_eq!(
2523 Evaluator::new(b"-2^2", &mut Cache::new(), &mut None, &mut Vec::new()).get_neg(),
2524 Ok(Ratio::from_integer(BigInt::from_biguint(
2525 Sign::Minus,
2526 BigUint::new(vec![4])
2527 )))
2528 );
2529 assert_eq!(
2531 Evaluator::new(b"2.0^2.0", &mut Cache::new(), &mut None, &mut Vec::new()).get_neg(),
2532 Ok(Ratio::from_integer(BigInt::from_biguint(
2533 Sign::Plus,
2534 BigUint::new(vec![4])
2535 )))
2536 );
2537 assert_eq!(
2539 Evaluator::new(b" -2", &mut Cache::new(), &mut None, &mut Vec::new()).get_neg(),
2540 Err(MissingTerm(0))
2541 );
2542 assert_eq!(
2543 Evaluator::new(b"\t-2", &mut Cache::new(), &mut None, &mut Vec::new()).get_neg(),
2544 Err(MissingTerm(0))
2545 );
2546 }
2547 #[expect(
2548 clippy::cognitive_complexity,
2549 clippy::too_many_lines,
2550 reason = "a lot to test"
2551 )]
2552 #[cfg(not(feature = "rand"))]
2553 #[test]
2554 fn mult() {
2555 assert_eq!(
2556 Evaluator::new(b"2 * 3", &mut Cache::new(), &mut None, &mut Vec::new()).get_mults(),
2557 Ok(Ratio::from_integer(BigInt::from_biguint(
2558 Sign::Plus,
2559 BigUint::new(vec![6])
2560 )))
2561 );
2562 assert_eq!(
2563 Evaluator::new(
2564 b"-2 * \t 3",
2565 &mut Cache::new(),
2566 &mut None,
2567 &mut Vec::new()
2568 )
2569 .get_mults(),
2570 Ok(Ratio::from_integer(BigInt::from_biguint(
2571 Sign::Minus,
2572 BigUint::new(vec![6])
2573 )))
2574 );
2575 assert_eq!(
2576 Evaluator::new(
2577 b"2\t * -3.0",
2578 &mut Cache::new(),
2579 &mut None,
2580 &mut Vec::new()
2581 )
2582 .get_mults(),
2583 Ok(Ratio::from_integer(BigInt::from_biguint(
2584 Sign::Minus,
2585 BigUint::new(vec![6])
2586 )))
2587 );
2588 assert_eq!(
2589 Evaluator::new(b"-2.5*-3.5", &mut Cache::new(), &mut None, &mut Vec::new()).get_mults(),
2590 Ok(Ratio::new(
2591 BigInt::from_biguint(Sign::Plus, BigUint::new(vec![35])),
2592 BigInt::from_biguint(Sign::Plus, BigUint::new(vec![4]))
2593 ))
2594 );
2595 assert_eq!(
2596 Evaluator::new(b"4.0\t / 6", &mut Cache::new(), &mut None, &mut Vec::new())
2597 .get_mults(),
2598 Ok(Ratio::new(
2599 BigInt::from_biguint(Sign::Plus, BigUint::new(vec![2])),
2600 BigInt::from_biguint(Sign::Plus, BigUint::new(vec![3]))
2601 ))
2602 );
2603 assert_eq!(
2604 Evaluator::new(b"6/3", &mut Cache::new(), &mut None, &mut Vec::new()).get_mults(),
2605 Ok(Ratio::from_integer(BigInt::from_biguint(
2606 Sign::Plus,
2607 BigUint::new(vec![2])
2608 )))
2609 );
2610 assert_eq!(
2611 Evaluator::new(b"-6/3", &mut Cache::new(), &mut None, &mut Vec::new()).get_mults(),
2612 Ok(Ratio::from_integer(BigInt::from_biguint(
2613 Sign::Minus,
2614 BigUint::new(vec![2])
2615 )))
2616 );
2617 assert_eq!(
2618 Evaluator::new(b"6/-3", &mut Cache::new(), &mut None, &mut Vec::new()).get_mults(),
2619 Ok(Ratio::from_integer(BigInt::from_biguint(
2620 Sign::Minus,
2621 BigUint::new(vec![2])
2622 )))
2623 );
2624 assert_eq!(
2625 Evaluator::new(
2626 b"- 6 /\t - 3",
2627 &mut Cache::new(),
2628 &mut None,
2629 &mut Vec::new()
2630 )
2631 .get_mults(),
2632 Ok(Ratio::from_integer(BigInt::from_biguint(
2633 Sign::Plus,
2634 BigUint::new(vec![2])
2635 )))
2636 );
2637 assert!(
2639 Evaluator::new(b"1/1.5", &mut Cache::new(), &mut None, &mut Vec::new())
2640 .get_mults()
2641 .is_ok_and(|r| {
2642 Evaluator::new(b"1/3/2", &mut Cache::new(), &mut None, &mut Vec::new())
2643 .get_mults()
2644 .is_ok_and(|r2| r != r2)
2645 })
2646 );
2647 assert!(
2648 Evaluator::new(b"1/1.5", &mut Cache::new(), &mut None, &mut Vec::new())
2649 .get_mults()
2650 .is_ok_and(|r| {
2651 Evaluator::new(b"1/(3/2)", &mut Cache::new(), &mut None, &mut Vec::new())
2652 .get_mults()
2653 .is_ok_and(|r2| r == r2)
2654 })
2655 );
2656 assert_eq!(
2658 Evaluator::new(b"-2.0", &mut Cache::new(), &mut None, &mut Vec::new()).get_mults(),
2659 Ok(Ratio::from_integer(BigInt::from_biguint(
2660 Sign::Minus,
2661 BigUint::new(vec![2])
2662 )))
2663 );
2664 assert_eq!(
2666 Evaluator::new(b" 2*2", &mut Cache::new(), &mut None, &mut Vec::new()).get_mults(),
2667 Err(MissingTerm(0))
2668 );
2669 assert_eq!(
2670 Evaluator::new(b"\t2/2", &mut Cache::new(), &mut None, &mut Vec::new()).get_mults(),
2671 Err(MissingTerm(0))
2672 );
2673 assert_eq!(
2674 Evaluator::new(
2675 b"4.0\t mod 6",
2676 &mut Cache::new(),
2677 &mut None,
2678 &mut Vec::new()
2679 )
2680 .get_mults(),
2681 Ok(Ratio::from_integer(BigInt::from_biguint(
2682 Sign::Plus,
2683 BigUint::new(vec![4])
2684 ),))
2685 );
2686 assert_eq!(
2687 Evaluator::new(b"5 mod 3", &mut Cache::new(), &mut None, &mut Vec::new()).get_mults(),
2688 Ok(Ratio::from_integer(BigInt::from_biguint(
2689 Sign::Plus,
2690 BigUint::new(vec![2])
2691 )))
2692 );
2693 assert_eq!(
2694 Evaluator::new(b"-5 mod 3", &mut Cache::new(), &mut None, &mut Vec::new()).get_mults(),
2695 Ok(Ratio::from_integer(BigInt::from_biguint(
2696 Sign::Plus,
2697 BigUint::new(vec![1])
2698 )))
2699 );
2700 assert_eq!(
2701 Evaluator::new(b"5 mod -3", &mut Cache::new(), &mut None, &mut Vec::new()).get_mults(),
2702 Ok(Ratio::from_integer(BigInt::from_biguint(
2703 Sign::Plus,
2704 BigUint::new(vec![2])
2705 )))
2706 );
2707 assert_eq!(
2708 Evaluator::new(
2709 b"-5 mod\t -3",
2710 &mut Cache::new(),
2711 &mut None,
2712 &mut Vec::new()
2713 )
2714 .get_mults(),
2715 Ok(Ratio::from_integer(BigInt::from_biguint(
2716 Sign::Plus,
2717 BigUint::new(vec![1])
2718 )))
2719 );
2720 assert_eq!(
2722 Evaluator::new(b"2/0", &mut Cache::new(), &mut None, &mut Vec::new()).get_mults(),
2723 Err(DivByZero(3))
2724 );
2725 assert_eq!(
2726 Evaluator::new(b"2 mod 0", &mut Cache::new(), &mut None, &mut Vec::new()).get_mults(),
2727 Err(ModZero(7))
2728 );
2729 assert_eq!(
2731 Evaluator::new(b"3.2 mod 1", &mut Cache::new(), &mut None, &mut Vec::new()).get_mults(),
2732 Err(ModIsNotInt(4))
2733 );
2734 assert_eq!(
2735 Evaluator::new(b"3 mod 3.2", &mut Cache::new(), &mut None, &mut Vec::new()).get_mults(),
2736 Err(ModIsNotInt(9))
2737 );
2738 assert_eq!(
2740 Evaluator::new(b"2*2^2", &mut Cache::new(), &mut None, &mut Vec::new()).get_mults(),
2741 Ok(Ratio::from_integer(BigInt::from_biguint(
2742 Sign::Plus,
2743 BigUint::new(vec![8])
2744 )))
2745 );
2746 assert_eq!(
2747 Evaluator::new(b"8/2^2", &mut Cache::new(), &mut None, &mut Vec::new()).get_mults(),
2748 Ok(Ratio::from_integer(BigInt::from_biguint(
2749 Sign::Plus,
2750 BigUint::new(vec![2])
2751 )))
2752 );
2753 assert_eq!(
2754 Evaluator::new(b"8 mod 3^2", &mut Cache::new(), &mut None, &mut Vec::new()).get_mults(),
2755 Ok(Ratio::from_integer(BigInt::from_biguint(
2756 Sign::Plus,
2757 BigUint::new(vec![8])
2758 )))
2759 );
2760 }
2761 #[expect(clippy::too_many_lines, reason = "a lot to test")]
2762 #[cfg(not(feature = "rand"))]
2763 #[test]
2764 fn add() {
2765 assert_eq!(
2766 Evaluator::new(b"2 + 3", &mut Cache::new(), &mut None, &mut Vec::new()).get_adds(),
2767 Ok(Ratio::from_integer(BigInt::from_biguint(
2768 Sign::Plus,
2769 BigUint::new(vec![5])
2770 )))
2771 );
2772 assert_eq!(
2773 Evaluator::new(b"-2 + 3", &mut Cache::new(), &mut None, &mut Vec::new()).get_adds(),
2774 Ok(Ratio::from_integer(BigInt::from_biguint(
2775 Sign::Plus,
2776 BigUint::new(vec![1])
2777 )))
2778 );
2779 assert_eq!(
2780 Evaluator::new(
2781 b"2 + \t -3.0",
2782 &mut Cache::new(),
2783 &mut None,
2784 &mut Vec::new()
2785 )
2786 .get_adds(),
2787 Ok(Ratio::from_integer(BigInt::from_biguint(
2788 Sign::Minus,
2789 BigUint::new(vec![1])
2790 )))
2791 );
2792 assert_eq!(
2793 Evaluator::new(b"-2.5+-3.5", &mut Cache::new(), &mut None, &mut Vec::new()).get_adds(),
2794 Ok(Ratio::from_integer(BigInt::from_biguint(
2795 Sign::Minus,
2796 BigUint::new(vec![6])
2797 )))
2798 );
2799 assert_eq!(
2800 Evaluator::new(b"4.0\t - 6", &mut Cache::new(), &mut None, &mut Vec::new()).get_adds(),
2801 Ok(Ratio::from_integer(BigInt::from_biguint(
2802 Sign::Minus,
2803 BigUint::new(vec![2])
2804 )))
2805 );
2806 assert_eq!(
2807 Evaluator::new(b"6-3", &mut Cache::new(), &mut None, &mut Vec::new()).get_adds(),
2808 Ok(Ratio::from_integer(BigInt::from_biguint(
2809 Sign::Plus,
2810 BigUint::new(vec![3])
2811 )))
2812 );
2813 assert_eq!(
2814 Evaluator::new(b"-6-3", &mut Cache::new(), &mut None, &mut Vec::new()).get_adds(),
2815 Ok(Ratio::from_integer(BigInt::from_biguint(
2816 Sign::Minus,
2817 BigUint::new(vec![9])
2818 )))
2819 );
2820 assert_eq!(
2821 Evaluator::new(b"6--3", &mut Cache::new(), &mut None, &mut Vec::new()).get_adds(),
2822 Ok(Ratio::from_integer(BigInt::from_biguint(
2823 Sign::Plus,
2824 BigUint::new(vec![9])
2825 )))
2826 );
2827 assert_eq!(
2828 Evaluator::new(
2829 b"- 6 -\t - 3",
2830 &mut Cache::new(),
2831 &mut None,
2832 &mut Vec::new()
2833 )
2834 .get_adds(),
2835 Ok(Ratio::from_integer(BigInt::from_biguint(
2836 Sign::Minus,
2837 BigUint::new(vec![3])
2838 )))
2839 );
2840 assert_eq!(
2842 Evaluator::new(b"2 * 8", &mut Cache::new(), &mut None, &mut Vec::new()).get_adds(),
2843 Ok(Ratio::from_integer(BigInt::from_biguint(
2844 Sign::Plus,
2845 BigUint::new(vec![16])
2846 )))
2847 );
2848 assert_eq!(
2849 Evaluator::new(b"8 /\t 2", &mut Cache::new(), &mut None, &mut Vec::new()).get_adds(),
2850 Ok(Ratio::from_integer(BigInt::from_biguint(
2851 Sign::Plus,
2852 BigUint::new(vec![4])
2853 )))
2854 );
2855 assert_eq!(
2857 Evaluator::new(b" 2+2", &mut Cache::new(), &mut None, &mut Vec::new()).get_adds(),
2858 Err(MissingTerm(0))
2859 );
2860 assert_eq!(
2861 Evaluator::new(b" 2-2", &mut Cache::new(), &mut None, &mut Vec::new()).get_adds(),
2862 Err(MissingTerm(0))
2863 );
2864 assert_eq!(
2866 Evaluator::new(b"2+2*2", &mut Cache::new(), &mut None, &mut Vec::new()).get_adds(),
2867 Ok(Ratio::from_integer(BigInt::from_biguint(
2868 Sign::Plus,
2869 BigUint::new(vec![6])
2870 )))
2871 );
2872 assert_eq!(
2873 Evaluator::new(b"2+2/2", &mut Cache::new(), &mut None, &mut Vec::new()).get_adds(),
2874 Ok(Ratio::from_integer(BigInt::from_biguint(
2875 Sign::Plus,
2876 BigUint::new(vec![3])
2877 )))
2878 );
2879 assert_eq!(
2880 Evaluator::new(b"2-2*2", &mut Cache::new(), &mut None, &mut Vec::new()).get_adds(),
2881 Ok(Ratio::from_integer(BigInt::from_biguint(
2882 Sign::Minus,
2883 BigUint::new(vec![2])
2884 )))
2885 );
2886 assert_eq!(
2887 Evaluator::new(b"2-2/2", &mut Cache::new(), &mut None, &mut Vec::new()).get_adds(),
2888 Ok(Ratio::from_integer(BigInt::from_biguint(
2889 Sign::Plus,
2890 BigUint::new(vec![1])
2891 )))
2892 );
2893 }
2894 #[cfg(not(feature = "rand"))]
2895 #[test]
2896 fn exit() {
2897 assert_eq!(
2898 Evaluator::new(b" q \n", &mut Cache::new(), &mut None, &mut Vec::new()).evaluate(),
2899 Ok(Exit)
2900 );
2901 assert_eq!(
2902 Evaluator::new(
2903 b" q \r\n",
2904 &mut Cache::new(),
2905 &mut None,
2906 &mut Vec::new()
2907 )
2908 .evaluate(),
2909 Ok(Exit)
2910 );
2911 assert_eq!(
2912 Evaluator::new(b"q\n", &mut Cache::new(), &mut None, &mut Vec::new()).evaluate(),
2913 Ok(Exit)
2914 );
2915 assert_eq!(
2916 Evaluator::new(b"q\r\n", &mut Cache::new(), &mut None, &mut Vec::new()).evaluate(),
2917 Ok(Exit)
2918 );
2919 assert_eq!(
2920 Evaluator::new(b"\rq\n", &mut Cache::new(), &mut None, &mut Vec::new()).evaluate(),
2921 Err(MissingTerm(0))
2922 );
2923 assert_eq!(
2924 Evaluator::new(b"\tq\n", &mut Cache::new(), &mut None, &mut Vec::new()).evaluate(),
2925 Ok(Exit)
2926 );
2927 assert_eq!(
2928 Evaluator::new(b"q\n\n", &mut Cache::new(), &mut None, &mut Vec::new()).evaluate(),
2929 Err(InvalidQuit)
2930 );
2931 assert_eq!(
2932 Evaluator::new(b"\nq\n", &mut Cache::new(), &mut None, &mut Vec::new()).evaluate(),
2933 Err(MissingTerm(0))
2934 );
2935 assert_eq!(
2936 Evaluator::new(b"q", &mut Cache::new(), &mut None, &mut Vec::new()).evaluate(),
2937 Ok(Exit)
2938 );
2939 }
2940 #[expect(clippy::unwrap_used, reason = "comment justifies correctness")]
2941 #[cfg(not(feature = "rand"))]
2942 #[test]
2943 fn store() {
2944 let mut prev = None;
2945 let mut cache = Cache::new();
2946 _ = Evaluator::new(b"1\n", &mut cache, &mut prev, &mut Vec::new())
2948 .evaluate()
2949 .unwrap();
2950 assert!(cache.is_empty());
2951 assert_eq!(
2952 Evaluator::new(b"s\n", &mut cache, &mut prev, &mut Vec::new()).evaluate(),
2953 Ok(Store(&Some(Ratio::from_integer(BigInt::from_biguint(
2954 Sign::Plus,
2955 BigUint::new(vec![1])
2956 )))))
2957 );
2958 assert_eq!(cache.len(), 1);
2959 assert_eq!(
2960 Evaluator::new(b"s2\n", &mut Cache::new(), &mut None, &mut Vec::new()).evaluate(),
2961 Err(InvalidStore)
2962 );
2963 }
2964 #[expect(clippy::too_many_lines, reason = "a lot to test")]
2965 #[cfg(not(feature = "rand"))]
2966 #[test]
2967 fn eval() {
2968 use core::str::FromStr as _;
2969 let mut prev = None;
2970 let mut cache = Cache::new();
2971 let mut exp = Vec::new();
2972 assert_eq!(
2973 Evaluator::new(b"1+2\n", &mut cache, &mut prev, &mut exp).evaluate(),
2974 Ok(Eval(&Ratio::from_integer(BigInt::from_biguint(
2975 Sign::Plus,
2976 BigUint::new(vec![3])
2977 ))))
2978 );
2979 assert_eq!(
2980 Evaluator::new(b"\t s \n", &mut cache, &mut prev, &mut exp).evaluate(),
2981 Ok(Store(&Some(Ratio::from_integer(BigInt::from_biguint(
2982 Sign::Plus,
2983 BigUint::new(vec![3])
2984 )))))
2985 );
2986 assert_eq!(
2987 Evaluator::new(b"-1/2+2*@\n", &mut cache, &mut prev, &mut exp).evaluate(),
2988 Ok(Eval(&Ratio::new(
2989 BigInt::from_biguint(Sign::Plus, BigUint::new(vec![11])),
2990 BigInt::from_biguint(Sign::Plus, BigUint::new(vec![2]))
2991 )))
2992 );
2993 assert_eq!(
2994 Evaluator::new(b"s\n", &mut cache, &mut prev, &mut exp).evaluate(),
2995 Ok(Store(&Some(Ratio::new(
2996 BigInt::from_biguint(Sign::Plus, BigUint::new(vec![11])),
2997 BigInt::from_biguint(Sign::Plus, BigUint::new(vec![2]))
2998 ))))
2999 );
3000 assert_eq!(
3001 Evaluator::new(b"@^@2!\r\n", &mut cache, &mut prev, &mut exp).evaluate(),
3002 Ok(Eval(&Ratio::new(
3003 BigInt::from_biguint(Sign::Plus, BigUint::new(vec![1_771_561])),
3004 BigInt::from_biguint(Sign::Plus, BigUint::new(vec![64]))
3005 )))
3006 );
3007 assert_eq!(
3008 Evaluator::new(b"s\n", &mut cache, &mut prev, &mut exp).evaluate(),
3009 Ok(Store(&Some(Ratio::new(
3010 BigInt::from_biguint(Sign::Plus, BigUint::new(vec![1_771_561])),
3011 BigInt::from_biguint(Sign::Plus, BigUint::new(vec![64]))
3012 ))))
3013 );
3014 assert!(
3016 Evaluator::new(
3017 b" \t 1 + (2 * |(7.98\t - 12/7)|) / 4!^@3!^|1-3|\t \n",
3018 &mut cache,
3019 &mut prev,
3020 &mut exp
3021 )
3022 .evaluate().is_ok_and(|r| {
3023 Ratio::from_str("2841328814244153299237884950647090899374680152474331/2841328814244153299237884950647090899374680152473600").is_ok_and(|r2| {
3024 r == Eval(&r2)
3025 })
3026 })
3027 );
3028 assert_eq!(
3029 Evaluator::new(
3030 b" \t round(19/6,0)!\t \r\n",
3031 &mut cache,
3032 &mut prev,
3033 &mut exp
3034 )
3035 .evaluate(),
3036 Ok(Eval(&Ratio::from_integer(BigInt::from_biguint(
3037 Sign::Plus,
3038 BigUint::new(vec![6])
3039 ))))
3040 );
3041 assert_eq!(
3042 Evaluator::new(
3043 b" \t 2^round(19/6,0)!\t \r\n",
3044 &mut cache,
3045 &mut prev,
3046 &mut exp
3047 )
3048 .evaluate(),
3049 Ok(Eval(&Ratio::from_integer(BigInt::from_biguint(
3050 Sign::Plus,
3051 BigUint::new(vec![64])
3052 ))))
3053 );
3054 assert_eq!(
3055 Evaluator::new(b"round(19/6,0)^2\t\n", &mut cache, &mut prev, &mut exp).evaluate(),
3056 Ok(Eval(&Ratio::from_integer(BigInt::from_biguint(
3057 Sign::Plus,
3058 BigUint::new(vec![9])
3059 ))))
3060 );
3061 assert_eq!(
3063 Evaluator::new(&[255, 255, 255, b'\n'], &mut cache, &mut prev, &mut exp).evaluate(),
3064 Err(MissingTerm(0))
3065 );
3066 assert_eq!(
3067 Evaluator::new(&[b'2', 255, b'\n'], &mut cache, &mut prev, &mut exp).evaluate(),
3068 Err(TrailingSyms(1))
3069 );
3070 assert_eq!(
3072 Evaluator::new(b"2\n\n", &mut cache, &mut prev, &mut exp).evaluate(),
3073 Err(TrailingSyms(1))
3074 );
3075 assert_eq!(
3076 prev,
3077 Some(Ratio::from_integer(BigInt::from_biguint(
3078 Sign::Plus,
3079 BigUint::new(vec![9])
3080 )))
3081 );
3082 assert_eq!(
3083 Evaluator::new(b"\n", &mut cache, &mut prev.clone(), &mut exp).evaluate(),
3084 Ok(Empty(&Some(Ratio::from_integer(BigInt::from_biguint(
3085 Sign::Plus,
3086 BigUint::new(vec![9])
3087 )))))
3088 );
3089 assert_eq!(
3090 prev,
3091 Some(Ratio::from_integer(BigInt::from_biguint(
3092 Sign::Plus,
3093 BigUint::new(vec![9])
3094 )))
3095 );
3096 assert_eq!(
3097 Evaluator::new(b"\r\n", &mut cache, &mut prev.clone(), &mut exp).evaluate(),
3098 Ok(Empty(&prev))
3099 );
3100 assert_eq!(
3101 Evaluator::new(&[0u8; 0], &mut cache, &mut prev.clone(), &mut exp).evaluate(),
3102 Ok(Empty(&prev))
3103 );
3104 }
3105 #[cfg(feature = "rand")]
3106 #[test]
3107 fn eval_iter() {
3108 struct Reader<'a> {
3109 data: &'a [u8],
3110 err: bool,
3111 }
3112 impl<'a> Reader<'a> {
3113 fn new(data: &'a [u8]) -> Self {
3114 Self { data, err: true }
3115 }
3116 }
3117 impl Read for Reader<'_> {
3118 #[expect(clippy::indexing_slicing, reason = "comment justifies correctness")]
3119 fn read(&mut self, buf: &mut [u8]) -> io::Result<usize> {
3120 if self.err {
3121 self.err = false;
3122 Err(Error::other(""))
3123 } else {
3124 let len = usize::min(buf.len(), self.data.len());
3125 buf[..len].copy_from_slice(&self.data[..len]);
3127 Ok(len)
3128 }
3129 }
3130 }
3131 impl BufRead for Reader<'_> {
3132 fn fill_buf(&mut self) -> io::Result<&[u8]> {
3133 if self.err {
3134 self.err = false;
3135 Err(Error::other(""))
3136 } else {
3137 Ok(self.data)
3138 }
3139 }
3140 #[expect(clippy::indexing_slicing, reason = "comment justifies correctness")]
3141 fn consume(&mut self, amount: usize) {
3142 self.data = &self.data[amount..];
3144 }
3145 }
3146 let mut iter = EvalIter::new(Reader::new(
3147 b"1+2\n4\n\nq\n5\ns\nrand() + rand(-139/@, 2984/134)\nab",
3148 ));
3149 assert!(
3150 iter.lend_next()
3151 .is_some_and(|res| res.map_or_else(|e| matches!(e, E::Error(_)), |_| false))
3152 );
3153 assert!(iter.lend_next().is_some_and(|res| {
3154 res.is_ok_and(|e| matches!(e, Eval(r) if r.numer().to_i32() == Some(3i32)))
3155 }));
3156 assert!(iter.lend_next().is_some_and(|res| {
3157 res.is_ok_and(|e| matches!(e, Eval(r) if r.numer().to_i32() == Some(4i32)))
3158 }));
3159 assert!(iter.lend_next().is_some_and(|res| {
3160 res.is_ok_and(
3161 |e| matches!(e, Empty(r) if r.as_ref().is_some_and(|val| val.numer().to_i32() == Some(4i32))),
3162 )
3163 }));
3164 assert!(iter.lend_next().is_none());
3165 assert!(iter.lend_next().is_some_and(|res| {
3166 res.is_ok_and(|e| matches!(e, Eval(r) if r.numer().to_i32() == Some(5i32)))
3167 }));
3168 assert!(iter.lend_next().is_some_and(|res| {
3169 res.is_ok_and(
3170 |e| matches!(e, Store(r) if r.as_ref().is_some_and(|val| val.numer().to_i32() == Some(5i32))),
3171 )
3172 }));
3173 assert!(
3174 iter.lend_next()
3175 .is_some_and(|res| res.is_ok_and(|e| matches!(e, Eval(r) if r.is_integer())))
3176 );
3177 assert!(iter.lend_next().is_some_and(|res| {
3178 res.is_err_and(|err| matches!(err, E::LangErr(ref e) if matches!(*e, MissingTerm(_))))
3179 }));
3180 assert!(iter.lend_next().is_none());
3181 assert!(iter.lend_next().is_none());
3182 assert!(iter.lend_next().is_none());
3183 }
3184}