From 81ceeeadb8fa4395c736916841c7a97e62b6127d Mon Sep 17 00:00:00 2001 From: Jesse Brault Date: Tue, 3 Mar 2026 12:31:52 -0600 Subject: [PATCH] Add parameter-list to regular fns. --- dmc-lib/src/ast/extern_function.rs | 59 +++++++++++---------- dmc-lib/src/ast/function.rs | 84 ++++++++++++++++++++++++------ dmc-lib/src/ast/parameter.rs | 8 +++ dmc-lib/src/parser.rs | 19 +++++-- 4 files changed, 125 insertions(+), 45 deletions(-) diff --git a/dmc-lib/src/ast/extern_function.rs b/dmc-lib/src/ast/extern_function.rs index e4cab9b..7efa5fb 100644 --- a/dmc-lib/src/ast/extern_function.rs +++ b/dmc-lib/src/ast/extern_function.rs @@ -3,8 +3,6 @@ use crate::diagnostic::Diagnostic; use crate::source_range::SourceRange; use crate::symbol::FunctionSymbol; use crate::symbol_table::{SymbolInsertError, SymbolTable}; -use std::cell::RefCell; -use std::rc::Rc; pub struct ExternFunction { declared_name: String, @@ -35,24 +33,24 @@ impl ExternFunction { let insert_result = symbol_table.insert_function_symbol(FunctionSymbol::new(&self.declared_name, true)); - let mut maybe_function_symbol: Option>> = None; - match insert_result { - Ok(function_symbol) => { - maybe_function_symbol = Some(function_symbol); + let function_symbol = match insert_result { + Ok(function_symbol) => function_symbol, + Err(symbol_insert_error) => { + return match symbol_insert_error { + SymbolInsertError::AlreadyDeclared(already_declared) => { + diagnostics.push(Diagnostic::new( + &format!( + "Function {} already declared in current scope.", + already_declared.name() + ), + self.declared_name_source_range.start(), + self.declared_name_source_range.end(), + )); + diagnostics + } + }; } - Err(symbol_insert_error) => match symbol_insert_error { - SymbolInsertError::AlreadyDeclared(already_declared) => { - diagnostics.push(Diagnostic::new( - &format!( - "Function {} already declared in current scope.", - already_declared.name() - ), - self.declared_name_source_range.start(), - self.declared_name_source_range.end(), - )); - } - }, - } + }; symbol_table.push_scope(&format!("extern_function_scope({})", &self.declared_name)); @@ -68,8 +66,7 @@ impl ExternFunction { } } } - maybe_function_symbol - .unwrap() + function_symbol .borrow_mut() .set_parameters(parameter_symbols); @@ -78,13 +75,21 @@ impl ExternFunction { diagnostics } - pub fn check_name_usages(&mut self, _symbol_table: &SymbolTable) -> Vec { - // no-op (for now) - vec![] + pub fn check_name_usages(&mut self, symbol_table: &SymbolTable) -> Vec { + self.parameters + .iter_mut() + .map(|parameter| parameter.check_name_usages(symbol_table)) + .filter_map(Result::err) + .flatten() + .collect() } - pub fn type_check(&mut self, _symbol_table: &SymbolTable) -> Vec { - // no-op (for now) - vec![] + pub fn type_check(&mut self, symbol_table: &SymbolTable) -> Vec { + self.parameters + .iter_mut() + .map(|parameter| parameter.type_check(symbol_table)) + .filter_map(Result::err) + .flatten() + .collect() } } diff --git a/dmc-lib/src/ast/function.rs b/dmc-lib/src/ast/function.rs index 59ad6bf..2da4eb5 100644 --- a/dmc-lib/src/ast/function.rs +++ b/dmc-lib/src/ast/function.rs @@ -1,4 +1,5 @@ use crate::ast::assemble_context::AssembleContext; +use crate::ast::parameter::Parameter; use crate::ast::statement::Statement; use crate::constants_table::ConstantsTable; use crate::diagnostic::Diagnostic; @@ -9,6 +10,7 @@ use crate::symbol_table::{SymbolInsertError, SymbolTable}; pub struct Function { declared_name: String, declared_name_source_range: SourceRange, + parameters: Vec, statements: Vec, } @@ -16,11 +18,13 @@ impl Function { pub fn new( declared_name: &str, declared_name_source_range: SourceRange, + parameters: Vec, statements: Vec, ) -> Self { Self { declared_name: declared_name.to_string(), declared_name_source_range, + parameters, statements, } } @@ -35,36 +39,72 @@ impl Function { pub fn gather_declared_names(&mut self, symbol_table: &mut SymbolTable) -> Vec { let mut diagnostics = vec![]; + // insert function symbol let insert_result = symbol_table.insert_function_symbol(FunctionSymbol::new(self.declared_name(), false)); - if let Err(symbol_insert_error) = insert_result { - match symbol_insert_error { - SymbolInsertError::AlreadyDeclared(already_declared) => { - diagnostics.push(Diagnostic::new( - &format!( - "Function {} already declared in current scope", - already_declared.name() - ), - self.declared_name_source_range.start(), - self.declared_name_source_range.end(), - )); + + // get function symbol if successful + let function_symbol = match insert_result { + Ok(function_symbol) => function_symbol, + Err(symbol_insert_error) => { + return match symbol_insert_error { + SymbolInsertError::AlreadyDeclared(already_declared) => { + diagnostics.push(Diagnostic::new( + &format!( + "Function {} already declared in current scope", + already_declared.name() + ), + self.declared_name_source_range.start(), + self.declared_name_source_range.end(), + )); + diagnostics + } + }; + } + }; + + // handle parameters + symbol_table.push_scope(&format!("parameter_scope({})", self.declared_name)); + let mut parameter_symbols = vec![]; + for parameter in &mut self.parameters { + match parameter.gather_declared_names(symbol_table) { + Ok(parameter_symbol) => { + parameter_symbols.push(parameter_symbol); + } + Err(mut parameter_diagnostics) => { + diagnostics.append(&mut parameter_diagnostics); } } } + function_symbol + .borrow_mut() + .set_parameters(parameter_symbols); - // todo: parameters - - symbol_table.push_scope(&format!("function_scope({})", self.declared_name())); + symbol_table.push_scope(&format!("body_scope({})", self.declared_name)); for statement in &mut self.statements { diagnostics.append(&mut statement.gather_declared_names(symbol_table)); } - symbol_table.pop_scope(); + symbol_table.pop_scope(); // body + symbol_table.pop_scope(); // params diagnostics } pub fn check_name_usages(&mut self, symbol_table: &SymbolTable) -> Vec { let mut diagnostics = vec![]; + + // parameters + diagnostics.append( + &mut self + .parameters + .iter_mut() + .map(|parameter| parameter.check_name_usages(symbol_table)) + .filter_map(|result| result.err()) + .flatten() + .collect(), + ); + + // statements for statement in &mut self.statements { diagnostics.append(&mut statement.check_name_usages(symbol_table)); } @@ -73,9 +113,23 @@ impl Function { pub fn type_check(&mut self, symbol_table: &SymbolTable) -> Vec { let mut diagnostics = vec![]; + + // parameters + diagnostics.append( + &mut self + .parameters + .iter_mut() + .map(|parameter| parameter.type_check(symbol_table)) + .filter_map(|result| result.err()) + .flatten() + .collect(), + ); + + // statements for statement in &mut self.statements { diagnostics.append(&mut statement.type_check(symbol_table)); } + diagnostics } diff --git a/dmc-lib/src/ast/parameter.rs b/dmc-lib/src/ast/parameter.rs index 4075d94..aec3230 100644 --- a/dmc-lib/src/ast/parameter.rs +++ b/dmc-lib/src/ast/parameter.rs @@ -45,4 +45,12 @@ impl Parameter { }, } } + + pub fn check_name_usages(&mut self, symbol_table: &SymbolTable) -> Result<(), Vec> { + Ok(()) // no-op for now + } + + pub fn type_check(&mut self, symbol_table: &SymbolTable) -> Result<(), Vec> { + Ok(()) // no-op for now + } } diff --git a/dmc-lib/src/parser.rs b/dmc-lib/src/parser.rs index 68f70fe..98413a1 100644 --- a/dmc-lib/src/parser.rs +++ b/dmc-lib/src/parser.rs @@ -219,7 +219,9 @@ impl<'a> Parser<'a> { self.expect_advance(TokenKind::Fn)?; let identifier_token = self.expect_advance(TokenKind::Identifier)?; self.expect_advance(TokenKind::LeftParentheses)?; - // add params + + let parameters = self.parameter_list()?; + self.expect_advance(TokenKind::RightParentheses)?; let mut statements = vec![]; let mut diagnostics = vec![]; @@ -248,6 +250,7 @@ impl<'a> Parser<'a> { Ok(Function::new( self.token_text(&identifier_token), SourceRange::new(identifier_token.start(), identifier_token.end()), + parameters, statements, )) } else { @@ -306,7 +309,7 @@ impl<'a> Parser<'a> { diagnostics.append(&mut parameter_diagnostics); } } - if self.lookahead.is_some() && self.peek_lookahead(TokenKind::Comma) { + if self.current.is_some() && self.peek_current(TokenKind::Comma) { self.advance(); } } @@ -480,7 +483,17 @@ mod smoke_tests { #[test] fn extern_fn_with_param() { - smoke_test("extern fn println(message: Any)") + smoke_test("extern fn println(message: Any)"); + } + + #[test] + fn fn_with_param() { + smoke_test("fn foo(bar: Int) end"); + } + + #[test] + fn fn_with_params() { + smoke_test("fn foo(bar: Int, baz: Int) end"); } }