diff --git a/src/ast/expr.rs b/src/ast/expr.rs index 3a56424..c0b8afc 100644 --- a/src/ast/expr.rs +++ b/src/ast/expr.rs @@ -23,7 +23,13 @@ pub struct WidenExpr { #[derive(Clone, Debug)] pub struct IdentExpr { + #[deprecated] pub symtbl_pos: usize, // position in the symbol table + + /// Name of the symbol + pub sym_name: String, + + /// Result type of the symbol pub result_type: LitTypeVariant } @@ -42,7 +48,9 @@ pub struct SubscriptExpr { #[derive(Clone, Debug)] pub struct FuncCallExpr { - pub symtbl_pos: usize, // position of the function being called in the symbol table, + /// Name of the called function + pub symbol_name: String, + pub result_type: LitTypeVariant, // function return type // args pub args: Vec diff --git a/src/ast/stmt.rs b/src/ast/stmt.rs index 00aa509..1d73313 100644 --- a/src/ast/stmt.rs +++ b/src/ast/stmt.rs @@ -15,24 +15,40 @@ pub struct ReturnStmt { #[derive(Clone, Debug)] pub struct VarDeclStmt { pub symtbl_pos: usize, // position of this symbol in the symbol table + + /// Name of the symbol + pub sym_name: String, + pub class: StorageClass } #[derive(Clone, Debug)] pub struct ArrVarDeclStmt { pub symtbl_pos: usize, + + /// Name of the symbol + pub sym_name: String, + pub class: StorageClass, pub vals: Vec } #[derive(Clone, Debug)] pub struct AssignStmt { - pub symtbl_pos: usize + #[deprecated] + pub symtbl_pos: usize, + + /// Name of the symbol + pub sym_name: String } #[derive(Clone, Debug)] pub struct FuncCallStmt { + #[deprecated] pub symtbl_pos: usize, + + pub symbol_name: String, + pub args: Vec } @@ -50,5 +66,8 @@ pub enum Stmt { Assignment(AssignStmt), VarDecl(VarDeclStmt), LValue(usize), // usize for symbol table position of this left value + LValue2 { + name: String + }, FuncCall(FuncCallStmt), } \ No newline at end of file diff --git a/src/code_gen/aarch64/aarch64_codegen.rs b/src/code_gen/aarch64/aarch64_codegen.rs index 0e579cd..8a84c81 100644 --- a/src/code_gen/aarch64/aarch64_codegen.rs +++ b/src/code_gen/aarch64/aarch64_codegen.rs @@ -206,7 +206,7 @@ impl<'aarch64> CodeGen for Aarch64CodeGen<'aarch64> { }; let func_name: String = if let Some(ctx_rc) = &mut self.ctx { - let ctx_borrow: std::cell::Ref> = ctx_rc.borrow(); + let ctx_borrow = ctx_rc.borrow(); let func_name: String = ctx_borrow.sym_table.get_symbol(index).unwrap().name.clone(); if let Some(finfo) = ctx_borrow.func_table.get(&func_name) { self.current_function = Some(finfo.clone()); @@ -219,6 +219,7 @@ impl<'aarch64> CodeGen for Aarch64CodeGen<'aarch64> { }; let func_info: FunctionInfo = self.current_function.as_ref().cloned().unwrap(); + self.ctx.as_ref().unwrap().borrow_mut().switch_to_func_scope(func_info.func_id); // If the function is declared as extern, print its external linkage // declaration and return a placeholder value indicating an unresolved @@ -250,7 +251,7 @@ impl<'aarch64> CodeGen for Aarch64CodeGen<'aarch64> { } if let Some(ref body) = ast.left { - _ = self.gen_code_from_ast(body, 0xFFFFFFFF, ast.operation)?; + self.gen_code_from_ast(body, 0xFFFFFFFF, ast.operation)?; if self.early_return_label_id != NO_REG { println!("_L{}:", self.early_return_label_id); self.early_return_label_id = NO_REG; // reset early return label after function code generation @@ -258,6 +259,7 @@ impl<'aarch64> CodeGen for Aarch64CodeGen<'aarch64> { } self.current_function = None; + self.ctx.as_ref().unwrap().borrow_mut().switch_to_global_scope(); // ldp -> Load Pair of Registers // Restore the saved frame pointer (x29) and link register (x30) from the stack. @@ -490,38 +492,6 @@ impl<'aarch64> CodeGen for Aarch64CodeGen<'aarch64> { self.reg_manager.borrow_mut() } - fn gen_func_call_stmt(&mut self, func_call_stmt: &FuncCallStmt) -> CodeGenResult { - let func_info: FunctionInfo = if let Some(ctx_rc) = &self.ctx { - let ctx_borrow = ctx_rc.borrow(); - if let Some(symbol) = ctx_borrow.sym_table.get_symbol(func_call_stmt.symtbl_pos) { - if let Some(func_info) = ctx_borrow.func_table.get(&symbol.name) { - func_info.clone() - } else { - panic!("function info not found"); - } - } else { - panic!("undefined symbol"); - } - } else { - return Err(CodeGenErr::NoContext); - }; - // Assign the function id whenever generating code for function - self.function_id = func_info.func_id; - let args: &Vec = &func_call_stmt.args; - let mut used_regs: Vec = Vec::::new(); - for expr in args { - let used_reg: AllocedReg = self.gen_expr(expr, ASTOperation::AST_FUNC_CALL, 0xFFFFFFFF, ASTOperation::AST_NONE)?; - used_regs.push(used_reg); - } - let mut _reg_mgr = self.reg_manager.borrow_mut(); - for ar in used_regs { - _reg_mgr.deallocate(ar.idx, &ar.lit_type()); - } - println!("bl _{}", func_info.name); - self.function_id = 0xFFFFFFFF; - Ok(AllocedReg::no_reg()) - } - fn gen_local_var_decl_stmt(&mut self, var_decl_stmt: &crate::ast::VarDeclStmt, expr_ast: &Expr) -> CodeGenResult { if self.current_function.is_none() { panic!("Parsing a local variable but function is not defined... Weird."); @@ -572,7 +542,7 @@ impl<'aarch64> CodeGen for Aarch64CodeGen<'aarch64> { fn gen_func_call_expr(&mut self, func_call_expr: &crate::ast::FuncCallExpr) -> CodeGenResult { let func_info_res: Option = if let Some(ctx_rc) = &self.ctx { let ctx_borrow = ctx_rc.borrow_mut(); - if let Some(symbol) = ctx_borrow.sym_table.get_symbol(func_call_expr.symtbl_pos) { + if let Ok(symbol) = ctx_borrow.find_sym(&func_call_expr.symbol_name) { ctx_borrow.func_table.get(&symbol.name).cloned() } else { None @@ -765,7 +735,6 @@ impl<'aarch64> Aarch64CodeGen<'aarch64> { } fn __allocate_reg(&mut self, val_type: &LitTypeVariant) -> AllocedReg { - println!("{:?}", val_type); let alloced_reg: RegAllocResult = self.reg_manager.borrow_mut().allocate(val_type); if alloced_reg.is_err() { panic!("Couldn't allocate register"); diff --git a/src/code_gen/cg_error.rs b/src/code_gen/cg_error.rs index 0f828e9..25984c3 100644 --- a/src/code_gen/cg_error.rs +++ b/src/code_gen/cg_error.rs @@ -1,3 +1,4 @@ +#[derive(Debug)] pub enum CodeGenErr { NoContext, UndefinedSymbol diff --git a/src/code_gen/codegen.rs b/src/code_gen/codegen.rs index b49542b..6795e79 100644 --- a/src/code_gen/codegen.rs +++ b/src/code_gen/codegen.rs @@ -30,7 +30,6 @@ use crate::ast::AssignStmt; use crate::ast::BinExpr; use crate::ast::Expr; use crate::ast::FuncCallExpr; -use crate::ast::FuncCallStmt; use crate::ast::LitValExpr; use crate::ast::Stmt; use crate::ast::VarDeclStmt; @@ -135,28 +134,15 @@ pub trait CodeGen { } else if ast_node.operation == ASTOperation::AST_GLUE { if let Some(left) = ast_node.left.as_ref() { - _ = self.gen_code_from_ast(left, reg, parent_ast_kind); + self.gen_code_from_ast(left, reg, parent_ast_kind)?; self.reg_manager().deallocate_all(); } if let Some(right) = ast_node.right.as_ref() { - _ = self.gen_code_from_ast(right, reg, parent_ast_kind); + self.gen_code_from_ast(right, reg, parent_ast_kind)?; self.reg_manager().deallocate_all(); } Ok(AllocedReg::no_reg()) } - else if ast_node.operation == ASTOperation::AST_FUNC_CALL { - if ast_node.result_type == LitTypeVariant::Void { - if let ASTKind::StmtAST(func_call_stmt) = &ast_node.kind { - match func_call_stmt { - Stmt::FuncCall(func_call) => { - return self.gen_func_call_stmt(func_call); - }, - _ => return Ok(AllocedReg::no_reg()) - } - } - } - Ok(AllocedReg::no_reg()) - } else if ast_node.operation == ASTOperation::AST_RETURN { let early_return = parent_ast_kind != ASTOperation::AST_FUNCTION; let possible_ret_stmt: Stmt = ast_node.kind.clone().unwrap_stmt(); @@ -259,7 +245,10 @@ pub trait CodeGen { crate::ast::ASTKind::Empty => Ok(AllocedReg::no_reg()) } }, - Expr::FuncCall(func_call) => self.gen_func_call_expr(func_call), + Expr::FuncCall(func_call) => { + println!("{:?}", expr); + self.gen_func_call_expr(func_call) + }, _ => Ok(AllocedReg::no_reg()) } } @@ -372,8 +361,6 @@ pub trait CodeGen { fn gen_return_stmt(&mut self, early_return: bool) -> CodeGenResult; - fn gen_func_call_stmt(&mut self, func_call_stmt: &FuncCallStmt) -> CodeGenResult; - fn gen_func_call_expr(&mut self, func_call_expr: &FuncCallExpr) -> CodeGenResult; fn gen_local_var_decl_stmt(&mut self, var_decl_stmt: &VarDeclStmt, expr_ast: &Expr) -> CodeGenResult; diff --git a/src/code_gen/reg/register.rs b/src/code_gen/reg/register.rs index cb04cb4..b68e5b2 100644 --- a/src/code_gen/reg/register.rs +++ b/src/code_gen/reg/register.rs @@ -34,6 +34,7 @@ pub type RegIdx = usize; pub const INVALID_REG_IDX: usize = 0xFFFFFFFF; +#[derive(Debug)] pub struct AllocedReg { pub size: RegSize, pub idx: RegIdx diff --git a/src/context/compiler_ctx.rs b/src/context/compiler_ctx.rs index 4d49610..bfb5f5d 100644 --- a/src/context/compiler_ctx.rs +++ b/src/context/compiler_ctx.rs @@ -22,7 +22,22 @@ OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE SOFTWARE. */ -use crate::{ast::SourceFile, FunctionInfoTable, Symbol, Symtable}; +use crate::{ + ast::SourceFile, + FunctionInfo, + FunctionInfoTable, + Symbol, + Symtable, + INVALID_FUNC_ID +}; + +use super::CtxError; + +#[derive(Debug, Eq, PartialEq)] +pub enum CompilerScope { + GLOBAL, + FUNCTION +} #[derive(Debug)] pub struct CompilerCtx<'ctx> { @@ -38,6 +53,10 @@ pub struct CompilerCtx<'ctx> { /// Source file that is currently being processed. pub current_file: Option<&'ctx SourceFile>, + + pub current_function: usize, + + pub scope: CompilerScope } impl<'ctx> CompilerCtx<'ctx> { @@ -47,10 +66,85 @@ impl<'ctx> CompilerCtx<'ctx> { func_table, label_id: 0, current_file: None, + current_function: INVALID_FUNC_ID, + scope: CompilerScope::GLOBAL } } pub fn incr_label_count(&mut self) { self.label_id += 1; } -} + + pub fn get_curr_func(&self) -> Option<&FunctionInfo> { + if let Some(symbol) = self.sym_table.get_symbol(self.current_function) { + if let Some(func_info) = self.func_table.get(&symbol.name) { + return Some(func_info); + } + } + None + } + + pub fn get_curr_func_mut(&mut self) -> Option<&mut FunctionInfo> { + if let Some(symbol) = self.sym_table.get_symbol(self.current_function) { + if let Some(func_info) = self.func_table.get_mut(&symbol.name) { + return Some(func_info); + } + } + None + } + + pub fn switch_to_func_scope(&mut self, func_id: usize) { + self.current_function = func_id; + self.scope = CompilerScope::FUNCTION; + } + + pub fn switch_to_global_scope(&mut self) { + self.current_function = INVALID_FUNC_ID; + self.scope = CompilerScope::GLOBAL; + } + + pub fn find_sym(&self, name: &str) -> Result<&Symbol, CtxError> { + if let Some(func_info) = self.get_curr_func() { + if let Some(sym_pos) = func_info.local_syms.find_symbol(name) { + if let Some(sym) = func_info.local_syms.get_symbol(sym_pos) { + return Ok(sym); + } + } + } + return self.find_sym_in_table(name, self.sym_table); + } + + fn find_sym_in_table<'a>(&'a self, name: &str, table: &'a Symtable) -> Result<&Symbol, CtxError> { + if let Some(sym_pos) = table.find_symbol(name) { + return if let Some(sym) = table.get_symbol(sym_pos) { + Ok(sym) + } else { + Err(CtxError::UndefinedSymbol) + }; + } + Err(CtxError::UndefinedSymbol) + } + + pub fn find_sym_mut(&mut self, name: &str) -> Result<&mut Symbol, CtxError> { + if let Some(local_sym_pos) = { + if let Some(func_info) = self.get_curr_func_mut() { + func_info.local_syms.find_symbol(name) + } else { + None + } + } { + if let Some(func_mut) = self.get_curr_func_mut() { + if let Some(mut_sym) = func_mut.local_syms.get_symbol_mut(local_sym_pos) { + return Ok(mut_sym); + } + } + } else if let Some(sym_pos) = self.sym_table.find_symbol(name) { + if let Some(sym) = self.sym_table.get_symbol_mut(sym_pos) { + return Ok(sym); + } else { + return Err(CtxError::UndefinedSymbol); + } + } + Err(CtxError::UndefinedSymbol) + } +} \ No newline at end of file diff --git a/src/context/ctx_error.rs b/src/context/ctx_error.rs new file mode 100644 index 0000000..e585ca3 --- /dev/null +++ b/src/context/ctx_error.rs @@ -0,0 +1,3 @@ +pub enum CtxError { + UndefinedSymbol +} \ No newline at end of file diff --git a/src/context/mod.rs b/src/context/mod.rs index 1897480..69da6cc 100644 --- a/src/context/mod.rs +++ b/src/context/mod.rs @@ -1,3 +1,5 @@ mod compiler_ctx; +mod ctx_error; -pub use compiler_ctx::*; \ No newline at end of file +pub use compiler_ctx::*; +pub use ctx_error::*; \ No newline at end of file diff --git a/src/main.rs b/src/main.rs index 768654d..75868f1 100644 --- a/src/main.rs +++ b/src/main.rs @@ -64,7 +64,7 @@ fn main() { let ctx: Rc> = Rc::new(RefCell::new(CompilerCtx::new(&mut symt, &mut funct))); // semantic analyzer - let s_analyzer: SemanticAnalyzer = SemanticAnalyzer::new(Rc::clone(&ctx)); + let mut s_analyzer: SemanticAnalyzer = SemanticAnalyzer::new(Rc::clone(&ctx)); // register manager let rm: RefCell = RefCell::new(Aarch64RegManager::new()); @@ -88,9 +88,9 @@ fn main() { for sf in &mut source_files { let tokens: Vec = sf.tokens.clone().unwrap(); ctx.borrow_mut().current_file = Some(sf); - let parse_result: Vec = parser_borrow.parse_with_ctx(Rc::clone(&ctx), tokens); + let mut parse_result: Vec = parser_borrow.parse_with_ctx(Rc::clone(&ctx), tokens); - s_analyzer.start_analysis(&parse_result); + s_analyzer.start_analysis(&mut parse_result); if !parser_borrow.has_parsing_errors() { cg.gen_with_ctx(Rc::clone(&ctx), &parse_result); diff --git a/src/parser/parser_impl.rs b/src/parser/parser_impl.rs index 61e3956..9848380 100644 --- a/src/parser/parser_impl.rs +++ b/src/parser/parser_impl.rs @@ -29,7 +29,6 @@ use crate::ast::AssignStmt; use crate::ast::BinExpr; use crate::ast::Expr; use crate::ast::FuncCallExpr; -use crate::ast::FuncCallStmt; use crate::ast::FuncDeclStmt; use crate::ast::IdentExpr; use crate::ast::LitValExpr; @@ -200,7 +199,8 @@ impl<'parser> Parser<'parser> { return self.parse_var_decl_stmt(); } } - match self.current_token.kind { + let curr_tok_kind: TokenKind = self.current_token.kind; + let result: ParseResult2 = match curr_tok_kind { TokenKind::KW_LET => self.parse_var_decl_stmt(), TokenKind::T_IDENTIFIER => self.assign_stmt_or_func_call(), TokenKind::KW_IF => self.parse_if_stmt(), @@ -221,7 +221,17 @@ impl<'parser> Parser<'parser> { } __err } + }; + match curr_tok_kind { + TokenKind::KW_LET + | TokenKind::KW_RETURN + | TokenKind::KW_BREAK + | TokenKind::T_IDENTIFIER => { + _ = self.token_match(TokenKind::T_SEMICOLON)?; + }, + _ => () } + result } // parse compound statement(statement starting with '{' and ending with '}') @@ -334,7 +344,7 @@ impl<'parser> Parser<'parser> { } } - _ = self.token_match(TokenKind::T_RPAREN); + self.token_match(TokenKind::T_RPAREN)?; let func_return_type: LitTypeVariant = self.__parse_fn_ret_type()?; self.skip_to_next_token(); @@ -407,7 +417,6 @@ impl<'parser> Parser<'parser> { // reset temporary symbols holder after the function has been parsed self.temp_local_syms = Symtable::new(); - self.temp_local_params = Symtable::new(); // Return AST for function declaration Ok(AST::new( @@ -517,7 +526,7 @@ impl<'parser> Parser<'parser> { return __err; } // skip semicolon - self.token_match(TokenKind::T_SEMICOLON)?; + // self.token_match(TokenKind::T_SEMICOLON)?; return Ok(AST::create_leaf( ASTKind::StmtAST(Stmt::Return(ReturnStmt { func_id: self.current_function_id, @@ -543,7 +552,7 @@ impl<'parser> Parser<'parser> { self.current_token.clone(), ))); } - _ = self.token_match(TokenKind::T_SEMICOLON)?; // expect semicolon to end a return statement + // _ = self.token_match(TokenKind::T_SEMICOLON)?; // expect semicolon to end a return statement Ok(AST::new( ASTKind::StmtAST(Stmt::Return(ReturnStmt { func_id: self.current_function_id, @@ -774,11 +783,12 @@ impl<'parser> Parser<'parser> { } else { self.add_symbol_global(sym.clone()).unwrap() }; - let return_result: Result> = if let Some(assign_ast_node_res) = assignment_parse_res { + let return_result: ParseResult2 = if let Some(assign_ast_node_res) = assignment_parse_res { Ok(AST::new( ASTKind::StmtAST(Stmt::VarDecl(VarDeclStmt { symtbl_pos: symbol_add_pos, - class: var_class + class: var_class, + sym_name: id_token.lexeme.clone() })), ASTOperation::AST_VAR_DECL, Some(assign_ast_node_res?), @@ -789,7 +799,8 @@ impl<'parser> Parser<'parser> { Ok(AST::new( ASTKind::StmtAST(Stmt::VarDecl(VarDeclStmt { symtbl_pos: symbol_add_pos, - class: var_class + class: var_class, + sym_name: id_token.lexeme.clone() })), ASTOperation::AST_VAR_DECL, None, @@ -797,13 +808,12 @@ impl<'parser> Parser<'parser> { var_type, )) }; - _ = self.token_match(TokenKind::T_SEMICOLON)?; return_result } fn gen_next_local_offset(&mut self, var_type: LitTypeVariant) -> i32 { - let temp_offset: i32 = if var_type.size() > 4 { - var_type.size() as i32 + let temp_offset: i32 = if var_type.size() <= 4 { + 4 } else { 8 }; @@ -881,7 +891,8 @@ impl<'parser> Parser<'parser> { ASTKind::StmtAST(Stmt::ArrVarDecl(ArrVarDeclStmt { symtbl_pos: symbol_add_pos, vals: array_values, - class: sym.class + class: sym.class, + sym_name: id_token.lexeme.clone() })), ASTOperation::AST_ARR_VAR_DECL, sym.lit_type, @@ -889,7 +900,7 @@ impl<'parser> Parser<'parser> { None ); - _ = self.token_match(TokenKind::T_SEMICOLON)?; + // _ = self.token_match(TokenKind::T_SEMICOLON)?; Ok(array_decl_ast ) } @@ -952,89 +963,34 @@ impl<'parser> Parser<'parser> { if tok_kind_after_id_tok != TokenKind::T_LPAREN { self.parse_assignment_stmt(id_token) } else { - let mut symbol_pos: usize = 0; - let symbol: Option = if let Some(ctx_rc) = &mut self.ctx { - let ctx_borrow = ctx_rc.borrow_mut(); - let sym_pos = ctx_borrow.sym_table.find_symbol(&id_token.lexeme); - if let Some(sp) = sym_pos { - symbol_pos = sp; - ctx_borrow.sym_table.get_symbol(sp).cloned() - } else { None } - } else { None }; - if let Some(sym) = symbol { - self.parse_func_call_expr(&sym, symbol_pos, &id_token) - } else { - Err(Box::new(BErr::undefined_symbol(self.get_current_file_name(), id_token.clone()))) - } + self.parse_func_call_expr(&id_token.lexeme, &id_token) } } fn parse_assignment_stmt(&mut self, id_token: Token) -> ParseResult2 { - let symbol_search_result: Option<(usize, StorageClass)> = self.find_symbol(&id_token.lexeme); - if symbol_search_result.is_none() { - self.skip_past(TokenKind::T_SEMICOLON); - return Err(Box::new(BErr::undefined_symbol( - self.get_current_file_name(), - id_token.clone(), - ))); - } - - let id_index_symt: usize = symbol_search_result.unwrap().0; - let symbol: Symbol = if let Some(ctx_rc) = &mut self.ctx { - let ctx_borrow = ctx_rc.borrow_mut(); - ctx_borrow - .sym_table - .get_symbol(id_index_symt) - .unwrap() - .clone() - } else { - return Err(Box::new(BErr::new( - BErrType::UndefinedSymbol, - self.get_current_file_name(), - self.current_token.clone(), - ))); - }; - - // we are in global scope but trying to assign to a local variable - if self.is_scope_global() && symbol.class == StorageClass::LOCAL { - self.skip_past(TokenKind::T_SEMICOLON); - return Err(Box::new(BErr::undefined_symbol( - self.get_current_file_name(), - id_token.clone(), - ))); - } - - // Check if we are assigning to a type other than SymbolType::Variable. If yes, panic! - if symbol.sym_type != SymbolType::Variable { - // self.skip_past(TokenKind::T_SEMICOLON); - panic!("Assigning to type '{:?}' is not allowed! '{:?}'", symbol.sym_type, symbol); - } - _ = self.token_match(TokenKind::T_EQUAL)?; let bin_expr_ast_node: AST = self.parse_equality()?; - // following code is going to break at some point. unwrap()ing an Option type without checking? - let _result_type: LitTypeVariant = bin_expr_ast_node.result_type; - - _ = self.token_match(TokenKind::T_SEMICOLON)?; + // _ = self.token_match(TokenKind::T_SEMICOLON)?; let lvalueid: AST = AST::create_leaf( - ASTKind::StmtAST(Stmt::LValue(id_index_symt)), + ASTKind::StmtAST(Stmt::LValue2{ name: id_token.lexeme.clone() }), ASTOperation::AST_LVIDENT, - symbol.lit_type, + LitTypeVariant::None, None, None ); Ok(AST::new( ASTKind::StmtAST(Stmt::Assignment(AssignStmt { - symtbl_pos: id_index_symt, + symtbl_pos: 0, + sym_name: id_token.lexeme.clone() })), ASTOperation::AST_ASSIGN, Some(lvalueid), Some(bin_expr_ast_node), - _result_type, + LitTypeVariant::Void, )) } @@ -1175,40 +1131,20 @@ impl<'parser> Parser<'parser> { ) )); } - let sym_find_res: Option<(usize, StorageClass)> = self.find_symbol(¤t_token.lexeme); - if sym_find_res.is_none() { - return Err(Box::new(BErr::undefined_symbol( - current_file.clone(), - current_token.clone(), - ))); - } - let id_index: usize = sym_find_res.unwrap().0; - let mut symbol: Symbol = if let Some(ctx_rc) = &mut self.ctx { - let ctx_borrow = ctx_rc.borrow_mut(); - ctx_borrow.sym_table.get_symbol(id_index).unwrap().clone() - } else { - return Err(Box::new(BErr::undefined_symbol( - current_file.clone(), - current_token.clone(), - ))); - }; - - // increment the use count of this symbol - symbol.incr_use(); - + let symbol_name: String = current_token.lexeme.clone(); let curr_tok_kind: TokenKind = self.current_token.kind; if curr_tok_kind == TokenKind::T_LPAREN { - self.parse_func_call_expr(&symbol, id_index, ¤t_token) - } else if curr_tok_kind == TokenKind::T_LBRACKET { - self.parse_array_index_expr(&symbol, id_index, ¤t_token) - } else { + self.parse_func_call_expr(&symbol_name, ¤t_token) + } + else { Ok(AST::create_leaf( ASTKind::ExprAST(Expr::Ident(IdentExpr { - symtbl_pos: id_index, - result_type: symbol.lit_type, + symtbl_pos: 0, + result_type: LitTypeVariant::None, + sym_name: symbol_name })), ASTOperation::AST_IDENT, - symbol.lit_type, + LitTypeVariant::None, // type will be identified at the semantic analysis phases if the symbol is defined None, None )) @@ -1288,18 +1224,11 @@ impl<'parser> Parser<'parser> { fn parse_func_call_expr( &mut self, - called_symbol: &Symbol, - sym_index: usize, + called_symbol: &str, sym_token: &Token, ) -> ParseResult2 { let current_file: String = self.get_current_file_name(); _ = self.token_match(TokenKind::T_LPAREN)?; - if called_symbol.sym_type != SymbolType::Function { - return Err(Box::new(BErr::noncallable_ident( - current_file.clone(), - sym_token.clone(), - ))); - } let curr_token_kind: TokenKind = self.current_token.kind; let mut func_args: Vec = vec![]; @@ -1332,53 +1261,33 @@ impl<'parser> Parser<'parser> { // Allocating extra 16 bytes to store x29(Frame Pointer), and x30(Link Register). // Storing and then loading them is collectively called a Frame Record. // self.local_offset += 16; - - if called_symbol.lit_type == LitTypeVariant::Void { - _ = self.token_match(TokenKind::T_SEMICOLON)?; - Ok(AST::create_leaf( - ASTKind::StmtAST( - Stmt::FuncCall( - FuncCallStmt { - symtbl_pos: sym_index, + Ok(AST::create_leaf( + ASTKind::ExprAST( + Expr::FuncCall( + FuncCallExpr { + result_type: LitTypeVariant::None, + symbol_name: called_symbol.to_string(), args: func_args } - )), - ASTOperation::AST_FUNC_CALL, - LitTypeVariant::Void, - None, - None - ) - ) - } - else { - Ok(AST::create_leaf( - ASTKind::ExprAST( - Expr::FuncCall( - FuncCallExpr { - symtbl_pos: sym_index, - result_type: called_symbol.lit_type, - args: func_args - } - ) - ), - ASTOperation::AST_FUNC_CALL, - called_symbol.lit_type, - None, - None - )) - } + ) + ), + ASTOperation::AST_FUNC_CALL, + LitTypeVariant::None, + Some(sym_token.clone()), + None + )) } fn add_symbol_global(&mut self, sym: Symbol) -> Option { let insert_pos: Option = { if let Some(ctx_rc) = &mut self.ctx { let mut ctx_borrow = ctx_rc.borrow_mut(); + self.next_global_sym_pos += 1; ctx_borrow.sym_table.insert(self.next_global_sym_pos, sym) } else { panic!("Can't add a new symbol globally"); } }; - self.next_global_sym_pos += 1; insert_pos } @@ -1388,41 +1297,6 @@ impl<'parser> Parser<'parser> { insert_pos } - fn find_symbol(&self, name: &str) -> Option<(usize, StorageClass)> { - // first search in the local scope to determine if the symbol exists in local scope - if let Some(local_pos) = self.find_symbol_local(name) { - return Some((local_pos, StorageClass::LOCAL)); - } - // then inquire global scope - if let Some(global_pos) = self.find_symbol_global(name) { - return Some((global_pos, StorageClass::GLOBAL)); - } - None - } - - fn find_symbol_global(&self, name: &str) -> Option { - if let Some(ctx_rc) = &self.ctx { - let ctx_borrow = ctx_rc.borrow_mut(); - for index in 0..self.next_global_sym_pos { - if let Some(symbol) = ctx_borrow.sym_table.get_symbol(index) { - if symbol.name == name { - return Some(index); - } - } - } - } - None - } - - fn find_symbol_local(&self, param_name: &str) -> Option { - let has_local_sym: Option = self.temp_local_syms.find_symbol(param_name); - if has_local_sym.is_some() { - has_local_sym - } else { - None - } - } - fn is_scope_global(&self) -> bool { self.current_function_id == INVALID_FUNC_ID } diff --git a/src/semantic/analyzer.rs b/src/semantic/analyzer.rs index ac949cb..182991e 100644 --- a/src/semantic/analyzer.rs +++ b/src/semantic/analyzer.rs @@ -24,38 +24,63 @@ SOFTWARE. use std::{cell::RefCell, rc::Rc}; -use crate::{ast::{ASTKind, ASTOperation, FuncCallExpr, Stmt, AST}, context::CompilerCtx, FunctionInfo, Symbol}; - -use super::{sa_errors::SAError, sa_types::SAResult, type_checker::TypeChecker}; +use crate::{ + ast::{ + ASTKind, + ASTOperation, + Expr, + Stmt, + AST + }, + context::CompilerCtx, + types::LitTypeVariant, + Symbol +}; + +use super::{ + sa_errors::{SAError, SATypeError}, + sa_types::SAResult, + type_checker::TypeChecker +}; + +#[allow(non_camel_case_types)] +enum _InternalSAErrType { + __ISET_UndefinedSymbol__ { + name: String // name of the symbol + } +} pub struct SemanticAnalyzer<'sa> { - pub ctx: Rc>> + pub ctx: Rc>>, } impl<'sa> SemanticAnalyzer<'sa> { pub fn new(ctx: Rc>>) -> Self { Self { - ctx + ctx, } } - pub fn start_analysis(&self, nodes: &Vec) { + pub fn start_analysis(&mut self, nodes: &mut Vec) { for node in nodes { - let _result: SAResult = self.analyze_node(node, ASTOperation::AST_NONE); + let result: SAResult = self.analyze_node(node, ASTOperation::AST_NONE); + if let Err(analysis_err) = result { + analysis_err.dump(); + } } } - fn analyze_node(&self, node: &AST, parent_ast_op: ASTOperation) -> SAResult { + fn analyze_node(&mut self, node: &mut AST, parent_ast_op: ASTOperation) -> SAResult { match node.operation { ASTOperation::AST_VAR_DECL => self.analyze_var_decl_stmt(node), ASTOperation::AST_FUNCTION => self.analyze_func_decl_stmt(node), - ASTOperation::AST_FUNC_CALL => self.analyze_func_call_expr(node), + ASTOperation::AST_FUNC_CALL => self.analyze_func_call(node), ASTOperation::AST_GLUE => { - if let Some(left) = node.left.as_ref() { - _ = self.analyze_node(left, parent_ast_op); + if let Some(left) = &mut node.left { + self.analyze_node(left, parent_ast_op)?; } - if let Some(right) = node.right.as_ref() { - _ = self.analyze_node(right, parent_ast_op); + if let Some(right) = &mut node.right { + self.analyze_node(right, parent_ast_op)?; } Ok(()) } @@ -63,7 +88,7 @@ impl<'sa> SemanticAnalyzer<'sa> { } } - fn analyze_func_decl_stmt(&self, node: &AST) -> SAResult { + fn analyze_func_decl_stmt(&mut self, node: &mut AST) -> SAResult { let func_id: usize = match &node.kind { ASTKind::StmtAST(stmt_ast) => { match stmt_ast { @@ -76,53 +101,131 @@ impl<'sa> SemanticAnalyzer<'sa> { _ => panic!("not a statement") }; - let ctx_borrow: std::cell::Ref> = self.ctx.borrow(); + let mut ctx_borrow = self.ctx.borrow_mut(); let func_name: String = ctx_borrow.sym_table.get_symbol(func_id).unwrap().name.clone(); - if ctx_borrow.func_table.get(&func_name).is_none() { + if let Some(_finfo) = ctx_borrow.func_table.get(&func_name) { + ctx_borrow.switch_to_func_scope(func_id); + } else { panic!("Function '{}' not found", func_name); - }; + } drop(ctx_borrow); - if let Some(func_body) = &node.left { + if let Some(func_body) = &mut node.left { return self.analyze_node(func_body, ASTOperation::AST_FUNCTION); } + self.ctx.borrow_mut().switch_to_global_scope(); Ok(()) } - fn analyze_func_call_expr(&self, node: &AST) -> SAResult { - Ok(()) + fn analyze_func_call(&self, node: &AST) -> SAResult { + let func_name: String = match &node.kind { + ASTKind::ExprAST(expr) => { + match expr { + Expr::FuncCall(func_call_expr) => { + func_call_expr.symbol_name.to_string() + }, + _ => panic!("Not a function call expression") + } + }, + _ => panic!("not a expression") + }; + let ctx_borrow = self.ctx.borrow(); + if let Some(func_sym_pos) = ctx_borrow.sym_table.find_symbol(&func_name) { + if let Some(func_sym) = ctx_borrow.sym_table.get_symbol(func_sym_pos) { + if !TypeChecker::is_callable(func_sym) { + return Err( + SAError::TypeError( + SATypeError::NonCallable { + sym_name: func_sym.name.clone() + } + ) + ); + } else { + return Ok(()); + } + } + } + Err(SAError::UndefinedSymbol { sym_name: func_name, token: node.start_token.clone().unwrap() }) } - fn analyze_var_decl_stmt(&self, node: &AST) -> SAResult { + fn analyze_var_decl_stmt(&self, node: &mut AST) -> SAResult { let mut ctx_borrow = self.ctx.borrow_mut(); if let ASTKind::StmtAST(stmt) = &node.kind { return match stmt { Stmt::VarDecl(var_decl_stmt) => { - let symbol: &mut Symbol = ctx_borrow.sym_table.get_mut_or_fail(var_decl_stmt.symtbl_pos); - let assign_expr: &ASTKind = &node.left.as_ref().unwrap().kind; - - if let ASTKind::ExprAST(expr) = assign_expr { - TypeChecker::type_check_var_decl_stmt(symbol, expr) + let symbol: Result<&mut Symbol, crate::context::CtxError> = ctx_borrow.find_sym_mut(&var_decl_stmt.sym_name); + if symbol.is_err() { + panic!("not good. how did I end up here? searching for a non-existing symbol while declaring a variable?"); + } + let assign_expr: &mut Box = node.left.as_mut().unwrap(); + if let ASTKind::ExprAST(expr) = &mut assign_expr.kind { + if let Err(expr_err) = self.annotate_expr_with_respective_type(expr) { + return Err(self.construct_sa_err(assign_expr, expr_err)); + } + TypeChecker::type_check_var_decl_stmt(symbol.ok().unwrap(), expr) } else { Ok(()) } }, Stmt::ArrVarDecl(arr_var_decl_stmt) => { - let sym: &mut Symbol = ctx_borrow.sym_table.get_mut_or_fail(arr_var_decl_stmt.symtbl_pos); + let symbol_res: Result<&mut Symbol, crate::context::CtxError> = ctx_borrow.find_sym_mut(&arr_var_decl_stmt.sym_name); + if symbol_res.is_err() { + panic!("not good. how did I end up here? searching for a non-existing symbol while declaring a variable?"); + } + let symbol: &mut crate::Symbol = symbol_res.ok().unwrap(); // array size validation - if sym.size != arr_var_decl_stmt.vals.len() { + if symbol.size != arr_var_decl_stmt.vals.len() { return Err(SAError::ArrayLengthError { - expected: sym.size, + expected: symbol.size, found: arr_var_decl_stmt.vals.len() }); } - TypeChecker::type_check_arr_var_decl_stmt(sym, &arr_var_decl_stmt.vals) + TypeChecker::type_check_arr_var_decl_stmt(symbol, &arr_var_decl_stmt.vals) }, _ => panic!("Not a variable declaration statement...") }; } Ok(()) } + + /// Annotates the given expression with its respective type, if identifiable. + /// + /// # Errors + /// Returns an error if the expression type is not supported or the symbol's type + /// is undefined. + fn annotate_expr_with_respective_type(&self, expr: &mut Expr) -> Result<(), _InternalSAErrType> { + match expr { + Expr::Ident(ident_expr) => { + if let Some(ident_type) = self.get_ident_type(&ident_expr.sym_name) { + ident_expr.result_type = ident_type; + Ok(()) + } + else { + Err(_InternalSAErrType::__ISET_UndefinedSymbol__ { + name: ident_expr.sym_name.clone() + }) + } + }, + Expr::LitVal(_) => Ok(()), + _ => panic!("Type annotation not supported for {:?} yet!", expr) + } + } + + /// Retrieves the literal type of a symbol by its name, if available. + /// This function does not return errors, but may return `None` if the + /// symbol cannot be found. + fn get_ident_type(&self, sym_name: &str) -> Option { + let ctx_borrow = self.ctx.borrow(); + ctx_borrow.find_sym(sym_name).ok().map(|symbol| symbol.lit_type) + } + + fn construct_sa_err(&self, ast: &AST, err: _InternalSAErrType) -> SAError { + match err { + _InternalSAErrType::__ISET_UndefinedSymbol__ { name } => { + SAError::UndefinedSymbol { sym_name: name, token: ast.start_token.clone().unwrap() } + } + } + } } #[cfg(test)] @@ -164,12 +267,13 @@ mod tests { CompilerCtx::new(symt, func_table) } - fn create_i32_var_decl_ast(pos: usize) -> AST { + fn create_i32_var_decl_ast(pos: usize, name: String) -> AST { AST::new( ASTKind::StmtAST(Stmt::VarDecl( VarDeclStmt { class: StorageClass::LOCAL, - symtbl_pos: pos + symtbl_pos: pos, + sym_name: name } )), ASTOperation::AST_VAR_DECL, @@ -191,12 +295,13 @@ mod tests { ) } - fn create_i32_var_decl_ast_with_bin_expr(pos: usize) -> AST { + fn create_i32_var_decl_ast_with_bin_expr(pos: usize, name: String) -> AST { AST::new( ASTKind::StmtAST(Stmt::VarDecl( VarDeclStmt { class: StorageClass::LOCAL, - symtbl_pos: pos + symtbl_pos: pos, + sym_name: name } )), ASTOperation::AST_VAR_DECL, @@ -253,8 +358,8 @@ mod tests { let a_analyzer: SemanticAnalyzer<'_> = SemanticAnalyzer::new(Rc::clone(&ctx)); - let no_type_var_ast: AST = create_i32_var_decl_ast(0); - let ar2: SAResult = a_analyzer.analyze_var_decl_stmt(&no_type_var_ast); + let mut no_type_var_ast: AST = create_i32_var_decl_ast(0, "number".to_string()); + let ar2: SAResult = a_analyzer.analyze_var_decl_stmt(&mut no_type_var_ast); assert!(ar2.is_ok()); // type has to be updated of non-type symbol @@ -273,8 +378,8 @@ mod tests { let a_analyzer: SemanticAnalyzer<'_> = SemanticAnalyzer::new(Rc::clone(&ctx)); - let no_type_var_ast: AST = create_i32_var_decl_ast_with_bin_expr(0); - let ar2: SAResult = a_analyzer.analyze_var_decl_stmt(&no_type_var_ast); + let mut no_type_var_ast: AST = create_i32_var_decl_ast_with_bin_expr(0, "number".to_string()); + let ar2: SAResult = a_analyzer.analyze_var_decl_stmt(&mut no_type_var_ast); assert!(ar2.is_err()); matches!( ar2, @@ -298,17 +403,16 @@ mod tests { let symt: &mut Symtable = &mut create_symt( vec![ create_i32_symbol("number".to_string()), - create_i32_symbol("number2".to_string()) ] ); let funct: &mut FunctionInfoTable = &mut create_funt(); let ctx: Rc>> = Rc::new(RefCell::new(create_ctx(symt, funct))); - let var_ast: AST = create_i32_var_decl_ast(0); + let mut var_ast: AST = create_i32_var_decl_ast(0, "number".to_string()); let a_analyzer: SemanticAnalyzer<'_> = SemanticAnalyzer::new(Rc::clone(&ctx)); - let analysis_res: SAResult = a_analyzer.analyze_var_decl_stmt(&var_ast); + let analysis_res: SAResult = a_analyzer.analyze_var_decl_stmt(&mut var_ast); assert!(analysis_res.is_ok()); } } \ No newline at end of file diff --git a/src/semantic/sa_errors.rs b/src/semantic/sa_errors.rs index 190c0a4..003a48b 100644 --- a/src/semantic/sa_errors.rs +++ b/src/semantic/sa_errors.rs @@ -22,11 +22,14 @@ OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE SOFTWARE. */ -use crate::{ast::ASTOperation, types::LitTypeVariant}; +use std::fmt; + +use crate::{ast::ASTOperation, tokenizer::Token, types::LitTypeVariant}; pub enum SATypeError { AssignmentTypeMismatch { - expected: LitTypeVariant, found: LitTypeVariant + expected: LitTypeVariant, + found: LitTypeVariant }, IncompatibleTypes { a: LitTypeVariant, @@ -34,12 +37,64 @@ pub enum SATypeError { operation: ASTOperation }, TypeMismatch { - a: LitTypeVariant, b: LitTypeVariant + expected: LitTypeVariant, + found: LitTypeVariant + }, + NonCallable { + sym_name: String } } pub enum SAError { TypeError(SATypeError), - ArrayLengthError { expected: usize, found: usize }, + ArrayLengthError { + expected: usize, + found: usize + }, + UndefinedSymbol { + sym_name: String, + token: Token + }, None +} + +impl fmt::Display for SATypeError { + fn fmt(&self, f: &mut fmt::Formatter<'_>) -> fmt::Result { + match self { + Self::AssignmentTypeMismatch { expected, found } => { + write!(f, "Assignment type mismatch: expected type `{}`, found `{}`.", expected, found) + } + Self::IncompatibleTypes { a, b, operation } => { + write!(f, "Incompatible types `{}` and `{}` for operation `{:?}`.", a, b, operation) + } + Self::TypeMismatch { expected, found } => { + write!(f, "Type mismatch: `{}` is not compatible with `{}`.", expected, found) + }, + Self::NonCallable{ sym_name} => { + write!(f, "'{}' is not a function.", sym_name) + } + } + } +} + +impl fmt::Display for SAError { + fn fmt(&self, f: &mut fmt::Formatter<'_>) -> fmt::Result { + match self { + SAError::TypeError(type_error) => write!(f, "Type Error: {}", type_error), + SAError::ArrayLengthError { expected, found } => { + write!(f, "Array length mismatch: expected `{}`, found `{}`.", expected, found) + }, + SAError::UndefinedSymbol{ sym_name, token} => { + write!(f, "{}:{}: compile error: Undefined symbol '{}'", token.pos.line, token.pos.column, sym_name) + }, + SAError::None => write!(f, "No error."), + } + } +} + +impl SAError { + pub fn dump(&self) { + println!("{}", self); + std::process::exit(1); + } } \ No newline at end of file diff --git a/src/semantic/type_checker.rs b/src/semantic/type_checker.rs index 7a14892..0631631 100644 --- a/src/semantic/type_checker.rs +++ b/src/semantic/type_checker.rs @@ -27,7 +27,7 @@ use crate::{ types::{ is_type_coalescing_possible, LitTypeVariant }, - Symbol + Symbol, SymbolType }; use super::{ @@ -77,6 +77,8 @@ impl TypeChecker { Ok(()) } + /// this fucktion is bullshit. do not use + /// IGNORE pub fn type_check_arr_var_decl_stmt(sym: &mut Symbol, vals: &Vec) -> SAResult { for expr in vals { if expr.result_type() != sym.lit_type @@ -95,4 +97,12 @@ impl TypeChecker { } Ok(()) } + + pub fn is_callable(sym: &Symbol) -> bool { + if sym.sym_type != SymbolType::Function { + return false; + + } + true + } } \ No newline at end of file diff --git a/src/symbol/function.rs b/src/symbol/function.rs index e93cbfc..30f725e 100644 --- a/src/symbol/function.rs +++ b/src/symbol/function.rs @@ -32,6 +32,9 @@ use super::{StorageClass, Symbol, SymbolTrait, Symtable}; /// Limit of local variables in a function. pub const LOCAL_LIMIT: usize = 1024; +/// Inavlid function ID. +pub const INVALID_FUNC_ID: usize = 0xFFFFFFFF; + /// Represents a function parameter in the symbol table. #[derive(Clone, Debug)] pub struct FuncParam { @@ -69,49 +72,6 @@ pub struct LocalSymbol { pub offset: usize, } -#[derive(Clone, Debug)] -pub struct LocalSymtable { - pub syms: Vec, - pub counter: usize, -} - -impl LocalSymtable { - pub fn new() -> Self { - Self { - syms: vec![], - counter: 0 - } - } - - /// Add a new symbol - pub fn add(&mut self, symbol: LocalSymbol) -> usize { - assert!(self.syms.len() < LOCAL_LIMIT, "Local variable count has exceeded the limit of '{}'", LOCAL_LIMIT); - self.syms.push(symbol); - self.syms.len() - 1 - } - - /// Get the position of symbol with the provided name if it exists - pub fn position(&self, name: &str) -> Option { - assert!(name.is_empty(), "Name can't be an empty string"); - self.syms.iter().position(|item| item.name == name) - } - - /// Get the symbol with the provided name if it exists - pub fn get(&self, name: &str) -> Option<&LocalSymbol> { - if let Some(pos) = self.position(name) { - return self.syms.get(pos); - } - None - } - - pub fn remove(&mut self, name: &str) -> Option { - if let Some(pos) = self.position(name) { - return Some(self.syms.remove(pos)); - } - None - } -} - #[derive(Clone, Debug)] pub struct FunctionInfo { pub name: String, @@ -169,4 +129,8 @@ impl FunctionInfoTable { pub fn get(&self, name: &str) -> Option<&FunctionInfo> { self.functions.get(name) } + + pub fn get_mut(&mut self, name: &str) -> Option<&mut FunctionInfo> { + self.functions.get_mut(name) + } } \ No newline at end of file