2024-05-09 16:41:59 -05:00
|
|
|
use {crate::parser, std::fmt::Write};
|
2024-05-09 11:16:01 -05:00
|
|
|
|
2024-05-09 16:41:59 -05:00
|
|
|
const STACK_PTR: &str = "r254";
|
|
|
|
const ZERO: &str = "r0";
|
|
|
|
const RET_ADDR: &str = "r31";
|
2024-05-09 11:16:01 -05:00
|
|
|
|
2024-05-09 16:41:59 -05:00
|
|
|
pub struct Codegen<'a> {
|
|
|
|
path: &'a std::path::Path,
|
|
|
|
code: String,
|
|
|
|
data: String,
|
2024-05-09 11:16:01 -05:00
|
|
|
}
|
|
|
|
|
2024-05-09 16:41:59 -05:00
|
|
|
impl<'a> Codegen<'a> {
|
|
|
|
pub fn new(path: &'a std::path::Path) -> Self {
|
2024-05-09 11:16:01 -05:00
|
|
|
Self {
|
2024-05-09 16:41:59 -05:00
|
|
|
path,
|
|
|
|
code: String::new(),
|
|
|
|
data: String::new(),
|
2024-05-09 11:16:01 -05:00
|
|
|
}
|
|
|
|
}
|
|
|
|
|
2024-05-09 16:41:59 -05:00
|
|
|
pub fn file(&mut self, exprs: &[parser::Expr]) -> std::fmt::Result {
|
|
|
|
for expr in exprs {
|
|
|
|
self.expr(expr)?;
|
2024-05-09 11:16:01 -05:00
|
|
|
}
|
2024-05-09 16:41:59 -05:00
|
|
|
Ok(())
|
2024-05-09 11:16:01 -05:00
|
|
|
}
|
|
|
|
|
2024-05-09 16:41:59 -05:00
|
|
|
fn expr(&mut self, expr: &parser::Expr) -> std::fmt::Result {
|
|
|
|
use parser::Expr as E;
|
|
|
|
match expr {
|
|
|
|
E::Decl {
|
|
|
|
name,
|
|
|
|
val:
|
|
|
|
E::Closure {
|
|
|
|
ret: E::Ident { name: "void" },
|
|
|
|
body,
|
|
|
|
},
|
|
|
|
} => {
|
|
|
|
writeln!(self.code, "{name}:")?;
|
|
|
|
self.expr(body)
|
2024-05-09 11:16:01 -05:00
|
|
|
}
|
2024-05-09 16:41:59 -05:00
|
|
|
E::Return { val: None } => self.ret(),
|
|
|
|
E::Block { stmts } => {
|
|
|
|
for stmt in stmts {
|
|
|
|
self.expr(stmt)?;
|
2024-05-09 11:16:01 -05:00
|
|
|
}
|
2024-05-09 16:41:59 -05:00
|
|
|
Ok(())
|
2024-05-09 11:16:01 -05:00
|
|
|
}
|
2024-05-09 16:41:59 -05:00
|
|
|
ast => unimplemented!("{:?}", ast),
|
2024-05-09 11:16:01 -05:00
|
|
|
}
|
|
|
|
}
|
|
|
|
|
2024-05-09 16:41:59 -05:00
|
|
|
fn stack_push(&mut self, value: impl std::fmt::Display, size: usize) -> std::fmt::Result {
|
|
|
|
writeln!(self.code, " st {value}, {STACK_PTR}, {ZERO}, {size}")?;
|
|
|
|
writeln!(
|
|
|
|
self.code,
|
|
|
|
" addi{} {STACK_PTR}, {STACK_PTR}, {size}",
|
|
|
|
size * 8
|
|
|
|
)
|
2024-05-09 11:16:01 -05:00
|
|
|
}
|
|
|
|
|
2024-05-09 16:41:59 -05:00
|
|
|
fn stack_pop(&mut self, value: impl std::fmt::Display, size: usize) -> std::fmt::Result {
|
|
|
|
writeln!(
|
|
|
|
self.code,
|
|
|
|
" subi{} {STACK_PTR}, {STACK_PTR}, {size}",
|
|
|
|
size * 8
|
|
|
|
)?;
|
|
|
|
writeln!(self.code, " ld {value}, {STACK_PTR}, {ZERO}, {size}")
|
2024-05-09 11:16:01 -05:00
|
|
|
}
|
|
|
|
|
2024-05-09 16:41:59 -05:00
|
|
|
fn call(&mut self, func: impl std::fmt::Display) -> std::fmt::Result {
|
|
|
|
self.stack_push(&func, 8)?;
|
|
|
|
self.global_jump(func)
|
2024-05-09 11:16:01 -05:00
|
|
|
}
|
|
|
|
|
2024-05-09 16:41:59 -05:00
|
|
|
fn ret(&mut self) -> std::fmt::Result {
|
|
|
|
self.stack_pop(RET_ADDR, 8)?;
|
|
|
|
self.global_jump(RET_ADDR)
|
2024-05-09 11:16:01 -05:00
|
|
|
}
|
|
|
|
|
2024-05-09 16:41:59 -05:00
|
|
|
fn global_jump(&mut self, label: impl std::fmt::Display) -> std::fmt::Result {
|
|
|
|
writeln!(self.code, " jala {ZERO}, {label}, 0")
|
2024-05-09 11:16:01 -05:00
|
|
|
}
|
|
|
|
|
2024-05-09 16:41:59 -05:00
|
|
|
pub fn dump(&mut self, mut out: impl std::fmt::Write) -> std::fmt::Result {
|
|
|
|
writeln!(out, "start:")?;
|
|
|
|
writeln!(out, " jala {ZERO}, main, 0")?;
|
|
|
|
writeln!(out, " tx")?;
|
|
|
|
writeln!(out, "{}", self.code)?;
|
|
|
|
writeln!(out, "{}", self.data)
|
2024-05-09 11:16:01 -05:00
|
|
|
}
|
|
|
|
}
|
|
|
|
|
2024-05-09 16:41:59 -05:00
|
|
|
#[cfg(test)]
|
|
|
|
mod tests {
|
|
|
|
fn generate(input: &'static str, output: &mut String) {
|
|
|
|
let mut parser = super::parser::Parser::new(input, std::path::Path::new("test"));
|
|
|
|
let exprs = parser.file();
|
|
|
|
let mut codegen = super::Codegen::new(std::path::Path::new("test"));
|
|
|
|
codegen.file(&exprs).unwrap();
|
|
|
|
codegen.dump(output).unwrap();
|
2024-05-09 11:16:01 -05:00
|
|
|
}
|
|
|
|
|
2024-05-09 16:41:59 -05:00
|
|
|
crate::run_tests! { generate:
|
|
|
|
example => include_str!("../examples/main_fn.hb");
|
2024-05-09 11:16:01 -05:00
|
|
|
}
|
|
|
|
}
|