dust-bunny/src/cg.rs

90 lines
2.4 KiB
Rust

use crate::ast::*;
use std::collections::HashMap;
use wasm_encoder::{Function, Instruction, ValType};
pub struct FunctionBuilder {
locals: Vec<ValType>,
local_names: HashMap<String, u32>,
instructions: Vec<Instruction<'static>>,
}
impl FunctionBuilder {
pub fn new() -> Self {
Self {
locals: Vec::new(),
local_names: HashMap::new(),
instructions: Vec::new(),
}
}
pub fn push_instr(&mut self, instr: Instruction<'static>) {
self.instructions.push(instr);
}
pub fn add_local(&mut self, name: &str, ty: ValType) -> u32 {
let index = self.locals.len() as u32;
self.locals.push(ty);
self.local_names.insert(name.to_string(), index);
index
}
pub fn get_local(&self, name: &str) -> u32 {
*self.local_names.get(name).unwrap()
}
pub fn finish(self) -> Function {
let mut func = Function::new_with_locals_types(self.locals.into_iter());
for instr in self.instructions.into_iter() {
func.instruction(&instr);
}
func.instruction(&Instruction::End);
func
}
}
pub fn codegen_branch(ctx: &mut FunctionBuilder, ast: &BranchBody) {
for stmt in ast.statements.iter() {
match stmt {
Statement::Let { ident, expr } => {
codegen_expr(ctx, expr);
let idx = ctx.add_local(ident.span.slice, ValType::I32);
ctx.push_instr(Instruction::LocalSet(idx));
}
}
}
if let Some(expr) = ast.tail_expr.as_ref() {
codegen_expr(ctx, expr);
}
}
pub fn codegen_expr(ctx: &mut FunctionBuilder, ast: &Expr) {
match ast {
Expr::BinaryOp(op, sides) => {
codegen_expr(ctx, &sides.0);
codegen_expr(ctx, &sides.1);
let instr = match op {
BinaryOp::Add => Instruction::I32Add,
};
ctx.push_instr(instr);
}
Expr::Literal(lit) => match lit {
Literal::DecimalInteger(span) => {
let int: i32 = span.slice.parse().unwrap();
let instr = Instruction::I32Const(int);
ctx.push_instr(instr);
}
},
Expr::Local(span) => {
let idx = ctx.get_local(span.slice);
let instr = Instruction::LocalGet(idx);
ctx.push_instr(instr);
}
}
}