From 12a3a61156562d8c6331e2662ae913e69d49e49a Mon Sep 17 00:00:00 2001 From: Jesse Brault Date: Fri, 31 Oct 2025 12:14:33 -0500 Subject: [PATCH] Work on functions and parameter name resolution. --- src/name_analysis/first_pass.rs | 109 +++++++++++++----- src/name_analysis/mod.rs | 24 ++++ .../symbol/class_member_symbol.rs | 9 +- src/name_analysis/symbol/lv_symbol.rs | 28 +++++ src/name_analysis/symbol/mod.rs | 1 + src/name_analysis/symbol/parameter_symbol.rs | 16 ++- src/name_analysis/symbol/variable_symbol.rs | 15 ++- src/name_analysis/symbol_table/mod.rs | 22 ++++ src/name_analysis/symbol_table/scope.rs | 38 +++++- src/name_analysis/symbol_table/symbol_tree.rs | 9 ++ src/std_core/mod.rs | 11 +- 11 files changed, 236 insertions(+), 46 deletions(-) create mode 100644 src/name_analysis/symbol/lv_symbol.rs diff --git a/src/name_analysis/first_pass.rs b/src/name_analysis/first_pass.rs index 2d23941..6ffc7ee 100644 --- a/src/name_analysis/first_pass.rs +++ b/src/name_analysis/first_pass.rs @@ -1,7 +1,7 @@ use crate::ast::node::{ CompilationUnit, ConcreteUseStatement, ConcreteUseStatementSuffix, Function, FunctionBody, - GenericParameters, Identifier, IdentifierOrFqn, Module, ModuleLevelDeclaration, Parameters, - PrimitiveType, ReturnType, StarUseStatement, TypeUse, TypedArray, UseStatement, + GenericParameters, Identifier, IdentifierOrFqn, Module, ModuleLevelDeclaration, Parameter, + Parameters, PrimitiveType, ReturnType, StarUseStatement, TypeUse, TypedArray, UseStatement, UseStatementIdentifier, UseStatementPrefix, }; use crate::diagnostic::DmDiagnostic; @@ -14,7 +14,7 @@ use crate::name_analysis::symbol::primitive_type_symbol::PrimitiveTypeSymbol; use crate::name_analysis::symbol::source_definition::SourceDefinition; use crate::name_analysis::symbol::type_symbol::TypeSymbol; use crate::name_analysis::symbol::use_symbol::{ConcreteUseSymbol, StarUseSymbol}; -use crate::name_analysis::symbol_table::SymbolTable; +use crate::name_analysis::symbol_table::{SymbolInsertError, SymbolTable}; use crate::name_analysis::util::{ format_fqn, handle_insert_error, handle_lookup_error, join_fqn_parts, }; @@ -243,8 +243,6 @@ fn na_p1_function( symbol_table: &mut SymbolTable, diagnostics: &mut Vec, ) -> Option>> { - symbol_table.push_scope(&format!("FunctionScope {}", function.identifier().name())); - let to_insert = FunctionSymbol::new( &symbol_table.resolve_fqn(Rc::from(function.identifier().name())), function.is_public(), @@ -253,25 +251,6 @@ fn na_p1_function( ); let function_symbol = match symbol_table.insert_function_symbol(to_insert) { Ok(function_symbol) => { - { - let mut as_ref_mut = function_symbol.borrow_mut(); - // generics - na_p1_generic_parameters(function.generics_mut(), symbol_table, diagnostics); - - // parameters - as_ref_mut.set_parameter_symbols(na_p1_parameters( - function.parameters_mut(), - symbol_table, - diagnostics, - )); - - // return type - let return_type = - na_p1_return_type(function.return_type_mut(), symbol_table, diagnostics); - if let Some(type_symbol) = return_type { - as_ref_mut.set_return_type(type_symbol); - } - } Some(function_symbol) } Err(symbol_insert_error) => { @@ -285,8 +264,37 @@ fn na_p1_function( None } }; + + if function_symbol.is_some() { + let mut as_ref_mut = function_symbol.as_ref().unwrap().borrow_mut(); - symbol_table.pop_scope(); + // push a scope for this function + symbol_table.push_scope(&format!("FunctionScope {}", function.identifier().name())); + + // generics + na_p1_generic_parameters(function.generics_mut(), symbol_table, diagnostics); + + // parameters + as_ref_mut.set_parameter_symbols(na_p1_parameters( + function.parameters_mut(), + symbol_table, + diagnostics, + )); + + // return type + let return_type = + na_p1_return_type(function.return_type_mut(), symbol_table, diagnostics); + if let Some(type_symbol) = return_type { + as_ref_mut.set_return_type(type_symbol); + } + + symbol_table.push_scope(&format!("FunctionBodyScope {}", function.identifier().name())); + + na_p1_function_body(function.function_body_mut(), symbol_table, diagnostics); + + symbol_table.pop_scope(); + symbol_table.pop_scope(); + } function_symbol } @@ -296,7 +304,40 @@ fn na_p1_parameters( symbol_table: &mut SymbolTable, diagnostics: &mut Vec, ) -> Vec>> { - todo!() + parameters + .parameters_mut() + .map(|parameter| na_p1_parameter(parameter, symbol_table, diagnostics)) + .filter(Option::is_some) + .map(Option::unwrap) + .collect() +} + +fn na_p1_parameter( + parameter: &mut Parameter, + symbol_table: &mut SymbolTable, + diagnostics: &mut Vec, +) -> Option>> { + let parameter_type_symbol = na_p1_type_use(parameter.type_use_mut(), symbol_table, diagnostics); + let to_insert = ParameterSymbol::new( + parameter.identifier().name(), + Some(SourceDefinition::from_identifier(parameter.identifier())), + parameter_type_symbol, + ); + match symbol_table.insert_parameter_symbol(to_insert) { + Ok(parameter_symbol) => { + Some(parameter_symbol) + } + Err(symbol_insert_error) => { + handle_insert_error( + symbol_insert_error, + parameter.identifier().name(), + parameter.identifier().file_id(), + parameter.identifier().range(), + diagnostics, + ); + None + } + } } fn na_p1_return_type( @@ -430,5 +471,19 @@ fn na_p1_function_body( symbol_table: &mut SymbolTable, diagnostics: &mut Vec, ) { - todo!() + match function_body { + FunctionBody::FunctionAliasBody(alias_body) => { + // no-op, resolve in pass 2 + } + FunctionBody::FunctionEqualsBody(equals_body) => { + // see below + } + FunctionBody::FunctionBlockBody(block_body) => { + // we need to do all insertion/resolution in pass 2, because we + // might call functions/use classes/etc from the same compilation + // unit which haven't been defined yet. So the strategy is to set + // the scope id for the body and then in pass 2, set the symbol + // table's current scope to that id. + } + } } diff --git a/src/name_analysis/mod.rs b/src/name_analysis/mod.rs index 3e00c8e..7359e43 100644 --- a/src/name_analysis/mod.rs +++ b/src/name_analysis/mod.rs @@ -71,6 +71,8 @@ mod tests { use codespan_reporting::term::termcolor::{ColorChoice, StandardStream}; use pest::Parser; use std::collections::HashMap; + use std::rc::Rc; + use crate::name_analysis::symbol::use_symbol::StarUseSymbol; fn parse_compilation_units<'a>( files: &mut SimpleFiles<&'a str, &'a str>, @@ -189,4 +191,26 @@ mod tests { )]); assert_number_of_diagnostics(sources, &mut SymbolTable::new(), 1); } + + #[test] + fn sees_println() { + let sources = HashMap::from([( + "main.dm", + " + fn main(args: Array) + println args + end + " + )]); + let mut symbol_table = SymbolTable::new(); + let global_std_core_use = StarUseSymbol::new( + &[Rc::from("std"), Rc::from("core")], + None + ); + symbol_table.insert_star_use_symbol(global_std_core_use) + .expect("Failed to insert star use symbol."); + + add_std_core_symbols(&mut symbol_table).expect("Failed to add std/core symbols."); + assert_no_diagnostics(sources, &mut symbol_table); + } } diff --git a/src/name_analysis/symbol/class_member_symbol.rs b/src/name_analysis/symbol/class_member_symbol.rs index fc529de..de59eb0 100644 --- a/src/name_analysis/symbol/class_member_symbol.rs +++ b/src/name_analysis/symbol/class_member_symbol.rs @@ -1,4 +1,5 @@ use crate::name_analysis::symbol::source_definition::SourceDefinition; +use crate::name_analysis::symbol::Symbol; use std::fmt::{Debug, Formatter}; #[derive(Clone)] @@ -23,11 +24,11 @@ impl ClassMemberSymbol { source_definition, } } - + pub fn is_public(&self) -> bool { self.is_public } - + pub fn is_mut(&self) -> bool { self.is_mut } @@ -35,8 +36,10 @@ impl ClassMemberSymbol { pub fn declared_name(&self) -> &str { &self.declared_name } +} - pub fn source_definition(&self) -> Option<&SourceDefinition> { +impl Symbol for ClassMemberSymbol { + fn source_definition(&self) -> Option<&SourceDefinition> { self.source_definition.as_ref() } } diff --git a/src/name_analysis/symbol/lv_symbol.rs b/src/name_analysis/symbol/lv_symbol.rs new file mode 100644 index 0000000..d174f3d --- /dev/null +++ b/src/name_analysis/symbol/lv_symbol.rs @@ -0,0 +1,28 @@ +use std::cell::RefCell; +use std::rc::Rc; +use crate::name_analysis::symbol::class_member_symbol::ClassMemberSymbol; +use crate::name_analysis::symbol::parameter_symbol::ParameterSymbol; +use crate::name_analysis::symbol::Symbol; +use crate::name_analysis::symbol::variable_symbol::VariableSymbol; + +pub enum LVSymbol { + ClassMember(Rc>), + Parameter(Rc>), + Variable(Rc>), +} + +impl LVSymbol { + pub fn to_symbol(self) -> Rc> { + match self { + LVSymbol::ClassMember(class_member_symbol) => { + class_member_symbol as Rc> + } + LVSymbol::Parameter(parameter_symbol) => { + parameter_symbol as Rc> + } + LVSymbol::Variable(variable_symbol) => { + variable_symbol as Rc> + } + } + } +} \ No newline at end of file diff --git a/src/name_analysis/symbol/mod.rs b/src/name_analysis/symbol/mod.rs index e9a090a..2fc8bf4 100644 --- a/src/name_analysis/symbol/mod.rs +++ b/src/name_analysis/symbol/mod.rs @@ -3,6 +3,7 @@ pub mod class_symbol; pub mod function_symbol; pub mod generic_type_symbol; pub mod interface_symbol; +pub mod lv_symbol; pub mod module_level_symbol; pub mod module_symbol; pub mod parameter_symbol; diff --git a/src/name_analysis/symbol/parameter_symbol.rs b/src/name_analysis/symbol/parameter_symbol.rs index a2d9cd4..a616390 100644 --- a/src/name_analysis/symbol/parameter_symbol.rs +++ b/src/name_analysis/symbol/parameter_symbol.rs @@ -1,9 +1,11 @@ use crate::name_analysis::symbol::source_definition::SourceDefinition; use crate::name_analysis::symbol::type_symbol::TypeSymbol; +use crate::name_analysis::symbol::Symbol; use std::fmt::{Debug, Formatter}; +use std::rc::Rc; pub struct ParameterSymbol { - declared_name: String, + declared_name: Rc, source_definition: Option, type_symbol: Option, } @@ -14,8 +16,8 @@ impl ParameterSymbol { source_definition: Option, type_symbol: Option, ) -> Self { - ParameterSymbol { - declared_name: declared_name.to_string(), + Self { + declared_name: Rc::from(declared_name), source_definition, type_symbol, } @@ -25,7 +27,13 @@ impl ParameterSymbol { &self.declared_name } - pub fn source_definition(&self) -> Option<&SourceDefinition> { + pub fn declared_name_owned(&self) -> Rc { + self.declared_name.clone() + } +} + +impl Symbol for ParameterSymbol { + fn source_definition(&self) -> Option<&SourceDefinition> { self.source_definition.as_ref() } } diff --git a/src/name_analysis/symbol/variable_symbol.rs b/src/name_analysis/symbol/variable_symbol.rs index fbef0f6..2fd2e9e 100644 --- a/src/name_analysis/symbol/variable_symbol.rs +++ b/src/name_analysis/symbol/variable_symbol.rs @@ -1,4 +1,5 @@ use crate::name_analysis::symbol::source_definition::SourceDefinition; +use crate::name_analysis::symbol::Symbol; use std::fmt::{Debug, Formatter}; #[derive(Clone)] @@ -9,7 +10,11 @@ pub struct VariableSymbol { } impl VariableSymbol { - pub fn new(declared_name: &str, is_mutable: bool, source_definition: Option) -> Self { + pub fn new( + declared_name: &str, + is_mutable: bool, + source_definition: Option, + ) -> Self { VariableSymbol { declared_name: declared_name.to_string(), is_mutable, @@ -20,12 +25,14 @@ impl VariableSymbol { pub fn declared_name(&self) -> &str { &self.declared_name } - + pub fn is_mutable(&self) -> bool { self.is_mutable } - - pub fn source_definition(&self) -> Option<&SourceDefinition> { +} + +impl Symbol for VariableSymbol { + fn source_definition(&self) -> Option<&SourceDefinition> { self.source_definition.as_ref() } } diff --git a/src/name_analysis/symbol_table/mod.rs b/src/name_analysis/symbol_table/mod.rs index bd787b9..cc38cea 100644 --- a/src/name_analysis/symbol_table/mod.rs +++ b/src/name_analysis/symbol_table/mod.rs @@ -1,6 +1,7 @@ use crate::name_analysis::symbol::function_symbol::FunctionSymbol; use crate::name_analysis::symbol::generic_type_symbol::GenericTypeSymbol; use crate::name_analysis::symbol::module_symbol::ModuleSymbol; +use crate::name_analysis::symbol::parameter_symbol::ParameterSymbol; use crate::name_analysis::symbol::type_symbol::TypeSymbol; use crate::name_analysis::symbol::usable_symbol::UsableSymbol; use crate::name_analysis::symbol::use_symbol::{ConcreteUseSymbol, StarUseSymbol}; @@ -112,6 +113,10 @@ impl SymbolTable { }) } + pub fn register_module(&mut self, fqn_parts: &[&str]) { + self.symbol_tree.register_module_by_fqn_parts(fqn_parts); + } + pub fn find_usable_symbols_by_base_fqn( &self, fqn_parts: &[Rc], @@ -205,6 +210,23 @@ impl SymbolTable { } } + pub fn insert_parameter_symbol( + &mut self, + parameter_symbol: ParameterSymbol, + ) -> Result>, SymbolInsertError> { + if let Some(defined_symbol) = self + .current_scope() + .find_lv_symbol(parameter_symbol.declared_name()) + { + Err(SymbolAlreadyDefined(defined_symbol.to_symbol())) + } else { + let inserted = self + .current_scope_mut() + .insert_parameter_symbol(parameter_symbol); + Ok(inserted) + } + } + pub fn lookup_type(&self, declared_name: &str) -> Result { let mut current_scope: Option<&Scope> = Some(self.current_scope()); while let Some(scope) = current_scope.take() { diff --git a/src/name_analysis/symbol_table/scope.rs b/src/name_analysis/symbol_table/scope.rs index cee7960..cc75a7a 100644 --- a/src/name_analysis/symbol_table/scope.rs +++ b/src/name_analysis/symbol_table/scope.rs @@ -3,6 +3,7 @@ use crate::name_analysis::symbol::class_symbol::ClassSymbol; use crate::name_analysis::symbol::function_symbol::FunctionSymbol; use crate::name_analysis::symbol::generic_type_symbol::GenericTypeSymbol; use crate::name_analysis::symbol::interface_symbol::InterfaceSymbol; +use crate::name_analysis::symbol::lv_symbol::LVSymbol; use crate::name_analysis::symbol::module_level_symbol::ModuleLevelSymbol; use crate::name_analysis::symbol::module_symbol::ModuleSymbol; use crate::name_analysis::symbol::parameter_symbol::ParameterSymbol; @@ -26,9 +27,9 @@ pub struct Scope { class_symbols: HashMap, Rc>>, generic_symbols: HashMap, Rc>>, function_symbols: HashMap, Rc>>, - parameter_symbols: HashMap, ParameterSymbol>, - variable_symbols: HashMap, VariableSymbol>, - class_member_symbols: HashMap, ClassMemberSymbol>, + parameter_symbols: HashMap, Rc>>, + variable_symbols: HashMap, Rc>>, + class_member_symbols: HashMap, Rc>>, debug_name: String, } @@ -125,12 +126,23 @@ impl Scope { pub fn get_class_symbol(&self, declared_name: &str) -> Option<&Rc>> { self.class_symbols.get(declared_name) } - - pub fn insert_generic_type_symbol(&mut self, symbol: GenericTypeSymbol) -> Rc> { + + pub fn insert_generic_type_symbol( + &mut self, + symbol: GenericTypeSymbol, + ) -> Rc> { let key = symbol.declared_name_owned(); insert_symbol!(self.generic_symbols, symbol, key) } + pub fn insert_parameter_symbol( + &mut self, + symbol: ParameterSymbol, + ) -> Rc> { + let key = symbol.declared_name_owned(); + insert_symbol!(self.parameter_symbols, symbol, key) + } + pub fn find_module_level_symbol(&self, declared_name: &str) -> Option { self.module_symbols .get(declared_name) @@ -168,6 +180,22 @@ impl Scope { }) } + pub fn find_lv_symbol(&self, declared_name: &str) -> Option { + self.class_member_symbols + .get(declared_name) + .map(|class_member_symbol| LVSymbol::ClassMember(class_member_symbol.clone())) + .or_else(|| { + self.parameter_symbols + .get(declared_name) + .map(|parameter_symbol| LVSymbol::Parameter(parameter_symbol.clone())) + }) + .or_else(|| { + self.variable_symbols + .get(declared_name) + .map(|variable_symbol| LVSymbol::Variable(variable_symbol.clone())) + }) + } + pub fn debug_name(&self) -> &str { &self.debug_name } diff --git a/src/name_analysis/symbol_table/symbol_tree.rs b/src/name_analysis/symbol_table/symbol_tree.rs index 3734872..f0dbadc 100644 --- a/src/name_analysis/symbol_table/symbol_tree.rs +++ b/src/name_analysis/symbol_table/symbol_tree.rs @@ -63,6 +63,15 @@ impl SymbolTree { self.recurse_register_module(&module_symbol.borrow().fqn_parts()); } + pub fn register_module_by_fqn_parts(&mut self, fqn_parts: &[&str]) { + self.recurse_register_module( + &fqn_parts + .iter() + .map(|part| Rc::from(*part)) + .collect::>>(), + ); + } + fn recurse_register_module(&mut self, fqn_parts: &[Rc]) { if fqn_parts.len() == 0 { panic!("Unable to register module fqn with no parts.") diff --git a/src/std_core/mod.rs b/src/std_core/mod.rs index f79a039..13d8612 100644 --- a/src/std_core/mod.rs +++ b/src/std_core/mod.rs @@ -7,11 +7,16 @@ use std::cell::RefCell; use std::rc::Rc; pub fn add_std_core_symbols(symbol_table: &mut SymbolTable) -> Result<(), SymbolInsertError> { + symbol_table.register_module(&["std"]); + symbol_table.register_module(&["std", "core"]); + symbol_table.set_current_fqn(&vec!["std", "core"]); - let println_msg_symbol = ParameterSymbol::new("msg", None, Some( - TypeSymbol::Primitive(PrimitiveTypeSymbol::Any) - )); + let println_msg_symbol = ParameterSymbol::new( + "msg", + None, + Some(TypeSymbol::Primitive(PrimitiveTypeSymbol::Any)), + ); let println_symbol = FunctionSymbol::with_parameters_and_return_type( &symbol_table.resolve_fqn(Rc::from("println")),