ableos/hblang/src/codegen.rs

109 lines
3 KiB
Rust
Raw Normal View History

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
}
}