Cleanup
This commit is contained in:
		
							parent
							
								
									61ba00ea58
								
							
						
					
					
						commit
						0392c293ba
					
				| @ -9,5 +9,5 @@ fn main() { | ||||
|         return 3; | ||||
|     } | ||||
| 
 | ||||
|     return test + simpleSub; | ||||
|     return arithmetic + simpleSub + boop; | ||||
| } | ||||
| @ -316,11 +316,13 @@ impl ast::Block { | ||||
|                         Ok(t) => InferredType::Static(*t, s_let.2), | ||||
|                         Err(e) => InferredType::DownstreamError(e.clone(), s_let.2), | ||||
|                     }; | ||||
|                     scope.set_var(VirtualVariable { | ||||
|                         name: s_let.0.clone(), | ||||
|                         inferred, | ||||
|                         meta: s_let.2.into(), | ||||
|                     }); | ||||
|                     state | ||||
|                         .note(scope.set_var(VirtualVariable { | ||||
|                             name: s_let.0.clone(), | ||||
|                             inferred, | ||||
|                             meta: s_let.2.into(), | ||||
|                         })) | ||||
|                         .ok(); | ||||
| 
 | ||||
|                     ( | ||||
|                         collapsed.ok().and_then(|t| { | ||||
| @ -356,6 +358,7 @@ impl ast::Block { | ||||
|             if let Some(expr) = r.1.process(state, scope) { | ||||
|                 Some((r.0.into(), Box::new(expr))) | ||||
|             } else { | ||||
|                 state.fatal = true; | ||||
|                 None? | ||||
|             } | ||||
|         } else { | ||||
|  | ||||
| @ -1,287 +0,0 @@ | ||||
| use std::borrow::BorrowMut; | ||||
| use std::ffi::{CStr, CString}; | ||||
| use std::mem; | ||||
| use std::ptr::null_mut; | ||||
| 
 | ||||
| use llvm_sys::analysis::LLVMVerifyModule; | ||||
| use llvm_sys::transforms::pass_manager_builder::{ | ||||
|     self, LLVMOpaquePassManagerBuilder, LLVMPassManagerBuilderCreate, | ||||
|     LLVMPassManagerBuilderSetOptLevel, | ||||
| }; | ||||
| use llvm_sys::{ | ||||
|     core::*, prelude::*, LLVMBasicBlock, LLVMBuilder, LLVMContext, LLVMModule, LLVMType, LLVMValue, | ||||
| }; | ||||
| 
 | ||||
| use crate::parser; | ||||
| 
 | ||||
| fn into_cstring<T: Into<String>>(value: T) -> CString { | ||||
|     let string = value.into(); | ||||
|     unsafe { CString::from_vec_with_nul_unchecked((string + "\0").into_bytes()) } | ||||
| } | ||||
| 
 | ||||
| #[derive(thiserror::Error, Debug)] | ||||
| pub enum Error { | ||||
|     #[error("Type mismatch: {0:?} vs {1:?}")] | ||||
|     TypeMismatch(IRType, IRType), | ||||
| } | ||||
| 
 | ||||
| #[derive(Clone, Debug, Eq, PartialEq)] | ||||
| pub enum IRType { | ||||
|     I32, | ||||
|     Boolean, | ||||
| } | ||||
| 
 | ||||
| impl IRType { | ||||
|     fn in_context(&self, context: &IRContext) -> *mut LLVMType { | ||||
|         use IRType::*; | ||||
|         unsafe { | ||||
|             return match self { | ||||
|                 I32 => LLVMInt32TypeInContext(context.context), | ||||
|                 Boolean => LLVMInt1TypeInContext(context.context), | ||||
|             }; | ||||
|         } | ||||
|     } | ||||
| } | ||||
| 
 | ||||
| #[derive(Clone)] | ||||
| pub struct IRValue(pub IRType, *mut LLVMValue); | ||||
| 
 | ||||
| impl IRValue { | ||||
|     pub fn from_literal(literal: &parser::Literal, module: &IRModule) -> Self { | ||||
|         use parser::Literal; | ||||
|         match literal { | ||||
|             Literal::I32(v) => { | ||||
|                 let ir_type = IRType::I32; | ||||
|                 unsafe { | ||||
|                     let ir_value = LLVMConstInt( | ||||
|                         ir_type.in_context(module.context), | ||||
|                         mem::transmute(*v as i64), | ||||
|                         1, | ||||
|                     ); | ||||
|                     return IRValue(ir_type, ir_value); | ||||
|                 } | ||||
|             } | ||||
|         }; | ||||
|     } | ||||
| } | ||||
| 
 | ||||
| pub struct IRContext { | ||||
|     context: *mut LLVMContext, | ||||
|     builder: *mut LLVMBuilder, | ||||
| } | ||||
| 
 | ||||
| impl IRContext { | ||||
|     pub fn new() -> IRContext { | ||||
|         unsafe { | ||||
|             // Set up a context, module and builder in that context.
 | ||||
|             let context = LLVMContextCreate(); | ||||
|             let builder = LLVMCreateBuilderInContext(context); | ||||
|             IRContext { context, builder } | ||||
|         } | ||||
|     } | ||||
| 
 | ||||
|     pub fn module<'a>(&'a mut self, name: String) -> IRModule<'a> { | ||||
|         IRModule::new(self, name) | ||||
|     } | ||||
| } | ||||
| 
 | ||||
| impl Drop for IRContext { | ||||
|     fn drop(&mut self) { | ||||
|         // Clean up. Values created in the context mostly get cleaned up there.
 | ||||
|         unsafe { | ||||
|             LLVMDisposeBuilder(self.builder); | ||||
|             LLVMContextDispose(self.context); | ||||
|         } | ||||
|     } | ||||
| } | ||||
| 
 | ||||
| pub struct IRModule<'a> { | ||||
|     context: &'a mut IRContext, | ||||
|     module: *mut LLVMModule, | ||||
| } | ||||
| 
 | ||||
| impl<'a> IRModule<'a> { | ||||
|     fn new<'b: 'a>(context: &'b mut IRContext, name: String) -> IRModule<'a> { | ||||
|         unsafe { | ||||
|             let module = | ||||
|                 LLVMModuleCreateWithNameInContext(into_cstring(name).as_ptr(), context.context); | ||||
| 
 | ||||
|             IRModule { context, module } | ||||
|         } | ||||
|     } | ||||
| 
 | ||||
|     pub fn print_to_string(&mut self) -> Result<&str, std::str::Utf8Error> { | ||||
|         unsafe { | ||||
|             LLVMVerifyModule( | ||||
|                 self.module, | ||||
|                 llvm_sys::analysis::LLVMVerifierFailureAction::LLVMPrintMessageAction, | ||||
|                 null_mut(), | ||||
|             ); | ||||
|             CStr::from_ptr(LLVMPrintModuleToString(self.module)).to_str() | ||||
|         } | ||||
|     } | ||||
| } | ||||
| 
 | ||||
| impl<'a> Drop for IRModule<'a> { | ||||
|     fn drop(&mut self) { | ||||
|         // Clean up. Values created in the context mostly get cleaned up there.
 | ||||
|         unsafe { | ||||
|             LLVMDisposeModule(self.module); | ||||
|         } | ||||
|     } | ||||
| } | ||||
| 
 | ||||
| pub struct IRFunction<'a, 'b> { | ||||
|     pub module: &'b IRModule<'a>, | ||||
|     /// The actual function
 | ||||
|     value: *mut LLVMValue, | ||||
| } | ||||
| 
 | ||||
| impl<'a, 'b> IRFunction<'a, 'b> { | ||||
|     pub fn new(name: &String, module: &'b IRModule<'a>) -> IRFunction<'a, 'b> { | ||||
|         unsafe { | ||||
|             // TODO, fix later!
 | ||||
| 
 | ||||
|             let return_type = LLVMInt32TypeInContext(module.context.context); | ||||
|             let mut argts = []; | ||||
|             let func_type = | ||||
|                 LLVMFunctionType(return_type, argts.as_mut_ptr(), argts.len() as u32, 0); | ||||
| 
 | ||||
|             let function = LLVMAddFunction(module.module, into_cstring(name).as_ptr(), func_type); | ||||
| 
 | ||||
|             IRFunction { | ||||
|                 module, | ||||
|                 value: function, | ||||
|             } | ||||
|         } | ||||
|     } | ||||
| } | ||||
| 
 | ||||
| pub struct IRBlock<'a, 'b, 'c> { | ||||
|     pub function: &'c IRFunction<'a, 'b>, | ||||
|     blockref: *mut LLVMBasicBlock, | ||||
| } | ||||
| 
 | ||||
| impl<'a, 'b, 'c> IRBlock<'a, 'b, 'c> { | ||||
|     pub fn new(function: &'c IRFunction<'a, 'b>, name: &CStr) -> IRBlock<'a, 'b, 'c> { | ||||
|         unsafe { | ||||
|             let blockref = | ||||
|                 LLVMCreateBasicBlockInContext(function.module.context.context, name.as_ptr()); | ||||
| 
 | ||||
|             IRBlock { function, blockref } | ||||
|         } | ||||
|     } | ||||
| 
 | ||||
|     pub fn add( | ||||
|         &mut self, | ||||
|         IRValue(lhs_t, lhs_v): IRValue, | ||||
|         IRValue(rhs_t, rhs_v): IRValue, | ||||
|     ) -> Result<IRValue, Error> { | ||||
|         unsafe { | ||||
|             LLVMPositionBuilderAtEnd(self.function.module.context.builder, self.blockref); | ||||
|             if lhs_t == rhs_t { | ||||
|                 Ok(IRValue( | ||||
|                     lhs_t, | ||||
|                     LLVMBuildAdd( | ||||
|                         self.function.module.context.builder, | ||||
|                         lhs_v, | ||||
|                         rhs_v, | ||||
|                         c"tmpadd".as_ptr(), | ||||
|                     ), | ||||
|                 )) | ||||
|             } else { | ||||
|                 Err(Error::TypeMismatch(lhs_t, rhs_t)) | ||||
|             } | ||||
|         } | ||||
|     } | ||||
| 
 | ||||
|     pub fn mult( | ||||
|         &mut self, | ||||
|         IRValue(lhs_t, lhs_v): IRValue, | ||||
|         IRValue(rhs_t, rhs_v): IRValue, | ||||
|     ) -> Result<IRValue, Error> { | ||||
|         unsafe { | ||||
|             LLVMPositionBuilderAtEnd(self.function.module.context.builder, self.blockref); | ||||
|             if lhs_t == rhs_t { | ||||
|                 Ok(IRValue( | ||||
|                     lhs_t, | ||||
|                     LLVMBuildMul( | ||||
|                         self.function.module.context.builder, | ||||
|                         lhs_v, | ||||
|                         rhs_v, | ||||
|                         c"tmpadd".as_ptr(), | ||||
|                     ), | ||||
|                 )) | ||||
|             } else { | ||||
|                 Err(Error::TypeMismatch(lhs_t, rhs_t)) | ||||
|             } | ||||
|         } | ||||
|     } | ||||
| 
 | ||||
|     pub fn less_than( | ||||
|         &mut self, | ||||
|         IRValue(lhs_t, lhs_v): IRValue, | ||||
|         IRValue(rhs_t, rhs_v): IRValue, | ||||
|     ) -> Result<IRValue, Error> { | ||||
|         unsafe { | ||||
|             LLVMPositionBuilderAtEnd(self.function.module.context.builder, self.blockref); | ||||
|             if lhs_t == rhs_t { | ||||
|                 Ok(IRValue( | ||||
|                     IRType::Boolean, | ||||
|                     LLVMBuildICmp( | ||||
|                         self.function.module.context.builder, | ||||
|                         llvm_sys::LLVMIntPredicate::LLVMIntULT, | ||||
|                         lhs_v, | ||||
|                         rhs_v, | ||||
|                         c"IntULT".as_ptr(), | ||||
|                     ), | ||||
|                 )) | ||||
|             } else { | ||||
|                 Err(Error::TypeMismatch(lhs_t, rhs_t)) | ||||
|             } | ||||
|         } | ||||
|     } | ||||
| 
 | ||||
|     pub fn add_return(&mut self, value: Option<IRValue>) { | ||||
|         unsafe { | ||||
|             LLVMPositionBuilderAtEnd(self.function.module.context.builder, self.blockref); | ||||
|             if let Some(IRValue(_, value)) = value { | ||||
|                 LLVMBuildRet(self.function.module.context.builder, value); | ||||
|             } else { | ||||
|                 LLVMBuildRetVoid(self.function.module.context.builder); | ||||
|             } | ||||
|         } | ||||
|     } | ||||
| 
 | ||||
|     pub fn branch( | ||||
|         &mut self, | ||||
|         IRValue(_, condition): IRValue, | ||||
|         then_block: &mut IRBlock, | ||||
|         else_block: &mut IRBlock, | ||||
|     ) { | ||||
|         unsafe { | ||||
|             LLVMPositionBuilderAtEnd(self.function.module.context.builder, self.blockref); | ||||
|             LLVMBuildCondBr( | ||||
|                 self.function.module.context.builder, | ||||
|                 condition, | ||||
|                 then_block.blockref, | ||||
|                 else_block.blockref, | ||||
|             ); | ||||
|         } | ||||
|     } | ||||
| 
 | ||||
|     pub fn move_into(&mut self, block: &mut IRBlock) { | ||||
|         unsafe { | ||||
|             LLVMPositionBuilderAtEnd(self.function.module.context.builder, self.blockref); | ||||
|             LLVMBuildBr(self.function.module.context.builder, block.blockref); | ||||
|         } | ||||
|     } | ||||
| } | ||||
| 
 | ||||
| impl<'a, 'b, 'c> Drop for IRBlock<'a, 'b, 'c> { | ||||
|     fn drop(&mut self) { | ||||
|         unsafe { | ||||
|             LLVMAppendExistingBasicBlock(self.function.value, self.blockref); | ||||
|         } | ||||
|     } | ||||
| } | ||||
| @ -1,176 +0,0 @@ | ||||
| mod llvm; | ||||
| 
 | ||||
| use std::collections::HashMap; | ||||
| 
 | ||||
| use llvm::{Error, IRBlock, IRContext, IRFunction, IRModule, IRValue}; | ||||
| 
 | ||||
| use crate::{ | ||||
|     parser::{ | ||||
|         Block, BlockLevelStatement, Expression, ExpressionKind, FunctionDefinition, IfExpression, | ||||
|         LetStatement, ReturnType, | ||||
|     }, | ||||
|     TopLevelStatement, | ||||
| }; | ||||
| 
 | ||||
| pub fn form_context() -> IRContext { | ||||
|     IRContext::new() | ||||
| } | ||||
| 
 | ||||
| pub fn from_statements( | ||||
|     context: &mut IRContext, | ||||
|     statements: Vec<TopLevelStatement>, | ||||
| ) -> Result<IRModule, Error> { | ||||
|     let mut module = context.module("testmod".to_owned()); | ||||
|     let mut scope = ScopeData::new(); | ||||
|     for statement in statements { | ||||
|         statement.codegen(&mut scope, &mut module); | ||||
|     } | ||||
| 
 | ||||
|     Ok(module) | ||||
| } | ||||
| 
 | ||||
| impl TopLevelStatement { | ||||
|     fn codegen(&self, scope: &mut ScopeData, module: &mut IRModule) { | ||||
|         match self { | ||||
|             Self::FunctionDefinition(func) => func.codegen(scope, module), | ||||
|             Self::Import(_) => panic!("not implemented"), | ||||
|         } | ||||
|     } | ||||
| } | ||||
| 
 | ||||
| impl FunctionDefinition { | ||||
|     fn codegen(&self, scope: &mut ScopeData, module: &mut IRModule) { | ||||
|         let FunctionDefinition(signature, block, _) = self; | ||||
|         let ir_function = IRFunction::new(&signature.name, module); | ||||
| 
 | ||||
|         let ir_block = IRBlock::new(&ir_function, c"entry"); | ||||
|         let mut scope = scope.inner(ir_block); | ||||
|         if let Some((_, val)) = block.codegen(&mut scope) { | ||||
|             scope.block.add_return(Some(val)); | ||||
|         } else { | ||||
|             scope.block.add_return(None); | ||||
|         } | ||||
|     } | ||||
| } | ||||
| 
 | ||||
| impl Block { | ||||
|     #[must_use] | ||||
|     fn codegen(&self, scope: &mut Scope) -> Option<(ReturnType, IRValue)> { | ||||
|         for statement in &self.0 { | ||||
|             statement.codegen(scope); | ||||
|         } | ||||
| 
 | ||||
|         if let Some((ret_type, return_exp)) = &self.1 { | ||||
|             let value = return_exp.codegen(scope); | ||||
|             Some((*ret_type, value)) | ||||
|         } else { | ||||
|             None | ||||
|         } | ||||
|     } | ||||
| } | ||||
| 
 | ||||
| impl BlockLevelStatement { | ||||
|     fn codegen(&self, scope: &mut Scope) { | ||||
|         use BlockLevelStatement::*; | ||||
|         match self { | ||||
|             Expression(exp) | Return(ReturnType::Soft, exp) => { | ||||
|                 exp.codegen(scope); | ||||
|             } | ||||
|             Let(LetStatement(name, exp, _)) => { | ||||
|                 let val = exp.codegen(scope); | ||||
|                 scope.data.insert(name, val); | ||||
|             } | ||||
|             Return(ReturnType::Hard, _) => panic!("hard returns here should not be possible.."), | ||||
|             Import(_) => panic!("block level import not supported"), | ||||
|         } | ||||
|     } | ||||
| } | ||||
| 
 | ||||
| impl Expression { | ||||
|     fn codegen(&self, scope: &mut Scope) -> IRValue { | ||||
|         let Expression(kind, _) = self; | ||||
| 
 | ||||
|         use ExpressionKind::*; | ||||
|         match kind { | ||||
|             Literal(lit) => IRValue::from_literal(lit, &scope.block.function.module), | ||||
|             VariableName(v) => scope.data.fetch(v), | ||||
|             Binop(op, lhs, rhs) => { | ||||
|                 let lhs = lhs.codegen(scope); | ||||
|                 let rhs = rhs.codegen(scope); | ||||
|                 use crate::parser::BinaryOperator::*; | ||||
|                 match op { | ||||
|                     Add => scope.block.add(lhs, rhs).unwrap(), | ||||
|                     Mult => scope.block.mult(lhs, rhs).unwrap(), | ||||
|                     LessThan => scope.block.less_than(lhs, rhs).unwrap(), | ||||
|                     _ => panic!("operator not supported: {:?}", op), | ||||
|                 } | ||||
|             } | ||||
|             IfExpr(ifx) => { | ||||
|                 let IfExpression(expr, block, _) = ifx.as_ref(); | ||||
|                 let condition = expr.codegen(scope); | ||||
| 
 | ||||
|                 let mut thenb = IRBlock::new(scope.block.function, c"then"); | ||||
|                 let mut afterb = IRBlock::new(scope.block.function, c"merge"); | ||||
| 
 | ||||
|                 scope.block.branch(condition, &mut thenb, &mut afterb); | ||||
|                 scope.block = afterb; | ||||
| 
 | ||||
|                 let mut then = scope.inner(thenb); | ||||
|                 match block.codegen(&mut then) { | ||||
|                     Some((ReturnType::Hard, v)) => then.block.add_return(Some(v)), | ||||
|                     _ => then.block.move_into(&mut scope.block), | ||||
|                 } | ||||
| 
 | ||||
|                 IRValue::from_literal(&crate::parser::Literal::I32(1), scope.block.function.module) | ||||
|             } | ||||
|             BlockExpr(_) => panic!("block expr not supported"), | ||||
|             FunctionCall(_) => panic!("function call expr not supported"), | ||||
|         } | ||||
|     } | ||||
| } | ||||
| 
 | ||||
| #[derive(Clone)] | ||||
| struct ScopeData { | ||||
|     vars: HashMap<String, IRValue>, | ||||
| } | ||||
| 
 | ||||
| impl ScopeData { | ||||
|     fn new() -> ScopeData { | ||||
|         ScopeData { | ||||
|             vars: HashMap::new(), | ||||
|         } | ||||
|     } | ||||
| 
 | ||||
|     fn with_block<'a, 'b, 'c>(self, block: IRBlock<'a, 'b, 'c>) -> Scope<'a, 'b, 'c> { | ||||
|         Scope { data: self, block } | ||||
|     } | ||||
| 
 | ||||
|     fn inner<'a, 'b, 'c>(&self, block: IRBlock<'a, 'b, 'c>) -> Scope<'a, 'b, 'c> { | ||||
|         self.clone().with_block(block) | ||||
|     } | ||||
| 
 | ||||
|     fn fetch(&self, name: &String) -> IRValue { | ||||
|         match self.vars.get(name) { | ||||
|             Some(val) => val.clone(), | ||||
|             _ => panic!("No such variable in scope: {}", name), | ||||
|         } | ||||
|     } | ||||
| 
 | ||||
|     fn insert(&mut self, name: &String, value: IRValue) { | ||||
|         match self.vars.insert(name.clone(), value) { | ||||
|             Some(_) => panic!("{} was already defined in scope", name), | ||||
|             _ => {} | ||||
|         } | ||||
|     } | ||||
| } | ||||
| 
 | ||||
| struct Scope<'a, 'b, 'c> { | ||||
|     data: ScopeData, | ||||
|     block: IRBlock<'a, 'b, 'c>, | ||||
| } | ||||
| 
 | ||||
| impl<'a, 'b, 'c> Scope<'a, 'b, 'c> { | ||||
|     fn inner(&self, block: IRBlock<'a, 'b, 'c>) -> Scope<'a, 'b, 'c> { | ||||
|         self.data.clone().with_block(block) | ||||
|     } | ||||
| } | ||||
| @ -1,222 +0,0 @@ | ||||
| use std::collections::{hash_map, HashMap}; | ||||
| 
 | ||||
| use crate::{ | ||||
|     ast::{ | ||||
|         BinaryOperator, Block, BlockLevelStatement, Expression, FunctionCallExpression, | ||||
|         FunctionDefinition, FunctionSignature, ReturnType, TopLevelStatement, | ||||
|     }, | ||||
|     llvm_ir::{self, IRBlock, IRFunction, IRModule, IRValue, IRValueType}, | ||||
| }; | ||||
| 
 | ||||
| #[derive(Clone)] | ||||
| pub struct ScopeData { | ||||
|     named_vars: HashMap<String, IRValue>, | ||||
|     defined_functions: HashMap<String, (FunctionSignature, Option<IRFunction>)>, | ||||
| } | ||||
| 
 | ||||
| impl ScopeData { | ||||
|     pub fn inner<'a, 'b>(&self, block: &'b mut IRBlock<'a>) -> Scope<'a, 'b> { | ||||
|         Scope { | ||||
|             block, | ||||
|             data: self.clone(), | ||||
|         } | ||||
|     } | ||||
| 
 | ||||
|     pub fn var(&self, name: &String) -> Option<&IRValue> { | ||||
|         self.named_vars.get(name) | ||||
|     } | ||||
| 
 | ||||
|     pub fn set_var(&mut self, name: &str, val: IRValue) -> Result<(), Error> { | ||||
|         if let hash_map::Entry::Vacant(e) = self.named_vars.entry(name.to_owned()) { | ||||
|             e.insert(val); | ||||
|             Ok(()) | ||||
|         } else { | ||||
|             Err(Error::VariableAlreadyDefined(name.to_owned())) | ||||
|         } | ||||
|     } | ||||
| 
 | ||||
|     pub fn function( | ||||
|         &mut self, | ||||
|         name: &String, | ||||
|     ) -> Option<&mut (FunctionSignature, Option<IRFunction>)> { | ||||
|         self.defined_functions.get_mut(name) | ||||
|     } | ||||
| 
 | ||||
|     pub fn set_function_signature( | ||||
|         &mut self, | ||||
|         name: &str, | ||||
|         sig: FunctionSignature, | ||||
|         ir: IRFunction, | ||||
|     ) -> Result<(), Error> { | ||||
|         if let hash_map::Entry::Vacant(e) = self.defined_functions.entry(name.to_owned()) { | ||||
|             e.insert((sig, Some(ir))); | ||||
|             Ok(()) | ||||
|         } else { | ||||
|             Err(Error::VariableAlreadyDefined(name.to_owned())) | ||||
|         } | ||||
|     } | ||||
| } | ||||
| 
 | ||||
| pub struct Scope<'a, 'b> { | ||||
|     pub block: &'b mut IRBlock<'a>, | ||||
|     pub data: ScopeData, | ||||
| } | ||||
| 
 | ||||
| impl<'a, 'b> Scope<'a, 'b> { | ||||
|     pub fn inner<'c>(&'c mut self) -> Scope<'a, 'c> { | ||||
|         Scope { | ||||
|             block: self.block, | ||||
|             data: self.data.clone(), | ||||
|         } | ||||
|     } | ||||
| } | ||||
| 
 | ||||
| pub fn codegen_from_statements(statements: Vec<TopLevelStatement>) -> Result<IRModule, Error> { | ||||
|     let mut module = IRModule::new("testmod"); | ||||
| 
 | ||||
|     let mut scope = ScopeData { | ||||
|         defined_functions: HashMap::new(), | ||||
|         named_vars: HashMap::new(), | ||||
|     }; | ||||
| 
 | ||||
|     for statement in &statements { | ||||
|         match statement { | ||||
|             TopLevelStatement::FunctionDefinition(FunctionDefinition(sig, _)) => { | ||||
|                 let function = module.create_func(&sig.name, IRValueType::I32); | ||||
|                 scope.set_function_signature(&sig.name.clone(), sig.clone(), function)?; | ||||
|             } | ||||
|             TopLevelStatement::Import(_) => {} | ||||
|         } | ||||
|     } | ||||
| 
 | ||||
|     for statement in &statements { | ||||
|         statement.codegen(&mut module, &mut scope)?; | ||||
|     } | ||||
| 
 | ||||
|     Ok(module) | ||||
| } | ||||
| 
 | ||||
| impl TopLevelStatement { | ||||
|     pub fn codegen(&self, module: &mut IRModule, root_data: &mut ScopeData) -> Result<(), Error> { | ||||
|         match self { | ||||
|             TopLevelStatement::FunctionDefinition(FunctionDefinition(sig, block)) => { | ||||
|                 if let Some((_, ir)) = root_data.function(&sig.name) { | ||||
|                     if let Some(ir_function) = ir.take() { | ||||
|                         let mut ir_block = module.create_block(); | ||||
|                         let mut scope = root_data.inner(&mut ir_block); | ||||
| 
 | ||||
|                         let (_, value) = match block.codegen(&mut scope)? { | ||||
|                             Some(v) => v, | ||||
|                             None => panic!("Void-return type function not yet implemented!"), | ||||
|                         }; | ||||
| 
 | ||||
|                         ir_function.add_definition(value, ir_block); | ||||
|                     } else { | ||||
|                         Err(Error::FunctionAlreadyDefined(sig.name.clone()))? | ||||
|                     } | ||||
|                 } else { | ||||
|                     panic!("Function was not declared before it's definition") | ||||
|                 } | ||||
|             } | ||||
|             TopLevelStatement::Import(_) => {} | ||||
|         } | ||||
|         Ok(()) | ||||
|     } | ||||
| } | ||||
| 
 | ||||
| impl Block { | ||||
|     pub fn codegen(&self, scope: &mut Scope) -> Result<Option<(ReturnType, IRValue)>, Error> { | ||||
|         for statement in &self.0 { | ||||
|             statement.codegen(scope)?; | ||||
|         } | ||||
| 
 | ||||
|         let value = if let Some((rt, exp)) = &self.1 { | ||||
|             Some((*rt, exp.codegen(scope)?)) | ||||
|         } else { | ||||
|             None | ||||
|         }; | ||||
| 
 | ||||
|         Ok(value) | ||||
|     } | ||||
| } | ||||
| 
 | ||||
| impl BlockLevelStatement { | ||||
|     pub fn codegen(&self, scope: &mut Scope) -> Result<(), Error> { | ||||
|         match self { | ||||
|             BlockLevelStatement::Let(let_statement) => { | ||||
|                 let val = let_statement.1.codegen(scope)?; | ||||
|                 scope.data.set_var(&let_statement.0, val)?; | ||||
|                 Ok(()) | ||||
|             } | ||||
|             BlockLevelStatement::Return(_) => panic!("Should never happen"), | ||||
|             BlockLevelStatement::Import(_) => Ok(()), // TODO: To implement
 | ||||
|             BlockLevelStatement::Expression(e) => { | ||||
|                 let _value = e.codegen(scope)?; | ||||
|                 Ok(()) | ||||
|             } | ||||
|         } | ||||
|     } | ||||
| } | ||||
| 
 | ||||
| impl Expression { | ||||
|     pub fn codegen(&self, scope: &mut Scope) -> Result<IRValue, Error> { | ||||
|         use Expression::*; | ||||
|         match self { | ||||
|             Binop(op, lhs, rhs) => match op { | ||||
|                 BinaryOperator::Add => { | ||||
|                     let lhs = lhs.codegen(scope)?; | ||||
|                     let rhs = rhs.codegen(scope)?; | ||||
|                     Ok(scope.block.add(lhs, rhs)?) | ||||
|                 } | ||||
|                 BinaryOperator::Mult => { | ||||
|                     let lhs = lhs.codegen(scope)?; | ||||
|                     let rhs = rhs.codegen(scope)?; | ||||
|                     Ok(scope.block.mul(lhs, rhs)?) | ||||
|                 } | ||||
|                 _ => panic!("Other binary operators not supported yet!"), | ||||
|             }, | ||||
|             BlockExpr(block) => { | ||||
|                 let mut inner = scope.inner(); | ||||
| 
 | ||||
|                 Ok(match block.codegen(&mut inner)? { | ||||
|                     Some((r_type, value)) => match r_type { | ||||
|                         ReturnType::Soft => value, | ||||
|                         ReturnType::Hard => { | ||||
|                             panic!("Hard returns in inner blocks not supported yet") | ||||
|                         } | ||||
|                     }, | ||||
|                     None => panic!("Void-return type block not yet implemented!"), | ||||
|                 }) | ||||
|             } | ||||
|             FunctionCall(fc) => { | ||||
|                 let FunctionCallExpression(name, _) = &**fc; | ||||
|                 if let Some((sig, _)) = scope.data.function(name) { | ||||
|                     Ok(scope.block.function_call(sig)?) | ||||
|                 } else { | ||||
|                     Err(Error::UndefinedFunction(name.clone()))? | ||||
|                 } | ||||
|             } | ||||
|             VariableName(name) => scope | ||||
|                 .data | ||||
|                 .var(name) | ||||
|                 .cloned() | ||||
|                 .ok_or(Error::UndefinedVariable(name.clone())), | ||||
|             Literal(lit) => Ok(scope.block.get_const(lit)), | ||||
|             IfExpr(_) => panic!("if expressions not yet supported"), | ||||
|         } | ||||
|     } | ||||
| } | ||||
| 
 | ||||
| #[derive(thiserror::Error, Debug)] | ||||
| pub enum Error { | ||||
|     #[error("Variable '{0}' already defined")] | ||||
|     VariableAlreadyDefined(String), | ||||
|     #[error("Variable '{0}' not yet defined")] | ||||
|     UndefinedVariable(String), | ||||
|     #[error("Function '{0}' not defined")] | ||||
|     UndefinedFunction(String), | ||||
|     #[error("Function '{0}' already defined")] | ||||
|     FunctionAlreadyDefined(String), | ||||
|     #[error(transparent)] | ||||
|     Deeper(#[from] llvm_ir::Error), | ||||
| } | ||||
| @ -1,203 +0,0 @@ | ||||
| use std::ffi::{CStr, CString}; | ||||
| use std::mem; | ||||
| 
 | ||||
| use llvm_sys::{core::*, prelude::*, LLVMBuilder, LLVMContext, LLVMModule}; | ||||
| 
 | ||||
| use crate::ast::{FunctionSignature, Literal}; | ||||
| 
 | ||||
| macro_rules! cstr { | ||||
|     ($string:expr) => { | ||||
|         core::ffi::CStr::from_bytes_with_nul_unchecked(concat!($string, "\0").as_bytes()).as_ptr() | ||||
|     }; | ||||
| } | ||||
| 
 | ||||
| #[derive(Clone, Debug)] | ||||
| #[must_use = "value contains raw pointer and must be inserted somewhere"] | ||||
| pub struct IRValue(IRValueType, LLVMValueRef); | ||||
| 
 | ||||
| #[derive(Clone, Debug, PartialEq, Eq)] | ||||
| pub enum IRValueType { | ||||
|     I32, | ||||
| } | ||||
| 
 | ||||
| impl IRValueType { | ||||
|     unsafe fn get_llvm_type(&self, module: &mut IRModule) -> LLVMTypeRef { | ||||
|         match *self { | ||||
|             Self::I32 => LLVMInt32TypeInContext(module.context), | ||||
|         } | ||||
|     } | ||||
| } | ||||
| 
 | ||||
| fn into_cstring<T: Into<String>>(value: T) -> CString { | ||||
|     let string = value.into(); | ||||
|     unsafe { CString::from_vec_with_nul_unchecked((string + "\0").into_bytes()) } | ||||
| } | ||||
| 
 | ||||
| pub struct IRModule { | ||||
|     context: *mut LLVMContext, | ||||
|     module: *mut LLVMModule, | ||||
|     builder: *mut LLVMBuilder, | ||||
| } | ||||
| 
 | ||||
| impl IRModule { | ||||
|     pub fn new<T: Into<String>>(name: T) -> IRModule { | ||||
|         unsafe { | ||||
|             // Set up a context, module and builder in that context.
 | ||||
|             let context = LLVMContextCreate(); | ||||
|             let module = LLVMModuleCreateWithNameInContext(into_cstring(name).as_ptr(), context); | ||||
|             let builder = LLVMCreateBuilderInContext(context); | ||||
| 
 | ||||
|             IRModule { | ||||
|                 context, | ||||
|                 module, | ||||
|                 builder, | ||||
|             } | ||||
|         } | ||||
|     } | ||||
| 
 | ||||
|     pub fn create_block(&mut self) -> IRBlock { | ||||
|         IRBlock::create("entry", self) | ||||
|     } | ||||
| 
 | ||||
|     pub fn create_func<T: Into<String>>( | ||||
|         &mut self, | ||||
|         name: T, | ||||
|         return_type: IRValueType, | ||||
|     ) -> IRFunction { | ||||
|         unsafe { | ||||
|             let mut argts = []; | ||||
|             let func_type = LLVMFunctionType( | ||||
|                 return_type.get_llvm_type(self), | ||||
|                 argts.as_mut_ptr(), | ||||
|                 argts.len() as u32, | ||||
|                 0, | ||||
|             ); | ||||
| 
 | ||||
|             let anon_func = LLVMAddFunction(self.module, into_cstring(name).as_ptr(), func_type); | ||||
|             IRFunction { | ||||
|                 value: IRValue(return_type, anon_func), | ||||
|             } | ||||
|         } | ||||
|     } | ||||
| 
 | ||||
|     pub fn print_to_string(&mut self) -> Result<&str, std::str::Utf8Error> { | ||||
|         unsafe { CStr::from_ptr(LLVMPrintModuleToString(self.module)).to_str() } | ||||
|     } | ||||
| } | ||||
| 
 | ||||
| impl Drop for IRModule { | ||||
|     fn drop(&mut self) { | ||||
|         // Clean up. Values created in the context mostly get cleaned up there.
 | ||||
|         unsafe { | ||||
|             LLVMDisposeBuilder(self.builder); | ||||
|             LLVMDisposeModule(self.module); | ||||
|             LLVMContextDispose(self.context); | ||||
|         } | ||||
|     } | ||||
| } | ||||
| 
 | ||||
| #[derive(Clone, Debug)] | ||||
| pub struct IRFunction { | ||||
|     value: IRValue, | ||||
| } | ||||
| 
 | ||||
| impl IRFunction { | ||||
|     pub fn add_definition(self, ret: IRValue, block: IRBlock) { | ||||
|         unsafe { | ||||
|             LLVMAppendExistingBasicBlock(self.value.1, block.blockref); | ||||
|             LLVMBuildRet(block.module.builder, ret.1); | ||||
|         } | ||||
|     } | ||||
| } | ||||
| 
 | ||||
| pub struct IRBlock<'a> { | ||||
|     module: &'a mut IRModule, | ||||
|     blockref: LLVMBasicBlockRef, | ||||
| } | ||||
| 
 | ||||
| impl<'a> IRBlock<'a> { | ||||
|     fn create<T: Into<String>>(name: T, codegen: &'a mut IRModule) -> IRBlock<'a> { | ||||
|         unsafe { | ||||
|             let blockref = | ||||
|                 LLVMCreateBasicBlockInContext(codegen.context, into_cstring(name).as_ptr()); | ||||
|             LLVMPositionBuilderAtEnd(codegen.builder, blockref); | ||||
|             IRBlock { | ||||
|                 module: codegen, | ||||
|                 blockref, | ||||
|             } | ||||
|         } | ||||
|     } | ||||
| 
 | ||||
|     pub fn get_const(&mut self, literal_type: &Literal) -> IRValue { | ||||
|         unsafe { | ||||
|             match *literal_type { | ||||
|                 Literal::I32(v) => IRValue( | ||||
|                     IRValueType::I32, | ||||
|                     LLVMConstInt( | ||||
|                         LLVMInt32TypeInContext(self.module.context), | ||||
|                         mem::transmute(v as i64), | ||||
|                         1, | ||||
|                     ), | ||||
|                 ), | ||||
|             } | ||||
|         } | ||||
|     } | ||||
| 
 | ||||
|     pub fn add(&mut self, lhs: IRValue, rhs: IRValue) -> Result<IRValue, Error> { | ||||
|         unsafe { | ||||
|             if lhs.0 == rhs.0 { | ||||
|                 Ok(IRValue( | ||||
|                     lhs.0, | ||||
|                     LLVMBuildAdd(self.module.builder, lhs.1, rhs.1, cstr!("tmpadd")), | ||||
|                 )) | ||||
|             } else { | ||||
|                 Err(Error::TypeMismatch(lhs.0, rhs.0)) | ||||
|             } | ||||
|         } | ||||
|     } | ||||
| 
 | ||||
|     pub fn mul(&mut self, lhs: IRValue, rhs: IRValue) -> Result<IRValue, Error> { | ||||
|         unsafe { | ||||
|             if lhs.0 == rhs.0 { | ||||
|                 Ok(IRValue( | ||||
|                     lhs.0, | ||||
|                     LLVMBuildMul(self.module.builder, lhs.1, rhs.1, cstr!("tmpadd")), | ||||
|                 )) | ||||
|             } else { | ||||
|                 Err(Error::TypeMismatch(lhs.0, rhs.0)) | ||||
|             } | ||||
|         } | ||||
|     } | ||||
| 
 | ||||
|     pub fn function_call(&mut self, callee: &FunctionSignature) -> Result<IRValue, Error> { | ||||
|         unsafe { | ||||
|             let function = LLVMGetNamedFunction( | ||||
|                 self.module.module, | ||||
|                 into_cstring(callee.name.clone()).as_ptr(), | ||||
|             ); | ||||
| 
 | ||||
|             let ret_t = LLVMInt32TypeInContext(self.module.context); | ||||
|             let mut argts = []; | ||||
|             let mut args = []; | ||||
| 
 | ||||
|             let fun_t = LLVMFunctionType(ret_t, argts.as_mut_ptr(), argts.len() as u32, 0); | ||||
| 
 | ||||
|             let call = LLVMBuildCall2( | ||||
|                 self.module.builder, | ||||
|                 fun_t, | ||||
|                 function, | ||||
|                 args.as_mut_ptr(), | ||||
|                 args.len() as u32, | ||||
|                 into_cstring(&callee.name).as_ptr(), | ||||
|             ); | ||||
| 
 | ||||
|             Ok(IRValue(IRValueType::I32, call)) | ||||
|         } | ||||
|     } | ||||
| } | ||||
| 
 | ||||
| #[derive(Debug, thiserror::Error)] | ||||
| pub enum Error { | ||||
|     #[error("Type Mismatch: {0:?} {1:?}")] | ||||
|     TypeMismatch(IRValueType, IRValueType), | ||||
| } | ||||
		Loading…
	
		Reference in New Issue
	
	Block a user