Compare commits
	
		
			1 Commits
		
	
	
		
	
	| Author | SHA1 | Date | |
|---|---|---|---|
| b98000cebe | 
| @ -13,8 +13,9 @@ fn main() { | ||||
| // Fibonacci | ||||
| 
 | ||||
| fn fibonacci(value: i32) -> i32 { | ||||
|     if value < 3 { | ||||
|         return 1; | ||||
|     if 1 < 3 { | ||||
|         1 | ||||
|     } else { | ||||
|         fibonacci(value - 1) + fibonacci(value - 2) | ||||
|     } | ||||
|     return fibonacci(value - 1) + fibonacci(value - 2); | ||||
| } | ||||
|  | ||||
| @ -182,12 +182,16 @@ impl Parse for FunctionCallExpression { | ||||
| } | ||||
| 
 | ||||
| #[derive(Debug, Clone)] | ||||
| pub struct IfExpression(Expression, pub Block); | ||||
| pub struct IfExpression(pub Expression, pub Block, pub Block); | ||||
| 
 | ||||
| impl Parse for IfExpression { | ||||
|     fn parse(mut stream: TokenStream) -> Result<Self, Error> { | ||||
|         stream.expect(Token::If)?; | ||||
|         Ok(IfExpression(stream.parse()?, stream.parse()?)) | ||||
|         let expr = stream.parse()?; | ||||
|         let then_block = stream.parse()?; | ||||
|         stream.expect(Token::Else)?; | ||||
|         let else_block = stream.parse()?; | ||||
|         Ok(IfExpression(expr, then_block, else_block)) | ||||
|     } | ||||
| } | ||||
| 
 | ||||
|  | ||||
| @ -3,7 +3,7 @@ use std::collections::{hash_map, HashMap}; | ||||
| use crate::{ | ||||
|     ast::{ | ||||
|         BinaryOperator, Block, BlockLevelStatement, Expression, FunctionCallExpression, | ||||
|         FunctionDefinition, FunctionSignature, ReturnType, TopLevelStatement, | ||||
|         FunctionDefinition, FunctionSignature, IfExpression, ReturnType, TopLevelStatement, | ||||
|     }, | ||||
|     llvm_ir::{self, IRBlock, IRFunction, IRModule, IRValue, IRValueType}, | ||||
| }; | ||||
| @ -102,7 +102,7 @@ impl TopLevelStatement { | ||||
|             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 ir_block = module.create_block(&sig.name); | ||||
|                         let mut scope = root_data.inner(&mut ir_block); | ||||
| 
 | ||||
|                         let (_, value) = match block.codegen(&mut scope)? { | ||||
| @ -173,6 +173,11 @@ impl Expression { | ||||
|                     let rhs = rhs.codegen(scope)?; | ||||
|                     Ok(scope.block.mul(lhs, rhs)?) | ||||
|                 } | ||||
|                 BinaryOperator::LessThan => { | ||||
|                     let lhs = lhs.codegen(scope)?; | ||||
|                     let rhs = rhs.codegen(scope)?; | ||||
|                     Ok(scope.block.cmp(lhs, rhs)?) | ||||
|                 } | ||||
|                 _ => panic!("Other binary operators not supported yet!"), | ||||
|             }, | ||||
|             BlockExpr(block) => { | ||||
| @ -202,11 +207,23 @@ impl Expression { | ||||
|                 .cloned() | ||||
|                 .ok_or(Error::UndefinedVariable(name.clone())), | ||||
|             Literal(lit) => Ok(scope.block.get_const(lit)), | ||||
|             IfExpr(_) => panic!("if expressions not yet supported"), | ||||
|             IfExpr(exp) => Ok(exp.codegen(scope)?), | ||||
|         } | ||||
|     } | ||||
| } | ||||
| 
 | ||||
| impl IfExpression { | ||||
|     pub fn codegen(&self, scope: &mut Scope) -> Result<IRValue, Error> { | ||||
|         let if_cond = self.0.codegen(scope)?; | ||||
|         let then_block = self.1.codegen(scope)?.unwrap(); | ||||
|         let else_block = self.2.codegen(scope)?.unwrap(); | ||||
|         let cond = scope | ||||
|             .block | ||||
|             .conditional_branch(if_cond, then_block.1, else_block.1)?; | ||||
|         Ok(cond) | ||||
|     } | ||||
| } | ||||
| 
 | ||||
| #[derive(thiserror::Error, Debug)] | ||||
| pub enum Error { | ||||
|     #[error("Variable '{0}' already defined")] | ||||
|  | ||||
| @ -22,6 +22,8 @@ pub enum Token { | ||||
|     Arrow, | ||||
|     /// `if`
 | ||||
|     If, | ||||
|     /// `else`
 | ||||
|     Else, | ||||
| 
 | ||||
|     // Symbols
 | ||||
|     /// `;`
 | ||||
| @ -160,6 +162,7 @@ pub fn tokenize<T: Into<String>>(to_tokenize: T) -> Result<Vec<FullToken>, Error | ||||
|                     "return" => Token::ReturnKeyword, | ||||
|                     "fn" => Token::FnKeyword, | ||||
|                     "if" => Token::If, | ||||
|                     "else" => Token::Else, | ||||
|                     _ => Token::Identifier(value), | ||||
|                 }; | ||||
|                 variant | ||||
|  | ||||
| @ -55,8 +55,8 @@ impl IRModule { | ||||
|         } | ||||
|     } | ||||
| 
 | ||||
|     pub fn create_block(&mut self) -> IRBlock { | ||||
|         IRBlock::create("entry", self) | ||||
|     pub fn create_block(&mut self, name: &str) -> IRBlock { | ||||
|         IRBlock::create(name, self) | ||||
|     } | ||||
| 
 | ||||
|     pub fn create_func<T: Into<String>>( | ||||
| @ -194,6 +194,75 @@ impl<'a> IRBlock<'a> { | ||||
|             Ok(IRValue(IRValueType::I32, call)) | ||||
|         } | ||||
|     } | ||||
| 
 | ||||
|     pub fn cmp(&self, lhs: IRValue, rhs: IRValue) -> Result<IRValue, Error> { | ||||
|         // FIXME! Only handles I32 comparisons for now
 | ||||
|         unsafe { | ||||
|             Ok(IRValue( | ||||
|                 IRValueType::I32, | ||||
|                 LLVMBuildICmp( | ||||
|                     self.module.builder, | ||||
|                     llvm_sys::LLVMIntPredicate::LLVMIntSLT, | ||||
|                     lhs.1, | ||||
|                     rhs.1, | ||||
|                     into_cstring("ifcond").as_ptr(), | ||||
|                 ), | ||||
|             )) | ||||
|         } | ||||
|     } | ||||
| 
 | ||||
|     pub fn conditional_branch( | ||||
|         &mut self, | ||||
|         if_ref: IRValue, | ||||
|         then_ret: IRValue, | ||||
|         else_ret: IRValue, | ||||
|     ) -> Result<IRValue, Error> { | ||||
|         unsafe { | ||||
|             dbg!("one"); | ||||
|             let ifcont_blockref = | ||||
|                 LLVMCreateBasicBlockInContext(self.module.context, into_cstring("ifcont").as_ptr()); | ||||
| 
 | ||||
|             dbg!("two"); | ||||
|             let (then_val, then_blockref) = { | ||||
|                 let block_ir = self.module.create_block("then"); | ||||
|                 LLVMBuildBr(block_ir.module.builder, ifcont_blockref); | ||||
|                 (then_ret, block_ir.blockref) | ||||
|             }; | ||||
| 
 | ||||
|             dbg!("three"); | ||||
|             let (else_val, else_blockref) = { | ||||
|                 let block_ir = self.module.create_block("else"); | ||||
|                 LLVMBuildBr(block_ir.module.builder, ifcont_blockref); | ||||
|                 (else_ret, block_ir.blockref) | ||||
|             }; | ||||
| 
 | ||||
|             dbg!("f"); | ||||
|             LLVMPositionBuilderAtEnd(self.module.builder, self.blockref); | ||||
| 
 | ||||
|             dbg!("s"); | ||||
|             LLVMBuildCondBr(self.module.builder, if_ref.1, then_blockref, else_blockref); | ||||
| 
 | ||||
|             dbg!("se"); | ||||
|             self.blockref = ifcont_blockref; | ||||
|             LLVMPositionBuilderAtEnd(self.module.builder, self.blockref); | ||||
| 
 | ||||
|             let phi = LLVMBuildPhi( | ||||
|                 self.module.builder, | ||||
|                 LLVMInt32TypeInContext(self.module.context), | ||||
|                 into_cstring("iftmp").as_ptr(), | ||||
|             ); | ||||
|             dbg!("e"); | ||||
|             LLVMAddIncoming( | ||||
|                 phi, | ||||
|                 [then_val.1, else_val.1].as_mut_ptr(), | ||||
|                 [then_blockref, else_blockref].as_mut_ptr(), | ||||
|                 2, | ||||
|             ); | ||||
| 
 | ||||
|             dbg!("ni"); | ||||
|             Ok(IRValue(IRValueType::I32, phi)) | ||||
|         } | ||||
|     } | ||||
| } | ||||
| 
 | ||||
| #[derive(Debug, thiserror::Error)] | ||||
|  | ||||
							
								
								
									
										0
									
								
								temp/test.png
									
									
									
									
									
										Normal file
									
								
							
							
						
						
									
										0
									
								
								temp/test.png
									
									
									
									
									
										Normal file
									
								
							
		Loading…
	
		Reference in New Issue
	
	Block a user