use colored::Colorize;
use std::fmt;
#[derive(Debug, PartialEq, Clone)]
pub enum Expr {
Nil,
Number(i64),
Boolean(bool),
Char(u8),
Str(String),
Identifier(String),
Symbol(String),
List(Vec<Expr>),
Cond { pred: Box<Expr>, then: Box<Expr>, alt: Option<Box<Expr>> },
Let { bindings: Vec<(String, Expr)>, body: Vec<Expr> },
Lambda(Code),
}
#[derive(Debug, PartialEq, Clone)]
pub struct Code {
pub name: Option<String>,
pub formals: Vec<String>,
pub free: Vec<String>,
pub body: Vec<Expr>,
}
impl fmt::Display for Expr {
fn fmt(&self, f: &mut fmt::Formatter) -> fmt::Result {
match self {
Expr::Nil => write!(f, "()"),
Expr::Number(n) => write!(f, "{}", n),
Expr::Boolean(t) => write!(f, "{}", if *t { "#t" } else { "#f" }),
Expr::Char(c) => write!(f, "{}", c),
Expr::Str(s) => write!(f, "\"{}\"", s),
Expr::Identifier(i) => write!(f, "{}", i),
Expr::Symbol(i) => write!(f, "'{}", i),
Expr::List(l) => {
write!(f, "(")?;
for i in l {
write!(f, "{} ", i)?;
}
write!(f, ")")
}
Expr::Cond { pred, then, alt } => match alt {
None => write!(f, "(if {} {})", pred, then),
Some(t) => write!(f, "(if {} {} {})", pred, then, t),
},
Expr::Let { bindings, body } => {
write!(f, "(let (")?;
bindings.iter().for_each(|(a, b)| write!(f, "({} {})", a, b).unwrap());
write!(f, ") ")?;
body.iter().for_each(|b| write!(f, "{}", b).unwrap());
write!(f, ")")
}
Expr::Lambda(Code { formals, body, .. }) => {
write!(f, "(λ (")?;
formals.iter().for_each(|arg| write!(f, "{}", arg).unwrap());
write!(f, ") ")?;
body.iter().for_each(|b| write!(f, "{}", b).unwrap());
write!(f, ")")
}
}
}
}
impl From<i64> for Expr {
fn from(i: i64) -> Self {
Expr::Number(i)
}
}
impl From<bool> for Expr {
fn from(b: bool) -> Self {
Expr::Boolean(b)
}
}
impl From<char> for Expr {
fn from(c: char) -> Self {
Expr::Char(c as u8)
}
}
impl From<&str> for Expr {
fn from(i: &str) -> Self {
Expr::Identifier(String::from(i))
}
}
pub struct Config {
pub program: String,
pub output: String,
}
impl Config {
pub fn asm(&self) -> String {
let stdout = String::from("/dev/stdout");
if self.output == stdout {
stdout
} else {
format!("{}.s", self.output)
}
}
}
#[derive(Debug)]
pub enum Error<'a> {
Parser(nom::Err<(&'a str, nom::error::ErrorKind)>),
Internal { message: String, e: Option<std::io::Error> },
Runtime(String),
Compilation(String),
}
impl<'a> From<std::io::Error> for Error<'a> {
fn from(error: std::io::Error) -> Self {
Error::Internal { message: String::from(""), e: Some(error) }
}
}
impl<'a> fmt::Display for Error<'a> {
fn fmt(&self, f: &mut fmt::Formatter) -> fmt::Result {
match self {
Self::Parser(e) => {
writeln!(f, "{}\n", "Failed to parse program".red().bold())?;
writeln!(f, "{:?}", e)
}
Self::Internal { message, e } => {
writeln!(f, "{}\n", "Something went wrong!".red().bold())?;
writeln!(f, "{}", message)?;
writeln!(f, "{:?}", e)
}
Self::Runtime(e) => {
writeln!(f, "{}\n", "Runtime error!".red().bold())?;
writeln!(f, "{:?}", e)
}
Self::Compilation(e) => {
writeln!(f, "{}\n", "Failed to compile program".red().bold())?;
writeln!(f, "{:?}", e)
}
}
}
}