use std::fmt; use crate::symbol::Symbol; #[derive(Debug, Clone, PartialEq, Eq, PartialOrd, Ord, Hash)] pub enum Ident { /// `x` Local(Symbol), /// `^x` Return(Symbol), } impl fmt::Display for Ident { fn fmt(&self, f: &mut fmt::Formatter<'_>) -> fmt::Result { match self { Ident::Local(name) => write!(f, "{name}"), Ident::Return(name) => write!(f, "^{name}"), } } } #[derive(Debug, Clone, Copy, PartialEq, Eq, PartialOrd, Ord, Hash)] pub enum BinOp { Add, Sub, Mul, Div, Mod, Pow, Eq, Lt, Le, } impl fmt::Display for BinOp { fn fmt(&self, f: &mut fmt::Formatter<'_>) -> fmt::Result { let str = match self { BinOp::Add => "+", BinOp::Sub => "-", BinOp::Mul => "*", BinOp::Div => "/", BinOp::Mod => "%", BinOp::Pow => "**", BinOp::Eq => "=", BinOp::Lt => "<", BinOp::Le => "<=", }; write!(f, "{str}") } } // TODO: great display repr for this for testing (yes it's allowed) #[derive(Debug, Clone)] pub enum Ast { /// `x`, `^x` Var(Ident), /// `x := y; #=> y` Set(Ident, Box), /// `fn ([a b] [c d]) ( ... )` Fn { inputs: Vec, outputs: Vec, body: Vec, }, /// `{^x; ^y := z}` Map(Vec), /// `f x` App(Box, Box), /// `x + y` (only builtins, sorry) BinOp(Box, BinOp, Box), /// `3` Num(f64), /// `(println bla; 3) #=> 3` Block(Vec), } impl fmt::Display for Ast { fn fmt(&self, f: &mut fmt::Formatter<'_>) -> fmt::Result { match self { Ast::Var(ident) => write!(f, "{ident}"), Ast::Set(ident, ast) => write!(f, "(set! {ident} {ast})"), Ast::Fn { inputs, outputs, body, } => { let body: Vec<_> = body.iter().map(|stmt| format!("{stmt}")).collect(); if body.is_empty() { write!(f, "(fn ([{}] [{}]))", inputs.join(" "), outputs.join(" "),) } else { write!( f, "(fn ([{}] [{}]) {})", inputs.join(" "), outputs.join(" "), body.join(" ") ) } } Ast::Map(body) => { let body: Vec<_> = body.iter().map(|stmt| format!("{stmt}")).collect(); write!(f, "{{{}}}", body.join(" ")) } Ast::App(func, x) => write!(f, "({func} {x})"), Ast::BinOp(lhs, op, rhs) => write!(f, "({lhs} {op} {rhs})"), Ast::Num(n) => write!(f, "{n}"), Ast::Block(body) => { let body: Vec<_> = body.iter().map(|stmt| format!("{stmt}")).collect(); write!(f, "({})", body.join(" ")) } } } }