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