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::rc::Rc;
|
||||
use std::cell::RefCell;
|
||||
use crate::name_analysis::symbol::use_symbol::UseSymbol;
|
||||
use crate::name_analysis::symbol::use_symbol::*;
|
||||
|
||||
#(#types)*
|
||||
};
|
||||
|
||||
@ -3,12 +3,12 @@ use codespan_reporting::term;
|
||||
use codespan_reporting::term::termcolor::{ColorChoice, StandardStream};
|
||||
use deimos::ast::build::build_ast;
|
||||
use deimos::name_analysis::analyze_names;
|
||||
use deimos::name_analysis::symbol_table::symbol_tree::SymbolTree;
|
||||
use deimos::name_analysis::symbol_table::SymbolTable;
|
||||
use deimos::parser::{DeimosParser, Rule};
|
||||
use deimos::std_core::add_std_core_symbols;
|
||||
use pest::Parser;
|
||||
use std::path::PathBuf;
|
||||
use deimos::name_analysis::symbol_tree::SymbolTree;
|
||||
|
||||
pub fn name_analysis(paths: &Vec<PathBuf>) -> Result<(), Box<dyn std::error::Error>> {
|
||||
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_tree = SymbolTree::new();
|
||||
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() {
|
||||
println!("Name analysis complete.");
|
||||
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::name_analysis::fqn_context::FqnContext;
|
||||
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_tree::SymbolTree;
|
||||
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;
|
||||
use crate::name_analysis::util::handle_insert_error;
|
||||
|
||||
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) {
|
||||
util::handle_insert_error(
|
||||
insert_error,
|
||||
$name,
|
||||
$node.file_id(),
|
||||
$node.range(),
|
||||
$symbol_kinds,
|
||||
$diagnostics,
|
||||
)
|
||||
}
|
||||
};
|
||||
}
|
||||
|
||||
pub fn nap1_compilation_unit(
|
||||
pub fn na_p1_compilation_unit(
|
||||
file_name: &str,
|
||||
compilation_unit: &mut CompilationUnit,
|
||||
symbol_table: &mut SymbolTable,
|
||||
symbol_tree: &mut SymbolTree,
|
||||
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());
|
||||
}
|
||||
symbol_table.set_current_fqn(
|
||||
&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() {
|
||||
nap1_use_statement(use_statement, symbol_table, diagnostics);
|
||||
na_p1_use_statement(use_statement, symbol_table, diagnostics);
|
||||
}
|
||||
|
||||
symbol_table.pop_scope();
|
||||
}
|
||||
|
||||
fn maybe_insert_concrete_use_symbol(
|
||||
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(
|
||||
fn na_p1_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 {
|
||||
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() {
|
||||
UseStatementSuffix::Identifier(identifier) => {
|
||||
let maybe_symbol = maybe_insert_concrete_use_symbol(
|
||||
use_statement,
|
||||
&identifier,
|
||||
fn na_p1_concrete_use_statement(
|
||||
concrete_use_statement: &mut ConcreteUseStatement,
|
||||
symbol_table: &mut SymbolTable,
|
||||
diagnostics: &mut Vec<DmDiagnostic>,
|
||||
) {
|
||||
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,
|
||||
diagnostics,
|
||||
);
|
||||
if let Some(concrete_use_symbol) = maybe_symbol {
|
||||
use_statement.use_symbols_mut().push(UseSymbol::Concrete(concrete_use_symbol));
|
||||
}
|
||||
}
|
||||
UseStatementSuffix::Star => {
|
||||
let maybe_symbol = match symbol_table.insert_star_use_symbol(
|
||||
StarUseSymbol::new(&base_fqn, Some(SourceDefinition::from_use_statement(use_statement)))
|
||||
) {
|
||||
Ok(inserted) => {
|
||||
Some(todo!())
|
||||
},
|
||||
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));
|
||||
}
|
||||
ConcreteUseStatementSuffix::UseList(use_list) => {
|
||||
for use_statement_identifier in use_list.identifiers_mut() {
|
||||
handle_concrete_use_statement_identifier(
|
||||
&prefixes,
|
||||
use_statement_identifier,
|
||||
symbol_table,
|
||||
diagnostics,
|
||||
);
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
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::node::CompilationUnit;
|
||||
use crate::diagnostic::DmDiagnostic;
|
||||
use crate::name_analysis::first_pass::nap1_compilation_unit;
|
||||
use crate::name_analysis::second_pass::nap2_compilation_unit;
|
||||
use crate::name_analysis::first_pass::na_p1_compilation_unit;
|
||||
use crate::name_analysis::second_pass::na_p2_compilation_unit;
|
||||
use crate::name_analysis::symbol_table::SymbolTable;
|
||||
use codespan_reporting::files::Files;
|
||||
use std::hash::Hash;
|
||||
use crate::name_analysis::symbol_tree::SymbolTree;
|
||||
|
||||
pub(self) mod fqn_context;
|
||||
// mod resolve;
|
||||
mod first_pass;
|
||||
mod scope_table;
|
||||
mod second_pass;
|
||||
pub mod symbol;
|
||||
pub mod symbol_table;
|
||||
pub mod symbol_tree;
|
||||
mod util;
|
||||
|
||||
pub fn analyze_names<'a, F: Files<'a, FileId = usize, Name = String>>(
|
||||
compilation_units: &mut Vec<Box<CompilationUnit>>,
|
||||
files: &'a F,
|
||||
symbol_table: &mut SymbolTable,
|
||||
symbol_tree: &mut SymbolTree,
|
||||
) -> Vec<DmDiagnostic> {
|
||||
let mut diagnostics = vec![];
|
||||
|
||||
// gather symbols
|
||||
for compilation_unit in compilation_units.iter_mut() {
|
||||
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
|
||||
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()
|
||||
|
||||
@ -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::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_tree::SymbolTree;
|
||||
use crate::name_analysis::util::{handle_lookup_error, use_statement_base_fqn};
|
||||
use std::cell::RefCell;
|
||||
use std::rc::Rc;
|
||||
use crate::name_analysis::util::handle_lookup_error;
|
||||
|
||||
pub fn nap2_compilation_unit(
|
||||
pub fn na_p2_compilation_unit(
|
||||
compilation_unit: &mut CompilationUnit,
|
||||
symbol_table: &SymbolTable,
|
||||
symbol_tree: &SymbolTree,
|
||||
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_tree, diagnostics);
|
||||
na_p2_use_statement(use_statement, symbol_table, diagnostics);
|
||||
}
|
||||
|
||||
// TODO: declarations
|
||||
}
|
||||
|
||||
fn find_usable_symbol(
|
||||
use_statement: &UseStatement,
|
||||
identifier: &Identifier,
|
||||
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,
|
||||
fn na_p2_use_statement(
|
||||
use_statement: &mut UseStatement,
|
||||
symbol_table: &SymbolTable,
|
||||
diagnostics: &mut Vec<DmDiagnostic>,
|
||||
) {
|
||||
let maybe_usable_symbol = find_usable_symbol(use_statement, identifier, symbol_tree);
|
||||
if let Some(usable_symbol) = maybe_usable_symbol {
|
||||
let maybe_concrete_use_symbol =
|
||||
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");
|
||||
match use_statement {
|
||||
UseStatement::ConcreteUseStatement(concrete_use_statement) => {
|
||||
na_p2_concrete_use_statement(concrete_use_statement, symbol_table, diagnostics);
|
||||
}
|
||||
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 {
|
||||
handle_lookup_error(
|
||||
SymbolLookupError::NoDefinition,
|
||||
&format!(
|
||||
"{}::{}",
|
||||
use_statement_base_fqn(use_statement),
|
||||
identifier.name()
|
||||
),
|
||||
use_statement.file_id(),
|
||||
use_statement.range(),
|
||||
&fqn_parts.join("::"),
|
||||
use_statement_identifier.identifier().file_id(),
|
||||
use_statement_identifier.identifier().range(),
|
||||
"Usable Symbol",
|
||||
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::rc::Rc;
|
||||
use crate::ast::node::{Identifier, Operator, UseStatement};
|
||||
|
||||
#[derive(Clone, Debug)]
|
||||
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 {
|
||||
Self {
|
||||
file_id: operator.file_id(),
|
||||
|
||||
@ -21,32 +21,29 @@ impl UseSymbol {
|
||||
|
||||
#[derive(Clone)]
|
||||
pub struct ConcreteUseSymbol {
|
||||
base_fqn: String,
|
||||
declared_name: String,
|
||||
fqn_parts: Vec<String>,
|
||||
source_definition: Option<SourceDefinition>,
|
||||
resolved_symbol: Option<UsableSymbol>,
|
||||
}
|
||||
|
||||
impl ConcreteUseSymbol {
|
||||
pub fn new(
|
||||
base_fqn: &str,
|
||||
declared_name: &str,
|
||||
fqn_parts: &[&str],
|
||||
source_definition: Option<SourceDefinition>,
|
||||
) -> Self {
|
||||
Self {
|
||||
base_fqn: base_fqn.to_string(),
|
||||
declared_name: declared_name.to_string(),
|
||||
fqn_parts: fqn_parts.iter().map(ToString::to_string).collect(),
|
||||
source_definition,
|
||||
resolved_symbol: None,
|
||||
}
|
||||
}
|
||||
|
||||
pub fn base_fqn(&self) -> &str {
|
||||
&self.base_fqn
|
||||
pub fn fqn_parts(&self) -> &[String] {
|
||||
self.fqn_parts.as_slice()
|
||||
}
|
||||
|
||||
pub fn declared_name(&self) -> &str {
|
||||
&self.declared_name
|
||||
self.fqn_parts.last().unwrap()
|
||||
}
|
||||
|
||||
pub fn source_definition(&self) -> Option<&SourceDefinition> {
|
||||
@ -65,8 +62,7 @@ impl ConcreteUseSymbol {
|
||||
impl Debug for ConcreteUseSymbol {
|
||||
fn fmt(&self, f: &mut Formatter<'_>) -> std::fmt::Result {
|
||||
f.debug_struct("ConcreteUseStatementSymbol")
|
||||
.field("base_fqn", &self.base_fqn)
|
||||
.field("declared_name", &self.declared_name)
|
||||
.field("fqn_parts", &self.fqn_parts)
|
||||
.field("source_definition", &self.source_definition)
|
||||
.finish()
|
||||
}
|
||||
|
||||
@ -1,3 +1,4 @@
|
||||
#[derive(Debug)]
|
||||
pub struct FqnContext {
|
||||
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::variable_symbol::VariableSymbol;
|
||||
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::SymbolLookupError::NoDefinition;
|
||||
use scope::Scope;
|
||||
@ -12,8 +14,11 @@ use std::cell::RefCell;
|
||||
use std::fmt::Display;
|
||||
use std::ops::Deref;
|
||||
use std::rc::Rc;
|
||||
use crate::name_analysis::symbol::usable_symbol::UsableSymbol;
|
||||
|
||||
pub(self) mod fqn_context;
|
||||
mod scope;
|
||||
pub mod symbol_tree;
|
||||
|
||||
#[derive(Debug)]
|
||||
pub enum SymbolInsertError {
|
||||
@ -29,6 +34,8 @@ pub enum SymbolLookupError {
|
||||
pub struct SymbolTable {
|
||||
scopes: Vec<Scope>,
|
||||
current_scope_id: usize,
|
||||
symbol_tree: Box<SymbolTree>,
|
||||
fqn_context: Box<FqnContext>,
|
||||
}
|
||||
|
||||
/// Contains a vec of scopes, like a flattened tree
|
||||
@ -37,6 +44,8 @@ impl SymbolTable {
|
||||
Self {
|
||||
scopes: vec![Scope::new(None, 0, String::from("GlobalScope"))],
|
||||
current_scope_id: 0,
|
||||
symbol_tree: Box::new(SymbolTree::new()),
|
||||
fqn_context: Box::new(FqnContext::new()),
|
||||
}
|
||||
}
|
||||
|
||||
@ -61,6 +70,41 @@ impl SymbolTable {
|
||||
}
|
||||
}
|
||||
|
||||
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 {
|
||||
&self.scopes[self.current_scope_id]
|
||||
}
|
||||
|
||||
@ -5,6 +5,7 @@ use crate::name_analysis::symbol::interface_symbol::InterfaceSymbol;
|
||||
use std::collections::HashMap;
|
||||
use std::rc::Rc;
|
||||
|
||||
#[derive(Debug)]
|
||||
pub struct SymbolTree {
|
||||
children: Box<HashMap<String, SymbolTree>>,
|
||||
classes: Box<HashMap<String, Rc<RefCell<ClassSymbol>>>>,
|
||||
@ -1,17 +1,8 @@
|
||||
use crate::ast::node::UseStatement;
|
||||
use crate::diagnostic::DmDiagnostic;
|
||||
use crate::name_analysis::symbol_table::{SymbolInsertError, SymbolLookupError};
|
||||
use codespan_reporting::diagnostic::{Diagnostic, Label};
|
||||
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(
|
||||
err: SymbolInsertError,
|
||||
error_symbol_name: &str,
|
||||
|
||||
@ -231,6 +231,11 @@ Namespace:
|
||||
member:
|
||||
rule: FullyQualifiedName
|
||||
UseStatement:
|
||||
tree_enum:
|
||||
rules:
|
||||
- ConcreteUseStatement
|
||||
- StarUseStatement
|
||||
ConcreteUseStatement:
|
||||
struct:
|
||||
children:
|
||||
- use_kw:
|
||||
@ -241,34 +246,54 @@ UseStatement:
|
||||
rule: UseStatementPrefix
|
||||
- suffix:
|
||||
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:
|
||||
special:
|
||||
kind: file_id
|
||||
- range:
|
||||
special:
|
||||
kind: range
|
||||
fields:
|
||||
- use_symbols:
|
||||
kind: UseSymbol
|
||||
vec: true
|
||||
UseStatementPrefix:
|
||||
struct:
|
||||
children:
|
||||
- identifier
|
||||
UseStatementSuffix:
|
||||
ConcreteUseStatementSuffix:
|
||||
tree_enum:
|
||||
rules:
|
||||
- Identifier
|
||||
- Star:
|
||||
child: false
|
||||
- UseStatementIdentifier
|
||||
- UseList
|
||||
UseStatementIdentifier:
|
||||
struct:
|
||||
children:
|
||||
- identifier
|
||||
fields:
|
||||
- symbol:
|
||||
kind: ConcreteUseSymbol
|
||||
wrap: rc_ref_cell
|
||||
UseList:
|
||||
struct:
|
||||
children:
|
||||
- identifiers:
|
||||
vec:
|
||||
rule: Identifier
|
||||
rule: UseStatementIdentifier
|
||||
|
||||
# Level declarations
|
||||
ModuleLevelDeclaration:
|
||||
|
||||
@ -322,9 +322,20 @@ Namespace = {
|
||||
}
|
||||
|
||||
UseStatement = {
|
||||
ConcreteUseStatement
|
||||
| StarUseStatement
|
||||
}
|
||||
|
||||
ConcreteUseStatement = {
|
||||
Use
|
||||
~ UseStatementPrefix*
|
||||
~ UseStatementSuffix
|
||||
~ ConcreteUseStatementSuffix
|
||||
}
|
||||
|
||||
StarUseStatement = {
|
||||
Use
|
||||
~ UseStatementPrefix*
|
||||
~ Star
|
||||
}
|
||||
|
||||
UseStatementPrefix = {
|
||||
@ -332,16 +343,19 @@ UseStatementPrefix = {
|
||||
~ "::"
|
||||
}
|
||||
|
||||
UseStatementSuffix = {
|
||||
Identifier
|
||||
| Star
|
||||
ConcreteUseStatementSuffix = {
|
||||
UseStatementIdentifier
|
||||
| UseList
|
||||
}
|
||||
|
||||
UseStatementIdentifier = {
|
||||
Identifier
|
||||
}
|
||||
|
||||
UseList = {
|
||||
"{"
|
||||
~ Identifier
|
||||
~ ( "," ~ Identifier )*
|
||||
~ UseStatementIdentifier
|
||||
~ ( "," ~ UseStatementIdentifier )*
|
||||
~ "}"
|
||||
}
|
||||
|
||||
|
||||
Loading…
Reference in New Issue
Block a user