WIP on name-analysis gather.

This commit is contained in:
Jesse Brault 2025-10-05 12:19:59 -05:00
parent 36e28ae4a9
commit d5ac6dfc2d
6 changed files with 384 additions and 211 deletions

View File

@ -1,4 +1,4 @@
pub(super) struct FqnContext {
pub struct FqnContext {
stack: Vec<String>,
}

View File

@ -1,16 +1,20 @@
use crate::ast::ast_node::{AstNode, AstNodeRef};
use crate::ast::node::{
CompilationUnit, Function, FunctionBlockBody, FunctionBody, Identifier, Statement,
UseStatement, UseStatementSuffix, VariableDeclaration,
Class, CompilationUnit, Function, FunctionBlockBody, FunctionBody, Identifier, Interface,
Module, Namespace, Statement, UseStatement, UseStatementSuffix, VariableDeclaration,
};
use crate::diagnostic::DmDiagnostic;
use crate::name_analysis::fqn_context::FqnContext;
use crate::name_analysis::symbol::function_symbol::FunctionSymbol;
use crate::name_analysis::symbol::module_symbol::ModuleSymbol;
use crate::name_analysis::symbol::source_definition::SourceDefinition;
use crate::name_analysis::symbol::type_symbol::{
ConcreteTypeSymbol, ConcreteTypeSymbolKind, TypeSymbol,
};
use crate::name_analysis::symbol::use_symbol::{ConcreteUseSymbol, StarUseSymbol};
use crate::name_analysis::symbol::variable_symbol::VariableSymbol;
use crate::name_analysis::symbol_table::{SymbolInsertError, SymbolTable};
use codespan_reporting::diagnostic::{Diagnostic, Label};
use std::collections::HashMap;
use std::range::Range;
fn handle_insert_error(
@ -45,165 +49,28 @@ fn handle_insert_error(
}
}
fn gather_identifier(
identifier: &Identifier,
symbol_table: &SymbolTable,
identifier_scope_ids: &mut HashMap<Identifier, usize>,
) {
identifier_scope_ids.insert(identifier.clone(), symbol_table.current_scope_id());
}
fn gather_concrete_use_symbol(
base_fqn: &str,
identifier: &Identifier,
symbol_table: &mut SymbolTable,
diagnostics: &mut Vec<DmDiagnostic>,
) {
let symbol = ConcreteUseSymbol::new(
base_fqn,
identifier.name(),
Some(SourceDefinition::from_identifier(identifier)),
);
if let Err(insert_error) = symbol_table.insert_concrete_use_symbol(symbol) {
handle_insert_error(
insert_error,
&base_fqn,
identifier.file_id(),
identifier.range(),
"Use Statement",
diagnostics,
);
}
}
fn gather_use_statement(
use_statement: &UseStatement,
symbol_table: &mut SymbolTable,
diagnostics: &mut Vec<DmDiagnostic>,
) {
let base_fqn = use_statement
.prefixes()
.map(|prefix| prefix.identifier().name())
.collect::<Vec<_>>()
.join("::");
match use_statement.suffix() {
UseStatementSuffix::Identifier(identifier) => {
gather_concrete_use_symbol(&base_fqn, identifier, symbol_table, diagnostics);
}
UseStatementSuffix::Star => {
let symbol = StarUseSymbol::new(
&base_fqn,
Some(SourceDefinition::from_use_statement(use_statement)),
);
let insert_result = symbol_table.insert_star_use_symbol(symbol);
if let Err(error) = insert_result {
handle_insert_error(
error,
&base_fqn,
use_statement.file_id(),
use_statement.range(),
"Use Statement",
diagnostics,
);
}
}
UseStatementSuffix::UseList(use_list) => {
for identifier in use_list.identifiers() {
gather_concrete_use_symbol(&base_fqn, identifier, symbol_table, diagnostics);
}
}
}
}
fn gather_function(
function: &Function,
symbol_table: &mut SymbolTable,
diagnostics: &mut Vec<DmDiagnostic>,
) {
let function_symbol = FunctionSymbol::without_parameters_or_return_type(
"",
function.identifier().name(),
function.is_public(),
false,
Some(SourceDefinition::from_identifier(function.identifier())),
);
if let Err(insert_error) = symbol_table.insert_function_symbol(function_symbol) {
handle_insert_error(
insert_error,
function.identifier().name(),
function.identifier().file_id(),
function.identifier().range(),
"Function",
diagnostics,
);
}
gather_node(
AstNodeRef::FunctionBody(function.function_body()),
symbol_table,
diagnostics,
);
}
fn gather_function_block_body(
function_block_body: &FunctionBlockBody,
symbol_table: &mut SymbolTable,
diagnostics: &mut Vec<DmDiagnostic>,
) {
symbol_table.push_scope("FunctionBlockBody");
gather_node_children(function_block_body, symbol_table, diagnostics);
symbol_table.pop_scope();
}
fn gather_variable_declaration(
variable_declaration: &VariableDeclaration,
symbol_table: &mut SymbolTable,
diagnostics: &mut Vec<DmDiagnostic>,
) {
let variable_symbol = VariableSymbol::new(
variable_declaration.identifier().name(),
variable_declaration.is_mut(),
Some(SourceDefinition::from_identifier(
variable_declaration.identifier(),
)),
);
if let Err(insert_error) = symbol_table.insert_variable_symbol(variable_symbol) {
handle_insert_error(
insert_error,
variable_declaration.identifier().name(),
variable_declaration.identifier().file_id(),
variable_declaration.identifier().range(),
"Variable",
diagnostics,
);
}
if let Some(expression) = variable_declaration.expression() {
gather_node(
AstNodeRef::Expression(expression),
symbol_table,
diagnostics,
);
}
}
fn gather_node_children(
node: &impl AstNode,
symbol_table: &mut SymbolTable,
fqn_context: &mut FqnContext,
diagnostics: &mut Vec<DmDiagnostic>,
) {
for child in node.children() {
gather_node(child, symbol_table, diagnostics);
gather_node(child, symbol_table, fqn_context, diagnostics);
}
}
fn gather_node(
node: AstNodeRef,
symbol_table: &mut SymbolTable,
fqn_context: &mut FqnContext,
diagnostics: &mut Vec<DmDiagnostic>,
) {
match node {
AstNodeRef::Operator(_) => {}
AstNodeRef::Identifier(_) => {}
AstNodeRef::Identifier(_) => {
unreachable!()
}
AstNodeRef::FullyQualifiedName(_) => {}
AstNodeRef::TypeUseList(_) => {}
AstNodeRef::IdentifierList(_) => {}
@ -222,26 +89,58 @@ fn gather_node(
AstNodeRef::Parameter(_) => {}
AstNodeRef::ReturnType(_) => {}
AstNodeRef::CompilationUnit(compilation_unit) => {
gather_node_children(compilation_unit, symbol_table, diagnostics);
gather_node_children(compilation_unit, symbol_table, fqn_context, diagnostics);
}
AstNodeRef::Namespace(namespace) => {
gather_namespace(namespace, fqn_context);
}
AstNodeRef::ParentMod(_) => {}
AstNodeRef::UseStatement(use_statement) => {
gather_use_statement(use_statement, symbol_table, diagnostics);
}
AstNodeRef::UseStatementPrefix(_) => {}
AstNodeRef::UseStatementSuffix(_) => {}
AstNodeRef::UseList(_) => {}
AstNodeRef::ModuleLevelDeclaration(module_level_declaration) => {
gather_node_children(module_level_declaration, symbol_table, diagnostics);
AstNodeRef::UseStatementPrefix(_) => {
unreachable!()
}
AstNodeRef::UseStatementSuffix(_) => {
unreachable!()
}
AstNodeRef::UseList(_) => {
unreachable!()
}
AstNodeRef::ModuleLevelDeclaration(module_level_declaration) => {
gather_node_children(
module_level_declaration,
symbol_table,
fqn_context,
diagnostics,
);
}
AstNodeRef::InterfaceLevelDeclaration(interface_level_declaration) => {
gather_node_children(
interface_level_declaration,
symbol_table,
fqn_context,
diagnostics,
);
}
AstNodeRef::ClassLevelDeclaration(class_level_declaration) => {
gather_node_children(
class_level_declaration,
symbol_table,
fqn_context,
diagnostics,
);
}
AstNodeRef::Module(module) => {
gather_module(module, symbol_table, fqn_context, diagnostics);
}
AstNodeRef::Interface(interface) => {
gather_interface(interface, symbol_table, fqn_context, diagnostics);
}
AstNodeRef::Class(class) => {
gather_class(class, symbol_table, fqn_context, diagnostics);
}
AstNodeRef::InterfaceLevelDeclaration(_) => {}
AstNodeRef::ClassLevelDeclaration(_) => {}
AstNodeRef::Module(_) => {}
AstNodeRef::CompanionModule(_) => {}
AstNodeRef::Interface(_) => {}
AstNodeRef::Class(_) => {}
AstNodeRef::Function(function) => {
gather_function(function, symbol_table, diagnostics);
gather_function(function, symbol_table, fqn_context, diagnostics);
}
AstNodeRef::OperatorFunction(_) => {}
AstNodeRef::PlatformFunction(_) => {}
@ -251,25 +150,45 @@ fn gather_node(
AstNodeRef::InterfaceDefaultOperatorFunction(_) => {}
AstNodeRef::FunctionBody(function_body) => match function_body {
FunctionBody::FunctionAliasBody(alias_body) => {
gather_node(alias_body.as_node_ref(), symbol_table, diagnostics);
gather_node(
alias_body.as_node_ref(),
symbol_table,
fqn_context,
diagnostics,
);
}
FunctionBody::FunctionEqualsBody(equals_body) => {
gather_node(equals_body.as_node_ref(), symbol_table, diagnostics);
gather_node(
equals_body.as_node_ref(),
symbol_table,
fqn_context,
diagnostics,
);
}
FunctionBody::FunctionBlockBody(block_body) => {
gather_node(block_body.as_node_ref(), symbol_table, diagnostics);
gather_node(
block_body.as_node_ref(),
symbol_table,
fqn_context,
diagnostics,
);
}
},
AstNodeRef::FunctionEqualsBody(_) => {}
AstNodeRef::FunctionAliasBody(_) => {}
AstNodeRef::FunctionBlockBody(block_body) => {
gather_function_block_body(block_body, symbol_table, diagnostics);
gather_function_block_body(block_body, symbol_table, fqn_context, diagnostics);
}
AstNodeRef::ClassConstructor(_) => {}
AstNodeRef::Member(_) => {}
AstNodeRef::Statement(statement) => match statement {
Statement::VariableDeclaration(variable_declaration) => {
gather_variable_declaration(variable_declaration, symbol_table, diagnostics);
gather_node(
variable_declaration.as_node_ref(),
symbol_table,
fqn_context,
diagnostics,
);
}
Statement::AssignmentStatement(_) => {}
Statement::ExpressionStatement(_) => {}
@ -332,10 +251,282 @@ pub fn gather_compilation_unit(
compilation_unit: &mut CompilationUnit,
file_name: &str,
symbol_table: &mut SymbolTable,
identifier_scope_ids: &mut HashMap<Identifier, usize>,
diagnostics: &mut Vec<DmDiagnostic>,
) {
let mut fqn_context = FqnContext::new();
symbol_table.push_scope(&format!("FileScope {}", file_name));
gather_node(compilation_unit.as_node_ref(), symbol_table, diagnostics);
gather_node(
compilation_unit.as_node_ref(),
symbol_table,
&mut fqn_context,
diagnostics,
);
symbol_table.pop_scope();
}
fn gather_namespace(namespace: &Namespace, fqn_context: &mut FqnContext) {
for identifier in namespace.fqn().identifiers() {
fqn_context.push(identifier.name());
}
}
fn gather_use_statement(
use_statement: &UseStatement,
symbol_table: &mut SymbolTable,
diagnostics: &mut Vec<DmDiagnostic>,
) {
let base_fqn = use_statement
.prefixes()
.map(|prefix| prefix.identifier().name())
.collect::<Vec<_>>()
.join("::");
match use_statement.suffix() {
UseStatementSuffix::Identifier(identifier) => {
gather_concrete_use_symbol(&base_fqn, identifier, symbol_table, diagnostics);
}
UseStatementSuffix::Star => {
let symbol = StarUseSymbol::new(
&base_fqn,
Some(SourceDefinition::from_use_statement(use_statement)),
);
let insert_result = symbol_table.insert_star_use_symbol(symbol);
if let Err(error) = insert_result {
handle_insert_error(
error,
&base_fqn,
use_statement.file_id(),
use_statement.range(),
"Use Statement",
diagnostics,
);
}
}
UseStatementSuffix::UseList(use_list) => {
for identifier in use_list.identifiers() {
gather_concrete_use_symbol(&base_fqn, identifier, symbol_table, diagnostics);
}
}
}
}
fn gather_concrete_use_symbol(
base_fqn: &str,
identifier: &Identifier,
symbol_table: &mut SymbolTable,
diagnostics: &mut Vec<DmDiagnostic>,
) {
let symbol = ConcreteUseSymbol::new(
base_fqn,
identifier.name(),
Some(SourceDefinition::from_identifier(identifier)),
);
if let Err(insert_error) = symbol_table.insert_concrete_use_symbol(symbol) {
handle_insert_error(
insert_error,
&base_fqn,
identifier.file_id(),
identifier.range(),
"Use Statement",
diagnostics,
);
}
}
fn gather_module(
module: &Module,
symbol_table: &mut SymbolTable,
fqn_context: &mut FqnContext,
diagnostics: &mut Vec<DmDiagnostic>,
) {
let module_symbol = ModuleSymbol::new(
&fqn_context.resolve(module.identifier().name()),
module.identifier().name(),
module.is_public(),
Some(SourceDefinition::from_identifier(module.identifier())),
);
if let Err(symbol_insert_error) = symbol_table.insert_module_symbol(module_symbol) {
handle_insert_error(
symbol_insert_error,
module.identifier().name(),
module.identifier().file_id(),
module.identifier().range(),
"Module",
diagnostics,
);
}
fqn_context.push(module.identifier().name());
symbol_table.push_scope(&format!("ModuleScope {}", module.identifier().name()));
for declaration in module.declarations() {
gather_node(
declaration.as_node_ref(),
symbol_table,
fqn_context,
diagnostics,
);
}
symbol_table.pop_scope();
fqn_context.pop();
}
fn gather_interface(
interface: &Interface,
symbol_table: &mut SymbolTable,
fqn_context: &mut FqnContext,
diagnostics: &mut Vec<DmDiagnostic>,
) {
let type_symbol = ConcreteTypeSymbol::new(
&fqn_context.resolve(interface.identifier().name()),
interface.identifier().name(),
interface.is_public(),
ConcreteTypeSymbolKind::Interface,
Some(SourceDefinition::from_identifier(interface.identifier())),
);
if let Err(symbol_insert_error) =
symbol_table.insert_type_symbol(TypeSymbol::Concrete(type_symbol))
{
handle_insert_error(
symbol_insert_error,
interface.identifier().name(),
interface.identifier().file_id(),
interface.identifier().range(),
"Interface",
diagnostics,
);
}
fqn_context.push(interface.identifier().name());
symbol_table.push_scope(&format!("InterfaceScope {}", interface.identifier().name()));
for declaration in interface.declarations() {
gather_node(
declaration.as_node_ref(),
symbol_table,
fqn_context,
diagnostics,
);
}
symbol_table.pop_scope();
fqn_context.pop();
}
fn gather_class(
class: &Class,
symbol_table: &mut SymbolTable,
fqn_context: &mut FqnContext,
diagnostics: &mut Vec<DmDiagnostic>,
) {
let class_symbol = ConcreteTypeSymbol::new(
&fqn_context.resolve(class.identifier().name()),
class.identifier().name(),
class.is_public(),
ConcreteTypeSymbolKind::Class,
Some(SourceDefinition::from_identifier(class.identifier())),
);
if let Err(symbol_insert_error) =
symbol_table.insert_type_symbol(TypeSymbol::Concrete(class_symbol))
{
handle_insert_error(
symbol_insert_error,
class.identifier().name(),
class.identifier().file_id(),
class.identifier().range(),
"Class",
diagnostics,
);
}
fqn_context.push(class.identifier().name());
symbol_table.push_scope(&format!("ClassScope {}", class.identifier().name()));
for declaration in class.class_level_declarations() {
gather_node(
declaration.as_node_ref(),
symbol_table,
fqn_context,
diagnostics,
);
}
symbol_table.pop_scope();
fqn_context.pop();
}
fn gather_function(
function: &Function,
symbol_table: &mut SymbolTable,
fqn_context: &mut FqnContext,
diagnostics: &mut Vec<DmDiagnostic>,
) {
let function_symbol = FunctionSymbol::without_parameters_or_return_type(
&fqn_context.resolve(function.identifier().name()),
function.identifier().name(),
function.is_public(),
false,
Some(SourceDefinition::from_identifier(function.identifier())),
);
if let Err(insert_error) = symbol_table.insert_function_symbol(function_symbol) {
handle_insert_error(
insert_error,
function.identifier().name(),
function.identifier().file_id(),
function.identifier().range(),
"Function",
diagnostics,
);
}
gather_node(
function.function_body().as_node_ref(),
symbol_table,
fqn_context,
diagnostics,
);
}
fn gather_function_block_body(
function_block_body: &FunctionBlockBody,
symbol_table: &mut SymbolTable,
fqn_context: &mut FqnContext,
diagnostics: &mut Vec<DmDiagnostic>,
) {
symbol_table.push_scope("FunctionBlockBody");
gather_node_children(function_block_body, symbol_table, fqn_context, diagnostics);
symbol_table.pop_scope();
}
fn gather_variable_declaration(
variable_declaration: &VariableDeclaration,
symbol_table: &mut SymbolTable,
fqn_context: &mut FqnContext,
diagnostics: &mut Vec<DmDiagnostic>,
) {
let variable_symbol = VariableSymbol::new(
variable_declaration.identifier().name(),
variable_declaration.is_mut(),
Some(SourceDefinition::from_identifier(
variable_declaration.identifier(),
)),
);
if let Err(insert_error) = symbol_table.insert_variable_symbol(variable_symbol) {
handle_insert_error(
insert_error,
variable_declaration.identifier().name(),
variable_declaration.identifier().file_id(),
variable_declaration.identifier().range(),
"Variable",
diagnostics,
);
}
if let Some(expression) = variable_declaration.expression() {
gather_node(
expression.as_node_ref(),
symbol_table,
fqn_context,
diagnostics,
);
}
}

View File

@ -27,7 +27,7 @@ use crate::name_analysis::symbol_table::SymbolTable;
use codespan_reporting::files::Files;
use std::collections::HashMap;
mod fqn_context;
pub(self) mod fqn_context;
mod gather;
// mod resolve;
pub mod symbol;
@ -44,13 +44,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();
gather_compilation_unit(
compilation_unit,
&file_name,
symbol_table,
&mut identifier_scope_ids,
&mut diagnostics,
);
gather_compilation_unit(compilation_unit, &file_name, symbol_table, &mut diagnostics);
}
// resolve symbols

View File

@ -28,6 +28,7 @@ pub struct ConcreteTypeSymbol {
fqn: String,
declared_name: String,
is_public: bool,
kind: ConcreteTypeSymbolKind,
source_definition: Option<SourceDefinition>,
}
@ -36,12 +37,14 @@ impl ConcreteTypeSymbol {
fqn: &str,
declared_name: &str,
is_public: bool,
kind: ConcreteTypeSymbolKind,
source_definition: Option<SourceDefinition>,
) -> Self {
Self {
fqn: fqn.to_string(),
declared_name: declared_name.to_string(),
is_public,
kind,
source_definition
}
}
@ -54,6 +57,10 @@ impl ConcreteTypeSymbol {
self.is_public
}
pub fn kind(&self) -> &ConcreteTypeSymbolKind {
&self.kind
}
pub fn declared_name(&self) -> &str {
&self.declared_name
}
@ -69,11 +76,18 @@ impl Debug for ConcreteTypeSymbol {
.field("fqn", &self.fqn)
.field("declared_name", &self.declared_name)
.field("is_public", &self.is_public)
.field("kind", &self.kind)
.field("source_definition", &self.source_definition)
.finish()
}
}
#[derive(Clone, Debug)]
pub enum ConcreteTypeSymbolKind {
Interface,
Class
}
#[derive(Clone)]
pub struct GenericTypeSymbol {
declared_name: String,

View File

@ -181,7 +181,7 @@ ReturnType:
CompilationUnit:
struct:
children:
- parent_mod:
- namespace:
member:
optional: true
- use_statements:
@ -196,12 +196,12 @@ CompilationUnit:
- file_id:
special:
kind: file_id
ParentMod:
Namespace:
struct:
children:
- mod_kw:
- ns_kw:
skip:
rule: Mod
rule: Ns
- fqn:
member:
rule: FullyQualifiedName
@ -253,7 +253,6 @@ ModuleLevelDeclaration:
InterfaceLevelDeclaration:
tree_enum:
rules:
- CompanionModule
- Interface
- Class
- InterfaceFunction
@ -263,7 +262,6 @@ InterfaceLevelDeclaration:
ClassLevelDeclaration:
tree_enum:
rules:
- CompanionModule
- Interface
- Class
- Function
@ -290,21 +288,6 @@ Module:
- end_kw:
skip:
rule: End
CompanionModule:
struct:
children:
- companion_kw:
skip:
rule: Companion
- mod_kw:
skip:
rule: Mod
- declarations:
vec:
rule: ModuleLevelDeclaration
- end_kw:
skip:
rule: End
Interface:
struct:
children:

View File

@ -307,13 +307,13 @@ ReturnType = {
CompilationUnit = {
SOI
~ ParentMod?
~ Namespace?
~ ( UseStatement | ModuleLevelDeclaration )*
~ EOI
}
ParentMod = {
Mod
Namespace = {
Ns
~ FullyQualifiedName
}
@ -352,8 +352,7 @@ ModuleLevelDeclaration = {
}
InterfaceLevelDeclaration = {
CompanionModule
| Interface
Interface
| Class
| InterfaceFunction
| InterfaceDefaultFunction
@ -362,8 +361,7 @@ InterfaceLevelDeclaration = {
}
ClassLevelDeclaration = {
CompanionModule
| Interface
Interface
| Class
| Function
| OperatorFunction
@ -380,13 +378,6 @@ Module = {
~ End
}
CompanionModule = {
Companion
~ Mod
~ ModuleLevelDeclaration*
~ End
}
Interface = {
Pub?
~ IntKw