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 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)
}

View File

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

View File

@ -1,14 +1,16 @@
pub struct StructSpec {
build: String,
children: Vec<Box<StructChild>>,
fields: Vec<Box<StructField>>,
derive: Vec<String>,
}
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 {
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<Item = &StructField> {
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<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::{
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<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 {
let child_ident = format_ident!("{}", vec_child.name());
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 {
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::<Vec<_>>();
let annotated_fields = build_spec
.fields()
.map(|field| make_annotated_field(field))
.collect::<Vec<_>>();
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::<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()
.map(|child| make_accessors(child))
.filter(Option::is_some)
.map(Option::unwrap)
.collect::<Vec<_>>();
let field_accessors = build_spec
.fields()
.map(|field| make_field_accessors(field))
.collect::<Vec<_>>();
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)*
}
}
}

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::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<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,
symbol_table: &mut SymbolTable,
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::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

View File

@ -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};
@ -50,9 +51,18 @@ fn nap2_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) {
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(
error,
lookup_error,
&fqn,
use_statement.file_id(),
use_statement.range(),
@ -60,6 +70,7 @@ fn nap2_use_statement(
diagnostics,
);
}
}
};
match use_statement.suffix() {

View File

@ -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<RefCell<ConcreteTypeSymbol>>),
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<SourceDefinition> {
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()
}
}
}
}

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::usable_symbol::ConcreteUsableSymbol;
use std::cell::RefCell;
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)]
pub struct ConcreteUseSymbol {
base_fqn: String,
declared_name: String,
source_definition: Option<SourceDefinition>,
resolved_symbol: Option<ConcreteUsableSymbol>,
}
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 {

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::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<Rc<RefCell<ConcreteUseSymbol>>> {
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<Symbol> {
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<Rc<RefCell<ConcreteUseSymbol>>, 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<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 {
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<Symbol, SymbolLookupError> {
todo!()
fqn: &str,
) -> Result<ConcreteUsableSymbol, SymbolLookupError> {
// 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);
}
pub fn resolve_usable_star(
&self,
base_fqn: &str,
) -> Result<(), SymbolLookupError> {
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(&self, base_fqn: &str) -> Result<(), SymbolLookupError> {
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::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<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>,
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>,
parameter_symbols: HashMap<String, ParameterSymbol>,
variable_symbols: HashMap<String, VariableSymbol>,
@ -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<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
}
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
}
@ -72,12 +88,24 @@ impl Scope {
&mut self.module_symbols
}
pub fn type_symbols(&self) -> &HashMap<String, TypeSymbol> {
&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<String, TypeSymbol> {
&mut self.type_symbols
pub fn get_concrete_type_symbol(&self, declared_name: &str) -> Option<Rc<RefCell<ConcreteTypeSymbol>>> {
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> {
@ -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());

View File

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