Bunch of work on name analysis. Reintroduce Rc<RefCell<_>> for symbols.

This commit is contained in:
Jesse Brault 2025-10-20 20:55:29 -05:00
parent 273d197841
commit b5c0e44eeb
14 changed files with 397 additions and 157 deletions

View File

@ -5,6 +5,22 @@ use crate::deserialize::util::{get_as_bool, make_build_fn_name, unwrap_single_me
use crate::spec::struct_spec::*; use crate::spec::struct_spec::*;
use yaml_rust2::Yaml; 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 { fn deserialize_skip_child(props: &Yaml) -> StructChild {
let rule = props["rule"].as_str().unwrap(); let rule = props["rule"].as_str().unwrap();
StructChild::SkipChild(SkipChild::new(rule)) StructChild::SkipChild(SkipChild::new(rule))
@ -151,6 +167,18 @@ pub fn deserialize_struct_spec(name: &str, struct_yaml: &Yaml) -> StructSpec {
} else { } else {
deserialize_error!("array", "children", name); 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() { let derive = if struct_yaml["derive"].is_array() {
struct_yaml["derive"].as_vec() struct_yaml["derive"].as_vec()
.unwrap() .unwrap()
@ -161,5 +189,5 @@ pub fn deserialize_struct_spec(name: &str, struct_yaml: &Yaml) -> StructSpec {
vec![] vec![]
}; };
StructSpec::new(name, children, derive) StructSpec::new(name, children, fields, derive)
} }

View File

@ -114,6 +114,9 @@ fn generate_node_file(build_specs: &[BuildSpec]) -> AstGeneratedFile {
.collect::<Vec<_>>(); .collect::<Vec<_>>();
let combined = quote! { let combined = quote! {
use std::range::Range; use std::range::Range;
use std::rc::Rc;
use std::cell::RefCell;
use crate::name_analysis::symbol::use_symbol::UseSymbol;
#(#types)* #(#types)*
}; };

View File

@ -1,14 +1,16 @@
pub struct StructSpec { pub struct StructSpec {
build: String, build: String,
children: Vec<Box<StructChild>>, children: Vec<Box<StructChild>>,
fields: Vec<Box<StructField>>,
derive: Vec<String>, derive: Vec<String>,
} }
impl StructSpec { impl StructSpec {
pub fn new(build: &str, children: Vec<Box<StructChild>>, derive: Vec<String>) -> Self { pub fn new(build: &str, children: Vec<Box<StructChild>>, fields: Vec<Box<StructField>>, derive: Vec<String>) -> Self {
Self { Self {
build: build.to_string(), build: build.to_string(),
children, children,
fields,
derive, derive,
} }
} }
@ -23,6 +25,10 @@ impl StructSpec {
self.children.iter().map(Box::as_ref) self.children.iter().map(Box::as_ref)
} }
pub fn fields(&self) -> impl Iterator<Item = &StructField> {
self.fields.iter().map(Box::as_ref)
}
pub fn derive(&self) -> &[String] { pub fn derive(&self) -> &[String] {
&self.derive &self.derive
} }
@ -266,3 +272,37 @@ pub enum SpecialChildKind {
FileId, FileId,
Range, Range,
} }
#[derive(Debug)]
pub struct StructField {
name: String,
kind: String,
wrap: Option<StructFieldWrap>,
}
impl StructField {
pub fn new(name: &str, kind: &str, wrap: Option<StructFieldWrap>) -> 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
}

View File

@ -1,10 +1,66 @@
use crate::spec::struct_spec::{ use crate::spec::struct_spec::{
MemberChild, MemberChildBuild, SpecialChild, SpecialChildKind, StructChild, StructSpec, MemberChild, MemberChildBuild, SpecialChild, SpecialChildKind, StructChild, StructField,
VecChild, VecChildBuild, StructFieldWrap, StructSpec, VecChild, VecChildBuild,
}; };
use proc_macro2::{Ident, TokenStream}; use proc_macro2::{Ident, TokenStream};
use quote::{format_ident, quote}; 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<RefCell<#inner>> }
}
}
} 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<RefCell<#inner>> }
}
}
} else {
let inner = format_ident!("{}", field.kind());
quote! { #inner }
};
quote! {
#field_ident: Option<#field_type>
}
}
fn make_vec_child_accessors(vec_child: &VecChild) -> TokenStream { fn make_vec_child_accessors(vec_child: &VecChild) -> TokenStream {
let child_ident = format_ident!("{}", vec_child.name()); let child_ident = format_ident!("{}", vec_child.name());
match vec_child.build() { match vec_child.build() {
@ -184,13 +240,18 @@ fn make_annotated_member(child: &StructChild) -> Option<TokenStream> {
pub fn make_struct_type(build_spec: &StructSpec) -> TokenStream { pub fn make_struct_type(build_spec: &StructSpec) -> TokenStream {
let type_ident = format_ident!("{}", build_spec.build()); let type_ident = format_ident!("{}", build_spec.build());
let annotated_members = build_spec let annotated_children_members = build_spec
.children() .children()
.map(|child| make_annotated_member(child)) .map(|child| make_annotated_member(child))
.filter(Option::is_some) .filter(Option::is_some)
.map(Option::unwrap) .map(Option::unwrap)
.collect::<Vec<_>>(); .collect::<Vec<_>>();
let annotated_fields = build_spec
.fields()
.map(|field| make_annotated_field(field))
.collect::<Vec<_>>();
let member_names = build_spec let member_names = build_spec
.children() .children()
.map(|child| make_member_ident(child)) .map(|child| make_member_ident(child))
@ -198,17 +259,28 @@ pub fn make_struct_type(build_spec: &StructSpec) -> TokenStream {
.map(Option::unwrap) .map(Option::unwrap)
.collect::<Vec<_>>(); .collect::<Vec<_>>();
let accessors = build_spec let field_initializers = build_spec
.fields()
.map(|field| make_field_initializer(field))
.collect::<Vec<_>>();
let child_accessors = build_spec
.children() .children()
.map(|child| make_accessors(child)) .map(|child| make_accessors(child))
.filter(Option::is_some) .filter(Option::is_some)
.map(Option::unwrap) .map(Option::unwrap)
.collect::<Vec<_>>(); .collect::<Vec<_>>();
let field_accessors = build_spec
.fields()
.map(|field| make_field_accessors(field))
.collect::<Vec<_>>();
let struct_stream = { let struct_stream = {
let base = quote! { let base = quote! {
pub struct #type_ident { pub struct #type_ident {
#(#annotated_members),* #(#annotated_children_members,)*
#(#annotated_fields,)*
} }
}; };
if !build_spec.derive().is_empty() { if !build_spec.derive().is_empty() {
@ -231,13 +303,15 @@ pub fn make_struct_type(build_spec: &StructSpec) -> TokenStream {
#struct_stream #struct_stream
impl #type_ident { impl #type_ident {
pub fn new(#(#annotated_members),*) -> Self { pub fn new(#(#annotated_children_members),*) -> Self {
Self { Self {
#(#member_names),* #(#member_names,)*
#(#field_initializers,)*
} }
} }
#(#accessors)* #(#child_accessors)*
#(#field_accessors)*
} }
} }
} }

View File

@ -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::diagnostic::DmDiagnostic;
use crate::name_analysis::fqn_context::FqnContext; use crate::name_analysis::fqn_context::FqnContext;
use crate::name_analysis::symbol::source_definition::SourceDefinition; 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::symbol_table::{SymbolInsertError, SymbolTable};
use crate::name_analysis::util::use_statement_base_fqn; use crate::name_analysis::util::use_statement_base_fqn;
use codespan_reporting::diagnostic::{Diagnostic, Label}; use codespan_reporting::diagnostic::{Diagnostic, Label};
use std::range::Range; use std::range::Range;
use std::rc::Rc;
fn handle_insert_error( fn handle_insert_error(
err: SymbolInsertError, 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, file_name: &str,
compilation_unit: &mut CompilationUnit, compilation_unit: &mut CompilationUnit,
symbol_table: &mut SymbolTable, symbol_table: &mut SymbolTable,
@ -85,13 +87,42 @@ pub fn np1_compilation_unit(
} }
for use_statement in compilation_unit.use_statements_mut() { 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(); 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<DmDiagnostic>,
) {
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, use_statement: &mut UseStatement,
symbol_table: &mut SymbolTable, symbol_table: &mut SymbolTable,
diagnostics: &mut Vec<DmDiagnostic>, diagnostics: &mut Vec<DmDiagnostic>,

View File

@ -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::ast_node::AstNode;
use crate::ast::node::CompilationUnit; use crate::ast::node::CompilationUnit;
use crate::diagnostic::DmDiagnostic; 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 crate::name_analysis::symbol_table::SymbolTable;
use codespan_reporting::files::Files; use codespan_reporting::files::Files;
use std::hash::Hash; use std::hash::Hash;
use crate::name_analysis::second_pass::nap2_compilation_unit;
pub(self) mod fqn_context; pub(self) mod fqn_context;
mod gather;
// mod resolve; // mod resolve;
mod first_pass; mod first_pass;
mod scope_table; mod scope_table;
@ -49,7 +48,7 @@ pub fn analyze_names<'a, F: Files<'a, FileId = usize, Name = String>>(
// gather symbols // gather symbols
for compilation_unit in compilation_units.iter_mut() { for compilation_unit in compilation_units.iter_mut() {
let file_name = files.name(compilation_unit.file_id()).unwrap(); 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 // resolve symbols

View File

@ -1,5 +1,6 @@
use crate::ast::node::{CompilationUnit, Identifier, UseStatement, UseStatementSuffix}; use crate::ast::node::{CompilationUnit, Identifier, UseStatement, UseStatementSuffix};
use crate::diagnostic::DmDiagnostic; use crate::diagnostic::DmDiagnostic;
use crate::name_analysis::symbol::use_symbol::UseSymbol;
use crate::name_analysis::symbol_table::{SymbolLookupError, SymbolTable}; use crate::name_analysis::symbol_table::{SymbolLookupError, SymbolTable};
use crate::name_analysis::util::use_statement_base_fqn; use crate::name_analysis::util::use_statement_base_fqn;
use codespan_reporting::diagnostic::{Diagnostic, Label}; use codespan_reporting::diagnostic::{Diagnostic, Label};
@ -47,18 +48,28 @@ fn nap2_use_statement(
diagnostics: &mut Vec<DmDiagnostic>, diagnostics: &mut Vec<DmDiagnostic>,
) { ) {
let base_fqn = use_statement_base_fqn(use_statement); let base_fqn = use_statement_base_fqn(use_statement);
let mut handle_concrete_use_symbol = |identifier: &Identifier| { let mut handle_concrete_use_symbol = |identifier: &Identifier| {
let fqn = format!("{}::{}", base_fqn, identifier.name()); let fqn = format!("{}::{}", base_fqn, identifier.name());
if let Err(error) = symbol_table.resolve_usable_by_fqn(&fqn) { match symbol_table.resolve_concrete_usable_by_fqn(&fqn) {
handle_lookup_error( Ok(resolved_symbol) => match *use_statement.use_symbol().unwrap().borrow() {
error, UseSymbol::Concrete(ref concrete_use_symbol) => {
&fqn, concrete_use_symbol
use_statement.file_id(), .borrow_mut()
use_statement.range(), .set_resolved_symbol(resolved_symbol);
"Usable Symbol", }
diagnostics, _ => panic!("Unexpected symbol type"),
); },
Err(lookup_error) => {
handle_lookup_error(
lookup_error,
&fqn,
use_statement.file_id(),
use_statement.range(),
"Usable Symbol",
diagnostics,
);
}
} }
}; };

View File

@ -4,26 +4,30 @@ pub(crate) mod module_symbol;
pub(crate) mod parameter_symbol; pub(crate) mod parameter_symbol;
pub(crate) mod source_definition; pub(crate) mod source_definition;
pub(crate) mod type_symbol; pub(crate) mod type_symbol;
pub(crate) mod usable_symbol;
pub(crate) mod use_symbol; pub(crate) mod use_symbol;
pub(crate) mod variable_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 class_member_symbol::ClassMemberSymbol;
use function_symbol::FunctionSymbol; use function_symbol::FunctionSymbol;
use module_symbol::ModuleSymbol; use module_symbol::ModuleSymbol;
use parameter_symbol::ParameterSymbol; use parameter_symbol::ParameterSymbol;
use source_definition::SourceDefinition; use source_definition::SourceDefinition;
use std::cell::RefCell;
use std::fmt::{Debug, Display}; use std::fmt::{Debug, Display};
use std::ops::Deref; use std::ops::Deref;
use std::rc::Rc;
use type_symbol::TypeSymbol; use type_symbol::TypeSymbol;
use variable_symbol::VariableSymbol; use variable_symbol::VariableSymbol;
#[derive(Debug, Clone)] #[derive(Debug, Clone)]
pub enum Symbol { pub enum Symbol {
ConcreteUse(ConcreteUseSymbol), Use(UseSymbol),
StarUse(StarUseSymbol),
Module(ModuleSymbol), Module(ModuleSymbol),
Type(TypeSymbol), Type(TypeSymbol),
ConcreteType(Rc<RefCell<ConcreteTypeSymbol>>),
Function(FunctionSymbol), Function(FunctionSymbol),
Parameter(ParameterSymbol), Parameter(ParameterSymbol),
Variable(VariableSymbol), Variable(VariableSymbol),
@ -31,16 +35,18 @@ pub enum Symbol {
} }
impl Symbol { impl Symbol {
pub fn definition(&self) -> Option<&SourceDefinition> { pub fn definition(&self) -> Option<SourceDefinition> {
match self { match self {
Symbol::ConcreteUse(concrete) => concrete.source_definition(), Symbol::Use(use_symbol) => use_symbol.source_definition(),
Symbol::StarUse(star) => star.source_definition(), Symbol::Module(module) => module.source_definition().cloned(),
Symbol::Module(module) => module.source_definition(), Symbol::Type(type_symbol) => type_symbol.source_definition().cloned(),
Symbol::Type(type_symbol) => type_symbol.source_definition(), Symbol::ConcreteType(concrete_type_symbol) => concrete_type_symbol.borrow().source_definition().cloned(),
Symbol::Function(function_symbol) => function_symbol.source_definition(), Symbol::Function(function_symbol) => function_symbol.source_definition().cloned(),
Symbol::Parameter(parameter_symbol) => parameter_symbol.source_definition(), Symbol::Parameter(parameter_symbol) => parameter_symbol.source_definition().cloned(),
Symbol::Variable(variable_symbol) => variable_symbol.source_definition(), Symbol::Variable(variable_symbol) => variable_symbol.source_definition().cloned(),
Symbol::ClassMember(class_member_symbol) => class_member_symbol.source_definition(), Symbol::ClassMember(class_member_symbol) => {
class_member_symbol.source_definition().cloned()
}
} }
} }
} }

View File

@ -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<RefCell<ConcreteTypeSymbol>>),
Function(Rc<RefCell<FunctionSymbol>>),
}

View File

@ -1,11 +1,30 @@
use crate::name_analysis::symbol::source_definition::SourceDefinition; 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::fmt::{Debug, Formatter};
use std::rc::Rc;
#[derive(Debug, Clone)]
pub enum UseSymbol {
Concrete(Rc<RefCell<ConcreteUseSymbol>>),
Star(StarUseSymbol),
}
impl UseSymbol {
pub fn source_definition(&self) -> Option<SourceDefinition> {
match self {
UseSymbol::Concrete(concrete) => concrete.borrow().source_definition().cloned(),
UseSymbol::Star(star) => star.source_definition().cloned(),
}
}
}
#[derive(Clone)] #[derive(Clone)]
pub struct ConcreteUseSymbol { pub struct ConcreteUseSymbol {
base_fqn: String, base_fqn: String,
declared_name: String, declared_name: String,
source_definition: Option<SourceDefinition>, source_definition: Option<SourceDefinition>,
resolved_symbol: Option<ConcreteUsableSymbol>,
} }
impl ConcreteUseSymbol { impl ConcreteUseSymbol {
@ -18,6 +37,7 @@ impl ConcreteUseSymbol {
base_fqn: base_fqn.to_string(), base_fqn: base_fqn.to_string(),
declared_name: declared_name.to_string(), declared_name: declared_name.to_string(),
source_definition, source_definition,
resolved_symbol: None,
} }
} }
@ -32,6 +52,14 @@ impl ConcreteUseSymbol {
pub fn source_definition(&self) -> Option<&SourceDefinition> { pub fn source_definition(&self) -> Option<&SourceDefinition> {
self.source_definition.as_ref() 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 { impl Debug for ConcreteUseSymbol {

View File

@ -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::function_symbol::FunctionSymbol;
use crate::name_analysis::symbol::module_symbol::ModuleSymbol; use crate::name_analysis::symbol::module_symbol::ModuleSymbol;
use crate::name_analysis::symbol::parameter_symbol::ParameterSymbol; use crate::name_analysis::symbol::parameter_symbol::ParameterSymbol;
use crate::name_analysis::symbol::type_symbol::TypeSymbol; use crate::name_analysis::symbol::type_symbol::ConcreteTypeSymbol;
use crate::name_analysis::symbol::use_symbol::{ConcreteUseSymbol, StarUseSymbol}; 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::variable_symbol::VariableSymbol;
use crate::name_analysis::symbol::*; use crate::name_analysis::symbol::*;
use crate::name_analysis::symbol_table::SymbolInsertError::SymbolAlreadyDefined; use crate::name_analysis::symbol_table::SymbolInsertError::SymbolAlreadyDefined;
use crate::name_analysis::symbol_table::SymbolLookupError::NoDefinition; use crate::name_analysis::symbol_table::SymbolLookupError::NoDefinition;
use scope::Scope; use scope::Scope;
use std::cell::RefCell;
use std::collections::VecDeque;
use std::fmt::Display; use std::fmt::Display;
use std::ops::Deref; use std::ops::Deref;
use std::rc::Rc;
mod scope; mod scope;
@ -44,13 +48,14 @@ impl SymbolTable {
} }
pub fn push_scope(&mut self, debug_name: &str) { 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( self.scopes.push(Scope::new(
Some(self.current_scope_id), Some(self.current_scope_id),
id, id_to_push,
debug_name.to_string(), 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) { pub fn pop_scope(&mut self) {
@ -70,20 +75,17 @@ impl SymbolTable {
fn find_current_scope_concrete_use_symbol( fn find_current_scope_concrete_use_symbol(
&self, &self,
declared_name: &str, declared_name: &str,
) -> Option<&ConcreteUseSymbol> { ) -> Option<Rc<RefCell<ConcreteUseSymbol>>> {
self.current_scope() self.current_scope()
.concrete_use_symbols() .concrete_use_symbols()
.get(declared_name) .get(declared_name)
.cloned()
} }
fn find_current_scope_star_use_symbol(&self, base_fqn: &str) -> Option<&StarUseSymbol> { fn find_current_scope_star_use_symbol(&self, base_fqn: &str) -> Option<&StarUseSymbol> {
self.current_scope().star_use_symbols().get(base_fqn) 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> { fn find_current_scope_module_symbol(&self, declared_name: &str) -> Option<&ModuleSymbol> {
self.current_scope().module_symbols().get(declared_name) 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<Symbol> { fn find_current_scope_usable_symbol(&self, declared_name: &str) -> Option<Symbol> {
self.find_current_scope_concrete_use_symbol(declared_name) self.find_current_scope_concrete_use_symbol(declared_name)
.map(|concrete_use_symbol| Symbol::ConcreteUse(concrete_use_symbol.clone())) .map(|concrete_use_symbol| {
.or_else(|| { Symbol::Use(UseSymbol::Concrete(concrete_use_symbol.clone()))
self.find_current_scope_type_symbol(declared_name)
.map(|type_symbol| Symbol::Type(type_symbol.clone()))
}) })
// .or_else(|| {
// self.find_current_scope_type_symbol(declared_name)
// .map(|type_symbol| Symbol::Type(type_symbol.clone()))
// })
.or_else(|| { .or_else(|| {
self.find_current_scope_module_symbol(declared_name) self.find_current_scope_module_symbol(declared_name)
.map(|module_symbol| Symbol::Module(module_symbol.clone())) .map(|module_symbol| Symbol::Module(module_symbol.clone()))
@ -133,17 +137,22 @@ impl SymbolTable {
pub fn insert_concrete_use_symbol( pub fn insert_concrete_use_symbol(
&mut self, &mut self,
concrete_use_symbol: ConcreteUseSymbol, concrete_use_symbol: ConcreteUseSymbol,
) -> Result<(), SymbolInsertError> { ) -> Result<Rc<RefCell<ConcreteUseSymbol>>, SymbolInsertError> {
if let Some(defined_symbol) = if let Some(defined_symbol) =
self.find_current_scope_usable_symbol(concrete_use_symbol.declared_name()) self.find_current_scope_usable_symbol(concrete_use_symbol.declared_name())
{ {
Err(SymbolAlreadyDefined(defined_symbol)) Err(SymbolAlreadyDefined(defined_symbol))
} else { } else {
self.current_scope_mut().concrete_use_symbols_mut().insert( let name = concrete_use_symbol.declared_name().to_string();
concrete_use_symbol.declared_name().to_string(), self.current_scope_mut()
concrete_use_symbol, .concrete_use_symbols_mut()
); .insert(name.clone(), Rc::new(RefCell::new(concrete_use_symbol)));
Ok(()) Ok(self
.current_scope()
.concrete_use_symbols()
.get(&name)
.cloned()
.unwrap())
} }
} }
@ -154,9 +163,9 @@ impl SymbolTable {
if let Some(defined_symbol) = if let Some(defined_symbol) =
self.find_current_scope_star_use_symbol(star_use_symbol.base_fqn()) 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(), defined_symbol.clone(),
))) ))))
} else { } else {
self.current_scope_mut() self.current_scope_mut()
.star_use_symbols_mut() .star_use_symbols_mut()
@ -181,15 +190,23 @@ impl SymbolTable {
} }
} }
pub fn insert_type_symbol(&mut self, type_symbol: TypeSymbol) -> Result<(), SymbolInsertError> { fn find_current_scope_concrete_type_symbol(
if let Some(defined_symbol) = &self,
self.find_current_scope_usable_symbol(type_symbol.declared_name()) declared_name: &str,
) -> Option<Rc<RefCell<ConcreteTypeSymbol>>> {
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 { } else {
self.current_scope_mut() self.current_scope_mut().insert_concrete_type_symbol(symbol);
.type_symbols_mut()
.insert(type_symbol.declared_name().to_string(), type_symbol);
Ok(()) 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( fn lookup_addressable_in_scope_by_identifier(
scope: &Scope, scope: &Scope,
identifier: &str, identifier: &str,
@ -350,12 +307,12 @@ impl SymbolTable {
.get(identifier) .get(identifier)
.map(|function_symbol| Symbol::Function(function_symbol.clone())) .map(|function_symbol| Symbol::Function(function_symbol.clone()))
}) })
.or_else(|| { // .or_else(|| {
scope // scope
.type_symbols() // .type_symbols()
.get(identifier) // .get(identifier)
.map(|type_symbol| Symbol::Type(type_symbol.clone())) // .map(|type_symbol| Symbol::Type(type_symbol.clone()))
}) // })
} }
pub fn lookup_addressable_by_identifier( pub fn lookup_addressable_by_identifier(
@ -378,17 +335,36 @@ impl SymbolTable {
Err(NoDefinition) Err(NoDefinition)
} }
pub fn resolve_usable_by_fqn( pub fn resolve_concrete_usable_by_fqn(
&self, &self,
fqn: &str fqn: &str,
) -> Result<Symbol, SymbolLookupError> { ) -> Result<ConcreteUsableSymbol, SymbolLookupError> {
todo!() // breadth-first search, use a queue
let mut search_stack: VecDeque<usize> = 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<RefCell<symbol>>
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( pub fn resolve_usable_star(&self, base_fqn: &str) -> Result<(), SymbolLookupError> {
&self,
base_fqn: &str,
) -> Result<(), SymbolLookupError> {
todo!() todo!()
} }
} }

View File

@ -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::function_symbol::FunctionSymbol;
use crate::name_analysis::symbol::module_symbol::ModuleSymbol; use crate::name_analysis::symbol::module_symbol::ModuleSymbol;
use crate::name_analysis::symbol::parameter_symbol::ParameterSymbol; 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::use_symbol::{ConcreteUseSymbol, StarUseSymbol};
use crate::name_analysis::symbol::variable_symbol::VariableSymbol; use crate::name_analysis::symbol::variable_symbol::VariableSymbol;
use std::cell::RefCell;
use std::collections::HashMap; use std::collections::HashMap;
use std::fmt::{Display, Formatter}; use std::fmt::{Display, Formatter};
use std::rc::Rc;
#[derive(Debug)] #[derive(Debug)]
pub struct Scope { pub struct Scope {
parent: Option<usize>, parent: Option<usize>,
id: usize, id: usize,
concrete_use_symbols: HashMap<String, ConcreteUseSymbol>, children: Vec<usize>,
concrete_use_symbols: HashMap<String, Rc<RefCell<ConcreteUseSymbol>>>,
star_use_symbols: HashMap<String, StarUseSymbol>, star_use_symbols: HashMap<String, StarUseSymbol>,
module_symbols: HashMap<String, ModuleSymbol>, module_symbols: HashMap<String, ModuleSymbol>,
type_symbols: HashMap<String, TypeSymbol>, concrete_type_symbols: HashMap<String, Rc<RefCell<ConcreteTypeSymbol>>>,
concrete_type_symbols_by_fqn: HashMap<String, Rc<RefCell<ConcreteTypeSymbol>>>,
function_symbols: HashMap<String, FunctionSymbol>, function_symbols: HashMap<String, FunctionSymbol>,
parameter_symbols: HashMap<String, ParameterSymbol>, parameter_symbols: HashMap<String, ParameterSymbol>,
variable_symbols: HashMap<String, VariableSymbol>, variable_symbols: HashMap<String, VariableSymbol>,
@ -28,10 +32,12 @@ impl Scope {
Self { Self {
parent, parent,
id, id,
children: vec![],
concrete_use_symbols: HashMap::new(), concrete_use_symbols: HashMap::new(),
star_use_symbols: HashMap::new(), star_use_symbols: HashMap::new(),
module_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(), function_symbols: HashMap::new(),
parameter_symbols: HashMap::new(), parameter_symbols: HashMap::new(),
variable_symbols: HashMap::new(), variable_symbols: HashMap::new(),
@ -48,11 +54,21 @@ impl Scope {
self.id self.id
} }
pub fn concrete_use_symbols(&self) -> &HashMap<String, ConcreteUseSymbol> { pub fn add_child(&mut self, child_id: usize) {
self.children.push(child_id);
}
pub fn children(&self) -> Vec<usize> {
self.children.clone()
}
pub fn concrete_use_symbols(&self) -> &HashMap<String, Rc<RefCell<ConcreteUseSymbol>>> {
&self.concrete_use_symbols &self.concrete_use_symbols
} }
pub fn concrete_use_symbols_mut(&mut self) -> &mut HashMap<String, ConcreteUseSymbol> { pub fn concrete_use_symbols_mut(
&mut self,
) -> &mut HashMap<String, Rc<RefCell<ConcreteUseSymbol>>> {
&mut self.concrete_use_symbols &mut self.concrete_use_symbols
} }
@ -72,12 +88,24 @@ impl Scope {
&mut self.module_symbols &mut self.module_symbols
} }
pub fn type_symbols(&self) -> &HashMap<String, TypeSymbol> { pub fn insert_concrete_type_symbol(&mut self, symbol: ConcreteTypeSymbol) {
&self.type_symbols 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<String, TypeSymbol> { pub fn get_concrete_type_symbol(&self, declared_name: &str) -> Option<Rc<RefCell<ConcreteTypeSymbol>>> {
&mut self.type_symbols self.concrete_type_symbols.get(declared_name).cloned()
}
pub fn get_concrete_type_symbol_by_fqn(&self, fqn: &str) -> Option<Rc<RefCell<ConcreteTypeSymbol>>> {
self.concrete_type_symbols_by_fqn.get(fqn).cloned()
} }
pub fn function_symbols(&self) -> &HashMap<String, FunctionSymbol> { pub fn function_symbols(&self) -> &HashMap<String, FunctionSymbol> {
@ -131,13 +159,15 @@ impl Display for Scope {
f, f,
"----Scope {} (p: {}) {}----", "----Scope {} (p: {}) {}----",
self.id(), 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() self.debug_name()
)?; )?;
write_symbols!(f, self.concrete_use_symbols()); write_symbols!(f, self.concrete_use_symbols());
write_symbols!(f, self.star_use_symbols()); write_symbols!(f, self.star_use_symbols());
write_symbols!(f, self.module_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.function_symbols());
write_symbols!(f, self.parameter_symbols()); write_symbols!(f, self.parameter_symbols());
write_symbols!(f, self.variable_symbols()); write_symbols!(f, self.variable_symbols());

View File

@ -248,6 +248,10 @@ UseStatement:
- range: - range:
special: special:
kind: range kind: range
fields:
- use_symbol:
kind: UseSymbol
wrap: rc_ref_cell
UseStatementPrefix: UseStatementPrefix:
struct: struct:
children: children: