bcsat 0.1.0

A parser, printer and related utilities for BCSAT (http://users.ics.aalto.fi/tjunttil/bcsat/)
pub mod options;
pub mod operators;
use std::fmt;
use ast::*;

pub use self::options::*;
use self::operators::*;

pub struct PrintBCSAT<'a, T>(&'a FormulaOptions, T);
type PF<'a, 'b> = PrintBCSAT<'a, &'b Formula>;

impl FormulaOptions {
    pub fn display<T>(&self, t: T) -> PrintBCSAT<T> {
        PrintBCSAT(self, t)
    }
    fn print_formula(&self, f: &mut fmt::Formatter, formula: &Formula) -> fmt::Result {
        use self::Formula::*;
        match *formula {
            Named(ref x) => write!(f, "{}", x),
            Constant(ref c) => write!(f, "{}", c),
            Comment(ref form, ref com) => self.print_comments.fmt(f, self.display(form), com),
            Imply(ref l, ref r) => {
                self.imply
                    .binary(f, Op::Imply, self.display(l), self.display(r))
            }
            ITE(ref i, ref t, ref e) => write!(f, "ITE{}", self.display(vec![i, t, e])),
            Not(ref n) => self.not.unary(f, Op::Not, self.display(n)),
            Equiv(ref v) => self.equiv.nary(f, Op::Equiv, self.display(v)),
            Odd(ref v) => self.odd.nary(f, Op::Odd, self.display(v)),
            Even(ref v) => self.even.nary(f, Op::Even, self.display(v)),
            And(ref v) => self.and.nary(f, Op::And, self.display(v)),
            Or(ref v) => self.or.nary(f, Op::Or, self.display(v)),
            Between(l, u, ref v) => write!(f, "[{}, {}]{}", l, u, self.display(v)),
        }
    }
}

impl InfixOptions {
    fn unary(&self, f: &mut fmt::Formatter, op: Op, n: PF) -> fmt::Result {
        use self::InfixOptions::*;
        match *self {
            InfixBinary(Parens::Yes) => write!(f, "{}({})", op.short(), n,),
            InfixBinary(_) => panic!("Not yet implemented: removing parentheses"),
            Long => write!(f, "{}({})", op, n),
        }
    }
    fn binary(&self, f: &mut fmt::Formatter, op: Op, l: PF, r: PF) -> fmt::Result {
        use self::InfixOptions::*;
        match *self {
            InfixBinary(Parens::Yes) => write!(f, "({}) {} ({})", l, op.short(), r),
            InfixBinary(_) => panic!("Not yet implemented: removing parentheses"),
            Long => write!(f, "{}({}, {})", op, l, r),
        }
    }
    fn nary(&self, f: &mut fmt::Formatter, op: Op, l: PrintBCSAT<&Vec<F>>) -> fmt::Result {
        match l.1.len() {
            2 => self.binary(f, op, l.0.display(&l.1[0]), l.0.display(&l.1[1])),
            _ => write!(f, "{}{}", op, l),
        }
    }
}
impl InfixChainOptions {
    fn nary(&self, f: &mut fmt::Formatter, op: Op, l: PrintBCSAT<&Vec<F>>) -> fmt::Result {
        use self::InfixChainOptions::*;
        match *self {
            InfixChain(Parens::Yes) => {
                let mut it = l.1.iter();
                if let Some(elem) = it.next() {
                    try!(write!(f, "({})", l.0.display(elem)));
                    for elem in it {
                        try!(write!(f, " {} ({})", op.short(), l.0.display(elem)));
                    }
                    Ok(())
                } else {
                    InfixOptions::Long.nary(f, op, l)
                }
            }
            InfixChain(_) => panic!("Not yet implemented: removing parentheses"),
            NoChain(ref x) => x.nary(f, op, l),
        }
    }
}
impl PrintComments {
    fn fmt<T>(&self, f: &mut fmt::Formatter, t: T, c: &str) -> fmt::Result
        where T: fmt::Display
    {
        use self::PrintComments::*;
        match *self {
            Yes => write!(f, "{} //{}\n", t, c),
            No => write!(f, "{}", t),
        }
    }
}

impl<'a, 'b> fmt::Display for PrintBCSAT<'a, &'b Formula> {
    fn fmt(&self, f: &mut fmt::Formatter) -> fmt::Result {
        self.0.print_formula(f, self.1)
    }
}
impl<'a, 'b, T> fmt::Display for PrintBCSAT<'a, &'b T>
    where for<'c> PrintBCSAT<'c, T>: fmt::Display,
          T: Clone
{
    fn fmt(&self, f: &mut fmt::Formatter) -> fmt::Result {
        self.0.display(self.1.clone()).fmt(f)
    }
}
impl<'a, T> fmt::Display for PrintBCSAT<'a, Box<T>>
    where for<'b> PrintBCSAT<'b, &'b T>: fmt::Display
{
    fn fmt<'x>(&'x self, f: &mut fmt::Formatter) -> fmt::Result {
        let d: PrintBCSAT<'a, &'x T> = self.0.display(&self.1);
        d.fmt(f)
    }
}
impl<'a, T> fmt::Display for PrintBCSAT<'a, Vec<T>>
    where for<'b, 'c> PrintBCSAT<'b, &'c T>: fmt::Display
{
    fn fmt(&self, f: &mut fmt::Formatter) -> fmt::Result {
        let mut it = self.1.iter();
        if let Some(elem) = it.next() {
            try!(write!(f, "({}", self.0.display(elem)));
            for elem in it {
                try!(write!(f, ", {}", self.0.display(elem)));
            }
            write!(f, ")")
        } else {
            write!(f, "()")
        }
    }
}
impl<'a, 'b> fmt::Display for PrintBCSAT<'a, &'b Statement> {
    fn fmt(&self, f: &mut fmt::Formatter) -> fmt::Result {
        use self::Statement::*;
        match *self.1 {
            Name(ref n) => write!(f, "{};", n),
            Defined(ref n, ref form) => write!(f, "{} := {};", n, self.0.display(form)),
            Assigned(ref form) => write!(f, "ASSIGN {};", self.0.display(form)),
            Comment(ref c) => write!(f, "//{}\n", c),
        }
    }
}
impl<'a, 'b> fmt::Display for PrintBCSAT<'a, &'b BCSAT> {
    fn fmt(&self, f: &mut fmt::Formatter) -> fmt::Result {
        try!(write!(f, "BC1.1\n"));
        for statement in &self.1.statements {
            try!(write!(f, "{}\n", self.0.display(statement)));
        }
        Ok(())
    }
}