diff --git a/src/analyser/src/error.rs b/src/analyser/src/error.rs index 160629e..418029b 100644 --- a/src/analyser/src/error.rs +++ b/src/analyser/src/error.rs @@ -33,6 +33,10 @@ pub enum SemanticError { id: usize, message: String, line: usize, + }, + #[error("[Semantic Error] Not Implemented Feature Error: {message:?}")] + NotImplementedFeatureError{ + message: String, }, #[error("System error: {0}")] SystemError(String), diff --git a/src/analyser/src/fmt.rs b/src/analyser/src/fmt.rs index d78d4d8..cd903cd 100644 --- a/src/analyser/src/fmt.rs +++ b/src/analyser/src/fmt.rs @@ -1,5 +1,5 @@ use std::fmt::{Display, Result}; -use crate::symbol::{Symbol, VarType, BasicType, FuncReturnType}; +use crate::symbol::{Symbol, VarType, BasicType}; use crate::table::ScopeTable; use crate::stack::ScopeStack; @@ -34,12 +34,6 @@ impl Display for BasicType { } } -impl Display for FuncReturnType { - fn fmt(&self, f: &mut std::fmt::Formatter) -> Result { - write!(f, "{:?}", self) - } -} - impl Display for ScopeTable { fn fmt(&self, f: &mut std::fmt::Formatter) -> std::fmt::Result { let mut result = String::new(); diff --git a/src/analyser/src/from.rs b/src/analyser/src/from.rs index 7deb2f4..9f9a90a 100644 --- a/src/analyser/src/from.rs +++ b/src/analyser/src/from.rs @@ -4,6 +4,7 @@ use spl_ast::tree::{Value, Variable, CompExpr}; use crate::manager::SymbolManager; use crate::symbol::*; use crate::error::SemanticError; +use crate::typer::FuncRetType; impl From for BasicType { fn from(value: Value) -> BasicType { @@ -17,3 +18,16 @@ impl From for BasicType { } } } + +impl From for FuncRetType { + fn from(basic_type: BasicType) -> FuncRetType { + match basic_type { + BasicType::Int => FuncRetType::Int, + BasicType::Float => FuncRetType::Float, + BasicType::Char => FuncRetType::Char, + BasicType::Bool => FuncRetType::Bool, + BasicType::String => FuncRetType::String, + BasicType::Null => FuncRetType::Void + } + } +} \ No newline at end of file diff --git a/src/analyser/src/impls.rs b/src/analyser/src/impls.rs index d822b4c..e6a0169 100644 --- a/src/analyser/src/impls.rs +++ b/src/analyser/src/impls.rs @@ -23,8 +23,8 @@ impl VarSymbol { manager.new_var_symbol(identifier, VarType::Array((type_t, dimensions)), is_global) } - pub fn struct_type(manager: &mut SymbolManager, identifier: String, fields: (Vec, Vec), is_global: bool) -> VarSymbol { - manager.new_var_symbol(identifier, VarType::Struct(fields), is_global) + pub fn struct_type(manager: &mut SymbolManager, struct_type: String, identifier: String, fields: Vec<(String, VarType)>, is_global: bool) -> VarSymbol { + manager.new_var_symbol(identifier, VarType::Struct((struct_type, fields)), is_global) } pub fn get_primitive(&self) -> Option { @@ -41,31 +41,35 @@ impl VarSymbol { } } - pub fn get_struct_field(&self, field: String) -> Option { + pub fn get_struct_field(&self, field: String) -> Option { match &self.symbol_type { - VarType::Struct((fields, types)) => { - for i in 0..fields.len() { - if fields[i] == field { - return match &types[i] { - VarType::Primitive(t) => Some(*t), - _ => None, - } + VarType::Struct((_ , fields)) => { + for i in fields.iter() { + if i.0 == field { + return Some(i.1.clone()); } } None }, _ => None, } - } + } + + pub fn get_struct_type(&self) -> Option { + match &self.symbol_type { + VarType::Struct((t, _)) => Some(t.clone()), + _ => None, + } + } } // From for FuncSymbol impl FuncSymbol { - fn define(manager: &mut SymbolManager, identifier: String, return_type: FuncReturnType, parameters: Vec) -> FuncSymbol { + fn define(manager: &mut SymbolManager, identifier: String, return_type: BasicType, parameters: Vec) -> FuncSymbol { manager.new_func_symbol(identifier, (return_type, parameters), true) } - fn get_return_type(&self) -> FuncReturnType { + fn get_return_type(&self) -> BasicType { match &self.symbol_type { (t, _) => t.clone(), } diff --git a/src/analyser/src/stack.rs b/src/analyser/src/stack.rs index 061ec06..4576040 100644 --- a/src/analyser/src/stack.rs +++ b/src/analyser/src/stack.rs @@ -1,5 +1,6 @@ use crate::table::ScopeTable; -use crate::symbol::{VarSymbol, FuncSymbol}; +use crate::symbol::{VarSymbol, FuncSymbol, VarType, StructType}; +use std::process::id; use std::rc::Rc; use std::cell::RefCell; use crate::error::SemanticError; @@ -7,6 +8,7 @@ use crate::error::SemanticError; #[derive(Clone, Debug)] pub struct ScopeStack { pub func_scope: Rc>>, + pub struct_scope: Rc>>, pub stack: Vec>>>, depth: usize, } @@ -14,8 +16,9 @@ pub struct ScopeStack { impl ScopeStack { pub fn new() -> Self { let func_scope = Rc::new(RefCell::new(ScopeTable::new())); + let struct_scope = Rc::new(RefCell::new(ScopeTable::new())); let stack = vec![Rc::new(RefCell::new(ScopeTable::new()))]; - ScopeStack { func_scope, stack , depth: 0} + ScopeStack { func_scope, struct_scope, stack , depth: 0} } // Scope Relevant @@ -60,27 +63,46 @@ impl ScopeStack { } } - pub fn update_var_symbol(&self, symbol: VarSymbol) -> Result<(), SemanticError> { - // Update the symbol in the top scope + pub fn get_var_symbol(&self, identifier: &String) -> Result { + // Search for the symbol in the stack from top to bottom for scope in self.stack.iter().rev() { - if let Some(current_symbol) = scope.borrow().lookup(&symbol.identifier) { - let mut current_symbol = current_symbol.clone(); - current_symbol.symbol_type = symbol.symbol_type.clone(); - return Ok(()); + if let Some(symbol) = scope.borrow().lookup(identifier) { + return Ok(symbol.clone()); } } Err(SemanticError::ReferenceError { id: 1, - variable: symbol.identifier.clone(), + variable: identifier.clone(), line: 0, }) } - pub fn get_var_symbol(&self, identifier: &String) -> Result { + pub fn validate_var_symbol(&self, identifier: &String, dim: Vec) -> Result { // Search for the symbol in the stack from top to bottom for scope in self.stack.iter().rev() { if let Some(symbol) = scope.borrow().lookup(identifier) { - return Ok(symbol.clone()); + match &symbol.symbol_type { + VarType::Array((_, dimensions)) => { + if dimensions.len() != dim.len() { + return Err(SemanticError::TypeError { + id: 23, + message: "Dimension Mismatched".to_string(), + line: 0, + }); + } + return Ok(symbol.symbol_type.clone()); + } + _ => { + if dim.len() > 0 { + return Err(SemanticError::TypeError { + id: 10, + message: "Applying indexing operator ([…]) on non-array type variables".to_string(), + line: 0, + }); + } + return Ok(symbol.symbol_type.clone()); + } + } } } Err(SemanticError::ReferenceError { @@ -90,6 +112,32 @@ impl ScopeStack { }) } + // Struct Relevant + pub fn define_struct(&self, struct_type: StructType) -> Result<(), SemanticError> { + let (identifier, _) = struct_type.clone(); + if self.struct_scope.borrow().lookup(&identifier).is_some() { + return Err(SemanticError::RedefinitionError { + id: 15, + variable: identifier.clone(), + line: 0, + }); + }else { + self.struct_scope.borrow_mut().insert(identifier.clone(), struct_type); + Ok(()) + } + } + + pub fn get_struct(&self, type_t: &String) -> Result { + if let Some(struct_type) = self.struct_scope.borrow().lookup(type_t) { + return Ok(struct_type.clone()); + } + Err(SemanticError::ReferenceError { + id: 14, + variable: type_t.clone(), + line: 0, + }) + } + // Function Relevant pub fn define_func_symbol(&self, symbol: FuncSymbol) -> Result<(), SemanticError> { if self.func_scope.borrow().lookup(&symbol.identifier).is_some() { diff --git a/src/analyser/src/symbol.rs b/src/analyser/src/symbol.rs index edcf336..54a3ed6 100644 --- a/src/analyser/src/symbol.rs +++ b/src/analyser/src/symbol.rs @@ -21,9 +21,10 @@ pub type FuncSymbol = Symbol; - Array Type `(Vec, Vec)` - Struct Type `(Vec)` - Function Type `FuncType` - - `(FuncReturnType, Vec)` + - `(BasicType, Vec)` Different Symbols are stored in different Symbol Tables. */ + #[derive(Clone, Debug)] pub enum VarType { Primitive(PrimType), @@ -33,8 +34,8 @@ pub enum VarType { pub type PrimType = (BasicType); pub type ArrayType = (BasicType, Vec); -pub type StructType = (Vec, Vec); -pub type FuncType = (FuncReturnType, Vec); +pub type StructType = (String, Vec<(String, VarType)>); +pub type FuncType = (BasicType, Vec); #[derive(Clone, Copy, Debug, PartialEq, Eq, PartialOrd, Ord)] pub enum BasicType { @@ -44,15 +45,4 @@ pub enum BasicType { Bool, String, Null -} - -#[derive(Clone, Copy, Debug, PartialEq, Eq, Default)] -pub enum FuncReturnType { - Int, - Char, - Float, - Bool, - String, - #[default] - Void } \ No newline at end of file diff --git a/src/analyser/src/typer.rs b/src/analyser/src/typer.rs index f1bd015..06fe104 100644 --- a/src/analyser/src/typer.rs +++ b/src/analyser/src/typer.rs @@ -1,11 +1,154 @@ +use crate::{error::SemanticError, symbol::{VarType, BasicType}}; + + pub struct TypeChecker{ - + pub current_scope: ScopeType, + pub current_type: BasicType, + pub func_ret_type: FuncRetType } impl TypeChecker { pub fn new() -> Self { - TypeChecker{} + TypeChecker{ + current_scope: ScopeType::Global, + current_type: BasicType::Null, + func_ret_type: FuncRetType::Null + } + } + pub fn check_binary_operations(&self, ltype: BasicType, rtype: BasicType) -> Result { + if ltype == rtype { + return Ok(ltype); + } else { + return Err(SemanticError::ImproperUsageError { + id: 0, + message: "Type mismatch".to_string(), + line: 0, + }); + } + } + + pub fn check_var_type(&self, var: VarType) -> Result { + match var { + VarType::Primitive(t) => Ok(t), + VarType::Array((t, _)) => Ok(t), + VarType::Struct(_) => Err(SemanticError::ImproperUsageError{ + id: 22, + message: "Invalid use of struct in computation expression".to_owned(), + line: 0 + }), + } + + } + + pub fn check_condition(&self, ltype: BasicType, rtype: BasicType) -> Result{ + match (ltype, rtype) { + (BasicType::Int, BasicType::Int) => { + Ok(BasicType::Bool) + } + (BasicType::Float, BasicType::Float) => { + Ok(BasicType::Bool) + } + _ => { + Err(SemanticError::TypeError{ + id: 7, + message: "Unmatched operands, such as adding an integer to a structure variable".to_owned(), + line: 0 + }) + } + } + } + + pub fn check_binary_condition(&self, ltype: BasicType, rtype: BasicType) -> Result{ + match (ltype, rtype) { + (BasicType::Bool, BasicType::Bool) => { + Ok(BasicType::Bool) + } + _ => { + Err(SemanticError::TypeError{ + id: 7, + message: "Unmatched operands, such as adding an integer to a structure variable".to_owned(), + line: 0 + }) + } + } } - pub fn check(&self) { + + pub fn check_ret_type(&self, type_t: BasicType) -> Result<(), SemanticError>{ + if FuncRetType::from(type_t) == self.func_ret_type { + Ok(()) + } else { + Err(SemanticError::TypeError{ + id: 8, + message: "A function’s return value type mismatches the declared type".to_string(), + line: 0 + }) + } } + + pub fn check_func_params(&self, params: Vec, args: Vec) -> Result<(), SemanticError>{ + if params.len() != args.len() { + return Err(SemanticError::TypeError{ + id: 9, + message: "The number of arguments passed to a function does not match the number of parameters in the function definition".to_string(), + line: 0 + }); + } + for i in 0..params.len() { + if params[i] != args[i] { + return Err(SemanticError::TypeError{ + id: 10, + message: "The type of an argument passed to a function does not match the type of the corresponding parameter in the function definition".to_string(), + line: 0 + }); + } + } + Ok(()) + } + + pub fn set_scope(&mut self, scope: ScopeType) -> ScopeType { + let prev_scope = self.current_scope.clone(); + self.current_scope = scope; + prev_scope + } + + pub fn get_scope(&self) -> ScopeType { + self.current_scope.clone() + } + + pub fn set_type(&mut self, t: BasicType) { + self.current_type = t; + } + + pub fn set_ret_type(&mut self, t: BasicType){ + match t { + BasicType::Int => self.func_ret_type = FuncRetType::Int, + BasicType::Float => self.func_ret_type = FuncRetType::Float, + BasicType::Char => self.func_ret_type = FuncRetType::Char, + BasicType::Bool => self.func_ret_type = FuncRetType::Bool, + BasicType::Null => self.func_ret_type = FuncRetType::Void, + BasicType::String => self.func_ret_type = FuncRetType::String, + } + } + + pub fn reset_ret_type(&mut self){ + self.func_ret_type = FuncRetType::Null + } +} + +#[derive(Clone, PartialEq, Eq, Debug)] +pub enum ScopeType { + Global, + Func, + LoopExpr +} + +#[derive(Clone, PartialEq, Eq, Debug)] +pub enum FuncRetType { + Int, + Char, + Float, + Bool, + String, + Void, + Null } \ No newline at end of file diff --git a/src/analyser/src/walker.rs b/src/analyser/src/walker.rs index d7d6e3a..89348c6 100644 --- a/src/analyser/src/walker.rs +++ b/src/analyser/src/walker.rs @@ -1,17 +1,15 @@ -use std::thread::Scope; - use spl_ast::tree::*; use crate::manager::SymbolManager; -use crate::error::SemanticError; +use crate::error::{SemanticError, SemanticErrorManager}; use crate::symbol::*; use crate::stack::ScopeStack; -use crate::typer::TypeChecker; +use crate::typer::{TypeChecker, ScopeType}; pub struct Walker { pub program: Program, pub symbol_tables: ScopeStack, pub manager: SymbolManager, - pub errors: Vec, + pub errors: SemanticErrorManager, pub typer: TypeChecker } @@ -20,7 +18,7 @@ impl Walker { Walker { program: program, manager: manager, - errors: Vec::new(), + errors: SemanticErrorManager::new(), symbol_tables: ScopeStack::new(), typer: TypeChecker::new() } @@ -30,8 +28,8 @@ impl Walker { self.symbol_tables.clone() } - pub fn get_errors(&self) -> Vec { - self.errors.clone() + pub fn get_errors(&self) -> &Vec { + self.errors.get_errors() } pub fn traverse(&mut self) { @@ -39,7 +37,6 @@ impl Walker { self.traverse_program(&program_clone); } - fn traverse_program(&mut self, program: &Program) { match program { Program::Program(parts) => { @@ -88,80 +85,229 @@ impl Walker { match variable { Variable::VarReference(name, dimensions) => { println!("VarReference: {:?}, Dimensions: {:?}", name, dimensions); - match self.symbol_tables.get_var_symbol(name) { - Ok(symbol) => { - return Some(symbol.symbol_type.clone()); - } - Err(err) => { - self.errors.push(err); - return None; - } + let dim = dimensions.iter() + .map(|comp_expr| { + if let Some(BasicType::Int) = self.traverse_comp_expr(comp_expr) { + Ok(0_usize) + } else { + Err(SemanticError::ImproperUsageError { + id: 12, + message: "Array indexing with a non-integer type expression".to_owned(), + line: 0, + }) + } + }) + .collect::, _>>() + .map_err(|err| { + self.errors.add_error(err); + }); + + match dim { + Ok(dim) => match self.symbol_tables.validate_var_symbol(name, dim) { + Ok(t) => Some(t), + Err(err) => { + self.errors.add_error(err); + None + } + }, + Err(_) => None, } } Variable::VarDeclaration(name, values, dimensions) => { println!("VarDeclaration: {:?}, Values: {:?}, Dimensions: {:?}", name, values, dimensions); // Validate all dimensions and collect them - let mut dim = Vec::new(); - for comp_expr in *dimensions.clone() { - match comp_expr { - CompExpr::Value(value) => match value { - Value::Integer(i) => dim.push(i as usize), - _ => { - // Return an error if any dimension is not an integer - self.errors.push(SemanticError::TypeError { - id: 18, - message: "Reference for array does not conform to Int type.".to_owned(), - line: 0 - }); - } - }, - _ => { - // Return an error for invalid dimension types - self.errors.push(SemanticError::TypeError { - id: 18, - message: "Reference for array does not conform to Int type.".to_owned(), - line: 0 - }); + let dim = dimensions.iter() + .map(|comp_expr| { + if let Some(BasicType::Int) = self.traverse_comp_expr(comp_expr) { + Ok(0_usize) + } else { + Err(SemanticError::ImproperUsageError { + id: 12, + message: "Array indexing with a non-integer type expression".to_owned(), + line: 0, + }) + } + }) + .collect::, _>>() + .map_err(|err| { + self.errors.add_error(err); + }); + + let symbol_type = BasicType::from(*values.clone()); + let var_type: Option = match dim { + Ok(dim) => { + if dim.len() > 0 { + Some(VarType::Array((symbol_type, dim))) + } else { + Some(VarType::Primitive(symbol_type)) } } - } + Err(_) => None + }; + let new_symbol = self.manager.new_var_symbol( *name.clone(), - VarType::Primitive(BasicType::from(*values.clone())), - true + var_type.clone().unwrap(), + false, ); + match self.symbol_tables.define_var_symbol(new_symbol) { - Ok(()) => { - return Some(VarType::Primitive(BasicType::from(*values.clone()))); - } + Ok(()) => Some(var_type.unwrap()), Err(err) => { - self.errors.push(err); - return None; + self.errors.add_error(err); + None } } } Variable::VarAssignment(name, value, dimensions) => { println!("VarAssignment: {:?}, Value: {:?}, Dimensions: {:?}", name, value, dimensions); - return None; + let dim = dimensions.iter() + .map(|comp_expr| { + if let Some(BasicType::Int) = self.traverse_comp_expr(comp_expr) { + Ok(0_usize) + } else { + Err(SemanticError::ImproperUsageError { + id: 12, + message: "Array indexing with a non-integer type expression".to_owned(), + line: 0, + }) + } + }) + .collect::, _>>() + .map_err(|err| { + self.errors.add_error(err); + }); + + match dim { + Ok(dim) => match self.symbol_tables.validate_var_symbol(name, dim) { + Ok(t) => Some(t), + Err(err) => { + self.errors.add_error(err); + None + } + }, + Err(_) => None, + } + } + Variable::StructReference(name) => { println!("StructReference: {:?}", name); return None; } + // Define in the global scope Variable::StructDefinition(name, variables) => { - return None; + println!("StructDefinition: {:?}", name); + let mut vars: Vec<(String, VarType)> = Vec::new(); + for var in *variables.clone() { + if let Some(var_type) = self.traverse_struct_field(&var) { + vars.push(var_type); + } + } + match self.symbol_tables.define_struct((*name.clone(), vars)) { + Ok(()) => { + return None; + } + Err(err) => { + self.errors.add_error(err); + return None; + } + } } + // Define a variable + // First check if the struct exists + // Then check if the variable is valid Variable::StructDeclaration(obj_type, name, variables) => { - return None; + match self.symbol_tables.get_struct(obj_type) { + Ok(struct_type) => { + let new_symbol = self.manager.new_var_symbol( + *name.clone(), + VarType::Struct(struct_type.clone()), + false, + ); + match self.symbol_tables.define_var_symbol(new_symbol) { + Ok(()) => Some(VarType::Struct(struct_type.clone())), + Err(err) => { + self.errors.add_error(err); + None + } + }} + Err(err) => { + self.errors.add_error(err); + None + } + } } + // Define a variable + // First check if the struct exists + // Then check if the variable is valid Variable::StructAssignment(name, field, value) => { - return None; + let var = self.symbol_tables.get_var_symbol(name).map_err(|err| { + self.errors.add_error(err); + }).ok()?; + + let fields = if let VarType::Struct((_, fields)) = var.symbol_type { + fields + } else { + self.errors.add_error(SemanticError::ImproperUsageError { + id: 13, + message: "Accessing members of a non-structure variable (i.e., misuse the dot operator)".to_owned(), + line: 0, + }); + return None; + }; + + let basic_type = self.traverse_comp_expr(&**value)?; + fields.iter() + .find(|(field_name, _)| field_name == &*field.clone()) + .and_then(|(_, field_type)| { + match self.typer.check_var_type(field_type.clone()) { + Ok(vartype) if basic_type == vartype => Some(field_type.clone()), + Ok(_) => None, + Err(err) => { + self.errors.add_error(SemanticError::NotImplementedFeatureError { + message: "Not supported assignment to struct field".to_owned() + }); + None + } + } + }) } Variable::MemberReference(name, field) => { - return None; + match self.symbol_tables.get_var_symbol(name) { + Ok(var) => { + if let VarType::Struct((struct_name, fields)) = var.symbol_type { + fields + .iter() + .find(|(field_name, _)| field_name == &*field.clone()) + .map(|(_, field_type)| field_type.clone()) + } else { + self.errors.add_error(SemanticError::ImproperUsageError { + id: 13, + message: "Accessing members of a non-structure variable (i.e., misuse the dot operator)".to_owned(), + line: 0, + }); + None + } + } + Err(err) => { + self.errors.add_error(err); + None + } + } }, + Variable::FormalParameter(name, values, dimensions) => { - return None; + println!("FormalParameter: {:?}, Values: {:?}, Dimensions: {:?}", name, values, dimensions); + let symbol_type = BasicType::from(*values.clone()); + let var_type = |dimensions: &[usize]| -> VarType { + if !dimensions.is_empty() { + VarType::Array((symbol_type.clone(), dimensions.to_vec())) + } else { + VarType::Primitive(symbol_type.clone()) + } + }; + return Some(var_type(&dimensions)); } Variable::Error => { return None; @@ -169,19 +315,140 @@ impl Walker { } } - fn traverse_function(&mut self, function: &Function) { + fn traverse_struct_field(&mut self, field: &Variable) -> Option<(String, VarType)> { + let mut vars: Vec<(String, VarType)> = Vec::new(); + match field { + Variable::VarDeclaration(varname, type_t, offsets) => { + let dim = offsets.iter() + .map(|comp_expr| { + if let Some(BasicType::Int) = self.traverse_comp_expr(comp_expr) { + Ok(0_usize) + } else { + Err(SemanticError::ImproperUsageError { + id: 12, + message: "Array indexing with a non-integer type expression".to_owned(), + line: 0, + }) + } + }) + .collect::, _>>() + .map_err(|err| { + self.errors.add_error(err); + }); + + let symbol_type = BasicType::from(*type_t.clone()); + let var: Option<(String, VarType)> = match dim { + Ok(dim) => { + if dim.len() > 0 { + Some((*varname.clone(), VarType::Array((symbol_type, dim)))) + } else { + Some((*varname.clone(), VarType::Primitive(symbol_type))) + } + } + Err(_) => None + }; + var + } + Variable::StructDeclaration(type_t, identifier, variables) => { + match self.symbol_tables.get_struct(type_t) { + Ok(struct_type) => { + let mut fields: Vec<(String, VarType)> = Vec::new(); + Some((*identifier.clone(), VarType::Struct((*type_t.clone(), fields)))) + } + Err(err) => { + self.errors.add_error(err); + None + } + } + } + Variable::VarAssignment(_, _, _) => { + self.errors.add_error(SemanticError::ImproperUsageError { + id: 24, + message: "Struct field assignment is not allowed".to_owned(), + line: 0, + }); + None + } + _ => { + None + } + } + } + + fn traverse_function(&mut self, function: &Function) -> Option{ match function { Function::FuncReference(name, params) => { println!("FuncReference: {:?}, Params: {:?}", name, params); + let mut args: Vec = Vec::new(); + for param in params { + if let Some(arg) = self.traverse_comp_expr(param) { + args.push(arg); + } + } + let mut params: Vec = Vec::new(); + let mut return_type: FuncType = (BasicType::Null, Vec::new()); + match self.symbol_tables.get_func_symbol(name) { + Ok(func_symbol) =>{ + func_symbol.symbol_type.1.iter().for_each( + |t| { + match t { + VarType::Primitive(basic_t) => { + params.push(*basic_t); + } + VarType::Array((basic_t, _)) => { + params.push(*basic_t); + } + VarType::Struct((_, _)) => { + self.errors.add_error(SemanticError::NotImplementedFeatureError { + message: "No struct type as function parameter".to_owned(), + }); + } + } + } + ); + return_type = func_symbol.symbol_type; + } + Err(err) => { + self.errors.add_error(err); + } + } + match self.typer.check_func_params(params, args) { + Ok(()) => { + return Some(return_type); + } + Err(err) => { + self.errors.add_error(err); + return None; + } + } } Function::FuncDeclaration(name, inputs, output, body) => { + self.typer.set_ret_type(BasicType::from(*output.clone())); println!("FuncDeclaration: {:?}, Output: {:?}", name, output); - for input in inputs.iter() { - self.traverse_variable(input); + self.symbol_tables.extend_scope(); + + let ret_type: BasicType = BasicType::from(*output.clone()); + let mut params: Vec = Vec::new(); + for param in inputs { + if let Some(var_type) = self.traverse_variable(param) { + params.push(var_type); + } } + self.manager.new_func_symbol(*name.clone(), (ret_type, params), true); + self.traverse_body(body); + match self.symbol_tables.exit_scope() { + Ok(()) => {} + Err(err) => { + self.errors.add_error(err) + } + } + self.typer.reset_ret_type(); + return None; + } + Function::Error => { + return None; } - Function::Error => println!("Error in Function"), } } @@ -193,12 +460,12 @@ impl Walker { for expr in exprs { self.traverse_expr(expr); } - // match self.symbol_tables.exit_scope() { - // Ok(()) => {} - // Err(err) => { - // self.errors.push(err) - // } - // } + match self.symbol_tables.exit_scope() { + Ok(()) => {} + Err(err) => { + self.errors.add_error(err) + } + } } Body::Error => println!("Error in Body"), } @@ -224,11 +491,36 @@ impl Walker { println!("Function Call"); self.traverse_function(function); } - Expr::Break => println!("Break"), - Expr::Continue => println!("Continue"), + Expr::Break => { + println!("Break"); + if self.typer.get_scope() != ScopeType::LoopExpr{ + self.errors.add_error(SemanticError::ImproperUsageError { + id: 17, + message: "Continue and break should only appear in while loop or for loop".to_owned(), + line: 0 + }); + } + }, + Expr::Continue => { + println!("Continue"); + if self.typer.get_scope() != ScopeType::LoopExpr{ + self.errors.add_error(SemanticError::ImproperUsageError { + id: 17, + message: "Continue and break should only appear in while loop or for loop".to_owned(), + line: 0 + }); + } + }, Expr::Return(comp_expr) => { println!("Return"); - self.traverse_comp_expr(comp_expr); + match self.traverse_comp_expr(comp_expr) { + Some(t) => { + if let Err(err) = self.typer.check_ret_type(t) { + self.errors.add_error(err); + } + } + None => {} + } } Expr::Body(body) => { println!("Body"); @@ -260,62 +552,148 @@ impl Walker { Loop::WhileExpr(cond, body) => { println!("WhileExpr"); self.traverse_cond_expr(cond); + + let prev_scope = self.typer.set_scope(ScopeType::LoopExpr); self.traverse_body(body); + self.typer.set_scope(prev_scope); } Loop::ForExpr(init, cond, increment, body) => { println!("ForExpr"); self.traverse_expr(init); self.traverse_cond_expr(cond); self.traverse_expr(increment); + + let prev_scope = self.typer.set_scope(ScopeType::LoopExpr); self.traverse_body(body); + self.typer.set_scope(prev_scope); } Loop::Error => println!("Error in Loop"), } } - fn traverse_cond_expr(&mut self, cond: &CondExpr) { + fn traverse_cond_expr(&mut self, cond: &CondExpr) -> Option { match cond { - CondExpr::Bool(value) => println!("Bool Condition: {:?}", value), + CondExpr::Bool(value) => { + return Some(BasicType::Bool) + }, CondExpr::UnaryCondition(op, expr) => { println!("UnaryCondition: {:?}", op); - self.traverse_cond_expr(expr); + match self.traverse_cond_expr(expr) { + Some(t) => { + return Some(t); + } + None => { + return None; + } + } } CondExpr::BinaryCondition(lhs, op, rhs) => { println!("BinaryCondition: {:?} {:?} {:?}", lhs, op, rhs); - self.traverse_cond_expr(lhs); - self.traverse_cond_expr(rhs); + if let Some(lhs_type) = self.traverse_cond_expr(lhs) { + if let Some(rhs_type) = self.traverse_cond_expr(rhs) { + match self.typer.check_binary_condition(lhs_type, rhs_type) { + Ok(t) => { + return Some(t); + } + Err(err) => { + self.errors.add_error(err); + return None; + } + } + } + } + return None; } CondExpr::Condition(lhs, op, rhs) => { println!("Condition: {:?} {:?} {:?}", lhs, op, rhs); - self.traverse_comp_expr(lhs); - self.traverse_comp_expr(rhs); + if let Some(lhs_type) = self.traverse_comp_expr(lhs) { + if let Some(rhs_type) = self.traverse_comp_expr(rhs) { + match self.typer.check_condition(lhs_type, rhs_type) { + Ok(t) => { + return Some(t); + } + Err(err) => { + self.errors.add_error(err); + return None; + } + } + } + } + return None; } - CondExpr::Error => println!("Error in Condition Expression"), + CondExpr::Error => { + return None; + }, } } - fn traverse_comp_expr(&mut self, comp: &CompExpr) { + fn traverse_comp_expr(&mut self, comp: &CompExpr) -> Option { match comp { - CompExpr::Value(value) => println!("Value: {:?}", value), + CompExpr::Value(value) => { + println!("Value: {:?}", value); + return Some(BasicType::from(value.clone())); + }, CompExpr::Variable(variable) => { - println!("Variable"); - self.traverse_variable(variable); + println!("Variable: {:?}", variable); + if let Some(var_type) = self.traverse_variable(variable) { + match self.typer.check_var_type(var_type) { + Ok(t) => { + return Some(t); + } + Err(err) => { + self.errors.add_error(err); + return None; + } + } + } else { + return None; + } } CompExpr::FuncCall(function) => { println!("Function Call"); - self.traverse_function(function); + match self.traverse_function(function) { + Some((return_type, _)) => { + return Some(return_type); + } + None => { + return None; + } + } } CompExpr::UnaryOperation(op, expr) => { println!("UnaryOperation: {:?}", op); - self.traverse_comp_expr(expr); + match self.traverse_comp_expr(expr) { + Some(t) => { + return Some(t); + } + None => { + return None; + } + } } CompExpr::BinaryOperation(lhs, op, rhs) => { println!("BinaryOperation: {:?} {:?} {:?}", lhs, op, rhs); - self.traverse_comp_expr(lhs); - self.traverse_comp_expr(rhs); + if let Some(lhs_type) = self.traverse_comp_expr(lhs) { + if let Some(rhs_type) = self.traverse_comp_expr(rhs) { + match self.typer.check_binary_operations(lhs_type, rhs_type) { + Ok(t) => { + return Some(t); + } + Err(err) => { + self.errors.add_error(err); + return None; + } + } + } + } + return None; + } + CompExpr::Error => { + return None; + } + CompExpr::Invalid => { + return None; } - CompExpr::Error => println!("Error in Computation Expression."), - CompExpr::Invalid => println!("Invlaid Computation Expression.") } }