#![no_std]
#![deny(
unsafe_code,
unused,
warnings,
clippy::all,
clippy::cargo,
clippy::nursery,
clippy::pedantic
)]
#![allow(
clippy::arithmetic_side_effects,
clippy::exhaustive_enums,
clippy::implicit_return,
clippy::integer_arithmetic,
clippy::into_iter_on_ref,
clippy::question_mark,
clippy::single_char_lifetime_names,
clippy::unseparated_literal_suffix
)]
extern crate alloc;
use alloc::string::{String, ToString};
use alloc::vec;
use alloc::vec::Vec;
use cache::Cache;
use core::convert;
use core::fmt::{self, Display, Formatter};
use num_bigint::{BigInt, BigUint, Sign};
use num_rational::Ratio;
use num_integer::Integer;
use num_traits::Pow;
use E::{
DivByZero, ExpDivByZero, ExpIsNotInt, InvalidAbs, InvalidDec, InvalidPar, InvalidQuit,
InvalidRecall, MissingLF, MissingTerm, NotEnoughPrevResults, NotNonNegIntFact, TrailingSyms,
};
use O::{Empty, Exit, Prev, Val};
pub mod cache;
#[derive(Debug)]
pub struct PrevVal<'a> {
val: &'a Ratio<BigInt>,
round: Option<u8>,
}
impl<'a> Display for PrevVal<'a> {
#[inline]
#[allow(unsafe_code, clippy::as_conversions, clippy::indexing_slicing)]
fn fmt(&self, f: &mut Formatter<'_>) -> fmt::Result {
if let Some(rem) = self.round {
let r = rem as usize;
let mult = BigInt::from_biguint(Sign::Plus, BigUint::new(vec![10])).pow(r);
let (int, frac) = (self.val * &mult).round().numer().div_rem(&mult);
let int_str = int.to_string().into_bytes();
let frac_str = frac.to_string().into_bytes();
let mut v = Vec::with_capacity(int_str.len() + 2 + r);
let frac_val = match (int_str[0] == b'-', frac_str[0] == b'-') {
(false, true) => {
v.push(b'-');
&frac_str[1..]
}
(true, true) => &frac_str[1..],
_ => frac_str.as_slice(),
};
v.extend_from_slice(int_str.as_slice());
if r > 0 {
v.push(b'.');
let len = v.len();
while v.len() < len + r - frac_val.len() {
v.push(b'0');
}
v.extend_from_slice(frac_val);
}
writeln!(f, "> {}", unsafe { String::from_utf8_unchecked(v) })
} else {
writeln!(f, "> {}", self.val)
}
}
}
#[derive(Clone, Copy, Debug)]
pub enum E {
MissingLF,
InvalidQuit,
InvalidRecall,
DivByZero(usize),
ExpIsNotInt(usize),
ExpDivByZero(usize),
NotNonNegIntFact(usize),
InvalidDec(usize),
NotEnoughPrevResults(u8),
InvalidAbs(usize),
InvalidPar(usize),
MissingTerm(usize),
TrailingSyms(usize),
}
impl Display for E {
#[inline]
fn fmt(&self, f: &mut Formatter<'_>) -> fmt::Result {
match *self {
MissingLF => f.write_str("The last character is not a line feed.\n"),
InvalidRecall => f.write_str("Invalid recall statement. A recall statement must be of the extended regex form: ^ *= *[0-9]?@[1-8]? *$.\n"),
InvalidQuit => f.write_str("Invalid quit statement. A quit statement must be of the extended regex form: ^ *q *$.\n"),
DivByZero(u) => writeln!(f, "Division by zero ending at position {u}."),
ExpIsNotInt(u) => writeln!(f, "Non-integer exponent with a base that was not 0 or 1 ending at position {u}."),
ExpDivByZero(u) => writeln!(f, "Non-negative exponent with a base of 0 ending at position {u}."),
NotNonNegIntFact(u) => writeln!(f, "Factorial of a rational number that was not a non-negative integer ending at position {u}."),
InvalidDec(u) => writeln!(f, "Invalid decimal literal expression ending at position {u}. A decimal literal expression must be of the extended regex form: *[0-9]+(\\.[0-9]+)?."),
NotEnoughPrevResults(len) => writeln!(f, "There are only {len} previous results."),
InvalidAbs(u) => writeln!(f, "Invalid absolute value expression ending at position {u}. An absolute value expression is an addition expression enclosed in '||'."),
InvalidPar(u) => writeln!(f, "Invalid parenthetical expression ending at position {u}. A parenthetical expression is an addition expression enclosed in '()'."),
MissingTerm(u) => writeln!(f, "Missing terminal expression at position {u}. A terminal expression is a decimal literal expression, recall expression, or addition expression enclosed in vertical bars or parentheses."),
TrailingSyms(u) => writeln!(f, "Trailing symbols starting at position {u}."),
}
}
}
#[derive(Debug)]
pub enum O<'a> {
Val(&'a Ratio<BigInt>),
Prev(PrevVal<'a>),
Empty,
Exit,
}
impl<'a> Display for O<'a> {
#[inline]
fn fmt(&self, f: &mut Formatter<'_>) -> fmt::Result {
match *self {
Val(r) => writeln!(f, "> {r}"),
Prev(ref p) => p.fmt(f),
Empty | Exit => Ok(()),
}
}
}
pub struct Evaluator<'input, 'cache, 'exp> {
utf8: &'input [u8],
i: usize,
prev: &'cache mut Cache<Ratio<BigInt>, 8>,
exp_cache: &'exp mut Vec<Ratio<BigInt>>,
}
impl<'input, 'cache, 'exp> Evaluator<'input, 'cache, 'exp> {
#[inline]
pub fn new(
utf8: &'input [u8],
prev: &'cache mut Cache<Ratio<BigInt>, 8>,
exp_cache: &'exp mut Vec<Ratio<BigInt>>,
) -> Evaluator<'input, 'cache, 'exp> {
Self {
utf8,
i: 0,
prev,
exp_cache,
}
}
#[inline]
#[allow(clippy::indexing_slicing)]
pub fn evaluate(mut self) -> Result<O<'cache>, E> {
self.utf8 = if self.utf8.last().map_or(true, |b| *b != b'\n') {
return Err(MissingLF)
} else {
&self.utf8[..(self.utf8.len() - 1)]
};
self.consume_ws();
let Some(b) = self.utf8.get(self.i) else {
return Ok(Empty)
};
if *b == b'=' {
self.i += 1;
self.consume_ws();
let Some(b2) = self.utf8.get(self.i) else {
return Err(InvalidRecall)
};
let b3 = *b2;
let round = b3.is_ascii_digit().then(|| {
self.i += 1;
b3 - b'0'
});
self.get_recall().map(|val| Prev(PrevVal { val, round }))
} else if *b == b'q' {
self.i += 1;
self.consume_ws();
if self.i == self.utf8.len() {
Ok(Exit)
} else {
Err(InvalidQuit)
}
} else {
self.get_adds().and_then(move |r| {
self.consume_ws();
if self.i == self.utf8.len() {
Ok(Val(self.prev.push(r)))
} else {
Err(TrailingSyms(self.i))
}
})
}
}
#[inline]
#[allow(clippy::indexing_slicing)]
fn consume_ws(&mut self) {
self.i += self.utf8[self.i..]
.into_iter()
.try_fold(0, |val, b| {
if *b == b' ' {
Ok(val + 1)
} else {
Err(val)
}
})
.map_or_else(convert::identity, convert::identity);
}
#[inline]
fn get_adds(&mut self) -> Result<Ratio<BigInt>, E> {
let mut left = self.get_mults()?;
let mut j;
self.consume_ws();
while let Some(i) = self.utf8.get(self.i) {
j = *i;
self.consume_ws();
if j == b'+' {
self.i += 1;
self.consume_ws();
left += self.get_mults()?;
} else if j == b'-' {
self.i += 1;
self.consume_ws();
left -= self.get_mults()?;
} else {
break;
}
}
Ok(left)
}
#[inline]
fn get_mults(&mut self) -> Result<Ratio<BigInt>, E> {
let mut left = self.get_neg()?;
let mut right;
let mut j;
self.consume_ws();
while let Some(i) = self.utf8.get(self.i) {
j = *i;
self.consume_ws();
if j == b'*' {
self.i += 1;
self.consume_ws();
left *= self.get_neg()?;
} else if j == b'/' {
self.i += 1;
self.consume_ws();
right = self.get_neg()?;
if right.numer().sign() == Sign::NoSign {
return Err(DivByZero(self.i));
}
left /= right;
} else {
break;
}
}
Ok(left)
}
#[inline]
fn get_neg(&mut self) -> Result<Ratio<BigInt>, E> {
let mut count = 0usize;
while let Some(b) = self.utf8.get(self.i) {
if *b == b'-' {
self.i += 1;
self.consume_ws();
count += 1;
} else {
break;
}
}
self.get_exps()
.map(|val| if count & 1 == 0 { val } else { -val })
}
#[inline]
#[allow(clippy::unwrap_used, clippy::unwrap_in_result)]
fn get_exps(&mut self) -> Result<Ratio<BigInt>, E> {
let mut t = self.get_fact()?;
let ix = self.exp_cache.len();
let mut prev;
let mut numer;
self.exp_cache.push(t);
self.consume_ws();
let mut j;
while let Some(i) = self.utf8.get(self.i) {
j = *i;
self.consume_ws();
if j == b'^' {
self.i += 1;
self.consume_ws();
t = self.get_neg()?;
prev = self.exp_cache.last().unwrap();
numer = prev.numer();
if numer.sign() == Sign::NoSign {
if t.numer().sign() == Sign::Minus {
return Err(ExpDivByZero(self.i));
}
self.exp_cache.push(t);
} else if prev.is_integer() {
if numer == &BigInt::new(Sign::Plus, vec![1]) {
} else if t.is_integer() {
self.exp_cache.push(t);
} else {
return Err(ExpIsNotInt(self.i));
}
} else if t.is_integer() {
self.exp_cache.push(t);
} else {
return Err(ExpIsNotInt(self.i));
}
} else {
break;
}
}
self.exp_cache.drain(ix..).try_rfold(
Ratio::from_integer(BigInt::new(Sign::Plus, vec![1])),
|exp, base| {
if exp.is_integer() {
Ok(base.pow(exp.numer()))
} else if base.numer().sign() == Sign::NoSign {
Ok(base)
} else {
Err(ExpIsNotInt(self.i))
}
},
)
}
#[inline]
fn get_fact(&mut self) -> Result<Ratio<BigInt>, E> {
#[inline]
fn fact(mut val: BigUint) -> BigUint {
let zero = BigUint::new(Vec::new());
let one = BigUint::new(vec![1]);
let mut calc = BigUint::new(vec![1]);
while val > zero {
calc *= &val;
val -= &one;
}
calc
}
let t = self.get_term()?;
let Some(b) = self.utf8.get(self.i) else {
return Ok(t)
};
if *b == b'!' {
self.i += 1;
if t.is_integer() {
let i = self.i;
t.numer()
.to_biguint()
.map_or_else(|| Err(NotNonNegIntFact(i)), |val| {
let mut factorial = fact(val);
while let Some(b2) = self.utf8.get(self.i) {
if *b2 == b'!' {
self.i += 1;
factorial = fact(factorial);
} else {
break;
}
}
Ok(Ratio::from_integer(BigInt::from_biguint(
Sign::Plus,
factorial,
)))
})
} else {
Err(NotNonNegIntFact(self.i))
}
} else {
Ok(t)
}
}
#[inline]
#[allow(clippy::option_if_let_else)]
fn get_term(&mut self) -> Result<Ratio<BigInt>, E> {
match self.get_rational() {
Ok(o) => match o {
Some(r) => Ok(r),
None => match self.get_prev() {
Ok(o2) => match o2 {
Some(r2) => Ok(r2.clone()),
None => self
.get_abs()
.and_then(|o3| o3.map_or_else(|| self.get_par(), Ok)),
},
Err(e2) => Err(e2),
},
},
Err(e) => Err(e),
}
}
#[inline]
fn get_par(&mut self) -> Result<Ratio<BigInt>, E> {
let Some(b) = self.utf8.get(self.i) else {
return Err(MissingTerm(self.i));
};
if *b == b'(' {
self.i += 1;
self.consume_ws();
let r = self.get_adds()?;
self.consume_ws();
let Some(b2) = self.utf8.get(self.i) else {
return Err(InvalidPar(self.i))
};
let b3 = *b2;
if b3 == b')' {
self.i += 1;
Ok(r)
} else {
Err(InvalidPar(self.i))
}
} else {
Err(MissingTerm(self.i))
}
}
#[inline]
fn get_abs(&mut self) -> Result<Option<Ratio<BigInt>>, E> {
let Some(b) = self.utf8.get(self.i) else {
return Ok(None)
};
if *b == b'|' {
self.i += 1;
self.consume_ws();
let r = self.get_adds()?;
self.consume_ws();
let Some(b2) = self.utf8.get(self.i) else {
return Err(InvalidAbs(self.i))
};
let b3 = *b2;
if b3 == b'|' {
self.i += 1;
Ok(Some(if r.numer().sign() == Sign::Minus {
-r
} else {
r
}))
} else {
Err(InvalidAbs(self.i))
}
} else {
Ok(None)
}
}
#[inline]
#[allow(clippy::as_conversions)]
fn get_prev_idx(&mut self) -> Option<usize> {
let Some(b) = self.utf8.get(self.i) else {
return None
};
(*b == b'@').then(|| {
self.i += 1;
self.utf8.get(self.i).map_or(0, |b2| {
if (b'1'..b'9').contains(b2) {
self.i += 1;
(*b2 - b'1') as usize
} else {
0
}
})
})
}
#[inline]
#[allow(clippy::as_conversions, clippy::cast_possible_truncation)]
fn get_prev(&mut self) -> Result<Option<&Ratio<BigInt>>, E> {
self.get_prev_idx().map_or_else(|| Ok(None), |i| {
self.prev
.get(i)
.map_or_else(|| Err(NotEnoughPrevResults(self.prev.len() as u8)), |r| Ok(Some(r)))
})
}
#[inline]
#[allow(clippy::as_conversions, clippy::cast_possible_truncation)]
fn get_recall(mut self) -> Result<&'cache Ratio<BigInt>, E> {
self.get_prev_idx().map_or_else(|| Err(InvalidRecall), move |i| {
self.consume_ws();
self.prev.get(i).map_or_else(|| Err(NotEnoughPrevResults(self.prev.len() as u8)), |val| {
if self.i == self.utf8.len() {
Ok(val)
} else {
Err(InvalidRecall)
}
})
})
}
#[inline]
#[allow(
clippy::as_conversions,
clippy::cast_lossless,
clippy::indexing_slicing
)]
fn get_rational(&mut self) -> Result<Option<Ratio<BigInt>>, E> {
#[inline]
fn to_biguint(v: &[u8]) -> (BigUint, usize) {
v.into_iter()
.try_fold((BigUint::new(Vec::new()), 0), |mut prev, d| {
if d.is_ascii_digit() {
prev.1 += 1;
prev.0 = prev.0 * 10u8 + (*d - b'0');
Ok(prev)
} else {
Err(prev)
}
})
.map_or_else(convert::identity, convert::identity)
}
let (int, len) = to_biguint(&self.utf8[self.i..]);
if len == 0 {
return Ok(None);
}
self.i += len;
if let Some(b) = self.utf8.get(self.i) {
if *b == b'.' {
self.i += 1;
let (numer, len2) = to_biguint(&self.utf8[self.i..]);
if len2 == 0 {
Err(InvalidDec(self.i))
} else {
self.i += len2;
Ok(Some(
Ratio::from_integer(BigInt::from_biguint(Sign::Plus, int))
+ Ratio::new(
BigInt::from_biguint(Sign::Plus, numer),
BigInt::from_biguint(Sign::Plus, BigUint::new(vec![10]).pow(len2)),
),
))
}
} else {
Ok(Some(Ratio::from_integer(BigInt::from_biguint(
Sign::Plus,
int,
))))
}
} else {
Ok(Some(Ratio::from_integer(BigInt::from_biguint(
Sign::Plus,
int,
))))
}
}
}
#[cfg(test)]
mod tests {
use super::*;
#[test]
fn prev_string() {
assert!(PrevVal { val: &Ratio::from_integer(BigInt::from_biguint(Sign::Plus, BigUint::new(vec![12]))), round: None }.to_string() == "> 12\n");
assert!(PrevVal { val: &Ratio::from_integer(BigInt::from_biguint(Sign::Plus, BigUint::new(vec![12]))), round: Some(0) }.to_string() == "> 12\n");
assert!(PrevVal { val: &Ratio::from_integer(BigInt::from_biguint(Sign::Minus, BigUint::new(vec![12]))), round: Some(1) }.to_string() == "> -12.0\n");
assert!(PrevVal { val: &Ratio::new(BigInt::from_biguint(Sign::Plus, BigUint::new(vec![2])), BigInt::from_biguint(Sign::Plus, BigUint::new(vec![3]))), round: None }.to_string() == "> 2/3\n");
assert!(PrevVal { val: &Ratio::new(BigInt::from_biguint(Sign::Minus, BigUint::new(vec![2])), BigInt::from_biguint(Sign::Plus, BigUint::new(vec![3]))), round: Some(0)}.to_string() == "> -1\n");
assert!(PrevVal { val: &Ratio::new(BigInt::from_biguint(Sign::Minus, BigUint::new(vec![2])), BigInt::from_biguint(Sign::Plus, BigUint::new(vec![3]))), round: Some(1)}.to_string() == "> -0.7\n");
assert!(PrevVal { val: &Ratio::new(BigInt::from_biguint(Sign::Minus, BigUint::new(vec![4])), BigInt::from_biguint(Sign::Plus, BigUint::new(vec![6]))), round: Some(2)}.to_string() == "> -0.67\n");
}
#[test]
fn number_literal() {
assert!(Evaluator::new(b"0", &mut Cache::new(), &mut Vec::new()).get_rational().unwrap().unwrap() == Ratio::from_integer(BigInt::from_biguint(Sign::NoSign, BigUint::new(Vec::new()))));
assert!(Evaluator::new(b"0000.00000", &mut Cache::new(), &mut Vec::new()).get_rational().unwrap().unwrap() == Ratio::from_integer(BigInt::from_biguint(Sign::NoSign, BigUint::new(Vec::new()))));
assert!(Evaluator::new(b"1 0", &mut Cache::new(), &mut Vec::new()).get_rational().unwrap().unwrap() == Ratio::from_integer(BigInt::from_biguint(Sign::Plus, BigUint::new(vec![1]))));
let int = b"3397450981271938475135134759823759835414";
let frac = b"913759810573549872354897210539127530981570";
let left = Ratio::from_integer(BigInt::parse_bytes(int, 10).unwrap());
let right = Ratio::new(BigInt::parse_bytes(frac, 10).unwrap(), BigInt::from_biguint(Sign::Plus, BigUint::new(vec![10]).pow(frac.len() + 1)));
let mut vec = Vec::new();
vec.extend_from_slice(int);
vec.push(b'.');
vec.push(b'0');
vec.extend_from_slice(frac);
assert!(Evaluator::new(vec.as_slice(), &mut Cache::new(), &mut Vec::new()).get_rational().unwrap().unwrap() == left + right);
assert!(Evaluator::new(b"000000014.0000000000000", &mut Cache::new(), &mut Vec::new()).get_rational().unwrap().unwrap() == Ratio::from_integer(BigInt::from_biguint(Sign::Plus, BigUint::new(vec![14]))));
assert!(match Evaluator::new(b"1.", &mut Cache::new(), &mut Vec::new()).get_rational().unwrap_err() {
E::InvalidDec(i) => i == 2,
_ => false,
});
assert!(match Evaluator::new(b"1. 2", &mut Cache::new(), &mut Vec::new()).get_rational().unwrap_err() {
E::InvalidDec(i) => i == 2,
_ => false,
});
assert!(Evaluator::new(b"a1", &mut Cache::new(), &mut Vec::new()).get_rational().unwrap().is_none());
assert!(Evaluator::new(b" 1", &mut Cache::new(), &mut Vec::new()).get_rational().unwrap().is_none());
assert!(Evaluator::new(b"-1", &mut Cache::new(), &mut Vec::new()).get_rational().unwrap().is_none());
assert!(Evaluator::new(b"1/2", &mut Cache::new(), &mut Vec::new()).get_rational().unwrap().unwrap() == Ratio::from_integer(BigInt::from_biguint(Sign::Plus, BigUint::new(vec![1]))));
assert!(Evaluator::new(b"130alj", &mut Cache::new(), &mut Vec::new()).get_rational().unwrap().unwrap() == Ratio::from_integer(BigInt::from_biguint(Sign::Plus, BigUint::new(vec![130]))));
}
#[test]
fn recall_expression() {
assert!(Evaluator::new(b"1", &mut Cache::new(), &mut Vec::new()).get_prev().unwrap().is_none());
assert!(Evaluator::new(b"a", &mut Cache::new(), &mut Vec::new()).get_prev().unwrap().is_none());
assert!(Evaluator::new(b" @", &mut Cache::new(), &mut Vec::new()).get_prev().unwrap().is_none());
assert!(match Evaluator::new(b"@", &mut Cache::new(), &mut Vec::new()).get_prev().unwrap_err() {
E::NotEnoughPrevResults(count) => count == 0,
_ => false,
});
assert!(match Evaluator::new(b"@4", &mut Cache::new(), &mut Vec::new()).get_prev().unwrap_err() {
E::NotEnoughPrevResults(count) => count == 0,
_ => false,
});
assert!(match Evaluator::new(b"@0", &mut Cache::new(), &mut Vec::new()).get_prev().unwrap_err() {
E::NotEnoughPrevResults(count) => count == 0,
_ => false,
});
let mut cache = Cache::new();
Evaluator::new(b"1\n", &mut cache, &mut Vec::new()).evaluate().unwrap();
assert!(Evaluator::new(b"@", &mut cache, &mut Vec::new()).get_prev().unwrap().unwrap() == &Ratio::from_integer(BigInt::from_biguint(Sign::Plus, BigUint::new(vec![1]))));
assert!(Evaluator::new(b"@&", &mut cache, &mut Vec::new()).get_prev().unwrap().unwrap() == &Ratio::from_integer(BigInt::from_biguint(Sign::Plus, BigUint::new(vec![1]))));
assert!(Evaluator::new(b"@0", &mut cache, &mut Vec::new()).get_prev().unwrap().unwrap() == &Ratio::from_integer(BigInt::from_biguint(Sign::Plus, BigUint::new(vec![1]))));
assert!(Evaluator::new(b"@9", &mut cache, &mut Vec::new()).get_prev().unwrap().unwrap() == &Ratio::from_integer(BigInt::from_biguint(Sign::Plus, BigUint::new(vec![1]))));
assert!(Evaluator::new(b"@ 2", &mut cache, &mut Vec::new()).get_prev().unwrap().unwrap() == &Ratio::from_integer(BigInt::from_biguint(Sign::Plus, BigUint::new(vec![1]))));
assert!(Evaluator::new(b"@10", &mut cache, &mut Vec::new()).get_prev().unwrap().unwrap() == &Ratio::from_integer(BigInt::from_biguint(Sign::Plus, BigUint::new(vec![1]))));
assert!(match Evaluator::new(b"@2", &mut cache, &mut Vec::new()).get_prev().unwrap_err() {
E::NotEnoughPrevResults(count) => count == 1,
_ => false,
});
Evaluator::new(b"2\n", &mut cache, &mut Vec::new()).evaluate().unwrap();
assert!(Evaluator::new(b"@", &mut cache, &mut Vec::new()).get_prev().unwrap().unwrap() == &Ratio::from_integer(BigInt::from_biguint(Sign::Plus, BigUint::new(vec![2]))));
assert!(Evaluator::new(b"@2", &mut cache, &mut Vec::new()).get_prev().unwrap().unwrap() == &Ratio::from_integer(BigInt::from_biguint(Sign::Plus, BigUint::new(vec![1]))));
assert!(match Evaluator::new(b"@3", &mut cache, &mut Vec::new()).get_prev().unwrap_err() {
E::NotEnoughPrevResults(count) => count == 2,
_ => false,
});
let mut v = vec![0, b'\n'];
for i in b'3'..=b'8' {
v[0] = i;
Evaluator::new(v.as_slice(), &mut cache, &mut Vec::new()).evaluate().unwrap();
}
v[0] = b'@';
for i in b'1'..=b'8' {
v[1] = i;
assert!(Evaluator::new(v.as_slice(), &mut cache, &mut Vec::new()).get_prev().unwrap().unwrap() == &Ratio::from_integer(BigInt::from_biguint(Sign::Plus, BigUint::new(vec![(b'9' - i) as u32]))));
}
assert!(Evaluator::new(b"@@", &mut cache, &mut Vec::new()).get_prev().unwrap().unwrap() == &Ratio::from_integer(BigInt::from_biguint(Sign::Plus, BigUint::new(vec![8]))));
Evaluator::new(b"9\n", &mut cache, &mut Vec::new()).evaluate().unwrap();
for i in b'1'..=b'8' {
v[1] = i;
assert!(Evaluator::new(v.as_slice(), &mut cache, &mut Vec::new()).get_prev().unwrap().unwrap() == &Ratio::from_integer(BigInt::from_biguint(Sign::Plus, BigUint::new(vec![((b'9' + 1) - i) as u32]))));
}
}
#[test]
fn abs() {
assert!(match Evaluator::new(b"|1", &mut Cache::new(), &mut Vec::new()).get_abs().unwrap_err() {
E::InvalidAbs(i) => i == 2,
_ => false,
});
assert!(match Evaluator::new(b"||1 + 2|", &mut Cache::new(), &mut Vec::new()).get_abs().unwrap_err() {
E::InvalidAbs(i) => i == 8,
_ => false,
});
assert!(Evaluator::new(b"| 0 |", &mut Cache::new(), &mut Vec::new()).get_abs().unwrap().unwrap() == Ratio::from_integer(BigInt::from_biguint(Sign::NoSign, BigUint::new(Vec::new()))));
assert!(Evaluator::new(b"| - 5 |", &mut Cache::new(), &mut Vec::new()).get_abs().unwrap().unwrap() == Ratio::from_integer(BigInt::from_biguint(Sign::Plus, BigUint::new(vec![5]))));
assert!(Evaluator::new(b"| | 2 - 5| * 9 |", &mut Cache::new(), &mut Vec::new()).get_abs().unwrap().unwrap() == Ratio::from_integer(BigInt::from_biguint(Sign::Plus, BigUint::new(vec![27]))));
assert!(Evaluator::new(b" |9|", &mut Cache::new(), &mut Vec::new()).get_abs().unwrap().is_none());
}
#[test]
fn par() {
assert!(match Evaluator::new(b"(1", &mut Cache::new(), &mut Vec::new()).get_par().unwrap_err() {
E::InvalidPar(i) => i == 2,
_ => false,
});
assert!(match Evaluator::new(b"((1 + 2)", &mut Cache::new(), &mut Vec::new()).get_par().unwrap_err() {
E::InvalidPar(i) => i == 8,
_ => false,
});
assert!(Evaluator::new(b"( 0 )", &mut Cache::new(), &mut Vec::new()).get_par().unwrap() == Ratio::from_integer(BigInt::from_biguint(Sign::NoSign, BigUint::new(Vec::new()))));
assert!(Evaluator::new(b"( - 5 )", &mut Cache::new(), &mut Vec::new()).get_par().unwrap() == Ratio::from_integer(BigInt::from_biguint(Sign::Minus, BigUint::new(vec![5]))));
assert!(Evaluator::new(b"( ( 2 - 5) * 9 )", &mut Cache::new(), &mut Vec::new()).get_par().unwrap() == Ratio::from_integer(BigInt::from_biguint(Sign::Minus, BigUint::new(vec![27]))));
assert!(match Evaluator::new(b" (2)", &mut Cache::new(), &mut Vec::new()).get_par().unwrap_err() {
E::MissingTerm(i) => i == 0,
_ => false,
});
}
#[test]
fn term() {
assert!(Evaluator::new(b"0000.00000", &mut Cache::new(), &mut Vec::new()).get_term().unwrap() == Ratio::from_integer(BigInt::from_biguint(Sign::NoSign, BigUint::new(Vec::new()))));
assert!(Evaluator::new(b"|4|", &mut Cache::new(), &mut Vec::new()).get_term().unwrap() == Ratio::from_integer(BigInt::from_biguint(Sign::Plus, BigUint::new(vec![4]))));
assert!(Evaluator::new(b"(4)", &mut Cache::new(), &mut Vec::new()).get_term().unwrap() == Ratio::from_integer(BigInt::from_biguint(Sign::Plus, BigUint::new(vec![4]))));
assert!(match Evaluator::new(b" 2", &mut Cache::new(), &mut Vec::new()).get_term().unwrap_err() {
E::MissingTerm(i) => i == 0,
_ => false,
});
let mut cache = Cache::new();
Evaluator::new(b"1\n", &mut cache, &mut Vec::new()).evaluate().unwrap();
assert!(Evaluator::new(b"@", &mut cache, &mut Vec::new()).get_term().unwrap() == Ratio::from_integer(BigInt::from_biguint(Sign::Plus, BigUint::new(vec![1]))));
}
#[test]
fn factorial() {
assert!(match Evaluator::new(b"(-1)!", &mut Cache::new(), &mut Vec::new()).get_fact().unwrap_err() {
E::NotNonNegIntFact(i) => i == 5,
_ => false,
});
assert!(match Evaluator::new(b"2.5!", &mut Cache::new(), &mut Vec::new()).get_fact().unwrap_err() {
E::NotNonNegIntFact(i) => i == 4,
_ => false,
});
assert!(Evaluator::new(b"7", &mut Cache::new(), &mut Vec::new()).get_fact().unwrap() == Ratio::from_integer(BigInt::from_biguint(Sign::Plus, BigUint::new(vec![7]))));
assert!(Evaluator::new(b"(7)", &mut Cache::new(), &mut Vec::new()).get_fact().unwrap() == Ratio::from_integer(BigInt::from_biguint(Sign::Plus, BigUint::new(vec![7]))));
assert!(Evaluator::new(b"|7|", &mut Cache::new(), &mut Vec::new()).get_fact().unwrap() == Ratio::from_integer(BigInt::from_biguint(Sign::Plus, BigUint::new(vec![7]))));
let mut cache = Cache::new();
Evaluator::new(b"3\n", &mut cache, &mut Vec::new()).evaluate().unwrap();
assert!(Evaluator::new(b"@!", &mut cache, &mut Vec::new()).get_fact().unwrap() == Ratio::from_integer(BigInt::from_biguint(Sign::Plus, BigUint::new(vec![6]))));
assert!(Evaluator::new(b"@", &mut cache, &mut Vec::new()).get_fact().unwrap() == Ratio::from_integer(BigInt::from_biguint(Sign::Plus, BigUint::new(vec![3]))));
assert!(Evaluator::new(b"0.0!", &mut Cache::new(), &mut Vec::new()).get_fact().unwrap() == Ratio::from_integer(BigInt::from_biguint(Sign::Plus, BigUint::new(vec![1]))));
assert!(Evaluator::new(b"1!", &mut Cache::new(), &mut Vec::new()).get_fact().unwrap() == Ratio::from_integer(BigInt::from_biguint(Sign::Plus, BigUint::new(vec![1]))));
assert!(Evaluator::new(b"4! ", &mut Cache::new(), &mut Vec::new()).get_fact().unwrap() == Ratio::from_integer(BigInt::from_biguint(Sign::Plus, BigUint::new(vec![24]))));
assert!(Evaluator::new(b"3!! ", &mut Cache::new(), &mut Vec::new()).get_fact().unwrap() == Ratio::from_integer(BigInt::from_biguint(Sign::Plus, BigUint::new(vec![720]))));
assert!(Evaluator::new(b"2!+3", &mut Cache::new(), &mut Vec::new()).get_fact().unwrap() == Ratio::from_integer(BigInt::from_biguint(Sign::Plus, BigUint::new(vec![2]))));
assert!(match Evaluator::new(b" 2!", &mut Cache::new(), &mut Vec::new()).get_fact().unwrap_err() {
E::MissingTerm(i) => i == 0,
_ => false,
});
assert!(match Evaluator::new(b"-2!", &mut Cache::new(), &mut Vec::new()).get_fact().unwrap_err() {
E::MissingTerm(i) => i == 0,
_ => false,
});
}
#[test]
fn exp() {
assert!(Evaluator::new(b"1 ^ 0", &mut Cache::new(), &mut Vec::new()).get_exps().unwrap() == Ratio::from_integer(BigInt::from_biguint(Sign::Plus, BigUint::new(vec![1]))));
assert!(Evaluator::new(b"1^0.5", &mut Cache::new(), &mut Vec::new()).get_exps().unwrap() == Ratio::from_integer(BigInt::from_biguint(Sign::Plus, BigUint::new(vec![1]))));
assert!(Evaluator::new(b"1^(-1/2)", &mut Cache::new(), &mut Vec::new()).get_exps().unwrap() == Ratio::from_integer(BigInt::from_biguint(Sign::Plus, BigUint::new(vec![1]))));
assert!(Evaluator::new(b"1.0^(-2)", &mut Cache::new(), &mut Vec::new()).get_exps().unwrap() == Ratio::from_integer(BigInt::from_biguint(Sign::Plus, BigUint::new(vec![1]))));
assert!(Evaluator::new(b"0^0", &mut Cache::new(), &mut Vec::new()).get_exps().unwrap() == Ratio::from_integer(BigInt::from_biguint(Sign::Plus, BigUint::new(vec![1]))));
assert!(Evaluator::new(b"0^1", &mut Cache::new(), &mut Vec::new()).get_exps().unwrap() == Ratio::from_integer(BigInt::from_biguint(Sign::NoSign, BigUint::new(vec![0]))));
assert!(Evaluator::new(b"0^0.5", &mut Cache::new(), &mut Vec::new()).get_exps().unwrap() == Ratio::from_integer(BigInt::from_biguint(Sign::NoSign, BigUint::new(vec![0]))));
assert!(Evaluator::new(b"4^0", &mut Cache::new(), &mut Vec::new()).get_exps().unwrap() == Ratio::from_integer(BigInt::from_biguint(Sign::Plus, BigUint::new(vec![1]))));
assert!(Evaluator::new(b"4^1", &mut Cache::new(), &mut Vec::new()).get_exps().unwrap() == Ratio::from_integer(BigInt::from_biguint(Sign::Plus, BigUint::new(vec![4]))));
assert!(Evaluator::new(b"4^(-2)", &mut Cache::new(), &mut Vec::new()).get_exps().unwrap() == Ratio::new(BigInt::from_biguint(Sign::Plus, BigUint::new(vec![1])), BigInt::from_biguint(Sign::Plus, BigUint::new(vec![16]))));
assert!(Evaluator::new(b"(-4)^0", &mut Cache::new(), &mut Vec::new()).get_exps().unwrap() == Ratio::from_integer(BigInt::from_biguint(Sign::Plus, BigUint::new(vec![1]))));
assert!(Evaluator::new(b"(-4)^1", &mut Cache::new(), &mut Vec::new()).get_exps().unwrap() == Ratio::from_integer(BigInt::from_biguint(Sign::Minus, BigUint::new(vec![4]))));
assert!(Evaluator::new(b"(-4)^2", &mut Cache::new(), &mut Vec::new()).get_exps().unwrap() == Ratio::from_integer(BigInt::from_biguint(Sign::Plus, BigUint::new(vec![16]))));
assert!(Evaluator::new(b"(-4)^(-2)", &mut Cache::new(), &mut Vec::new()).get_exps().unwrap() == Ratio::new(BigInt::from_biguint(Sign::Plus, BigUint::new(vec![1])), BigInt::from_biguint(Sign::Plus, BigUint::new(vec![16]))));
assert!(Evaluator::new(b"(-4)^(-3)", &mut Cache::new(), &mut Vec::new()).get_exps().unwrap() == Ratio::new(BigInt::from_biguint(Sign::Minus, BigUint::new(vec![1])), BigInt::from_biguint(Sign::Plus, BigUint::new(vec![64]))));
assert!(Evaluator::new(b"(2/3)^0", &mut Cache::new(), &mut Vec::new()).get_exps().unwrap() == Ratio::from_integer(BigInt::from_biguint(Sign::Plus, BigUint::new(vec![1]))));
assert!(Evaluator::new(b"(2/3)^(2)", &mut Cache::new(), &mut Vec::new()).get_exps().unwrap() == Ratio::new(BigInt::from_biguint(Sign::Plus, BigUint::new(vec![4])), BigInt::from_biguint(Sign::Plus, BigUint::new(vec![9]))));
assert!(Evaluator::new(b"(2/3)^(-3)", &mut Cache::new(), &mut Vec::new()).get_exps().unwrap() == Ratio::new(BigInt::from_biguint(Sign::Plus, BigUint::new(vec![27])), BigInt::from_biguint(Sign::Plus, BigUint::new(vec![8]))));
assert!(Evaluator::new(b"(-2/3)^0", &mut Cache::new(), &mut Vec::new()).get_exps().unwrap() == Ratio::from_integer(BigInt::from_biguint(Sign::Plus, BigUint::new(vec![1]))));
assert!(Evaluator::new(b"(-2/3)^(2)", &mut Cache::new(), &mut Vec::new()).get_exps().unwrap() == Ratio::new(BigInt::from_biguint(Sign::Plus, BigUint::new(vec![4])), BigInt::from_biguint(Sign::Plus, BigUint::new(vec![9]))));
assert!(Evaluator::new(b"(-2/3)^(3)", &mut Cache::new(), &mut Vec::new()).get_exps().unwrap() == Ratio::new(BigInt::from_biguint(Sign::Minus, BigUint::new(vec![8])), BigInt::from_biguint(Sign::Plus, BigUint::new(vec![27]))));
assert!(Evaluator::new(b"(-2/3)^(-2)", &mut Cache::new(), &mut Vec::new()).get_exps().unwrap() == Ratio::new(BigInt::from_biguint(Sign::Plus, BigUint::new(vec![9])), BigInt::from_biguint(Sign::Plus, BigUint::new(vec![4]))));
assert!(Evaluator::new(b"(-2/3)^(-3)", &mut Cache::new(), &mut Vec::new()).get_exps().unwrap() == Ratio::new(BigInt::from_biguint(Sign::Minus, BigUint::new(vec![27])), BigInt::from_biguint(Sign::Plus, BigUint::new(vec![8]))));
assert!(match Evaluator::new(b"0^(-1)", &mut Cache::new(), &mut Vec::new()).get_exps().unwrap_err() {
E::ExpDivByZero(i) => i == 6,
_ => false,
});
assert!(match Evaluator::new(b"2^(1/2)", &mut Cache::new(), &mut Vec::new()).get_exps().unwrap_err() {
E::ExpIsNotInt(i) => i == 7,
_ => false,
});
assert!(Evaluator::new(b"3!", &mut Cache::new(), &mut Vec::new()).get_exps().unwrap() == Ratio::from_integer(BigInt::from_biguint(Sign::Plus, BigUint::new(vec![6]))));
assert!(Evaluator::new(b"2^3!", &mut Cache::new(), &mut Vec::new()).get_exps().unwrap() == Ratio::from_integer(BigInt::from_biguint(Sign::Plus, BigUint::new(vec![64]))));
assert!(Evaluator::new(b"3!^2", &mut Cache::new(), &mut Vec::new()).get_exps().unwrap() == Ratio::from_integer(BigInt::from_biguint(Sign::Plus, BigUint::new(vec![36]))));
assert!(match Evaluator::new(b" 2^2", &mut Cache::new(), &mut Vec::new()).get_exps().unwrap_err() {
E::MissingTerm(i) => i == 0,
_ => false,
});
}
#[test]
fn neg() {
assert!(Evaluator::new(b"-1", &mut Cache::new(), &mut Vec::new()).get_neg().unwrap() == Ratio::from_integer(BigInt::from_biguint(Sign::Minus, BigUint::new(vec![1]))));
assert!(Evaluator::new(b"- - 1", &mut Cache::new(), &mut Vec::new()).get_neg().unwrap() == Ratio::from_integer(BigInt::from_biguint(Sign::Plus, BigUint::new(vec![1]))));
assert!(Evaluator::new(b"-0", &mut Cache::new(), &mut Vec::new()).get_neg().unwrap() == Ratio::from_integer(BigInt::from_biguint(Sign::NoSign, BigUint::new(Vec::new()))));
assert!(Evaluator::new(b"-2^2", &mut Cache::new(), &mut Vec::new()).get_neg().unwrap() == Ratio::from_integer(BigInt::from_biguint(Sign::Minus, BigUint::new(vec![4]))));
assert!(Evaluator::new(b"2.0^2.0", &mut Cache::new(), &mut Vec::new()).get_neg().unwrap() == Ratio::from_integer(BigInt::from_biguint(Sign::Plus, BigUint::new(vec![4]))));
assert!(match Evaluator::new(b" -2", &mut Cache::new(), &mut Vec::new()).get_neg().unwrap_err() {
E::MissingTerm(i) => i == 0,
_ => false,
});
}
#[test]
fn mult() {
assert!(Evaluator::new(b"2 * 3", &mut Cache::new(), &mut Vec::new()).get_mults().unwrap() == Ratio::from_integer(BigInt::from_biguint(Sign::Plus, BigUint::new(vec![6]))));
assert!(Evaluator::new(b"-2 * 3", &mut Cache::new(), &mut Vec::new()).get_mults().unwrap() == Ratio::from_integer(BigInt::from_biguint(Sign::Minus, BigUint::new(vec![6]))));
assert!(Evaluator::new(b"2 * -3.0", &mut Cache::new(), &mut Vec::new()).get_mults().unwrap() == Ratio::from_integer(BigInt::from_biguint(Sign::Minus, BigUint::new(vec![6]))));
assert!(Evaluator::new(b"-2.5*-3.5", &mut Cache::new(), &mut Vec::new()).get_mults().unwrap() == Ratio::new(BigInt::from_biguint(Sign::Plus, BigUint::new(vec![35])), BigInt::from_biguint(Sign::Plus, BigUint::new(vec![4]))));
assert!(Evaluator::new(b"4.0 / 6", &mut Cache::new(), &mut Vec::new()).get_mults().unwrap() == Ratio::new(BigInt::from_biguint(Sign::Plus, BigUint::new(vec![2])), BigInt::from_biguint(Sign::Plus, BigUint::new(vec![3]))));
assert!(Evaluator::new(b"6/3", &mut Cache::new(), &mut Vec::new()).get_mults().unwrap() == Ratio::from_integer(BigInt::from_biguint(Sign::Plus, BigUint::new(vec![2]))));
assert!(Evaluator::new(b"-6/3", &mut Cache::new(), &mut Vec::new()).get_mults().unwrap() == Ratio::from_integer(BigInt::from_biguint(Sign::Minus, BigUint::new(vec![2]))));
assert!(Evaluator::new(b"6/-3", &mut Cache::new(), &mut Vec::new()).get_mults().unwrap() == Ratio::from_integer(BigInt::from_biguint(Sign::Minus, BigUint::new(vec![2]))));
assert!(Evaluator::new(b"- 6 / - 3", &mut Cache::new(), &mut Vec::new()).get_mults().unwrap() == Ratio::from_integer(BigInt::from_biguint(Sign::Plus, BigUint::new(vec![2]))));
assert!(Evaluator::new(b"1/1.5", &mut Cache::new(), &mut Vec::new()).get_mults().unwrap() != Evaluator::new(b"1/3/2", &mut Cache::new(), &mut Vec::new()).get_mults().unwrap());
assert!(Evaluator::new(b"1/1.5", &mut Cache::new(), &mut Vec::new()).get_mults().unwrap() == Evaluator::new(b"1/(3/2)", &mut Cache::new(), &mut Vec::new()).get_mults().unwrap());
assert!(Evaluator::new(b"-2.0", &mut Cache::new(), &mut Vec::new()).get_mults().unwrap() == Ratio::from_integer(BigInt::from_biguint(Sign::Minus, BigUint::new(vec![2]))));
assert!(match Evaluator::new(b" 2*2", &mut Cache::new(), &mut Vec::new()).get_mults().unwrap_err() {
E::MissingTerm(i) => i == 0,
_ => false,
});
assert!(match Evaluator::new(b" 2/2", &mut Cache::new(), &mut Vec::new()).get_mults().unwrap_err() {
E::MissingTerm(i) => i == 0,
_ => false,
});
assert!(match Evaluator::new(b"2/0", &mut Cache::new(), &mut Vec::new()).get_mults().unwrap_err() {
E::DivByZero(i) => i == 3,
_ => false,
});
assert!(Evaluator::new(b"2*2^2", &mut Cache::new(), &mut Vec::new()).get_mults().unwrap() == Ratio::from_integer(BigInt::from_biguint(Sign::Plus, BigUint::new(vec![8]))));
assert!(Evaluator::new(b"8/2^2", &mut Cache::new(), &mut Vec::new()).get_mults().unwrap() == Ratio::from_integer(BigInt::from_biguint(Sign::Plus, BigUint::new(vec![2]))));
}
#[test]
fn add() {
assert!(Evaluator::new(b"2 + 3", &mut Cache::new(), &mut Vec::new()).get_adds().unwrap() == Ratio::from_integer(BigInt::from_biguint(Sign::Plus, BigUint::new(vec![5]))));
assert!(Evaluator::new(b"-2 + 3", &mut Cache::new(), &mut Vec::new()).get_adds().unwrap() == Ratio::from_integer(BigInt::from_biguint(Sign::Plus, BigUint::new(vec![1]))));
assert!(Evaluator::new(b"2 + -3.0", &mut Cache::new(), &mut Vec::new()).get_adds().unwrap() == Ratio::from_integer(BigInt::from_biguint(Sign::Minus, BigUint::new(vec![1]))));
assert!(Evaluator::new(b"-2.5+-3.5", &mut Cache::new(), &mut Vec::new()).get_adds().unwrap() == Ratio::from_integer(BigInt::from_biguint(Sign::Minus, BigUint::new(vec![6]))));
assert!(Evaluator::new(b"4.0 - 6", &mut Cache::new(), &mut Vec::new()).get_adds().unwrap() == Ratio::from_integer(BigInt::from_biguint(Sign::Minus, BigUint::new(vec![2]))));
assert!(Evaluator::new(b"6-3", &mut Cache::new(), &mut Vec::new()).get_adds().unwrap() == Ratio::from_integer(BigInt::from_biguint(Sign::Plus, BigUint::new(vec![3]))));
assert!(Evaluator::new(b"-6-3", &mut Cache::new(), &mut Vec::new()).get_adds().unwrap() == Ratio::from_integer(BigInt::from_biguint(Sign::Minus, BigUint::new(vec![9]))));
assert!(Evaluator::new(b"6--3", &mut Cache::new(), &mut Vec::new()).get_adds().unwrap() == Ratio::from_integer(BigInt::from_biguint(Sign::Plus, BigUint::new(vec![9]))));
assert!(Evaluator::new(b"- 6 - - 3", &mut Cache::new(), &mut Vec::new()).get_adds().unwrap() == Ratio::from_integer(BigInt::from_biguint(Sign::Minus, BigUint::new(vec![3]))));
assert!(Evaluator::new(b"2 * 8", &mut Cache::new(), &mut Vec::new()).get_adds().unwrap() == Ratio::from_integer(BigInt::from_biguint(Sign::Plus, BigUint::new(vec![16]))));
assert!(Evaluator::new(b"8 / 2", &mut Cache::new(), &mut Vec::new()).get_adds().unwrap() == Ratio::from_integer(BigInt::from_biguint(Sign::Plus, BigUint::new(vec![4]))));
assert!(match Evaluator::new(b" 2+2", &mut Cache::new(), &mut Vec::new()).get_adds().unwrap_err() {
E::MissingTerm(i) => i == 0,
_ => false,
});
assert!(match Evaluator::new(b" 2-2", &mut Cache::new(), &mut Vec::new()).get_adds().unwrap_err() {
E::MissingTerm(i) => i == 0,
_ => false,
});
assert!(Evaluator::new(b"2+2*2", &mut Cache::new(), &mut Vec::new()).get_adds().unwrap() == Ratio::from_integer(BigInt::from_biguint(Sign::Plus, BigUint::new(vec![6]))));
assert!(Evaluator::new(b"2+2/2", &mut Cache::new(), &mut Vec::new()).get_adds().unwrap() == Ratio::from_integer(BigInt::from_biguint(Sign::Plus, BigUint::new(vec![3]))));
assert!(Evaluator::new(b"2-2*2", &mut Cache::new(), &mut Vec::new()).get_adds().unwrap() == Ratio::from_integer(BigInt::from_biguint(Sign::Minus, BigUint::new(vec![2]))));
assert!(Evaluator::new(b"2-2/2", &mut Cache::new(), &mut Vec::new()).get_adds().unwrap() == Ratio::from_integer(BigInt::from_biguint(Sign::Plus, BigUint::new(vec![1]))));
}
#[test]
fn empty() {
assert!(match Evaluator::new(b" \n", &mut Cache::new(), &mut Vec::new()).evaluate().unwrap() {
O::Empty => true,
_ => false,
});
assert!(match Evaluator::new(b"\n", &mut Cache::new(), &mut Vec::new()).evaluate().unwrap() {
O::Empty => true,
_ => false,
});
assert!(match Evaluator::new(b"\r\n", &mut Cache::new(), &mut Vec::new()).evaluate().unwrap_err() {
E::MissingTerm(i) => i == 0,
_ => false,
});
assert!(match Evaluator::new(b"\t\n", &mut Cache::new(), &mut Vec::new()).evaluate().unwrap_err() {
E::MissingTerm(i) => i == 0,
_ => false,
});
assert!(match Evaluator::new(b"\n\n", &mut Cache::new(), &mut Vec::new()).evaluate().unwrap_err() {
E::MissingTerm(i) => i == 0,
_ => false,
});
assert!(match Evaluator::new(b"\n ", &mut Cache::new(), &mut Vec::new()).evaluate().unwrap_err() {
E::MissingLF => true,
_ => false,
});
}
#[test]
fn exit() {
assert!(match Evaluator::new(b" q \n", &mut Cache::new(), &mut Vec::new()).evaluate().unwrap() {
O::Exit=> true,
_ => false,
});
assert!(match Evaluator::new(b"q\n", &mut Cache::new(), &mut Vec::new()).evaluate().unwrap() {
O::Exit=> true,
_ => false,
});
assert!(match Evaluator::new(b"\rq\n", &mut Cache::new(), &mut Vec::new()).evaluate().unwrap_err() {
E::MissingTerm(i) => i == 0,
_ => false,
});
assert!(match Evaluator::new(b"\tq\n", &mut Cache::new(), &mut Vec::new()).evaluate().unwrap_err() {
E::MissingTerm(i) => i == 0,
_ => false,
});
assert!(match Evaluator::new(b"q\n\n", &mut Cache::new(), &mut Vec::new()).evaluate().unwrap_err() {
E::InvalidQuit => true,
_ => false,
});
assert!(match Evaluator::new(b"\nq\n", &mut Cache::new(), &mut Vec::new()).evaluate().unwrap_err() {
E::MissingTerm(i) => i == 0,
_ => false,
});
assert!(match Evaluator::new(b"q", &mut Cache::new(), &mut Vec::new()).evaluate().unwrap_err() {
E::MissingLF => true,
_ => false,
});
}
#[test]
fn recall_statement() {
let mut cache = Cache::new();
Evaluator::new(b"1\n", &mut cache, &mut Vec::new()).evaluate().unwrap();
assert!(match Evaluator::new(b" = @ \n", &mut cache, &mut Vec::new()).evaluate().unwrap() {
O::Prev(v)=> v.val == &Ratio::from_integer(BigInt::from_biguint(Sign::Plus, BigUint::new(vec![1]))) && v.round.is_none(),
_ => false,
});
assert!(match Evaluator::new(b" = 2@ \n", &mut cache, &mut Vec::new()).evaluate().unwrap() {
O::Prev(v)=> v.val == &Ratio::from_integer(BigInt::from_biguint(Sign::Plus, BigUint::new(vec![1]))) && v.round.unwrap() == 2,
_ => false,
});
assert!(match Evaluator::new(b"=9@1\n", &mut cache, &mut Vec::new()).evaluate().unwrap() {
O::Prev(v)=> v.val == &Ratio::from_integer(BigInt::from_biguint(Sign::Plus, BigUint::new(vec![1]))) && v.round.unwrap() == 9,
_ => false,
});
assert!(match Evaluator::new(b"=0@1\n", &mut cache, &mut Vec::new()).evaluate().unwrap() {
O::Prev(v)=> v.val == &Ratio::from_integer(BigInt::from_biguint(Sign::Plus, BigUint::new(vec![1]))) && v.round.unwrap() == 0,
_ => false,
});
assert!(match Evaluator::new(b"=@2\n", &mut Cache::new(), &mut Vec::new()).evaluate().unwrap_err() {
E::NotEnoughPrevResults(count)=> count == 0,
_ => false,
});
assert!(match Evaluator::new(b"=@ 1\n", &mut cache, &mut Vec::new()).evaluate().unwrap_err() {
E::InvalidRecall => true,
_ => false,
});
assert!(match Evaluator::new(b"=0 @1\n", &mut cache, &mut Vec::new()).evaluate().unwrap_err() {
E::InvalidRecall => true,
_ => false,
});
assert!(match Evaluator::new(b"=@", &mut cache, &mut Vec::new()).evaluate().unwrap_err() {
E::MissingLF=> true,
_ => false,
});
}
#[test]
fn eval() {
use core::str::FromStr;
let mut cache = Cache::new();
let mut exp = Vec::new();
assert!(match Evaluator::new(b"1+2\n", &mut cache, &mut exp).evaluate().unwrap() {
O::Val(i) => i == &Ratio::from_integer(BigInt::from_biguint(Sign::Plus, BigUint::new(vec![3]))),
_ => false,
});
assert!(match Evaluator::new(b"-1/2+2*@\n", &mut cache, &mut exp).evaluate().unwrap() {
O::Val(i) => i == &Ratio::new(BigInt::from_biguint(Sign::Plus, BigUint::new(vec![11])), BigInt::from_biguint(Sign::Plus, BigUint::new(vec![2]))),
_ => false,
});
assert!(match Evaluator::new(b"@^@2!\n", &mut cache, &mut exp).evaluate().unwrap() {
O::Val(i) => i == &Ratio::new(BigInt::from_biguint(Sign::Plus, BigUint::new(vec![1771561])), BigInt::from_biguint(Sign::Plus, BigUint::new(vec![64]))),
_ => false,
});
assert!(match Evaluator::new(b" 1 + (2 * |(7.98 - 12/7)|) / 4!^@3!^|1-3| \n", &mut cache, &mut exp).evaluate().unwrap() {
O::Val(i) => i == &Ratio::from_str("2841328814244153299237884950647090899374680152474331/2841328814244153299237884950647090899374680152473600").unwrap(),
_ => false,
});
assert!(match Evaluator::new(&[255, 255, 255, b'\n'], &mut cache, &mut exp).evaluate().unwrap_err() {
E::MissingTerm(i) => i == 0,
_ => false,
});
assert!(match Evaluator::new(&[b'2', 255, b'\n'], &mut cache, &mut exp).evaluate().unwrap_err() {
E::TrailingSyms(i) => i == 1,
_ => false,
});
assert!(match Evaluator::new(&[b'2', b'\n', b'\n'], &mut cache, &mut exp).evaluate().unwrap_err() {
E::TrailingSyms(i) => i == 1,
_ => false,
});
assert!(match Evaluator::new(&[b'\n'], &mut cache, &mut exp).evaluate().unwrap() {
O::Empty => true,
_ => false,
});
assert!(match Evaluator::new(&[], &mut cache, &mut exp).evaluate().unwrap_err() {
E::MissingLF => true,
_ => false,
});
}
}