use std::collections::HashMap; use std::mem; use std::convert::TryInto; use inkwell::builder::Builder; use inkwell::context::Context; use inkwell::module::Module; use inkwell::values::{BasicValueEnum, FunctionValue, IntValue}; use crate::ast; type Scope<'ctx> = HashMap>; pub struct ModuleCodeGen<'ctx> { context: &'ctx Context, module: Module<'ctx>, builder: Builder<'ctx>, scope: Scope<'ctx>, } impl<'ctx> ModuleCodeGen<'ctx> { pub fn new(context: &'ctx Context, name: String) -> Self { return ModuleCodeGen{ context: context, module: context.create_module(&name), builder: context.create_builder(), scope: Scope::new(), } } pub fn gen_literal_int(&mut self, literal_int: ast::LiteralInt) -> IntValue<'ctx> { self.context.i64_type().const_int(unsafe { mem::transmute::(literal_int.value) }, true) } pub fn gen_op_expression(&mut self, scope: &Scope<'ctx>, lhs: Box, op: ast::Operator, rhs: Box) -> IntValue<'ctx> { let lhs_result = self.gen_expression(scope, lhs); let rhs_result = self.gen_expression(scope, rhs); self.gen_op_int(lhs_result, rhs_result, op) } pub fn gen_op_int(&mut self, lhs: IntValue<'ctx>, rhs: IntValue<'ctx>, op: ast::Operator) -> IntValue<'ctx> { match op { ast::Operator::Plus => self.builder.build_int_add(lhs, rhs, "add"), ast::Operator::Minus => self.builder.build_int_sub(lhs, rhs, "sub"), ast::Operator::Mul => self.builder.build_int_mul(lhs, rhs, "mul"), ast::Operator::Div => self.builder.build_int_signed_div(lhs, rhs, "div"), } } pub fn gen_expression(&mut self, scope: &Scope<'ctx>, expression: Box) -> IntValue<'ctx> { match *expression { ast::Expression::LiteralInt(literal_int) => self.gen_literal_int(literal_int), ast::Expression::Identifier(identifier) => { match scope[&identifier.name] { BasicValueEnum::IntValue(value) => value, _ => panic!("function returned type other than int, no types yet"), } }, ast::Expression::FunctionCall(function_call) => self.gen_function_call(scope, function_call), ast::Expression::Op(lhs, op, rhs) => self.gen_op_expression(scope, lhs, op, rhs), } } pub fn gen_function_call(&mut self, scope: &Scope<'ctx>, function_call: ast::FunctionCall) -> IntValue<'ctx> { println!("Calling function: {}", &function_call.name.name); let fn_value = self.module.get_function(&function_call.name.name).unwrap(); let mut arguments = Vec::new(); for expression in function_call.arguments.into_iter() { arguments.push(BasicValueEnum::IntValue(self.gen_expression(scope, expression))); } let result = self.builder.build_call(fn_value, &arguments, &function_call.name.name) .try_as_basic_value() .left() .unwrap(); match result { BasicValueEnum::IntValue(value) => value, _ => panic!("function returned type other than int, no types yet"), } } // Generates a FunctionValue for an `ast::Function`. This does not genereate a body, // that task is left to the `gen_function` function. The reason this is split // between two functions is that first all signatures are generated and then all bodies. This // allows bodies to reference `FunctionValue` wherever they are declared in the file. pub fn gen_signature(&mut self, function: &ast::Function) -> FunctionValue { let mut args = Vec::new(); for _ in &function.arguments { args.push(self.context.i64_type().into()); } let fn_type = self.context.i64_type().fn_type(&args, false); println!("Adding function: {}", &function.name.name); let fn_value = self.module.add_function(&function.name.name, fn_type, None); fn_value } pub fn gen_function(&mut self, function: ast::Function) { let fn_value = self.module.get_function(&function.name.name).unwrap(); let basic_block = self.context.append_basic_block(fn_value, "entry"); self.builder.position_at_end(basic_block); let mut scope = self.scope.clone(); for (i, param) in function.arguments.into_iter().enumerate() { scope.insert(param.name.name, fn_value.get_nth_param(i.try_into().unwrap()).unwrap()); } let body = function.block; let return_value = self.gen_expression(&scope, body.expression); self.builder.build_return(Some(&return_value)); } pub fn gen_module(&mut self, module: ast::Module) { // generate all signatures before the fuction bodies for function in &module.functions { self.gen_signature(&function); } for function in module.functions { self.gen_function(function); } } pub fn dump(&self) -> String { self.module.print_to_string().to_string() } }