solveq/src/output.rs

67 lines
1.9 KiB
Rust
Raw Normal View History

2024-08-28 03:24:51 +00:00
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<EquationLanguage>) -> 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<EquationLanguage>, 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<EquationLanguage>, 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<EquationLanguage>, 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)
}
}
}