From e24763dfb69c70ed3e16ae1a6a931aab5354c504 Mon Sep 17 00:00:00 2001 From: Toni Date: Thu, 19 Mar 2026 13:16:34 +0100 Subject: [PATCH] gut analyzer by moving the arity check to the typechecker --- src/analyzer.rs | 193 +++++---------------------------------------- src/main.rs | 5 +- src/typechecker.rs | 20 ++++- 3 files changed, 38 insertions(+), 180 deletions(-) diff --git a/src/analyzer.rs b/src/analyzer.rs index e218125..d65277f 100644 --- a/src/analyzer.rs +++ b/src/analyzer.rs @@ -1,7 +1,7 @@ use std::collections::HashMap; use crate::{ - parser::{Expr, Stmt}, + parser::Stmt, tokenizer::{ZernError, error}, }; @@ -62,39 +62,8 @@ impl Analyzer { } } - pub fn register_function(&mut self, stmt: &Stmt) -> Result<(), ZernError> { - if let Stmt::Function { - name, - params, - return_type, - body: _, - exported: _, - } = stmt - { - if self.functions.contains_key(&name.lexeme) { - return error!(name.loc, format!("tried to redefine '{}'", name.lexeme)); - } - self.functions.insert( - name.lexeme.clone(), - FnType { - return_type: return_type.lexeme.clone(), - params: Some(params.iter().map(|x| x.var_type.lexeme.clone()).collect()), - }, - ); - } - Ok(()) - } - - pub fn analyze_stmt(&mut self, stmt: &Stmt) -> Result<(), ZernError> { + pub fn register_declaration(&mut self, stmt: &Stmt) -> Result<(), ZernError> { match stmt { - Stmt::Expression(expr) => self.analyze_expr(expr)?, - Stmt::Let { - name: _, - var_type: _, - initializer, - } => { - self.analyze_expr(initializer)?; - } Stmt::Const { name, value } => { if self.constants.contains_key(&name.lexeme) || self.functions.contains_key(&name.lexeme) @@ -114,57 +83,6 @@ impl Analyzer { .insert(name.lexeme.clone(), value.lexeme.parse().unwrap()); } } - Stmt::Block(statements) => { - for stmt in statements { - self.analyze_stmt(stmt)?; - } - } - Stmt::If { - keyword: _, - condition, - then_branch, - else_branch, - } => { - self.analyze_expr(condition)?; - self.analyze_stmt(then_branch)?; - self.analyze_stmt(else_branch)?; - } - Stmt::While { - keyword: _, - condition, - body, - } => { - self.analyze_expr(condition)?; - self.analyze_stmt(body)?; - } - Stmt::Function { - name, - params: _, - return_type, - body, - exported: _, - } => { - if name.lexeme == "main" && return_type.lexeme != "i64" { - return error!(&name.loc, "main must return i64"); - } - - self.analyze_stmt(body)?; - } - Stmt::Return { expr, keyword: _ } => { - self.analyze_expr(expr)?; - } - Stmt::For { - var: _, - start, - end, - body, - } => { - self.analyze_expr(start)?; - self.analyze_expr(end)?; - self.analyze_stmt(body)?; - } - Stmt::Break => {} - Stmt::Continue => {} Stmt::Extern(name) => { if self.functions.contains_key(&name.lexeme) { return error!(name.loc, format!("tried to redefine '{}'", name.lexeme)); @@ -172,6 +90,24 @@ impl Analyzer { self.functions .insert(name.lexeme.clone(), FnType::new_variadic("any")); } + Stmt::Function { + name, + params, + return_type, + body: _, + exported: _, + } => { + if self.functions.contains_key(&name.lexeme) { + return error!(name.loc, format!("tried to redefine '{}'", name.lexeme)); + } + self.functions.insert( + name.lexeme.clone(), + FnType { + return_type: return_type.lexeme.clone(), + params: Some(params.iter().map(|x| x.var_type.lexeme.clone()).collect()), + }, + ); + } Stmt::Struct { name, fields } => { let mut fields_map: HashMap = HashMap::new(); @@ -189,94 +125,7 @@ impl Analyzer { self.structs.insert(name.lexeme.clone(), fields_map); } - } - Ok(()) - } - - pub fn analyze_expr(&mut self, expr: &Expr) -> Result<(), ZernError> { - match expr { - Expr::Binary { left, op: _, right } => { - self.analyze_expr(left)?; - self.analyze_expr(right)?; - } - Expr::Logical { left, op: _, right } => { - self.analyze_expr(left)?; - self.analyze_expr(right)?; - } - Expr::Grouping(expr) => self.analyze_expr(expr)?, - Expr::Literal(_) => {} - Expr::Unary { op: _, right } => { - self.analyze_expr(right)?; - } - Expr::Variable(_) => {} - Expr::Assign { left, op: _, value } => { - self.analyze_expr(left)?; - self.analyze_expr(value)?; - } - Expr::Call { - callee, - paren, - args, - } => { - if let Expr::Variable(callee_name) = *callee.clone() { - if self.functions.contains_key(&callee_name.lexeme) { - // its a function (defined/builtin/extern) - if let Some(fn_type) = self.functions.get(&callee_name.lexeme) { - // if its None, its variadic - if let Some(params) = &fn_type.params - && params.len() != args.len() - { - return error!( - &paren.loc, - format!( - "expected {} arguments, got {}", - params.len(), - args.len() - ) - ); - } - } else { - return error!( - &paren.loc, - format!("undefined function: {}", callee_name.lexeme) - ); - } - } else { - // its a variable containing function address - self.analyze_expr(callee)?; - } - } else { - // its an expression that evalutes to function address - self.analyze_expr(callee)?; - } - - for arg in args { - self.analyze_expr(arg)?; - } - } - Expr::ArrayLiteral(exprs) => { - for expr in exprs { - self.analyze_expr(expr)?; - } - } - Expr::Index { - expr, - bracket: _, - index, - } => { - self.analyze_expr(expr)?; - self.analyze_expr(index)?; - } - Expr::AddrOf { op: _, expr } => { - self.analyze_expr(expr)?; - } - Expr::New(_) => {} - Expr::MemberAccess { left, field: _ } => { - self.analyze_expr(left)?; - } - Expr::Cast { expr, type_name: _ } => { - self.analyze_expr(expr)?; - } + _ => {} } Ok(()) } diff --git a/src/main.rs b/src/main.rs index da7fdd3..10585ef 100644 --- a/src/main.rs +++ b/src/main.rs @@ -46,10 +46,7 @@ fn compile_file(args: Args) -> Result<(), ZernError> { let mut analyzer = analyzer::Analyzer::new(); for stmt in &statements { - analyzer.register_function(stmt)?; - } - for stmt in &statements { - analyzer.analyze_stmt(stmt)?; + analyzer.register_declaration(stmt)?; } let mut typechecker = typechecker::TypeChecker::new(&analyzer); diff --git a/src/typechecker.rs b/src/typechecker.rs index 07fb7a7..01c40fd 100644 --- a/src/typechecker.rs +++ b/src/typechecker.rs @@ -160,12 +160,16 @@ impl<'a> TypeChecker<'a> { env.pop_scope(); } Stmt::Function { - name: _, + name, params, return_type, body, exported: _, } => { + if name.lexeme == "main" && return_type.lexeme != "i64" { + return error!(&name.loc, "main must return i64"); + } + if !self.is_valid_type_name(&return_type.lexeme) { return error!( &return_type.loc, @@ -369,12 +373,20 @@ impl<'a> TypeChecker<'a> { args, } => { if let Expr::Variable(callee_name) = &**callee { - if self.analyzer.functions.contains_key(&callee_name.lexeme) { - let fn_type = &self.analyzer.functions[&callee_name.lexeme]; + if let Some(fn_type) = self.analyzer.functions.get(&callee_name.lexeme) { // its a function (defined/builtin/extern) if let Some(params) = fn_type.params.clone() { + if params.len() != args.len() { + return error!( + &paren.loc, + format!( + "expected {} arguments, got {}", + params.len(), + args.len() + ) + ); + } for (i, arg) in args.iter().enumerate() { - // arity is checked in the analyzer expect_type!(self.typecheck_expr(env, arg)?, params[i], paren.loc); } } else {