From 6b6ba1d71237664fe3fcea3059b34b68d4a8c0fc Mon Sep 17 00:00:00 2001 From: Jesse Brault Date: Sun, 18 May 2025 18:03:40 -0500 Subject: [PATCH] Major refactor of name analysis and related. --- src/ast/build.rs | 20 +- src/ast/mod.rs | 45 ++-- src/ast/pretty_print.rs | 4 +- src/ast/unparse.rs | 4 +- src/lib.rs | 1 + src/name_analysis/gather.rs | 210 +++++++++--------- src/name_analysis/mod.rs | 2 + src/name_analysis/resolve.rs | 33 +-- src/name_analysis/symbol.rs | 345 ++++++++++++++++++++---------- src/name_analysis/symbol_table.rs | 264 ++++++++++++++--------- src/std_core/mod.rs | 27 +++ 11 files changed, 553 insertions(+), 402 deletions(-) create mode 100644 src/std_core/mod.rs diff --git a/src/ast/build.rs b/src/ast/build.rs index 957c02c..16ecafe 100644 --- a/src/ast/build.rs +++ b/src/ast/build.rs @@ -600,7 +600,7 @@ fn build_platform_function_declaration( let mut identifier = None; let mut parameters = Parameters::default(); let mut return_type = None; - + for inner_pair in platform_function_pair.into_inner() { match inner_pair.as_rule() { Rule::Pub => { @@ -609,7 +609,7 @@ fn build_platform_function_declaration( Rule::FunctionModifier => { modifier = Some(build_function_modifier(file_id, inner_pair)); } - Rule::Platform | Rule::Fn => {}, + Rule::Platform | Rule::Fn => {} Rule::GenericParameters => { generics = build_generic_parameters(file_id, inner_pair); } @@ -625,7 +625,7 @@ fn build_platform_function_declaration( _ => unreachable!(), } } - + PlatformFunctionDeclaration { is_public, modifier, @@ -813,20 +813,20 @@ fn build_use_statement(file_id: usize, use_statement_pair: Pair) -> UseSta )) } else { last = Some(match inner_pair.as_rule() { - Rule::Identifier => { - UseStatementLast::Identifier(build_identifier(file_id, inner_pair)) - } + Rule::Identifier => UseStatementLast::Identifier(Rc::new(RefCell::new( + build_identifier(file_id, inner_pair), + ))), Rule::Star => UseStatementLast::Star, Rule::UseList => UseStatementLast::Identifiers( inner_pair .into_inner() .map(|identifier_pair| { - expect_and_use( + Rc::new(RefCell::new(expect_and_use( file_id, identifier_pair, Rule::Identifier, build_identifier, - ) + ))) }) .collect(), ), @@ -842,7 +842,7 @@ fn build_use_statement(file_id: usize, use_statement_pair: Pair) -> UseSta Range { start: as_span.start(), end: as_span.end(), - } + }, ) } @@ -1843,7 +1843,7 @@ mod tests { fn use_list() { assert_builds("use std::core::{print, println};"); } - + #[test] fn platform_function() { assert_builds("platform fn println(msg: Any) -> Void;"); diff --git a/src/ast/mod.rs b/src/ast/mod.rs index a8b27d8..60bd899 100644 --- a/src/ast/mod.rs +++ b/src/ast/mod.rs @@ -2,7 +2,9 @@ use crate::ast::named::Named; use crate::name_analysis::symbol::Symbol; use pest::Parser; use std::borrow::Cow; +use std::cell::RefCell; use std::range::Range; +use std::rc::Rc; pub mod build; pub mod named; @@ -463,8 +465,11 @@ pub struct UseStatement { symbol: Option, } -/// First is declared_name, second is fully_qualified_name -pub type UseStatementName = (String, String); +pub struct UseStatementImport<'a> { + pub declared_name: String, + pub fqn: String, + pub identifier: &'a mut Identifier, +} impl UseStatement { pub fn new( @@ -482,7 +487,7 @@ impl UseStatement { symbol: None, } } - + pub fn base_name(&self) -> Cow<'_, str> { use UseStatementLast::*; if self.identifiers.is_empty() { @@ -504,47 +509,25 @@ impl UseStatement { } } - 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 } @@ -552,8 +535,8 @@ impl UseStatement { #[derive(Debug)] pub enum UseStatementLast { - Identifier(Identifier), - Identifiers(Vec), + Identifier(Rc>), + Identifiers(Vec>>), Star, } diff --git a/src/ast/pretty_print.rs b/src/ast/pretty_print.rs index e852f2a..c33b627 100644 --- a/src/ast/pretty_print.rs +++ b/src/ast/pretty_print.rs @@ -606,10 +606,10 @@ impl PrettyPrint for UseStatementLast { writer.writeln_indented("UseStatementLast")?; writer.increase_indent(); match self { - UseStatementLast::Identifier(i) => i.pretty_print(writer)?, + UseStatementLast::Identifier(i) => i.borrow().pretty_print(writer)?, UseStatementLast::Identifiers(is) => { for i in is { - i.pretty_print(writer)?; + i.borrow().pretty_print(writer)?; } }, UseStatementLast::Star => { diff --git a/src/ast/unparse.rs b/src/ast/unparse.rs index c4caa67..404d837 100644 --- a/src/ast/unparse.rs +++ b/src/ast/unparse.rs @@ -749,7 +749,7 @@ impl Unparse for UseStatementLast { UseStatementLast::Identifiers(identifiers) => { writer.write("{")?; for (i, identifier) in identifiers.iter().enumerate() { - identifier.unparse(writer)?; + identifier.borrow().unparse(writer)?; if i != identifiers.len() - 1 { writer.write(", ")?; } @@ -757,7 +757,7 @@ impl Unparse for UseStatementLast { writer.write("}")?; Ok(()) } - UseStatementLast::Identifier(i) => i.unparse(writer), + UseStatementLast::Identifier(i) => i.borrow().unparse(writer), } } } diff --git a/src/lib.rs b/src/lib.rs index 916222f..d667f1e 100644 --- a/src/lib.rs +++ b/src/lib.rs @@ -6,5 +6,6 @@ pub mod module; pub mod name_analysis; pub mod object_file; pub mod parser; +mod std_core; pub mod util; pub mod vm; diff --git a/src/name_analysis/gather.rs b/src/name_analysis/gather.rs index 0504838..6ee4ea6 100644 --- a/src/name_analysis/gather.rs +++ b/src/name_analysis/gather.rs @@ -1,11 +1,13 @@ use crate::ast::named::Named; use crate::ast::*; +use crate::diagnostic::DmDiagnostic; use crate::name_analysis::fqn_context::FqnContext; use crate::name_analysis::symbol::*; -use crate::name_analysis::symbol_table::{ScopeLevel, SymbolInsertError, SymbolTable}; +use crate::name_analysis::symbol_table::{SymbolInsertError, SymbolTable}; use codespan_reporting::diagnostic::{Diagnostic, Label}; +use std::cell::RefCell; use std::range::Range; -use crate::diagnostic::DmDiagnostic; +use std::rc::Rc; fn handle_insert_error( err: SymbolInsertError, @@ -17,25 +19,24 @@ fn handle_insert_error( ) { match err { SymbolInsertError::SymbolAlreadyDefined(s) => { - let already_defined_definition = s.definition(); - diagnostics.push( - 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."), - ) - .with_label( - Label::secondary( - already_defined_definition.file_id(), - already_defined_definition.range(), - ) + 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); } } } @@ -128,10 +129,7 @@ pub(super) fn gather_compilation_unit( fqn_context.push(namespace.name().to_string()); } - symbol_table.push_scope( - &format!("FileScope({})", compilation_unit.file_name), - ScopeLevel::ModuleOrInterfaceOrClass, - ); + symbol_table.push_scope(&format!("FileScope({})", compilation_unit.file_name)); for use_statement in &mut compilation_unit.use_statements { gather_use_statement(use_statement, symbol_table, &mut fqn_context, diagnostics) } @@ -142,6 +140,35 @@ pub(super) fn gather_compilation_unit( assert_eq!(symbol_table.current_scope_id(), 0); } +fn handle_use_statement_import( + symbol_table: &mut SymbolTable, + base_name: &str, + identifier: Rc>, + diagnostics: &mut Vec, +) { + let borrowed_identifier = identifier.borrow(); + let declared_name = borrowed_identifier.name().to_string(); + let insert_result = symbol_table.insert_use_statement_symbol(UseStatementSymbol::new( + &format!("{}::{}", base_name, &declared_name), + &declared_name, + Some(identifier.clone()), + )); + if let Err(err) = insert_result { + handle_insert_error( + err, + &declared_name, + borrowed_identifier.file_id, + borrowed_identifier.range, + "Use statement", + diagnostics, + ); + } + drop(borrowed_identifier); + identifier + .borrow_mut() + .set_scope_id(symbol_table.current_scope_id()) +} + fn gather_use_statement( use_statement: &mut UseStatement, symbol_table: &mut SymbolTable, @@ -151,38 +178,23 @@ fn gather_use_statement( 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, - ); + let base_name = use_statement.base_name().to_string(); + match &mut use_statement.last { + UseStatementLast::Identifier(identifier) => { + handle_use_statement_import(symbol_table, &base_name, identifier.clone(), 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 { + handle_use_statement_import( + symbol_table, + &base_name, + identifier.clone(), + diagnostics, + ) } - UseStatementLast::Identifiers(identifiers) => { - for identifier in identifiers { - identifier.set_scope_id(symbol_table.current_scope_id()); - } - } - _ => {} } + UseStatementLast::Star => panic!(), } - use_statement.set_scope_id(symbol_table.current_scope_id()); } fn gather_module_level_declaration( @@ -228,15 +240,12 @@ fn gather_module_declaration( let module_name = declaration.identifier.name(); - let insert_result = symbol_table.insert( + let insert_result = symbol_table.insert_module_symbol(ModuleSymbol::new( + &fqn_context.resolve(&module_name), &module_name, - Symbol::Module(ModuleSymbol::new( - &fqn_context.resolve(&module_name), - &module_name, - declaration.is_public, - &declaration.identifier, - )), - ); + declaration.is_public, + Some(&declaration.identifier), + )); if let Err(err) = insert_result { handle_insert_error( @@ -251,10 +260,7 @@ fn gather_module_declaration( fqn_context.push(module_name.to_string()); - symbol_table.push_scope( - &format!("Module '{}' Scope", module_name), - ScopeLevel::ModuleOrInterfaceOrClass, - ); + symbol_table.push_scope(&format!("ModuleScope({})", module_name)); for inner_declaration in &mut declaration.declarations { gather_module_level_declaration(inner_declaration, symbol_table, fqn_context, diagnostics); } @@ -270,15 +276,12 @@ fn gather_class_declaration( let declared_name = class_declaration.identifier.name(); let resolved_name = fqn_context.resolve(&declared_name); - let insert_result = symbol_table.insert( + let insert_result = symbol_table.insert_type_symbol(TypeSymbol::new( + &resolved_name, &declared_name, - Symbol::Class(ClassSymbol::new( - &resolved_name, - &declared_name, - class_declaration.is_public, - &class_declaration.identifier, - )), - ); + class_declaration.is_public, + Some(&class_declaration.identifier), + )); if let Err(err) = insert_result { handle_insert_error( err, @@ -302,16 +305,13 @@ fn gather_function_definition( let declared_name = function.identifier.name(); let resolved_name = fqn_context.resolve(&declared_name); - let insert_result = symbol_table.insert( + let insert_result = symbol_table.insert_function_symbol(FunctionSymbol::new( + &resolved_name, &declared_name, - Symbol::Function(FunctionSymbol::new( - &resolved_name, - &declared_name, - function.is_public, - false, - &function.identifier, - )), - ); + function.is_public, + false, + Some(&function.identifier), + )); if let Err(err) = insert_result { handle_insert_error( @@ -328,10 +328,7 @@ fn gather_function_definition( .identifier .set_scope_id(symbol_table.current_scope_id()); - symbol_table.push_scope( - &format!("FunctionScope({})", resolved_name), - ScopeLevel::Function, - ); + symbol_table.push_scope(&format!("FunctionScope({})", resolved_name)); gather_parameters( &mut function.parameters, symbol_table, @@ -351,16 +348,13 @@ fn gather_platform_function_definition( let declared_name = platform_function_declaration.identifier.name(); let fully_qualified_name = fqn_context.resolve(&declared_name); - let insert_result = symbol_table.insert( + let insert_result = symbol_table.insert_function_symbol(FunctionSymbol::new( + &fully_qualified_name, &declared_name, - Symbol::Function(FunctionSymbol::new( - &fully_qualified_name, - &declared_name, - platform_function_declaration.is_public, - true, - &platform_function_declaration.identifier, - )), - ); + platform_function_declaration.is_public, + true, + Some(&platform_function_declaration.identifier), + )); if let Err(err) = insert_result { handle_insert_error( @@ -379,10 +373,7 @@ fn gather_platform_function_definition( .identifier .set_scope_id(symbol_table.current_scope_id()); - symbol_table.push_scope( - &format!("FunctionScope({})", declared_name_as_string), - ScopeLevel::Function, - ); + symbol_table.push_scope(&format!("FunctionScope({})", declared_name_as_string)); gather_parameters( &mut platform_function_declaration.parameters, symbol_table, @@ -411,14 +402,10 @@ fn gather_parameter( ) { let parameter_name = parameter.identifier.name(); - let insert_result = symbol_table.insert( + let insert_result = symbol_table.insert_parameter_symbol(ParameterSymbol::new( ¶meter_name, - Symbol::Variable(VariableSymbol::new( - ¶meter_name, - false, - SourceDefinition::from_identifier(¶meter.identifier), - )), - ); + Some(¶meter.identifier), + )); if let Err(err) = insert_result { handle_insert_error( @@ -462,7 +449,7 @@ fn gather_block_statement( fqn_context: &mut FqnContext, diagnostics: &mut Vec, ) { - symbol_table.push_scope("BlockStatementScope", ScopeLevel::Function); + symbol_table.push_scope("BlockStatementScope"); gather_block_statement_inner(block, symbol_table, fqn_context, diagnostics); symbol_table.pop_scope(); } @@ -512,14 +499,11 @@ fn gather_variable_declaration( ) { let variable_name = variable_declaration.identifier.name(); - let insert_result = symbol_table.insert( + let insert_result = symbol_table.insert_variable_symbol(VariableSymbol::new( &variable_name, - Symbol::Variable(VariableSymbol::new( - &variable_name, - variable_declaration.is_mutable, - SourceDefinition::from_identifier(&variable_declaration.identifier), - )), - ); + variable_declaration.is_mutable, + Some(&variable_declaration.identifier), + )); if let Err(err) = insert_result { handle_insert_error( diff --git a/src/name_analysis/mod.rs b/src/name_analysis/mod.rs index e7db1b4..c46c582 100644 --- a/src/name_analysis/mod.rs +++ b/src/name_analysis/mod.rs @@ -35,6 +35,7 @@ mod tests { use super::*; use crate::ast::build::build_ast; use crate::parser::{DeimosParser, Rule}; + use crate::std_core::add_std_core_symbols; use codespan_reporting::files::SimpleFiles; use codespan_reporting::term; use codespan_reporting::term::termcolor::{ColorChoice, StandardStream}; @@ -61,6 +62,7 @@ mod tests { } let mut symbol_table = SymbolTable::new(); + add_std_core_symbols(&mut symbol_table).expect("Failed to add std_core_symbols"); let diagnostics = analyze_names(&mut compilation_units, &mut symbol_table); diff --git a/src/name_analysis/resolve.rs b/src/name_analysis/resolve.rs index 126fe96..d0e3826 100644 --- a/src/name_analysis/resolve.rs +++ b/src/name_analysis/resolve.rs @@ -1,8 +1,8 @@ use crate::ast::named::Named; use crate::ast::*; -use crate::name_analysis::symbol_table::{SymbolLookupError, SymbolTable}; -use codespan_reporting::diagnostic::{Diagnostic, Label}; use crate::diagnostic::DmDiagnostic; +use crate::name_analysis::symbol_table::SymbolTable; +use codespan_reporting::diagnostic::{Diagnostic, Label}; fn resolve_fully_qualified_name( fully_qualified_name: &mut FullyQualifiedName, @@ -160,30 +160,11 @@ fn resolve_use_statement( 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.push( - Diagnostic::error() - .with_message(&format!( - "No definition found for symbol '{}'", - fully_qualified_name - )) - .with_label(Label::primary(use_statement.file_id, use_statement.range)), - ); - } - }, - } + + match &use_statement.last { + UseStatementLast::Identifier(identifier) => {} + UseStatementLast::Identifiers(identifiers) => {} + UseStatementLast::Star => panic!(), } } diff --git a/src/name_analysis/symbol.rs b/src/name_analysis/symbol.rs index 355d4a4..c974d0d 100644 --- a/src/name_analysis/symbol.rs +++ b/src/name_analysis/symbol.rs @@ -1,6 +1,8 @@ +use std::cell::RefCell; use crate::ast::{Identifier, UseStatement}; use std::fmt::Display; use std::range::Range; +use std::rc::Rc; #[derive(Clone, Debug)] pub struct SourceDefinition { @@ -15,7 +17,16 @@ impl SourceDefinition { range: identifier.range, } } + + pub fn from_identifier_rc(identifier: Rc>) -> Self { + let borrowed = identifier.borrow(); + SourceDefinition { + file_id: borrowed.file_id, + range: borrowed.range, + } + } + #[deprecated(note = "Use identifier instead.")] pub fn from_use_statement(use_statement: &UseStatement) -> Self { SourceDefinition { file_id: use_statement.file_id, @@ -32,33 +43,50 @@ impl SourceDefinition { } } +pub trait SymbolInner { + fn declared_name(&self) -> &str; + fn definition(&self) -> &Option; +} + +/* Symbol */ + #[derive(Debug, Clone)] pub enum Symbol { - Function(FunctionSymbol), - Variable(VariableSymbol), - Module(ModuleSymbol), - Class(ClassSymbol), - UseStatement(UseStatementSymbol), + UseStatement(Rc), + Module(Rc), + Type(Rc), + Function(Rc), + Parameter(Rc), + Variable(Rc), } impl Symbol { pub fn name(&self) -> &str { match self { - Symbol::Function(s) => s.declared_name.as_str(), - 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(), + Symbol::UseStatement(s) => s.declared_name(), + Symbol::Module(s) => s.declared_name(), + Symbol::Type(s) => s.declared_name(), + Symbol::Function(s) => s.declared_name(), + Symbol::Parameter(s) => s.declared_name(), + Symbol::Variable(s) => s.declared_name(), } } - pub fn definition(&self) -> &SourceDefinition { + pub fn definition(&self) -> &Option { match self { - Symbol::Function(s) => s.definition(), - Symbol::Module(s) => s.definition(), - Symbol::Variable(s) => s.definition(), - Symbol::Class(s) => s.definition(), Symbol::UseStatement(s) => s.definition(), + Symbol::Module(s) => s.definition(), + Symbol::Type(s) => s.definition(), + Symbol::Function(s) => s.definition(), + Symbol::Parameter(s) => s.definition(), + Symbol::Variable(s) => s.definition(), + } + } + + pub fn unwrap_use_statement_symbol(&self) -> &UseStatementSymbol { + match self { + Symbol::UseStatement(s) => s, + _ => panic!("unwrap_use_statement_symbol called on non-use statement symbol"), } } } @@ -67,93 +95,74 @@ impl Display for Symbol { fn fmt(&self, f: &mut std::fmt::Formatter) -> std::fmt::Result { use Symbol::*; match self { - Function(function_symbol) => write!(f, "{}", function_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), + Module(module_symbol) => write!(f, "{}", module_symbol), + Type(class_symbol) => write!(f, "{}", class_symbol), + Function(function_symbol) => write!(f, "{}", function_symbol), + Parameter(parameter_symbol) => write!(f, "{}", parameter_symbol), + Variable(variable_symbol) => write!(f, "{}", variable_symbol), } } } +/* Use-statement */ + #[derive(Debug, Clone)] -pub struct FunctionSymbol { +pub struct UseStatementSymbol { pub fqn: String, pub declared_name: String, - pub is_public: bool, - pub is_platform: bool, - definition: SourceDefinition, + definition: Option, + referenced_symbol: Option> } -impl FunctionSymbol { - pub fn new( - fqn: &str, - declared_name: &str, - is_public: bool, - is_platform: bool, - identifier: &Identifier, - ) -> FunctionSymbol { - FunctionSymbol { +impl UseStatementSymbol { + pub fn new(fqn: &str, declared_name: &str, identifier: Option>>) -> Self { + UseStatementSymbol { fqn: fqn.to_string(), declared_name: declared_name.to_string(), - is_public, - is_platform, - definition: SourceDefinition::from_identifier(identifier), + definition: identifier.map(SourceDefinition::from_identifier_rc), + referenced_symbol: None, } } - fn definition(&self) -> &SourceDefinition { + 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 } } -impl Display for FunctionSymbol { +impl Display for UseStatementSymbol { fn fmt(&self, f: &mut std::fmt::Formatter) -> std::fmt::Result { write!( f, - "FunctionSymbol(fqn = {}, declared_name = {}, is_public = {})", - self.fqn, self.declared_name, self.is_public + "UseStatementSymbol(fqn = {}, declared_name = {})", + self.fqn, self.declared_name ) } } -#[derive(Debug, Clone)] -pub struct VariableSymbol { - pub name: String, - pub is_mutable: bool, - definition: SourceDefinition, -} -impl VariableSymbol { - pub fn new(name: &str, is_mutable: bool, definition: SourceDefinition) -> Self { - VariableSymbol { - name: name.to_string(), - is_mutable, - definition, - } - } +/* Module */ - pub fn definition(&self) -> &SourceDefinition { - &self.definition - } -} - -impl Display for VariableSymbol { - fn fmt(&self, f: &mut std::fmt::Formatter) -> std::fmt::Result { - write!( - f, - "VariableSymbol(name = {}, is_mutable = {})", - self.name, self.is_mutable - ) - } -} - -#[derive(Debug, Clone)] +#[derive(Debug)] pub struct ModuleSymbol { - pub fqn: String, - pub declared_name: String, - pub is_public: bool, - definition: SourceDefinition, + fqn: String, + declared_name: String, + is_public: bool, + definition: Option, } impl ModuleSymbol { @@ -161,17 +170,23 @@ impl ModuleSymbol { fqn: &str, declared_name: &str, is_public: bool, - identifier: &Identifier, + identifier: Option<&Identifier>, ) -> ModuleSymbol { ModuleSymbol { fqn: fqn.to_string(), declared_name: declared_name.to_string(), is_public, - definition: SourceDefinition::from_identifier(identifier), + definition: identifier.map(SourceDefinition::from_identifier), } } +} - pub fn definition(&self) -> &SourceDefinition { +impl SymbolInner for ModuleSymbol { + fn declared_name(&self) -> &str { + self.declared_name.as_str() + } + + fn definition(&self) -> &Option { &self.definition } } @@ -186,76 +201,180 @@ impl Display for ModuleSymbol { } } -#[derive(Debug, Clone)] -pub struct ClassSymbol { - pub fqn: String, - pub declared_name: String, - pub is_public: bool, - definition: SourceDefinition, +/* Class */ + +#[derive(Debug)] +pub struct TypeSymbol { + fqn: String, + declared_name: String, + is_public: bool, + definition: Option, } -impl ClassSymbol { - pub fn new(fqn: &str, declared_name: &str, is_public: bool, identifier: &Identifier) -> Self { - ClassSymbol { +impl TypeSymbol { + pub fn new(fqn: &str, declared_name: &str, is_public: bool, identifier: Option<&Identifier>) -> Self { + TypeSymbol { fqn: fqn.to_string(), declared_name: declared_name.to_string(), is_public, - definition: SourceDefinition::from_identifier(identifier), + definition: identifier.map(SourceDefinition::from_identifier), } } - pub fn definition(&self) -> &SourceDefinition { + pub fn fqn(&self) -> &str { + &self.fqn + } + + pub fn is_public(&self) -> bool { + self.is_public + } +} + +impl SymbolInner for TypeSymbol { + fn declared_name(&self) -> &str { + &self.declared_name + } + + fn definition(&self) -> &Option { &self.definition } } -impl Display for ClassSymbol { +impl Display for TypeSymbol { fn fmt(&self, f: &mut std::fmt::Formatter) -> std::fmt::Result { write!( f, - "ClassSymbol(fqn = {}, declared_name = {})", + "TypeSymbol(fqn = {}, declared_name = {})", self.fqn, self.declared_name ) } } -#[derive(Debug, Clone)] -pub struct UseStatementSymbol { - pub fqn: String, - pub declared_name: String, - definition: SourceDefinition, - referenced_symbol: Option> +/* Function */ + +#[derive(Debug)] +pub struct FunctionSymbol { + fqn: String, + declared_name: String, + is_public: bool, + is_platform: bool, + definition: Option, } -impl UseStatementSymbol { - pub fn new(fqn: &str, declared_name: &str, definition: SourceDefinition) -> Self { - UseStatementSymbol { +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(), - definition, - referenced_symbol: None, + is_public, + is_platform, + definition: identifier.map(SourceDefinition::from_identifier), } } - - 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() + pub fn fqn(&self) -> &str { + &self.fqn } } -impl Display for UseStatementSymbol { +impl SymbolInner for FunctionSymbol { + fn declared_name(&self) -> &str { + self.declared_name.as_str() + } + + fn definition(&self) -> &Option { + &self.definition + } +} + +impl Display for FunctionSymbol { fn fmt(&self, f: &mut std::fmt::Formatter) -> std::fmt::Result { write!( f, - "UseStatementSymbol(fqn = {}, declared_name = {})", - self.fqn, self.declared_name + "FunctionSymbol(fqn = {}, declared_name = {}, is_public = {})", + self.fqn, self.declared_name, self.is_public + ) + } +} + +/* Parameter */ + +#[derive(Debug)] +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 + } +} + +impl Display for ParameterSymbol { + fn fmt(&self, f: &mut std::fmt::Formatter) -> std::fmt::Result { + write!( + f, + "ParameterSymbol({})", + self.declared_name + ) + } +} + +/* Variable */ + +#[derive(Debug)] +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 + } +} + +impl Display for VariableSymbol { + fn fmt(&self, f: &mut std::fmt::Formatter) -> std::fmt::Result { + write!( + f, + "VariableSymbol(name = {}, is_mutable = {})", + self.declared_name, self.is_mutable ) } } diff --git a/src/name_analysis/symbol_table.rs b/src/name_analysis/symbol_table.rs index 3241ed7..86aef8f 100644 --- a/src/name_analysis/symbol_table.rs +++ b/src/name_analysis/symbol_table.rs @@ -1,94 +1,109 @@ -use crate::name_analysis::symbol::Symbol; +use crate::name_analysis::symbol::{ + FunctionSymbol, ModuleSymbol, ParameterSymbol, Symbol, SymbolInner, TypeSymbol, + UseStatementSymbol, VariableSymbol, +}; 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, -} +use std::rc::Rc; +/* Scope */ #[derive(Debug)] -pub struct Scope { - level: ScopeLevel, +struct Scope { parent: Option, - use_statement_symbols: HashMap, - module_symbols: HashMap, - type_symbols: HashMap, - function_symbols: HashMap, - variable_symbols: HashMap, + use_statement_symbols: HashMap>, + module_symbols: HashMap>, + type_symbols: HashMap>, + function_symbols: HashMap>, + parameter_symbols: HashMap>, + variable_symbols: HashMap>, debug_name: String, } impl Scope { - pub fn new(parent: Option, debug_name: String, level: ScopeLevel) -> Scope { + pub fn new(parent: Option, debug_name: String) -> Scope { Scope { - level, 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(), debug_name, } } - pub fn level(&self) -> ScopeLevel { - self.level.clone() + fn get_any_symbol(&self, name: &str) -> Option { + self.variable_symbols.get(name) + .map(|s| Symbol::Variable(s.clone())) + .or_else(|| self.parameter_symbols.get(name).map(|s| Symbol::Parameter(s.clone()))) + .or_else(|| self.function_symbols.get(name).map(|s| Symbol::Function(s.clone()))) + .or_else(|| self.type_symbols.get(name).map(|ts| Symbol::Type(ts.clone()))) + .or_else(|| self.module_symbols.get(name).map(|ms| Symbol::Module(ms.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."), + 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 } - 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 + fn get_usable_symbol_by_fqn(&self, fqn: &str) -> Option { + for function_symbol in self.function_symbols.values() { + if function_symbol.fqn() == fqn { + return Some(Symbol::Function(function_symbol.clone())); + } + } + for type_symbol in self.type_symbols.values() { + if type_symbol.fqn() == fqn { + return Some(Symbol::Type(type_symbol.clone())); + } + } + None + } + + fn get_usable_symbol_by_declared_name(&self, declared_name: &str) -> Option { + for function_symbol in self.function_symbols.values() { + if function_symbol.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 } } +/* Symbol table */ + +#[derive(Debug)] pub enum SymbolInsertError { SymbolAlreadyDefined(Symbol), } +#[derive(Debug)] pub enum SymbolLookupError { NoDefinition, } @@ -103,11 +118,7 @@ pub struct SymbolTable { impl SymbolTable { pub fn new() -> Self { let mut t = SymbolTable { - scopes: vec![Scope::new( - None, - String::from("GlobalScope"), - ScopeLevel::Global, - )], + scopes: vec![Scope::new(None, String::from("GlobalScope"))], current_scope_id: 0, }; t @@ -121,12 +132,11 @@ impl SymbolTable { &self.scopes } - pub fn push_scope(&mut self, debug_name: &str, level: ScopeLevel) { + 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(), - level, )); self.current_scope_id = id; } @@ -137,65 +147,112 @@ impl SymbolTable { } } - pub fn insert(&mut self, name: &str, symbol: Symbol) -> Result<(), SymbolInsertError> { - match symbol { - Symbol::Function(_) | Symbol::Variable(_) => { - 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( + pub fn insert_use_statement_symbol( &mut self, - name: &str, - symbol: Symbol, + use_statement_symbol: UseStatementSymbol, ) -> Result<(), SymbolInsertError> { - if let Some(defined_symbol) = self.scopes[self.current_scope_id] - .function_symbols - .get(name) + 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.clone())) + Err(SymbolAlreadyDefined(defined_symbol)) } else { - self.scopes[self.current_scope_id] - .function_symbols - .insert(name.to_string(), symbol); + current_scope.use_statement_symbols.insert( + use_statement_symbol.declared_name().to_string(), + Rc::new(use_statement_symbol), + ); Ok(()) } } - fn insert_module_or_type( + pub fn insert_module_symbol( &mut self, - name: &str, - symbol: Symbol, + module_symbol: ModuleSymbol, ) -> Result<(), SymbolInsertError> { - if let Some(defined_symbol) = self.scopes[self.current_scope_id].type_symbols.get(name) { - Err(SymbolAlreadyDefined(defined_symbol.clone())) + 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 { - self.scopes[self.current_scope_id] - .type_symbols - .insert(name.to_string(), symbol); + current_scope.module_symbols.insert( + module_symbol.declared_name().to_string(), + Rc::new(module_symbol), + ); Ok(()) } } - fn insert_use_statement_symbol( + 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, - name: &str, - symbol: Symbol, + function_symbol: FunctionSymbol, ) -> Result<(), SymbolInsertError> { - if let Some(defined_symbol) = self.scopes[self.current_scope_id].get_any_symbol(name) { - Err(SymbolAlreadyDefined(defined_symbol.clone())) + 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 { - self.scopes[self.current_scope_id] - .use_statement_symbols - .insert(name.to_string(), symbol); + current_scope.function_symbols.insert( + function_symbol.declared_name().to_string(), + Rc::new(function_symbol), + ); Ok(()) } } - pub fn lookup(&self, name: &str, scope_id: usize) -> Result<&Symbol, SymbolLookupError> { + 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 { + current_scope.parameter_symbols.insert( + parameter_symbol.declared_name().to_string(), + Rc::new(parameter_symbol), + ); + Ok(()) + } + } + + 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 { + current_scope.variable_symbols.insert( + variable_symbol.declared_name().to_string(), + Rc::new(variable_symbol), + ); + Ok(()) + } + } + + pub fn lookup(&self, 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_any_symbol(name) { @@ -210,16 +267,13 @@ impl SymbolTable { Err(NoDefinition) } - pub fn lookup_usable( + pub fn lookup_usable_by_fqn( &self, fully_qualified_name: &str, scope_id: usize, - ) -> Result<&Symbol, SymbolLookupError> { + ) -> Result { for scope in &self.scopes { - if scope.level == ScopeLevel::Function { - continue; - } - if let Some(symbol) = scope.get_usable_symbol(fully_qualified_name) { + if let Some(symbol) = scope.get_usable_symbol_by_fqn(fully_qualified_name) { return Ok(symbol); } } diff --git a/src/std_core/mod.rs b/src/std_core/mod.rs new file mode 100644 index 0000000..4aeee04 --- /dev/null +++ b/src/std_core/mod.rs @@ -0,0 +1,27 @@ +use crate::name_analysis::symbol::{FunctionSymbol, Symbol, TypeSymbol}; +use crate::name_analysis::symbol_table::{SymbolInsertError, SymbolTable}; + +pub fn add_std_core_symbols(symbol_table: &mut SymbolTable) -> Result<(), SymbolInsertError> { + symbol_table.insert_type_symbol( + TypeSymbol::new("std::core:Array", "Array", true, None), + )?; + symbol_table.insert_function_symbol( + FunctionSymbol::new( + "std::core::println", + "println", + true, + true, + None, + ), + )?; + symbol_table.insert_function_symbol( + FunctionSymbol::new( + "std::core::print", + "print", + true, + true, + None, + ), + )?; + Ok(()) +}