use crate::ast::{Function, Module, Statement};
use crate::generator::{Generator, GeneratorResult};
struct Assembly {
asm: Vec<String>,
}
impl From<Assembly> for String {
fn from(asm: Assembly) -> Self {
asm.build()
}
}
impl Assembly {
fn new() -> Assembly {
Assembly { asm: vec![] }
}
fn add<S: Into<String>>(&mut self, string: S) {
self.asm.push(string.into())
}
fn build(&self) -> String {
self.asm.join("\n")
}
}
pub struct X86Generator;
impl Generator for X86Generator {
fn generate(prog: Module) -> GeneratorResult<String> {
Ok(Self::new().gen_program(prog).build())
}
}
impl X86Generator {
fn new() -> Self {
X86Generator {}
}
fn gen_program(&mut self, prog: Module) -> Assembly {
let mut asm = Assembly::new();
let Module {
func,
globals,
structs: _,
path: _,
imports: _,
} = prog;
asm.add(".intel_syntax noprefix");
asm.add(".text");
for f in func {
asm.add(self.gen_function(f));
}
asm.add(".data");
for g in globals {
asm.add(format!("_{0}: .word 0", g));
}
asm
}
fn gen_function(&mut self, func: Function) -> Assembly {
let mut asm = Assembly::new();
let has_return: bool = match &func.body {
Statement::Block {
statements,
scope: _,
} => statements
.iter()
.any(|s| matches!(*s, Statement::Return(_))),
_ => panic!("Function body should be of type Block"),
};
asm.add(format!(".globl _{}", func.name));
asm.add(format!("_{}:", func.name));
asm.add("push rbp");
asm.add("mov rbp, rsp");
if !has_return {
asm.add("mov rsp, rbp");
asm.add("pop rbp");
asm.add("ret\n");
}
asm
}
}