Compare commits

...

1 Commits

Author SHA1 Message Date
b98000cebe tart adding an if-statement 2024-07-17 17:13:10 +03:00
6 changed files with 104 additions and 10 deletions

View File

@ -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);
}

View File

@ -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))
}
}

View File

@ -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")]

View File

@ -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

View File

@ -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
View File