From b98000cebe8f57d595894901fffa10dd4847df97 Mon Sep 17 00:00:00 2001 From: sofia Date: Wed, 17 Jul 2024 17:13:10 +0300 Subject: [PATCH] tart adding an if-statement --- examples/reid/easiest.reid | 7 ++-- src/ast.rs | 8 +++-- src/codegen.rs | 23 ++++++++++-- src/lexer.rs | 3 ++ src/llvm_ir.rs | 73 ++++++++++++++++++++++++++++++++++++-- temp/test.png | 0 6 files changed, 104 insertions(+), 10 deletions(-) create mode 100644 temp/test.png diff --git a/examples/reid/easiest.reid b/examples/reid/easiest.reid index 2033023..f8822c1 100644 --- a/examples/reid/easiest.reid +++ b/examples/reid/easiest.reid @@ -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); } diff --git a/src/ast.rs b/src/ast.rs index 6d240ae..e2cfc48 100644 --- a/src/ast.rs +++ b/src/ast.rs @@ -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 { 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)) } } diff --git a/src/codegen.rs b/src/codegen.rs index 83b1e12..23fef0f 100644 --- a/src/codegen.rs +++ b/src/codegen.rs @@ -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 { + 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")] diff --git a/src/lexer.rs b/src/lexer.rs index 20e128e..d6963e7 100644 --- a/src/lexer.rs +++ b/src/lexer.rs @@ -22,6 +22,8 @@ pub enum Token { Arrow, /// `if` If, + /// `else` + Else, // Symbols /// `;` @@ -160,6 +162,7 @@ pub fn tokenize>(to_tokenize: T) -> Result, Error "return" => Token::ReturnKeyword, "fn" => Token::FnKeyword, "if" => Token::If, + "else" => Token::Else, _ => Token::Identifier(value), }; variant diff --git a/src/llvm_ir.rs b/src/llvm_ir.rs index d0c754f..fab7a0e 100644 --- a/src/llvm_ir.rs +++ b/src/llvm_ir.rs @@ -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>( @@ -194,6 +194,75 @@ impl<'a> IRBlock<'a> { Ok(IRValue(IRValueType::I32, call)) } } + + pub fn cmp(&self, lhs: IRValue, rhs: IRValue) -> Result { + // 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 { + 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)] diff --git a/temp/test.png b/temp/test.png new file mode 100644 index 0000000..e69de29