diff --git a/src/IR/func.rs b/src/IR/func.rs index 844a58b8..4601023a 100644 --- a/src/IR/func.rs +++ b/src/IR/func.rs @@ -131,7 +131,7 @@ impl Function { let mut string = String::new(); - string += &format!("define {} @{}({}) {{\n", self.ty.ret, self.name, { + string += &format!("define {} {} @{}({}) {{\n", self.linkage, self.ty.ret, self.name, { let mut fmt = String::new(); for (name, metadata) in &self.ty.args { @@ -158,8 +158,9 @@ impl Function { /// Emits the Ir of the function into an colored string pub fn dumpColored(&self, profile: ColorProfile) -> String { if self.linkage == Linkage::Extern { - let string = format!("{} {} @{}( {})\n", + let string = format!("{} {} {} @{}( {})\n", profile.markup("declare", ColorClass::Instr), + profile.markup(&format!("{}", self.linkage), ColorClass::Ty), profile.markup(&self.ty.ret.to_string(), ColorClass::Ty), profile.markup(&self.name, ColorClass::Name), { let mut fmt = String::new(); diff --git a/src/IR/parser/mod.rs b/src/IR/parser/mod.rs index ad41c51e..96e22275 100644 --- a/src/IR/parser/mod.rs +++ b/src/IR/parser/mod.rs @@ -7,7 +7,7 @@ use lexer::Loc; use crate::Support::{self, Colorize}; -use super::Module; +use super::{Module, TypeMetadata}; /// Ygen-Ir lexing pub mod lexer; @@ -75,6 +75,42 @@ pub enum IrError { /// A unkown type UnkownType(lexer::Token), + + /// Value defined twice + DefinedTwice { + /// the location + loc: Loc, + /// the name + name: String, + }, + + /// the given return type is different than the expected one from the function type + FuncWrongReturnTyoe { + /// the expected return type + expected: TypeMetadata, + /// the found type + found: TypeMetadata, + /// location + loc: Loc, + }, + + /// unkown thing + Unkown { + /// whats unkown (e.g: block) + what: String, + /// the "thingy"s name + name: String, + /// location + loc: Loc, + }, + + /// an extern function has an body + ExternFunWithBody { + /// the name of the function + name: String, + /// the location + loc: Loc, + } } impl Display for IrError { @@ -187,6 +223,52 @@ impl Display for IrError { fab.to_string() } + + IrError::DefinedTwice { loc, name } => { + let mut fab = Support::Error::new("defined twice", "", "", ""); + + fab.deactivateLocationDisplay(); + + fab.setCodeLine(loc.line_string.to_owned()); + fab.addWhere(format!("{} was defined twice", name), loc.coloumn, loc.length); + + fab.to_string() + } + + IrError::FuncWrongReturnTyoe { expected, found, loc } => { + let mut fab = Support::Error::new("wrong return type", "", "", ""); + + fab.deactivateLocationDisplay(); + + fab.setCodeLine(loc.line_string.to_owned()); + + fab.addWhere(format!("encountered the wrong return type: {found} but expected: {expected}"), loc.coloumn, loc.length); + + fab.to_string() + } + + IrError::Unkown { what, name, loc } => { + let mut fab = Support::Error::new(format!("unkown {what}"), "", "", "col"); + + fab.deactivateLocationDisplay(); + + fab.setCodeLine(loc.line_string.to_owned()); + + fab.addWhere(format!("unkown {what}: {name}"), loc.coloumn, loc.length); + + fab.to_string() + } + + IrError::ExternFunWithBody { name, loc } => { + let mut fab = Support::Error::new("extern function has an body", "", "", ""); + + fab.deactivateLocationDisplay(); + + fab.setCodeLine(loc.line_string.to_owned()); + fab.addWhere(format!("the func {name} is imported and has a body which isn't allowed"), loc.coloumn, loc.length); + + fab.to_string() + } }) } } diff --git a/src/IR/parser/parser.rs b/src/IR/parser/parser.rs index 939fc80a..1d64b2e0 100644 --- a/src/IR/parser/parser.rs +++ b/src/IR/parser/parser.rs @@ -10,8 +10,8 @@ use super::IrError; #[derive(Debug, Clone, Eq)] #[allow(missing_docs)] pub struct IrInstr { - loc: Loc, - inst: Box, + pub(crate) loc: Loc, + pub(crate) inst: Box, } impl PartialEq for IrInstr { @@ -23,8 +23,8 @@ impl PartialEq for IrInstr { #[derive(Debug, Clone, PartialEq, Eq)] #[allow(missing_docs)] pub struct IrBlock { - loc: Loc, - body: Vec, + pub(crate) loc: Loc, + pub(crate) body: Vec, } /// An ir statement @@ -39,6 +39,8 @@ pub enum IrStmt { args: (HashMap, /*unlim args*/bool), body: HashMap, scope: Linkage, + + location: Loc, }, /// a constant Const{ @@ -106,6 +108,7 @@ impl IrParser { self.expect( TokenType::Func(String::new()) )?; let tok = self.current_token()?; + let loc = tok.loc.to_owned(); if let TokenType::Func(func) = &tok.typ { name = func.to_string(); } else { unreachable!() } @@ -160,6 +163,8 @@ impl IrParser { scope: Linkage::Extern, args: (args, unlim), ret: ret, + + location: loc, }) } @@ -168,6 +173,7 @@ impl IrParser { let mut body = HashMap::new(); let mut args = HashMap::new(); + let mut link = Linkage::External; self.expect( TokenType::Define )?; self.input.pop_front(); // advance over define @@ -175,9 +181,23 @@ impl IrParser { let ret = self.parse_type()?; self.input.pop_front(); + let curr = self.current_token()?; + + if let TokenType::Ident(ident) = &curr.typ { + link = match ident.as_str() { + "local" | "internal" | "private" => Linkage::Internal, + _ => Err(IrError::Unkown { + what: "linkage".to_owned(), + name: ident.to_owned(), + loc: curr.loc.clone() + })? + }; + } + self.expect( TokenType::Func(String::new()) )?; let tok = self.current_token()?; + let loc = tok.loc.to_owned(); if let TokenType::Func(func) = &tok.typ { name = func.to_string(); } else { unreachable!() } @@ -237,8 +257,10 @@ impl IrParser { name: name, body: body, args: (args, false), - scope: Linkage::Extern, + scope: link, ret: ret, + + location: loc, }) } diff --git a/src/IR/parser/semnatic.rs b/src/IR/parser/semnatic.rs index 2620e847..94be9fde 100644 --- a/src/IR/parser/semnatic.rs +++ b/src/IR/parser/semnatic.rs @@ -1,10 +1,21 @@ -use super::parser::IrStmt; +use std::collections::HashMap; + +use crate::Obj::Linkage; +use crate::IR::{Const, FnTy, FunctionType, Type, TypeMetadata, Var}; + +use crate::prelude::ir::*; + +use super::parser::{IrStmt, IrBlock}; +use super::lexer::Loc; use super::IrError; /// semantic analaysiz for ir stmts #[derive(Debug, Clone, PartialEq, Eq)] pub struct IrSemnatic<'a> { input: &'a Vec, + + const_sigs: HashMap, + func_sigs: HashMap, } impl<'a> IrSemnatic<'a> { @@ -12,13 +23,135 @@ impl<'a> IrSemnatic<'a> { pub fn new(exprs: &'a Vec) -> Self { Self { input: exprs, + + const_sigs: HashMap::new(), + func_sigs: HashMap::new(), } } /// verifys the input pub fn verify(&mut self) -> Result<(), IrError> { - todo!(); + for stmt in self.input { + match stmt { + IrStmt::Func { name, ret, args, body: _, scope, location } => self.add_func(name, *ret, args, scope, location)?, + IrStmt::Const { name, data: _, location, scope } => self.add_const(name, scope, location)? + } + } + + for stmt in self.input { + match stmt { + IrStmt::Func { name, ret, args, body, scope, location } => self.analizye_func(name, *ret, args, body, *scope, location)?, + IrStmt::Const { name, data, location, scope } => self.analyize_const(name, data, location, *scope)?, + } + } + + Ok(()) + } + + fn add_func(&mut self, name: &String, ret: TypeMetadata, args: &(HashMap, bool), scope: &Linkage, loc: &Loc) -> Result<(), IrError> { + if self.func_sigs.contains_key(name) { + Err(IrError::DefinedTwice { + loc: loc.clone(), + name: name.to_owned() + })? + } + + let mut fun_args = vec![]; + + for (_, arg) in &args.0 { + fun_args.push( *arg ); + } + + let ty = FnTy(fun_args, ret); + + self.func_sigs.insert(name.to_owned(), (ty, *scope)); + + Ok(()) + } + + fn add_const(&mut self, name: &String, scope: &Linkage, loc: &Loc) -> Result<(), IrError> { + if self.func_sigs.contains_key(name) { + Err(IrError::DefinedTwice { + loc: loc.clone(), + name: name.to_owned() + })? + } + + self.const_sigs.insert(name.to_owned(), *scope); + Ok(()) + } + + fn analizye_func(&mut self, name: &String, ret: TypeMetadata, args: &(HashMap, bool), body: &HashMap, scope: Linkage, loc: &Loc) -> Result<(), IrError> { + let mut vars = HashMap::new(); + + let mut blocks = vec![]; + + for (name, ty) in &args.0 { + vars.insert(name.to_owned(), *ty); + } + + if Linkage::Extern == scope && body.len() > 0 { + Err(IrError::ExternFunWithBody { + name: name.to_owned(), + loc: loc.to_owned(), + })? + } + + for (name, block) in body { + if blocks.contains(name) { + Err(IrError::DefinedTwice { + loc: block.loc.to_owned(), + name: name.to_owned() + })? + } + + blocks.push(name.to_owned()); + + for node in &block.body { + let instr = &node.inst; + let loc = node.loc.to_owned(); + + let any = instr.as_any(); + + if let Some(node) = any.downcast_ref::>() { + self.analiyze_ret_int(node, ret, loc)?; + } else if let Some(node) = any.downcast_ref::>() { + self.analiyze_assign_const(node, loc)?; + } + } + } + + Ok(()) + } + + fn analiyze_ret_int(&mut self, node: &Return, fsig: TypeMetadata, loc: Loc) -> Result<(), IrError> { + let ret: TypeMetadata = node.inner1.into(); + + if ret != fsig { + Err(IrError::FuncWrongReturnTyoe { + expected: fsig, + found: ret, + loc: loc, + })? + } + + Ok(()) + } + + fn analiyze_assign_const(&mut self, node: &Assign, loc: Loc) -> Result<(), IrError> { + let name = &node.inner2.name; + if !self.const_sigs.contains_key(name) { + Err(IrError::Unkown { + what: "const".to_owned(), + loc: loc, + name: name.to_owned(), + })? + } + + Ok(()) + } - //Ok(()) + fn analyize_const(&mut self, _: &String, _: &Vec, _: &Loc, _: Linkage) -> Result<(), IrError> { + Ok(()) // what can go wrong on constants? } -} \ No newline at end of file +} \ No newline at end of file diff --git a/src/Obj/wrapper.rs b/src/Obj/wrapper.rs index 43323d8c..2f78f176 100644 --- a/src/Obj/wrapper.rs +++ b/src/Obj/wrapper.rs @@ -9,6 +9,7 @@ use crate::debug::DebugRegistry; use crate::prelude::Triple; use crate::Target::{self, Arch, CallConv}; use std::collections::BTreeMap; +use std::fmt::Display; use std::fs::File; use std::error::Error; @@ -97,6 +98,16 @@ pub enum Linkage { Internal, } +impl Display for Linkage { + fn fmt(&self, f: &mut std::fmt::Formatter<'_>) -> std::fmt::Result { + write!(f, "{}", match self { + Linkage::External => "", + Linkage::Extern => "extern", + Linkage::Internal => "local", + }) + } +} + /// Builds object files. /// It also supports debugging information #[derive(Debug, Clone, PartialEq, Eq)] diff --git a/tools/ylc/main.rs b/tools/ylc/main.rs index 9c4defd6..25e62711 100644 --- a/tools/ylc/main.rs +++ b/tools/ylc/main.rs @@ -109,7 +109,13 @@ fn main() -> Result<(), Box> { println!("{:?}", parser.out); } - IrSemnatic::new(&parser.out).verify()?; + match IrSemnatic::new(&parser.out).verify() { + Ok(_) => {}, + Err(err) => { + println!("{}", err); + exit(-1) + } + } let mut gen = IrGen::new(parser.out);