nac3/nac3core/src/codegen/generator.rs

162 lines
5.0 KiB
Rust

use crate::{
codegen::{expr::*, stmt::*, CodeGenContext},
toplevel::{DefinitionId, TopLevelDef},
typecheck::typedef::{FunSignature, Type},
};
use inkwell::values::{BasicValueEnum, PointerValue};
use nac3parser::ast::{Expr, Stmt, StrRef};
pub trait CodeGenerator {
/// Return the module name for the code generator.
fn get_name(&self) -> &str;
/// Generate function call and returns the function return value.
/// - obj: Optional object for method call.
/// - fun: Function signature and definition ID.
/// - params: Function parameters. Note that this does not include the object even if the
/// function is a class method.
fn gen_call<'ctx, 'a>(
&mut self,
ctx: &mut CodeGenContext<'ctx, 'a>,
obj: Option<(Type, BasicValueEnum<'ctx>)>,
fun: (&FunSignature, DefinitionId),
params: Vec<(Option<StrRef>, BasicValueEnum<'ctx>)>,
) -> Option<BasicValueEnum<'ctx>> {
gen_call(self, ctx, obj, fun, params)
}
/// Generate object constructor and returns the constructed object.
/// - signature: Function signature of the contructor.
/// - def: Class definition for the constructor class.
/// - params: Function parameters.
fn gen_constructor<'ctx, 'a>(
&mut self,
ctx: &mut CodeGenContext<'ctx, 'a>,
signature: &FunSignature,
def: &TopLevelDef,
params: Vec<(Option<StrRef>, BasicValueEnum<'ctx>)>,
) -> BasicValueEnum<'ctx> {
gen_constructor(self, ctx, signature, def, params)
}
/// Generate a function instance.
/// - obj: Optional object for method call.
/// - fun: Function signature, definition ID and the substitution key.
/// - params: Function parameters. Note that this does not include the object even if the
/// function is a class method.
/// Note that this function should check if the function is generated in another thread (due to
/// possible race condition), see the default implementation for an example.
fn gen_func_instance<'ctx, 'a>(
&mut self,
ctx: &mut CodeGenContext<'ctx, 'a>,
obj: Option<(Type, BasicValueEnum<'ctx>)>,
fun: (&FunSignature, &mut TopLevelDef, String),
) -> String {
gen_func_instance(ctx, obj, fun)
}
/// Generate the code for an expression.
fn gen_expr<'ctx, 'a>(
&mut self,
ctx: &mut CodeGenContext<'ctx, 'a>,
expr: &Expr<Option<Type>>,
) -> Option<BasicValueEnum<'ctx>> {
gen_expr(self, ctx, expr)
}
/// Allocate memory for a variable and return a pointer pointing to it.
/// The default implementation places the allocations at the start of the function.
fn gen_var_alloc<'ctx, 'a>(
&mut self,
ctx: &mut CodeGenContext<'ctx, 'a>,
ty: Type,
) -> PointerValue<'ctx> {
gen_var(ctx, ty)
}
/// Return a pointer pointing to the target of the expression.
fn gen_store_target<'ctx, 'a>(
&mut self,
ctx: &mut CodeGenContext<'ctx, 'a>,
pattern: &Expr<Option<Type>>,
) -> PointerValue<'ctx> {
gen_store_target(self, ctx, pattern)
}
/// Generate code for an assignment expression.
fn gen_assign<'ctx, 'a>(
&mut self,
ctx: &mut CodeGenContext<'ctx, 'a>,
target: &Expr<Option<Type>>,
value: BasicValueEnum<'ctx>,
) {
gen_assign(self, ctx, target, value)
}
/// Generate code for a while expression.
/// Return true if the while loop must early return
fn gen_while<'ctx, 'a>(
&mut self,
ctx: &mut CodeGenContext<'ctx, 'a>,
stmt: &Stmt<Option<Type>>,
) -> bool {
gen_while(self, ctx, stmt);
false
}
/// Generate code for a while expression.
/// Return true if the while loop must early return
fn gen_for<'ctx, 'a>(
&mut self,
ctx: &mut CodeGenContext<'ctx, 'a>,
stmt: &Stmt<Option<Type>>,
) -> bool {
gen_for(self, ctx, stmt);
false
}
/// Generate code for an if expression.
/// Return true if the statement must early return
fn gen_if<'ctx, 'a>(
&mut self,
ctx: &mut CodeGenContext<'ctx, 'a>,
stmt: &Stmt<Option<Type>>,
) -> bool {
gen_if(self, ctx, stmt)
}
fn gen_with<'ctx, 'a>(
&mut self,
ctx: &mut CodeGenContext<'ctx, 'a>,
stmt: &Stmt<Option<Type>>,
) -> bool {
gen_with(self, ctx, stmt)
}
/// Generate code for a statement
/// Return true if the statement must early return
fn gen_stmt<'ctx, 'a>(
&mut self,
ctx: &mut CodeGenContext<'ctx, 'a>,
stmt: &Stmt<Option<Type>>,
) -> bool {
gen_stmt(self, ctx, stmt)
}
}
pub struct DefaultCodeGenerator {
name: String,
}
impl DefaultCodeGenerator {
pub fn new(name: String) -> DefaultCodeGenerator {
DefaultCodeGenerator { name }
}
}
impl CodeGenerator for DefaultCodeGenerator {
fn get_name(&self) -> &str {
&self.name
}
}