tart adding an if-statement
This commit is contained in:
		
							parent
							
								
									47b9d7e044
								
							
						
					
					
						commit
						b98000cebe
					
				| @ -13,8 +13,9 @@ fn main() { | |||||||
| // Fibonacci | // Fibonacci | ||||||
| 
 | 
 | ||||||
| fn fibonacci(value: i32) -> i32 { | fn fibonacci(value: i32) -> i32 { | ||||||
|     if value < 3 { |     if 1 < 3 { | ||||||
|         return 1; |         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)] | #[derive(Debug, Clone)] | ||||||
| pub struct IfExpression(Expression, pub Block); | pub struct IfExpression(pub Expression, pub Block, pub Block); | ||||||
| 
 | 
 | ||||||
| impl Parse for IfExpression { | impl Parse for IfExpression { | ||||||
|     fn parse(mut stream: TokenStream) -> Result<Self, Error> { |     fn parse(mut stream: TokenStream) -> Result<Self, Error> { | ||||||
|         stream.expect(Token::If)?; |         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::{ | use crate::{ | ||||||
|     ast::{ |     ast::{ | ||||||
|         BinaryOperator, Block, BlockLevelStatement, Expression, FunctionCallExpression, |         BinaryOperator, Block, BlockLevelStatement, Expression, FunctionCallExpression, | ||||||
|         FunctionDefinition, FunctionSignature, ReturnType, TopLevelStatement, |         FunctionDefinition, FunctionSignature, IfExpression, ReturnType, TopLevelStatement, | ||||||
|     }, |     }, | ||||||
|     llvm_ir::{self, IRBlock, IRFunction, IRModule, IRValue, IRValueType}, |     llvm_ir::{self, IRBlock, IRFunction, IRModule, IRValue, IRValueType}, | ||||||
| }; | }; | ||||||
| @ -102,7 +102,7 @@ impl TopLevelStatement { | |||||||
|             TopLevelStatement::FunctionDefinition(FunctionDefinition(sig, block)) => { |             TopLevelStatement::FunctionDefinition(FunctionDefinition(sig, block)) => { | ||||||
|                 if let Some((_, ir)) = root_data.function(&sig.name) { |                 if let Some((_, ir)) = root_data.function(&sig.name) { | ||||||
|                     if let Some(ir_function) = ir.take() { |                     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 mut scope = root_data.inner(&mut ir_block); | ||||||
| 
 | 
 | ||||||
|                         let (_, value) = match block.codegen(&mut scope)? { |                         let (_, value) = match block.codegen(&mut scope)? { | ||||||
| @ -173,6 +173,11 @@ impl Expression { | |||||||
|                     let rhs = rhs.codegen(scope)?; |                     let rhs = rhs.codegen(scope)?; | ||||||
|                     Ok(scope.block.mul(lhs, rhs)?) |                     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!"), |                 _ => panic!("Other binary operators not supported yet!"), | ||||||
|             }, |             }, | ||||||
|             BlockExpr(block) => { |             BlockExpr(block) => { | ||||||
| @ -202,11 +207,23 @@ impl Expression { | |||||||
|                 .cloned() |                 .cloned() | ||||||
|                 .ok_or(Error::UndefinedVariable(name.clone())), |                 .ok_or(Error::UndefinedVariable(name.clone())), | ||||||
|             Literal(lit) => Ok(scope.block.get_const(lit)), |             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)] | #[derive(thiserror::Error, Debug)] | ||||||
| pub enum Error { | pub enum Error { | ||||||
|     #[error("Variable '{0}' already defined")] |     #[error("Variable '{0}' already defined")] | ||||||
|  | |||||||
| @ -22,6 +22,8 @@ pub enum Token { | |||||||
|     Arrow, |     Arrow, | ||||||
|     /// `if`
 |     /// `if`
 | ||||||
|     If, |     If, | ||||||
|  |     /// `else`
 | ||||||
|  |     Else, | ||||||
| 
 | 
 | ||||||
|     // Symbols
 |     // Symbols
 | ||||||
|     /// `;`
 |     /// `;`
 | ||||||
| @ -160,6 +162,7 @@ pub fn tokenize<T: Into<String>>(to_tokenize: T) -> Result<Vec<FullToken>, Error | |||||||
|                     "return" => Token::ReturnKeyword, |                     "return" => Token::ReturnKeyword, | ||||||
|                     "fn" => Token::FnKeyword, |                     "fn" => Token::FnKeyword, | ||||||
|                     "if" => Token::If, |                     "if" => Token::If, | ||||||
|  |                     "else" => Token::Else, | ||||||
|                     _ => Token::Identifier(value), |                     _ => Token::Identifier(value), | ||||||
|                 }; |                 }; | ||||||
|                 variant |                 variant | ||||||
|  | |||||||
| @ -55,8 +55,8 @@ impl IRModule { | |||||||
|         } |         } | ||||||
|     } |     } | ||||||
| 
 | 
 | ||||||
|     pub fn create_block(&mut self) -> IRBlock { |     pub fn create_block(&mut self, name: &str) -> IRBlock { | ||||||
|         IRBlock::create("entry", self) |         IRBlock::create(name, self) | ||||||
|     } |     } | ||||||
| 
 | 
 | ||||||
|     pub fn create_func<T: Into<String>>( |     pub fn create_func<T: Into<String>>( | ||||||
| @ -194,6 +194,75 @@ impl<'a> IRBlock<'a> { | |||||||
|             Ok(IRValue(IRValueType::I32, call)) |             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)] | #[derive(Debug, thiserror::Error)] | ||||||
|  | |||||||
							
								
								
									
										0
									
								
								temp/test.png
									
									
									
									
									
										Normal file
									
								
							
							
						
						
									
										0
									
								
								temp/test.png
									
									
									
									
									
										Normal file
									
								
							
		Loading…
	
		Reference in New Issue
	
	Block a user