use egg::{RecExpr, Id}; use crate::language::EquationLanguage; // there is already a Display implementation generated by define_langauge! // but we want an alternative string conversion pub fn print_term(expr: &RecExpr) -> String { let root_id = Id::from(expr.as_ref().len()-1); print_term_inner(expr, root_id).0 } // the second result is the precedence of the top level op: 1 = '+-', 2 = '*/', 3 = '^', 4 = primitive fn print_term_inner(expr: &RecExpr, id: Id) -> (String, usize) { match &expr[id] { EquationLanguage::Num(c) => { (format!("{}", c), if c.denom == 1 { 4 } else { 2 }) }, EquationLanguage::Neg([a]) => { (print_unary(expr, *a, "-", 1), 1) }, EquationLanguage::Add([a,b]) => { (print_binary(expr, *a, *b, "+", 1), 1) }, EquationLanguage::Sub([a,b]) => { (print_binary(expr, *a, *b, "-", 1), 1) }, EquationLanguage::Mul([a,b]) => { (print_binary(expr, *a, *b, "*", 2), 2) }, EquationLanguage::Div([a,b]) => { (print_binary(expr, *a, *b, "/", 2), 2) }, EquationLanguage::Power([a,b]) => { (print_binary(expr, *a, *b, "^", 3), 3) }, _ => unimplemented!() } } fn print_unary(expr: &RecExpr, a: Id, op: &str, precedence: usize) -> String { let (astr, aprec) = print_term_inner(expr, a); if aprec > precedence { format!("{}{}", op, astr) } else { format!("{}({})", op, astr) } } fn print_binary(expr: &RecExpr, a: Id, b: Id, op: &str, precedence: usize) -> String { let (astr, aprec) = print_term_inner(expr, a); let (bstr, bprec) = print_term_inner(expr, b); if aprec > precedence { if bprec > precedence { format!("{} {} {}", astr, op, bstr) } else { format!("{} {} ({})", astr, op, bstr) } } else { if bprec > precedence { format!("({}) {} {}", astr, op, bstr) } else { format!("({}) {} ({})", astr, op, bstr) } } }