#![allow(unused_imports)] #![allow(dead_code)] use crust::{ ast::{Block, Cmd, Expr, Func, Op, Span, SpanExpr}, parse::{parse_block, parse_expr}, }; use inkwell::{ builder::Builder, context::Context, execution_engine::{ExecutionEngine, JitFunction}, module::Module, passes::PassManager, types::BasicTypeEnum, values::{BasicValueEnum, FloatValue, FunctionValue, InstructionValue, IntValue, PointerValue}, FloatPredicate, OptimizationLevel, }; use std::collections::HashMap; use std::error::Error; type ExprFunc = unsafe extern "C" fn() -> i32; fn main() -> Result<(), Box<dyn Error>> { let context = Context::create(); let module = context.create_module("expr"); let builder = context.create_builder(); let fpm = PassManager::create(&module); fpm.initialize(); let execution_engine = module.create_jit_execution_engine(OptimizationLevel::None)?; match parse_block(Span::new( " { let abba : mut i32 = 7; abba = 5; return 2 + abba } ", )) { Ok((_, prog)) => { println!("ast : {:?}", &prog); let u32_type = context.i32_type(); let fn_type = u32_type.fn_type(&[], false); let function = module.add_function("expr", fn_type, None); let basic_block = context.append_basic_block(&function, "entry"); builder.position_at_end(&basic_block); let mut compiler = Compiler { context: &context, builder: &builder, module: &module, fn_value_opt: Some(function), variables: HashMap::new(), //&fpm, }; compiler.compile_block(prog); let fun_expr: JitFunction<ExprFunc> = unsafe { execution_engine.get_function("expr").ok().unwrap() }; unsafe { println!("\nexecution result : {}", fun_expr.call()); } } _ => panic!(), } module.print_to_stderr(); Ok(()) } /// Compiler holds the LLVM state for the compilation pub struct Compiler<'a> { pub context: &'a Context, pub builder: &'a Builder, // pub fpm: &'a PassManager<FunctionValue>, pub module: &'a Module, // pub function: &'a Func<'a>, variables: HashMap<String, PointerValue>, fn_value_opt: Option<FunctionValue>, } /// Compilation assumes the program to be semantically correct (well formed) impl<'a> Compiler<'a> { /// Gets a defined function given its name. #[inline] fn get_function(&self, name: &str) -> Option<FunctionValue> { self.module.get_function(name) } /// Returns the `PointerValue` representing the variable `id`. #[inline] fn get_variable(&self, id: &str) -> &PointerValue { match self.variables.get(id) { Some(var) => var, None => panic!( "Could not find a matching variable, {} in {:?}", id, self.variables ), } } /// Returns the `FunctionValue` representing the function being compiled. #[inline] fn fn_value(&self) -> FunctionValue { self.fn_value_opt.unwrap() } /// For now, returns an IntValue /// Boolean is i1, single bit integers in LLVM /// However we might to choose to store them as i8 or i32 fn compile_expr(&self, expr: &SpanExpr) -> IntValue { match expr.1.clone() { Expr::Id(id) => { let var = self.get_variable(&id); self.builder.build_load(*var, &id).into_int_value() } Expr::Num(i) => self.context.i32_type().const_int(i as u64, false), Expr::BinOp(op, l, r) => { let lv = self.compile_expr(&l); let rv = self.compile_expr(&r); match op { Op::Add => self.builder.build_int_add(lv, rv, "sum"), _ => unimplemented!(), } } // Todo: Binop, Unop, Booleans, Function calls _ => unimplemented!(), } } /// Creates a new stack allocation instruction in the entry block of the function. fn create_entry_block_alloca(&mut self, name: &str) -> PointerValue { let builder = self.context.create_builder(); let entry = self.fn_value().get_first_basic_block().unwrap(); match entry.get_first_instruction() { Some(first_instr) => builder.position_before(&first_instr), None => builder.position_at_end(&entry), } let alloca = builder.build_alloca(self.context.i32_type(), name); self.variables.insert(name.to_string(), alloca); alloca } /// Compiles a command into (InstructionValue, b:bool) /// `b` indicates that its a return value of the basic block fn compile_cmd(&mut self, cmd: &Cmd) -> (InstructionValue, bool) { match cmd { Cmd::Assign((_, lexp), rexp) => match lexp { Expr::Id(id) => { let var = self.get_variable(id); let rexp = self.compile_expr(rexp); (self.builder.build_store(*var, rexp), false) } _ => panic!("we are bad"), }, // -- TODO: This is code from my `old` interpreter // Cmd::If(exp, then_block, opt_else) => { // if get_bool(eval_expr(exp, mem, venv, fenv)) { // eval_body(then_block.to_vec(), mem, venv, fenv) // } else { // if let Some(else_block) = opt_else { // eval_body(else_block.to_vec(), mem, venv, fenv) // } else { // None // } // } // } // -- TODO: While Cmd::Let(_, id, _, exp) => { let exp = self.compile_expr(exp); // allocate a local variable (on the stack) let alloca = self.create_entry_block_alloca(id.fragment); // store the (initial) value let store = self.builder.build_store(alloca, exp); (store, false) } Cmd::Return(exp) => { let expr = self.compile_expr(exp); (self.builder.build_return(Some(&expr)), true) } _ => unimplemented!(), } } pub fn compile_block(&mut self, cmds: Vec<Cmd>) -> InstructionValue { for c in &cmds { let (cmd, ret) = self.compile_cmd(c); // early return (e.g., inside a loop/conditional) if ret { return cmd; } } panic!(); } // TODO, function declarations } // SHAMELESSLY STOLEN FROM inkwell!!!! // // ====================================================================================== // // COMPILER ============================================================================= // // ====================================================================================== // /// Defines the `Expr` compiler. // pub struct Compiler<'a> { // pub context: &'a Context, // pub builder: &'a Builder, // pub fpm: &'a PassManager<FunctionValue>, // pub module: &'a Module, // pub function: &'a Func<'a>, // variables: HashMap<String, PointerValue>, // fn_value_opt: Option<FunctionValue>, // } // impl<'a> Compiler<'a> { // /// Gets a defined function given its name. // #[inline] // fn get_function(&self, name: &str) -> Option<FunctionValue> { // self.module.get_function(name) // } // /// Returns the `FunctionValue` representing the function being compiled. // #[inline] // fn fn_value(&self) -> FunctionValue { // self.fn_value_opt.unwrap() // } // /// Creates a new stack allocation instruction in the entry block of the function. // fn create_entry_block_alloca(&self, name: &str) -> PointerValue { // let builder = self.context.create_builder(); // let entry = self.fn_value().get_first_basic_block().unwrap(); // match entry.get_first_instruction() { // Some(first_instr) => builder.position_before(&first_instr), // None => builder.position_at_end(&entry), // } // builder.build_alloca(self.context.f64_type(), name) // } // /// Compiles the specified `Expr` into an LLVM `FloatValue`. // fn compile_expr( // &mut self, // expr: &Expr, // ) -> Result<FloatValue, &'static str> { // match *expr { // // Expr::Num(nb) => Ok(self.context.i32_type().const_int(nb, true)), // // Expr::Variable(ref name) => { // // match self.variables.get(name.as_str()) { // // Some(var) => Ok(self // // .builder // // .build_load(*var, name.as_str()) // // .into_float_value()), // // None => Err("Could not find a matching variable."), // // } // // } // // Expr::VarIn { // // ref variables, // // ref body, // // } => { // // let mut old_bindings = Vec::new(); // // for &(ref var_name, ref initializer) in variables { // // let var_name = var_name.as_str(); // // let initial_val = match *initializer { // // Some(ref init) => self.compile_expr(init)?, // // None => self.context.f64_type().const_float(0.), // // }; // // let alloca = self.create_entry_block_alloca(var_name); // // self.builder.build_store(alloca, initial_val); // // if let Some(old_binding) = self.variables.remove(var_name) { // // old_bindings.push(old_binding); // // } // // self.variables.insert(var_name.to_string(), alloca); // // } // // let body = self.compile_expr(body)?; // // for binding in old_bindings { // // self.variables.insert( // // binding.get_name().to_str().unwrap().to_string(), // // binding, // // ); // // } // // Ok(body) // // } // // Expr::Binary { // // op, // // ref left, // // ref right, // // } => { // // if op == '=' { // // // handle assignement // // let var_name = match *left.borrow() { // // Expr::Variable(ref var_name) => var_name, // // _ => { // // return Err("Expected variable as left-hand operator of assignement."); // // } // // }; // // let var_val = self.compile_expr(right)?; // // let var = self // // .variables // // .get(var_name.as_str()) // // .ok_or("Undefined variable.")?; // // self.builder.build_store(*var, var_val); // // Ok(var_val) // // } else { // // let lhs = self.compile_expr(left)?; // // let rhs = self.compile_expr(right)?; // // match op { // // '+' => { // // Ok(self.builder.build_float_add(lhs, rhs, "tmpadd")) // // } // // '-' => { // // Ok(self.builder.build_float_sub(lhs, rhs, "tmpsub")) // // } // // '*' => { // // Ok(self.builder.build_float_mul(lhs, rhs, "tmpmul")) // // } // // '/' => { // // Ok(self.builder.build_float_div(lhs, rhs, "tmpdiv")) // // } // // '<' => Ok({ // // let cmp = self.builder.build_float_compare( // // FloatPredicate::ULT, // // lhs, // // rhs, // // "tmpcmp", // // ); // // self.builder.build_unsigned_int_to_float( // // cmp, // // self.context.f64_type(), // // "tmpbool", // // ) // // }), // // '>' => Ok({ // // let cmp = self.builder.build_float_compare( // // FloatPredicate::ULT, // // rhs, // // lhs, // // "tmpcmp", // // ); // // self.builder.build_unsigned_int_to_float( // // cmp, // // self.context.f64_type(), // // "tmpbool", // // ) // // }), // // custom => { // // let mut name = String::from("binary"); // // name.push(custom); // // match self.get_function(name.as_str()) { // // Some(fun) => { // // match self // // .builder // // .build_call( // // fun, // // &[lhs.into(), rhs.into()], // // "tmpbin", // // ) // // .try_as_basic_value() // // .left() // // { // // Some(value) => { // // Ok(value.into_float_value()) // // } // // None => Err("Invalid call produced."), // // } // // } // // None => Err("Undefined binary operator."), // // } // // } // // } // // } // // } // // Expr::Call { // // ref fn_name, // // ref args, // // } => match self.get_function(fn_name.as_str()) { // // Some(fun) => { // // let mut compiled_args = Vec::with_capacity(args.len()); // // for arg in args { // // compiled_args.push(self.compile_expr(arg)?); // // } // // let argsv: Vec<BasicValueEnum> = compiled_args // // .iter() // // .by_ref() // // .map(|&val| val.into()) // // .collect(); // // match self // // .builder // // .build_call(fun, argsv.as_slice(), "tmp") // // .try_as_basic_value() // // .left() // // { // // Some(value) => Ok(value.into_float_value()), // // None => Err("Invalid call produced."), // // } // // } // // None => Err("Unknown function."), // // }, // // Expr::Conditional { // // ref cond, // // ref consequence, // // ref alternative, // // } => { // // let parent = self.fn_value(); // // let zero_const = self.context.f64_type().const_float(0.0); // // // create condition by comparing without 0.0 and returning an int // // let cond = self.compile_expr(cond)?; // // let cond = self.builder.build_float_compare( // // FloatPredicate::ONE, // // cond, // // zero_const, // // "ifcond", // // ); // // // build branch // // let then_bb = self.context.append_basic_block(&parent, "then"); // // let else_bb = self.context.append_basic_block(&parent, "else"); // // let cont_bb = // // self.context.append_basic_block(&parent, "ifcont"); // // self.builder // // .build_conditional_branch(cond, &then_bb, &else_bb); // // // build then block // // self.builder.position_at_end(&then_bb); // // let then_val = self.compile_expr(consequence)?; // // self.builder.build_unconditional_branch(&cont_bb); // // let then_bb = self.builder.get_insert_block().unwrap(); // // // build else block // // self.builder.position_at_end(&else_bb); // // let else_val = self.compile_expr(alternative)?; // // self.builder.build_unconditional_branch(&cont_bb); // // let else_bb = self.builder.get_insert_block().unwrap(); // // // emit merge block // // self.builder.position_at_end(&cont_bb); // // let phi = // // self.builder.build_phi(self.context.f64_type(), "iftmp"); // // phi.add_incoming(&[ // // (&then_val, &then_bb), // // (&else_val, &else_bb), // // ]); // // Ok(phi.as_basic_value().into_float_value()) // // } // // Expr::For { // // ref var_name, // // ref start, // // ref end, // // ref step, // // ref body, // // } => { // // let parent = self.fn_value(); // // let start_alloca = self.create_entry_block_alloca(var_name); // // let start = self.compile_expr(start)?; // // self.builder.build_store(start_alloca, start); // // // go from current block to loop block // // let loop_bb = self.context.append_basic_block(&parent, "loop"); // // self.builder.build_unconditional_branch(&loop_bb); // // self.builder.position_at_end(&loop_bb); // // let old_val = self.variables.remove(var_name.as_str()); // // self.variables.insert(var_name.to_owned(), start_alloca); // // // emit body // // self.compile_expr(body)?; // // // emit step // // let step = match *step { // // Some(ref step) => self.compile_expr(step)?, // // None => self.context.f64_type().const_float(1.0), // // }; // // // compile end condition // // let end_cond = self.compile_expr(end)?; // // let curr_var = self.builder.build_load(start_alloca, var_name); // // let next_var = self.builder.build_float_add( // // curr_var.into_float_value(), // // step, // // "nextvar", // // ); // // self.builder.build_store(start_alloca, next_var); // // let end_cond = self.builder.build_float_compare( // // FloatPredicate::ONE, // // end_cond, // // self.context.f64_type().const_float(0.0), // // "loopcond", // // ); // // let after_bb = // // self.context.append_basic_block(&parent, "afterloop"); // // self.builder // // .build_conditional_branch(end_cond, &loop_bb, &after_bb); // // self.builder.position_at_end(&after_bb); // // self.variables.remove(var_name); // // if let Some(val) = old_val { // // self.variables.insert(var_name.to_owned(), val); // // } // // Ok(self.context.f64_type().const_float(0.0)) // // } // _ => unimplemented!(), // } // } // /// Compiles the specified `Prototype` into an extern LLVM `FunctionValue`. // fn compile_prototype( // &self, // sig: &Sig, // ) -> Result<FunctionValue, &'static str> { // let ret_type = sig.2; // let args_types = std::iter::repeat(ret_type) // .take(sig.1.len()) // .map(|f| f.into()) // .collect::<Vec<BasicTypeEnum>>(); // let args_types = args_types.as_slice(); // let fn_type = self.context.f64_type().fn_type(args_types, false); // let fn_val = self.module.add_function(sig.0.as_str(), fn_type, None); // // set arguments names // for (i, arg) in fn_val.get_param_iter().enumerate() { // arg.into_float_value().set_name(proto.args[i].as_str()); // } // // finally return built prototype // Ok(fn_val) // } // /// Compiles the specified `Function` into an LLVM `FunctionValue`. // fn compile_fn(&mut self) -> Result<FunctionValue, &'static str> { // let sig = &self.function.sig; // let function = self.compile_sig(sig)?; // // got external function, returning only compiled prototype // // if self.function.body.is_none() { // // return Ok(function); // // } // let entry = self.context.append_basic_block(&function, "entry"); // self.builder.position_at_end(&entry); // // update fn field // self.fn_value_opt = Some(function); // // build variables map // self.variables.reserve(proto.args.len()); // for (i, arg) in function.get_param_iter().enumerate() { // let arg_name = proto.args[i].as_str(); // let alloca = self.create_entry_block_alloca(arg_name); // self.builder.build_store(alloca, arg); // self.variables.insert(proto.args[i].clone(), alloca); // } // // compile body // let body = self.compile_expr(self.function.body.as_ref().unwrap())?; // self.builder.build_return(Some(&body)); // // return the whole thing after verification and optimization // if function.verify(true) { // self.fpm.run_on(&function); // Ok(function) // } else { // unsafe { // function.delete(); // } // Err("Invalid generated function.") // } // } // /// Compiles the specified `Function` in the given `Context` and using the specified `Builder`, `PassManager`, and `Module`. // pub fn compile( // context: &'a Context, // builder: &'a Builder, // pass_manager: &'a PassManager<FunctionValue>, // module: &'a Module, // function: &Function, // ) -> Result<FunctionValue, &'static str> { // let mut compiler = Compiler { // context: context, // builder: builder, // fpm: pass_manager, // module: module, // function: function, // fn_value_opt: None, // variables: HashMap::new(), // }; // compiler.compile_fn() // } // }