diff --git a/src/ast/build.rs b/src/ast/build.rs index 7c3a05f..957c02c 100644 --- a/src/ast/build.rs +++ b/src/ast/build.rs @@ -794,6 +794,7 @@ fn build_field_declaration(file_id: usize, field_pair: Pair) -> FieldDecla } fn build_use_statement(file_id: usize, use_statement_pair: Pair) -> UseStatement { + let as_span = use_statement_pair.as_span(); let mut inner = use_statement_pair.into_inner(); let inner_length = inner.len(); @@ -834,10 +835,15 @@ fn build_use_statement(file_id: usize, use_statement_pair: Pair) -> UseSta } } - UseStatement { + UseStatement::new( identifiers, - last: last.unwrap(), - } + last.unwrap(), + file_id, + Range { + start: as_span.start(), + end: as_span.end(), + } + ) } fn build_block_statement(file_id: usize, block_statement_pair: Pair) -> BlockStatement { diff --git a/src/ast/mod.rs b/src/ast/mod.rs index e0715ac..a8b27d8 100644 --- a/src/ast/mod.rs +++ b/src/ast/mod.rs @@ -1,5 +1,7 @@ +use crate::ast::named::Named; use crate::name_analysis::symbol::Symbol; use pest::Parser; +use std::borrow::Cow; use std::range::Range; pub mod build; @@ -455,6 +457,97 @@ pub struct FieldDeclaration { pub struct UseStatement { pub identifiers: Vec, pub last: UseStatementLast, + pub file_id: usize, + pub range: Range, + scope_id: Option, + symbol: Option, +} + +/// First is declared_name, second is fully_qualified_name +pub type UseStatementName = (String, String); + +impl UseStatement { + pub fn new( + identifiers: Vec, + last: UseStatementLast, + file_id: usize, + range: Range, + ) -> Self { + UseStatement { + identifiers, + last, + file_id, + range, + scope_id: None, + symbol: None, + } + } + + pub fn base_name(&self) -> Cow<'_, str> { + use UseStatementLast::*; + if self.identifiers.is_empty() { + match &self.last { + Identifier(_) => Cow::from(""), + Star | Identifiers(_) => panic!(), // should never get here because of grammar + } + } else if self.identifiers.len() == 1 { + self.identifiers[0].name() + } else { + let mut acc = String::new(); + for (i, identifier) in self.identifiers.iter().enumerate() { + acc.push_str(&identifier.name()); + if i != self.identifiers.len() - 1 { + acc.push_str("::"); + } + } + Cow::from(acc) + } + } + + pub fn names(&self) -> Vec { + let base_name = self.base_name(); + use UseStatementLast::*; + match &self.last { + Identifier(identifier) => vec![( + identifier.name().to_string(), + base_name.to_string() + "::" + &identifier.name(), + )], + Identifiers(identifiers) => { + let mut names = Vec::new(); + for identifier in identifiers { + names.push(( + identifier.name().to_string(), + base_name.to_string() + "::" + &identifier.name(), + )) + } + names + } + Star => panic!("Cannot call names() on a star UseStatement"), + } + } + + pub fn is_star(&self) -> bool { + match &self.last { + UseStatementLast::Star => true, + _ => false, + } + } + + pub fn set_scope_id(&mut self, scope_id: usize) { + self.scope_id = Some(scope_id); + } + + pub fn scope_id(&self) -> Option { + self.scope_id + } + + pub fn set_symbol(&mut self, symbol: Symbol) { + self.symbol = Some(symbol); + } + + pub fn symbol(&self) -> &Option { + &self.symbol + } } #[derive(Debug)] diff --git a/src/name_analysis/gather.rs b/src/name_analysis/gather.rs index f19b27f..e271917 100644 --- a/src/name_analysis/gather.rs +++ b/src/name_analysis/gather.rs @@ -1,10 +1,8 @@ use crate::ast::named::Named; use crate::ast::*; use crate::name_analysis::fqn_context::FqnContext; -use crate::name_analysis::symbol::{ - ClassSymbol, FunctionSymbol, ModuleSymbol, SourceDefinition, Symbol, VariableSymbol, -}; -use crate::name_analysis::symbol_table::{SymbolInsertError, SymbolTable}; +use crate::name_analysis::symbol::*; +use crate::name_analysis::symbol_table::{ScopeLevel, SymbolInsertError, SymbolTable}; use crate::name_analysis::DiagnosticsContainer; use codespan_reporting::diagnostic::{Diagnostic, Label}; use std::range::Range; @@ -121,7 +119,74 @@ fn gather_generic_arguments( } } -pub(super) fn gather_module_level_declaration( +pub(super) fn gather_compilation_unit( + compilation_unit: &mut CompilationUnit, + symbol_table: &mut SymbolTable, + diagnostics: &mut DiagnosticsContainer, +) { + let mut fqn_context = FqnContext::new(); + if let Some(namespace) = &compilation_unit.namespace { + fqn_context.push(namespace.name().to_string()); + } + + symbol_table.push_scope( + &format!("FileScope({})", compilation_unit.file_name), + ScopeLevel::ModuleOrInterfaceOrClass, + ); + for use_statement in &mut compilation_unit.use_statements { + gather_use_statement(use_statement, symbol_table, &mut fqn_context, diagnostics) + } + for declaration in &mut compilation_unit.declarations { + gather_module_level_declaration(declaration, symbol_table, &mut fqn_context, diagnostics); + } + symbol_table.pop_scope(); + assert_eq!(symbol_table.current_scope_id(), 0); +} + +fn gather_use_statement( + use_statement: &mut UseStatement, + symbol_table: &mut SymbolTable, + fqn_context: &mut FqnContext, + diagnostics: &mut DiagnosticsContainer, +) { + if use_statement.is_star() { + todo!() + } + for (declared_name, fully_qualified_name) in use_statement.names() { + let insert_result = symbol_table.insert( + &declared_name, + Symbol::UseStatement(UseStatementSymbol::new( + &fully_qualified_name, + &declared_name, + SourceDefinition::from_use_statement(use_statement), + )), + ); + if let Err(err) = insert_result { + handle_insert_error( + err, + &declared_name, + use_statement.file_id, + use_statement.range, + "Use statement", + diagnostics, + ); + } + match &mut use_statement.last { + UseStatementLast::Identifier(identifier) => { + identifier.set_scope_id(symbol_table.current_scope_id()); + } + UseStatementLast::Identifiers(identifiers) => { + for identifier in identifiers { + identifier.set_scope_id(symbol_table.current_scope_id()); + } + } + _ => {} + } + } + use_statement.set_scope_id(symbol_table.current_scope_id()); +} + +fn gather_module_level_declaration( declaration: &mut ModuleLevelDeclaration, symbol_table: &mut SymbolTable, fqn_context: &mut FqnContext, @@ -187,7 +252,10 @@ fn gather_module_declaration( fqn_context.push(module_name.to_string()); - symbol_table.push_scope(&format!("Module '{}' Scope", module_name)); + symbol_table.push_scope( + &format!("Module '{}' Scope", module_name), + ScopeLevel::ModuleOrInterfaceOrClass, + ); for inner_declaration in &mut declaration.declarations { gather_module_level_declaration(inner_declaration, symbol_table, fqn_context, diagnostics); } @@ -261,7 +329,10 @@ fn gather_function_definition( .identifier .set_scope_id(symbol_table.current_scope_id()); - symbol_table.push_scope(&format!("FunctionScope({})", resolved_name)); + symbol_table.push_scope( + &format!("FunctionScope({})", resolved_name), + ScopeLevel::Function, + ); gather_parameters( &mut function.parameters, symbol_table, @@ -309,7 +380,10 @@ fn gather_platform_function_definition( .identifier .set_scope_id(symbol_table.current_scope_id()); - symbol_table.push_scope(&format!("FunctionScope({})", declared_name_as_string)); + symbol_table.push_scope( + &format!("FunctionScope({})", declared_name_as_string), + ScopeLevel::Function, + ); gather_parameters( &mut platform_function_declaration.parameters, symbol_table, @@ -389,7 +463,7 @@ fn gather_block_statement( fqn_context: &mut FqnContext, diagnostics: &mut DiagnosticsContainer, ) { - symbol_table.push_scope("BlockStatementScope"); + symbol_table.push_scope("BlockStatementScope", ScopeLevel::Function); gather_block_statement_inner(block, symbol_table, fqn_context, diagnostics); symbol_table.pop_scope(); } diff --git a/src/name_analysis/mod.rs b/src/name_analysis/mod.rs index 25513ee..ae12543 100644 --- a/src/name_analysis/mod.rs +++ b/src/name_analysis/mod.rs @@ -1,9 +1,8 @@ use crate::ast::named::Named; use crate::ast::CompilationUnit; use crate::diagnostic::DmDiagnostic; -use crate::name_analysis::fqn_context::FqnContext; -use crate::name_analysis::gather::gather_module_level_declaration; -use crate::name_analysis::resolve::resolve_module_level_declaration; +use crate::name_analysis::gather::gather_compilation_unit; +use crate::name_analysis::resolve::resolve_compilation_unit; use crate::name_analysis::symbol_table::SymbolTable; mod fqn_context; @@ -42,29 +41,12 @@ pub fn analyze_names( // gather symbols for compilation_unit in compilation_units.iter_mut() { - let mut fqn_context = FqnContext::new(); - if let Some(namespace) = &compilation_unit.namespace { - fqn_context.push(namespace.name().to_string()); - } - - symbol_table.push_scope(&format!("FileScope({})", compilation_unit.file_name)); - for declaration in &mut compilation_unit.declarations { - gather_module_level_declaration( - declaration, - symbol_table, - &mut fqn_context, - &mut diagnostics, - ); - } - symbol_table.pop_scope(); - assert_eq!(symbol_table.current_scope_id(), 0); + gather_compilation_unit(compilation_unit, symbol_table, &mut diagnostics); } // resolve symbols for compilation_unit in compilation_units.iter_mut() { - for declaration in &mut compilation_unit.declarations { - resolve_module_level_declaration(declaration, symbol_table, &mut diagnostics); - } + resolve_compilation_unit(compilation_unit, symbol_table, &mut diagnostics); } diagnostics.into() @@ -82,7 +64,7 @@ mod tests { use pest::Parser; use std::collections::HashMap; - fn assert_no_diagnostics(sources: HashMap<&str, &str>) { + fn assert_no_diagnostics(sources: HashMap<&str, &str>) -> SymbolTable { let mut files = SimpleFiles::new(); let mut compilation_units = vec![]; @@ -115,6 +97,12 @@ mod tests { eprintln!("{}", symbol_table); panic!("Diagnostics was not empty!"); } + + for compilation_unit in &compilation_units { + dbg!(compilation_unit); + } + + symbol_table } #[test] @@ -127,7 +115,7 @@ mod tests { }"}, )]); - assert_no_diagnostics(sources) + assert_no_diagnostics(sources); } #[test] diff --git a/src/name_analysis/resolve.rs b/src/name_analysis/resolve.rs index aa80a87..e95fe18 100644 --- a/src/name_analysis/resolve.rs +++ b/src/name_analysis/resolve.rs @@ -1,6 +1,6 @@ use crate::ast::named::Named; use crate::ast::*; -use crate::name_analysis::symbol_table::SymbolTable; +use crate::name_analysis::symbol_table::{SymbolLookupError, SymbolTable}; use crate::name_analysis::DiagnosticsContainer; use codespan_reporting::diagnostic::{Diagnostic, Label}; @@ -37,15 +37,15 @@ fn resolve_fully_qualified_name( fn resolve_type_use( type_use: &mut TypeUse, symbol_table: &mut SymbolTable, - diagnostics: &mut DiagnosticsContainer + diagnostics: &mut DiagnosticsContainer, ) { match type_use { - TypeUse::Void => {}, + TypeUse::Void => {} TypeUse::InterfaceOrClass(interface_or_class_type_use) => { resolve_interface_or_class_type_use( interface_or_class_type_use, symbol_table, - diagnostics + diagnostics, ); } TypeUse::Tuple(tuple_type_use) => { @@ -60,73 +60,65 @@ fn resolve_type_use( fn resolve_interface_or_class_type_use( interface_or_class_type_use: &mut InterfaceOrClassTypeUse, symbol_table: &mut SymbolTable, - diagnostics: &mut DiagnosticsContainer + diagnostics: &mut DiagnosticsContainer, ) { resolve_fully_qualified_name( &mut interface_or_class_type_use.fqn, symbol_table, - diagnostics + diagnostics, ); resolve_generic_arguments( &mut interface_or_class_type_use.generics, symbol_table, - diagnostics + diagnostics, ); } fn resolve_tuple_type_use( tuple_type_use: &mut TupleTypeUse, symbol_table: &mut SymbolTable, - diagnostics: &mut DiagnosticsContainer + diagnostics: &mut DiagnosticsContainer, ) { - resolve_tuple_arguments( - &mut tuple_type_use.arguments, - symbol_table, - diagnostics - ); + resolve_tuple_arguments(&mut tuple_type_use.arguments, symbol_table, diagnostics); } fn resolve_function_type_use( function_type_use: &mut FunctionTypeUse, symbol_table: &mut SymbolTable, - diagnostics: &mut DiagnosticsContainer + diagnostics: &mut DiagnosticsContainer, ) { resolve_parameters(&mut function_type_use.parameters, symbol_table, diagnostics); - resolve_return_type(&mut function_type_use.return_type, symbol_table, diagnostics); + resolve_return_type( + &mut function_type_use.return_type, + symbol_table, + diagnostics, + ); } fn resolve_generic_arguments( generic_arguments: &mut GenericArguments, symbol_table: &mut SymbolTable, - diagnostics: &mut DiagnosticsContainer + diagnostics: &mut DiagnosticsContainer, ) { for generic_argument in &mut generic_arguments.0 { - resolve_type_use( - generic_argument, - symbol_table, - diagnostics - ); + resolve_type_use(generic_argument, symbol_table, diagnostics); } } fn resolve_tuple_arguments( tuple_type_use: &mut TupleArguments, symbol_table: &mut SymbolTable, - diagnostics: &mut DiagnosticsContainer + diagnostics: &mut DiagnosticsContainer, ) { for type_use in &mut tuple_type_use.0 { - resolve_type_use( - type_use, - symbol_table, - diagnostics - ); + resolve_type_use(type_use, symbol_table, diagnostics); } } fn resolve_implements_list( implements_list: &mut ImplementsList, symbol_table: &mut SymbolTable, - diagnostics: &mut DiagnosticsContainer + diagnostics: &mut DiagnosticsContainer, ) { todo!() } @@ -134,7 +126,7 @@ fn resolve_implements_list( fn resolve_parameters( parameters: &mut Parameters, symbol_table: &mut SymbolTable, - diagnostics: &mut DiagnosticsContainer + diagnostics: &mut DiagnosticsContainer, ) { for parameter in &mut parameters.0 { resolve_type_use(&mut parameter.type_use, symbol_table, diagnostics); @@ -144,30 +136,70 @@ fn resolve_parameters( fn resolve_return_type( return_type: &mut ReturnType, symbol_table: &mut SymbolTable, - diagnostics: &mut DiagnosticsContainer + diagnostics: &mut DiagnosticsContainer, ) { - resolve_type_use( - &mut return_type.declared_type, - symbol_table, - diagnostics - ); - resolve_references( - &mut return_type.references, - symbol_table, - diagnostics - ); + resolve_type_use(&mut return_type.declared_type, symbol_table, diagnostics); + resolve_references(&mut return_type.references, symbol_table, diagnostics); } fn resolve_references( references: &mut References, symbol_table: &mut SymbolTable, - diagnostics: &mut DiagnosticsContainer + diagnostics: &mut DiagnosticsContainer, ) { for reference in &mut references.0 { todo!() } } +fn resolve_use_statement( + use_statement: &mut UseStatement, + symbol_table: &mut SymbolTable, + diagnostics: &mut DiagnosticsContainer, +) { + if use_statement.is_star() { + todo!() + } + for (_, fully_qualified_name) in use_statement.names() { + let lookup_result = symbol_table.lookup_usable( + &fully_qualified_name, + use_statement + .scope_id() + .expect("UseStatement.scope_id was not set."), + ); + match lookup_result { + Ok(referenced_symbol) => { + use_statement.set_symbol(referenced_symbol.clone()); + } + Err(err) => match err { + SymbolLookupError::NoDefinition => { + diagnostics.add( + Diagnostic::error() + .with_message(&format!( + "No definition found for symbol '{}'", + fully_qualified_name + )) + .with_label(Label::primary(use_statement.file_id, use_statement.range)), + ); + } + }, + } + } +} + +pub(super) fn resolve_compilation_unit( + compilation_unit: &mut CompilationUnit, + symbol_table: &mut SymbolTable, + diagnostics: &mut DiagnosticsContainer, +) { + for use_statement in &mut compilation_unit.use_statements { + resolve_use_statement(use_statement, symbol_table, diagnostics); + } + for declaration in &mut compilation_unit.declarations { + resolve_module_level_declaration(declaration, symbol_table, diagnostics); + } +} + pub(super) fn resolve_module_level_declaration( declaration: &mut ModuleLevelDeclaration, symbol_table: &mut SymbolTable, @@ -178,13 +210,11 @@ pub(super) fn resolve_module_level_declaration( Function(function_definition) => { resolve_function_definition(function_definition, symbol_table, diagnostics) } - PlatformFunction(platform_function_declaration) => { - resolve_platform_function_declaration( - platform_function_declaration, - symbol_table, - diagnostics, - ) - } + PlatformFunction(platform_function_declaration) => resolve_platform_function_declaration( + platform_function_declaration, + symbol_table, + diagnostics, + ), Class(class_declaration) => { // todo } @@ -197,18 +227,34 @@ fn resolve_function_definition( symbol_table: &mut SymbolTable, diagnostics: &mut DiagnosticsContainer, ) { - resolve_parameters(&mut function_definition.parameters, symbol_table, diagnostics); - resolve_return_type(&mut function_definition.return_type, symbol_table, diagnostics); + resolve_parameters( + &mut function_definition.parameters, + symbol_table, + diagnostics, + ); + resolve_return_type( + &mut function_definition.return_type, + symbol_table, + diagnostics, + ); resolve_function_body(&mut function_definition.body, symbol_table, diagnostics); } fn resolve_platform_function_declaration( platform_function_declaration: &mut PlatformFunctionDeclaration, symbol_table: &mut SymbolTable, - diagnostics: &mut DiagnosticsContainer + diagnostics: &mut DiagnosticsContainer, ) { - resolve_parameters(&mut platform_function_declaration.parameters, symbol_table, diagnostics); - resolve_return_type(&mut platform_function_declaration.return_type, symbol_table, diagnostics); + resolve_parameters( + &mut platform_function_declaration.parameters, + symbol_table, + diagnostics, + ); + resolve_return_type( + &mut platform_function_declaration.return_type, + symbol_table, + diagnostics, + ); } fn resolve_function_body( @@ -298,32 +344,16 @@ fn resolve_expression( resolve_binary_expression(binary_expression, symbol_table, diagnostics); } UnaryPrefix(prefix_expression) => { - resolve_prefix_expression( - prefix_expression, - symbol_table, - diagnostics, - ); + resolve_prefix_expression(prefix_expression, symbol_table, diagnostics); } UnarySuffix(suffix_expression) => { - resolve_suffix_expression( - suffix_expression, - symbol_table, - diagnostics, - ); + resolve_suffix_expression(suffix_expression, symbol_table, diagnostics); } Call(call_expression) => { - resolve_call_expression( - call_expression, - symbol_table, - diagnostics, - ) + resolve_call_expression(call_expression, symbol_table, diagnostics) } ObjectAccess(object_access) => { - resolve_object_access( - object_access, - symbol_table, - diagnostics, - ); + resolve_object_access(object_access, symbol_table, diagnostics); } FullyQualifiedName(fqn) => resolve_fully_qualified_name(fqn, symbol_table, diagnostics), Literal(literal) => { @@ -338,17 +368,25 @@ fn resolve_expression( fn resolve_ternary_expression( ternary_expression: &mut TernaryExpression, symbol_table: &mut SymbolTable, - diagnostics: &mut DiagnosticsContainer + diagnostics: &mut DiagnosticsContainer, ) { resolve_expression(&mut ternary_expression.condition, symbol_table, diagnostics); - resolve_expression(&mut ternary_expression.true_expression, symbol_table, diagnostics); - resolve_expression(&mut ternary_expression.false_expression, symbol_table, diagnostics); + resolve_expression( + &mut ternary_expression.true_expression, + symbol_table, + diagnostics, + ); + resolve_expression( + &mut ternary_expression.false_expression, + symbol_table, + diagnostics, + ); } fn resolve_binary_expression( binary_expression: &mut BinaryExpression, symbol_table: &mut SymbolTable, - diagnostics: &mut DiagnosticsContainer + diagnostics: &mut DiagnosticsContainer, ) { resolve_expression(&mut binary_expression.left, symbol_table, diagnostics); resolve_expression(&mut binary_expression.right, symbol_table, diagnostics); @@ -357,7 +395,7 @@ fn resolve_binary_expression( fn resolve_prefix_expression( prefix_expression: &mut PrefixExpression, symbol_table: &mut SymbolTable, - diagnostics: &mut DiagnosticsContainer + diagnostics: &mut DiagnosticsContainer, ) { resolve_expression(&mut prefix_expression.expression, symbol_table, diagnostics); } @@ -365,7 +403,7 @@ fn resolve_prefix_expression( fn resolve_suffix_expression( suffix_expression: &mut SuffixExpression, symbol_table: &mut SymbolTable, - diagnostics: &mut DiagnosticsContainer + diagnostics: &mut DiagnosticsContainer, ) { resolve_expression(&mut suffix_expression.expression, symbol_table, diagnostics); } @@ -373,7 +411,7 @@ fn resolve_suffix_expression( fn resolve_call_expression( call_expression: &mut CallExpression, symbol_table: &mut SymbolTable, - diagnostics: &mut DiagnosticsContainer + diagnostics: &mut DiagnosticsContainer, ) { resolve_expression(&mut call_expression.callee, symbol_table, diagnostics); if let Some(turbo_fish) = &mut call_expression.turbo_fish { @@ -385,7 +423,7 @@ fn resolve_call_expression( fn resolve_turbo_fish( turbo_fish: &mut TurboFish, symbol_table: &mut SymbolTable, - diagnostics: &mut DiagnosticsContainer + diagnostics: &mut DiagnosticsContainer, ) { todo!() } @@ -393,7 +431,7 @@ fn resolve_turbo_fish( fn resolve_call_arguments( call_arguments: &mut CallArguments, symbol_table: &mut SymbolTable, - diagnostics: &mut DiagnosticsContainer + diagnostics: &mut DiagnosticsContainer, ) { for argument in &mut call_arguments.0 { resolve_call_argument(argument, symbol_table, diagnostics); @@ -403,7 +441,7 @@ fn resolve_call_arguments( fn resolve_call_argument( call_argument: &mut CallArgument, symbol_table: &mut SymbolTable, - diagnostics: &mut DiagnosticsContainer + diagnostics: &mut DiagnosticsContainer, ) { resolve_expression(&mut call_argument.0, symbol_table, diagnostics); } @@ -411,7 +449,7 @@ fn resolve_call_argument( fn resolve_closure( closure: &mut Closure, symbol_table: &mut SymbolTable, - diagnostics: &mut DiagnosticsContainer + diagnostics: &mut DiagnosticsContainer, ) { todo!() } @@ -419,7 +457,7 @@ fn resolve_closure( fn resolve_object_access( object_access: &mut ObjectAccess, symbol_table: &mut SymbolTable, - diagnostics: &mut DiagnosticsContainer + diagnostics: &mut DiagnosticsContainer, ) { todo!() } @@ -427,7 +465,7 @@ fn resolve_object_access( fn resolve_literal( literal: &mut Literal, symbol_table: &mut SymbolTable, - diagnostics: &mut DiagnosticsContainer + diagnostics: &mut DiagnosticsContainer, ) { match literal { Literal::DString(d_string) => resolve_d_string(d_string, symbol_table, diagnostics), @@ -439,7 +477,7 @@ fn resolve_literal( fn resolve_d_string( d_string: &mut DString, symbol_table: &mut SymbolTable, - diagnostics: &mut DiagnosticsContainer + diagnostics: &mut DiagnosticsContainer, ) { todo!() -} \ No newline at end of file +} diff --git a/src/name_analysis/symbol.rs b/src/name_analysis/symbol.rs index 9dda203..355d4a4 100644 --- a/src/name_analysis/symbol.rs +++ b/src/name_analysis/symbol.rs @@ -1,4 +1,4 @@ -use crate::ast::Identifier; +use crate::ast::{Identifier, UseStatement}; use std::fmt::Display; use std::range::Range; @@ -16,6 +16,13 @@ impl SourceDefinition { } } + pub fn from_use_statement(use_statement: &UseStatement) -> Self { + SourceDefinition { + file_id: use_statement.file_id, + range: use_statement.range, + } + } + pub fn file_id(&self) -> usize { self.file_id } @@ -31,6 +38,7 @@ pub enum Symbol { Variable(VariableSymbol), Module(ModuleSymbol), Class(ClassSymbol), + UseStatement(UseStatementSymbol), } impl Symbol { @@ -40,6 +48,7 @@ impl Symbol { Symbol::Variable(s) => s.name.as_str(), Symbol::Module(s) => s.declared_name.as_str(), Symbol::Class(s) => s.declared_name.as_str(), + Symbol::UseStatement(s) => s.declared_name.as_str(), } } @@ -49,6 +58,7 @@ impl Symbol { Symbol::Module(s) => s.definition(), Symbol::Variable(s) => s.definition(), Symbol::Class(s) => s.definition(), + Symbol::UseStatement(s) => s.definition(), } } } @@ -61,6 +71,7 @@ impl Display for Symbol { Variable(variable_symbol) => write!(f, "{}", variable_symbol), Module(module_symbol) => write!(f, "{}", module_symbol), Class(class_symbol) => write!(f, "{}", class_symbol), + UseStatement(use_statement_symbol) => write!(f, "{}", use_statement_symbol), } } } @@ -192,7 +203,7 @@ impl ClassSymbol { definition: SourceDefinition::from_identifier(identifier), } } - + pub fn definition(&self) -> &SourceDefinition { &self.definition } @@ -207,3 +218,44 @@ impl Display for ClassSymbol { ) } } + +#[derive(Debug, Clone)] +pub struct UseStatementSymbol { + pub fqn: String, + pub declared_name: String, + definition: SourceDefinition, + referenced_symbol: Option> +} + +impl UseStatementSymbol { + pub fn new(fqn: &str, declared_name: &str, definition: SourceDefinition) -> Self { + UseStatementSymbol { + fqn: fqn.to_string(), + declared_name: declared_name.to_string(), + definition, + referenced_symbol: None, + } + } + + pub fn definition(&self) -> &SourceDefinition { + &self.definition + } + + 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 Display for UseStatementSymbol { + fn fmt(&self, f: &mut std::fmt::Formatter) -> std::fmt::Result { + write!( + f, + "UseStatementSymbol(fqn = {}, declared_name = {})", + self.fqn, self.declared_name + ) + } +} diff --git a/src/name_analysis/symbol_table.rs b/src/name_analysis/symbol_table.rs index 66db1f2..3241ed7 100644 --- a/src/name_analysis/symbol_table.rs +++ b/src/name_analysis/symbol_table.rs @@ -1,25 +1,88 @@ use crate::name_analysis::symbol::Symbol; -use std::collections::HashMap; -use std::fmt::Display; use crate::name_analysis::symbol_table::SymbolInsertError::SymbolAlreadyDefined; use crate::name_analysis::symbol_table::SymbolLookupError::NoDefinition; +use std::collections::HashMap; +use std::fmt::Display; +#[derive(Debug, PartialEq, Clone)] +pub enum ScopeLevel { + Global, + ModuleOrInterfaceOrClass, + Function, +} + +#[derive(Debug)] pub struct Scope { + level: ScopeLevel, parent: Option, - function_and_variable_symbols: HashMap, - type_and_module_symbols: HashMap, + use_statement_symbols: HashMap, + module_symbols: HashMap, + type_symbols: HashMap, + function_symbols: HashMap, + variable_symbols: HashMap, debug_name: String, } impl Scope { - pub fn new(parent: Option, debug_name: String) -> Scope { + pub fn new(parent: Option, debug_name: String, level: ScopeLevel) -> Scope { Scope { + level, parent, - function_and_variable_symbols: HashMap::new(), - type_and_module_symbols: HashMap::new(), + use_statement_symbols: HashMap::new(), + module_symbols: HashMap::new(), + type_symbols: HashMap::new(), + function_symbols: HashMap::new(), + variable_symbols: HashMap::new(), debug_name, } } + + pub fn level(&self) -> ScopeLevel { + self.level.clone() + } + + fn get_any_symbol(&self, name: &str) -> Option<&Symbol> { + self.variable_symbols + .get(name) + .or_else(|| self.function_symbols.get(name)) + .or_else(|| self.type_symbols.get(name)) + .or_else(|| self.module_symbols.get(name)) + .or_else(|| self.use_statement_symbols.get(name)) + } + + fn get_usable_symbol(&self, fqn: &str) -> Option<&Symbol> { + for function_symbol in self.function_symbols.values() { + match function_symbol { + Symbol::Function(s) => { + if s.fqn == fqn { + return Some(function_symbol); + } + } + _ => panic!("Cannot have non-function in function_symbols."), + } + } + for type_symbol in self.type_symbols.values() { + match type_symbol { + Symbol::Class(s) => { + if s.fqn == fqn { + return Some(type_symbol); + } + } + _ => panic!("Cannot have non-class in type_symbols."), + } + } + None + } + + pub fn symbols(&self) -> Vec<&Symbol> { + let mut symbols: Vec<&Symbol> = Vec::new(); + symbols.extend(self.use_statement_symbols.values()); + symbols.extend(self.module_symbols.values()); + symbols.extend(self.type_symbols.values()); + symbols.extend(self.function_symbols.values()); + symbols.extend(self.variable_symbols.values()); + symbols + } } pub enum SymbolInsertError { @@ -27,9 +90,10 @@ pub enum SymbolInsertError { } pub enum SymbolLookupError { - NoDefinition + NoDefinition, } +#[derive(Debug)] pub struct SymbolTable { scopes: Vec, current_scope_id: usize, @@ -39,7 +103,11 @@ pub struct SymbolTable { impl SymbolTable { pub fn new() -> Self { let mut t = SymbolTable { - scopes: vec![Scope::new(None, String::from("GlobalScope"))], + scopes: vec![Scope::new( + None, + String::from("GlobalScope"), + ScopeLevel::Global, + )], current_scope_id: 0, }; t @@ -49,10 +117,17 @@ impl SymbolTable { self.current_scope_id } - pub fn push_scope(&mut self, debug_name: &str) { + pub fn scopes(&self) -> &Vec { + &self.scopes + } + + pub fn push_scope(&mut self, debug_name: &str, level: ScopeLevel) { let id = self.scopes.len(); - self.scopes - .push(Scope::new(Some(self.current_scope_id), debug_name.to_string())); + self.scopes.push(Scope::new( + Some(self.current_scope_id), + debug_name.to_string(), + level, + )); self.current_scope_id = id; } @@ -68,32 +143,53 @@ impl SymbolTable { self.insert_function_or_variable(name, symbol) } Symbol::Module(_) | Symbol::Class(_) => self.insert_module_or_type(name, symbol), + Symbol::UseStatement(_) => self.insert_use_statement_symbol(name, symbol), } } - fn insert_function_or_variable(&mut self, name: &str, symbol: Symbol) -> Result<(), SymbolInsertError> { + fn insert_function_or_variable( + &mut self, + name: &str, + symbol: Symbol, + ) -> Result<(), SymbolInsertError> { if let Some(defined_symbol) = self.scopes[self.current_scope_id] - .function_and_variable_symbols + .function_symbols .get(name) { Err(SymbolAlreadyDefined(defined_symbol.clone())) } else { self.scopes[self.current_scope_id] - .function_and_variable_symbols + .function_symbols .insert(name.to_string(), symbol); Ok(()) } } - fn insert_module_or_type(&mut self, name: &str, symbol: Symbol) -> Result<(), SymbolInsertError> { - if let Some(defined_symbol) = self.scopes[self.current_scope_id] - .type_and_module_symbols - .get(name) - { + fn insert_module_or_type( + &mut self, + name: &str, + symbol: Symbol, + ) -> Result<(), SymbolInsertError> { + if let Some(defined_symbol) = self.scopes[self.current_scope_id].type_symbols.get(name) { Err(SymbolAlreadyDefined(defined_symbol.clone())) } else { self.scopes[self.current_scope_id] - .type_and_module_symbols + .type_symbols + .insert(name.to_string(), symbol); + Ok(()) + } + } + + fn insert_use_statement_symbol( + &mut self, + name: &str, + symbol: Symbol, + ) -> Result<(), SymbolInsertError> { + if let Some(defined_symbol) = self.scopes[self.current_scope_id].get_any_symbol(name) { + Err(SymbolAlreadyDefined(defined_symbol.clone())) + } else { + self.scopes[self.current_scope_id] + .use_statement_symbols .insert(name.to_string(), symbol); Ok(()) } @@ -102,7 +198,7 @@ impl SymbolTable { pub fn lookup(&self, name: &str, scope_id: usize) -> Result<&Symbol, SymbolLookupError> { let mut scope_opt = Some(&self.scopes[scope_id]); while let Some(scope) = scope_opt { - if let Some(symbol) = scope.function_and_variable_symbols.get(name) { + if let Some(symbol) = scope.get_any_symbol(name) { return Ok(symbol); } scope_opt = if let Some(parent_id) = scope.parent { @@ -113,6 +209,22 @@ impl SymbolTable { } Err(NoDefinition) } + + pub fn lookup_usable( + &self, + fully_qualified_name: &str, + scope_id: usize, + ) -> Result<&Symbol, SymbolLookupError> { + for scope in &self.scopes { + if scope.level == ScopeLevel::Function { + continue; + } + if let Some(symbol) = scope.get_usable_symbol(fully_qualified_name) { + return Ok(symbol); + } + } + Err(NoDefinition) + } } impl Display for SymbolTable { @@ -120,10 +232,19 @@ impl Display for SymbolTable { 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 (name, symbol) in &scope.type_and_module_symbols { + for (name, symbol) in &scope.use_statement_symbols { writeln!(f, " {}({})", name, symbol)?; } - for (name, symbol) in &scope.function_and_variable_symbols { + for (name, symbol) in &scope.module_symbols { + writeln!(f, " {}({})", name, symbol)?; + } + for (name, symbol) in &scope.type_symbols { + writeln!(f, " {}({})", name, symbol)?; + } + for (name, symbol) in &scope.function_symbols { + writeln!(f, " {}({})", name, symbol)?; + } + for (name, symbol) in &scope.variable_symbols { writeln!(f, " {}({})", name, symbol)?; } }