Implement some kind of if/else
This commit is contained in:
parent
8defa39b31
commit
e21f47e34b
@ -214,7 +214,7 @@ impl Parse for FunctionCallExpression {
|
|||||||
}
|
}
|
||||||
|
|
||||||
#[derive(Debug, Clone)]
|
#[derive(Debug, Clone)]
|
||||||
pub struct IfExpression(Expression, pub Block, pub TokenRange);
|
pub struct IfExpression(pub Expression, pub Block, pub TokenRange);
|
||||||
|
|
||||||
impl Parse for IfExpression {
|
impl Parse for IfExpression {
|
||||||
fn parse(mut stream: TokenStream) -> Result<Self, Error> {
|
fn parse(mut stream: TokenStream) -> Result<Self, Error> {
|
||||||
|
@ -1,3 +1,4 @@
|
|||||||
|
use std::borrow::BorrowMut;
|
||||||
use std::ffi::{CStr, CString};
|
use std::ffi::{CStr, CString};
|
||||||
use std::mem;
|
use std::mem;
|
||||||
|
|
||||||
@ -21,6 +22,7 @@ pub enum Error {
|
|||||||
#[derive(Clone, Debug, Eq, PartialEq)]
|
#[derive(Clone, Debug, Eq, PartialEq)]
|
||||||
pub enum IRType {
|
pub enum IRType {
|
||||||
I32,
|
I32,
|
||||||
|
Boolean,
|
||||||
}
|
}
|
||||||
|
|
||||||
impl IRType {
|
impl IRType {
|
||||||
@ -29,6 +31,7 @@ impl IRType {
|
|||||||
unsafe {
|
unsafe {
|
||||||
return match self {
|
return match self {
|
||||||
I32 => LLVMInt32TypeInContext(context.context),
|
I32 => LLVMInt32TypeInContext(context.context),
|
||||||
|
Boolean => LLVMInt1TypeInContext(context.context),
|
||||||
};
|
};
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
@ -140,26 +143,20 @@ impl<'a, 'b> IRFunction<'a, 'b> {
|
|||||||
}
|
}
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
pub fn attach(&mut self, block: IRBlock) {
|
|
||||||
unsafe { LLVMAppendExistingBasicBlock(self.value, block.blockref) }
|
|
||||||
}
|
|
||||||
}
|
}
|
||||||
|
|
||||||
pub struct IRBlock<'a, 'b> {
|
pub struct IRBlock<'a, 'b, 'c> {
|
||||||
pub module: &'b IRModule<'a>,
|
pub function: &'c IRFunction<'a, 'b>,
|
||||||
blockref: *mut LLVMBasicBlock,
|
blockref: *mut LLVMBasicBlock,
|
||||||
}
|
}
|
||||||
|
|
||||||
impl<'a, 'b, 'c> IRBlock<'a, 'b> {
|
impl<'a, 'b, 'c> IRBlock<'a, 'b, 'c> {
|
||||||
pub fn new(module: &'b IRModule<'a>) -> IRBlock<'a, 'b> {
|
pub fn new(function: &'c IRFunction<'a, 'b>, name: &CStr) -> IRBlock<'a, 'b, 'c> {
|
||||||
unsafe {
|
unsafe {
|
||||||
let blockref = LLVMCreateBasicBlockInContext(
|
let blockref =
|
||||||
module.context.context,
|
LLVMCreateBasicBlockInContext(function.module.context.context, name.as_ptr());
|
||||||
into_cstring("entryblock").as_ptr(),
|
|
||||||
);
|
|
||||||
|
|
||||||
IRBlock { module, blockref }
|
IRBlock { function, blockref }
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
@ -169,12 +166,12 @@ impl<'a, 'b, 'c> IRBlock<'a, 'b> {
|
|||||||
IRValue(rhs_t, rhs_v): IRValue,
|
IRValue(rhs_t, rhs_v): IRValue,
|
||||||
) -> Result<IRValue, Error> {
|
) -> Result<IRValue, Error> {
|
||||||
unsafe {
|
unsafe {
|
||||||
LLVMPositionBuilderAtEnd(self.module.context.builder, self.blockref);
|
LLVMPositionBuilderAtEnd(self.function.module.context.builder, self.blockref);
|
||||||
if lhs_t == rhs_t {
|
if lhs_t == rhs_t {
|
||||||
Ok(IRValue(
|
Ok(IRValue(
|
||||||
lhs_t,
|
lhs_t,
|
||||||
LLVMBuildAdd(
|
LLVMBuildAdd(
|
||||||
self.module.context.builder,
|
self.function.module.context.builder,
|
||||||
lhs_v,
|
lhs_v,
|
||||||
rhs_v,
|
rhs_v,
|
||||||
c"tmpadd".as_ptr(),
|
c"tmpadd".as_ptr(),
|
||||||
@ -192,12 +189,12 @@ impl<'a, 'b, 'c> IRBlock<'a, 'b> {
|
|||||||
IRValue(rhs_t, rhs_v): IRValue,
|
IRValue(rhs_t, rhs_v): IRValue,
|
||||||
) -> Result<IRValue, Error> {
|
) -> Result<IRValue, Error> {
|
||||||
unsafe {
|
unsafe {
|
||||||
LLVMPositionBuilderAtEnd(self.module.context.builder, self.blockref);
|
LLVMPositionBuilderAtEnd(self.function.module.context.builder, self.blockref);
|
||||||
if lhs_t == rhs_t {
|
if lhs_t == rhs_t {
|
||||||
Ok(IRValue(
|
Ok(IRValue(
|
||||||
lhs_t,
|
lhs_t,
|
||||||
LLVMBuildMul(
|
LLVMBuildMul(
|
||||||
self.module.context.builder,
|
self.function.module.context.builder,
|
||||||
lhs_v,
|
lhs_v,
|
||||||
rhs_v,
|
rhs_v,
|
||||||
c"tmpadd".as_ptr(),
|
c"tmpadd".as_ptr(),
|
||||||
@ -209,14 +206,70 @@ impl<'a, 'b, 'c> IRBlock<'a, 'b> {
|
|||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
pub fn add_return(&mut self, value: Option<IRValue>) {
|
pub fn less_than(
|
||||||
|
&mut self,
|
||||||
|
IRValue(lhs_t, lhs_v): IRValue,
|
||||||
|
IRValue(rhs_t, rhs_v): IRValue,
|
||||||
|
) -> Result<IRValue, Error> {
|
||||||
unsafe {
|
unsafe {
|
||||||
LLVMPositionBuilderAtEnd(self.module.context.builder, self.blockref);
|
LLVMPositionBuilderAtEnd(self.function.module.context.builder, self.blockref);
|
||||||
if let Some(IRValue(_, value)) = value {
|
if lhs_t == rhs_t {
|
||||||
LLVMBuildRet(self.module.context.builder, value);
|
Ok(IRValue(
|
||||||
|
IRType::Boolean,
|
||||||
|
LLVMBuildICmp(
|
||||||
|
self.function.module.context.builder,
|
||||||
|
llvm_sys::LLVMIntPredicate::LLVMIntULT,
|
||||||
|
lhs_v,
|
||||||
|
rhs_v,
|
||||||
|
c"IntULT".as_ptr(),
|
||||||
|
),
|
||||||
|
))
|
||||||
} else {
|
} else {
|
||||||
LLVMBuildRetVoid(self.module.context.builder);
|
Err(Error::TypeMismatch(lhs_t, rhs_t))
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
pub fn add_return(&mut self, value: Option<IRValue>) {
|
||||||
|
unsafe {
|
||||||
|
LLVMPositionBuilderAtEnd(self.function.module.context.builder, self.blockref);
|
||||||
|
if let Some(IRValue(_, value)) = value {
|
||||||
|
LLVMBuildRet(self.function.module.context.builder, value);
|
||||||
|
} else {
|
||||||
|
LLVMBuildRetVoid(self.function.module.context.builder);
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
pub fn branch(
|
||||||
|
&mut self,
|
||||||
|
IRValue(_, condition): IRValue,
|
||||||
|
then_block: &mut IRBlock,
|
||||||
|
else_block: &mut IRBlock,
|
||||||
|
) {
|
||||||
|
unsafe {
|
||||||
|
LLVMPositionBuilderAtEnd(self.function.module.context.builder, self.blockref);
|
||||||
|
LLVMBuildCondBr(
|
||||||
|
self.function.module.context.builder,
|
||||||
|
condition,
|
||||||
|
then_block.blockref,
|
||||||
|
else_block.blockref,
|
||||||
|
);
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
pub fn move_into(&mut self, block: &mut IRBlock) {
|
||||||
|
unsafe {
|
||||||
|
LLVMPositionBuilderAtEnd(self.function.module.context.builder, self.blockref);
|
||||||
|
LLVMBuildBr(self.function.module.context.builder, block.blockref);
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
impl<'a, 'b, 'c> Drop for IRBlock<'a, 'b, 'c> {
|
||||||
|
fn drop(&mut self) {
|
||||||
|
unsafe {
|
||||||
|
LLVMAppendExistingBasicBlock(self.function.value, self.blockref);
|
||||||
|
}
|
||||||
|
}
|
||||||
}
|
}
|
||||||
|
@ -6,8 +6,8 @@ use llvm::{Error, IRBlock, IRContext, IRFunction, IRModule, IRValue};
|
|||||||
|
|
||||||
use crate::{
|
use crate::{
|
||||||
ast::{
|
ast::{
|
||||||
Block, BlockLevelStatement, Expression, ExpressionKind, FunctionDefinition, LetStatement,
|
Block, BlockLevelStatement, Expression, ExpressionKind, FunctionDefinition, IfExpression,
|
||||||
ReturnType,
|
LetStatement, ReturnType,
|
||||||
},
|
},
|
||||||
TopLevelStatement,
|
TopLevelStatement,
|
||||||
};
|
};
|
||||||
@ -41,13 +41,11 @@ impl TopLevelStatement {
|
|||||||
impl FunctionDefinition {
|
impl FunctionDefinition {
|
||||||
fn codegen(&self, scope: &mut ScopeData, module: &mut IRModule) {
|
fn codegen(&self, scope: &mut ScopeData, module: &mut IRModule) {
|
||||||
let FunctionDefinition(signature, block, _) = self;
|
let FunctionDefinition(signature, block, _) = self;
|
||||||
let mut ir_function = IRFunction::new(&signature.name, module);
|
let ir_function = IRFunction::new(&signature.name, module);
|
||||||
|
|
||||||
let ir_block = IRBlock::new(&module);
|
let ir_block = IRBlock::new(&ir_function, c"entry");
|
||||||
let mut scope = scope.inner(ir_block);
|
let mut scope = scope.inner(ir_block);
|
||||||
block.codegen(&mut scope);
|
block.codegen(&mut scope);
|
||||||
|
|
||||||
ir_function.attach(scope.block);
|
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
@ -87,7 +85,7 @@ impl Expression {
|
|||||||
|
|
||||||
use ExpressionKind::*;
|
use ExpressionKind::*;
|
||||||
match kind {
|
match kind {
|
||||||
Literal(lit) => IRValue::from_literal(lit, &mut scope.block.module),
|
Literal(lit) => IRValue::from_literal(lit, &scope.block.function.module),
|
||||||
VariableName(v) => scope.data.fetch(v),
|
VariableName(v) => scope.data.fetch(v),
|
||||||
Binop(op, lhs, rhs) => {
|
Binop(op, lhs, rhs) => {
|
||||||
let lhs = lhs.codegen(scope);
|
let lhs = lhs.codegen(scope);
|
||||||
@ -96,10 +94,28 @@ impl Expression {
|
|||||||
match op {
|
match op {
|
||||||
Add => scope.block.add(lhs, rhs).unwrap(),
|
Add => scope.block.add(lhs, rhs).unwrap(),
|
||||||
Mult => scope.block.mult(lhs, rhs).unwrap(),
|
Mult => scope.block.mult(lhs, rhs).unwrap(),
|
||||||
|
LessThan => scope.block.less_than(lhs, rhs).unwrap(),
|
||||||
_ => panic!("operator not supported: {:?}", op),
|
_ => panic!("operator not supported: {:?}", op),
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
_ => panic!("expression type not supported"),
|
IfExpr(ifx) => {
|
||||||
|
let IfExpression(expr, block, _) = ifx.as_ref();
|
||||||
|
let condition = expr.codegen(scope);
|
||||||
|
|
||||||
|
let mut then = IRBlock::new(scope.block.function, c"then");
|
||||||
|
let mut after = IRBlock::new(scope.block.function, c"merge");
|
||||||
|
|
||||||
|
scope.block.branch(condition, &mut then, &mut after);
|
||||||
|
scope.block = after;
|
||||||
|
|
||||||
|
let mut inner = scope.inner(then);
|
||||||
|
block.codegen(&mut inner);
|
||||||
|
inner.block.move_into(&mut scope.block);
|
||||||
|
|
||||||
|
IRValue::from_literal(&crate::ast::Literal::I32(1), scope.block.function.module)
|
||||||
|
}
|
||||||
|
BlockExpr(_) => panic!("block expr not supported"),
|
||||||
|
FunctionCall(_) => panic!("function call expr not supported"),
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
@ -116,11 +132,11 @@ impl ScopeData {
|
|||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
fn with_block<'a, 'b>(self, block: IRBlock<'a, 'b>) -> Scope<'a, 'b> {
|
fn with_block<'a, 'b, 'c>(self, block: IRBlock<'a, 'b, 'c>) -> Scope<'a, 'b, 'c> {
|
||||||
Scope { data: self, block }
|
Scope { data: self, block }
|
||||||
}
|
}
|
||||||
|
|
||||||
fn inner<'a, 'b>(&self, block: IRBlock<'a, 'b>) -> Scope<'a, 'b> {
|
fn inner<'a, 'b, 'c>(&self, block: IRBlock<'a, 'b, 'c>) -> Scope<'a, 'b, 'c> {
|
||||||
self.clone().with_block(block)
|
self.clone().with_block(block)
|
||||||
}
|
}
|
||||||
|
|
||||||
@ -139,13 +155,13 @@ impl ScopeData {
|
|||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
struct Scope<'a, 'b> {
|
struct Scope<'a, 'b, 'c> {
|
||||||
data: ScopeData,
|
data: ScopeData,
|
||||||
block: IRBlock<'a, 'b>,
|
block: IRBlock<'a, 'b, 'c>,
|
||||||
}
|
}
|
||||||
|
|
||||||
impl<'a, 'b> Scope<'a, 'b> {
|
impl<'a, 'b, 'c> Scope<'a, 'b, 'c> {
|
||||||
fn inner(&self, block: IRBlock<'a, 'b>) -> Scope<'a, 'b> {
|
fn inner(&self, block: IRBlock<'a, 'b, 'c>) -> Scope<'a, 'b, 'c> {
|
||||||
self.data.clone().with_block(block)
|
self.data.clone().with_block(block)
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
Loading…
Reference in New Issue
Block a user