use super::{
atom::{Atom, AtomView},
coefficient::CoefficientView,
};
#[derive(Clone, Debug)]
pub struct PrintOptions {
pub compact: bool,
pub hide_all_namespaces: bool,
pub hide_namespace: Option<&'static str>,
pub stable_debug: bool,
}
impl Default for PrintOptions {
fn default() -> Self {
Self {
compact: false,
hide_all_namespaces: true,
hide_namespace: None,
stable_debug: false,
}
}
}
pub fn print(atom: &Atom) -> String {
print_with_options(atom, &PrintOptions::default())
}
pub fn print_with_options(atom: &Atom, options: &PrintOptions) -> String {
let mut out = String::new();
print_view_to_string(&atom.as_view(), options, &mut out);
out
}
pub fn print_debug(atom: &Atom) -> String {
print_with_options(
atom,
&PrintOptions {
hide_all_namespaces: false,
hide_namespace: None,
stable_debug: true,
..PrintOptions::default()
},
)
}
pub fn print_view_to_string(view: &AtomView<'_>, options: &PrintOptions, out: &mut String) {
print_view_prec(view, options, out, 0);
}
fn print_view_prec(view: &AtomView<'_>, options: &PrintOptions, out: &mut String, parent_prec: u8) {
match view {
AtomView::Num(n) => match n.get_coeff_view() {
CoefficientView::Natural(num, den) => {
if den == 1 {
out.push_str(&num.to_string());
} else {
out.push_str(&format!("{}/{}", num, den));
}
}
CoefficientView::Large(_) => out.push_str("<large>"),
},
AtomView::Var(v) => out.push_str(&format_symbol(v.get_symbol(), options)),
AtomView::Fun(f) => {
out.push_str(&format_symbol(f.get_symbol(), options));
out.push('(');
for (i, arg) in f.iter().enumerate() {
if i > 0 {
out.push(',');
}
print_view_prec(&arg, options, out, 0);
}
out.push(')');
}
AtomView::Pow(p) => {
let need = parent_prec > 3;
if need {
out.push('(');
}
let (base, exp) = p.get_base_exp();
print_view_prec(&base, options, out, 3);
out.push('^');
print_view_prec(&exp, options, out, 3);
if need {
out.push(')');
}
}
AtomView::Mul(m) => {
let need = parent_prec > 2;
if need {
out.push('(');
}
for (i, factor) in m.iter().enumerate() {
if i > 0 {
out.push('*');
}
print_view_prec(&factor, options, out, 2);
}
if need {
out.push(')');
}
}
AtomView::Add(a) => {
let need = parent_prec > 1;
if need {
out.push('(');
}
for (i, term) in a.iter().enumerate() {
if i > 0 {
out.push('+');
}
print_view_prec(&term, options, out, 1);
}
if need {
out.push(')');
}
}
}
let _ = options.compact;
}
fn format_symbol(symbol: super::state::Symbol, options: &PrintOptions) -> String {
if options.stable_debug {
return symbol.get_name().to_string();
}
if options.hide_all_namespaces {
return symbol.get_stripped_name().to_string();
}
if let Some(namespace) = options.hide_namespace {
if symbol.get_namespace() == namespace {
return symbol.get_stripped_name().to_string();
}
}
symbol.get_name().to_string()
}