use inpt::split::{Line, Parenthetical};
use inpt::Inpt;

#[derive(Inpt, Debug)]
#[inpt(bounds = "")]
enum Term {
    Par(Parenthetical<Box<Equation>>),
    Lit(f64),
}

#[derive(Inpt, Debug)]
#[inpt(bounds = "")]
enum Equation {
    #[inpt(regex = r"-")]
    Neg(#[inpt(after)] Term),
    #[inpt(regex = r"\+")]
    Add(#[inpt(before)] Term, #[inpt(after)] Box<Equation>),
    #[inpt(regex = r"-")]
    Sub(#[inpt(before)] Term, #[inpt(after)] Box<Equation>),
    #[inpt(regex = r"\*")]
    Mul(#[inpt(before)] Term, #[inpt(after)] Box<Equation>),
    #[inpt(regex = r"/")]
    Div(#[inpt(before)] Term, #[inpt(after)] Box<Equation>),
    #[inpt(regex = r"\^")]
    Pow(#[inpt(before)] Term, #[inpt(after)] Term),
    Ter(Term),
}

impl Equation {
    fn value(self) -> f64 {
        fn v(term: Term) -> f64 {
            match term {
                Term::Par(x) => x.inner.value(),
                Term::Lit(x) => x,
            }
        }

        use Equation::*;
        match self {
            Neg(x) => -v(x),
            Add(a, b) => v(a) + b.value(),
            Sub(a, b) => v(a) - b.value(),
            Mul(a, b) => v(a) * b.value(),
            Div(a, b) => v(a) / b.value(),
            Pow(a, b) => v(a).powf(v(b)),
            Ter(x) => v(x),
        }
    }
}

#[inpt::main]
pub fn main(eqs: Vec<Line<Equation>>) {
    for Line { inner: eq } in eqs {
        println!("=  {}", eq.value())
    }
}
