use std::fmt;
use std::rc::Rc;
use crate::op::*;
use crate::opers::*;
use crate::parse::*;
use crate::errors::*;
use crate::context::*;
use crate::num::*;
use crate::answer::*;
use crate::expr::*;
#[derive(Debug, Clone)]
pub enum Term<N: Num> {
Num(Answer<N>),
Operation(Rc<dyn Operate<N>>),
Function(String, Vec<Term<N>>),
Var(String),
}
#[derive(Debug, Clone)]
enum Expr {
Num(f64),
Op(Op),
Sub(Vec<Expr>),
Var(String),
Func(String, Vec<Vec<Expr>>),
}
impl<N: Num + 'static> Term<N> {
pub fn parse(raw: &str) -> Result<Self, ParseError> {
let ctx = Context::new();
Self::parse_ctx(raw, &ctx)
}
pub fn parse_ctx(raw: &str, ctx: &Context<N>) -> Result<Self, ParseError> {
let raw = raw.trim();
let paren_tokens = get_tokens(raw)?;
let exprs = paren_to_exprs(paren_tokens, ctx)?;
let exprs = if ctx.cfg.implicit_multiplication {
insert_operators(exprs)
} else {
exprs
};
let postfix = tokenexprs_to_postfix(exprs);
let term = postfix_to_term(postfix, ctx)?;
Ok(term)
}
pub fn eval(&self) -> Calculation<N> {
let ctx = Context::new();
self.eval_ctx(&ctx)
}
pub fn eval_ctx(&self, ctx: &Context<N>) -> Calculation<N> {
match *self {
Term::Num(ref num) => Ok(num.clone()), Term::Operation(ref oper) => oper.eval(ctx), Term::Function(ref name, ref args) => {
if let Some(func) = ctx.funcs.get(name) {
func.eval(args, ctx)
} else {
Err(MathError::UndefinedFunction { name: name.clone() })
}
}
Term::Var(ref name) => {
if let Some(var) = ctx.vars.get(name) {
var.eval_ctx(ctx)
} else {
Err(MathError::UndefinedVariable { name: name.clone() })
}
}
}
}
pub fn to_string(&self) -> String {
match *self {
Term::Num(ref num) => format!("{}", num),
Term::Operation(ref op) => format!("{}", op.to_string()),
Term::Function(ref name, ref args) => format!("{}({})", name, {
let mut buf = String::new();
for (i, arg) in args.iter().enumerate() {
buf.push_str(&arg.to_string());
if i + 1 < args.len() {
buf.push_str(", ");
}
}
buf
}),
Term::Var(ref name) => format!("{}", name),
}
}
}
impl<N: Num + 'static> fmt::Display for Term<N> {
fn fmt(&self, f: &mut fmt::Formatter) -> fmt::Result {
write!(f, "{}", self.to_string())
}
}
impl<N: Num> From<Expression<N>> for Term<N> {
fn from(t: Expression<N>) -> Term<N> {
t.term
}
}
impl<N: Num> From<N> for Term<N> {
fn from(t: N) -> Term<N> {
Term::Num(Answer::Single(t))
}
}
impl<N: Num> From<Answer<N>> for Term<N> {
fn from(t: Answer<N>) -> Term<N> {
Term::Num(t)
}
}
fn paren_to_exprs<N: Num + 'static>(raw: Vec<ParenToken>, ctx: &Context<N>) -> Result<Vec<Expr>, ParseError> {
let mut mtokens = Vec::new();
let mut pending_name = None;
for rt in raw {
match rt {
ParenToken::Num(num) => {
if let Some(pending_name) = pending_name.take() {
mtokens.push(Expr::Var(pending_name));
}
mtokens.push(Expr::Num(num));
}
ParenToken::Op(op) => {
if let Some(pending_name) = pending_name.take() {
mtokens.push(Expr::Var(pending_name));
}
mtokens.push(Expr::Op(op));
}
ParenToken::Sub(sub) => {
if let Some(name) = pending_name.take() {
if ctx.cfg.implicit_multiplication {
if ctx.funcs.contains_key(&name) {
mtokens.push(Expr::Func(name, tokens_to_args(sub, ctx)?)); } else {
mtokens.push(Expr::Var(name)); mtokens.push(Expr::Sub(paren_to_exprs(sub, ctx)?)); }
} else {
mtokens.push(Expr::Func(name, tokens_to_args(sub, ctx)?)); }
} else {
mtokens.push(Expr::Sub(paren_to_exprs(sub, ctx)?));
}
}
ParenToken::Name(name) => {
if let Some(pending_name) = pending_name.take() {
mtokens.push(Expr::Var(pending_name));
}
pending_name = Some(name);
}
ParenToken::Comma => {
return Err(ParseError::UnexpectedToken {
token: String::from(","),
})
}
}
}
if let Some(pending_name) = pending_name.take() {
mtokens.push(Expr::Var(pending_name));
}
Ok(mtokens)
}
fn tokens_to_args<N: Num + 'static>(raw: Vec<ParenToken>, ctx: &Context<N>) -> Result<Vec<Vec<Expr>>, ParseError> {
let args: Vec<&[ParenToken]> = raw.split(|ptoken| match *ptoken {
ParenToken::Comma => true,
_ => false,
}).collect();
let mut new = Vec::new();
for arg in args {
if arg.is_empty() {
continue; }
let arg = arg.to_vec();
new.push(paren_to_exprs(arg, ctx)?)
}
Ok(new)
}
#[cfg_attr(feature = "cargo-clippy", allow(redundant_closure))]
fn insert_operators(mut raw: Vec<Expr>) -> Vec<Expr> {
let mut i = 0;
if raw.is_empty() {
return Vec::new();
}
while i < raw.len() - 1 {
if raw[i].is_operand() && raw[i + 1].is_operand() {
raw.insert(i + 1, Expr::Op(Op::In(In::Mul)));
} else {
match raw[i] {
Expr::Op(Op::Post(_)) => {
if raw[i + 1].is_operand() {
raw.insert(i + 1, Expr::Op(Op::In(In::Mul)));
}
}
_ => {}
}
i += 1;
}
}
let mut new = Vec::new();
for texpr in raw {
match texpr {
Expr::Sub(texprs) => new.push(Expr::Sub(insert_operators(texprs))),
Expr::Func(name, args) => new.push(Expr::Func(
name,
args.into_iter()
.map(|texprs| insert_operators(texprs))
.collect(),
)),
t => new.push(t),
}
}
new
}
fn tokenexprs_to_postfix(raw: Vec<Expr>) -> Vec<Expr> {
fn recurse(raw: &[Expr]) -> Vec<Expr> {
let mut stack = Vec::new();
let mut ops: Vec<Op> = Vec::new();
for texpr in raw {
match *texpr {
Expr::Num(num) => stack.push(Expr::Num(num)), Expr::Op(ref op) => {
while let Some(top_op) = ops.pop() {
if op.should_shunt(&top_op.clone()) {
stack.push(Expr::Op(top_op));
} else {
ops.push(top_op); break;
}
}
ops.push(op.clone()); }
Expr::Var(ref name) => stack.push(Expr::Var(name.clone())), Expr::Func(ref name, ref texprs_args) => stack.push(Expr::Func(name.clone(), {
let mut new_texprs_args = Vec::new();
for texprs in texprs_args {
new_texprs_args.push(recurse(texprs)); }
new_texprs_args
})),
Expr::Sub(ref texprs) => stack.push(Expr::Sub(recurse(texprs))), }
}
while let Some(op) = ops.pop() {
stack.push(Expr::Op(op));
}
stack
}
recurse(&raw)
}
fn postfix_to_term<N: Num + 'static>(raw: Vec<Expr>, ctx: &Context<N>) -> Result<Term<N>, ParseError> {
let mut stack = Vec::new();
for texpr in raw {
match texpr {
Expr::Num(num) => stack.push(Term::Num(N::from_f64(num, ctx).unwrap())), Expr::Op(op) => {
macro_rules! pop {
() => {
match stack.pop() {
Some(v) => v,
None => return Err(ParseError::Expected {
expected: Expected::Expression
}),
}
}
}
let oper: Rc<dyn Operate<N>> = match op {
Op::In(op) => match op {
In::Add => Rc::new(Add {
b: pop!(),
a: pop!(),
}),
In::Sub => Rc::new(Sub {
b: pop!(),
a: pop!(),
}),
In::Mul => Rc::new(Mul {
b: pop!(),
a: pop!(),
}),
In::Div => Rc::new(Div {
b: pop!(),
a: pop!(),
}),
In::Pow => Rc::new(Pow {
b: pop!(),
a: pop!(),
}),
In::PlusMinus => Rc::new(PlusMinus {
b: pop!(),
a: pop!(),
}),
},
Op::Pre(op) => match op {
Pre::Neg => Rc::new(Neg { a: pop!() }),
Pre::Pos => Rc::new(Pos { a: pop!() }),
Pre::PosNeg => Rc::new(PosNeg { a: pop!() }),
},
Op::Post(op) => match op {
Post::Fact => Rc::new(Fact { a: pop!() }),
Post::Percent => Rc::new(Percent { a: pop!() }),
},
};
stack.push(Term::Operation(oper));
}
Expr::Sub(texprs) => {
stack.push(postfix_to_term(texprs, ctx)?);
}
Expr::Var(name) => stack.push(Term::Var(name)), Expr::Func(name, args) => {
stack.push(Term::Function(name, {
let mut new = Vec::new();
for texprs in args {
new.push(postfix_to_term(texprs, ctx)?);
}
new
}));
}
}
}
if stack.len() > 1 {
return Err(ParseError::Expected {
expected: Expected::Operator,
});
}
if let Some(term) = stack.pop() {
Ok(term)
} else {
Err(ParseError::Expected {
expected: Expected::Expression,
})
}
}
impl Expr {
fn is_operand(&self) -> bool {
use self::Expr::*;
match *self {
Num(_) | Var(_) | Func(_, _) | Sub(_) => true,
Op(_) => false,
}
}
}