Various new ideas for name analysis.

This commit is contained in:
Jesse Brault 2025-10-20 18:31:54 -05:00
parent d32580a1d4
commit af8f0b5dac
14 changed files with 577 additions and 199 deletions

View File

@ -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,10 +10,10 @@ 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() {
Some(child) => match child.kind() {
EnumRuleChildKind::Node(node_child) => {
let child_ident = format_ident!("{}", node_child.node_kind().to_case(Case::Snake));
let child_ident =
format_ident!("{}", node_child.node_kind().to_case(Case::Snake));
quote! {
#type_ident::#rule_ident(#child_ident) => vec![
#child_ident
@ -22,8 +22,7 @@ pub fn make_enum_ast_node_impl(enum_spec: &TreeEnumBuildSpec) -> TokenStream {
}
_ => quote! {
#type_ident::#rule_ident(_) => vec![]
}
}
},
},
None => {
quote! {
@ -34,6 +33,34 @@ pub fn make_enum_ast_node_impl(enum_spec: &TreeEnumBuildSpec) -> TokenStream {
})
.collect::<Vec<_>>();
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::<Vec<_>>();
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)
}
}
}
}

View File

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

View File

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

View File

@ -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<TokenStream> {
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<TokenStream> {
fn make_type_ident(build_spec: &BuildSpec) -> Option<Ident> {
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<TokenStream> {
BuildSpec::Production(_) => None,
BuildSpec::NodeProduction(_) => None,
}
.map(|type_ident| {
}
pub fn make_ast_enum_member(build_spec: &BuildSpec) -> Option<TokenStream> {
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<TokenStream> {
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<TokenStream> {
match build_spec {
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::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| {
make_type_ident(build_spec).map(|type_ident| {
quote! {
AstNodeRef::#type_ident(inner) => *inner
}
})
}
pub fn make_ast_node_ref_mut_unwrapper(build_spec: &BuildSpec) -> Option<TokenStream> {
make_type_ident(build_spec).map(|type_ident| {
quote! {
AstNodeRefMut::#type_ident(inner) => *inner
}
})
}

View File

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

View File

@ -16,6 +16,19 @@ pub fn make_polymorphic_type_ast_node_impl(spec: &PolymorphicTypeBuildSpec) -> T
})
.collect::<Vec<_>>();
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::<Vec<_>>();
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)
}
}
}
}

View File

@ -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<TokenStream> {
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::<Vec<_>>();
.collect::<Vec<_>>()
}
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)
}
}
}
}

View File

@ -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::<Vec<_>>();
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::<Vec<_>>();
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::<Vec<_>>();
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::<Vec<_>>();
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)*

View File

@ -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<usize>,
symbol_types: &str,
diagnostics: &mut Vec<DmDiagnostic>,
) {
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<DmDiagnostic>,
) {
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<DmDiagnostic>,
) {
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
);
}
}
}
}

View File

@ -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<DmDiagnostic>,
) {
for child in node.children() {
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<DmDiagnostic>,
) {
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<DmDiagnostic>,
) {
@ -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<DmDiagnostic>,
@ -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<DmDiagnostic>,
@ -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<DmDiagnostic>,
@ -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<DmDiagnostic>,
@ -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<DmDiagnostic>,
@ -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<DmDiagnostic>,
@ -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<DmDiagnostic>,
@ -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<DmDiagnostic>,
@ -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<DmDiagnostic>,
@ -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<DmDiagnostic>,
@ -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<DmDiagnostic>,
@ -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<DmDiagnostic>,
@ -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<DmDiagnostic>,
@ -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<DmDiagnostic>,
@ -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<DmDiagnostic>,
@ -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<DmDiagnostic>,
) {
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<DmDiagnostic>,
) {
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<DmDiagnostic>,
) {
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<DmDiagnostic>,
@ -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<DmDiagnostic>,
) {
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<DmDiagnostic>,
@ -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);
}
}

View File

@ -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<CompilationUnit>],
compilation_units: &mut Vec<Box<CompilationUnit>>,
files: &'a F,
symbol_table: &mut SymbolTable,
) -> Vec<DmDiagnostic> {
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

View File

@ -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<usize>,
symbol_types: &str,
diagnostics: &mut Vec<DmDiagnostic>,
) {
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<DmDiagnostic>,
) {
// 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<DmDiagnostic>,
) {
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);
}
}
}
}

View File

@ -377,6 +377,20 @@ impl SymbolTable {
}
Err(NoDefinition)
}
pub fn resolve_usable_by_fqn(
&self,
fqn: &str
) -> Result<Symbol, SymbolLookupError> {
todo!()
}
pub fn resolve_usable_star(
&self,
base_fqn: &str,
) -> Result<(), SymbolLookupError> {
todo!()
}
}
impl Display for SymbolTable {

11
src/name_analysis/util.rs Normal file
View File

@ -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::<Vec<_>>()
.join("::")
}