puyo-3/src/ast.rs
2026-01-02 23:56:42 -05:00

114 lines
3 KiB
Rust

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<Ast>),
/// `fn ([a b] [c d]) ( ... )`
Fn {
inputs: Vec<Symbol>,
outputs: Vec<Symbol>,
body: Vec<Ast>,
},
/// `{^x; ^y := z}`
Map(Vec<Ast>),
/// `f x`
App(Box<Ast>, Box<Ast>),
/// `x + y` (only builtins, sorry)
BinOp(Box<Ast>, BinOp, Box<Ast>),
/// `3`
Num(f64),
/// `(println bla; 3) #=> 3`
Block(Vec<Ast>),
}
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(" "))
}
}
}
}