From d653d26e14301f49f7d3065b785b4c36c1e41bce Mon Sep 17 00:00:00 2001 From: Jesse Brault Date: Tue, 28 Oct 2025 10:43:42 -0500 Subject: [PATCH] Work on star-use symbols. --- src/name_analysis/first_pass.rs | 49 ++++++++++---- src/name_analysis/second_pass.rs | 48 ++++++++++---- src/name_analysis/symbol/source_definition.rs | 11 +++- src/name_analysis/symbol/usable_symbol.rs | 2 +- src/name_analysis/symbol/use_symbol.rs | 10 +++ src/name_analysis/symbol_table/mod.rs | 25 ++++++-- src/name_analysis/symbol_table/symbol_tree.rs | 64 ++++++++++++++----- src/name_analysis/util.rs | 10 ++- src/parser/ast.yaml | 4 ++ 9 files changed, 173 insertions(+), 50 deletions(-) diff --git a/src/name_analysis/first_pass.rs b/src/name_analysis/first_pass.rs index 2dccb04..c107e5b 100644 --- a/src/name_analysis/first_pass.rs +++ b/src/name_analysis/first_pass.rs @@ -1,9 +1,4 @@ -use crate::ast::node::{ - CompilationUnit, ConcreteUseStatement, ConcreteUseStatementSuffix, Function, FunctionBody, - GenericParameters, Identifier, IdentifierOrFqn, Module, ModuleLevelDeclaration, Parameters, - PrimitiveType, ReturnType, TypeUse, TypedArray, UseStatement, UseStatementIdentifier, - UseStatementPrefix, -}; +use crate::ast::node::{CompilationUnit, ConcreteUseStatement, ConcreteUseStatementSuffix, Function, FunctionBody, GenericParameters, Identifier, IdentifierOrFqn, Module, ModuleLevelDeclaration, Parameters, PrimitiveType, ReturnType, StarUseStatement, TypeUse, TypedArray, UseStatement, UseStatementIdentifier, UseStatementPrefix}; use crate::diagnostic::DmDiagnostic; use crate::name_analysis::symbol::function_symbol::FunctionSymbol; use crate::name_analysis::symbol::generic_type_symbol::GenericTypeSymbol; @@ -13,9 +8,9 @@ use crate::name_analysis::symbol::parameter_symbol::ParameterSymbol; 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; -use crate::name_analysis::symbol_table::SymbolTable; -use crate::name_analysis::util::{format_fqn, handle_insert_error, handle_lookup_error}; +use crate::name_analysis::symbol::use_symbol::{ConcreteUseSymbol, StarUseSymbol}; +use crate::name_analysis::symbol_table::{SymbolInsertError, SymbolTable}; +use crate::name_analysis::util::{format_fqn, handle_insert_error, handle_lookup_error, join_fqn_parts}; use std::cell::RefCell; use std::rc::Rc; @@ -60,7 +55,7 @@ fn na_p1_use_statement( na_p1_concrete_use_statement(concrete_use_statement, symbol_table, diagnostics); } UseStatement::StarUseStatement(star_use_statement) => { - todo!() + na_p1_star_use_statement(star_use_statement, symbol_table, diagnostics); } } } @@ -100,7 +95,7 @@ fn na_p1_concrete_use_statement( } fn handle_concrete_use_statement_identifier( - prefixes: &Vec>, + prefixes: &[Rc], use_statement_identifier: &mut UseStatementIdentifier, symbol_table: &mut SymbolTable, diagnostics: &mut Vec, @@ -134,6 +129,38 @@ fn handle_concrete_use_statement_identifier( } } +fn na_p1_star_use_statement( + star_use_statement: &mut StarUseStatement, + symbol_table: &mut SymbolTable, + diagnostics: &mut Vec, +) { + let fqn_parts = star_use_statement + .prefixes() + .map(UseStatementPrefix::identifier) + .map(Identifier::name) + .map(|name| Rc::from(name)) + .collect::>>(); + + let to_insert = StarUseSymbol::new( + &fqn_parts, + Some(SourceDefinition::from_star_use_statement(star_use_statement)) + ); + match symbol_table.insert_star_use_symbol(to_insert) { + Ok(star_use_symbol) => { + star_use_statement.set_symbol(star_use_symbol); + } + Err(symbol_insert_error) => { + handle_insert_error( + symbol_insert_error, + &join_fqn_parts(&fqn_parts), + star_use_statement.file_id(), + star_use_statement.range(), + diagnostics, + ); + } + } +} + fn na_p1_module_level_declaration( module_level_declaration: &mut ModuleLevelDeclaration, symbol_table: &mut SymbolTable, diff --git a/src/name_analysis/second_pass.rs b/src/name_analysis/second_pass.rs index a6d2ed8..3cd90ab 100644 --- a/src/name_analysis/second_pass.rs +++ b/src/name_analysis/second_pass.rs @@ -1,10 +1,11 @@ use crate::ast::node::{ - CompilationUnit, ConcreteUseStatement, ConcreteUseStatementSuffix, Identifier, UseStatement, - UseStatementIdentifier, UseStatementPrefix, + CompilationUnit, ConcreteUseStatement, ConcreteUseStatementSuffix, Identifier, + StarUseStatement, UseStatement, UseStatementIdentifier, UseStatementPrefix, }; use crate::diagnostic::DmDiagnostic; use crate::name_analysis::symbol_table::{SymbolLookupError, SymbolTable}; -use crate::name_analysis::util::handle_lookup_error; +use crate::name_analysis::util::{handle_lookup_error, join_fqn_parts}; +use std::rc::Rc; pub fn na_p2_compilation_unit( compilation_unit: &mut CompilationUnit, @@ -29,7 +30,7 @@ fn na_p2_use_statement( na_p2_concrete_use_statement(concrete_use_statement, symbol_table, diagnostics); } UseStatement::StarUseStatement(star_use_statement) => { - todo!() + na_p2_star_use_statement(star_use_statement, symbol_table, diagnostics); } } } @@ -39,12 +40,12 @@ fn na_p2_concrete_use_statement( symbol_table: &SymbolTable, diagnostics: &mut Vec, ) { - let base_fqn_parts: Vec = concrete_use_statement + let base_fqn_parts = concrete_use_statement .prefixes() .map(UseStatementPrefix::identifier) .map(Identifier::name) - .map(ToString::to_string) - .collect(); + .map(Rc::from) + .collect::>>(); match concrete_use_statement.suffix_mut() { ConcreteUseStatementSuffix::UseStatementIdentifier(use_statement_identifier) => { @@ -69,17 +70,14 @@ fn na_p2_concrete_use_statement( } fn handle_concrete_use_statement_identifier( - base_fqn_parts: &[String], + base_fqn_parts: &[Rc], use_statement_identifier: &mut UseStatementIdentifier, symbol_table: &SymbolTable, diagnostics: &mut Vec, ) { let fqn_parts = { - let mut all_parts: Vec<&str> = vec![]; - for part in base_fqn_parts { - all_parts.push(part); - } - all_parts.push(use_statement_identifier.identifier().name()); + let mut all_parts = base_fqn_parts.to_vec(); + all_parts.push(Rc::from(use_statement_identifier.identifier().name())); all_parts }; @@ -93,10 +91,32 @@ fn handle_concrete_use_statement_identifier( } else { handle_lookup_error( SymbolLookupError::NoDefinition, - &fqn_parts.join("::"), + &join_fqn_parts(&fqn_parts), use_statement_identifier.identifier().file_id(), use_statement_identifier.identifier().range(), diagnostics, ); } } + +fn na_p2_star_use_statement( + star_use_statement: &mut StarUseStatement, + symbol_table: &SymbolTable, + diagnostics: &mut Vec, +) { + let mut symbol_ref_mut = star_use_statement.symbol().unwrap().borrow_mut(); + match symbol_table.find_usable_symbols_by_base_fqn(symbol_ref_mut.fqn_parts()) { + Ok(usable_symbols) => { + symbol_ref_mut.set_resolved_symbols(usable_symbols); + } + Err(symbol_lookup_error) => { + handle_lookup_error( + symbol_lookup_error, + &join_fqn_parts(symbol_ref_mut.fqn_parts()), + star_use_statement.file_id(), + star_use_statement.range(), + diagnostics, + ); + } + } +} diff --git a/src/name_analysis/symbol/source_definition.rs b/src/name_analysis/symbol/source_definition.rs index 5f96d6b..02f29e9 100644 --- a/src/name_analysis/symbol/source_definition.rs +++ b/src/name_analysis/symbol/source_definition.rs @@ -1,4 +1,4 @@ -use crate::ast::node::{Identifier, Operator}; +use crate::ast::node::{Identifier, Operator, StarUseStatement}; use std::range::Range; #[derive(Clone, Debug)] @@ -14,7 +14,7 @@ impl SourceDefinition { range: identifier.range(), } } - + pub fn from_operator(operator: &Operator) -> Self { Self { file_id: operator.file_id(), @@ -22,6 +22,13 @@ impl SourceDefinition { } } + pub fn from_star_use_statement(star_use_statement: &StarUseStatement) -> Self { + Self { + file_id: star_use_statement.file_id(), + range: star_use_statement.range(), + } + } + pub fn file_id(&self) -> usize { self.file_id } diff --git a/src/name_analysis/symbol/usable_symbol.rs b/src/name_analysis/symbol/usable_symbol.rs index 62de51d..3c7219b 100644 --- a/src/name_analysis/symbol/usable_symbol.rs +++ b/src/name_analysis/symbol/usable_symbol.rs @@ -5,7 +5,7 @@ use crate::name_analysis::symbol::Symbol; use std::cell::RefCell; use std::rc::Rc; -#[derive(Debug)] +#[derive(Debug, Clone)] pub enum UsableSymbol { Interface(Rc>), Class(Rc>), diff --git a/src/name_analysis/symbol/use_symbol.rs b/src/name_analysis/symbol/use_symbol.rs index 16a950c..391da08 100644 --- a/src/name_analysis/symbol/use_symbol.rs +++ b/src/name_analysis/symbol/use_symbol.rs @@ -76,6 +76,7 @@ impl Debug for ConcreteUseSymbol { pub struct StarUseSymbol { fqn_parts: Vec>, source_definition: Option, + resolved_symbols: Vec, } impl StarUseSymbol { @@ -83,12 +84,21 @@ impl StarUseSymbol { Self { fqn_parts: fqn_parts.to_vec(), source_definition, + resolved_symbols: vec![], } } pub fn fqn_parts(&self) -> &[Rc] { &self.fqn_parts } + + pub fn resolved_symbols(&self) -> &[UsableSymbol] { + &self.resolved_symbols + } + + pub fn set_resolved_symbols(&mut self, symbols: Vec) { + self.resolved_symbols = symbols; + } } impl Symbol for StarUseSymbol { diff --git a/src/name_analysis/symbol_table/mod.rs b/src/name_analysis/symbol_table/mod.rs index ac94432..bd787b9 100644 --- a/src/name_analysis/symbol_table/mod.rs +++ b/src/name_analysis/symbol_table/mod.rs @@ -1,4 +1,5 @@ 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::type_symbol::TypeSymbol; use crate::name_analysis::symbol::usable_symbol::UsableSymbol; @@ -12,7 +13,6 @@ use std::cell::RefCell; use std::fmt::Display; use std::ops::Deref; use std::rc::Rc; -use crate::name_analysis::symbol::generic_type_symbol::GenericTypeSymbol; pub(self) mod fqn_context; mod scope; @@ -25,6 +25,7 @@ pub enum SymbolInsertError { pub enum SymbolLookupError { NoDefinition, + NoSuchNamespace, } #[derive(Debug)] @@ -95,7 +96,7 @@ impl SymbolTable { parts } - pub fn find_usable_symbol(&self, fqn_parts: &[&str]) -> Option { + pub fn find_usable_symbol(&self, fqn_parts: &[Rc]) -> Option { self.symbol_tree .find_interface(fqn_parts) .map(|interface_symbol| UsableSymbol::Interface(interface_symbol)) @@ -111,6 +112,13 @@ impl SymbolTable { }) } + pub fn find_usable_symbols_by_base_fqn( + &self, + fqn_parts: &[Rc], + ) -> Result, SymbolLookupError> { + self.symbol_tree.find_all_by_base_fqn(fqn_parts) + } + fn current_scope(&self) -> &Scope { &self.scopes[self.current_scope_id] } @@ -179,15 +187,20 @@ impl SymbolTable { Ok(inserted) } } - + pub fn insert_generic_type_symbol( &mut self, generic_type_symbol: GenericTypeSymbol, ) -> Result>, SymbolInsertError> { - if let Some(defined_symbol) = self.current_scope().find_type_symbol(generic_type_symbol.declared_name()) { + if let Some(defined_symbol) = self + .current_scope() + .find_type_symbol(generic_type_symbol.declared_name()) + { Err(SymbolAlreadyDefined(defined_symbol.to_symbol())) } else { - let inserted = self.current_scope_mut().insert_generic_type_symbol(generic_type_symbol); + let inserted = self + .current_scope_mut() + .insert_generic_type_symbol(generic_type_symbol); Ok(inserted) } } @@ -205,7 +218,7 @@ impl SymbolTable { } Err(SymbolLookupError::NoDefinition) } - + pub fn lookup_type_by_fqn(&self, fqn_parts: &[&str]) -> Result { todo!() } diff --git a/src/name_analysis/symbol_table/symbol_tree.rs b/src/name_analysis/symbol_table/symbol_tree.rs index fb624d9..3734872 100644 --- a/src/name_analysis/symbol_table/symbol_tree.rs +++ b/src/name_analysis/symbol_table/symbol_tree.rs @@ -2,6 +2,8 @@ use crate::name_analysis::symbol::class_symbol::ClassSymbol; use crate::name_analysis::symbol::function_symbol::FunctionSymbol; use crate::name_analysis::symbol::interface_symbol::InterfaceSymbol; use crate::name_analysis::symbol::module_symbol::ModuleSymbol; +use crate::name_analysis::symbol::usable_symbol::UsableSymbol; +use crate::name_analysis::symbol_table::SymbolLookupError; use std::cell::RefCell; use std::collections::HashMap; use std::rc::Rc; @@ -24,35 +26,35 @@ impl SymbolTree { } } - pub fn find_class(&self, fqn_parts: &[&str]) -> Option>> { + pub fn find_class(&self, fqn_parts: &[Rc]) -> Option>> { match fqn_parts.len() { 0 => None, - 1 => self.classes.get(fqn_parts[0]).cloned(), + 1 => self.classes.get(&fqn_parts[0]).cloned(), _ => self .children - .get(fqn_parts[0]) + .get(&fqn_parts[0]) .and_then(|child_tree| child_tree.find_class(&fqn_parts[1..])), } } - pub fn find_interface(&self, fqn_parts: &[&str]) -> Option>> { + pub fn find_interface(&self, fqn_parts: &[Rc]) -> Option>> { match fqn_parts.len() { 0 => None, - 1 => self.interfaces.get(fqn_parts[0]).cloned(), + 1 => self.interfaces.get(&fqn_parts[0]).cloned(), _ => self .children - .get(fqn_parts[0]) + .get(&fqn_parts[0]) .and_then(|child_tree| child_tree.find_interface(&fqn_parts[1..])), } } - pub fn find_function(&self, fqn_parts: &[&str]) -> Option>> { + pub fn find_function(&self, fqn_parts: &[Rc]) -> Option>> { match fqn_parts.len() { 0 => None, - 1 => self.functions.get(fqn_parts[0]).cloned(), + 1 => self.functions.get(&fqn_parts[0]).cloned(), _ => self .children - .get(fqn_parts[0]) + .get(&fqn_parts[0]) .and_then(|child_tree| child_tree.find_function(&fqn_parts[1..])), } } @@ -79,15 +81,19 @@ impl SymbolTree { } } } - + pub fn register_function(&mut self, function_symbol: Rc>) { let fqn_parts = function_symbol.borrow().fqn_parts_owned(); - self.recurse_register_function(function_symbol, &fqn_parts); + self.recurse_register_function(function_symbol, &fqn_parts); } - - fn recurse_register_function(&mut self, function_symbol: Rc>, fqn_parts: &[Rc]) { + + fn recurse_register_function( + &mut self, + function_symbol: Rc>, + fqn_parts: &[Rc], + ) { if fqn_parts.len() == 0 { - panic!("Unable to register function fqn with no parts.") + panic!("Unable to register function fqn with no parts."); } if fqn_parts.len() == 1 { self.functions.insert(fqn_parts[0].clone(), function_symbol); @@ -100,5 +106,33 @@ impl SymbolTree { } } } - + + pub fn find_all_by_base_fqn( + &self, + fqn_parts: &[Rc], + ) -> Result, SymbolLookupError> { + match fqn_parts.len() { + 0 => { + let mut all_symbols: Vec = vec![]; + for interface_symbol in self.interfaces.values() { + all_symbols.push(UsableSymbol::Interface(interface_symbol.clone())); + } + for class_symbol in self.classes.values() { + all_symbols.push(UsableSymbol::Class(class_symbol.clone())); + } + for function_symbol in self.functions.values() { + all_symbols.push(UsableSymbol::Function(function_symbol.clone())); + } + Ok(all_symbols) + } + _ => { + if self.children.contains_key(fqn_parts[0].as_ref()) { + let child = self.children.get(fqn_parts[0].as_ref()).unwrap(); + child.find_all_by_base_fqn(fqn_parts) + } else { + Err(SymbolLookupError::NoSuchNamespace) + } + } + } + } } diff --git a/src/name_analysis/util.rs b/src/name_analysis/util.rs index ce24193..0347fdf 100644 --- a/src/name_analysis/util.rs +++ b/src/name_analysis/util.rs @@ -45,11 +45,19 @@ pub fn handle_lookup_error( match err { SymbolLookupError::NoDefinition => { let diagnostic = Diagnostic::error() - .with_message(format!("No such symbol '{}' in scope.", error_symbol_name,)) + .with_message(format!("No such symbol '{}' in scope.", error_symbol_name)) .with_label( Label::primary(error_file_id, error_range).with_message("Symbol used here."), ); diagnostics.push(diagnostic); + }, + SymbolLookupError::NoSuchNamespace => { + let diagnostic = Diagnostic::error() + .with_message(format!("No such namespace '{}' found", error_symbol_name)) + .with_label( + Label::primary(error_file_id, error_range).with_message("Namespace used here.") + ); + diagnostics.push(diagnostic); } } } diff --git a/src/parser/ast.yaml b/src/parser/ast.yaml index 35ea073..dfe20be 100644 --- a/src/parser/ast.yaml +++ b/src/parser/ast.yaml @@ -281,6 +281,10 @@ StarUseStatement: - range: special: kind: range + fields: + - symbol: + kind: StarUseSymbol + wrap: rc_ref_cell UseStatementPrefix: struct: children: