Skip to content

Commit

Permalink
[IR] adding variables + [ERRORS] adding a bit of error handling
Browse files Browse the repository at this point in the history
  • Loading branch information
Cr0a3 committed Jul 10, 2024
1 parent e224209 commit a468859
Show file tree
Hide file tree
Showing 7 changed files with 261 additions and 18 deletions.
22 changes: 17 additions & 5 deletions examples/simple.rs
Original file line number Diff line number Diff line change
@@ -1,6 +1,8 @@
use std::{error::Error, process::exit};

use Ygen::prelude::*;

pub fn main() {
pub fn main() -> Result<(), Box<dyn Error>> {
let mut module = Module::new();
let mut builder = IRBuilder::new();

Expand All @@ -11,11 +13,21 @@ pub fn main() {
let entry = func.addBlock("entry");
builder.positionAtEnd(entry);

builder.BuildRet(
Type::i32(5)
);
let val = builder.BuildAdd(Type::i32(5), Type::i32(5))?;

builder.BuildRet( val );

match module.verify() {
Ok(_) => {},
Err(e) => {
println!("{}", e);
exit(0)
},
};

println!("{}",
module.dump()
module.dumpColored()
);

Ok(())
}
35 changes: 28 additions & 7 deletions src/IR/block.rs
Original file line number Diff line number Diff line change
@@ -1,13 +1,14 @@
use crate::Support::Colorize;

use super::{Function, ir::Ir};
use super::{ir::Ir, Function, VerifyError};

#[derive(Debug, Clone)]
/// A basic block: stores ir of a specific area of a function
pub struct Block {
//pub(crate) func: Function,
pub(crate) name: String,
pub(crate) ir: Vec<Box<dyn Ir>>,
pub(crate) nodes: Vec<Box<dyn Ir>>,
varCount: usize,
}

impl Block {
Expand All @@ -16,7 +17,8 @@ impl Block {
Self {
//func: func.clone(),
name: name.to_string(),
ir: vec![],
nodes: vec![],
varCount: 0,
}
}

Expand All @@ -26,15 +28,15 @@ impl Block {

dump += &format!("{}:\n", self.name);

for node in &self.ir {
for node in &self.nodes {
dump += &format!("\t{}\n", node.dump());
}

dump
}

pub(crate) fn push_ir(&mut self, ir: Box<dyn Ir>) {
self.ir.push( ir );
self.nodes.push( ir );
}

/// Emits the ir of the block into one colored string
Expand All @@ -43,10 +45,29 @@ impl Block {

dump += &format!("{}:\n", self.name.cyan());

for node in &self.ir {
dump += &format!("\t{}\n", node.dumpColored());
for node in &self.nodes {
dump += &format!(" {}\n", node.dumpColored());
}

dump
}

/// Requests an new variable name - which is the current var index
/// Also counts up by one
pub fn reqVarName(&mut self) -> String {
let num = self.varCount;
self.varCount += 1;

num.to_string()
}

/// Verifys if the block and all of its ir nodes are correct:
/// * Checks if the return type is the actual specified return type of the function
pub fn verify(&self, func: &Function) -> Result<(), VerifyError> {
for node in &self.nodes {
node.verify(func.ty.clone())?;
}

Ok(())
}
}
16 changes: 14 additions & 2 deletions src/IR/func.rs
Original file line number Diff line number Diff line change
Expand Up @@ -2,6 +2,7 @@ use std::collections::VecDeque;

use super::Block;
use super::TypeMetadata;
use super::VerifyError;
use crate::Support::Colorize;

/// Stores the function type
Expand Down Expand Up @@ -87,7 +88,7 @@ impl Function {
});

for block in &self.blocks {
string += &format!(" {}\n", block.dump());
string += &format!(" {}\n", block.dump());
}

string += "}";
Expand All @@ -110,11 +111,22 @@ impl Function {
});

for block in &self.blocks {
string += &format!(" {}\n", block.dumpColored());
string += &format!(" {}\n", block.dumpColored());
}

string += "}";

string
}

/// Verifys if the function and all of its blocks are correct:
/// * Checks if the return type is the actual specified return type of the function
/// * Checks all ir nodes
pub fn verify(&self) -> Result<(), VerifyError> {
for block in &self.blocks {
block.verify(self)?
}

Ok(())
}
}
138 changes: 136 additions & 2 deletions src/IR/ir.rs
Original file line number Diff line number Diff line change
@@ -1,11 +1,43 @@
use std::fmt::Debug;
use super::{IRBuilder, Type, TypeMetadata};
use std::{error::Error, fmt::Debug};
use super::{FunctionType, IRBuilder, Type, TypeMetadata, Var, VerifyError};

macro_rules! IrTypeWith3 {
($name:tt, $param1:tt, $param2:tt, $param3:tt) => {
/// An Ir node
#[derive(Debug, Clone)]
pub struct $name<$param1, $param2, $param3> {
/// first inner value
pub inner1: $param1,
/// second inner value
pub inner2: $param2,
/// third inner value
pub inner3: $param3,
}


impl<$param1, $param2, $param3> $name<$param1, $param2, $param3> {
/// Creates new instance
#[allow(dead_code)]
pub fn new(op0: $param1, op1: $param2, op2: $param3) -> Box<Self> {
Box::from(
Self {
inner1: op0,
inner2: op1,
inner3: op2,
}
)
}
}
};
}
/*macro_rules! IrTypeWith2 {
($name:tt, $param1:tt, $param2:tt) => {
/// An Ir node
#[derive(Debug, Clone)]
pub struct $name<$param1, $param2> {
/// first inner value
pub inner1: $param1,
/// second inner value
pub inner2: $param2,
}
Expand Down Expand Up @@ -49,6 +81,7 @@ macro_rules! IrTypeWith1 {
}

IrTypeWith1!(Return, T);
IrTypeWith3!(Add, T, U, Z);

use crate::Support::Colorize;

Expand All @@ -66,6 +99,70 @@ impl Ir for Return<Type> {
let metadata: TypeMetadata = self.inner1.into();
format!("{} {} {}", "ret".blue(), metadata.to_string().green(), self.inner1.val().to_string().blue())
}

fn verify(&self, FuncTy: FunctionType) -> Result<(), VerifyError> {
let ty: TypeMetadata = self.inner1.into();

if ty != FuncTy.ret {
Err(VerifyError::RetTyNotFnTy(ty, FuncTy.ret))?
}

Ok(())
}
}

impl Ir for Return<Var> {
fn clone_box(&self) -> Box<dyn Ir> {
Box::new(self.clone())
}

fn dump(&self) -> String {
format!("ret {} {}", self.inner1.ty, self.inner1.name)
}

fn dumpColored(&self) -> String {
format!("{} {} {}", "ret".blue(), self.inner1.ty.to_string().green(), self.inner1.name.to_string().blue())
}

fn verify(&self, FuncTy: FunctionType) -> Result<(), VerifyError> {
let ty: TypeMetadata = self.inner1.ty.into();

if ty != FuncTy.ret {
Err(VerifyError::RetTyNotFnTy(ty, FuncTy.ret))?
}

Ok(())
}
}

impl Ir for Add<Type, Type, Var> {
fn clone_box(&self) -> Box<dyn Ir> {
Box::new(self.clone())
}

fn dump(&self) -> String {
format!("{} = add {} {}, {}", self.inner3.name, self.inner3.ty, self.inner1.val(), self.inner2.val())
}

fn dumpColored(&self) -> String {
format!("{} = {} {} {}, {}",
self.inner3.name.magenta(),
"add".blue(),
self.inner3.ty.to_string().green(),
self.inner1.val().to_string().blue(),
self.inner2.val().to_string().blue()
)
}

fn verify(&self, FuncTy: FunctionType) -> Result<(), VerifyError> {
let ty: TypeMetadata = self.inner1.into();

if ty != FuncTy.ret {
Err(VerifyError::RetTyNotFnTy(ty, FuncTy.ret))?
}

Ok(())
}
}

/// Trait for the return instruction
Expand All @@ -83,13 +180,50 @@ impl BuildReturn<Type> for IRBuilder<'_> {
}
}

impl BuildReturn<Var> for IRBuilder<'_> {
fn BuildRet(&mut self, var: Var) {
self.blocks.get_mut(self.curr).expect("the IRBuilder needs to have an current block\nConsider creating one")
.push_ir(Return::new(var))
}
}

/// Trait for the return instruction
/// Used for overloading the CreateRet function
/// So you can return a TypeConstant or a variable
pub trait BuildAdd<T, U> {
/// Adds to values
fn BuildAdd(&mut self, op0: T, op1: U) -> Result<Var, Box<dyn Error>>;
}

impl BuildAdd<Type, Type> for IRBuilder<'_> {
fn BuildAdd(&mut self, op0: Type, op1: Type) -> Result<Var, Box<dyn Error>> {
let block = self.blocks.get_mut(self.curr).expect("the IRBuilder needs to have an current block\nConsider creating one");

let op0Ty: TypeMetadata = op0.into();
let op1Ty: TypeMetadata = op1.into();

if op0Ty != op1Ty {
Err(VerifyError::Op0Op1TyNoMatch(op0Ty, op1Ty))?
}

let ty = op0Ty; // now both types need to be the same
let var = Var::new(block, ty);

block.push_ir(Add::new(op0, op1, var.clone()));

Ok(var)
}
}

/// The ir trait
pub(crate) trait Ir: Debug {
/// Returns the ir node as his textual representation
fn dump(&self) -> String;
/// Returns the ir node as his textual representation with colors
fn dumpColored(&self) -> String;

fn verify(&self, FuncTy: FunctionType) -> Result<(), VerifyError>;

/// Clones the node into a box of `Box<dyn Ir>`
fn clone_box(&self) -> Box<dyn Ir>;
}
Expand Down
37 changes: 36 additions & 1 deletion src/IR/mod.rs
Original file line number Diff line number Diff line change
Expand Up @@ -3,12 +3,47 @@ mod func;
mod typ;
mod builder;
mod block;
mod var;
/// Stores all ir nodes and the ir trait
pub mod ir;

use std::error::Error;
use std::fmt::Display;

pub use module::Module;
pub use func::{Function, FunctionType};
pub use typ::Type;
pub use typ::TypeMetadata;
pub use builder::IRBuilder;
pub use block::Block;
pub use block::Block;
pub use var::Var;

/// An error which stores if an ir node is invalid
#[derive(Debug, Clone, Copy, PartialEq, Eq)]
pub enum VerifyError {
/// The type of the ret node doesn't match the function return type
RetTyNotFnTy(TypeMetadata, TypeMetadata),
/// The type of op0 operand doesn't match the type of the op1 operand
Op0Op1TyNoMatch(TypeMetadata, TypeMetadata),
}

impl Display for VerifyError {
fn fmt(&self, f: &mut std::fmt::Formatter<'_>) -> std::fmt::Result {
write!(f, "{}", match &self {
VerifyError::RetTyNotFnTy(retTy, fnTy) => {
format!(
"The return type of the return node needs to be the same as the one of the function:\n{}",
format!(" ret {} ... but the function return type is {}", retTy, fnTy),
)
},
VerifyError::Op0Op1TyNoMatch(op0Ty, op1Ty) => {
format!(
"The type of the 1. operand needs to be the same as the one of the second operand:\n{}",
format!(" op0 {} ... but the op1 type is {}", op0Ty, op1Ty),
)

},
})
}
}
impl Error for VerifyError {}
Loading

0 comments on commit a468859

Please sign in to comment.