WIP never ending name analysis.
This commit is contained in:
parent
664aebfd61
commit
93c6a71185
@ -116,7 +116,7 @@ fn generate_node_file(build_specs: &[BuildSpec]) -> AstGeneratedFile {
|
|||||||
use std::range::Range;
|
use std::range::Range;
|
||||||
use std::rc::Rc;
|
use std::rc::Rc;
|
||||||
use std::cell::RefCell;
|
use std::cell::RefCell;
|
||||||
use crate::name_analysis::symbol::use_symbol::UseSymbol;
|
use crate::name_analysis::symbol::use_symbol::*;
|
||||||
|
|
||||||
#(#types)*
|
#(#types)*
|
||||||
};
|
};
|
||||||
|
|||||||
@ -3,12 +3,12 @@ use codespan_reporting::term;
|
|||||||
use codespan_reporting::term::termcolor::{ColorChoice, StandardStream};
|
use codespan_reporting::term::termcolor::{ColorChoice, StandardStream};
|
||||||
use deimos::ast::build::build_ast;
|
use deimos::ast::build::build_ast;
|
||||||
use deimos::name_analysis::analyze_names;
|
use deimos::name_analysis::analyze_names;
|
||||||
|
use deimos::name_analysis::symbol_table::symbol_tree::SymbolTree;
|
||||||
use deimos::name_analysis::symbol_table::SymbolTable;
|
use deimos::name_analysis::symbol_table::SymbolTable;
|
||||||
use deimos::parser::{DeimosParser, Rule};
|
use deimos::parser::{DeimosParser, Rule};
|
||||||
use deimos::std_core::add_std_core_symbols;
|
use deimos::std_core::add_std_core_symbols;
|
||||||
use pest::Parser;
|
use pest::Parser;
|
||||||
use std::path::PathBuf;
|
use std::path::PathBuf;
|
||||||
use deimos::name_analysis::symbol_tree::SymbolTree;
|
|
||||||
|
|
||||||
pub fn name_analysis(paths: &Vec<PathBuf>) -> Result<(), Box<dyn std::error::Error>> {
|
pub fn name_analysis(paths: &Vec<PathBuf>) -> Result<(), Box<dyn std::error::Error>> {
|
||||||
let mut compilation_units = vec![];
|
let mut compilation_units = vec![];
|
||||||
@ -30,10 +30,13 @@ pub fn name_analysis(paths: &Vec<PathBuf>) -> Result<(), Box<dyn std::error::Err
|
|||||||
}
|
}
|
||||||
|
|
||||||
let mut symbol_table = SymbolTable::new();
|
let mut symbol_table = SymbolTable::new();
|
||||||
let mut symbol_tree = SymbolTree::new();
|
|
||||||
add_std_core_symbols(&mut symbol_table).expect("Failed to add std::core symbols.");
|
add_std_core_symbols(&mut symbol_table).expect("Failed to add std::core symbols.");
|
||||||
|
|
||||||
let diagnostics = analyze_names(&mut compilation_units, &files, &mut symbol_table, &mut symbol_tree);
|
let diagnostics = analyze_names(
|
||||||
|
&mut compilation_units,
|
||||||
|
&files,
|
||||||
|
&mut symbol_table,
|
||||||
|
);
|
||||||
if diagnostics.is_empty() {
|
if diagnostics.is_empty() {
|
||||||
println!("Name analysis complete.");
|
println!("Name analysis complete.");
|
||||||
println!("{}", symbol_table);
|
println!("{}", symbol_table);
|
||||||
|
|||||||
@ -1,136 +1,119 @@
|
|||||||
use crate::ast::node::{CompilationUnit, Identifier, UseStatement, UseStatementSuffix};
|
use crate::ast::node::{
|
||||||
|
CompilationUnit, ConcreteUseStatement, ConcreteUseStatementSuffix, Identifier, UseStatement,
|
||||||
|
UseStatementIdentifier, UseStatementPrefix,
|
||||||
|
};
|
||||||
use crate::diagnostic::DmDiagnostic;
|
use crate::diagnostic::DmDiagnostic;
|
||||||
use crate::name_analysis::fqn_context::FqnContext;
|
|
||||||
use crate::name_analysis::symbol::source_definition::SourceDefinition;
|
use crate::name_analysis::symbol::source_definition::SourceDefinition;
|
||||||
use crate::name_analysis::symbol::use_symbol::{ConcreteUseSymbol, StarUseSymbol, UseSymbol};
|
use crate::name_analysis::symbol::use_symbol::ConcreteUseSymbol;
|
||||||
use crate::name_analysis::symbol_table::SymbolTable;
|
use crate::name_analysis::symbol_table::SymbolTable;
|
||||||
use crate::name_analysis::symbol_tree::SymbolTree;
|
use crate::name_analysis::util::handle_insert_error;
|
||||||
use crate::name_analysis::util;
|
|
||||||
use crate::name_analysis::util::{handle_insert_error, use_statement_base_fqn};
|
|
||||||
use std::cell::RefCell;
|
|
||||||
use std::rc::Rc;
|
|
||||||
|
|
||||||
macro_rules! insert_symbol {
|
pub fn na_p1_compilation_unit(
|
||||||
($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) {
|
|
||||||
util::handle_insert_error(
|
|
||||||
insert_error,
|
|
||||||
$name,
|
|
||||||
$node.file_id(),
|
|
||||||
$node.range(),
|
|
||||||
$symbol_kinds,
|
|
||||||
$diagnostics,
|
|
||||||
)
|
|
||||||
}
|
|
||||||
};
|
|
||||||
}
|
|
||||||
|
|
||||||
pub fn nap1_compilation_unit(
|
|
||||||
file_name: &str,
|
file_name: &str,
|
||||||
compilation_unit: &mut CompilationUnit,
|
compilation_unit: &mut CompilationUnit,
|
||||||
symbol_table: &mut SymbolTable,
|
symbol_table: &mut SymbolTable,
|
||||||
symbol_tree: &mut SymbolTree,
|
|
||||||
diagnostics: &mut Vec<DmDiagnostic>,
|
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() {
|
if let Some(namespace) = compilation_unit.namespace() {
|
||||||
for identifier in namespace.fqn().identifiers() {
|
symbol_table.set_current_fqn(
|
||||||
fqn_context.push(identifier.name());
|
&namespace
|
||||||
}
|
.fqn()
|
||||||
|
.identifiers()
|
||||||
|
.map(Identifier::name)
|
||||||
|
.collect::<Vec<_>>(),
|
||||||
|
);
|
||||||
}
|
}
|
||||||
|
|
||||||
|
symbol_table.push_scope(&format!("FileScope {}", file_name));
|
||||||
|
|
||||||
for use_statement in compilation_unit.use_statements_mut() {
|
for use_statement in compilation_unit.use_statements_mut() {
|
||||||
nap1_use_statement(use_statement, symbol_table, diagnostics);
|
na_p1_use_statement(use_statement, symbol_table, diagnostics);
|
||||||
}
|
}
|
||||||
|
|
||||||
symbol_table.pop_scope();
|
symbol_table.pop_scope();
|
||||||
}
|
}
|
||||||
|
|
||||||
fn maybe_insert_concrete_use_symbol(
|
fn na_p1_use_statement(
|
||||||
use_statement: &UseStatement,
|
|
||||||
identifier: &Identifier,
|
|
||||||
symbol_table: &mut SymbolTable,
|
|
||||||
diagnostics: &mut Vec<DmDiagnostic>,
|
|
||||||
) -> Option<Rc<RefCell<ConcreteUseSymbol>>> {
|
|
||||||
let base_fqn = use_statement_base_fqn(use_statement);
|
|
||||||
let to_insert = ConcreteUseSymbol::new(
|
|
||||||
&base_fqn,
|
|
||||||
identifier.name(),
|
|
||||||
Some(SourceDefinition::from_identifier(identifier)),
|
|
||||||
);
|
|
||||||
match symbol_table.insert_concrete_use_symbol(to_insert) {
|
|
||||||
Ok(inserted) => Some(inserted),
|
|
||||||
Err(insert_error) => {
|
|
||||||
handle_insert_error(
|
|
||||||
insert_error,
|
|
||||||
identifier.name(),
|
|
||||||
identifier.file_id(),
|
|
||||||
identifier.range(),
|
|
||||||
"Use Symbol",
|
|
||||||
diagnostics,
|
|
||||||
);
|
|
||||||
None
|
|
||||||
}
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
fn nap1_use_statement(
|
|
||||||
use_statement: &mut UseStatement,
|
use_statement: &mut UseStatement,
|
||||||
symbol_table: &mut SymbolTable,
|
symbol_table: &mut SymbolTable,
|
||||||
diagnostics: &mut Vec<DmDiagnostic>,
|
diagnostics: &mut Vec<DmDiagnostic>,
|
||||||
) {
|
) {
|
||||||
let base_fqn = use_statement_base_fqn(use_statement);
|
match use_statement {
|
||||||
|
UseStatement::ConcreteUseStatement(concrete_use_statement) => {
|
||||||
|
na_p1_concrete_use_statement(concrete_use_statement, symbol_table, diagnostics);
|
||||||
|
}
|
||||||
|
UseStatement::StarUseStatement(star_use_statement) => {
|
||||||
|
todo!()
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
match use_statement.suffix() {
|
fn na_p1_concrete_use_statement(
|
||||||
UseStatementSuffix::Identifier(identifier) => {
|
concrete_use_statement: &mut ConcreteUseStatement,
|
||||||
let maybe_symbol = maybe_insert_concrete_use_symbol(
|
symbol_table: &mut SymbolTable,
|
||||||
use_statement,
|
diagnostics: &mut Vec<DmDiagnostic>,
|
||||||
&identifier,
|
) {
|
||||||
|
let prefixes: Vec<String> = concrete_use_statement
|
||||||
|
.prefixes()
|
||||||
|
.map(UseStatementPrefix::identifier)
|
||||||
|
.map(Identifier::name)
|
||||||
|
.map(ToString::to_string)
|
||||||
|
.collect::<Vec<_>>();
|
||||||
|
|
||||||
|
match concrete_use_statement.suffix_mut() {
|
||||||
|
ConcreteUseStatementSuffix::UseStatementIdentifier(use_statement_identifier) => {
|
||||||
|
handle_concrete_use_statement_identifier(
|
||||||
|
&prefixes,
|
||||||
|
use_statement_identifier,
|
||||||
symbol_table,
|
symbol_table,
|
||||||
diagnostics,
|
diagnostics,
|
||||||
);
|
);
|
||||||
if let Some(concrete_use_symbol) = maybe_symbol {
|
|
||||||
use_statement.use_symbols_mut().push(UseSymbol::Concrete(concrete_use_symbol));
|
|
||||||
}
|
|
||||||
}
|
}
|
||||||
UseStatementSuffix::Star => {
|
ConcreteUseStatementSuffix::UseList(use_list) => {
|
||||||
let maybe_symbol = match symbol_table.insert_star_use_symbol(
|
for use_statement_identifier in use_list.identifiers_mut() {
|
||||||
StarUseSymbol::new(&base_fqn, Some(SourceDefinition::from_use_statement(use_statement)))
|
handle_concrete_use_statement_identifier(
|
||||||
) {
|
&prefixes,
|
||||||
Ok(inserted) => {
|
use_statement_identifier,
|
||||||
Some(todo!())
|
symbol_table,
|
||||||
},
|
diagnostics,
|
||||||
Err(insert_error) => {
|
);
|
||||||
handle_insert_error(
|
|
||||||
insert_error,
|
|
||||||
&base_fqn,
|
|
||||||
use_statement.file_id(),
|
|
||||||
use_statement.range(),
|
|
||||||
"Star Use Symbol",
|
|
||||||
diagnostics,
|
|
||||||
);
|
|
||||||
None
|
|
||||||
}
|
|
||||||
};
|
|
||||||
}
|
|
||||||
UseStatementSuffix::UseList(use_list) => {
|
|
||||||
let maybe_symbols = use_list.identifiers()
|
|
||||||
.map(|identifier| {
|
|
||||||
maybe_insert_concrete_use_symbol(
|
|
||||||
use_statement,
|
|
||||||
identifier,
|
|
||||||
symbol_table,
|
|
||||||
diagnostics,
|
|
||||||
)
|
|
||||||
})
|
|
||||||
.collect::<Vec<_>>();
|
|
||||||
for maybe_symbol in maybe_symbols {
|
|
||||||
if let Some(symbol) = maybe_symbol {
|
|
||||||
use_statement.use_symbols_mut().push(UseSymbol::Concrete(symbol));
|
|
||||||
}
|
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
fn handle_concrete_use_statement_identifier(
|
||||||
|
prefixes: &Vec<String>,
|
||||||
|
use_statement_identifier: &mut UseStatementIdentifier,
|
||||||
|
symbol_table: &mut SymbolTable,
|
||||||
|
diagnostics: &mut Vec<DmDiagnostic>,
|
||||||
|
) {
|
||||||
|
let mut fqn_parts: Vec<&str> = vec![];
|
||||||
|
for prefix in prefixes {
|
||||||
|
fqn_parts.push(prefix);
|
||||||
|
}
|
||||||
|
fqn_parts.push(use_statement_identifier.identifier().name());
|
||||||
|
|
||||||
|
let to_insert = ConcreteUseSymbol::new(
|
||||||
|
&fqn_parts,
|
||||||
|
Some(SourceDefinition::from_identifier(
|
||||||
|
use_statement_identifier.identifier(),
|
||||||
|
)),
|
||||||
|
);
|
||||||
|
|
||||||
|
match symbol_table.insert_concrete_use_symbol(to_insert) {
|
||||||
|
Ok(inserted) => {
|
||||||
|
use_statement_identifier.set_symbol(inserted);
|
||||||
|
}
|
||||||
|
Err(insert_error) => {
|
||||||
|
handle_insert_error(
|
||||||
|
insert_error,
|
||||||
|
use_statement_identifier.identifier().name(),
|
||||||
|
use_statement_identifier.identifier().file_id(),
|
||||||
|
use_statement_identifier.identifier().range(),
|
||||||
|
"Use Symbol",
|
||||||
|
diagnostics,
|
||||||
|
);
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|||||||
@ -23,40 +23,36 @@ The resolve phase has one main responsibility: resolve all references based on t
|
|||||||
use crate::ast::ast_node::AstNode;
|
use crate::ast::ast_node::AstNode;
|
||||||
use crate::ast::node::CompilationUnit;
|
use crate::ast::node::CompilationUnit;
|
||||||
use crate::diagnostic::DmDiagnostic;
|
use crate::diagnostic::DmDiagnostic;
|
||||||
use crate::name_analysis::first_pass::nap1_compilation_unit;
|
use crate::name_analysis::first_pass::na_p1_compilation_unit;
|
||||||
use crate::name_analysis::second_pass::nap2_compilation_unit;
|
use crate::name_analysis::second_pass::na_p2_compilation_unit;
|
||||||
use crate::name_analysis::symbol_table::SymbolTable;
|
use crate::name_analysis::symbol_table::SymbolTable;
|
||||||
use codespan_reporting::files::Files;
|
use codespan_reporting::files::Files;
|
||||||
use std::hash::Hash;
|
use std::hash::Hash;
|
||||||
use crate::name_analysis::symbol_tree::SymbolTree;
|
|
||||||
|
|
||||||
pub(self) mod fqn_context;
|
|
||||||
// mod resolve;
|
// mod resolve;
|
||||||
mod first_pass;
|
mod first_pass;
|
||||||
mod scope_table;
|
mod scope_table;
|
||||||
mod second_pass;
|
mod second_pass;
|
||||||
pub mod symbol;
|
pub mod symbol;
|
||||||
pub mod symbol_table;
|
pub mod symbol_table;
|
||||||
pub mod symbol_tree;
|
|
||||||
mod util;
|
mod util;
|
||||||
|
|
||||||
pub fn analyze_names<'a, F: Files<'a, FileId = usize, Name = String>>(
|
pub fn analyze_names<'a, F: Files<'a, FileId = usize, Name = String>>(
|
||||||
compilation_units: &mut Vec<Box<CompilationUnit>>,
|
compilation_units: &mut Vec<Box<CompilationUnit>>,
|
||||||
files: &'a F,
|
files: &'a F,
|
||||||
symbol_table: &mut SymbolTable,
|
symbol_table: &mut SymbolTable,
|
||||||
symbol_tree: &mut SymbolTree,
|
|
||||||
) -> Vec<DmDiagnostic> {
|
) -> Vec<DmDiagnostic> {
|
||||||
let mut diagnostics = vec![];
|
let mut diagnostics = vec![];
|
||||||
|
|
||||||
// gather symbols
|
// gather symbols
|
||||||
for compilation_unit in compilation_units.iter_mut() {
|
for compilation_unit in compilation_units.iter_mut() {
|
||||||
let file_name = files.name(compilation_unit.file_id()).unwrap();
|
let file_name = files.name(compilation_unit.file_id()).unwrap();
|
||||||
nap1_compilation_unit(&file_name, compilation_unit, symbol_table, symbol_tree, &mut diagnostics);
|
na_p1_compilation_unit(&file_name, compilation_unit, symbol_table, &mut diagnostics);
|
||||||
}
|
}
|
||||||
|
|
||||||
// resolve symbols
|
// resolve symbols
|
||||||
for compilation_unit in compilation_units {
|
for compilation_unit in compilation_units {
|
||||||
nap2_compilation_unit(compilation_unit, symbol_table, symbol_tree, &mut diagnostics);
|
na_p2_compilation_unit(compilation_unit, symbol_table, &mut diagnostics);
|
||||||
}
|
}
|
||||||
|
|
||||||
diagnostics.into()
|
diagnostics.into()
|
||||||
|
|||||||
@ -1,125 +1,103 @@
|
|||||||
use crate::ast::node::{CompilationUnit, Identifier, UseStatement, UseStatementSuffix};
|
use crate::ast::node::{
|
||||||
|
CompilationUnit, ConcreteUseStatement, ConcreteUseStatementSuffix, Identifier, UseStatement,
|
||||||
|
UseStatementIdentifier, UseStatementPrefix,
|
||||||
|
};
|
||||||
use crate::diagnostic::DmDiagnostic;
|
use crate::diagnostic::DmDiagnostic;
|
||||||
use crate::name_analysis::symbol::usable_symbol::UsableSymbol;
|
|
||||||
use crate::name_analysis::symbol::use_symbol::{ConcreteUseSymbol, UseSymbol};
|
|
||||||
use crate::name_analysis::symbol_table::{SymbolLookupError, SymbolTable};
|
use crate::name_analysis::symbol_table::{SymbolLookupError, SymbolTable};
|
||||||
use crate::name_analysis::symbol_tree::SymbolTree;
|
use crate::name_analysis::util::handle_lookup_error;
|
||||||
use crate::name_analysis::util::{handle_lookup_error, use_statement_base_fqn};
|
|
||||||
use std::cell::RefCell;
|
|
||||||
use std::rc::Rc;
|
|
||||||
|
|
||||||
pub fn nap2_compilation_unit(
|
pub fn na_p2_compilation_unit(
|
||||||
compilation_unit: &mut CompilationUnit,
|
compilation_unit: &mut CompilationUnit,
|
||||||
symbol_table: &SymbolTable,
|
symbol_table: &SymbolTable,
|
||||||
symbol_tree: &SymbolTree,
|
|
||||||
diagnostics: &mut Vec<DmDiagnostic>,
|
diagnostics: &mut Vec<DmDiagnostic>,
|
||||||
) {
|
) {
|
||||||
// TODO: check namespace for proper file name
|
// TODO: check namespace for proper file name
|
||||||
for use_statement in compilation_unit.use_statements_mut() {
|
for use_statement in compilation_unit.use_statements_mut() {
|
||||||
nap2_use_statement(use_statement, symbol_tree, diagnostics);
|
na_p2_use_statement(use_statement, symbol_table, diagnostics);
|
||||||
}
|
}
|
||||||
|
|
||||||
// TODO: declarations
|
// TODO: declarations
|
||||||
}
|
}
|
||||||
|
|
||||||
fn find_usable_symbol(
|
fn na_p2_use_statement(
|
||||||
use_statement: &UseStatement,
|
use_statement: &mut UseStatement,
|
||||||
identifier: &Identifier,
|
symbol_table: &SymbolTable,
|
||||||
symbol_tree: &SymbolTree,
|
|
||||||
) -> Option<UsableSymbol> {
|
|
||||||
let fqn_parts: Vec<&str> = {
|
|
||||||
let mut base: Vec<&str> = use_statement
|
|
||||||
.prefixes()
|
|
||||||
.map(|prefix| prefix.identifier().name())
|
|
||||||
.collect();
|
|
||||||
base.push(identifier.name());
|
|
||||||
base
|
|
||||||
};
|
|
||||||
symbol_tree
|
|
||||||
.find_interface(&fqn_parts)
|
|
||||||
.map(|interface_symbol| UsableSymbol::Interface(interface_symbol))
|
|
||||||
.or_else(|| {
|
|
||||||
symbol_tree
|
|
||||||
.find_class(&fqn_parts)
|
|
||||||
.map(|class_symbol| UsableSymbol::Class(class_symbol))
|
|
||||||
})
|
|
||||||
.or_else(|| {
|
|
||||||
symbol_tree
|
|
||||||
.find_function(&fqn_parts)
|
|
||||||
.map(|function_symbol| UsableSymbol::Function(function_symbol))
|
|
||||||
})
|
|
||||||
}
|
|
||||||
|
|
||||||
fn find_matching_concrete_use_symbol(
|
|
||||||
use_statement: &UseStatement,
|
|
||||||
identifier: &Identifier,
|
|
||||||
) -> Option<Rc<RefCell<ConcreteUseSymbol>>> {
|
|
||||||
let base_fqn = use_statement_base_fqn(use_statement);
|
|
||||||
use_statement
|
|
||||||
.use_symbols()
|
|
||||||
.iter()
|
|
||||||
.find(|use_symbol| match use_symbol {
|
|
||||||
UseSymbol::Concrete(concrete_use_symbol) => {
|
|
||||||
let borrowed = concrete_use_symbol.borrow();
|
|
||||||
borrowed.base_fqn() == base_fqn && borrowed.declared_name() == identifier.name()
|
|
||||||
}
|
|
||||||
_ => false,
|
|
||||||
})
|
|
||||||
.map(|use_symbol| match use_symbol {
|
|
||||||
UseSymbol::Concrete(concrete) => concrete.clone(),
|
|
||||||
_ => panic!(),
|
|
||||||
})
|
|
||||||
}
|
|
||||||
|
|
||||||
fn handle_concrete_use(
|
|
||||||
use_statement: &UseStatement,
|
|
||||||
identifier: &Identifier,
|
|
||||||
symbol_tree: &SymbolTree,
|
|
||||||
diagnostics: &mut Vec<DmDiagnostic>,
|
diagnostics: &mut Vec<DmDiagnostic>,
|
||||||
) {
|
) {
|
||||||
let maybe_usable_symbol = find_usable_symbol(use_statement, identifier, symbol_tree);
|
match use_statement {
|
||||||
if let Some(usable_symbol) = maybe_usable_symbol {
|
UseStatement::ConcreteUseStatement(concrete_use_statement) => {
|
||||||
let maybe_concrete_use_symbol =
|
na_p2_concrete_use_statement(concrete_use_statement, symbol_table, diagnostics);
|
||||||
find_matching_concrete_use_symbol(use_statement, identifier);
|
|
||||||
if let Some(concrete_use_symbol) = maybe_concrete_use_symbol {
|
|
||||||
concrete_use_symbol
|
|
||||||
.borrow_mut()
|
|
||||||
.set_resolved_symbol(usable_symbol);
|
|
||||||
} else {
|
|
||||||
panic!("Can't find matching ConcreteUseSymbol");
|
|
||||||
}
|
}
|
||||||
|
UseStatement::StarUseStatement(star_use_statement) => {
|
||||||
|
todo!()
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
fn na_p2_concrete_use_statement(
|
||||||
|
concrete_use_statement: &mut ConcreteUseStatement,
|
||||||
|
symbol_table: &SymbolTable,
|
||||||
|
diagnostics: &mut Vec<DmDiagnostic>,
|
||||||
|
) {
|
||||||
|
let base_fqn_parts: Vec<String> = concrete_use_statement
|
||||||
|
.prefixes()
|
||||||
|
.map(UseStatementPrefix::identifier)
|
||||||
|
.map(Identifier::name)
|
||||||
|
.map(ToString::to_string)
|
||||||
|
.collect();
|
||||||
|
|
||||||
|
match concrete_use_statement.suffix_mut() {
|
||||||
|
ConcreteUseStatementSuffix::UseStatementIdentifier(use_statement_identifier) => {
|
||||||
|
handle_concrete_use_statement_identifier(
|
||||||
|
&base_fqn_parts,
|
||||||
|
use_statement_identifier,
|
||||||
|
symbol_table,
|
||||||
|
diagnostics,
|
||||||
|
);
|
||||||
|
}
|
||||||
|
ConcreteUseStatementSuffix::UseList(use_list) => {
|
||||||
|
for use_statement_identifier in use_list.identifiers_mut() {
|
||||||
|
handle_concrete_use_statement_identifier(
|
||||||
|
&base_fqn_parts,
|
||||||
|
use_statement_identifier,
|
||||||
|
symbol_table,
|
||||||
|
diagnostics,
|
||||||
|
);
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
fn handle_concrete_use_statement_identifier(
|
||||||
|
base_fqn_parts: &[String],
|
||||||
|
use_statement_identifier: &mut UseStatementIdentifier,
|
||||||
|
symbol_table: &SymbolTable,
|
||||||
|
diagnostics: &mut Vec<DmDiagnostic>,
|
||||||
|
) {
|
||||||
|
let fqn_parts = {
|
||||||
|
let mut all_parts: Vec<&str> = vec![];
|
||||||
|
for part in base_fqn_parts {
|
||||||
|
all_parts.push(part);
|
||||||
|
}
|
||||||
|
all_parts.push(use_statement_identifier.identifier().name());
|
||||||
|
all_parts
|
||||||
|
};
|
||||||
|
|
||||||
|
let maybe_usable_symbol = symbol_table.find_usable_symbol(&fqn_parts);
|
||||||
|
if let Some(usable_symbol) = maybe_usable_symbol {
|
||||||
|
use_statement_identifier
|
||||||
|
.symbol_mut()
|
||||||
|
.expect("Should have set the symbol on the use statement already.")
|
||||||
|
.borrow_mut()
|
||||||
|
.set_resolved_symbol(usable_symbol);
|
||||||
} else {
|
} else {
|
||||||
handle_lookup_error(
|
handle_lookup_error(
|
||||||
SymbolLookupError::NoDefinition,
|
SymbolLookupError::NoDefinition,
|
||||||
&format!(
|
&fqn_parts.join("::"),
|
||||||
"{}::{}",
|
use_statement_identifier.identifier().file_id(),
|
||||||
use_statement_base_fqn(use_statement),
|
use_statement_identifier.identifier().range(),
|
||||||
identifier.name()
|
|
||||||
),
|
|
||||||
use_statement.file_id(),
|
|
||||||
use_statement.range(),
|
|
||||||
"Usable Symbol",
|
"Usable Symbol",
|
||||||
diagnostics,
|
diagnostics,
|
||||||
);
|
);
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
fn nap2_use_statement(
|
|
||||||
use_statement: &mut UseStatement,
|
|
||||||
symbol_tree: &SymbolTree,
|
|
||||||
diagnostics: &mut Vec<DmDiagnostic>,
|
|
||||||
) {
|
|
||||||
match use_statement.suffix() {
|
|
||||||
UseStatementSuffix::Identifier(identifier) => {
|
|
||||||
handle_concrete_use(use_statement, identifier, symbol_tree, diagnostics);
|
|
||||||
}
|
|
||||||
UseStatementSuffix::Star => {
|
|
||||||
todo!("Resolve star symbols")
|
|
||||||
}
|
|
||||||
UseStatementSuffix::UseList(use_list) => {
|
|
||||||
for identifier in use_list.identifiers() {
|
|
||||||
handle_concrete_use(use_statement, identifier, symbol_tree, diagnostics);
|
|
||||||
}
|
|
||||||
}
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|||||||
@ -1,7 +1,5 @@
|
|||||||
use std::cell::RefCell;
|
use crate::ast::node::{Identifier, Operator};
|
||||||
use std::range::Range;
|
use std::range::Range;
|
||||||
use std::rc::Rc;
|
|
||||||
use crate::ast::node::{Identifier, Operator, UseStatement};
|
|
||||||
|
|
||||||
#[derive(Clone, Debug)]
|
#[derive(Clone, Debug)]
|
||||||
pub struct SourceDefinition {
|
pub struct SourceDefinition {
|
||||||
@ -17,13 +15,6 @@ impl SourceDefinition {
|
|||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
pub fn from_use_statement(use_statement: &UseStatement) -> Self {
|
|
||||||
Self {
|
|
||||||
file_id: use_statement.file_id(),
|
|
||||||
range: use_statement.range(),
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
pub fn from_operator(operator: &Operator) -> Self {
|
pub fn from_operator(operator: &Operator) -> Self {
|
||||||
Self {
|
Self {
|
||||||
file_id: operator.file_id(),
|
file_id: operator.file_id(),
|
||||||
|
|||||||
@ -21,32 +21,29 @@ impl UseSymbol {
|
|||||||
|
|
||||||
#[derive(Clone)]
|
#[derive(Clone)]
|
||||||
pub struct ConcreteUseSymbol {
|
pub struct ConcreteUseSymbol {
|
||||||
base_fqn: String,
|
fqn_parts: Vec<String>,
|
||||||
declared_name: String,
|
|
||||||
source_definition: Option<SourceDefinition>,
|
source_definition: Option<SourceDefinition>,
|
||||||
resolved_symbol: Option<UsableSymbol>,
|
resolved_symbol: Option<UsableSymbol>,
|
||||||
}
|
}
|
||||||
|
|
||||||
impl ConcreteUseSymbol {
|
impl ConcreteUseSymbol {
|
||||||
pub fn new(
|
pub fn new(
|
||||||
base_fqn: &str,
|
fqn_parts: &[&str],
|
||||||
declared_name: &str,
|
|
||||||
source_definition: Option<SourceDefinition>,
|
source_definition: Option<SourceDefinition>,
|
||||||
) -> Self {
|
) -> Self {
|
||||||
Self {
|
Self {
|
||||||
base_fqn: base_fqn.to_string(),
|
fqn_parts: fqn_parts.iter().map(ToString::to_string).collect(),
|
||||||
declared_name: declared_name.to_string(),
|
|
||||||
source_definition,
|
source_definition,
|
||||||
resolved_symbol: None,
|
resolved_symbol: None,
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
pub fn base_fqn(&self) -> &str {
|
pub fn fqn_parts(&self) -> &[String] {
|
||||||
&self.base_fqn
|
self.fqn_parts.as_slice()
|
||||||
}
|
}
|
||||||
|
|
||||||
pub fn declared_name(&self) -> &str {
|
pub fn declared_name(&self) -> &str {
|
||||||
&self.declared_name
|
self.fqn_parts.last().unwrap()
|
||||||
}
|
}
|
||||||
|
|
||||||
pub fn source_definition(&self) -> Option<&SourceDefinition> {
|
pub fn source_definition(&self) -> Option<&SourceDefinition> {
|
||||||
@ -65,8 +62,7 @@ impl ConcreteUseSymbol {
|
|||||||
impl Debug for ConcreteUseSymbol {
|
impl Debug for ConcreteUseSymbol {
|
||||||
fn fmt(&self, f: &mut Formatter<'_>) -> std::fmt::Result {
|
fn fmt(&self, f: &mut Formatter<'_>) -> std::fmt::Result {
|
||||||
f.debug_struct("ConcreteUseStatementSymbol")
|
f.debug_struct("ConcreteUseStatementSymbol")
|
||||||
.field("base_fqn", &self.base_fqn)
|
.field("fqn_parts", &self.fqn_parts)
|
||||||
.field("declared_name", &self.declared_name)
|
|
||||||
.field("source_definition", &self.source_definition)
|
.field("source_definition", &self.source_definition)
|
||||||
.finish()
|
.finish()
|
||||||
}
|
}
|
||||||
|
|||||||
@ -1,3 +1,4 @@
|
|||||||
|
#[derive(Debug)]
|
||||||
pub struct FqnContext {
|
pub struct FqnContext {
|
||||||
stack: Vec<String>,
|
stack: Vec<String>,
|
||||||
}
|
}
|
||||||
@ -5,6 +5,8 @@ use crate::name_analysis::symbol::parameter_symbol::ParameterSymbol;
|
|||||||
use crate::name_analysis::symbol::use_symbol::{ConcreteUseSymbol, StarUseSymbol, UseSymbol};
|
use crate::name_analysis::symbol::use_symbol::{ConcreteUseSymbol, StarUseSymbol, UseSymbol};
|
||||||
use crate::name_analysis::symbol::variable_symbol::VariableSymbol;
|
use crate::name_analysis::symbol::variable_symbol::VariableSymbol;
|
||||||
use crate::name_analysis::symbol::*;
|
use crate::name_analysis::symbol::*;
|
||||||
|
use crate::name_analysis::symbol_table::fqn_context::FqnContext;
|
||||||
|
use crate::name_analysis::symbol_table::symbol_tree::SymbolTree;
|
||||||
use crate::name_analysis::symbol_table::SymbolInsertError::SymbolAlreadyDefined;
|
use crate::name_analysis::symbol_table::SymbolInsertError::SymbolAlreadyDefined;
|
||||||
use crate::name_analysis::symbol_table::SymbolLookupError::NoDefinition;
|
use crate::name_analysis::symbol_table::SymbolLookupError::NoDefinition;
|
||||||
use scope::Scope;
|
use scope::Scope;
|
||||||
@ -12,8 +14,11 @@ use std::cell::RefCell;
|
|||||||
use std::fmt::Display;
|
use std::fmt::Display;
|
||||||
use std::ops::Deref;
|
use std::ops::Deref;
|
||||||
use std::rc::Rc;
|
use std::rc::Rc;
|
||||||
|
use crate::name_analysis::symbol::usable_symbol::UsableSymbol;
|
||||||
|
|
||||||
|
pub(self) mod fqn_context;
|
||||||
mod scope;
|
mod scope;
|
||||||
|
pub mod symbol_tree;
|
||||||
|
|
||||||
#[derive(Debug)]
|
#[derive(Debug)]
|
||||||
pub enum SymbolInsertError {
|
pub enum SymbolInsertError {
|
||||||
@ -29,6 +34,8 @@ pub enum SymbolLookupError {
|
|||||||
pub struct SymbolTable {
|
pub struct SymbolTable {
|
||||||
scopes: Vec<Scope>,
|
scopes: Vec<Scope>,
|
||||||
current_scope_id: usize,
|
current_scope_id: usize,
|
||||||
|
symbol_tree: Box<SymbolTree>,
|
||||||
|
fqn_context: Box<FqnContext>,
|
||||||
}
|
}
|
||||||
|
|
||||||
/// Contains a vec of scopes, like a flattened tree
|
/// Contains a vec of scopes, like a flattened tree
|
||||||
@ -37,6 +44,8 @@ impl SymbolTable {
|
|||||||
Self {
|
Self {
|
||||||
scopes: vec![Scope::new(None, 0, String::from("GlobalScope"))],
|
scopes: vec![Scope::new(None, 0, String::from("GlobalScope"))],
|
||||||
current_scope_id: 0,
|
current_scope_id: 0,
|
||||||
|
symbol_tree: Box::new(SymbolTree::new()),
|
||||||
|
fqn_context: Box::new(FqnContext::new()),
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
@ -60,6 +69,41 @@ impl SymbolTable {
|
|||||||
self.current_scope_id = parent_id;
|
self.current_scope_id = parent_id;
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
pub fn set_current_fqn(&mut self, names: &[&str]) {
|
||||||
|
self.fqn_context = Box::new(FqnContext::new());
|
||||||
|
for name in names {
|
||||||
|
self.fqn_context.push(*name);
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
pub fn push_fqn_part(&mut self, part: &str) {
|
||||||
|
self.fqn_context.push(part);
|
||||||
|
}
|
||||||
|
|
||||||
|
pub fn pop_fqn_part(&mut self) {
|
||||||
|
self.fqn_context.pop();
|
||||||
|
}
|
||||||
|
|
||||||
|
pub fn symbol_tree(&self) -> &SymbolTree {
|
||||||
|
&self.symbol_tree
|
||||||
|
}
|
||||||
|
|
||||||
|
pub fn find_usable_symbol(&self, fqn_parts: &[&str]) -> Option<UsableSymbol> {
|
||||||
|
self.symbol_tree
|
||||||
|
.find_interface(fqn_parts)
|
||||||
|
.map(|interface_symbol| UsableSymbol::Interface(interface_symbol))
|
||||||
|
.or_else(|| {
|
||||||
|
self.symbol_tree
|
||||||
|
.find_class(fqn_parts)
|
||||||
|
.map(|class_symbol| UsableSymbol::Class(class_symbol))
|
||||||
|
})
|
||||||
|
.or_else(|| {
|
||||||
|
self.symbol_tree
|
||||||
|
.find_function(fqn_parts)
|
||||||
|
.map(|function_symbol| UsableSymbol::Function(function_symbol))
|
||||||
|
})
|
||||||
|
}
|
||||||
|
|
||||||
fn current_scope(&self) -> &Scope {
|
fn current_scope(&self) -> &Scope {
|
||||||
&self.scopes[self.current_scope_id]
|
&self.scopes[self.current_scope_id]
|
||||||
|
|||||||
@ -5,6 +5,7 @@ use crate::name_analysis::symbol::interface_symbol::InterfaceSymbol;
|
|||||||
use std::collections::HashMap;
|
use std::collections::HashMap;
|
||||||
use std::rc::Rc;
|
use std::rc::Rc;
|
||||||
|
|
||||||
|
#[derive(Debug)]
|
||||||
pub struct SymbolTree {
|
pub struct SymbolTree {
|
||||||
children: Box<HashMap<String, SymbolTree>>,
|
children: Box<HashMap<String, SymbolTree>>,
|
||||||
classes: Box<HashMap<String, Rc<RefCell<ClassSymbol>>>>,
|
classes: Box<HashMap<String, Rc<RefCell<ClassSymbol>>>>,
|
||||||
@ -1,17 +1,8 @@
|
|||||||
use crate::ast::node::UseStatement;
|
|
||||||
use crate::diagnostic::DmDiagnostic;
|
use crate::diagnostic::DmDiagnostic;
|
||||||
use crate::name_analysis::symbol_table::{SymbolInsertError, SymbolLookupError};
|
use crate::name_analysis::symbol_table::{SymbolInsertError, SymbolLookupError};
|
||||||
use codespan_reporting::diagnostic::{Diagnostic, Label};
|
use codespan_reporting::diagnostic::{Diagnostic, Label};
|
||||||
use std::range::Range;
|
use std::range::Range;
|
||||||
|
|
||||||
pub fn use_statement_base_fqn(use_statement: &UseStatement) -> String {
|
|
||||||
use_statement
|
|
||||||
.prefixes()
|
|
||||||
.map(|prefix| prefix.identifier().name())
|
|
||||||
.collect::<Vec<_>>()
|
|
||||||
.join("::")
|
|
||||||
}
|
|
||||||
|
|
||||||
pub fn handle_insert_error(
|
pub fn handle_insert_error(
|
||||||
err: SymbolInsertError,
|
err: SymbolInsertError,
|
||||||
error_symbol_name: &str,
|
error_symbol_name: &str,
|
||||||
|
|||||||
@ -231,6 +231,11 @@ Namespace:
|
|||||||
member:
|
member:
|
||||||
rule: FullyQualifiedName
|
rule: FullyQualifiedName
|
||||||
UseStatement:
|
UseStatement:
|
||||||
|
tree_enum:
|
||||||
|
rules:
|
||||||
|
- ConcreteUseStatement
|
||||||
|
- StarUseStatement
|
||||||
|
ConcreteUseStatement:
|
||||||
struct:
|
struct:
|
||||||
children:
|
children:
|
||||||
- use_kw:
|
- use_kw:
|
||||||
@ -241,34 +246,54 @@ UseStatement:
|
|||||||
rule: UseStatementPrefix
|
rule: UseStatementPrefix
|
||||||
- suffix:
|
- suffix:
|
||||||
member:
|
member:
|
||||||
rule: UseStatementSuffix
|
rule: ConcreteUseStatementSuffix
|
||||||
|
- file_id:
|
||||||
|
special:
|
||||||
|
kind: file_id
|
||||||
|
- range:
|
||||||
|
special:
|
||||||
|
kind: range
|
||||||
|
StarUseStatement:
|
||||||
|
struct:
|
||||||
|
children:
|
||||||
|
- use_kw:
|
||||||
|
skip:
|
||||||
|
rule: Use
|
||||||
|
- prefixes:
|
||||||
|
vec:
|
||||||
|
rule: UseStatementPrefix
|
||||||
|
- star_sym:
|
||||||
|
skip:
|
||||||
|
rule: Star
|
||||||
- file_id:
|
- file_id:
|
||||||
special:
|
special:
|
||||||
kind: file_id
|
kind: file_id
|
||||||
- range:
|
- range:
|
||||||
special:
|
special:
|
||||||
kind: range
|
kind: range
|
||||||
fields:
|
|
||||||
- use_symbols:
|
|
||||||
kind: UseSymbol
|
|
||||||
vec: true
|
|
||||||
UseStatementPrefix:
|
UseStatementPrefix:
|
||||||
struct:
|
struct:
|
||||||
children:
|
children:
|
||||||
- identifier
|
- identifier
|
||||||
UseStatementSuffix:
|
ConcreteUseStatementSuffix:
|
||||||
tree_enum:
|
tree_enum:
|
||||||
rules:
|
rules:
|
||||||
- Identifier
|
- UseStatementIdentifier
|
||||||
- Star:
|
|
||||||
child: false
|
|
||||||
- UseList
|
- UseList
|
||||||
|
UseStatementIdentifier:
|
||||||
|
struct:
|
||||||
|
children:
|
||||||
|
- identifier
|
||||||
|
fields:
|
||||||
|
- symbol:
|
||||||
|
kind: ConcreteUseSymbol
|
||||||
|
wrap: rc_ref_cell
|
||||||
UseList:
|
UseList:
|
||||||
struct:
|
struct:
|
||||||
children:
|
children:
|
||||||
- identifiers:
|
- identifiers:
|
||||||
vec:
|
vec:
|
||||||
rule: Identifier
|
rule: UseStatementIdentifier
|
||||||
|
|
||||||
# Level declarations
|
# Level declarations
|
||||||
ModuleLevelDeclaration:
|
ModuleLevelDeclaration:
|
||||||
|
|||||||
@ -322,9 +322,20 @@ Namespace = {
|
|||||||
}
|
}
|
||||||
|
|
||||||
UseStatement = {
|
UseStatement = {
|
||||||
|
ConcreteUseStatement
|
||||||
|
| StarUseStatement
|
||||||
|
}
|
||||||
|
|
||||||
|
ConcreteUseStatement = {
|
||||||
Use
|
Use
|
||||||
~ UseStatementPrefix*
|
~ UseStatementPrefix*
|
||||||
~ UseStatementSuffix
|
~ ConcreteUseStatementSuffix
|
||||||
|
}
|
||||||
|
|
||||||
|
StarUseStatement = {
|
||||||
|
Use
|
||||||
|
~ UseStatementPrefix*
|
||||||
|
~ Star
|
||||||
}
|
}
|
||||||
|
|
||||||
UseStatementPrefix = {
|
UseStatementPrefix = {
|
||||||
@ -332,16 +343,19 @@ UseStatementPrefix = {
|
|||||||
~ "::"
|
~ "::"
|
||||||
}
|
}
|
||||||
|
|
||||||
UseStatementSuffix = {
|
ConcreteUseStatementSuffix = {
|
||||||
Identifier
|
UseStatementIdentifier
|
||||||
| Star
|
|
||||||
| UseList
|
| UseList
|
||||||
}
|
}
|
||||||
|
|
||||||
|
UseStatementIdentifier = {
|
||||||
|
Identifier
|
||||||
|
}
|
||||||
|
|
||||||
UseList = {
|
UseList = {
|
||||||
"{"
|
"{"
|
||||||
~ Identifier
|
~ UseStatementIdentifier
|
||||||
~ ( "," ~ Identifier )*
|
~ ( "," ~ UseStatementIdentifier )*
|
||||||
~ "}"
|
~ "}"
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|||||||
Loading…
Reference in New Issue
Block a user