diff --git a/examples/crust.rs b/examples/crust.rs index 61af057e3c3a589ab11c12e2539fcfde6083f6f7..7a408daf211785079f71513db881e43c7a098811 100644 --- a/examples/crust.rs +++ b/examples/crust.rs @@ -1,3 +1,6 @@ +#![allow(unused_imports)] +#![allow(dead_code)] + use crust::{ ast::{Block, Cmd, Expr, Func, Op, Span, SpanExpr}, parse::{parse_block, parse_expr}, @@ -10,10 +13,7 @@ use inkwell::{ module::Module, passes::PassManager, types::BasicTypeEnum, - values::{ - BasicValueEnum, FloatValue, FunctionValue, InstructionValue, IntValue, - PointerValue, - }, + values::{BasicValueEnum, FloatValue, FunctionValue, InstructionValue, IntValue, PointerValue}, FloatPredicate, OptimizationLevel, }; use std::collections::HashMap; @@ -23,23 +23,23 @@ type ExprFunc = unsafe extern "C" fn() -> i32; fn main() -> Result<(), Box<dyn Error>> { let context = Context::create(); - let mut module = context.create_module("expr"); + 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)?; + let execution_engine = module.create_jit_execution_engine(OptimizationLevel::None)?; match parse_block(Span::new( " { - let abba : i32 = 7; + let abba : mut i32 = 7; + abba = 5; return 2 + abba } ", )) { Ok((_, prog)) => { - println!("{:?}", &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); @@ -54,18 +54,17 @@ fn main() -> Result<(), Box<dyn Error>> { variables: HashMap::new(), //&fpm, }; - let res = compiler.compile_block(prog); - // builder.build_return(Some(&res)); + compiler.compile_block(prog); let fun_expr: JitFunction<ExprFunc> = unsafe { execution_engine.get_function("expr").ok().unwrap() }; unsafe { - println!("{}", fun_expr.call()); + println!("\nexecution result : {}", fun_expr.call()); } } _ => panic!(), } - println!("module: {}", module.print_to_string()); + module.print_to_stderr(); Ok(()) } @@ -87,24 +86,33 @@ impl<'a> Compiler<'a> { 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) => match self.variables.get(&id) { - Some(var) => { - self.builder.build_load(*var, &id).into_int_value() - } - None => panic!( - "Could not find a matching variable. - {} in {:?}", - id, self.variables - ), - }, + 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) => { @@ -115,6 +123,7 @@ impl<'a> Compiler<'a> { _ => unimplemented!(), } } + // Todo: Binop, Unop, Booleans, Function calls _ => unimplemented!(), } } @@ -134,19 +143,20 @@ impl<'a> Compiler<'a> { 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) { - // println!("{:?}", cmd); match cmd { - // Cmd::Assign(lexp, rexp) => { - // let rval = eval_expr(rexp, mem, venv, fenv); - // println!("val {:?}", rval); - // let addr = eval_lvalue(lexp, mem, venv, fenv); - // // println!("lval {:?}", lval); - // // let addr = venv.get(&lval).unwrap(); - - // mem.Menv.insert(addr, rval); - // None - // } + 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) @@ -158,10 +168,12 @@ impl<'a> Compiler<'a> { // } // } // } + // -- TODO: While Cmd::Let(_, id, _, exp) => { let exp = self.compile_expr(exp); - println!("\n-- let id.fragment {}\n", id.fragment); + // 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) } @@ -176,28 +188,18 @@ impl<'a> Compiler<'a> { 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!(); } -} -// fn main() { -// let p = parse_prog(Span::new( -// " -// fn main() -> i32 -// { -// let a : i32 = 1 + 2; -// a = a + 1; -// return a -// } -// ", -// )); -// println!("{:?}", &p); -// } + // TODO, function declarations +} +// SHAMELESSLY STOLEN FROM inkwell!!!! // // ====================================================================================== // // COMPILER ============================================================================= // // ======================================================================================