use cas_error::Error;
use cas_parser::parser::{
ast::{binary::Binary, expr::Expr, literal::Literal},
token::op::{BinOp, BinOpKind},
Parser,
};
use std::collections::HashSet;
pub fn predict_independent(expr: Expr) -> (Variable, Expr) {
let expr = if let Expr::Binary(Binary {
lhs,
op: BinOp {
kind: BinOpKind::Eq,
implicit,
span: op_span,
},
rhs,
span,
}) = expr {
if let Expr::Literal(Literal::Symbol(sym)) = lhs.as_ref() {
return match sym.name.as_str() {
"x" => (Variable::Y, *rhs),
"y" => (Variable::X, *rhs),
"theta" => (Variable::Theta, *rhs),
_ => todo!("unknown special variable"),
};
} else if let Expr::Literal(Literal::Symbol(sym)) = rhs.as_ref() {
return match sym.name.as_str() {
"x" => (Variable::Y, *lhs),
"y" => (Variable::X, *lhs),
"theta" => (Variable::Theta, *lhs),
_ => todo!("unknown special variable"),
};
}
Expr::Binary(Binary {
lhs,
op: BinOp {
kind: BinOpKind::Eq,
implicit,
span: op_span,
},
rhs,
span,
})
} else {
expr
};
let vars = expr.post_order_iter()
.filter_map(|node| match node {
Expr::Literal(Literal::Symbol(sym)) => match sym.name.as_str() {
"x" => Some(Variable::X),
"y" => Some(Variable::Y),
"theta" => Some(Variable::Theta),
_ => None,
},
_ => None,
})
.collect::<HashSet<_>>();
if vars.len() > 1 {
todo!("multiple special variables")
} else if let Some(var) = vars.into_iter().next() {
(var, expr)
} else {
todo!("no special variables")
}
}
#[derive(Clone, Copy, Debug, Eq, PartialEq, Hash)]
pub enum Variable {
X,
Y,
Theta,
}
impl Variable {
pub fn as_str(self) -> &'static str {
match self {
Self::X => "x",
Self::Y => "y",
Self::Theta => "theta",
}
}
}
#[derive(Clone, Debug)]
pub struct AnalyzedExpr {
pub expr: Expr,
pub independent: Variable,
pub color: (f64, f64, f64),
}
impl AnalyzedExpr {
pub fn new(expr: Expr) -> Self {
let (independent, expr) = predict_independent(expr);
Self {
expr,
independent,
color: (1.0, 0.0, 0.0),
}
}
pub fn parse(expr: &str) -> Result<Self, Vec<Error>> {
Parser::new(expr)
.try_parse_full()
.map(Self::new)
}
pub fn with_color(mut self, color: (f64, f64, f64)) -> Self {
self.color = color;
self
}
}