evaltrees 0.1.0

A simple term-rewriting interpreter that displays intermediate expressions.
Documentation
#[cfg(test)]
mod tests;

use std::fmt::{Display, Formatter, Result as FmtResult};

use ast::Op;
use cst::{Decl, Expr};

impl Display for Decl {
    fn fmt(&self, fmt: &mut Formatter) -> FmtResult {
        write!(fmt, "{}", self.name)?;
        for arg in &self.args {
            write!(fmt, " {}", arg)?;
        }
        write!(fmt, " = {}", self.body)
    }
}

impl Display for Expr {
    fn fmt(&self, fmt: &mut Formatter) -> FmtResult {
        fmt_expr(self, 0, fmt)
    }
}

fn fmt_expr(expr: &Expr, prec: usize, fmt: &mut Formatter) -> FmtResult {
    match *expr {
        Expr::If(ref c, ref t, ref e) => {
            if prec > 0 {
                write!(fmt, "(")?;
            }
            write!(fmt, "if ")?;
            fmt_expr(c, 0, fmt)?;
            write!(fmt, " then ")?;
            fmt_expr(t, 0, fmt)?;
            write!(fmt, " else ")?;
            fmt_expr(e, 0, fmt)?;
            if prec > 0 {
                write!(fmt, ")")?;
            }
            Ok(())
        }
        Expr::List(ref es) => {
            write!(fmt, "[")?;
            let mut first = true;
            for e in es {
                if first {
                    first = false;
                } else {
                    write!(fmt, "; ")?;
                }
                fmt_expr(e, 0, fmt)?;
            }
            write!(fmt, "]")
        }
        Expr::Literal(lit) => write!(fmt, "{}", lit),
        Expr::Op(Op::Add, ref l, ref r) => {
            if prec > 1 {
                write!(fmt, "(")?;
            }
            fmt_expr(l, 1, fmt)?;
            write!(fmt, " + ")?;
            fmt_expr(r, 2, fmt)?;
            if prec > 1 {
                write!(fmt, ")")?;
            }
            Ok(())
        }
        Expr::Op(Op::App, ref l, ref r) => {
            if prec > 3 {
                write!(fmt, "(")?;
            }
            fmt_expr(l, 3, fmt)?;
            write!(fmt, " ")?;
            fmt_expr(r, 4, fmt)?;
            if prec > 3 {
                write!(fmt, ")")?;
            }
            Ok(())
        }
        Expr::Op(Op::Cons, ref l, ref r) => {
            if prec > 0 {
                write!(fmt, "(")?;
            }
            fmt_expr(l, 1, fmt)?;
            write!(fmt, " :: ")?;
            fmt_expr(r, 0, fmt)?;
            if prec > 0 {
                write!(fmt, ")")?;
            }
            Ok(())
        }
        Expr::Op(Op::Div, ref l, ref r) => {
            if prec > 2 {
                write!(fmt, "(")?;
            }
            fmt_expr(l, 2, fmt)?;
            write!(fmt, " / ")?;
            fmt_expr(r, 3, fmt)?;
            if prec > 2 {
                write!(fmt, ")")?;
            }
            Ok(())
        }
        Expr::Op(Op::Mod, ref l, ref r) => {
            if prec > 2 {
                write!(fmt, "(")?;
            }
            fmt_expr(l, 2, fmt)?;
            write!(fmt, " mod ")?;
            fmt_expr(r, 3, fmt)?;
            if prec > 2 {
                write!(fmt, ")")?;
            }
            Ok(())
        }
        Expr::Op(Op::Mul, ref l, ref r) => {
            if prec > 2 {
                write!(fmt, "(")?;
            }
            fmt_expr(l, 2, fmt)?;
            write!(fmt, " * ")?;
            fmt_expr(r, 3, fmt)?;
            if prec > 2 {
                write!(fmt, ")")?;
            }
            Ok(())
        }
        Expr::Op(Op::Sub, ref l, ref r) => {
            if prec > 1 {
                write!(fmt, "(")?;
            }
            fmt_expr(l, 1, fmt)?;
            write!(fmt, " - ")?;
            fmt_expr(r, 2, fmt)?;
            if prec > 1 {
                write!(fmt, ")")?;
            }
            Ok(())
        }
        Expr::Variable(sym) => write!(fmt, "{}", sym),
    }
}