Work on star-use symbols.

This commit is contained in:
Jesse Brault 2025-10-28 10:43:42 -05:00
parent 5721bd1e83
commit d653d26e14
9 changed files with 173 additions and 50 deletions

View File

@ -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<Rc<str>>,
prefixes: &[Rc<str>],
use_statement_identifier: &mut UseStatementIdentifier,
symbol_table: &mut SymbolTable,
diagnostics: &mut Vec<DmDiagnostic>,
@ -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<DmDiagnostic>,
) {
let fqn_parts = star_use_statement
.prefixes()
.map(UseStatementPrefix::identifier)
.map(Identifier::name)
.map(|name| Rc::from(name))
.collect::<Vec<Rc<str>>>();
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,

View File

@ -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<DmDiagnostic>,
) {
let base_fqn_parts: Vec<String> = 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::<Vec<Rc<str>>>();
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<str>],
use_statement_identifier: &mut UseStatementIdentifier,
symbol_table: &SymbolTable,
diagnostics: &mut Vec<DmDiagnostic>,
) {
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<DmDiagnostic>,
) {
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,
);
}
}
}

View File

@ -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
}

View File

@ -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<RefCell<InterfaceSymbol>>),
Class(Rc<RefCell<ClassSymbol>>),

View File

@ -76,6 +76,7 @@ impl Debug for ConcreteUseSymbol {
pub struct StarUseSymbol {
fqn_parts: Vec<Rc<str>>,
source_definition: Option<SourceDefinition>,
resolved_symbols: Vec<UsableSymbol>,
}
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<str>] {
&self.fqn_parts
}
pub fn resolved_symbols(&self) -> &[UsableSymbol] {
&self.resolved_symbols
}
pub fn set_resolved_symbols(&mut self, symbols: Vec<UsableSymbol>) {
self.resolved_symbols = symbols;
}
}
impl Symbol for StarUseSymbol {

View File

@ -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<UsableSymbol> {
pub fn find_usable_symbol(&self, fqn_parts: &[Rc<str>]) -> Option<UsableSymbol> {
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<str>],
) -> Result<Vec<UsableSymbol>, 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<Rc<RefCell<GenericTypeSymbol>>, 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<TypeSymbol, SymbolLookupError> {
todo!()
}

View File

@ -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<Rc<RefCell<ClassSymbol>>> {
pub fn find_class(&self, fqn_parts: &[Rc<str>]) -> Option<Rc<RefCell<ClassSymbol>>> {
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<Rc<RefCell<InterfaceSymbol>>> {
pub fn find_interface(&self, fqn_parts: &[Rc<str>]) -> Option<Rc<RefCell<InterfaceSymbol>>> {
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<Rc<RefCell<FunctionSymbol>>> {
pub fn find_function(&self, fqn_parts: &[Rc<str>]) -> Option<Rc<RefCell<FunctionSymbol>>> {
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<RefCell<FunctionSymbol>>) {
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<RefCell<FunctionSymbol>>, fqn_parts: &[Rc<str>]) {
fn recurse_register_function(
&mut self,
function_symbol: Rc<RefCell<FunctionSymbol>>,
fqn_parts: &[Rc<str>],
) {
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<str>],
) -> Result<Vec<UsableSymbol>, SymbolLookupError> {
match fqn_parts.len() {
0 => {
let mut all_symbols: Vec<UsableSymbol> = 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)
}
}
}
}
}

View File

@ -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);
}
}
}

View File

@ -281,6 +281,10 @@ StarUseStatement:
- range:
special:
kind: range
fields:
- symbol:
kind: StarUseSymbol
wrap: rc_ref_cell
UseStatementPrefix:
struct:
children: