brainstem 0.1.0

A Brainfuck compiler and interpreter library, with a BrainStem frontend language.
Documentation
use std::fmt::{Debug, Error, Formatter};

pub enum Statement<'input> {
    VarDeclaration(&'input str, Expression<'input>),
    ArrayDeclaration(&'input str, Vec<Expression<'input>>),
    If(
        Expression<'input>,
        Box<Statement<'input>>,
        Option<Box<Statement<'input>>>,
    ),
    PutChar(Expression<'input>),
    While(Expression<'input>, Box<Statement<'input>>),
    Block(Vec<Statement<'input>>),
    Expression(Expression<'input>),
    PushStackFrame(Vec<(&'input str, Expression<'input>)>),
    PopStackFrame,
    MoveToStackFrameBelow(&'input str),
}

impl Debug for Statement<'_> {
    fn fmt(&self, fmt: &mut Formatter<'_>) -> Result<(), Error> {
        use self::Statement::*;
        match *self {
            VarDeclaration(n, ref i) => {
                write!(fmt, "var {} = {:?};", n, i)
            }
            ArrayDeclaration(n, ref i) => {
                let initializers = i
                    .iter()
                    .map(|e| format!("{:?}", e))
                    .collect::<Vec<_>>()
                    .join("; ");
                write!(fmt, "ArrayDeclaration({}; ({}));", n, initializers)
            }
            If(ref c, ref t, ref e) => match e {
                Some(e) => write!(fmt, "if {:?} then {:?} else {:?};", c, t, e),
                None => write!(fmt, "if {:?} then {:?};", c, t),
            },
            PutChar(ref e) => write!(fmt, "putc({:?});", e),
            While(ref c, ref s) => write!(fmt, "while {:?} {:?}", c, s),
            Block(ref v) => {
                writeln!(fmt, "{{")?;
                for s in v {
                    writeln!(fmt, "{:?}", s)?;
                }
                write!(fmt, "}}")
            }
            Expression(ref e) => write!(fmt, "{:?};", e),
            PushStackFrame(ref m) => {
                let initializers = m
                    .iter()
                    .map(|(k, v)| format!("{}={:?}", k, v))
                    .collect::<Vec<_>>()
                    .join("; ");
                write!(fmt, "PushStackFrame({});", initializers)
            }
            PopStackFrame => write!(fmt, "PopStackFrame;"),
            MoveToStackFrameBelow(ref n) => write!(fmt, "MoveToStackFrameBelow({});", n),
        }
    }
}

#[derive(Clone)]
pub enum Expression<'input> {
    Literal(i32),
    Not(Box<Expression<'input>>),
    Binary(Box<Expression<'input>>, Opcode, Box<Expression<'input>>),
    Variable(&'input str),
    ArrayLookup(&'input str, Box<Expression<'input>>),
    Assignment(&'input str, Box<Expression<'input>>),
    ArrayAssignment(
        &'input str,
        Box<Expression<'input>>,
        Box<Expression<'input>>,
    ),
    MemoryRead(Box<Expression<'input>>),
    MemoryWrite(Box<Expression<'input>>, Box<Expression<'input>>),
}

#[derive(Copy, Clone)]
pub enum Opcode {
    Mul,
    Div,
    Mod,
    Add,
    Sub,
    And,
    Or,
    Lt,
    Le,
    Eq,
    Ne,
}

impl From<&str> for Opcode {
    fn from(op: &str) -> Self {
        match op {
            "*" => Opcode::Mul,
            "/" => Opcode::Div,
            "%" => Opcode::Mod,
            "+" => Opcode::Add,
            "-" => Opcode::Sub,
            "&&" => Opcode::And,
            "||" => Opcode::Or,
            "<" => Opcode::Lt,
            "<=" => Opcode::Le,
            "==" => Opcode::Eq,
            "!=" => Opcode::Ne,
            _ => panic!("Unsupported operator: {}", op),
        }
    }
}

impl Debug for Expression<'_> {
    fn fmt(&self, fmt: &mut Formatter<'_>) -> Result<(), Error> {
        use self::Expression::*;
        match *self {
            Literal(n) => write!(fmt, "{}", n),
            Not(ref e) => write!(fmt, "!{:?}", e),
            Binary(ref l, op, ref r) => write!(fmt, "({:?} {:?} {:?})", l, op, r),
            Variable(s) => write!(fmt, "{}", s),
            ArrayLookup(s, ref i) => write!(fmt, "ArrayLookup({}; {:?})", s, i),
            Assignment(s, ref e) => write!(fmt, "{} = {:?}", s, e),
            ArrayAssignment(s, ref i, ref e) => {
                write!(fmt, "ArrayAssignment({}; {:?}; {:?})", s, i, e)
            }
            MemoryRead(ref e) => write!(fmt, "MemoryRead(addr={:?})", e),
            MemoryWrite(ref a, ref e) => write!(fmt, "MemoryWrite(addr={:?}; value={:?})", a, e),
        }
    }
}

impl Debug for Opcode {
    fn fmt(&self, fmt: &mut Formatter<'_>) -> Result<(), Error> {
        use self::Opcode::*;
        match *self {
            Mul => write!(fmt, "*"),
            Div => write!(fmt, "/"),
            Mod => write!(fmt, "%"),
            Add => write!(fmt, ""),
            Sub => write!(fmt, ""),
            And => write!(fmt, "&&"),
            Or => write!(fmt, "||"),
            Lt => write!(fmt, "lt"),
            Le => write!(fmt, "le"),
            Eq => write!(fmt, "=="),
            Ne => write!(fmt, "!="),
        }
    }
}