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()), | ||||||
|         } |         } | ||||||
|     } |     } | ||||||
| 
 | 
 | ||||||
| @ -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 { |     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
	 Jesse Brault
						Jesse Brault