From af8f0b5dacf8631d0f1a7711570c508526a67669 Mon Sep 17 00:00:00 2001 From: Jesse Brault Date: Mon, 20 Oct 2025 18:31:54 -0500 Subject: [PATCH] Various new ideas for name analysis. --- ast-generator/src/ast_node/enum_ast_node.rs | 65 ++++-- .../src/ast_node/leaf_enum_ast_node.rs | 6 + .../src/ast_node/leaf_struct_ast_node.rs | 6 + ast-generator/src/ast_node/mod.rs | 110 ++++------ .../polymorphic_enum_loop_ast_node.rs | 8 + .../src/ast_node/polymorphic_type_ast_node.rs | 23 ++ ast-generator/src/ast_node/struct_ast_node.rs | 47 ++++- ast-generator/src/lib.rs | 35 ++- src/name_analysis/first_pass.rs | 147 +++++++++++++ src/name_analysis/gather.rs | 199 +++++++++--------- src/name_analysis/mod.rs | 18 +- src/name_analysis/second_pass.rs | 87 ++++++++ src/name_analysis/symbol_table/mod.rs | 14 ++ src/name_analysis/util.rs | 11 + 14 files changed, 577 insertions(+), 199 deletions(-) create mode 100644 src/name_analysis/first_pass.rs create mode 100644 src/name_analysis/second_pass.rs create mode 100644 src/name_analysis/util.rs diff --git a/ast-generator/src/ast_node/enum_ast_node.rs b/ast-generator/src/ast_node/enum_ast_node.rs index 90aa6b9..a5bf937 100644 --- a/ast-generator/src/ast_node/enum_ast_node.rs +++ b/ast-generator/src/ast_node/enum_ast_node.rs @@ -1,5 +1,5 @@ -use convert_case::{Case, Casing}; use crate::spec::tree_enum_spec::{EnumRuleChildKind, TreeEnumBuildSpec}; +use convert_case::{Case, Casing}; use proc_macro2::TokenStream; use quote::{format_ident, quote}; @@ -10,20 +10,19 @@ pub fn make_enum_ast_node_impl(enum_spec: &TreeEnumBuildSpec) -> TokenStream { .map(|rule| { let rule_ident = format_ident!("{}", rule.rule()); match rule.child() { - Some(child) => { - match child.kind() { - EnumRuleChildKind::Node(node_child) => { - let child_ident = format_ident!("{}", node_child.node_kind().to_case(Case::Snake)); - quote! { - #type_ident::#rule_ident(#child_ident) => vec![ - #child_ident - ] - } - } - _ => quote! { - #type_ident::#rule_ident(_) => vec![] + Some(child) => match child.kind() { + EnumRuleChildKind::Node(node_child) => { + let child_ident = + format_ident!("{}", node_child.node_kind().to_case(Case::Snake)); + quote! { + #type_ident::#rule_ident(#child_ident) => vec![ + #child_ident + ] } } + _ => quote! { + #type_ident::#rule_ident(_) => vec![] + }, }, None => { quote! { @@ -33,7 +32,35 @@ pub fn make_enum_ast_node_impl(enum_spec: &TreeEnumBuildSpec) -> TokenStream { } }) .collect::>(); - + + let mut_match_arms = enum_spec + .rules() + .map(|rule| { + let rule_ident = format_ident!("{}", rule.rule()); + match rule.child() { + Some(child) => match child.kind() { + EnumRuleChildKind::Node(node_child) => { + let child_ident = + format_ident!("{}", node_child.node_kind().to_case(Case::Snake)); + quote! { + #type_ident::#rule_ident(#child_ident) => { + f(#child_ident as &'a mut dyn AstNode<'a>) + } + } + } + _ => quote! { + #type_ident::#rule_ident(_) => {} + }, + }, + None => { + quote! { + #type_ident::#rule_ident => {} + } + } + } + }) + .collect::>(); + quote! { impl<'a> AstNode<'a> for #type_ident { fn children(&'a self) -> Vec<&'a dyn AstNode<'a>> { @@ -42,9 +69,19 @@ pub fn make_enum_ast_node_impl(enum_spec: &TreeEnumBuildSpec) -> TokenStream { } } + fn for_each_child_mut(&'a mut self, mut f: &mut dyn FnMut(&'a mut dyn AstNode<'a>)) { + match self { + #(#mut_match_arms,)* + } + } + fn as_node_ref(&'a self) -> AstNodeRef<'a> { AstNodeRef::#type_ident(&self) } + + fn as_node_ref_mut(&'a mut self) -> AstNodeRefMut<'a> { + AstNodeRefMut::#type_ident(self) + } } } } diff --git a/ast-generator/src/ast_node/leaf_enum_ast_node.rs b/ast-generator/src/ast_node/leaf_enum_ast_node.rs index 4af859c..bebccc3 100644 --- a/ast-generator/src/ast_node/leaf_enum_ast_node.rs +++ b/ast-generator/src/ast_node/leaf_enum_ast_node.rs @@ -10,9 +10,15 @@ pub fn make_leaf_enum_ast_node_impl(spec: &LeafEnumBuildSpec) -> TokenStream { vec![] } + fn for_each_child_mut(&'a mut self, mut f: &mut dyn FnMut(&'a mut dyn AstNode<'a>)) {} + fn as_node_ref(&'a self) -> AstNodeRef<'a> { AstNodeRef::#type_ident(&self) } + + fn as_node_ref_mut(&'a mut self) -> AstNodeRefMut<'a> { + AstNodeRefMut::#type_ident(self) + } } } } diff --git a/ast-generator/src/ast_node/leaf_struct_ast_node.rs b/ast-generator/src/ast_node/leaf_struct_ast_node.rs index 7dff5d8..9549ca4 100644 --- a/ast-generator/src/ast_node/leaf_struct_ast_node.rs +++ b/ast-generator/src/ast_node/leaf_struct_ast_node.rs @@ -10,9 +10,15 @@ pub fn make_leaf_struct_ast_node_impl(spec: &LeafStructBuildSpec) -> TokenStream vec![] } + fn for_each_child_mut(&'a mut self, mut f: &mut dyn FnMut(&'a mut dyn AstNode<'a>)) {} + fn as_node_ref(&'a self) -> AstNodeRef<'a> { AstNodeRef::#type_ident(&self) } + + fn as_node_ref_mut(&'a mut self) -> AstNodeRefMut<'a> { + AstNodeRefMut::#type_ident(self) + } } } } diff --git a/ast-generator/src/ast_node/mod.rs b/ast-generator/src/ast_node/mod.rs index ccfe5a0..fbbac07 100644 --- a/ast-generator/src/ast_node/mod.rs +++ b/ast-generator/src/ast_node/mod.rs @@ -1,63 +1,47 @@ mod enum_ast_node; mod leaf_enum_ast_node; -mod struct_ast_node; mod leaf_struct_ast_node; -mod polymorphic_type_ast_node; mod polymorphic_enum_loop_ast_node; +mod polymorphic_type_ast_node; +mod struct_ast_node; -use crate::spec::BuildSpec; -use proc_macro2::TokenStream; -use quote::{format_ident, quote}; use crate::ast_node::enum_ast_node::make_enum_ast_node_impl; use crate::ast_node::leaf_enum_ast_node::make_leaf_enum_ast_node_impl; use crate::ast_node::leaf_struct_ast_node::make_leaf_struct_ast_node_impl; use crate::ast_node::polymorphic_enum_loop_ast_node::make_polymorphic_enum_loop_ast_node_impl; use crate::ast_node::polymorphic_type_ast_node::make_polymorphic_type_ast_node_impl; use crate::ast_node::struct_ast_node::make_struct_ast_node_impl; +use crate::spec::BuildSpec; +use proc_macro2::{Ident, TokenStream}; +use quote::{format_ident, quote}; pub fn make_ast_node_impl(build_spec: &BuildSpec) -> Option { match build_spec { - BuildSpec::Enum(enum_spec) => { - Some(make_enum_ast_node_impl(enum_spec)) - } - BuildSpec::LeafEnum(leaf_enum) => { - Some(make_leaf_enum_ast_node_impl(leaf_enum)) - } - BuildSpec::Struct(struct_spec) => { - Some(make_struct_ast_node_impl(struct_spec)) - } - BuildSpec::LeafStruct(leaf_struct) => { - Some(make_leaf_struct_ast_node_impl(leaf_struct)) - } + BuildSpec::Enum(enum_spec) => Some(make_enum_ast_node_impl(enum_spec)), + BuildSpec::LeafEnum(leaf_enum) => Some(make_leaf_enum_ast_node_impl(leaf_enum)), + BuildSpec::Struct(struct_spec) => Some(make_struct_ast_node_impl(struct_spec)), + BuildSpec::LeafStruct(leaf_struct) => Some(make_leaf_struct_ast_node_impl(leaf_struct)), BuildSpec::Production(_) => None, BuildSpec::NodeProduction(_) => None, BuildSpec::PolymorphicType(polymorphic_type) => { Some(make_polymorphic_type_ast_node_impl(polymorphic_type)) } - BuildSpec::PolymorphicEnumLoop(polymorphic_enum_loop) => { - Some(make_polymorphic_enum_loop_ast_node_impl(polymorphic_enum_loop)) - } + BuildSpec::PolymorphicEnumLoop(polymorphic_enum_loop) => Some( + make_polymorphic_enum_loop_ast_node_impl(polymorphic_enum_loop), + ), BuildSpec::PolymorphicPassThrough(_) => None, } } -pub fn make_ast_enum_member(build_spec: &BuildSpec) -> Option { +fn make_type_ident(build_spec: &BuildSpec) -> Option { match build_spec { - BuildSpec::Struct(struct_spec) => { - Some(format_ident!("{}", struct_spec.build())) - } - BuildSpec::LeafStruct(leaf_struct) => { - Some(format_ident!("{}", leaf_struct.build())) - } - BuildSpec::Enum(enum_spec) => { - Some(format_ident!("{}", enum_spec.build())) - } - BuildSpec::LeafEnum(leaf_enum) => { - Some(format_ident!("{}", leaf_enum.build())) - } + BuildSpec::Struct(struct_spec) => Some(format_ident!("{}", struct_spec.build())), + BuildSpec::LeafStruct(leaf_struct) => Some(format_ident!("{}", leaf_struct.build())), + BuildSpec::Enum(enum_spec) => Some(format_ident!("{}", enum_spec.build())), + BuildSpec::LeafEnum(leaf_enum) => Some(format_ident!("{}", leaf_enum.build())), BuildSpec::PolymorphicType(polymorphic_type) => { Some(format_ident!("{}", polymorphic_type.name())) - }, + } BuildSpec::PolymorphicEnumLoop(polymorphic_enum_loop) => { Some(format_ident!("{}", polymorphic_enum_loop.name())) } @@ -65,40 +49,36 @@ pub fn make_ast_enum_member(build_spec: &BuildSpec) -> Option { BuildSpec::Production(_) => None, BuildSpec::NodeProduction(_) => None, } - .map(|type_ident| { - quote! { - #type_ident(&'a #type_ident) - } - }) +} + +pub fn make_ast_enum_member(build_spec: &BuildSpec) -> Option { + make_type_ident(build_spec).map(|type_ident| { + quote! { + #type_ident(&'a #type_ident) + } + }) +} + +pub fn make_ast_enum_mut_member(build_spec: &BuildSpec) -> Option { + make_type_ident(build_spec).map(|type_ident| { + quote! { + #type_ident(&'a mut #type_ident) + } + }) } pub fn make_ast_node_ref_unwrapper(build_spec: &BuildSpec) -> Option { - match build_spec { - BuildSpec::Enum(enum_spec) => { - Some(format_ident!("{}", enum_spec.build())) + make_type_ident(build_spec).map(|type_ident| { + quote! { + AstNodeRef::#type_ident(inner) => *inner } - BuildSpec::LeafEnum(leaf_enum) => { - Some(format_ident!("{}", leaf_enum.build())) + }) +} + +pub fn make_ast_node_ref_mut_unwrapper(build_spec: &BuildSpec) -> Option { + make_type_ident(build_spec).map(|type_ident| { + quote! { + AstNodeRefMut::#type_ident(inner) => *inner } - BuildSpec::Struct(struct_spec) => { - Some(format_ident!("{}", struct_spec.build())) - } - BuildSpec::LeafStruct(leaf_struct) => { - Some(format_ident!("{}", leaf_struct.build())) - } - BuildSpec::Production(_) => None, - BuildSpec::NodeProduction(_) => None, - BuildSpec::PolymorphicType(polymorphic_type) => { - Some(format_ident!("{}", polymorphic_type.name())) - } - BuildSpec::PolymorphicEnumLoop(polymorphic_enum_loop) => { - Some(format_ident!("{}", polymorphic_enum_loop.name())) - } - BuildSpec::PolymorphicPassThrough(_) => None - } - .map(|type_ident| { - quote! { - AstNodeRef::#type_ident(inner) => *inner - } - }) + }) } \ No newline at end of file diff --git a/ast-generator/src/ast_node/polymorphic_enum_loop_ast_node.rs b/ast-generator/src/ast_node/polymorphic_enum_loop_ast_node.rs index c5c1bde..8894012 100644 --- a/ast-generator/src/ast_node/polymorphic_enum_loop_ast_node.rs +++ b/ast-generator/src/ast_node/polymorphic_enum_loop_ast_node.rs @@ -41,9 +41,17 @@ pub fn make_polymorphic_enum_loop_ast_node_impl( children } + fn for_each_child_mut(&'a mut self, mut f: &mut dyn FnMut(&'a mut dyn AstNode<'a>)) { + todo!() + } + fn as_node_ref(&'a self) -> AstNodeRef<'a> { AstNodeRef::#type_ident(&self) } + + fn as_node_ref_mut(&'a mut self) -> AstNodeRefMut<'a> { + AstNodeRefMut::#type_ident(self) + } } } } diff --git a/ast-generator/src/ast_node/polymorphic_type_ast_node.rs b/ast-generator/src/ast_node/polymorphic_type_ast_node.rs index 8c1e67d..8591c24 100644 --- a/ast-generator/src/ast_node/polymorphic_type_ast_node.rs +++ b/ast-generator/src/ast_node/polymorphic_type_ast_node.rs @@ -16,6 +16,19 @@ pub fn make_polymorphic_type_ast_node_impl(spec: &PolymorphicTypeBuildSpec) -> T }) .collect::>(); + let match_arms_mut = spec + .variants() + .map(|variant| { + let variant_ident = format_ident!("{}", variant.name()); + let child_ident = format_ident!("{}", variant.inner_kind().to_case(Case::Snake)); + quote! { + #type_ident::#variant_ident(#child_ident) => { + f(#child_ident as &'a mut dyn AstNode) + } + } + }) + .collect::>(); + quote! { impl<'a> AstNode<'a> for #type_ident { fn children(&'a self) -> Vec<&'a dyn AstNode<'a>> { @@ -24,9 +37,19 @@ pub fn make_polymorphic_type_ast_node_impl(spec: &PolymorphicTypeBuildSpec) -> T } } + fn for_each_child_mut(&'a mut self, mut f: &mut dyn FnMut(&'a mut dyn AstNode<'a>)) { + match self { + #(#match_arms_mut,)* + } + } + fn as_node_ref(&'a self) -> AstNodeRef<'a> { AstNodeRef::#type_ident(&self) } + + fn as_node_ref_mut(&'a mut self) -> AstNodeRefMut<'a> { + AstNodeRefMut::#type_ident(self) + } } } } diff --git a/ast-generator/src/ast_node/struct_ast_node.rs b/ast-generator/src/ast_node/struct_ast_node.rs index 68484a1..b65fa7c 100644 --- a/ast-generator/src/ast_node/struct_ast_node.rs +++ b/ast-generator/src/ast_node/struct_ast_node.rs @@ -2,19 +2,27 @@ use crate::spec::struct_spec::{MemberChildBuild, StructChild, StructSpec, VecChi use proc_macro2::TokenStream; use quote::{format_ident, quote}; -pub fn make_struct_ast_node_impl(spec: &StructSpec) -> TokenStream { - let type_ident = format_ident!("{}", spec.build()); - let child_adders = spec - .children() +fn make_child_adders(spec: &StructSpec, is_mut: bool) -> Vec { + let as_clause = if is_mut { + quote! { as &mut dyn AstNode } + } else { + quote! { as &dyn AstNode } + }; + + spec.children() .map(|child| match child { StructChild::SkipChild(_) => None, StructChild::VecChild(vec_child) => match vec_child.build() { VecChildBuild::String(_) => None, VecChildBuild::Node(_) => { - let child_ident = format_ident!("{}", vec_child.name()); + let child_ident = if is_mut { + format_ident!("{}_mut", vec_child.name()) + } else { + format_ident!("{}", vec_child.name()) + }; let children_stream = quote! { for child in self.#child_ident() { - children.push(child as &dyn AstNode); + children.push(child #as_clause); } }; Some(children_stream) @@ -22,16 +30,21 @@ pub fn make_struct_ast_node_impl(spec: &StructSpec) -> TokenStream { }, StructChild::MemberChild(member_child) => match member_child.build() { MemberChildBuild::Node(_) => { - let child_ident = format_ident!("{}", member_child.name()); + let child_ident = if is_mut { + format_ident!("{}_mut", member_child.name()) + } else { + format_ident!("{}", member_child.name()) + }; + if member_child.optional() { Some(quote! { if let Some(#child_ident) = self.#child_ident() { - children.push(#child_ident as &dyn AstNode); + children.push(#child_ident #as_clause); } }) } else { Some(quote! { - children.push(self.#child_ident() as &dyn AstNode) + children.push(self.#child_ident() #as_clause) }) } } @@ -41,7 +54,13 @@ pub fn make_struct_ast_node_impl(spec: &StructSpec) -> TokenStream { }) .filter(Option::is_some) .map(Option::unwrap) - .collect::>(); + .collect::>() +} + +pub fn make_struct_ast_node_impl(spec: &StructSpec) -> TokenStream { + let type_ident = format_ident!("{}", spec.build()); + let child_adders = make_child_adders(spec, false); + let child_adders_mut = make_child_adders(spec, true); quote! { impl<'a> AstNode<'a> for #type_ident { @@ -51,9 +70,17 @@ pub fn make_struct_ast_node_impl(spec: &StructSpec) -> TokenStream { children } + fn for_each_child_mut(&'a mut self, mut f: &mut dyn FnMut(&'a mut dyn AstNode<'a>)) { + todo!() + } + fn as_node_ref(&'a self) -> AstNodeRef<'a> { AstNodeRef::#type_ident(&self) } + + fn as_node_ref_mut(&'a mut self) -> AstNodeRefMut<'a> { + AstNodeRefMut::#type_ident(self) + } } } } diff --git a/ast-generator/src/lib.rs b/ast-generator/src/lib.rs index a8f0266..30c7836 100644 --- a/ast-generator/src/lib.rs +++ b/ast-generator/src/lib.rs @@ -6,7 +6,10 @@ mod spec; mod type_gen; mod walk; -use crate::ast_node::{make_ast_enum_member, make_ast_node_impl, make_ast_node_ref_unwrapper}; +use crate::ast_node::{ + make_ast_enum_member, make_ast_enum_mut_member, make_ast_node_impl, + make_ast_node_ref_mut_unwrapper, make_ast_node_ref_unwrapper, +}; use crate::build_fn::make_build_fn; use crate::deserialize::deserialize_yaml_spec; use crate::pretty_print::make_pretty_print_impl; @@ -165,6 +168,13 @@ fn generate_ast_node_file(build_specs: &[BuildSpec]) -> AstGeneratedFile { .map(Option::unwrap) .collect::>(); + let ast_enum_mut_members = build_specs + .iter() + .map(|build_spec| make_ast_enum_mut_member(build_spec)) + .filter(Option::is_some) + .map(Option::unwrap) + .collect::>(); + let inner_unwrappers = build_specs .iter() .map(|build_spec| make_ast_node_ref_unwrapper(build_spec)) @@ -172,6 +182,13 @@ fn generate_ast_node_file(build_specs: &[BuildSpec]) -> AstGeneratedFile { .map(Option::unwrap) .collect::>(); + let inner_mut_unwrappers = build_specs + .iter() + .map(|build_spec| make_ast_node_ref_mut_unwrapper(build_spec)) + .filter(Option::is_some) + .map(Option::unwrap) + .collect::>(); + let combined = quote! { use crate::ast::node::*; @@ -187,10 +204,26 @@ fn generate_ast_node_file(build_specs: &[BuildSpec]) -> AstGeneratedFile { } } + pub enum AstNodeRefMut<'a> { + #(#ast_enum_mut_members,)* + } + + impl<'a> AstNodeRefMut<'a> { + pub fn inner(&mut self) -> &mut dyn AstNode<'a> { + match self { + #(#inner_mut_unwrappers,)* + } + } + } + pub trait AstNode<'a> { fn children(&'a self) -> Vec<&'a dyn AstNode<'a>>; + fn for_each_child_mut(&'a mut self, f: &mut dyn FnMut(&'a mut dyn AstNode<'a>)); + fn as_node_ref(&'a self) -> AstNodeRef<'a>; + + fn as_node_ref_mut(&'a mut self) -> AstNodeRefMut<'a>; } #(#impls)* diff --git a/src/name_analysis/first_pass.rs b/src/name_analysis/first_pass.rs new file mode 100644 index 0000000..beb2166 --- /dev/null +++ b/src/name_analysis/first_pass.rs @@ -0,0 +1,147 @@ +use crate::ast::node::{CompilationUnit, 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_table::{SymbolInsertError, SymbolTable}; +use crate::name_analysis::util::use_statement_base_fqn; +use codespan_reporting::diagnostic::{Diagnostic, Label}; +use std::range::Range; + +fn handle_insert_error( + err: SymbolInsertError, + error_symbol_name: &str, + error_file_id: usize, + error_range: Range, + symbol_types: &str, + diagnostics: &mut Vec, +) { + match err { + SymbolInsertError::SymbolAlreadyDefined(s) => { + let mut diagnostic = Diagnostic::error() + .with_message(format!( + "{} symbol '{}' already defined in the current scope.", + symbol_types, error_symbol_name, + )) + .with_label( + Label::primary(error_file_id, error_range) + .with_message("Symbol duplicated here."), + ); + + if let Some(source_definition) = s.definition() { + diagnostic = diagnostic.with_label( + Label::secondary(source_definition.file_id(), source_definition.range()) + .with_message("Symbol defined here."), + ); + } + + diagnostics.push(diagnostic); + } + } +} + +macro_rules! insert_symbol { + ($insert_method:ident, $symbol:expr, $symbol_table:ident, $name:expr, $node:ident, $symbol_kinds:literal, $diagnostics:ident) => { + if let Err(insert_error) = $symbol_table.$insert_method($symbol) { + handle_insert_error( + insert_error, + $name, + $node.file_id(), + $node.range(), + $symbol_kinds, + $diagnostics, + ) + } + }; +} + +macro_rules! insert_concrete_use_symbol { + ($symbol:expr, $symbol_table:ident, $symbol_name:expr, $source_node:ident, $symbol_kinds:literal, $diagnostics:ident) => { + insert_symbol!( + insert_concrete_use_symbol, + $symbol, + $symbol_table, + $symbol_name, + $source_node, + $symbol_kinds, + $diagnostics + ) + }; +} + +pub fn np1_compilation_unit( + file_name: &str, + compilation_unit: &mut CompilationUnit, + symbol_table: &mut SymbolTable, + diagnostics: &mut Vec, +) { + let mut fqn_context = FqnContext::new(); + symbol_table.push_scope(&format!("FileScope {}", file_name)); + + if let Some(namespace) = compilation_unit.namespace() { + for identifier in namespace.fqn().identifiers() { + fqn_context.push(identifier.name()); + } + } + + for use_statement in compilation_unit.use_statements_mut() { + np1_use_statement(use_statement, symbol_table, diagnostics); + } + + symbol_table.pop_scope(); +} + +fn np1_use_statement( + use_statement: &mut UseStatement, + symbol_table: &mut SymbolTable, + diagnostics: &mut Vec, +) { + let base_fqn = use_statement_base_fqn(use_statement); + + match use_statement.suffix() { + UseStatementSuffix::Identifier(identifier) => { + insert_concrete_use_symbol!( + ConcreteUseSymbol::new( + &base_fqn, + identifier.name(), + Some(SourceDefinition::from_identifier(identifier)) + ), + symbol_table, + &base_fqn, + identifier, + "Use Statement", + diagnostics + ) + } + UseStatementSuffix::Star => { + insert_symbol!( + insert_star_use_symbol, + StarUseSymbol::new( + &base_fqn, + Some(SourceDefinition::from_use_statement(use_statement)) + ), + symbol_table, + &base_fqn, + use_statement, + "Use Statement", + diagnostics + ); + } + UseStatementSuffix::UseList(use_list) => { + for identifier in use_list.identifiers() { + insert_concrete_use_symbol!( + ConcreteUseSymbol::new( + &base_fqn, + identifier.name(), + Some(SourceDefinition::from_identifier(identifier)) + ), + symbol_table, + &base_fqn, + identifier, + "Use Statement", + diagnostics + ); + } + } + } +} diff --git a/src/name_analysis/gather.rs b/src/name_analysis/gather.rs index 33847f8..08f9355 100644 --- a/src/name_analysis/gather.rs +++ b/src/name_analysis/gather.rs @@ -1,5 +1,5 @@ /// The gather phase must exclusively gather all named items that can be used elsewhere. -use crate::ast::ast_node::{AstNode, AstNodeRef}; +use crate::ast::ast_node::{AstNode, AstNodeRef, AstNodeRefMut}; use crate::ast::node::{ Class, Closure, ClosureParameter, CompilationUnit, ForStatement, Function, FunctionBody, GenericParameters, Identifier, IfClause, Interface, InterfaceDefaultFunction, @@ -81,54 +81,55 @@ fn handle_lookup_error( } fn gather_node_children<'a>( - node: &'a dyn AstNode<'a>, + node: &'a mut dyn AstNode<'a>, symbol_table: &mut SymbolTable, fqn_context: &mut FqnContext, diagnostics: &mut Vec, ) { - for child in node.children() { - gather_node(child, symbol_table, fqn_context, diagnostics); - } + node.for_each_child_mut(&mut |child| { + gather_node(child, symbol_table, fqn_context, diagnostics); + }); } fn gather_node<'a>( - node: &'a dyn AstNode<'a>, + node: &'a mut dyn AstNode<'a>, symbol_table: &mut SymbolTable, fqn_context: &mut FqnContext, diagnostics: &mut Vec, ) { - match node.as_node_ref() { - AstNodeRef::GenericParameters(generic_parameters) => { + let node_ref = node.as_node_ref_mut(); + match node_ref { + AstNodeRefMut::GenericParameters(generic_parameters) => { gather_generic_parameters(generic_parameters, symbol_table, diagnostics); } - AstNodeRef::Parameter(parameter) => { + AstNodeRefMut::Parameter(parameter) => { gather_parameter(parameter, symbol_table, diagnostics); } - AstNodeRef::Namespace(namespace) => { + AstNodeRefMut::Namespace(namespace) => { gather_namespace(namespace, fqn_context); } - AstNodeRef::UseStatement(use_statement) => { + AstNodeRefMut::UseStatement(use_statement) => { gather_use_statement(use_statement, symbol_table, diagnostics); } - AstNodeRef::Module(module) => { + AstNodeRefMut::Module(module) => { gather_module(module, symbol_table, fqn_context, diagnostics); } - AstNodeRef::Interface(interface) => { + AstNodeRefMut::Interface(interface) => { gather_interface(interface, symbol_table, fqn_context, diagnostics); } - AstNodeRef::Class(class) => { + AstNodeRefMut::Class(class) => { gather_class(class, symbol_table, fqn_context, diagnostics); } - AstNodeRef::Function(function) => { + AstNodeRefMut::Function(function) => { gather_function(function, symbol_table, fqn_context, diagnostics); } - AstNodeRef::OperatorFunction(operator_function) => { + AstNodeRefMut::OperatorFunction(operator_function) => { gather_operator_function(operator_function, symbol_table, fqn_context, diagnostics); } - AstNodeRef::PlatformFunction(platform_function) => { + AstNodeRefMut::PlatformFunction(platform_function) => { gather_platform_function(platform_function, symbol_table, fqn_context, diagnostics); } - AstNodeRef::PlatformOperatorFunction(platform_operator_function) => { + AstNodeRefMut::PlatformOperatorFunction(platform_operator_function) => { gather_platform_operator_function( platform_operator_function, symbol_table, @@ -136,10 +137,10 @@ fn gather_node<'a>( diagnostics, ); } - AstNodeRef::InterfaceFunction(interface_function) => { + AstNodeRefMut::InterfaceFunction(interface_function) => { gather_interface_function(interface_function, symbol_table, fqn_context, diagnostics); } - AstNodeRef::InterfaceDefaultFunction(interface_default_function) => { + AstNodeRefMut::InterfaceDefaultFunction(interface_default_function) => { gather_interface_default_function( interface_default_function, symbol_table, @@ -147,7 +148,7 @@ fn gather_node<'a>( diagnostics, ); } - AstNodeRef::InterfaceOperatorFunction(interface_operator_function) => { + AstNodeRefMut::InterfaceOperatorFunction(interface_operator_function) => { gather_interface_operator_function( interface_operator_function, symbol_table, @@ -155,7 +156,7 @@ fn gather_node<'a>( diagnostics, ); } - AstNodeRef::InterfaceDefaultOperatorFunction(interface_default_operator_function) => { + AstNodeRefMut::InterfaceDefaultOperatorFunction(interface_default_operator_function) => { gather_interface_default_operator_function( interface_default_operator_function, symbol_table, @@ -163,13 +164,13 @@ fn gather_node<'a>( diagnostics, ); } - AstNodeRef::FunctionBody(function_body) => { + AstNodeRefMut::FunctionBody(function_body) => { gather_function_body(function_body, symbol_table, fqn_context, diagnostics); } - AstNodeRef::Member(member) => { + AstNodeRefMut::Member(member) => { gather_member(member, symbol_table, fqn_context, diagnostics); } - AstNodeRef::VariableDeclaration(variable_declaration) => { + AstNodeRefMut::VariableDeclaration(variable_declaration) => { gather_variable_declaration( variable_declaration, symbol_table, @@ -177,32 +178,32 @@ fn gather_node<'a>( diagnostics, ); } - AstNodeRef::IfClause(if_clause) => { + AstNodeRefMut::IfClause(if_clause) => { gather_if_clause(if_clause, symbol_table, fqn_context, diagnostics); } - AstNodeRef::IfElseIf(if_else_if) => { + AstNodeRefMut::IfElseIf(if_else_if) => { gather_node_children(if_else_if, symbol_table, fqn_context, diagnostics); } - AstNodeRef::WhileStatement(while_statement) => { + AstNodeRefMut::WhileStatement(while_statement) => { gather_while_statement(while_statement, symbol_table, fqn_context, diagnostics); } - AstNodeRef::ForStatement(for_statement) => { + AstNodeRefMut::ForStatement(for_statement) => { gather_for_statement(for_statement, symbol_table, fqn_context, diagnostics); } - AstNodeRef::VariableUse(variable_use) => { + AstNodeRefMut::VariableUse(variable_use) => { gather_variable_use(variable_use, symbol_table, diagnostics); } - AstNodeRef::TernaryExpression(ternary_expression) => { + AstNodeRefMut::TernaryExpression(ternary_expression) => { gather_ternary_expression(ternary_expression, symbol_table, fqn_context, diagnostics); } - AstNodeRef::Closure(closure) => { + AstNodeRefMut::Closure(closure) => { gather_closure(closure, symbol_table, fqn_context, diagnostics); } - AstNodeRef::ClosureParameter(closure_parameter) => { + AstNodeRefMut::ClosureParameter(closure_parameter) => { gather_closure_parameter(closure_parameter, symbol_table, fqn_context, diagnostics); } - _ => gather_node_children(node, symbol_table, fqn_context, diagnostics), + _ => todo!() } } @@ -230,7 +231,7 @@ fn gather_generic_parameters<'a>( } fn gather_parameter<'a>( - parameter: &'a Parameter, + parameter: &'a mut Parameter, symbol_table: &mut SymbolTable, diagnostics: &mut Vec, ) { @@ -251,7 +252,7 @@ fn gather_parameter<'a>( } pub fn gather_compilation_unit<'a>( - compilation_unit: &'a CompilationUnit, + compilation_unit: &'a mut CompilationUnit, file_name: &str, symbol_table: &mut SymbolTable, diagnostics: &mut Vec, @@ -337,7 +338,7 @@ fn gather_concrete_use_symbol( } fn gather_module<'a>( - module: &'a Module, + module: &'a mut Module, symbol_table: &mut SymbolTable, fqn_context: &mut FqnContext, diagnostics: &mut Vec, @@ -362,7 +363,7 @@ fn gather_module<'a>( fqn_context.push(module.identifier().name()); symbol_table.push_scope(&format!("ModuleScope {}", module.identifier().name())); - for declaration in module.declarations() { + for declaration in module.declarations_mut() { gather_node(declaration, symbol_table, fqn_context, diagnostics); } @@ -371,7 +372,7 @@ fn gather_module<'a>( } fn gather_interface<'a>( - interface: &'a Interface, + interface: &'a mut Interface, symbol_table: &mut SymbolTable, fqn_context: &mut FqnContext, diagnostics: &mut Vec, @@ -399,7 +400,7 @@ fn gather_interface<'a>( fqn_context.push(interface.identifier().name()); symbol_table.push_scope(&format!("InterfaceScope {}", interface.identifier().name())); - for declaration in interface.declarations() { + for declaration in interface.declarations_mut() { gather_node(declaration, symbol_table, fqn_context, diagnostics); } @@ -408,7 +409,7 @@ fn gather_interface<'a>( } fn gather_class<'a>( - class: &'a Class, + class: &'a mut Class, symbol_table: &mut SymbolTable, fqn_context: &mut FqnContext, diagnostics: &mut Vec, @@ -437,12 +438,12 @@ fn gather_class<'a>( symbol_table.push_scope(&format!("ClassScope {}", class.identifier().name())); gather_node( - class.class_constructor(), + class.class_constructor_mut(), symbol_table, fqn_context, diagnostics, ); - for declaration in class.class_level_declarations() { + for declaration in class.class_level_declarations_mut() { gather_node(declaration, symbol_table, fqn_context, diagnostics); } @@ -451,7 +452,7 @@ fn gather_class<'a>( } fn gather_function<'a>( - function: &'a Function, + function: &'a mut Function, symbol_table: &mut SymbolTable, fqn_context: &mut FqnContext, diagnostics: &mut Vec, @@ -474,21 +475,21 @@ fn gather_function<'a>( ); } symbol_table.push_scope(&format!("FunctionScope {}", function.identifier().name())); - gather_node(function.generics(), symbol_table, fqn_context, diagnostics); + gather_node(function.generics_mut(), symbol_table, fqn_context, diagnostics); gather_node( - function.parameters(), + function.parameters_mut(), symbol_table, fqn_context, diagnostics, ); gather_node( - function.return_type(), + function.return_type_mut(), symbol_table, fqn_context, diagnostics, ); gather_node( - function.function_body(), + function.function_body_mut(), symbol_table, fqn_context, diagnostics, @@ -497,7 +498,7 @@ fn gather_function<'a>( } fn gather_operator_function<'a>( - operator_function: &'a OperatorFunction, + operator_function: &'a mut OperatorFunction, symbol_table: &mut SymbolTable, fqn_context: &mut FqnContext, diagnostics: &mut Vec, @@ -526,25 +527,25 @@ fn gather_operator_function<'a>( operator_function.operator().inner().name() )); gather_node( - operator_function.generics(), + operator_function.generics_mut(), symbol_table, fqn_context, diagnostics, ); gather_node( - operator_function.parameters(), + operator_function.parameters_mut(), symbol_table, fqn_context, diagnostics, ); gather_node( - operator_function.return_type(), + operator_function.return_type_mut(), symbol_table, fqn_context, diagnostics, ); gather_node( - operator_function.function_body(), + operator_function.function_body_mut(), symbol_table, fqn_context, diagnostics, @@ -553,7 +554,7 @@ fn gather_operator_function<'a>( } fn gather_platform_function<'a>( - platform_function: &'a PlatformFunction, + platform_function: &'a mut PlatformFunction, symbol_table: &mut SymbolTable, fqn_context: &mut FqnContext, diagnostics: &mut Vec, @@ -582,19 +583,19 @@ fn gather_platform_function<'a>( platform_function.identifier().name() )); gather_node( - platform_function.generics(), + platform_function.generics_mut(), symbol_table, fqn_context, diagnostics, ); gather_node( - platform_function.parameters(), + platform_function.parameters_mut(), symbol_table, fqn_context, diagnostics, ); gather_node( - platform_function.return_type(), + platform_function.return_type_mut(), symbol_table, fqn_context, diagnostics, @@ -603,7 +604,7 @@ fn gather_platform_function<'a>( } fn gather_platform_operator_function<'a>( - platform_operator_function: &'a PlatformOperatorFunction, + platform_operator_function: &'a mut PlatformOperatorFunction, symbol_table: &mut SymbolTable, fqn_context: &mut FqnContext, diagnostics: &mut Vec, @@ -632,19 +633,19 @@ fn gather_platform_operator_function<'a>( platform_operator_function.operator().inner().name() )); gather_node( - platform_operator_function.generics(), + platform_operator_function.generics_mut(), symbol_table, fqn_context, diagnostics, ); gather_node( - platform_operator_function.parameters(), + platform_operator_function.parameters_mut(), symbol_table, fqn_context, diagnostics, ); gather_node( - platform_operator_function.return_type(), + platform_operator_function.return_type_mut(), symbol_table, fqn_context, diagnostics, @@ -653,7 +654,7 @@ fn gather_platform_operator_function<'a>( } fn gather_interface_function<'a>( - interface_function: &'a InterfaceFunction, + interface_function: &'a mut InterfaceFunction, symbol_table: &mut SymbolTable, fqn_context: &mut FqnContext, diagnostics: &mut Vec, @@ -682,19 +683,19 @@ fn gather_interface_function<'a>( interface_function.identifier().name() )); gather_node( - interface_function.generics(), + interface_function.generics_mut(), symbol_table, fqn_context, diagnostics, ); gather_node( - interface_function.parameters(), + interface_function.parameters_mut(), symbol_table, fqn_context, diagnostics, ); gather_node( - interface_function.return_type(), + interface_function.return_type_mut(), symbol_table, fqn_context, diagnostics, @@ -703,7 +704,7 @@ fn gather_interface_function<'a>( } fn gather_interface_default_function<'a>( - interface_default_function: &'a InterfaceDefaultFunction, + interface_default_function: &'a mut InterfaceDefaultFunction, symbol_table: &mut SymbolTable, fqn_context: &mut FqnContext, diagnostics: &mut Vec, @@ -732,25 +733,25 @@ fn gather_interface_default_function<'a>( interface_default_function.identifier().name() )); gather_node( - interface_default_function.generics(), + interface_default_function.generics_mut(), symbol_table, fqn_context, diagnostics, ); gather_node( - interface_default_function.parameters(), + interface_default_function.parameters_mut(), symbol_table, fqn_context, diagnostics, ); gather_node( - interface_default_function.return_type(), + interface_default_function.return_type_mut(), symbol_table, fqn_context, diagnostics, ); gather_node( - interface_default_function.function_body(), + interface_default_function.function_body_mut(), symbol_table, fqn_context, diagnostics, @@ -759,7 +760,7 @@ fn gather_interface_default_function<'a>( } fn gather_interface_operator_function<'a>( - interface_operator_function: &'a InterfaceOperatorFunction, + interface_operator_function: &'a mut InterfaceOperatorFunction, symbol_table: &mut SymbolTable, fqn_context: &mut FqnContext, diagnostics: &mut Vec, @@ -788,19 +789,19 @@ fn gather_interface_operator_function<'a>( interface_operator_function.operator().inner().name() )); gather_node( - interface_operator_function.generics(), + interface_operator_function.generics_mut(), symbol_table, fqn_context, diagnostics, ); gather_node( - interface_operator_function.parameters(), + interface_operator_function.parameters_mut(), symbol_table, fqn_context, diagnostics, ); gather_node( - interface_operator_function.return_type(), + interface_operator_function.return_type_mut(), symbol_table, fqn_context, diagnostics, @@ -809,7 +810,7 @@ fn gather_interface_operator_function<'a>( } fn gather_interface_default_operator_function<'a>( - interface_default_operator_function: &'a InterfaceDefaultOperatorFunction, + interface_default_operator_function: &'a mut InterfaceDefaultOperatorFunction, symbol_table: &mut SymbolTable, fqn_context: &mut FqnContext, diagnostics: &mut Vec, @@ -852,25 +853,25 @@ fn gather_interface_default_operator_function<'a>( .name() )); gather_node( - interface_default_operator_function.generics(), + interface_default_operator_function.generics_mut(), symbol_table, fqn_context, diagnostics, ); gather_node( - interface_default_operator_function.parameters(), + interface_default_operator_function.parameters_mut(), symbol_table, fqn_context, diagnostics, ); gather_node( - interface_default_operator_function.return_type(), + interface_default_operator_function.return_type_mut(), symbol_table, fqn_context, diagnostics, ); gather_node( - interface_default_operator_function.function_body(), + interface_default_operator_function.function_body_mut(), symbol_table, fqn_context, diagnostics, @@ -879,7 +880,7 @@ fn gather_interface_default_operator_function<'a>( } fn gather_function_body<'a>( - function_body: &'a FunctionBody, + function_body: &'a mut FunctionBody, symbol_table: &mut SymbolTable, fqn_context: &mut FqnContext, diagnostics: &mut Vec, @@ -890,7 +891,7 @@ fn gather_function_body<'a>( } fn gather_member<'a>( - member: &'a Member, + member: &'a mut Member, symbol_table: &mut SymbolTable, fqn_context: &mut FqnContext, diagnostics: &mut Vec, @@ -911,11 +912,11 @@ fn gather_member<'a>( diagnostics, ); } - gather_node(member.type_use(), symbol_table, fqn_context, diagnostics); + gather_node(member.type_use_mut(), symbol_table, fqn_context, diagnostics); } fn gather_variable_declaration<'a>( - variable_declaration: &'a VariableDeclaration, + variable_declaration: &'a mut VariableDeclaration, symbol_table: &mut SymbolTable, fqn_context: &mut FqnContext, diagnostics: &mut Vec, @@ -937,26 +938,26 @@ fn gather_variable_declaration<'a>( diagnostics, ); } - if let Some(expression) = variable_declaration.expression() { + if let Some(expression) = variable_declaration.expression_mut() { gather_node(expression, symbol_table, fqn_context, diagnostics); } } fn gather_if_clause<'a>( - if_clause: &'a IfClause, + if_clause: &'a mut IfClause, symbol_table: &mut SymbolTable, fqn_context: &mut FqnContext, diagnostics: &mut Vec, ) { symbol_table.push_scope("IfClauseScope"); gather_node( - if_clause.expression(), + if_clause.expression_mut(), symbol_table, fqn_context, diagnostics, ); symbol_table.push_scope("IfClauseStatementsScope"); - for statement in if_clause.statements() { + for statement in if_clause.statements_mut() { gather_node(statement, symbol_table, fqn_context, diagnostics); } symbol_table.pop_scope(); @@ -964,20 +965,20 @@ fn gather_if_clause<'a>( } fn gather_while_statement<'a>( - while_statement: &'a WhileStatement, + while_statement: &'a mut WhileStatement, symbol_table: &mut SymbolTable, fqn_context: &mut FqnContext, diagnostics: &mut Vec, ) { symbol_table.push_scope("WhileStatementScope"); gather_node( - while_statement.expression(), + while_statement.expression_mut(), symbol_table, fqn_context, diagnostics, ); symbol_table.push_scope("WhileStatementStatementsScope"); - for statement in while_statement.statements() { + for statement in while_statement.statements_mut() { gather_node(statement, symbol_table, fqn_context, diagnostics); } symbol_table.pop_scope(); @@ -985,13 +986,13 @@ fn gather_while_statement<'a>( } fn gather_for_statement<'a>( - for_statement: &'a ForStatement, + for_statement: &'a mut ForStatement, symbol_table: &mut SymbolTable, fqn_context: &mut FqnContext, diagnostics: &mut Vec, ) { gather_node( - for_statement.expression(), + for_statement.expression_mut(), symbol_table, fqn_context, diagnostics, @@ -1015,7 +1016,7 @@ fn gather_for_statement<'a>( ); } symbol_table.push_scope("ForStatementStatementsScope"); - for statement in for_statement.statements() { + for statement in for_statement.statements_mut() { gather_node(statement, symbol_table, fqn_context, diagnostics); } symbol_table.pop_scope(); @@ -1043,7 +1044,7 @@ fn gather_variable_use<'a>( } fn gather_ternary_expression<'a>( - ternary_expression: &'a TernaryExpression, + ternary_expression: &'a mut TernaryExpression, symbol_table: &mut SymbolTable, fqn_context: &mut FqnContext, diagnostics: &mut Vec, @@ -1054,20 +1055,20 @@ fn gather_ternary_expression<'a>( } fn gather_closure<'a>( - closure: &'a Closure, + closure: &'a mut Closure, symbol_table: &mut SymbolTable, fqn_context: &mut FqnContext, diagnostics: &mut Vec, ) { symbol_table.push_scope("ClosureScope"); gather_node( - closure.closure_parameters(), + closure.closure_parameters_mut(), symbol_table, fqn_context, diagnostics, ); symbol_table.push_scope("ClosureStatementsScope"); - for statement in closure.statements() { + for statement in closure.statements_mut() { gather_node(statement, symbol_table, fqn_context, diagnostics); } symbol_table.pop_scope(); @@ -1075,7 +1076,7 @@ fn gather_closure<'a>( } fn gather_closure_parameter<'a>( - closure_parameter: &'a ClosureParameter, + closure_parameter: &'a mut ClosureParameter, symbol_table: &mut SymbolTable, fqn_context: &mut FqnContext, diagnostics: &mut Vec, @@ -1096,7 +1097,7 @@ fn gather_closure_parameter<'a>( diagnostics, ); } - if let Some(type_use) = closure_parameter.type_use() { + if let Some(type_use) = closure_parameter.type_use_mut() { gather_node(type_use, symbol_table, fqn_context, diagnostics); } } diff --git a/src/name_analysis/mod.rs b/src/name_analysis/mod.rs index 16ff01d..f95fe5e 100644 --- a/src/name_analysis/mod.rs +++ b/src/name_analysis/mod.rs @@ -23,7 +23,7 @@ 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::gather::gather_compilation_unit; +use crate::name_analysis::first_pass::np1_compilation_unit; use crate::name_analysis::symbol_table::SymbolTable; use codespan_reporting::files::Files; use std::hash::Hash; @@ -31,26 +31,24 @@ use std::hash::Hash; pub(self) mod fqn_context; mod gather; // mod resolve; +mod first_pass; +mod scope_table; +mod second_pass; pub mod symbol; pub mod symbol_table; -mod scope_table; +mod util; pub fn analyze_names<'a, F: Files<'a, FileId = usize, Name = String>>( - compilation_units: &[Box], + compilation_units: &mut Vec>, files: &'a F, symbol_table: &mut SymbolTable, ) -> Vec { let mut diagnostics = vec![]; // gather symbols - for compilation_unit in compilation_units { + for compilation_unit in compilation_units.iter_mut() { let file_name = files.name(compilation_unit.file_id()).unwrap(); - gather_compilation_unit( - compilation_unit, - &file_name, - symbol_table, - &mut diagnostics, - ); + np1_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 new file mode 100644 index 0000000..25251df --- /dev/null +++ b/src/name_analysis/second_pass.rs @@ -0,0 +1,87 @@ +use crate::ast::node::{CompilationUnit, Identifier, UseStatement, UseStatementSuffix}; +use crate::diagnostic::DmDiagnostic; +use crate::name_analysis::symbol_table::{SymbolLookupError, SymbolTable}; +use crate::name_analysis::util::use_statement_base_fqn; +use codespan_reporting::diagnostic::{Diagnostic, Label}; +use std::range::Range; + +fn handle_lookup_error( + err: SymbolLookupError, + error_symbol_name: &str, + error_file_id: usize, + error_range: Range, + symbol_types: &str, + diagnostics: &mut Vec, +) { + match err { + SymbolLookupError::NoDefinition => { + let diagnostic = Diagnostic::error() + .with_message(format!( + "No such {} symbol '{}' in scope.", + symbol_types, error_symbol_name, + )) + .with_label( + Label::primary(error_file_id, error_range).with_message("Symbol used here."), + ); + diagnostics.push(diagnostic); + } + } +} + +pub fn nap2_compilation_unit( + compilation_unit: &mut CompilationUnit, + symbol_table: &SymbolTable, + diagnostics: &mut Vec, +) { + // TODO: check namespace for proper file name + for use_statement in compilation_unit.use_statements_mut() { + nap2_use_statement(use_statement, symbol_table, diagnostics); + } + + // TODO: declarations +} + +fn nap2_use_statement( + use_statement: &mut UseStatement, + symbol_table: &SymbolTable, + 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 use_statement.suffix() { + UseStatementSuffix::Identifier(identifier) => { + handle_concrete_use_symbol(identifier); + } + UseStatementSuffix::Star => { + if let Err(error) = symbol_table.resolve_usable_star(&base_fqn) { + handle_lookup_error( + error, + &base_fqn, + use_statement.file_id(), + use_statement.range(), + "Star Usable Symbol", + diagnostics, + ); + } + } + UseStatementSuffix::UseList(use_list) => { + for identifier in use_list.identifiers() { + handle_concrete_use_symbol(identifier); + } + } + } +} diff --git a/src/name_analysis/symbol_table/mod.rs b/src/name_analysis/symbol_table/mod.rs index 1033e98..66aef8f 100644 --- a/src/name_analysis/symbol_table/mod.rs +++ b/src/name_analysis/symbol_table/mod.rs @@ -377,6 +377,20 @@ impl SymbolTable { } Err(NoDefinition) } + + pub fn resolve_usable_by_fqn( + &self, + fqn: &str + ) -> Result { + todo!() + } + + pub fn resolve_usable_star( + &self, + base_fqn: &str, + ) -> Result<(), SymbolLookupError> { + todo!() + } } impl Display for SymbolTable { diff --git a/src/name_analysis/util.rs b/src/name_analysis/util.rs new file mode 100644 index 0000000..c835589 --- /dev/null +++ b/src/name_analysis/util.rs @@ -0,0 +1,11 @@ +use crate::ast::node::UseStatement; + +pub fn use_statement_base_fqn( + use_statement: &UseStatement +) -> String { + use_statement + .prefixes() + .map(|prefix| prefix.identifier().name()) + .collect::>() + .join("::") +} \ No newline at end of file