diff --git a/src/name_analysis/gather.rs b/src/name_analysis/gather.rs index e753f74..c6a8991 100644 --- a/src/name_analysis/gather.rs +++ b/src/name_analysis/gather.rs @@ -2,10 +2,43 @@ use crate::ast::ast_node::{AstNode, AstNodeRef}; use crate::ast::node::{CompilationUnit, Identifier, UseStatement, UseStatementSuffix}; use crate::diagnostic::DmDiagnostic; use crate::name_analysis::symbol::source_definition::SourceDefinition; -use crate::name_analysis::symbol::use_symbol::StarUseStatementSymbol; -use crate::name_analysis::symbol::UseStatementSymbol; -use crate::name_analysis::symbol_table::SymbolTable; +use crate::name_analysis::symbol::use_symbol::{ConcreteUseSymbol, StarUseSymbol}; +use crate::name_analysis::symbol_table::{SymbolInsertError, SymbolTable}; +use codespan_reporting::diagnostic::{Diagnostic, Label}; use std::collections::HashMap; +use std::range::Range; + +fn handle_insert_error( + err: SymbolInsertError, + error_symbol_name: &str, + error_file_id: usize, + error_range: Range, + symbol_types: &str, + diagnostics: &mut Vec, +) { + match err { + SymbolInsertError::SymbolAlreadyDefined(s) => { + let mut diagnostic = Diagnostic::error() + .with_message(format!( + "{} symbol '{}' already defined in the current scope.", + symbol_types, error_symbol_name, + )) + .with_label( + Label::primary(error_file_id, error_range) + .with_message("Symbol duplicated here."), + ); + + if let Some(source_definition) = s.definition() { + diagnostic = diagnostic.with_label( + Label::secondary(source_definition.file_id(), source_definition.range()) + .with_message("Symbol defined here."), + ); + } + + diagnostics.push(diagnostic); + } + } +} fn gather_identifier( identifier: &Identifier, @@ -15,27 +48,61 @@ fn gather_identifier( identifier_scope_ids.insert(identifier.clone(), symbol_table.current_scope_id()); } +fn gather_concrete_use_symbol(base_fqn: &str, identifier: &Identifier, symbol_table: &mut SymbolTable, diagnostics: &mut Vec) { + let symbol = ConcreteUseSymbol::new( + base_fqn, + identifier.name(), + Some(SourceDefinition::from_identifier(identifier)), + ); + if let Err(insert_error) = symbol_table.insert_concrete_use_symbol(symbol) { + handle_insert_error( + insert_error, + &base_fqn, + identifier.file_id(), + identifier.range(), + "Use Statement", + diagnostics, + ); + } +} + fn gather_use_statement( use_statement: &UseStatement, symbol_table: &mut SymbolTable, diagnostics: &mut Vec, ) { - let mut fully_qualified_name = String::new(); - for prefix in use_statement.prefixes() { - fully_qualified_name.push_str(&format!("{}::", prefix.identifier().name())); - } + let base_fqn = use_statement + .prefixes() + .map(|prefix| prefix.identifier().name()) + .collect::>() + .join("::"); + match use_statement.suffix() { - UseStatementSuffix::Identifier(identifier) => {} + UseStatementSuffix::Identifier(identifier) => { + gather_concrete_use_symbol(&base_fqn, identifier, symbol_table, diagnostics); + } UseStatementSuffix::Star => { - let symbol_inner = StarUseStatementSymbol::new( - &fully_qualified_name, + let symbol = StarUseSymbol::new( + &base_fqn, Some(SourceDefinition::from_use_statement(use_statement)), ); - let symbol = UseStatementSymbol::Star(symbol_inner); - symbol_table.insert_use_statement_symbol(symbol); - todo!() + let insert_result = symbol_table.insert_star_use_symbol(symbol); + if let Err(error) = insert_result { + handle_insert_error( + error, + &base_fqn, + use_statement.file_id(), + use_statement.range(), + "Use Statement", + diagnostics, + ); + } + } + UseStatementSuffix::UseList(use_list) => { + for identifier in use_list.identifiers() { + gather_concrete_use_symbol(&base_fqn, identifier, symbol_table, diagnostics); + } } - UseStatementSuffix::UseList(use_list) => {} } } diff --git a/src/name_analysis/symbol/class_member_symbol.rs b/src/name_analysis/symbol/class_member_symbol.rs new file mode 100644 index 0000000..8cd74f3 --- /dev/null +++ b/src/name_analysis/symbol/class_member_symbol.rs @@ -0,0 +1,45 @@ +use crate::name_analysis::symbol::source_definition::SourceDefinition; +use std::fmt::{Debug, Formatter}; + +#[derive(Clone)] +pub struct ClassMemberSymbol { + declared_name: String, + is_field: bool, + source_definition: Option, +} + +impl ClassMemberSymbol { + pub fn new( + declared_name: &str, + is_field: bool, + source_definition: Option, + ) -> Self { + Self { + declared_name: declared_name.to_string(), + is_field, + source_definition, + } + } + + pub fn declared_name(&self) -> &str { + &self.declared_name + } + + pub fn is_field(&self) -> bool { + self.is_field + } + + pub fn source_definition(&self) -> Option<&SourceDefinition> { + self.source_definition.as_ref() + } +} + +impl Debug for ClassMemberSymbol { + fn fmt(&self, f: &mut Formatter<'_>) -> std::fmt::Result { + f.debug_struct("ClassMemberSymbol") + .field("declared_name", &self.declared_name) + .field("is_field", &self.is_field) + .field("source_definition", &self.source_definition) + .finish() + } +} diff --git a/src/name_analysis/symbol/function_symbol.rs b/src/name_analysis/symbol/function_symbol.rs new file mode 100644 index 0000000..fd3113f --- /dev/null +++ b/src/name_analysis/symbol/function_symbol.rs @@ -0,0 +1,101 @@ +use crate::name_analysis::symbol::parameter_symbol::ParameterSymbol; +use crate::name_analysis::symbol::source_definition::SourceDefinition; +use crate::name_analysis::symbol::type_symbol::ConcreteTypeSymbol; +use std::fmt::{Debug, Formatter}; + +#[derive(Clone)] +pub struct FunctionSymbol { + fqn: String, + declared_name: String, + is_public: bool, + is_platform: bool, + source_definition: Option, + parameters: Vec, + return_type: Option, // todo: can we use TypeSymbol? +} + +impl FunctionSymbol { + pub fn without_parameters_or_return_type( + fqn: &str, + declared_name: &str, + is_public: bool, + is_platform: bool, + source_definition: Option, + ) -> FunctionSymbol { + FunctionSymbol { + fqn: fqn.to_string(), + declared_name: declared_name.to_string(), + is_public, + is_platform, + source_definition, + parameters: Vec::new(), + return_type: None, + } + } + + pub fn with_parameters(self, parameters: Vec) -> Self { + Self { + fqn: self.fqn, + declared_name: self.declared_name, + is_public: self.is_public, + is_platform: self.is_platform, + source_definition: self.source_definition, + parameters, + return_type: self.return_type, + } + } + + pub fn with_return_type(self, return_type: ConcreteTypeSymbol) -> Self { + Self { + fqn: self.fqn, + declared_name: self.declared_name, + is_public: self.is_public, + is_platform: self.is_platform, + source_definition: self.source_definition, + parameters: self.parameters, + return_type: Some(return_type), + } + } + + pub fn fqn(&self) -> &str { + &self.fqn + } + + pub fn declared_name(&self) -> &str { + &self.declared_name + } + + pub fn is_public(&self) -> bool { + self.is_public + } + + pub fn is_platform(&self) -> bool { + self.is_platform + } + + pub fn source_definition(&self) -> Option<&SourceDefinition> { + self.source_definition.as_ref() + } + + pub fn parameters(&self) -> &[ParameterSymbol] { + &self.parameters + } + + pub fn return_type(&self) -> Option<&ConcreteTypeSymbol> { + self.return_type.as_ref() + } +} + +impl Debug for FunctionSymbol { + fn fmt(&self, f: &mut Formatter<'_>) -> std::fmt::Result { + f.debug_struct("FunctionSymbol") + .field("fqn", &self.fqn) + .field("declared_name", &self.declared_name) + .field("is_public", &self.is_public) + .field("is_platform", &self.is_platform) + .field("parameters", &self.parameters) + .field("return_type", &self.return_type) + .field("source_definition", &self.source_definition) + .finish() + } +} diff --git a/src/name_analysis/symbol/mod.rs b/src/name_analysis/symbol/mod.rs index b13e2ef..5925433 100644 --- a/src/name_analysis/symbol/mod.rs +++ b/src/name_analysis/symbol/mod.rs @@ -1,445 +1,46 @@ -pub(super) mod source_definition; -pub(super) mod use_symbol; +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 use_symbol; +pub(crate) mod variable_symbol; -use crate::ast::node::Identifier; +use crate::name_analysis::symbol::use_symbol::{ConcreteUseSymbol, StarUseSymbol}; +use class_member_symbol::ClassMemberSymbol; +use function_symbol::FunctionSymbol; +use module_symbol::ModuleSymbol; +use parameter_symbol::ParameterSymbol; use source_definition::SourceDefinition; -use std::cell::RefCell; -use std::fmt::{Debug, Display, Formatter}; +use std::fmt::{Debug, Display}; use std::ops::Deref; -use std::rc::Rc; - -pub trait SymbolInner { - fn declared_name(&self) -> &str; - fn definition(&self) -> Option; -} - -/* Symbol */ +use type_symbol::TypeSymbol; +use variable_symbol::VariableSymbol; #[derive(Debug, Clone)] pub enum Symbol { - UseStatement(Rc>), - Module(Rc), - Type(Rc), - Function(Rc>), - Parameter(Rc), - Variable(Rc), - ClassMember(Rc), + ConcreteUse(ConcreteUseSymbol), + StarUse(StarUseSymbol), + Module(ModuleSymbol), + Type(TypeSymbol), + Function(FunctionSymbol), + Parameter(ParameterSymbol), + Variable(VariableSymbol), + ClassMember(ClassMemberSymbol), } impl Symbol { - pub fn definition(&self) -> Option { + pub fn definition(&self) -> Option<&SourceDefinition> { match self { - Symbol::UseStatement(s) => s.borrow().definition(), - Symbol::Module(s) => s.definition(), - Symbol::Type(s) => match s.deref() { - TypeSymbol::Concrete(cts) => cts.definition(), - TypeSymbol::Generic(gts) => gts.definition(), - }, - Symbol::Function(s) => s.borrow().definition(), - Symbol::Parameter(s) => s.definition(), - Symbol::Variable(s) => s.definition(), - Symbol::ClassMember(s) => s.definition(), - } - } - - pub fn unwrap_use_statement_symbol(&self) -> Rc> { - match self { - Symbol::UseStatement(s) => s.clone(), - _ => panic!("unwrap_use_statement_symbol called on non-use statement symbol"), + Symbol::ConcreteUse(concrete) => concrete.source_definition(), + Symbol::StarUse(star) => star.source_definition(), + Symbol::Module(module) => module.source_definition(), + Symbol::Type(type_symbol) => type_symbol.source_definition(), + Symbol::Function(function_symbol) => function_symbol.source_definition(), + Symbol::Parameter(parameter_symbol) => parameter_symbol.source_definition(), + Symbol::Variable(variable_symbol) => variable_symbol.source_definition(), + Symbol::ClassMember(class_member_symbol) => class_member_symbol.source_definition(), } } } - -/* Use-statement */ - -pub struct UseStatementSymbol { - pub fqn: String, - pub declared_name: String, - definition: Option, - referenced_symbol: Option>, -} - -impl UseStatementSymbol { - pub fn new(fqn: &str, declared_name: &str, identifier: Option<&Identifier>) -> Self { - UseStatementSymbol { - fqn: fqn.to_string(), - declared_name: declared_name.to_string(), - definition: identifier.map(SourceDefinition::from_identifier), - referenced_symbol: None, - } - } - - pub fn set_referenced_symbol(&mut self, referenced_symbol: Symbol) { - self.referenced_symbol = Some(Box::new(referenced_symbol)); - } - - pub fn referenced_symbol(&self) -> Option> { - self.referenced_symbol.clone() - } -} - -impl SymbolInner for UseStatementSymbol { - fn declared_name(&self) -> &str { - &self.declared_name - } - - fn definition(&self) -> Option { - self.definition.clone() - } -} - -impl Debug for UseStatementSymbol { - fn fmt(&self, f: &mut Formatter<'_>) -> std::fmt::Result { - f.debug_struct("UseStatementSymbol") - .field("fqn", &self.fqn) - .field("declared_name", &self.declared_name) - .field("referenced_symbol", &self.referenced_symbol) - .finish() - } -} - -/* Module */ - -pub struct ModuleSymbol { - fqn: String, - declared_name: String, - is_public: bool, - definition: Option, -} - -impl ModuleSymbol { - pub fn new( - fqn: &str, - declared_name: &str, - is_public: bool, - identifier: Option<&Identifier>, - ) -> ModuleSymbol { - ModuleSymbol { - fqn: fqn.to_string(), - declared_name: declared_name.to_string(), - is_public, - definition: identifier.map(SourceDefinition::from_identifier), - } - } -} - -impl SymbolInner for ModuleSymbol { - fn declared_name(&self) -> &str { - self.declared_name.as_str() - } - - fn definition(&self) -> Option { - self.definition.clone() - } -} - -impl Debug for ModuleSymbol { - fn fmt(&self, f: &mut Formatter<'_>) -> std::fmt::Result { - f.debug_struct("ModuleSymbol") - .field("fqn", &self.fqn) - .field("declared_name", &self.declared_name) - .field("is_public", &self.is_public) - .finish() - } -} - -/* TypeSymbol */ - -#[derive(Debug)] -pub enum TypeSymbol { - Concrete(ConcreteTypeSymbol), - Generic(GenericTypeSymbol), -} - -impl TypeSymbol { - pub fn declared_name(&self) -> &str { - match self { - TypeSymbol::Concrete(t) => t.declared_name(), - TypeSymbol::Generic(t) => t.declared_name(), - } - } -} - -pub struct ConcreteTypeSymbol { - fqn: String, - declared_name: String, - is_public: bool, - definition: Option, -} - -impl ConcreteTypeSymbol { - pub fn new( - fqn: &str, - declared_name: &str, - is_public: bool, - identifier: Option<&Identifier>, - ) -> Self { - ConcreteTypeSymbol { - fqn: fqn.to_string(), - declared_name: declared_name.to_string(), - is_public, - definition: identifier.map(SourceDefinition::from_identifier), - } - } - - pub fn fqn(&self) -> &str { - &self.fqn - } - - pub fn is_public(&self) -> bool { - self.is_public - } -} - -impl SymbolInner for ConcreteTypeSymbol { - fn declared_name(&self) -> &str { - &self.declared_name - } - - fn definition(&self) -> Option { - self.definition.clone() - } -} - -impl Debug for ConcreteTypeSymbol { - fn fmt(&self, f: &mut Formatter<'_>) -> std::fmt::Result { - f.debug_struct("TypeSymbol") - .field("fqn", &self.fqn) - .field("declared_name", &self.declared_name) - .field("is_public", &self.is_public) - .finish() - } -} - -pub struct GenericTypeSymbol { - declared_name: String, - source_definition: SourceDefinition, -} - -impl GenericTypeSymbol { - pub fn new(declared_name: &str, source_definition: SourceDefinition) -> Self { - GenericTypeSymbol { - declared_name: declared_name.to_string(), - source_definition, - } - } -} - -impl SymbolInner for GenericTypeSymbol { - fn declared_name(&self) -> &str { - self.declared_name.as_str() - } - - fn definition(&self) -> Option { - Some(self.source_definition.clone()) - } -} - -impl Debug for GenericTypeSymbol { - fn fmt(&self, f: &mut Formatter<'_>) -> std::fmt::Result { - f.debug_struct("GenericTypeSymbol") - .field("declared_name", &self.declared_name) - .finish() - } -} - -/* Function */ - -pub struct FunctionSymbol { - fqn: String, - declared_name: String, - is_public: bool, - is_platform: bool, - definition: Option, - parameters: Vec>, - return_type: Option>, -} - -impl FunctionSymbol { - pub fn new( - fqn: &str, - declared_name: &str, - is_public: bool, - is_platform: bool, - identifier: Option<&Identifier>, - ) -> FunctionSymbol { - FunctionSymbol { - fqn: fqn.to_string(), - declared_name: declared_name.to_string(), - is_public, - is_platform, - definition: identifier.map(SourceDefinition::from_identifier), - parameters: Vec::new(), - return_type: None, - } - } - - pub fn with_parameters(self, parameters: Vec) -> Self { - Self { - fqn: self.fqn, - declared_name: self.declared_name, - is_public: self.is_public, - is_platform: self.is_platform, - definition: self.definition, - parameters: parameters - .into_iter() - .map(|parameter| Rc::new(parameter)) - .collect(), - return_type: self.return_type, - } - } - - pub fn with_return_type(self, return_type: ConcreteTypeSymbol) -> Self { - Self { - fqn: self.fqn, - declared_name: self.declared_name, - is_public: self.is_public, - is_platform: self.is_platform, - definition: self.definition, - parameters: self.parameters, - return_type: Some(Rc::new(return_type)), - } - } - - pub fn fqn(&self) -> &str { - &self.fqn - } - - pub fn set_parameters(&mut self, parameters: Vec>) { - self.parameters = parameters; - } - - pub fn set_return_type(&mut self, return_type: Rc) { - self.return_type = Some(return_type); - } -} - -impl SymbolInner for FunctionSymbol { - fn declared_name(&self) -> &str { - self.declared_name.as_str() - } - - fn definition(&self) -> Option { - self.definition.clone() - } -} - -impl Debug for FunctionSymbol { - fn fmt(&self, f: &mut Formatter<'_>) -> std::fmt::Result { - f.debug_struct("FunctionSymbol") - .field("fqn", &self.fqn) - .field("declared_name", &self.declared_name) - .field("is_public", &self.is_public) - .field("is_platform", &self.is_platform) - .field("parameters", &self.parameters) - .field("return_type", &self.return_type) - .finish() - } -} - -/* Parameter */ - -pub struct ParameterSymbol { - declared_name: String, - definition: Option, -} - -impl ParameterSymbol { - pub fn new(declared_name: &str, identifier: Option<&Identifier>) -> Self { - ParameterSymbol { - declared_name: declared_name.to_string(), - definition: identifier.map(SourceDefinition::from_identifier), - } - } -} - -impl SymbolInner for ParameterSymbol { - fn declared_name(&self) -> &str { - &self.declared_name - } - - fn definition(&self) -> Option { - self.definition.clone() - } -} - -impl Debug for ParameterSymbol { - fn fmt(&self, f: &mut Formatter<'_>) -> std::fmt::Result { - f.debug_struct("ParameterSymbol") - .field("declared_name", &self.declared_name) - .finish() - } -} - -/* Variable */ - -pub struct VariableSymbol { - declared_name: String, - is_mutable: bool, - definition: Option, -} - -impl VariableSymbol { - pub fn new(declared_name: &str, is_mutable: bool, identifier: Option<&Identifier>) -> Self { - VariableSymbol { - declared_name: declared_name.to_string(), - is_mutable, - definition: identifier.map(SourceDefinition::from_identifier), - } - } -} - -impl SymbolInner for VariableSymbol { - fn declared_name(&self) -> &str { - self.declared_name.as_str() - } - - fn definition(&self) -> Option { - self.definition.clone() - } -} - -impl Debug for VariableSymbol { - fn fmt(&self, f: &mut Formatter<'_>) -> std::fmt::Result { - f.debug_struct("VariableSymbol") - .field("declared_name", &self.declared_name) - .field("is_mutable", &self.is_mutable) - .finish() - } -} - -/* Class Member */ - -pub struct ClassMemberSymbol { - declared_name: String, - is_field: bool, - definition: Option, -} - -impl ClassMemberSymbol { - pub fn new(declared_name: &str, is_field: bool, definition: Option) -> Self { - ClassMemberSymbol { - declared_name: declared_name.to_string(), - is_field, - definition, - } - } -} - -impl SymbolInner for ClassMemberSymbol { - fn declared_name(&self) -> &str { - self.declared_name.as_str() - } - - fn definition(&self) -> Option { - self.definition.clone() - } -} - -impl Debug for ClassMemberSymbol { - fn fmt(&self, f: &mut Formatter<'_>) -> std::fmt::Result { - f.debug_struct("ClassMemberSymbol") - .field("declared_name", &self.declared_name) - .finish() - } -} diff --git a/src/name_analysis/symbol/module_symbol.rs b/src/name_analysis/symbol/module_symbol.rs new file mode 100644 index 0000000..b733f49 --- /dev/null +++ b/src/name_analysis/symbol/module_symbol.rs @@ -0,0 +1,53 @@ +use crate::name_analysis::symbol::source_definition::SourceDefinition; +use std::fmt::{Debug, Formatter}; + +#[derive(Clone)] +pub struct ModuleSymbol { + fqn: String, + declared_name: String, + is_public: bool, + source_definition: Option, +} + +impl ModuleSymbol { + pub fn new( + fqn: &str, + declared_name: &str, + is_public: bool, + source_definition: Option, + ) -> Self { + Self { + fqn: fqn.to_string(), + declared_name: declared_name.to_string(), + is_public, + source_definition, + } + } + + pub fn fqn(&self) -> &str { + &self.fqn + } + + pub fn declared_name(&self) -> &str { + &self.declared_name + } + + pub fn is_public(&self) -> bool { + self.is_public + } + + pub fn source_definition(&self) -> Option<&SourceDefinition> { + self.source_definition.as_ref() + } +} + +impl Debug for ModuleSymbol { + fn fmt(&self, f: &mut Formatter<'_>) -> std::fmt::Result { + f.debug_struct("ModuleSymbol") + .field("fqn", &self.fqn) + .field("declared_name", &self.declared_name) + .field("is_public", &self.is_public) + .field("source_definition", &self.source_definition) + .finish() + } +} diff --git a/src/name_analysis/symbol/parameter_symbol.rs b/src/name_analysis/symbol/parameter_symbol.rs new file mode 100644 index 0000000..5024f8d --- /dev/null +++ b/src/name_analysis/symbol/parameter_symbol.rs @@ -0,0 +1,34 @@ +use crate::name_analysis::symbol::source_definition::SourceDefinition; +use std::fmt::{Debug, Formatter}; + +#[derive(Clone)] +pub struct ParameterSymbol { + declared_name: String, + source_definition: Option, +} + +impl ParameterSymbol { + pub fn new(declared_name: &str, source_definition: Option) -> Self { + ParameterSymbol { + declared_name: declared_name.to_string(), + source_definition, + } + } + + pub fn declared_name(&self) -> &str { + &self.declared_name + } + + pub fn source_definition(&self) -> Option<&SourceDefinition> { + self.source_definition.as_ref() + } +} + +impl Debug for ParameterSymbol { + fn fmt(&self, f: &mut Formatter<'_>) -> std::fmt::Result { + f.debug_struct("ParameterSymbol") + .field("declared_name", &self.declared_name) + .field("source_definition", &self.source_definition) + .finish() + } +} diff --git a/src/name_analysis/symbol/type_symbol.rs b/src/name_analysis/symbol/type_symbol.rs new file mode 100644 index 0000000..4ae5d2e --- /dev/null +++ b/src/name_analysis/symbol/type_symbol.rs @@ -0,0 +1,107 @@ +use crate::name_analysis::symbol::source_definition::SourceDefinition; +use std::fmt::{Debug, Formatter}; + +#[derive(Clone, Debug)] +pub enum TypeSymbol { + Concrete(ConcreteTypeSymbol), + Generic(GenericTypeSymbol), +} + +impl TypeSymbol { + pub fn declared_name(&self) -> &str { + match self { + TypeSymbol::Concrete(t) => t.declared_name(), + TypeSymbol::Generic(t) => t.declared_name(), + } + } + + pub fn source_definition(&self) -> Option<&SourceDefinition> { + match self { + TypeSymbol::Concrete(t) => t.source_definition(), + TypeSymbol::Generic(t) => t.source_definition(), + } + } +} + +#[derive(Clone)] +pub struct ConcreteTypeSymbol { + fqn: String, + declared_name: String, + is_public: bool, + source_definition: Option, +} + +impl ConcreteTypeSymbol { + pub fn new( + fqn: &str, + declared_name: &str, + is_public: bool, + source_definition: Option, + ) -> Self { + Self { + fqn: fqn.to_string(), + declared_name: declared_name.to_string(), + is_public, + source_definition + } + } + + pub fn fqn(&self) -> &str { + &self.fqn + } + + pub fn is_public(&self) -> bool { + self.is_public + } + + pub fn declared_name(&self) -> &str { + &self.declared_name + } + + pub fn source_definition(&self) -> Option<&SourceDefinition> { + self.source_definition.as_ref() + } +} + +impl Debug for ConcreteTypeSymbol { + fn fmt(&self, f: &mut Formatter<'_>) -> std::fmt::Result { + f.debug_struct("TypeSymbol") + .field("fqn", &self.fqn) + .field("declared_name", &self.declared_name) + .field("is_public", &self.is_public) + .field("source_definition", &self.source_definition) + .finish() + } +} + +#[derive(Clone)] +pub struct GenericTypeSymbol { + declared_name: String, + source_definition: Option, +} + +impl GenericTypeSymbol { + pub fn new(declared_name: &str, source_definition: Option) -> Self { + GenericTypeSymbol { + declared_name: declared_name.to_string(), + source_definition, + } + } + + pub fn declared_name(&self) -> &str { + &self.declared_name + } + + pub fn source_definition(&self) -> Option<&SourceDefinition> { + self.source_definition.as_ref() + } +} + +impl Debug for GenericTypeSymbol { + fn fmt(&self, f: &mut Formatter<'_>) -> std::fmt::Result { + f.debug_struct("GenericTypeSymbol") + .field("declared_name", &self.declared_name) + .field("source_definition", &self.source_definition) + .finish() + } +} diff --git a/src/name_analysis/symbol/use_symbol.rs b/src/name_analysis/symbol/use_symbol.rs index c6c6610..f8b3898 100644 --- a/src/name_analysis/symbol/use_symbol.rs +++ b/src/name_analysis/symbol/use_symbol.rs @@ -1,16 +1,56 @@ use crate::name_analysis::symbol::source_definition::SourceDefinition; +use std::fmt::{Debug, Formatter}; -pub enum UseStatementSymbol { - Concrete, - Star(StarUseStatementSymbol), +#[derive(Clone)] +pub struct ConcreteUseSymbol { + base_fqn: String, + declared_name: String, + source_definition: Option, } -pub struct StarUseStatementSymbol { +impl ConcreteUseSymbol { + pub fn new( + base_fqn: &str, + declared_name: &str, + source_definition: Option, + ) -> Self { + Self { + base_fqn: base_fqn.to_string(), + declared_name: declared_name.to_string(), + source_definition, + } + } + + pub fn base_fqn(&self) -> &str { + &self.base_fqn + } + + pub fn declared_name(&self) -> &str { + &self.declared_name + } + + pub fn source_definition(&self) -> Option<&SourceDefinition> { + self.source_definition.as_ref() + } +} + +impl Debug for ConcreteUseSymbol { + fn fmt(&self, f: &mut Formatter<'_>) -> std::fmt::Result { + f.debug_struct("ConcreteUseStatementSymbol") + .field("base_fqn", &self.base_fqn) + .field("declared_name", &self.declared_name) + .field("source_definition", &self.source_definition) + .finish() + } +} + +#[derive(Clone)] +pub struct StarUseSymbol { base_fqn: String, source_definition: Option, } -impl StarUseStatementSymbol { +impl StarUseSymbol { pub fn new(base_fqn: &str, source_definition: Option) -> Self { Self { base_fqn: base_fqn.to_string(), @@ -26,3 +66,12 @@ impl StarUseStatementSymbol { self.source_definition.as_ref() } } + +impl Debug for StarUseSymbol { + fn fmt(&self, f: &mut Formatter<'_>) -> std::fmt::Result { + f.debug_struct("StarUseStatementSymbol") + .field("base_fqn", &self.base_fqn) + .field("source_definition", &self.source_definition) + .finish() + } +} diff --git a/src/name_analysis/symbol/variable_symbol.rs b/src/name_analysis/symbol/variable_symbol.rs new file mode 100644 index 0000000..fbef0f6 --- /dev/null +++ b/src/name_analysis/symbol/variable_symbol.rs @@ -0,0 +1,41 @@ +use crate::name_analysis::symbol::source_definition::SourceDefinition; +use std::fmt::{Debug, Formatter}; + +#[derive(Clone)] +pub struct VariableSymbol { + declared_name: String, + is_mutable: bool, + source_definition: Option, +} + +impl VariableSymbol { + pub fn new(declared_name: &str, is_mutable: bool, source_definition: Option) -> Self { + VariableSymbol { + declared_name: declared_name.to_string(), + is_mutable, + source_definition, + } + } + + 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> { + self.source_definition.as_ref() + } +} + +impl Debug for VariableSymbol { + fn fmt(&self, f: &mut Formatter<'_>) -> std::fmt::Result { + f.debug_struct("VariableSymbol") + .field("declared_name", &self.declared_name) + .field("is_mutable", &self.is_mutable) + .field("source_definition", &self.source_definition) + .finish() + } +} diff --git a/src/name_analysis/symbol_table.rs b/src/name_analysis/symbol_table.rs deleted file mode 100644 index 7db4ed8..0000000 --- a/src/name_analysis/symbol_table.rs +++ /dev/null @@ -1,468 +0,0 @@ -use crate::name_analysis::symbol::*; -use crate::name_analysis::symbol_table::SymbolInsertError::SymbolAlreadyDefined; -use crate::name_analysis::symbol_table::SymbolLookupError::NoDefinition; -use std::cell::RefCell; -use std::collections::HashMap; -use std::fmt::Display; -use std::ops::Deref; -use std::rc::Rc; - -/* Scope */ - -#[derive(Debug)] -struct Scope { - parent: Option, - use_statement_symbols: HashMap>>, - module_symbols: HashMap>, - type_symbols: HashMap>, - function_symbols: HashMap>>, - parameter_symbols: HashMap>, - variable_symbols: HashMap>, - class_member_symbols: HashMap>, - debug_name: String, -} - -impl Scope { - pub fn new(parent: Option, debug_name: String) -> Scope { - Scope { - parent, - use_statement_symbols: HashMap::new(), - module_symbols: HashMap::new(), - type_symbols: HashMap::new(), - function_symbols: HashMap::new(), - parameter_symbols: HashMap::new(), - variable_symbols: HashMap::new(), - class_member_symbols: HashMap::new(), - debug_name, - } - } - - fn get_module_symbol_by_declared_name(&self, name: &str) -> Option> { - for module_symbol in self.module_symbols.values() { - if module_symbol.declared_name() == name { - return Some(module_symbol.clone()); - } - } - None - } - - fn get_type_symbol_by_declared_name(&self, declared_name: &str) -> Option> { - if let Some(type_symbol) = self.type_symbols.get(declared_name) { - Some(type_symbol.clone()) - } else { - for use_statement_symbol in self.use_statement_symbols.values() { - let borrowed = use_statement_symbol.borrow(); - if borrowed.declared_name() == declared_name { - if let Some(referenced_symbol) = borrowed.referenced_symbol() { - match *referenced_symbol { - Symbol::Type(type_symbol) => return Some(type_symbol.clone()), - _ => continue, - } - } - } - } - None - } - } - - fn get_type_symbol_by_fqn(&self, fqn: &str) -> Option> { - self.type_symbols - .values() - .find(|s| match s.deref().deref() { - TypeSymbol::Concrete(cts) => cts.fqn() == fqn, - _ => false, - }) - .cloned() - } - - fn get_usable_symbol_by_fqn(&self, fqn: &str) -> Option { - for function_symbol in self.function_symbols.values() { - if function_symbol.borrow().fqn() == fqn { - return Some(Symbol::Function(function_symbol.clone())); - } - } - for type_symbol in self.type_symbols.values() { - match type_symbol.deref() { - TypeSymbol::Concrete(concrete_type_symbol) => { - if concrete_type_symbol.fqn() == fqn { - return Some(Symbol::Type(type_symbol.clone())); - } - } - _ => continue, - } - } - None - } - - fn get_usable_symbol_by_declared_name(&self, declared_name: &str) -> Option { - for function_symbol in self.function_symbols.values() { - if function_symbol.borrow().declared_name() == declared_name { - return Some(Symbol::Function(function_symbol.clone())); - } - } - for type_symbol in self.type_symbols.values() { - if type_symbol.declared_name() == declared_name { - return Some(Symbol::Type(type_symbol.clone())); - } - } - None - } - - fn get_value_symbol_by_declared_name(&self, declared_name: &str) -> Option { - for variable_symbol in self.variable_symbols.values() { - if variable_symbol.declared_name() == declared_name { - return Some(Symbol::Variable(variable_symbol.clone())); - } - } - for parameter_symbol in self.parameter_symbols.values() { - if parameter_symbol.declared_name() == declared_name { - return Some(Symbol::Parameter(parameter_symbol.clone())); - } - } - None - } - - fn get_expressible_by_declared_name(&self, declared_name: &str) -> Option { - self.variable_symbols - .get(declared_name) - .map(|s| Symbol::Variable(s.clone())) - .or_else(|| { - self.parameter_symbols - .get(declared_name) - .map(|p| Symbol::Parameter(p.clone())) - }) - .or_else(|| { - self.class_member_symbols - .get(declared_name) - .map(|cms| Symbol::ClassMember(cms.clone())) - }) - .or_else(|| { - self.function_symbols - .get(declared_name) - .map(|f| Symbol::Function(f.clone())) - }) - .or_else(|| { - self.type_symbols - .get(declared_name) - .map(|t| Symbol::Type(t.clone())) - }) - .or_else(|| { - self.use_statement_symbols - .get(declared_name) - .map(|us| Symbol::UseStatement(us.clone())) - }) - } - - fn get_expressible_by_fqn(&self, fqn: &str) -> Option { - self.function_symbols - .values() - .find(|fs| fs.borrow().fqn() == fqn) - .map(|f| Symbol::Function(f.clone())) - .or_else(|| { - self.get_type_symbol_by_fqn(fqn) - .map(|ts| Symbol::Type(ts.clone())) - }) - } -} - -/* Symbol table */ - -#[derive(Debug)] -pub enum SymbolInsertError { - SymbolAlreadyDefined(Symbol), -} - -#[derive(Debug)] -pub enum SymbolLookupError { - NoDefinition, -} - -#[derive(Debug)] -pub struct SymbolTable { - scopes: Vec, - current_scope_id: usize, -} - -/// Contains a vec of scopes, like a flattened tree -impl SymbolTable { - pub fn new() -> Self { - let mut t = SymbolTable { - scopes: vec![Scope::new(None, String::from("GlobalScope"))], - current_scope_id: 0, - }; - t - } - - pub fn current_scope_id(&self) -> usize { - self.current_scope_id - } - - pub fn scopes(&self) -> &Vec { - &self.scopes - } - - pub fn push_scope(&mut self, debug_name: &str) { - let id = self.scopes.len(); - self.scopes.push(Scope::new( - Some(self.current_scope_id), - debug_name.to_string(), - )); - self.current_scope_id = id; - } - - pub fn pop_scope(&mut self) { - if let Some(parent_id) = self.scopes[self.current_scope_id].parent { - self.current_scope_id = parent_id; - } - } - - pub fn insert_use_statement_symbol( - &mut self, - use_statement_symbol: UseStatementSymbol, - ) -> Result>, SymbolInsertError> { - let current_scope = self.scopes.get_mut(self.current_scope_id).unwrap(); - if let Some(defined_symbol) = - current_scope.get_usable_symbol_by_declared_name(use_statement_symbol.declared_name()) - { - Err(SymbolAlreadyDefined(defined_symbol)) - } else { - let declared_name = use_statement_symbol.declared_name().to_string(); - let to_insert = Rc::new(RefCell::new(use_statement_symbol)); - let to_return = to_insert.clone(); - current_scope - .use_statement_symbols - .insert(declared_name, to_insert); - Ok(to_return) - } - } - - pub fn insert_module_symbol( - &mut self, - module_symbol: ModuleSymbol, - ) -> Result<(), SymbolInsertError> { - let current_scope = self.scopes.get_mut(self.current_scope_id).unwrap(); - if let Some(defined_symbol) = - current_scope.get_module_symbol_by_declared_name(module_symbol.declared_name()) - { - Err(SymbolAlreadyDefined(Symbol::Module(defined_symbol.clone()))) - } else { - current_scope.module_symbols.insert( - module_symbol.declared_name().to_string(), - Rc::new(module_symbol), - ); - Ok(()) - } - } - - pub fn insert_type_symbol(&mut self, type_symbol: TypeSymbol) -> Result<(), SymbolInsertError> { - let current_scope = self.scopes.get_mut(self.current_scope_id).unwrap(); - if let Some(defined_symbol) = - current_scope.get_usable_symbol_by_declared_name(type_symbol.declared_name()) - { - Err(SymbolAlreadyDefined(defined_symbol)) - } else { - current_scope.type_symbols.insert( - type_symbol.declared_name().to_string(), - Rc::new(type_symbol), - ); - Ok(()) - } - } - - pub fn insert_function_symbol( - &mut self, - function_symbol: FunctionSymbol, - ) -> Result>, SymbolInsertError> { - let current_scope = self.scopes.get_mut(self.current_scope_id).unwrap(); - if let Some(defined_symbol) = - current_scope.get_usable_symbol_by_declared_name(function_symbol.declared_name()) - { - Err(SymbolAlreadyDefined(defined_symbol)) - } else { - let declared_name = function_symbol.declared_name().to_string(); - let to_insert = Rc::new(RefCell::new(function_symbol)); - let to_return = to_insert.clone(); - current_scope - .function_symbols - .insert(declared_name, to_insert); - Ok(to_return) - } - } - - pub fn insert_parameter_symbol( - &mut self, - parameter_symbol: ParameterSymbol, - ) -> Result, SymbolInsertError> { - let current_scope = self.scopes.get_mut(self.current_scope_id).unwrap(); - if let Some(defined_symbol) = - current_scope.get_value_symbol_by_declared_name(parameter_symbol.declared_name()) - { - Err(SymbolAlreadyDefined(defined_symbol)) - } else { - let to_insert = Rc::new(parameter_symbol); - let to_return = to_insert.clone(); - current_scope - .parameter_symbols - .insert(to_insert.declared_name().to_string(), to_insert); - Ok(to_return) - } - } - - pub fn insert_variable_symbol( - &mut self, - variable_symbol: VariableSymbol, - ) -> Result, SymbolInsertError> { - let current_scope = self.scopes.get_mut(self.current_scope_id).unwrap(); - if let Some(defined_symbol) = - current_scope.get_value_symbol_by_declared_name(variable_symbol.declared_name()) - { - Err(SymbolAlreadyDefined(defined_symbol)) - } else { - let declared_name = variable_symbol.declared_name().to_string(); - let to_insert = Rc::new(variable_symbol); - let to_return = to_insert.clone(); - current_scope - .variable_symbols - .insert(declared_name, to_insert); - Ok(to_return) - } - } - - pub fn insert_class_member_symbol( - &mut self, - class_member_symbol: ClassMemberSymbol, - ) -> Result<(), SymbolInsertError> { - let current_scope = self.scopes.get_mut(self.current_scope_id).unwrap(); - if let Some(defined_symbol) = - current_scope.get_expressible_by_declared_name(class_member_symbol.declared_name()) - { - Err(SymbolAlreadyDefined(defined_symbol)) - } else { - current_scope.class_member_symbols.insert( - class_member_symbol.declared_name().to_string(), - Rc::new(class_member_symbol), - ); - Ok(()) - } - } - - pub fn lookup_type_by_declared_name( - &self, - declared_name: &str, - scope_id: usize, - ) -> Result, SymbolLookupError> { - let mut scope_opt = Some(&self.scopes[scope_id]); - while let Some(scope) = scope_opt { - if let Some(symbol) = scope.get_type_symbol_by_declared_name(declared_name) { - return Ok(symbol); - } - scope_opt = if let Some(parent_id) = scope.parent { - Some(&self.scopes[parent_id]) - } else { - None - } - } - Err(NoDefinition) - } - - pub fn lookup_type_by_fqn( - &self, - fqn: &str, - scope_id: usize, - ) -> Result, SymbolLookupError> { - let mut scope_opt = Some(&self.scopes[scope_id]); - while let Some(scope) = scope_opt { - if let Some(symbol) = scope.get_type_symbol_by_fqn(fqn) { - return Ok(symbol); - } - scope_opt = if let Some(parent_id) = scope.parent { - Some(&self.scopes[parent_id]) - } else { - None - } - } - Err(NoDefinition) - } - - pub fn lookup_usable_by_fqn( - &self, - fully_qualified_name: &str, - scope_id: usize, - ) -> Result { - for scope in &self.scopes { - if let Some(symbol) = scope.get_usable_symbol_by_fqn(fully_qualified_name) { - return Ok(symbol); - } - } - Err(NoDefinition) - } - - pub fn lookup_expressible_by_declared_name( - &self, - declared_name: &str, - scope_id: usize, - ) -> Result { - let mut scope_opt = Some(&self.scopes[scope_id]); - while let Some(scope) = scope_opt { - if let Some(symbol) = scope.get_expressible_by_declared_name(declared_name) { - return Ok(symbol); - } - scope_opt = if let Some(parent_id) = scope.parent { - Some(&self.scopes[parent_id]) - } else { - None - } - } - Err(NoDefinition) - } - - pub fn lookup_expressible_by_fqn( - &self, - fqn: &str, - scope_id: usize, - ) -> Result { - let mut scope_opt = Some(&self.scopes[scope_id]); - while let Some(scope) = scope_opt { - if let Some(symbol) = scope.get_expressible_by_fqn(fqn) { - return Ok(symbol); - } - scope_opt = if let Some(parent_id) = scope.parent { - Some(&self.scopes[parent_id]) - } else { - None - } - } - Err(NoDefinition) - } -} - -impl Display for SymbolTable { - fn fmt(&self, f: &mut std::fmt::Formatter) -> std::fmt::Result { - writeln!(f, "SymbolTable(current_scope = {})", self.current_scope_id)?; - for (i, scope) in self.scopes.iter().enumerate() { - writeln!(f, "----Scope {} {}----", i, scope.debug_name)?; - for symbol in scope.use_statement_symbols.values() { - writeln!(f, "{:#?}", symbol.borrow())?; - } - for symbol in scope.module_symbols.values() { - writeln!(f, "{:#?}", symbol)?; - } - for symbol in scope.type_symbols.values() { - writeln!(f, "{:#?}", symbol)?; - } - for symbol in scope.function_symbols.values() { - writeln!(f, "{:#?}", symbol.borrow())?; - } - for symbol in scope.parameter_symbols.values() { - writeln!(f, "{:#?}", symbol)?; - } - for symbol in scope.variable_symbols.values() { - writeln!(f, "{:#?}", symbol)?; - } - for symbol in scope.class_member_symbols.values() { - writeln!(f, "{:#?}", symbol)?; - } - } - Ok(()) - } -} diff --git a/src/name_analysis/symbol_table/mod.rs b/src/name_analysis/symbol_table/mod.rs new file mode 100644 index 0000000..dec99b6 --- /dev/null +++ b/src/name_analysis/symbol_table/mod.rs @@ -0,0 +1,333 @@ +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::TypeSymbol; +use crate::name_analysis::symbol::use_symbol::{ConcreteUseSymbol, StarUseSymbol}; +use crate::name_analysis::symbol::variable_symbol::VariableSymbol; +use crate::name_analysis::symbol::*; +use crate::name_analysis::symbol_table::SymbolInsertError::SymbolAlreadyDefined; +use crate::name_analysis::symbol_table::SymbolLookupError::NoDefinition; +use scope::Scope; +use std::fmt::Display; +use std::ops::Deref; + +mod scope; + +#[derive(Debug)] +pub enum SymbolInsertError { + SymbolAlreadyDefined(Symbol), +} + +#[derive(Debug)] +pub enum SymbolLookupError { + NoDefinition, +} + +#[derive(Debug)] +pub struct SymbolTable { + scopes: Vec, + current_scope_id: usize, +} + +/// Contains a vec of scopes, like a flattened tree +impl SymbolTable { + pub fn new() -> Self { + Self { + scopes: vec![Scope::new(None, 0, String::from("GlobalScope"))], + current_scope_id: 0, + } + } + + pub fn current_scope_id(&self) -> usize { + self.current_scope_id + } + + pub fn push_scope(&mut self, debug_name: &str) { + let id = self.scopes.len(); + self.scopes + .push(Scope::new(Some(self.current_scope_id), id, debug_name.to_string())); + self.current_scope_id = id; + } + + pub fn pop_scope(&mut self) { + if let Some(parent_id) = self.scopes[self.current_scope_id].parent() { + self.current_scope_id = parent_id; + } + } + + fn current_scope(&self) -> &Scope { + self.scopes.last().unwrap() + } + + fn current_scope_mut(&mut self) -> &mut Scope { + self.scopes.last_mut().unwrap() + } + + fn find_current_scope_concrete_use_symbol( + &self, + declared_name: &str, + ) -> Option<&ConcreteUseSymbol> { + self.current_scope() + .concrete_use_symbols() + .get(declared_name) + } + + fn find_current_scope_star_use_symbol(&self, base_fqn: &str) -> Option<&StarUseSymbol> { + self.current_scope().star_use_symbols().get(base_fqn) + } + + fn find_current_scope_type_symbol(&self, declared_name: &str) -> Option<&TypeSymbol> { + self.current_scope().type_symbols().get(declared_name) + } + + fn find_current_scope_module_symbol(&self, declared_name: &str) -> Option<&ModuleSymbol> { + self.current_scope().module_symbols().get(declared_name) + } + + fn find_current_scope_parameter_symbol(&self, declared_name: &str) -> Option<&ParameterSymbol> { + self.current_scope().parameter_symbols().get(declared_name) + } + + fn find_current_scope_variable_symbol(&self, declared_name: &str) -> Option<&VariableSymbol> { + self.current_scope().variable_symbols().get(declared_name) + } + + fn find_current_scope_class_member_symbol( + &self, + declared_name: &str, + ) -> Option<&ClassMemberSymbol> { + self.current_scope() + .class_member_symbols() + .get(declared_name) + } + + fn find_current_scope_variable_or_parameter_symbol( + &self, + declared_name: &str, + ) -> Option { + self.find_current_scope_variable_symbol(declared_name) + .map(|variable_symbol| Symbol::Variable(variable_symbol.clone())) + .or_else(|| { + self.find_current_scope_parameter_symbol(declared_name) + .map(|parameter_symbol| Symbol::Parameter(parameter_symbol.clone())) + }) + } + + fn find_current_scope_usable_symbol(&self, declared_name: &str) -> Option { + self.find_current_scope_concrete_use_symbol(declared_name) + .map(|concrete_use_symbol| Symbol::ConcreteUse(concrete_use_symbol.clone())) + .or_else(|| { + self.find_current_scope_type_symbol(declared_name) + .map(|type_symbol| Symbol::Type(type_symbol.clone())) + }) + .or_else(|| { + self.find_current_scope_module_symbol(declared_name) + .map(|module_symbol| Symbol::Module(module_symbol.clone())) + }) + } + + pub fn insert_concrete_use_symbol( + &mut self, + concrete_use_symbol: ConcreteUseSymbol, + ) -> Result<(), SymbolInsertError> { + if let Some(defined_symbol) = + self.find_current_scope_usable_symbol(concrete_use_symbol.declared_name()) + { + Err(SymbolAlreadyDefined(defined_symbol)) + } else { + self.current_scope_mut().concrete_use_symbols_mut().insert( + concrete_use_symbol.declared_name().to_string(), + concrete_use_symbol, + ); + Ok(()) + } + } + + pub fn insert_star_use_symbol( + &mut self, + star_use_symbol: StarUseSymbol, + ) -> Result<(), SymbolInsertError> { + if let Some(defined_symbol) = + self.find_current_scope_star_use_symbol(star_use_symbol.base_fqn()) + { + Err(SymbolAlreadyDefined(Symbol::StarUse( + defined_symbol.clone(), + ))) + } else { + self.current_scope_mut() + .star_use_symbols_mut() + .insert(star_use_symbol.base_fqn().to_string(), star_use_symbol); + Ok(()) + } + } + + pub fn insert_module_symbol( + &mut self, + module_symbol: ModuleSymbol, + ) -> Result<(), SymbolInsertError> { + if let Some(defined_symbol) = + self.find_current_scope_usable_symbol(module_symbol.declared_name()) + { + Err(SymbolAlreadyDefined(defined_symbol)) + } else { + self.current_scope_mut() + .module_symbols_mut() + .insert(module_symbol.declared_name().to_string(), module_symbol); + Ok(()) + } + } + + pub fn insert_type_symbol(&mut self, type_symbol: TypeSymbol) -> Result<(), SymbolInsertError> { + if let Some(defined_symbol) = + self.find_current_scope_usable_symbol(type_symbol.declared_name()) + { + Err(SymbolAlreadyDefined(defined_symbol)) + } else { + self.current_scope_mut() + .type_symbols_mut() + .insert(type_symbol.declared_name().to_string(), type_symbol); + Ok(()) + } + } + + pub fn insert_function_symbol( + &mut self, + function_symbol: FunctionSymbol, + ) -> Result<(), SymbolInsertError> { + if let Some(defined_symbol) = + self.find_current_scope_usable_symbol(function_symbol.declared_name()) + { + Err(SymbolAlreadyDefined(defined_symbol)) + } else { + self.current_scope_mut() + .function_symbols_mut() + .insert(function_symbol.declared_name().to_string(), function_symbol); + Ok(()) + } + } + + pub fn insert_parameter_symbol( + &mut self, + parameter_symbol: ParameterSymbol, + ) -> Result<(), SymbolInsertError> { + if let Some(defined_symbol) = + self.find_current_scope_parameter_symbol(parameter_symbol.declared_name()) + { + Err(SymbolAlreadyDefined(Symbol::Parameter( + defined_symbol.clone(), + ))) + } else { + self.current_scope_mut().parameter_symbols_mut().insert( + parameter_symbol.declared_name().to_string(), + parameter_symbol, + ); + Ok(()) + } + } + + pub fn insert_variable_symbol( + &mut self, + variable_symbol: VariableSymbol, + ) -> Result<(), SymbolInsertError> { + if let Some(defined_symbol) = + self.find_current_scope_variable_or_parameter_symbol(variable_symbol.declared_name()) + { + Err(SymbolAlreadyDefined(defined_symbol)) + } else { + self.current_scope_mut() + .variable_symbols_mut() + .insert(variable_symbol.declared_name().to_string(), variable_symbol); + Ok(()) + } + } + + pub fn insert_class_member_symbol( + &mut self, + class_member_symbol: ClassMemberSymbol, + ) -> Result<(), SymbolInsertError> { + if let Some(defined_symbol) = + self.find_current_scope_class_member_symbol(class_member_symbol.declared_name()) + { + Err(SymbolAlreadyDefined(Symbol::ClassMember( + defined_symbol.clone(), + ))) + } else { + self.current_scope_mut().class_member_symbols_mut().insert( + class_member_symbol.declared_name().to_string(), + class_member_symbol, + ); + Ok(()) + } + } + + fn lookup_type_in_scope_by_declared_name<'a>( + scope: &'a Scope, + declared_name: &str, + ) -> Option<&'a TypeSymbol> { + scope.type_symbols().get(declared_name) + } + + pub fn lookup_type_by_declared_name( + &self, + declared_name: &str, + scope_id: usize, + ) -> Result<&TypeSymbol, SymbolLookupError> { + let mut scope_opt = Some(&self.scopes[scope_id]); + while let Some(scope) = scope_opt { + if let Some(symbol) = Self::lookup_type_in_scope_by_declared_name(scope, declared_name) + { + return Ok(symbol); + } + scope_opt = if let Some(parent_id) = scope.parent() { + Some(&self.scopes[parent_id]) + } else { + None + } + } + Err(NoDefinition) + } + + fn lookup_type_in_scope_by_fqn<'a>(scope: &'a Scope, fqn: &str) -> Option<&'a TypeSymbol> { + for type_symbol in scope.type_symbols().values() { + match type_symbol { + TypeSymbol::Concrete(concrete_type_symbol) => { + if concrete_type_symbol.fqn() == fqn { + return Some(type_symbol); + } + } + TypeSymbol::Generic(_) => {} + } + } + None + } + + pub fn lookup_type_by_fqn( + &self, + fqn: &str, + scope_id: usize, + ) -> Result<&TypeSymbol, SymbolLookupError> { + let mut scope_opt = Some(&self.scopes[scope_id]); + while let Some(scope) = scope_opt { + if let Some(type_symbol) = Self::lookup_type_in_scope_by_fqn(scope, fqn) { + return Ok(type_symbol); + } + scope_opt = if let Some(parent_id) = scope.parent() { + Some(&self.scopes[parent_id]) + } else { + None + } + } + Err(NoDefinition) + } +} + +impl Display for SymbolTable { + fn fmt(&self, f: &mut std::fmt::Formatter) -> std::fmt::Result { + writeln!(f, "SymbolTable(current_scope = {})", self.current_scope_id)?; + for scope in &self.scopes { + writeln!(f, "{}", scope)?; + } + Ok(()) + } +} diff --git a/src/name_analysis/symbol_table/scope.rs b/src/name_analysis/symbol_table/scope.rs new file mode 100644 index 0000000..56bbee3 --- /dev/null +++ b/src/name_analysis/symbol_table/scope.rs @@ -0,0 +1,141 @@ +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::TypeSymbol; +use crate::name_analysis::symbol::use_symbol::{ConcreteUseSymbol, StarUseSymbol}; +use crate::name_analysis::symbol::variable_symbol::VariableSymbol; +use std::collections::HashMap; +use std::fmt::{Display, Formatter}; + +#[derive(Debug)] +pub struct Scope { + parent: Option, + id: usize, + concrete_use_symbols: HashMap, + star_use_symbols: HashMap, + module_symbols: HashMap, + type_symbols: HashMap, + function_symbols: HashMap, + parameter_symbols: HashMap, + variable_symbols: HashMap, + class_member_symbols: HashMap, + debug_name: String, +} + +impl Scope { + pub fn new(parent: Option, id: usize, debug_name: String) -> Self { + Self { + parent, + id, + concrete_use_symbols: HashMap::new(), + star_use_symbols: HashMap::new(), + module_symbols: HashMap::new(), + type_symbols: HashMap::new(), + function_symbols: HashMap::new(), + parameter_symbols: HashMap::new(), + variable_symbols: HashMap::new(), + class_member_symbols: HashMap::new(), + debug_name, + } + } + + pub fn parent(&self) -> Option { + self.parent + } + + pub fn id(&self) -> usize { + self.id + } + + pub fn concrete_use_symbols(&self) -> &HashMap { + &self.concrete_use_symbols + } + + pub fn concrete_use_symbols_mut(&mut self) -> &mut HashMap { + &mut self.concrete_use_symbols + } + + pub fn star_use_symbols(&self) -> &HashMap { + &self.star_use_symbols + } + + pub fn star_use_symbols_mut(&mut self) -> &mut HashMap { + &mut self.star_use_symbols + } + + pub fn module_symbols(&self) -> &HashMap { + &self.module_symbols + } + + pub fn module_symbols_mut(&mut self) -> &mut HashMap { + &mut self.module_symbols + } + + pub fn type_symbols(&self) -> &HashMap { + &self.type_symbols + } + + pub fn type_symbols_mut(&mut self) -> &mut HashMap { + &mut self.type_symbols + } + + pub fn function_symbols(&self) -> &HashMap { + &self.function_symbols + } + + pub fn function_symbols_mut(&mut self) -> &mut HashMap { + &mut self.function_symbols + } + + pub fn parameter_symbols(&self) -> &HashMap { + &self.parameter_symbols + } + + pub fn parameter_symbols_mut(&mut self) -> &mut HashMap { + &mut self.parameter_symbols + } + + pub fn variable_symbols(&self) -> &HashMap { + &self.variable_symbols + } + + pub fn variable_symbols_mut(&mut self) -> &mut HashMap { + &mut self.variable_symbols + } + + pub fn class_member_symbols(&self) -> &HashMap { + &self.class_member_symbols + } + + pub fn class_member_symbols_mut(&mut self) -> &mut HashMap { + &mut self.class_member_symbols + } + + pub fn debug_name(&self) -> &str { + &self.debug_name + } +} + +macro_rules! write_symbols { + ( $f:expr, $symbols:expr ) => { + for symbol in $symbols.values() { + writeln!($f, "{:#?}", symbol)?; + } + }; +} + +impl Display for Scope { + fn fmt(&self, f: &mut Formatter<'_>) -> std::fmt::Result { + writeln!(f, "----Scope {} {}----", self.id(), self.debug_name())?; + write_symbols!(f, self.concrete_use_symbols()); + write_symbols!(f, self.star_use_symbols()); + write_symbols!(f, self.module_symbols()); + write_symbols!(f, self.type_symbols()); + write_symbols!(f, self.function_symbols()); + write_symbols!(f, self.parameter_symbols()); + write_symbols!(f, self.variable_symbols()); + write_symbols!(f, self.class_member_symbols()); + Ok(()) + } +} diff --git a/src/std_core/mod.rs b/src/std_core/mod.rs index 15228d6..619e6c3 100644 --- a/src/std_core/mod.rs +++ b/src/std_core/mod.rs @@ -1,14 +1,27 @@ -use crate::name_analysis::symbol::{FunctionSymbol, ParameterSymbol}; +use crate::name_analysis::symbol::function_symbol::FunctionSymbol; +use crate::name_analysis::symbol::parameter_symbol::ParameterSymbol; use crate::name_analysis::symbol_table::{SymbolInsertError, SymbolTable}; pub fn add_std_core_symbols(symbol_table: &mut SymbolTable) -> Result<(), SymbolInsertError> { symbol_table.insert_function_symbol( - FunctionSymbol::new("std::core::println", "println", true, true, None) - .with_parameters(vec![ParameterSymbol::new("msg", None)]), + FunctionSymbol::without_parameters_or_return_type( + "std::core::println", + "println", + true, + true, + None, + ) + .with_parameters(vec![ParameterSymbol::new("msg", None)]), )?; symbol_table.insert_function_symbol( - FunctionSymbol::new("std::core::print", "print", true, true, None) - .with_parameters(vec![ParameterSymbol::new("msg", None)]), + FunctionSymbol::without_parameters_or_return_type( + "std::core::print", + "print", + true, + true, + None, + ) + .with_parameters(vec![ParameterSymbol::new("msg", None)]), )?; Ok(()) }