aboutsummaryrefslogtreecommitdiffstats
path: root/src
diff options
context:
space:
mode:
Diffstat (limited to 'src')
-rw-r--r--src/eval.rs139
-rw-r--r--src/expr.rs106
-rw-r--r--src/main.rs3
-rw-r--r--src/parser.rs390
4 files changed, 427 insertions, 211 deletions
diff --git a/src/eval.rs b/src/eval.rs
index dce9d68..a72f271 100644
--- a/src/eval.rs
+++ b/src/eval.rs
@@ -1,4 +1,5 @@
use std::fmt::{Display, Formatter};
+use Num::{Float, Int};
#[derive(Clone, Copy, Debug, PartialEq)]
pub enum Num {
@@ -6,25 +7,17 @@ pub enum Num {
Float(f64),
}
-pub fn int(i: i128) -> Num {
- Num::Int(i)
-}
-
-pub fn float(f: f64) -> Num {
- Num::Float(f)
-}
-
impl Num {
fn as_float(self) -> f64 {
match self {
- Num::Int(i) => i as f64,
- Num::Float(f) => f,
+ Int(i) => i as f64,
+ Float(f) => f,
}
}
fn powi(self, p: i128) -> Num {
if p == 0 {
- return int(1);
+ return Int(1);
}
if p == 1 {
return self;
@@ -37,106 +30,106 @@ impl Num {
pub fn pow(self, other: Num) -> Num {
match other {
- Num::Int(i) => {
+ Int(i) => {
if i >= 0 {
return self.powi(i);
}
if let Ok(i_32) = i32::try_from(i) {
- return float(self.as_float().powi(i_32));
+ return Float(self.as_float().powi(i_32));
}
- float(1.).div(self).powi(-i)
+ Float(1.).div(self).powi(-i)
}
- Num::Float(f) => float(self.as_float().powf(f)),
+ Float(f) => Float(self.as_float().powf(f)),
}
}
pub fn mul(self, other: Num) -> Num {
- if let (Num::Int(i1), Num::Int(i2)) = (self, other) {
+ if let (Int(i1), Int(i2)) = (self, other) {
if let Some(p) = i1.checked_mul(i2) {
- return int(p);
+ return Int(p);
}
}
- float(self.as_float() * other.as_float())
+ Float(self.as_float() * other.as_float())
}
pub fn div(self, other: Num) -> Num {
- float(self.as_float() / other.as_float())
+ Float(self.as_float() / other.as_float())
}
pub fn int_div(self, other: Num) -> Num {
- if let (Num::Int(i1), Num::Int(i2)) = (self, other) {
+ if let (Int(i1), Int(i2)) = (self, other) {
if let Some(q) = i1.checked_div(i2) {
- return int(q);
+ return Int(q);
}
}
- int((self.as_float() / other.as_float()) as i128)
+ Int((self.as_float() / other.as_float()) as i128)
}
pub fn modulo(self, other: Num) -> Num {
- if let (Num::Int(i1), Num::Int(i2)) = (self, other) {
+ if let (Int(i1), Int(i2)) = (self, other) {
if let Some(r) = i1.checked_rem(i2) {
if i2 > 0 && r < 0 || i2 < 0 && r > 0 {
- return int(r + i2);
+ return Int(r + i2);
}
- return int(r);
+ return Int(r);
}
}
let n1 = self.as_float();
let n2 = other.as_float();
let r = n1 % n2;
if n2 > 0. && r < 0. || n2 < 0. && r > 0. {
- return float(r + n2);
+ return Float(r + n2);
}
- float(r)
+ Float(r)
}
pub fn add(self, other: Num) -> Num {
- if let (Num::Int(i1), Num::Int(i2)) = (self, other) {
+ if let (Int(i1), Int(i2)) = (self, other) {
if let Some(s) = i1.checked_add(i2) {
- return int(s);
+ return Int(s);
}
}
- float(self.as_float() + other.as_float())
+ Float(self.as_float() + other.as_float())
}
pub fn sub(self, other: Num) -> Num {
- if let (Num::Int(i1), Num::Int(i2)) = (self, other) {
+ if let (Int(i1), Int(i2)) = (self, other) {
if let Some(d) = i1.checked_sub(i2) {
- return int(d);
+ return Int(d);
}
}
- float(self.as_float() - other.as_float())
+ Float(self.as_float() - other.as_float())
}
pub fn sin(self) -> Num {
- float(self.as_float().sin())
+ Float(self.as_float().sin())
}
pub fn cos(self) -> Num {
- float(self.as_float().cos())
+ Float(self.as_float().cos())
}
pub fn tan(self) -> Num {
- float(self.as_float().tan())
+ Float(self.as_float().tan())
}
pub fn asin(self) -> Num {
- float(self.as_float().asin())
+ Float(self.as_float().asin())
}
pub fn acos(self) -> Num {
- float(self.as_float().acos())
+ Float(self.as_float().acos())
}
pub fn atan(self) -> Num {
- float(self.as_float().atan())
+ Float(self.as_float().atan())
}
pub fn sqrt(self) -> Num {
match self {
- Num::Int(i) if i >= 0 => {
+ Int(i) if i >= 0 => {
if i <= 1 {
- return int(i);
+ return Int(i);
}
let mut x0 = i / 2;
let mut x1 = (x0 + i / x0) / 2;
@@ -145,51 +138,51 @@ impl Num {
x1 = (x0 + i / x0) / 2;
}
if x0 * x0 == i {
- return int(x0);
+ return Int(x0);
}
}
_ => (),
}
- float(self.as_float().sqrt())
+ Float(self.as_float().sqrt())
}
pub fn log(self) -> Num {
- float(self.as_float().ln())
+ Float(self.as_float().ln())
}
pub fn log10(self) -> Num {
- float(self.as_float().log10())
+ Float(self.as_float().log10())
}
pub fn log2(self) -> Num {
- float(self.as_float().log2())
+ Float(self.as_float().log2())
}
pub fn floor(self) -> Num {
match self {
- Num::Int(i) => int(i),
- Num::Float(f) => int(f.floor() as i128),
+ Int(i) => Int(i),
+ Float(f) => Int(f.floor() as i128),
}
}
pub fn ceil(self) -> Num {
match self {
- Num::Int(i) => int(i),
- Num::Float(f) => int(f.ceil() as i128),
+ Int(i) => Int(i),
+ Float(f) => Int(f.ceil() as i128),
}
}
pub fn round(self) -> Num {
match self {
- Num::Int(i) => int(i),
- Num::Float(f) => int(f.round_ties_even() as i128),
+ Int(i) => Int(i),
+ Float(f) => Int(f.round_ties_even() as i128),
}
}
pub fn abs(self) -> Num {
match self {
- Num::Int(i) => int(i.abs()),
- Num::Float(f) => float(f.abs()),
+ Int(i) => Int(i.abs()),
+ Float(f) => Float(f.abs()),
}
}
}
@@ -197,8 +190,8 @@ impl Num {
impl Display for Num {
fn fmt(&self, f: &mut Formatter<'_>) -> Result<(), std::fmt::Error> {
match self {
- Num::Int(n) => write!(f, "{n}"),
- Num::Float(n) => {
+ Int(n) => write!(f, "{n}"),
+ Float(n) => {
if !(-1e30..=1e30).contains(n) {
return write!(f, "{n:.7e}");
}
@@ -218,76 +211,76 @@ mod tests {
#[test]
fn pow_positive_int() {
- assert_eq!(int(2).pow(int(16)), int(65536));
+ assert_eq!(Int(2).pow(Int(16)), Int(65536));
}
#[test]
fn pow_negative_int() {
- assert_eq!(int(2).pow(int(-3)), float(0.125));
+ assert_eq!(Int(2).pow(Int(-3)), Float(0.125));
}
#[test]
fn pow_float() {
- assert_eq!(int(4).pow(float(0.5)), float(2.));
+ assert_eq!(Int(4).pow(Float(0.5)), Float(2.));
}
#[test]
fn pow_overflow() {
- assert_eq!(int(2).pow(int(1 << 126)), float(f64::INFINITY));
+ assert_eq!(Int(2).pow(Int(1 << 126)), Float(f64::INFINITY));
}
#[test]
fn pow_underflow() {
- assert_eq!(int(2).pow(int(-(1 << 126))), float(0.));
+ assert_eq!(Int(2).pow(Int(-(1 << 126))), Float(0.));
}
#[test]
fn modulo_pos() {
- assert_eq!(int(5).modulo(int(3)), int(2));
+ assert_eq!(Int(5).modulo(Int(3)), Int(2));
}
#[test]
fn modulo_pos_neg() {
- assert_eq!(int(5).modulo(int(-3)), int(-1));
+ assert_eq!(Int(5).modulo(Int(-3)), Int(-1));
}
#[test]
fn modulo_neg_pos() {
- assert_eq!(int(-5).modulo(int(3)), int(1));
+ assert_eq!(Int(-5).modulo(Int(3)), Int(1));
}
#[test]
fn modulo_neg() {
- assert_eq!(int(-5).modulo(int(-3)), int(-2));
+ assert_eq!(Int(-5).modulo(Int(-3)), Int(-2));
}
#[test]
fn modulo_float_pos() {
- assert_eq!(float(5.).modulo(int(3)), float(2.));
+ assert_eq!(Float(5.).modulo(Int(3)), Float(2.));
}
#[test]
fn modulo_float_pos_neg() {
- assert_eq!(float(5.).modulo(int(-3)), float(-1.));
+ assert_eq!(Float(5.).modulo(Int(-3)), Float(-1.));
}
#[test]
fn modulo_float_neg_pos() {
- assert_eq!(float(-5.).modulo(int(3)), float(1.));
+ assert_eq!(Float(-5.).modulo(Int(3)), Float(1.));
}
#[test]
fn modulo_float_neg() {
- assert_eq!(float(-5.).modulo(int(-3)), float(-2.));
+ assert_eq!(Float(-5.).modulo(Int(-3)), Float(-2.));
}
#[test]
fn sqrt() {
for n in 0..65536 {
assert_eq!(
- int(n * n).sqrt(),
- int(n),
- "int({}).sqrt() is not equal to {}",
+ Int(n * n).sqrt(),
+ Int(n),
+ "Int({}).sqrt() is not equal to {}",
n * n,
n
);
@@ -296,6 +289,6 @@ mod tests {
#[test]
fn sqrt_big() {
- assert_eq!(int(1 << 126).sqrt(), int(1 << 63));
+ assert_eq!(Int(1 << 126).sqrt(), Int(1 << 63));
}
}
diff --git a/src/expr.rs b/src/expr.rs
new file mode 100644
index 0000000..1022de4
--- /dev/null
+++ b/src/expr.rs
@@ -0,0 +1,106 @@
+use crate::eval::Num;
+
+#[derive(Clone, Copy, Debug, PartialEq, Eq)]
+pub enum BinOp {
+ Pow,
+ Mul,
+ Div,
+ IntDiv,
+ Mod,
+ Add,
+ Sub,
+}
+
+#[derive(Clone, Copy, Debug, PartialEq, Eq)]
+pub enum UnOp {
+ Neg,
+ Sin,
+ Cos,
+ Tan,
+ Asin,
+ Acos,
+ Atan,
+ Sqrt,
+ Log,
+ Log10,
+ Log2,
+ Floor,
+ Ceil,
+ Round,
+ Abs,
+}
+
+#[derive(Debug, PartialEq)]
+pub enum Expr {
+ Num(Num),
+ UnOp {
+ op: UnOp,
+ x: Box<Expr>,
+ },
+ BinOp {
+ op: BinOp,
+ x: Box<Expr>,
+ y: Box<Expr>,
+ },
+}
+
+impl BinOp {
+ pub fn expr(self, x: Expr, y: Expr) -> Expr {
+ Expr::BinOp {
+ op: self,
+ x: Box::new(x),
+ y: Box::new(y),
+ }
+ }
+
+ fn eval(self, x: Num, y: Num) -> Num {
+ match self {
+ BinOp::Pow => x.pow(y),
+ BinOp::Mul => x.mul(y),
+ BinOp::Div => x.div(y),
+ BinOp::IntDiv => x.int_div(y),
+ BinOp::Mod => x.modulo(y),
+ BinOp::Add => x.add(y),
+ BinOp::Sub => x.sub(y),
+ }
+ }
+}
+
+impl UnOp {
+ pub fn expr(self, x: Expr) -> Expr {
+ Expr::UnOp {
+ op: self,
+ x: Box::new(x),
+ }
+ }
+
+ fn eval(self, x: Num) -> Num {
+ match self {
+ UnOp::Neg => Num::Int(0).sub(x),
+ UnOp::Sin => x.sin(),
+ UnOp::Cos => x.cos(),
+ UnOp::Tan => x.tan(),
+ UnOp::Asin => x.asin(),
+ UnOp::Acos => x.acos(),
+ UnOp::Atan => x.atan(),
+ UnOp::Sqrt => x.sqrt(),
+ UnOp::Log => x.log(),
+ UnOp::Log10 => x.log10(),
+ UnOp::Log2 => x.log2(),
+ UnOp::Floor => x.floor(),
+ UnOp::Ceil => x.ceil(),
+ UnOp::Round => x.round(),
+ UnOp::Abs => x.abs(),
+ }
+ }
+}
+
+impl Expr {
+ pub fn eval(&self) -> Num {
+ match self {
+ Expr::Num(n) => *n,
+ Expr::UnOp { op, x } => op.eval(x.eval()),
+ Expr::BinOp { op, x, y } => op.eval(x.eval(), y.eval()),
+ }
+ }
+}
diff --git a/src/main.rs b/src/main.rs
index 8976e17..9af3e48 100644
--- a/src/main.rs
+++ b/src/main.rs
@@ -1,4 +1,5 @@
mod eval;
+mod expr;
mod lexer;
mod parser;
@@ -39,7 +40,7 @@ fn main() -> ExitCode {
window.destroy();
}
if let Some(n) = parser::parse(&input.text()) {
- output.set_text(&format!("{n}"));
+ output.set_text(&format!("{}", n.eval()));
}
}),
);
diff --git a/src/parser.rs b/src/parser.rs
index 5e02037..6eeb9d8 100644
--- a/src/parser.rs
+++ b/src/parser.rs
@@ -1,14 +1,12 @@
-use crate::eval;
use crate::eval::Num;
+use crate::expr::{BinOp, Expr, UnOp};
use crate::lexer::Lexer;
use std::str::FromStr;
enum Op {
Paren,
- Op {
- prec: i8,
- eval: Box<dyn FnOnce(Num) -> Num>,
- },
+ Un(UnOp),
+ Bin(BinOp, Expr),
}
struct Parser<'a> {
@@ -51,213 +49,161 @@ impl<'a> Parser<'a> {
let Ok(f) = f64::from_str(t) else {
return None;
};
- return Some(eval::float(f));
+ return Some(Num::Float(f));
}
let Ok(i) = i128::from_str(t) else {
return None;
};
- Some(eval::int(i))
+ Some(Num::Int(i))
}
fn parse_const(&mut self) -> Option<Num> {
if self.symbol("e") {
- return Some(eval::float(std::f64::consts::E));
+ return Some(Num::Float(std::f64::consts::E));
}
if self.symbol("pi") {
- return Some(eval::float(std::f64::consts::PI));
+ return Some(Num::Float(std::f64::consts::PI));
}
self.parse_num()
}
fn parse_fun(&mut self) -> bool {
if self.symbol("-") {
- self.stack.push(Op::Op {
- prec: 3,
- eval: Box::new(|n| eval::int(0).sub(n)),
- });
+ self.stack.push(Op::Un(UnOp::Neg));
return true;
}
if self.symbol("sin") {
- self.stack.push(Op::Op {
- prec: 3,
- eval: Box::new(Num::sin),
- });
+ self.stack.push(Op::Un(UnOp::Sin));
return true;
}
if self.symbol("cos") {
- self.stack.push(Op::Op {
- prec: 3,
- eval: Box::new(Num::cos),
- });
+ self.stack.push(Op::Un(UnOp::Cos));
return true;
}
if self.symbol("tan") {
- self.stack.push(Op::Op {
- prec: 3,
- eval: Box::new(Num::tan),
- });
+ self.stack.push(Op::Un(UnOp::Tan));
return true;
}
if self.symbol("asin") || self.symbol("arcsin") {
- self.stack.push(Op::Op {
- prec: 3,
- eval: Box::new(Num::asin),
- });
+ self.stack.push(Op::Un(UnOp::Asin));
return true;
}
if self.symbol("acos") || self.symbol("arccos") {
- self.stack.push(Op::Op {
- prec: 3,
- eval: Box::new(Num::acos),
- });
+ self.stack.push(Op::Un(UnOp::Acos));
return true;
}
if self.symbol("atan") || self.symbol("arctan") {
- self.stack.push(Op::Op {
- prec: 3,
- eval: Box::new(Num::atan),
- });
+ self.stack.push(Op::Un(UnOp::Atan));
return true;
}
if self.symbol("sqrt") {
- self.stack.push(Op::Op {
- prec: 3,
- eval: Box::new(Num::sqrt),
- });
+ self.stack.push(Op::Un(UnOp::Sqrt));
return true;
}
if self.symbol("log") || self.symbol("ln") {
- self.stack.push(Op::Op {
- prec: 3,
- eval: Box::new(Num::log),
- });
+ self.stack.push(Op::Un(UnOp::Log));
return true;
}
if self.symbol("log10") {
- self.stack.push(Op::Op {
- prec: 3,
- eval: Box::new(Num::log10),
- });
+ self.stack.push(Op::Un(UnOp::Log10));
return true;
}
if self.symbol("log2") {
- self.stack.push(Op::Op {
- prec: 3,
- eval: Box::new(Num::log2),
- });
+ self.stack.push(Op::Un(UnOp::Log2));
return true;
}
if self.symbol("floor") {
- self.stack.push(Op::Op {
- prec: 3,
- eval: Box::new(Num::floor),
- });
+ self.stack.push(Op::Un(UnOp::Floor));
return true;
}
if self.symbol("ceil") || self.symbol("ceiling") {
- self.stack.push(Op::Op {
- prec: 3,
- eval: Box::new(Num::ceil),
- });
+ self.stack.push(Op::Un(UnOp::Ceil));
return true;
}
if self.symbol("round") {
- self.stack.push(Op::Op {
- prec: 3,
- eval: Box::new(Num::round),
- });
+ self.stack.push(Op::Un(UnOp::Round));
return true;
}
if self.symbol("abs") {
- self.stack.push(Op::Op {
- prec: 3,
- eval: Box::new(Num::abs),
- });
+ self.stack.push(Op::Un(UnOp::Abs));
return true;
}
false
}
+}
+
+fn prec(op: BinOp) -> i8 {
+ match op {
+ BinOp::Pow => 2,
+ BinOp::Mul => 1,
+ BinOp::Div => 1,
+ BinOp::IntDiv => 1,
+ BinOp::Mod => 1,
+ BinOp::Add => 0,
+ BinOp::Sub => 0,
+ }
+}
- fn eval(&mut self, n: Num, target_prec: i8) -> Num {
- let mut n = n;
- while let Some(Op::Op { prec, .. }) = self.stack.last() {
- if *prec < target_prec {
- break;
+impl<'a> Parser<'a> {
+ fn eval(&mut self, e: Expr, target_prec: i8) -> Expr {
+ let mut e = e;
+ loop {
+ match self.stack.last() {
+ None | Some(Op::Paren) => break,
+ Some(Op::Bin(op, _)) if prec(*op) < target_prec => break,
+ _ => (),
+ }
+ match self.stack.pop().unwrap() {
+ Op::Un(op) => e = op.expr(e),
+ Op::Bin(op, e1) => e = op.expr(e1, e),
+ Op::Paren => unreachable!(),
}
- let Some(Op::Op { eval, .. }) = self.stack.pop() else {
- unreachable!();
- };
- n = eval(n);
}
- n
+ e
}
- fn parse_op(&mut self, n: Num) {
+ fn parse_op(&mut self, e: Expr) {
if self.symbol("^") {
- let n1 = self.eval(n, 3);
- self.stack.push(Op::Op {
- prec: 2,
- eval: Box::new(move |n2| n1.pow(n2)),
- });
+ let e = self.eval(e, 3);
+ self.stack.push(Op::Bin(BinOp::Pow, e));
return;
}
if self.symbol("*") {
- let n1 = self.eval(n, 1);
- self.stack.push(Op::Op {
- prec: 1,
- eval: Box::new(move |n2| n1.mul(n2)),
- });
+ let e = self.eval(e, 1);
+ self.stack.push(Op::Bin(BinOp::Mul, e));
return;
}
if self.symbol("/") {
- let n1 = self.eval(n, 1);
- self.stack.push(Op::Op {
- prec: 1,
- eval: Box::new(move |n2| n1.div(n2)),
- });
+ let e = self.eval(e, 1);
+ self.stack.push(Op::Bin(BinOp::Div, e));
return;
}
if self.symbol("//") {
- let n1 = self.eval(n, 1);
- self.stack.push(Op::Op {
- prec: 1,
- eval: Box::new(move |n2| n1.int_div(n2)),
- });
+ let e = self.eval(e, 1);
+ self.stack.push(Op::Bin(BinOp::IntDiv, e));
return;
}
if self.symbol("%") {
- let n1 = self.eval(n, 1);
- self.stack.push(Op::Op {
- prec: 1,
- eval: Box::new(move |n2| n1.modulo(n2)),
- });
+ let e = self.eval(e, 1);
+ self.stack.push(Op::Bin(BinOp::Mod, e));
return;
}
if self.symbol("+") {
- let n1 = self.eval(n, 0);
- self.stack.push(Op::Op {
- prec: 0,
- eval: Box::new(move |n2| n1.add(n2)),
- });
+ let e = self.eval(e, 0);
+ self.stack.push(Op::Bin(BinOp::Add, e));
return;
}
if self.symbol("-") {
- let n1 = self.eval(n, 0);
- self.stack.push(Op::Op {
- prec: 0,
- eval: Box::new(move |n2| n1.sub(n2)),
- });
+ let e = self.eval(e, 0);
+ self.stack.push(Op::Bin(BinOp::Sub, e));
return;
}
- let n1 = self.eval(n, 1);
- self.stack.push(Op::Op {
- prec: 1,
- eval: Box::new(move |n2| n1.mul(n2)),
- });
+ let e = self.eval(e, 1);
+ self.stack.push(Op::Bin(BinOp::Mul, e));
}
- fn parse(&mut self) -> Option<Num> {
- let mut n = loop {
+ fn parse(&mut self) -> Option<Expr> {
+ let mut e = loop {
if self.symbol("(") {
self.stack.push(Op::Paren);
continue;
@@ -265,32 +211,33 @@ impl<'a> Parser<'a> {
if self.parse_fun() {
continue;
}
- let mut n = self.parse_const()?;
+ let mut e = Expr::Num(self.parse_const()?);
while self.symbol(")") {
loop {
- let op = self.stack.pop()?;
- let Op::Op { eval, .. } = op else {
- break;
- };
- n = eval(n);
+ match self.stack.pop()? {
+ Op::Un(op) => e = op.expr(e),
+ Op::Bin(op, e1) => e = op.expr(e1, e),
+ Op::Paren => break,
+ }
}
}
if self.peek().is_none() {
- break n;
+ break e;
}
- self.parse_op(n);
+ self.parse_op(e);
};
- while let Some(op) = self.stack.pop() {
- let Op::Op { eval, .. } = op else {
- return None;
- };
- n = eval(n);
+ loop {
+ match self.stack.pop() {
+ Some(Op::Paren) => return None,
+ Some(Op::Un(op)) => e = op.expr(e),
+ Some(Op::Bin(op, e1)) => e = op.expr(e1, e),
+ None => return Some(e),
+ }
}
- Some(n)
}
}
-pub fn parse(expr: &str) -> Option<Num> {
+pub fn parse(expr: &str) -> Option<Expr> {
let mut p = Parser {
r: Lexer { buf: expr },
first_token: None,
@@ -298,3 +245,172 @@ pub fn parse(expr: &str) -> Option<Num> {
};
p.parse()
}
+
+#[cfg(test)]
+mod tests {
+ use super::*;
+
+ fn int(i: i128) -> Expr {
+ Expr::Num(Num::Int(i))
+ }
+
+ fn float(f: f64) -> Expr {
+ Expr::Num(Num::Float(f))
+ }
+
+ #[test]
+ fn parse_int() {
+ assert_eq!(parse("500"), Some(int(500)));
+ }
+
+ #[test]
+ fn parse_float() {
+ assert_eq!(parse("1e2"), Some(float(100.)));
+ }
+
+ #[test]
+ fn parse_fun() {
+ assert_eq!(
+ parse("sin pi"),
+ Some(UnOp::Sin.expr(float(std::f64::consts::PI)))
+ );
+ }
+
+ #[test]
+ fn parse_nested_fun() {
+ assert_eq!(
+ parse("log log 100"),
+ Some(UnOp::Log.expr(UnOp::Log.expr(int(100))))
+ );
+ }
+
+ #[test]
+ fn parse_power() {
+ assert_eq!(
+ parse("2^1^2"),
+ Some(BinOp::Pow.expr(int(2), BinOp::Pow.expr(int(1), int(2))))
+ );
+ }
+
+ #[test]
+ fn parse_fun_power() {
+ assert_eq!(
+ parse("log 2^2"),
+ Some(BinOp::Pow.expr(UnOp::Log.expr(int(2)), int(2)))
+ );
+ }
+
+ #[test]
+ fn parse_power_fun() {
+ assert_eq!(
+ parse("2^log 2"),
+ Some(BinOp::Pow.expr(int(2), UnOp::Log.expr(int(2))))
+ );
+ }
+
+ #[test]
+ fn parse_pow_mul() {
+ assert_eq!(
+ parse("2^2*2"),
+ Some(BinOp::Mul.expr(BinOp::Pow.expr(int(2), int(2)), int(2)))
+ );
+ }
+
+ #[test]
+ fn parse_mul_pow() {
+ assert_eq!(
+ parse("2*2^2"),
+ Some(BinOp::Mul.expr(int(2), BinOp::Pow.expr(int(2), int(2))))
+ );
+ }
+
+ #[test]
+ fn parse_mul_div() {
+ assert_eq!(
+ parse("2*2/2"),
+ Some(BinOp::Div.expr(BinOp::Mul.expr(int(2), int(2)), int(2)))
+ );
+ }
+
+ #[test]
+ fn parse_add_mul() {
+ assert_eq!(
+ parse("2+2*2"),
+ Some(BinOp::Add.expr(int(2), BinOp::Mul.expr(int(2), int(2))))
+ );
+ }
+
+ #[test]
+ fn parse_mul_add() {
+ assert_eq!(
+ parse("2*2+2"),
+ Some(BinOp::Add.expr(BinOp::Mul.expr(int(2), int(2)), int(2)))
+ );
+ }
+
+ #[test]
+ fn parse_fun_add() {
+ assert_eq!(
+ parse("log 2+2"),
+ Some(BinOp::Add.expr(UnOp::Log.expr(int(2)), int(2))),
+ );
+ }
+
+ #[test]
+ fn parse_parens() {
+ assert_eq!(
+ parse("(1+2)*3"),
+ Some(BinOp::Mul.expr(BinOp::Add.expr(int(1), int(2)), int(3)))
+ );
+ }
+
+ #[test]
+ fn parse_implicit_multiplication() {
+ assert_eq!(
+ parse("2pi"),
+ Some(BinOp::Mul.expr(int(2), float(std::f64::consts::PI))),
+ );
+ }
+
+ #[test]
+ fn parse_implicit_multiplication_neg() {
+ assert_eq!(
+ parse("-2 2 -2"),
+ Some(BinOp::Sub.expr(BinOp::Mul.expr(UnOp::Neg.expr(int(2)), int(2)), int(2)))
+ );
+ }
+
+ #[test]
+ fn parse_fun_implicit_multiplication() {
+ assert_eq!(
+ parse("sin 2pi"),
+ Some(BinOp::Mul.expr(UnOp::Sin.expr(int(2)), float(std::f64::consts::PI))),
+ );
+ }
+
+ #[test]
+ fn parse_unary_negate() {
+ assert_eq!(
+ parse("1---2"),
+ Some(BinOp::Sub.expr(int(1), UnOp::Neg.expr(UnOp::Neg.expr(int(2)))))
+ );
+ }
+
+ #[test]
+ fn parse_negate_fun() {
+ assert_eq!(
+ parse("log-log 2"),
+ Some(UnOp::Log.expr(UnOp::Neg.expr(UnOp::Log.expr(int(2)))))
+ );
+ }
+
+ #[test]
+ fn parse_unmatched_parens() {
+ assert_eq!(parse("0))))"), None,);
+ }
+
+ #[test]
+ fn parse_unmatched_op() {
+ assert_eq!(parse("2^2+"), None,);
+ }
+}