diff --git a/src/bin/dmc/name_analysis.rs b/src/bin/dmc/name_analysis.rs index 62851f9..f497647 100644 --- a/src/bin/dmc/name_analysis.rs +++ b/src/bin/dmc/name_analysis.rs @@ -8,6 +8,7 @@ use deimos::parser::{DeimosParser, Rule}; use deimos::std_core::add_std_core_symbols; use pest::Parser; use std::path::PathBuf; +use deimos::name_analysis::symbol_tree::SymbolTree; pub fn name_analysis(paths: &Vec) -> Result<(), Box> { let mut compilation_units = vec![]; @@ -29,9 +30,10 @@ pub fn name_analysis(paths: &Vec) -> Result<(), Box, ) { let mut fqn_context = FqnContext::new(); @@ -103,7 +105,7 @@ fn handle_concrete_use_statement( let to_insert = ConcreteUseSymbol::new( &base_fqn, identifier.name(), - Some(SourceDefinition::from_identifier(identifier)) + Some(SourceDefinition::from_identifier(identifier)), ); match symbol_table.insert_concrete_use_symbol(to_insert) { Ok(inserted) => { @@ -116,7 +118,7 @@ fn handle_concrete_use_statement( identifier.file_id(), identifier.range(), "Use Symbol", - diagnostics + diagnostics, ); } } @@ -142,7 +144,14 @@ fn nap1_use_statement( identifier, "Use Statement", diagnostics - ) + ); + use_statement.set_use_symbol(Rc::new(RefCell::new(UseSymbol::Concrete(Rc::new( + RefCell::new(ConcreteUseSymbol::new( + &base_fqn, + identifier.name(), + Some(SourceDefinition::from_use_statement(use_statement)), + )), + ))))); } UseStatementSuffix::Star => { insert_symbol!( diff --git a/src/name_analysis/mod.rs b/src/name_analysis/mod.rs index a933572..5249f94 100644 --- a/src/name_analysis/mod.rs +++ b/src/name_analysis/mod.rs @@ -28,6 +28,7 @@ use crate::name_analysis::second_pass::nap2_compilation_unit; use crate::name_analysis::symbol_table::SymbolTable; use codespan_reporting::files::Files; use std::hash::Hash; +use crate::name_analysis::symbol_tree::SymbolTree; pub(self) mod fqn_context; // mod resolve; @@ -36,24 +37,26 @@ mod scope_table; mod second_pass; pub mod symbol; pub mod symbol_table; +pub mod symbol_tree; mod util; pub fn analyze_names<'a, F: Files<'a, FileId = usize, Name = String>>( compilation_units: &mut Vec>, files: &'a F, symbol_table: &mut SymbolTable, + symbol_tree: &mut SymbolTree, ) -> Vec { let mut diagnostics = vec![]; // gather symbols for compilation_unit in compilation_units.iter_mut() { let file_name = files.name(compilation_unit.file_id()).unwrap(); - nap1_compilation_unit(&file_name, compilation_unit, symbol_table, &mut diagnostics); + nap1_compilation_unit(&file_name, compilation_unit, symbol_table, symbol_tree, &mut diagnostics); } // resolve symbols for compilation_unit in compilation_units { - nap2_compilation_unit(compilation_unit, symbol_table, &mut diagnostics); + nap2_compilation_unit(compilation_unit, symbol_table, symbol_tree, &mut diagnostics); } diagnostics.into() diff --git a/src/name_analysis/second_pass.rs b/src/name_analysis/second_pass.rs index 4a428eb..53a93cd 100644 --- a/src/name_analysis/second_pass.rs +++ b/src/name_analysis/second_pass.rs @@ -1,8 +1,9 @@ use crate::ast::node::{CompilationUnit, Identifier, UseStatement, UseStatementSuffix}; use crate::diagnostic::DmDiagnostic; +use crate::name_analysis::symbol::usable_symbol::ConcreteUsableSymbol; use crate::name_analysis::symbol::use_symbol::UseSymbol; use crate::name_analysis::symbol_table::{SymbolLookupError, SymbolTable}; -use crate::name_analysis::util::use_statement_base_fqn; +use crate::name_analysis::symbol_tree::SymbolTree; use codespan_reporting::diagnostic::{Diagnostic, Label}; use std::range::Range; @@ -32,66 +33,84 @@ fn handle_lookup_error( pub fn nap2_compilation_unit( compilation_unit: &mut CompilationUnit, symbol_table: &SymbolTable, + symbol_tree: &SymbolTree, diagnostics: &mut Vec, ) { // TODO: check namespace for proper file name for use_statement in compilation_unit.use_statements_mut() { - nap2_use_statement(use_statement, symbol_table, diagnostics); + nap2_use_statement(use_statement, symbol_tree, diagnostics); } // TODO: declarations } -fn nap2_use_statement( - use_statement: &mut UseStatement, - symbol_table: &SymbolTable, +fn handle_concrete_use_symbol( + use_statement: &UseStatement, + identifier: &Identifier, + symbol_tree: &SymbolTree, diagnostics: &mut Vec, ) { - let base_fqn = use_statement_base_fqn(use_statement); - - let mut handle_concrete_use_symbol = |identifier: &Identifier| { - let fqn = format!("{}::{}", base_fqn, identifier.name()); - match symbol_table.resolve_concrete_usable_by_fqn(&fqn) { - Ok(resolved_symbol) => match *use_statement.use_symbol().unwrap().borrow() { - UseSymbol::Concrete(ref concrete_use_symbol) => { - concrete_use_symbol - .borrow_mut() - .set_resolved_symbol(resolved_symbol); - } - _ => panic!("Unexpected symbol type"), - }, - Err(lookup_error) => { - handle_lookup_error( - lookup_error, - &fqn, - use_statement.file_id(), - use_statement.range(), - "Usable Symbol", - diagnostics, - ); - } - } + let mut fqn_parts: Vec<&str> = { + let mut base: Vec<&str> = use_statement + .prefixes() + .map(|prefix| prefix.identifier().name()) + .collect(); + base.push(identifier.name()); + base }; + let found = symbol_tree + .find_interface(&fqn_parts) + .map(|interface_symbol| ConcreteUsableSymbol::Interface(interface_symbol)) + .or_else(|| { + symbol_tree + .find_class(&fqn_parts) + .map(|class_symbol| ConcreteUsableSymbol::Class(class_symbol)) + }) + .or_else(|| { + symbol_tree + .find_function(&fqn_parts) + .map(|function_symbol| ConcreteUsableSymbol::Function(function_symbol)) + }); + if let Some(concrete_usable_symbol) = found { + let use_symbol_ref = use_statement.use_symbol().unwrap().borrow(); + match *use_symbol_ref { + UseSymbol::Concrete(ref concrete_use_symbol) => { + concrete_use_symbol + .borrow_mut() + .set_resolved_symbol(concrete_usable_symbol); + } + _ => panic!( + "Unexpected UseSymbol type (expected Concrete, found: {:?}", + *use_symbol_ref + ), + } + } else { + handle_lookup_error( + SymbolLookupError::NoDefinition, + &fqn_parts.join("::"), + use_statement.file_id(), + use_statement.range(), + "Usable Symbol", + diagnostics, + ); + } +} +fn nap2_use_statement( + use_statement: &mut UseStatement, + symbol_tree: &SymbolTree, + diagnostics: &mut Vec, +) { match use_statement.suffix() { UseStatementSuffix::Identifier(identifier) => { - handle_concrete_use_symbol(identifier); + handle_concrete_use_symbol(use_statement, identifier, symbol_tree, diagnostics); } UseStatementSuffix::Star => { - if let Err(error) = symbol_table.resolve_usable_star(&base_fqn) { - handle_lookup_error( - error, - &base_fqn, - use_statement.file_id(), - use_statement.range(), - "Star Usable Symbol", - diagnostics, - ); - } + todo!("Resolve star symbols") } UseStatementSuffix::UseList(use_list) => { for identifier in use_list.identifiers() { - handle_concrete_use_symbol(identifier); + handle_concrete_use_symbol(use_statement, identifier, symbol_tree, diagnostics); } } } diff --git a/src/name_analysis/symbol/class_symbol.rs b/src/name_analysis/symbol/class_symbol.rs new file mode 100644 index 0000000..6697d06 --- /dev/null +++ b/src/name_analysis/symbol/class_symbol.rs @@ -0,0 +1,40 @@ +use std::cell::RefCell; +use std::collections::HashMap; +use std::rc::Rc; +use crate::name_analysis::symbol::class_member_symbol::ClassMemberSymbol; +use crate::name_analysis::symbol::function_symbol::FunctionSymbol; + +#[derive(Debug)] +pub struct ClassSymbol { + declared_name: Rc, + fqn: Rc, + members: HashMap, Rc>>, + functions: HashMap, Rc>> +} + +impl ClassSymbol { + pub fn new(declared_name: &str, fqn: &str) -> Self { + Self { + declared_name: Rc::new(declared_name.to_string()), + fqn: Rc::new(fqn.to_string()), + members: HashMap::new(), + functions: HashMap::new(), + } + } + + pub fn declared_name(&self) -> &str { + &self.declared_name + } + + pub fn declared_name_owned(&self) -> Rc { + self.declared_name.clone() + } + + pub fn fqn(&self) -> &str { + &self.fqn + } + + pub fn fqn_owned(&self) -> Rc { + self.fqn.clone() + } +} \ No newline at end of file diff --git a/src/name_analysis/symbol/interface_symbol.rs b/src/name_analysis/symbol/interface_symbol.rs new file mode 100644 index 0000000..6e79a1f --- /dev/null +++ b/src/name_analysis/symbol/interface_symbol.rs @@ -0,0 +1,36 @@ +use std::collections::HashMap; +use std::rc::Rc; +use crate::name_analysis::symbol::function_symbol::FunctionSymbol; + +#[derive(Debug)] +pub struct InterfaceSymbol { + declared_name: Rc, + fqn: Rc, + functions: HashMap, +} + +impl InterfaceSymbol { + pub fn new(declared_name: &str, fqn: &str) -> Self { + Self { + declared_name: Rc::new(declared_name.to_string()), + fqn: Rc::new(fqn.to_string()), + functions: HashMap::new(), + } + } + + pub fn declared_name(&self) -> &str { + &self.declared_name + } + + pub fn declared_name_owned(&self) -> Rc { + self.declared_name.clone() + } + + pub fn fqn(&self) -> &str { + &self.fqn + } + + pub fn fqn_owned(&self) -> Rc { + self.fqn.clone() + } +} diff --git a/src/name_analysis/symbol/mod.rs b/src/name_analysis/symbol/mod.rs index 50e4e37..609493e 100644 --- a/src/name_analysis/symbol/mod.rs +++ b/src/name_analysis/symbol/mod.rs @@ -1,12 +1,14 @@ -pub(crate) mod class_member_symbol; -pub(crate) mod function_symbol; -pub(crate) mod module_symbol; -pub(crate) mod parameter_symbol; -pub(crate) mod source_definition; -pub(crate) mod type_symbol; -pub(crate) mod usable_symbol; -pub(crate) mod use_symbol; -pub(crate) mod variable_symbol; +pub mod class_member_symbol; +pub mod class_symbol; +pub mod function_symbol; +pub mod interface_symbol; +pub mod module_symbol; +pub mod parameter_symbol; +pub mod source_definition; +pub mod type_symbol; +pub mod usable_symbol; +pub mod use_symbol; +pub mod variable_symbol; use crate::name_analysis::symbol::type_symbol::ConcreteTypeSymbol; use crate::name_analysis::symbol::use_symbol::UseSymbol; @@ -40,7 +42,9 @@ impl Symbol { Symbol::Use(use_symbol) => use_symbol.source_definition(), Symbol::Module(module) => module.source_definition().cloned(), Symbol::Type(type_symbol) => type_symbol.source_definition().cloned(), - Symbol::ConcreteType(concrete_type_symbol) => concrete_type_symbol.borrow().source_definition().cloned(), + Symbol::ConcreteType(concrete_type_symbol) => { + concrete_type_symbol.borrow().source_definition().cloned() + } Symbol::Function(function_symbol) => function_symbol.source_definition().cloned(), Symbol::Parameter(parameter_symbol) => parameter_symbol.source_definition().cloned(), Symbol::Variable(variable_symbol) => variable_symbol.source_definition().cloned(), diff --git a/src/name_analysis/symbol/usable_symbol.rs b/src/name_analysis/symbol/usable_symbol.rs index 02d2c39..7988d50 100644 --- a/src/name_analysis/symbol/usable_symbol.rs +++ b/src/name_analysis/symbol/usable_symbol.rs @@ -1,10 +1,12 @@ +use crate::name_analysis::symbol::class_symbol::ClassSymbol; use crate::name_analysis::symbol::function_symbol::FunctionSymbol; -use crate::name_analysis::symbol::type_symbol::{ConcreteTypeSymbol, TypeSymbol}; +use crate::name_analysis::symbol::interface_symbol::InterfaceSymbol; use std::cell::RefCell; use std::rc::Rc; #[derive(Clone, Debug)] pub enum ConcreteUsableSymbol { - Type(Rc>), + Interface(Rc>), + Class(Rc>), Function(Rc>), } diff --git a/src/name_analysis/symbol_table/mod.rs b/src/name_analysis/symbol_table/mod.rs index b9a007c..ea04716 100644 --- a/src/name_analysis/symbol_table/mod.rs +++ b/src/name_analysis/symbol_table/mod.rs @@ -2,7 +2,6 @@ use crate::name_analysis::symbol::class_member_symbol::ClassMemberSymbol; use crate::name_analysis::symbol::function_symbol::FunctionSymbol; use crate::name_analysis::symbol::module_symbol::ModuleSymbol; use crate::name_analysis::symbol::parameter_symbol::ParameterSymbol; -use crate::name_analysis::symbol::type_symbol::ConcreteTypeSymbol; use crate::name_analysis::symbol::usable_symbol::ConcreteUsableSymbol; use crate::name_analysis::symbol::use_symbol::{ConcreteUseSymbol, StarUseSymbol, UseSymbol}; use crate::name_analysis::symbol::variable_symbol::VariableSymbol; @@ -190,27 +189,6 @@ impl SymbolTable { } } - fn find_current_scope_concrete_type_symbol( - &self, - declared_name: &str, - ) -> Option>> { - self.current_scope().get_concrete_type_symbol(declared_name) - } - - pub fn insert_concrete_type_symbol( - &mut self, - symbol: ConcreteTypeSymbol, - ) -> Result<(), SymbolInsertError> { - if let Some(defined_type) = - self.find_current_scope_concrete_type_symbol(symbol.declared_name()) - { - Err(SymbolAlreadyDefined(Symbol::ConcreteType(defined_type))) - } else { - self.current_scope_mut().insert_concrete_type_symbol(symbol); - Ok(()) - } - } - pub fn insert_function_symbol( &mut self, function_symbol: FunctionSymbol, @@ -334,39 +312,6 @@ impl SymbolTable { } Err(NoDefinition) } - - pub fn resolve_concrete_usable_by_fqn( - &self, - fqn: &str, - ) -> Result { - // breadth-first search, use a queue - let mut search_stack: VecDeque = VecDeque::new(); - search_stack.push_back(0); // global scope - - while let Some(scope_id) = search_stack.pop_front() { - let scope = &self.scopes[scope_id]; - for child_id in scope.children() { - search_stack.push_back(child_id); - } - - if let Some(concrete_type_symbol) = scope.get_concrete_type_symbol_by_fqn(fqn) { - return Ok(ConcreteUsableSymbol::Type(concrete_type_symbol)); - } - - // TODO: this is inefficient. Use a (cached) hash table of Fqn => Rc> - for function_symbol in scope.function_symbols().values() { - if function_symbol.fqn() == fqn { - return Ok(ConcreteUsableSymbol::Function(todo!())); - } - } - } - - Err(NoDefinition) - } - - pub fn resolve_usable_star(&self, base_fqn: &str) -> Result<(), SymbolLookupError> { - todo!() - } } impl Display for SymbolTable { diff --git a/src/name_analysis/symbol_table/scope.rs b/src/name_analysis/symbol_table/scope.rs index f858b2e..253c055 100644 --- a/src/name_analysis/symbol_table/scope.rs +++ b/src/name_analysis/symbol_table/scope.rs @@ -1,8 +1,9 @@ use crate::name_analysis::symbol::class_member_symbol::ClassMemberSymbol; +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::parameter_symbol::ParameterSymbol; -use crate::name_analysis::symbol::type_symbol::{ConcreteTypeSymbol, TypeSymbol}; use crate::name_analysis::symbol::use_symbol::{ConcreteUseSymbol, StarUseSymbol}; use crate::name_analysis::symbol::variable_symbol::VariableSymbol; use std::cell::RefCell; @@ -18,8 +19,8 @@ pub struct Scope { concrete_use_symbols: HashMap>>, star_use_symbols: HashMap, module_symbols: HashMap, - concrete_type_symbols: HashMap>>, - concrete_type_symbols_by_fqn: HashMap>>, + interface_symbols: HashMap, Rc>>, + class_symbols: HashMap, Rc>>, function_symbols: HashMap, parameter_symbols: HashMap, variable_symbols: HashMap, @@ -36,8 +37,8 @@ impl Scope { concrete_use_symbols: HashMap::new(), star_use_symbols: HashMap::new(), module_symbols: HashMap::new(), - concrete_type_symbols: HashMap::new(), - concrete_type_symbols_by_fqn: HashMap::new(), + interface_symbols: HashMap::new(), + class_symbols: HashMap::new(), function_symbols: HashMap::new(), parameter_symbols: HashMap::new(), variable_symbols: HashMap::new(), @@ -88,24 +89,25 @@ impl Scope { &mut self.module_symbols } - pub fn insert_concrete_type_symbol(&mut self, symbol: ConcreteTypeSymbol) { - let as_rc = Rc::new(RefCell::new(symbol)); - self.concrete_type_symbols.insert( - as_rc.borrow().declared_name().to_string(), - as_rc.clone(), - ); - self.concrete_type_symbols_by_fqn.insert( - as_rc.borrow().fqn().to_string(), - as_rc.clone(), - ); + pub fn insert_interface_symbol(&mut self, symbol: InterfaceSymbol) { + self.interface_symbols + .insert(symbol.declared_name_owned(), Rc::new(RefCell::new(symbol))); } - - pub fn get_concrete_type_symbol(&self, declared_name: &str) -> Option>> { - self.concrete_type_symbols.get(declared_name).cloned() + + pub fn get_interface_symbol( + &self, + declared_name: Rc, + ) -> Option>> { + self.interface_symbols.get(&declared_name).cloned() } - - pub fn get_concrete_type_symbol_by_fqn(&self, fqn: &str) -> Option>> { - self.concrete_type_symbols_by_fqn.get(fqn).cloned() + + pub fn insert_class_symbol(&mut self, symbol: ClassSymbol) { + self.class_symbols + .insert(symbol.declared_name_owned(), Rc::new(RefCell::new(symbol))); + } + + pub fn get_class_symbol(&self, declared_name: Rc) -> Option>> { + self.class_symbols.get(&declared_name).cloned() } pub fn function_symbols(&self) -> &HashMap { diff --git a/src/name_analysis/symbol_tree.rs b/src/name_analysis/symbol_tree.rs new file mode 100644 index 0000000..9c06668 --- /dev/null +++ b/src/name_analysis/symbol_tree.rs @@ -0,0 +1,57 @@ +use std::cell::RefCell; +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 std::collections::HashMap; +use std::rc::Rc; + +pub struct SymbolTree { + children: Box>, + classes: Box>>>, + interfaces: Box>>>, + functions: Box>>>, +} + +impl SymbolTree { + pub fn new() -> Self { + Self { + children: Box::new(HashMap::new()), + classes: Box::new(HashMap::new()), + interfaces: Box::new(HashMap::new()), + functions: Box::new(HashMap::new()), + } + } + + pub fn find_class(&self, fqn_parts: &[&str]) -> Option>> { + match fqn_parts.len() { + 0 => None, + 1 => self.classes.get(fqn_parts[0]).cloned(), + _ => self + .children + .get(fqn_parts[0]) + .and_then(|child_tree| child_tree.find_class(&fqn_parts[1..])), + } + } + + pub fn find_interface(&self, fqn_parts: &[&str]) -> Option>> { + match fqn_parts.len() { + 0 => None, + 1 => self.interfaces.get(fqn_parts[0]).cloned(), + _ => self + .children + .get(fqn_parts[0]) + .and_then(|child_tree| child_tree.find_interface(&fqn_parts[1..])), + } + } + + pub fn find_function(&self, fqn_parts: &[&str]) -> Option>> { + match fqn_parts.len() { + 0 => None, + 1 => self.functions.get(fqn_parts[0]).cloned(), + _ => self + .children + .get(fqn_parts[0]) + .and_then(|child_tree| child_tree.find_function(&fqn_parts[1..])), + } + } +}