From a468859f66a1dac7741d9e722aefb95d3472684e Mon Sep 17 00:00:00 2001 From: TheCPP Date: Wed, 10 Jul 2024 17:12:04 +0200 Subject: [PATCH] [IR] adding variables + [ERRORS] adding a bit of error handling --- examples/simple.rs | 22 ++++++-- src/IR/block.rs | 35 +++++++++--- src/IR/func.rs | 16 +++++- src/IR/ir.rs | 138 ++++++++++++++++++++++++++++++++++++++++++++- src/IR/mod.rs | 37 +++++++++++- src/IR/module.rs | 13 ++++- src/IR/var.rs | 18 ++++++ 7 files changed, 261 insertions(+), 18 deletions(-) create mode 100644 src/IR/var.rs diff --git a/examples/simple.rs b/examples/simple.rs index 927b37dc..cda05c75 100644 --- a/examples/simple.rs +++ b/examples/simple.rs @@ -1,6 +1,8 @@ +use std::{error::Error, process::exit}; + use Ygen::prelude::*; -pub fn main() { +pub fn main() -> Result<(), Box> { let mut module = Module::new(); let mut builder = IRBuilder::new(); @@ -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(()) } \ No newline at end of file diff --git a/src/IR/block.rs b/src/IR/block.rs index a815f010..27a7d052 100644 --- a/src/IR/block.rs +++ b/src/IR/block.rs @@ -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>, + pub(crate) nodes: Vec>, + varCount: usize, } impl Block { @@ -16,7 +17,8 @@ impl Block { Self { //func: func.clone(), name: name.to_string(), - ir: vec![], + nodes: vec![], + varCount: 0, } } @@ -26,7 +28,7 @@ impl Block { dump += &format!("{}:\n", self.name); - for node in &self.ir { + for node in &self.nodes { dump += &format!("\t{}\n", node.dump()); } @@ -34,7 +36,7 @@ impl Block { } pub(crate) fn push_ir(&mut self, ir: Box) { - self.ir.push( ir ); + self.nodes.push( ir ); } /// Emits the ir of the block into one colored string @@ -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(()) + } } \ No newline at end of file diff --git a/src/IR/func.rs b/src/IR/func.rs index 3e548077..ebe56d9b 100644 --- a/src/IR/func.rs +++ b/src/IR/func.rs @@ -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 @@ -87,7 +88,7 @@ impl Function { }); for block in &self.blocks { - string += &format!(" {}\n", block.dump()); + string += &format!(" {}\n", block.dump()); } string += "}"; @@ -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(()) + } } diff --git a/src/IR/ir.rs b/src/IR/ir.rs index 608cb600..e1202b1e 100644 --- a/src/IR/ir.rs +++ b/src/IR/ir.rs @@ -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 { + 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, } @@ -49,6 +81,7 @@ macro_rules! IrTypeWith1 { } IrTypeWith1!(Return, T); +IrTypeWith3!(Add, T, U, Z); use crate::Support::Colorize; @@ -66,6 +99,70 @@ impl Ir for Return { 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 { + fn clone_box(&self) -> Box { + 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 { + fn clone_box(&self) -> Box { + 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 @@ -83,6 +180,41 @@ impl BuildReturn for IRBuilder<'_> { } } +impl BuildReturn 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 { + /// Adds to values + fn BuildAdd(&mut self, op0: T, op1: U) -> Result>; +} + +impl BuildAdd for IRBuilder<'_> { + fn BuildAdd(&mut self, op0: Type, op1: Type) -> Result> { + 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 @@ -90,6 +222,8 @@ pub(crate) trait Ir: Debug { /// 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` fn clone_box(&self) -> Box; } diff --git a/src/IR/mod.rs b/src/IR/mod.rs index 86e2ccf3..c5a512a8 100644 --- a/src/IR/mod.rs +++ b/src/IR/mod.rs @@ -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; \ No newline at end of file +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 {} \ No newline at end of file diff --git a/src/IR/module.rs b/src/IR/module.rs index 5d422fa2..25b29684 100644 --- a/src/IR/module.rs +++ b/src/IR/module.rs @@ -1,4 +1,4 @@ -use super::{func::FunctionType, Function}; +use super::{func::FunctionType, Function, VerifyError}; use std::collections::HashMap; /// ## The Module @@ -60,4 +60,15 @@ impl Module { string } + + /// Verifys if every function is 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 (_, func) in &self.funcs { + func.verify()? + } + + Ok(()) + } } diff --git a/src/IR/var.rs b/src/IR/var.rs new file mode 100644 index 00000000..a1268f16 --- /dev/null +++ b/src/IR/var.rs @@ -0,0 +1,18 @@ +use super::{Block, TypeMetadata}; + +/// A variable +#[derive(Debug, Clone, PartialEq, Eq)] +pub struct Var { + pub(crate) name: String, + pub(crate) ty: TypeMetadata, +} + +impl Var { + /// Creats an new variable + pub fn new(block: &mut Block, ty: TypeMetadata) -> Self { + Self { + name: format!("%{}", block.reqVarName()), + ty: ty, + } + } +} \ No newline at end of file