From b5c0e44eeb41c0766f1c8b7110a712ae0930ad95 Mon Sep 17 00:00:00 2001 From: Jesse Brault Date: Mon, 20 Oct 2025 20:55:29 -0500 Subject: [PATCH] Bunch of work on name analysis. Reintroduce Rc> for symbols. --- ast-generator/src/deserialize/struct_spec.rs | 30 ++- ast-generator/src/lib.rs | 3 + ast-generator/src/spec/struct_spec.rs | 42 +++- ast-generator/src/type_gen/struct_type.rs | 90 ++++++++- src/name_analysis/first_pass.rs | 41 +++- .../{gather.rs => gather_2.rs.bak} | 0 src/name_analysis/mod.rs | 7 +- src/name_analysis/second_pass.rs | 31 ++- src/name_analysis/symbol/mod.rs | 30 +-- src/name_analysis/symbol/usable_symbol.rs | 10 + src/name_analysis/symbol/use_symbol.rs | 28 +++ src/name_analysis/symbol_table/mod.rs | 182 ++++++++---------- src/name_analysis/symbol_table/scope.rs | 56 ++++-- src/parser/ast.yaml | 4 + 14 files changed, 397 insertions(+), 157 deletions(-) rename src/name_analysis/{gather.rs => gather_2.rs.bak} (100%) create mode 100644 src/name_analysis/symbol/usable_symbol.rs diff --git a/ast-generator/src/deserialize/struct_spec.rs b/ast-generator/src/deserialize/struct_spec.rs index 9cb5295..e141aaa 100644 --- a/ast-generator/src/deserialize/struct_spec.rs +++ b/ast-generator/src/deserialize/struct_spec.rs @@ -5,6 +5,22 @@ use crate::deserialize::util::{get_as_bool, make_build_fn_name, unwrap_single_me use crate::spec::struct_spec::*; use yaml_rust2::Yaml; +fn deserialize_field(field_yaml: &Yaml) -> StructField { + let (name, props) = unwrap_single_member_hash(field_yaml); + let kind = props["kind"].as_str().unwrap(); + let wrap = if let Some(wrap) = props["wrap"].as_str() { + match wrap { + "rc_ref_cell" => { + Some(StructFieldWrap::RcRefCell) + } + _ => panic!() + } + } else { + None + }; + StructField::new(&name, kind, wrap) +} + fn deserialize_skip_child(props: &Yaml) -> StructChild { let rule = props["rule"].as_str().unwrap(); StructChild::SkipChild(SkipChild::new(rule)) @@ -151,6 +167,18 @@ pub fn deserialize_struct_spec(name: &str, struct_yaml: &Yaml) -> StructSpec { } else { deserialize_error!("array", "children", name); }; + + let fields = if struct_yaml["fields"].is_array() { + struct_yaml["fields"].as_vec() + .unwrap() + .iter() + .map(|field| deserialize_field(field)) + .map(Box::new) + .collect() + } else { + vec![] + }; + let derive = if struct_yaml["derive"].is_array() { struct_yaml["derive"].as_vec() .unwrap() @@ -161,5 +189,5 @@ pub fn deserialize_struct_spec(name: &str, struct_yaml: &Yaml) -> StructSpec { vec![] }; - StructSpec::new(name, children, derive) + StructSpec::new(name, children, fields, derive) } diff --git a/ast-generator/src/lib.rs b/ast-generator/src/lib.rs index 30c7836..df53b9f 100644 --- a/ast-generator/src/lib.rs +++ b/ast-generator/src/lib.rs @@ -114,6 +114,9 @@ fn generate_node_file(build_specs: &[BuildSpec]) -> AstGeneratedFile { .collect::>(); let combined = quote! { use std::range::Range; + use std::rc::Rc; + use std::cell::RefCell; + use crate::name_analysis::symbol::use_symbol::UseSymbol; #(#types)* }; diff --git a/ast-generator/src/spec/struct_spec.rs b/ast-generator/src/spec/struct_spec.rs index aeb97a3..06b842f 100644 --- a/ast-generator/src/spec/struct_spec.rs +++ b/ast-generator/src/spec/struct_spec.rs @@ -1,14 +1,16 @@ pub struct StructSpec { build: String, children: Vec>, + fields: Vec>, derive: Vec, } impl StructSpec { - pub fn new(build: &str, children: Vec>, derive: Vec) -> Self { + pub fn new(build: &str, children: Vec>, fields: Vec>, derive: Vec) -> Self { Self { build: build.to_string(), children, + fields, derive, } } @@ -23,6 +25,10 @@ impl StructSpec { self.children.iter().map(Box::as_ref) } + pub fn fields(&self) -> impl Iterator { + self.fields.iter().map(Box::as_ref) + } + pub fn derive(&self) -> &[String] { &self.derive } @@ -266,3 +272,37 @@ pub enum SpecialChildKind { FileId, Range, } + +#[derive(Debug)] +pub struct StructField { + name: String, + kind: String, + wrap: Option, +} + +impl StructField { + pub fn new(name: &str, kind: &str, wrap: Option) -> Self { + Self { + name: name.to_string(), + kind: kind.to_string(), + wrap, + } + } + + pub fn name(&self) -> &str { + &self.name + } + + pub fn kind(&self) -> &str { + &self.kind + } + + pub fn wrap(&self) -> Option<&StructFieldWrap> { + self.wrap.as_ref() + } +} + +#[derive(Debug)] +pub enum StructFieldWrap { + RcRefCell +} diff --git a/ast-generator/src/type_gen/struct_type.rs b/ast-generator/src/type_gen/struct_type.rs index 7e42117..e3d450d 100644 --- a/ast-generator/src/type_gen/struct_type.rs +++ b/ast-generator/src/type_gen/struct_type.rs @@ -1,10 +1,66 @@ use crate::spec::struct_spec::{ - MemberChild, MemberChildBuild, SpecialChild, SpecialChildKind, StructChild, StructSpec, - VecChild, VecChildBuild, + MemberChild, MemberChildBuild, SpecialChild, SpecialChildKind, StructChild, StructField, + StructFieldWrap, StructSpec, VecChild, VecChildBuild, }; use proc_macro2::{Ident, TokenStream}; use quote::{format_ident, quote}; +fn make_field_accessors(field: &StructField) -> TokenStream { + let field_ident = format_ident!("{}", field.name()); + let field_type = { + let inner = format_ident!("{}", field.kind()); + if let Some(wrap) = field.wrap() { + match wrap { + StructFieldWrap::RcRefCell => { + quote! { Rc> } + } + } + } else { + quote! { #inner } + } + }; + let set_field_ident = format_ident!("set_{}", field.name()); + let field_ident_mut = format_ident!("{}_mut", field.name()); + + quote! { + pub fn #field_ident(&self) -> Option<&#field_type> { + self.#field_ident.as_ref() + } + + pub fn #field_ident_mut(&mut self) -> Option<&mut #field_type> { + self.#field_ident.as_mut() + } + + pub fn #set_field_ident(&mut self, #field_ident: #field_type) { + self.#field_ident = Some(#field_ident); + } + } +} + +fn make_field_initializer(field: &StructField) -> TokenStream { + let field_ident = format_ident!("{}", field.name()); + quote! { #field_ident: None } +} + +fn make_annotated_field(field: &StructField) -> TokenStream { + let field_ident = format_ident!("{}", field.name()); + let field_type = if let Some(wrap) = field.wrap() { + match wrap { + StructFieldWrap::RcRefCell => { + let inner = format_ident!("{}", field.kind()); + quote! { Rc> } + } + } + } else { + let inner = format_ident!("{}", field.kind()); + quote! { #inner } + }; + + quote! { + #field_ident: Option<#field_type> + } +} + fn make_vec_child_accessors(vec_child: &VecChild) -> TokenStream { let child_ident = format_ident!("{}", vec_child.name()); match vec_child.build() { @@ -184,13 +240,18 @@ fn make_annotated_member(child: &StructChild) -> Option { pub fn make_struct_type(build_spec: &StructSpec) -> TokenStream { let type_ident = format_ident!("{}", build_spec.build()); - let annotated_members = build_spec + let annotated_children_members = build_spec .children() .map(|child| make_annotated_member(child)) .filter(Option::is_some) .map(Option::unwrap) .collect::>(); + let annotated_fields = build_spec + .fields() + .map(|field| make_annotated_field(field)) + .collect::>(); + let member_names = build_spec .children() .map(|child| make_member_ident(child)) @@ -198,17 +259,28 @@ pub fn make_struct_type(build_spec: &StructSpec) -> TokenStream { .map(Option::unwrap) .collect::>(); - let accessors = build_spec + let field_initializers = build_spec + .fields() + .map(|field| make_field_initializer(field)) + .collect::>(); + + let child_accessors = build_spec .children() .map(|child| make_accessors(child)) .filter(Option::is_some) .map(Option::unwrap) .collect::>(); + let field_accessors = build_spec + .fields() + .map(|field| make_field_accessors(field)) + .collect::>(); + let struct_stream = { let base = quote! { pub struct #type_ident { - #(#annotated_members),* + #(#annotated_children_members,)* + #(#annotated_fields,)* } }; if !build_spec.derive().is_empty() { @@ -231,13 +303,15 @@ pub fn make_struct_type(build_spec: &StructSpec) -> TokenStream { #struct_stream impl #type_ident { - pub fn new(#(#annotated_members),*) -> Self { + pub fn new(#(#annotated_children_members),*) -> Self { Self { - #(#member_names),* + #(#member_names,)* + #(#field_initializers,)* } } - #(#accessors)* + #(#child_accessors)* + #(#field_accessors)* } } } diff --git a/src/name_analysis/first_pass.rs b/src/name_analysis/first_pass.rs index beb2166..f9be1fa 100644 --- a/src/name_analysis/first_pass.rs +++ b/src/name_analysis/first_pass.rs @@ -1,12 +1,14 @@ -use crate::ast::node::{CompilationUnit, UseStatement, UseStatementSuffix}; +use std::cell::RefCell; +use crate::ast::node::{CompilationUnit, Identifier, UseStatement, UseStatementSuffix}; use crate::diagnostic::DmDiagnostic; use crate::name_analysis::fqn_context::FqnContext; use crate::name_analysis::symbol::source_definition::SourceDefinition; -use crate::name_analysis::symbol::use_symbol::{ConcreteUseSymbol, StarUseSymbol}; +use crate::name_analysis::symbol::use_symbol::{ConcreteUseSymbol, StarUseSymbol, UseSymbol}; use crate::name_analysis::symbol_table::{SymbolInsertError, SymbolTable}; use crate::name_analysis::util::use_statement_base_fqn; use codespan_reporting::diagnostic::{Diagnostic, Label}; use std::range::Range; +use std::rc::Rc; fn handle_insert_error( err: SymbolInsertError, @@ -69,7 +71,7 @@ macro_rules! insert_concrete_use_symbol { }; } -pub fn np1_compilation_unit( +pub fn nap1_compilation_unit( file_name: &str, compilation_unit: &mut CompilationUnit, symbol_table: &mut SymbolTable, @@ -85,13 +87,42 @@ pub fn np1_compilation_unit( } for use_statement in compilation_unit.use_statements_mut() { - np1_use_statement(use_statement, symbol_table, diagnostics); + nap1_use_statement(use_statement, symbol_table, diagnostics); } symbol_table.pop_scope(); } -fn np1_use_statement( +fn handle_concrete_use_statement( + use_statement: &mut UseStatement, + identifier: &Identifier, + symbol_table: &mut SymbolTable, + diagnostics: &mut Vec, +) { + let base_fqn = use_statement_base_fqn(use_statement); + let to_insert = ConcreteUseSymbol::new( + &base_fqn, + identifier.name(), + Some(SourceDefinition::from_identifier(identifier)) + ); + match symbol_table.insert_concrete_use_symbol(to_insert) { + Ok(inserted) => { + use_statement.set_use_symbol(Rc::new(RefCell::new(UseSymbol::Concrete(inserted)))); + } + Err(insert_error) => { + handle_insert_error( + insert_error, + identifier.name(), + identifier.file_id(), + identifier.range(), + "Use Symbol", + diagnostics + ); + } + } +} + +fn nap1_use_statement( use_statement: &mut UseStatement, symbol_table: &mut SymbolTable, diagnostics: &mut Vec, diff --git a/src/name_analysis/gather.rs b/src/name_analysis/gather_2.rs.bak similarity index 100% rename from src/name_analysis/gather.rs rename to src/name_analysis/gather_2.rs.bak diff --git a/src/name_analysis/mod.rs b/src/name_analysis/mod.rs index 08c9988..a933572 100644 --- a/src/name_analysis/mod.rs +++ b/src/name_analysis/mod.rs @@ -23,14 +23,13 @@ The resolve phase has one main responsibility: resolve all references based on t use crate::ast::ast_node::AstNode; use crate::ast::node::CompilationUnit; use crate::diagnostic::DmDiagnostic; -use crate::name_analysis::first_pass::np1_compilation_unit; +use crate::name_analysis::first_pass::nap1_compilation_unit; +use crate::name_analysis::second_pass::nap2_compilation_unit; use crate::name_analysis::symbol_table::SymbolTable; use codespan_reporting::files::Files; use std::hash::Hash; -use crate::name_analysis::second_pass::nap2_compilation_unit; pub(self) mod fqn_context; -mod gather; // mod resolve; mod first_pass; mod scope_table; @@ -49,7 +48,7 @@ pub fn analyze_names<'a, F: Files<'a, FileId = usize, Name = String>>( // gather symbols for compilation_unit in compilation_units.iter_mut() { let file_name = files.name(compilation_unit.file_id()).unwrap(); - np1_compilation_unit(&file_name, compilation_unit, symbol_table, &mut diagnostics); + nap1_compilation_unit(&file_name, compilation_unit, symbol_table, &mut diagnostics); } // resolve symbols diff --git a/src/name_analysis/second_pass.rs b/src/name_analysis/second_pass.rs index 25251df..4a428eb 100644 --- a/src/name_analysis/second_pass.rs +++ b/src/name_analysis/second_pass.rs @@ -1,5 +1,6 @@ use crate::ast::node::{CompilationUnit, Identifier, UseStatement, UseStatementSuffix}; use crate::diagnostic::DmDiagnostic; +use crate::name_analysis::symbol::use_symbol::UseSymbol; use crate::name_analysis::symbol_table::{SymbolLookupError, SymbolTable}; use crate::name_analysis::util::use_statement_base_fqn; use codespan_reporting::diagnostic::{Diagnostic, Label}; @@ -47,18 +48,28 @@ fn nap2_use_statement( diagnostics: &mut Vec, ) { let base_fqn = use_statement_base_fqn(use_statement); - + let mut handle_concrete_use_symbol = |identifier: &Identifier| { let fqn = format!("{}::{}", base_fqn, identifier.name()); - if let Err(error) = symbol_table.resolve_usable_by_fqn(&fqn) { - handle_lookup_error( - error, - &fqn, - use_statement.file_id(), - use_statement.range(), - "Usable Symbol", - diagnostics, - ); + match symbol_table.resolve_concrete_usable_by_fqn(&fqn) { + Ok(resolved_symbol) => match *use_statement.use_symbol().unwrap().borrow() { + UseSymbol::Concrete(ref concrete_use_symbol) => { + concrete_use_symbol + .borrow_mut() + .set_resolved_symbol(resolved_symbol); + } + _ => panic!("Unexpected symbol type"), + }, + Err(lookup_error) => { + handle_lookup_error( + lookup_error, + &fqn, + use_statement.file_id(), + use_statement.range(), + "Usable Symbol", + diagnostics, + ); + } } }; diff --git a/src/name_analysis/symbol/mod.rs b/src/name_analysis/symbol/mod.rs index 5925433..50e4e37 100644 --- a/src/name_analysis/symbol/mod.rs +++ b/src/name_analysis/symbol/mod.rs @@ -4,26 +4,30 @@ pub(crate) mod module_symbol; pub(crate) mod parameter_symbol; pub(crate) mod source_definition; pub(crate) mod type_symbol; +pub(crate) mod usable_symbol; pub(crate) mod use_symbol; pub(crate) mod variable_symbol; -use crate::name_analysis::symbol::use_symbol::{ConcreteUseSymbol, StarUseSymbol}; +use crate::name_analysis::symbol::type_symbol::ConcreteTypeSymbol; +use crate::name_analysis::symbol::use_symbol::UseSymbol; 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}; use std::ops::Deref; +use std::rc::Rc; use type_symbol::TypeSymbol; use variable_symbol::VariableSymbol; #[derive(Debug, Clone)] pub enum Symbol { - ConcreteUse(ConcreteUseSymbol), - StarUse(StarUseSymbol), + Use(UseSymbol), Module(ModuleSymbol), Type(TypeSymbol), + ConcreteType(Rc>), Function(FunctionSymbol), Parameter(ParameterSymbol), Variable(VariableSymbol), @@ -31,16 +35,18 @@ pub enum Symbol { } impl Symbol { - pub fn definition(&self) -> Option<&SourceDefinition> { + pub fn definition(&self) -> Option { match self { - 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(), + Symbol::Use(use_symbol) => use_symbol.source_definition(), + Symbol::Module(module) => module.source_definition().cloned(), + Symbol::Type(type_symbol) => type_symbol.source_definition().cloned(), + Symbol::ConcreteType(concrete_type_symbol) => concrete_type_symbol.borrow().source_definition().cloned(), + Symbol::Function(function_symbol) => function_symbol.source_definition().cloned(), + Symbol::Parameter(parameter_symbol) => parameter_symbol.source_definition().cloned(), + Symbol::Variable(variable_symbol) => variable_symbol.source_definition().cloned(), + Symbol::ClassMember(class_member_symbol) => { + class_member_symbol.source_definition().cloned() + } } } } diff --git a/src/name_analysis/symbol/usable_symbol.rs b/src/name_analysis/symbol/usable_symbol.rs new file mode 100644 index 0000000..02d2c39 --- /dev/null +++ b/src/name_analysis/symbol/usable_symbol.rs @@ -0,0 +1,10 @@ +use crate::name_analysis::symbol::function_symbol::FunctionSymbol; +use crate::name_analysis::symbol::type_symbol::{ConcreteTypeSymbol, TypeSymbol}; +use std::cell::RefCell; +use std::rc::Rc; + +#[derive(Clone, Debug)] +pub enum ConcreteUsableSymbol { + Type(Rc>), + Function(Rc>), +} diff --git a/src/name_analysis/symbol/use_symbol.rs b/src/name_analysis/symbol/use_symbol.rs index f8b3898..d9d59da 100644 --- a/src/name_analysis/symbol/use_symbol.rs +++ b/src/name_analysis/symbol/use_symbol.rs @@ -1,11 +1,30 @@ use crate::name_analysis::symbol::source_definition::SourceDefinition; +use crate::name_analysis::symbol::usable_symbol::ConcreteUsableSymbol; +use std::cell::RefCell; use std::fmt::{Debug, Formatter}; +use std::rc::Rc; + +#[derive(Debug, Clone)] +pub enum UseSymbol { + Concrete(Rc>), + Star(StarUseSymbol), +} + +impl UseSymbol { + pub fn source_definition(&self) -> Option { + match self { + UseSymbol::Concrete(concrete) => concrete.borrow().source_definition().cloned(), + UseSymbol::Star(star) => star.source_definition().cloned(), + } + } +} #[derive(Clone)] pub struct ConcreteUseSymbol { base_fqn: String, declared_name: String, source_definition: Option, + resolved_symbol: Option, } impl ConcreteUseSymbol { @@ -18,6 +37,7 @@ impl ConcreteUseSymbol { base_fqn: base_fqn.to_string(), declared_name: declared_name.to_string(), source_definition, + resolved_symbol: None, } } @@ -32,6 +52,14 @@ impl ConcreteUseSymbol { pub fn source_definition(&self) -> Option<&SourceDefinition> { self.source_definition.as_ref() } + + pub fn resolved_symbol(&self) -> Option<&ConcreteUsableSymbol> { + self.resolved_symbol.as_ref() + } + + pub fn set_resolved_symbol(&mut self, symbol: ConcreteUsableSymbol) { + self.resolved_symbol = Some(symbol); + } } impl Debug for ConcreteUseSymbol { diff --git a/src/name_analysis/symbol_table/mod.rs b/src/name_analysis/symbol_table/mod.rs index 9ca54cb..b9a007c 100644 --- a/src/name_analysis/symbol_table/mod.rs +++ b/src/name_analysis/symbol_table/mod.rs @@ -2,15 +2,19 @@ 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::type_symbol::ConcreteTypeSymbol; +use crate::name_analysis::symbol::usable_symbol::ConcreteUsableSymbol; +use crate::name_analysis::symbol::use_symbol::{ConcreteUseSymbol, StarUseSymbol, UseSymbol}; use crate::name_analysis::symbol::variable_symbol::VariableSymbol; 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::cell::RefCell; +use std::collections::VecDeque; use std::fmt::Display; use std::ops::Deref; +use std::rc::Rc; mod scope; @@ -44,13 +48,14 @@ impl SymbolTable { } pub fn push_scope(&mut self, debug_name: &str) { - let id = self.scopes.len(); + let id_to_push = self.scopes.len(); self.scopes.push(Scope::new( Some(self.current_scope_id), - id, + id_to_push, debug_name.to_string(), )); - self.current_scope_id = id; + self.current_scope_mut().add_child(id_to_push); + self.current_scope_id = id_to_push; } pub fn pop_scope(&mut self) { @@ -70,20 +75,17 @@ impl SymbolTable { fn find_current_scope_concrete_use_symbol( &self, declared_name: &str, - ) -> Option<&ConcreteUseSymbol> { + ) -> Option>> { self.current_scope() .concrete_use_symbols() .get(declared_name) + .cloned() } 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) } @@ -119,11 +121,13 @@ impl SymbolTable { 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())) + .map(|concrete_use_symbol| { + Symbol::Use(UseSymbol::Concrete(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())) @@ -133,17 +137,22 @@ impl SymbolTable { pub fn insert_concrete_use_symbol( &mut self, concrete_use_symbol: ConcreteUseSymbol, - ) -> Result<(), SymbolInsertError> { + ) -> 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(()) + let name = concrete_use_symbol.declared_name().to_string(); + self.current_scope_mut() + .concrete_use_symbols_mut() + .insert(name.clone(), Rc::new(RefCell::new(concrete_use_symbol))); + Ok(self + .current_scope() + .concrete_use_symbols() + .get(&name) + .cloned() + .unwrap()) } } @@ -154,9 +163,9 @@ impl SymbolTable { if let Some(defined_symbol) = self.find_current_scope_star_use_symbol(star_use_symbol.base_fqn()) { - Err(SymbolAlreadyDefined(Symbol::StarUse( + Err(SymbolAlreadyDefined(Symbol::Use(UseSymbol::Star( defined_symbol.clone(), - ))) + )))) } else { self.current_scope_mut() .star_use_symbols_mut() @@ -181,15 +190,23 @@ impl SymbolTable { } } - 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()) + fn find_current_scope_concrete_type_symbol( + &self, + declared_name: &str, + ) -> Option>> { + self.current_scope().get_concrete_type_symbol(declared_name) + } + + pub fn insert_concrete_type_symbol( + &mut self, + symbol: ConcreteTypeSymbol, + ) -> Result<(), SymbolInsertError> { + if let Some(defined_type) = + self.find_current_scope_concrete_type_symbol(symbol.declared_name()) { - Err(SymbolAlreadyDefined(defined_symbol)) + Err(SymbolAlreadyDefined(Symbol::ConcreteType(defined_type))) } else { - self.current_scope_mut() - .type_symbols_mut() - .insert(type_symbol.declared_name().to_string(), type_symbol); + self.current_scope_mut().insert_concrete_type_symbol(symbol); Ok(()) } } @@ -264,66 +281,6 @@ impl SymbolTable { } } - 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) - } - fn lookup_addressable_in_scope_by_identifier( scope: &Scope, identifier: &str, @@ -350,12 +307,12 @@ impl SymbolTable { .get(identifier) .map(|function_symbol| Symbol::Function(function_symbol.clone())) }) - .or_else(|| { - scope - .type_symbols() - .get(identifier) - .map(|type_symbol| Symbol::Type(type_symbol.clone())) - }) + // .or_else(|| { + // scope + // .type_symbols() + // .get(identifier) + // .map(|type_symbol| Symbol::Type(type_symbol.clone())) + // }) } pub fn lookup_addressable_by_identifier( @@ -378,17 +335,36 @@ impl SymbolTable { Err(NoDefinition) } - pub fn resolve_usable_by_fqn( + pub fn resolve_concrete_usable_by_fqn( &self, - fqn: &str - ) -> Result { - todo!() + fqn: &str, + ) -> Result { + // breadth-first search, use a queue + let mut search_stack: VecDeque = VecDeque::new(); + search_stack.push_back(0); // global scope + + while let Some(scope_id) = search_stack.pop_front() { + let scope = &self.scopes[scope_id]; + for child_id in scope.children() { + search_stack.push_back(child_id); + } + + if let Some(concrete_type_symbol) = scope.get_concrete_type_symbol_by_fqn(fqn) { + return Ok(ConcreteUsableSymbol::Type(concrete_type_symbol)); + } + + // TODO: this is inefficient. Use a (cached) hash table of Fqn => Rc> + for function_symbol in scope.function_symbols().values() { + if function_symbol.fqn() == fqn { + return Ok(ConcreteUsableSymbol::Function(todo!())); + } + } + } + + Err(NoDefinition) } - pub fn resolve_usable_star( - &self, - base_fqn: &str, - ) -> Result<(), SymbolLookupError> { + pub fn resolve_usable_star(&self, base_fqn: &str) -> Result<(), SymbolLookupError> { todo!() } } diff --git a/src/name_analysis/symbol_table/scope.rs b/src/name_analysis/symbol_table/scope.rs index 0b0c6fb..f858b2e 100644 --- a/src/name_analysis/symbol_table/scope.rs +++ b/src/name_analysis/symbol_table/scope.rs @@ -2,20 +2,24 @@ 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::type_symbol::{ConcreteTypeSymbol, TypeSymbol}; use crate::name_analysis::symbol::use_symbol::{ConcreteUseSymbol, StarUseSymbol}; use crate::name_analysis::symbol::variable_symbol::VariableSymbol; +use std::cell::RefCell; use std::collections::HashMap; use std::fmt::{Display, Formatter}; +use std::rc::Rc; #[derive(Debug)] pub struct Scope { parent: Option, id: usize, - concrete_use_symbols: HashMap, + children: Vec, + concrete_use_symbols: HashMap>>, star_use_symbols: HashMap, module_symbols: HashMap, - type_symbols: HashMap, + concrete_type_symbols: HashMap>>, + concrete_type_symbols_by_fqn: HashMap>>, function_symbols: HashMap, parameter_symbols: HashMap, variable_symbols: HashMap, @@ -28,10 +32,12 @@ impl Scope { Self { parent, id, + children: vec![], concrete_use_symbols: HashMap::new(), star_use_symbols: HashMap::new(), module_symbols: HashMap::new(), - type_symbols: HashMap::new(), + concrete_type_symbols: HashMap::new(), + concrete_type_symbols_by_fqn: HashMap::new(), function_symbols: HashMap::new(), parameter_symbols: HashMap::new(), variable_symbols: HashMap::new(), @@ -48,11 +54,21 @@ impl Scope { self.id } - pub fn concrete_use_symbols(&self) -> &HashMap { + pub fn add_child(&mut self, child_id: usize) { + self.children.push(child_id); + } + + pub fn children(&self) -> Vec { + self.children.clone() + } + + pub fn concrete_use_symbols(&self) -> &HashMap>> { &self.concrete_use_symbols } - pub fn concrete_use_symbols_mut(&mut self) -> &mut HashMap { + pub fn concrete_use_symbols_mut( + &mut self, + ) -> &mut HashMap>> { &mut self.concrete_use_symbols } @@ -72,12 +88,24 @@ impl Scope { &mut self.module_symbols } - pub fn type_symbols(&self) -> &HashMap { - &self.type_symbols + pub fn insert_concrete_type_symbol(&mut self, symbol: ConcreteTypeSymbol) { + let as_rc = Rc::new(RefCell::new(symbol)); + self.concrete_type_symbols.insert( + as_rc.borrow().declared_name().to_string(), + as_rc.clone(), + ); + self.concrete_type_symbols_by_fqn.insert( + as_rc.borrow().fqn().to_string(), + as_rc.clone(), + ); } - - pub fn type_symbols_mut(&mut self) -> &mut HashMap { - &mut self.type_symbols + + pub fn get_concrete_type_symbol(&self, declared_name: &str) -> Option>> { + self.concrete_type_symbols.get(declared_name).cloned() + } + + pub fn get_concrete_type_symbol_by_fqn(&self, fqn: &str) -> Option>> { + self.concrete_type_symbols_by_fqn.get(fqn).cloned() } pub fn function_symbols(&self) -> &HashMap { @@ -131,13 +159,15 @@ impl Display for Scope { f, "----Scope {} (p: {}) {}----", self.id(), - self.parent().map(|parent_id| format!("{}", parent_id)).unwrap_or_else(|| "None".to_string()), + self.parent() + .map(|parent_id| format!("{}", parent_id)) + .unwrap_or_else(|| "None".to_string()), 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()); + todo!("self.concrete_type_symbols"); write_symbols!(f, self.function_symbols()); write_symbols!(f, self.parameter_symbols()); write_symbols!(f, self.variable_symbols()); diff --git a/src/parser/ast.yaml b/src/parser/ast.yaml index 4b86b91..2992818 100644 --- a/src/parser/ast.yaml +++ b/src/parser/ast.yaml @@ -248,6 +248,10 @@ UseStatement: - range: special: kind: range + fields: + - use_symbol: + kind: UseSymbol + wrap: rc_ref_cell UseStatementPrefix: struct: children: