Compare commits

...

5 Commits

Author SHA1 Message Date
Jesse Brault
13330300c1 WIP fleshing out of block and expression name analysis. 2025-10-31 13:04:22 -05:00
Jesse Brault
12a3a61156 Work on functions and parameter name resolution. 2025-10-31 12:14:33 -05:00
Jesse Brault
9b83a531ca Remove un-needed test. 2025-10-29 12:14:52 -05:00
Jesse Brault
e5c5be6d95 Re-enable tests for name analysis. Currently failing. 2025-10-29 12:13:39 -05:00
Jesse Brault
d653d26e14 Work on star-use symbols. 2025-10-28 10:43:42 -05:00
20 changed files with 986 additions and 363 deletions

View File

@ -116,8 +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::type_symbol::*;
use crate::name_analysis::symbol::use_symbol::*;
use crate::name_analysis::symbol::*;
#(#types)*
};

View File

@ -79,9 +79,9 @@ pub mod build {
include!(concat!(env!("OUT_DIR"), "/src/ast/build.rs"));
pub fn build_ast(file_id: usize, parsed_pairs: &mut Pairs<Rule>) -> Box<CompilationUnit> {
pub fn build_ast(file_id: usize, parsed_pairs: &mut Pairs<Rule>) -> CompilationUnit {
let compilation_unit_pair = parsed_pairs.next().unwrap();
Box::new(build_compilation_unit(file_id, compilation_unit_pair))
build_compilation_unit(file_id, compilation_unit_pair)
}
#[cfg(test)]
@ -174,22 +174,6 @@ pub mod pretty_print {
pub mod ast_node {
include!(concat!(env!("OUT_DIR"), "/src/ast/ast_node.rs"));
#[cfg(test)]
mod tests {
use crate::ast::ast_node::AstNode;
use crate::ast::node::CompilationUnit;
fn get_cu() -> CompilationUnit {
todo!()
}
#[test]
fn simple() {
let cu = get_cu();
for child in cu.children() {}
}
}
}
pub mod walk {

View File

@ -3,40 +3,69 @@ 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::collections::HashMap;
use std::fmt::{Debug, Display, Formatter};
use std::path::PathBuf;
pub fn name_analysis(paths: &Vec<PathBuf>) -> Result<(), Box<dyn std::error::Error>> {
let mut compilation_units = vec![];
let mut files: SimpleFiles<String, String> = SimpleFiles::new();
struct ParseErrors {
errors: Vec<pest::error::Error<Rule>>,
}
impl Debug for ParseErrors {
fn fmt(&self, f: &mut Formatter<'_>) -> std::fmt::Result {
Display::fmt(self, f)
}
}
impl Display for ParseErrors {
fn fmt(&self, f: &mut Formatter<'_>) -> std::fmt::Result {
writeln!(f, "There were errors during parsing.")?;
for parse_error in &self.errors {
writeln!(f, "{}", parse_error)?;
}
Ok(())
}
}
impl std::error::Error for ParseErrors {}
pub fn name_analysis(paths: &[PathBuf]) -> Result<(), Box<dyn std::error::Error>> {
let mut paths_and_sources: HashMap<String, String> = HashMap::new();
for path in paths {
let src = std::fs::read_to_string(path).unwrap();
let parse_result = DeimosParser::parse(Rule::CompilationUnit, &src);
let file_id = files.add(path.display().to_string(), src.clone()); // I don't love this clone
paths_and_sources.insert(path.display().to_string(), src);
}
let mut compilation_units = vec![];
let mut files: SimpleFiles<&str, &str> = SimpleFiles::new();
let mut parse_errors = vec![];
for (path, source) in &paths_and_sources {
let parse_result = DeimosParser::parse(Rule::CompilationUnit, source);
match parse_result {
Ok(mut pairs) => {
let file_id = files.add(path, source);
let compilation_unit = build_ast(file_id, &mut pairs);
compilation_units.push(compilation_unit);
Ok::<(), Box<dyn std::error::Error>>(())
}
Err(e) => Err(e.into()),
}?;
Err(error) => {
parse_errors.push(error);
}
}
}
if !parse_errors.is_empty() {
return Err(Box::new(ParseErrors { errors: parse_errors }));
}
let mut symbol_table = SymbolTable::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,
);
let diagnostics = analyze_names(&mut compilation_units, &files, &mut symbol_table);
if diagnostics.is_empty() {
println!("Name analysis complete.");
println!("{}", symbol_table);

View File

@ -1,8 +1,8 @@
use crate::ast::node::{
CompilationUnit, ConcreteUseStatement, ConcreteUseStatementSuffix, Function, FunctionBody,
GenericParameters, Identifier, IdentifierOrFqn, Module, ModuleLevelDeclaration, Parameters,
PrimitiveType, ReturnType, TypeUse, TypedArray, UseStatement, UseStatementIdentifier,
UseStatementPrefix,
GenericParameters, Identifier, IdentifierOrFqn, Module, ModuleLevelDeclaration, Parameter,
Parameters, PrimitiveType, ReturnType, StarUseStatement, TypeUse, TypedArray, UseStatement,
UseStatementIdentifier, UseStatementPrefix,
};
use crate::diagnostic::DmDiagnostic;
use crate::name_analysis::symbol::function_symbol::FunctionSymbol;
@ -13,10 +13,13 @@ use crate::name_analysis::symbol::parameter_symbol::ParameterSymbol;
use crate::name_analysis::symbol::primitive_type_symbol::PrimitiveTypeSymbol;
use crate::name_analysis::symbol::source_definition::SourceDefinition;
use crate::name_analysis::symbol::type_symbol::TypeSymbol;
use crate::name_analysis::symbol::use_symbol::ConcreteUseSymbol;
use crate::name_analysis::symbol::use_symbol::{ConcreteUseSymbol, StarUseSymbol};
use crate::name_analysis::symbol_table::SymbolTable;
use crate::name_analysis::util::{format_fqn, handle_insert_error, handle_lookup_error};
use crate::name_analysis::util::{
format_fqn, handle_insert_error, handle_lookup_error, join_fqn_parts,
};
use std::cell::RefCell;
use std::fmt::format;
use std::rc::Rc;
pub fn na_p1_compilation_unit(
@ -60,7 +63,7 @@ fn na_p1_use_statement(
na_p1_concrete_use_statement(concrete_use_statement, symbol_table, diagnostics);
}
UseStatement::StarUseStatement(star_use_statement) => {
todo!()
na_p1_star_use_statement(star_use_statement, symbol_table, diagnostics);
}
}
}
@ -100,7 +103,7 @@ fn na_p1_concrete_use_statement(
}
fn handle_concrete_use_statement_identifier(
prefixes: &Vec<Rc<str>>,
prefixes: &[Rc<str>],
use_statement_identifier: &mut UseStatementIdentifier,
symbol_table: &mut SymbolTable,
diagnostics: &mut Vec<DmDiagnostic>,
@ -134,6 +137,40 @@ fn handle_concrete_use_statement_identifier(
}
}
fn na_p1_star_use_statement(
star_use_statement: &mut StarUseStatement,
symbol_table: &mut SymbolTable,
diagnostics: &mut Vec<DmDiagnostic>,
) {
let fqn_parts = star_use_statement
.prefixes()
.map(UseStatementPrefix::identifier)
.map(Identifier::name)
.map(|name| Rc::from(name))
.collect::<Vec<Rc<str>>>();
let to_insert = StarUseSymbol::new(
&fqn_parts,
Some(SourceDefinition::from_star_use_statement(
star_use_statement,
)),
);
match symbol_table.insert_star_use_symbol(to_insert) {
Ok(star_use_symbol) => {
star_use_statement.set_symbol(star_use_symbol);
}
Err(symbol_insert_error) => {
handle_insert_error(
symbol_insert_error,
&join_fqn_parts(&fqn_parts),
star_use_statement.file_id(),
star_use_statement.range(),
diagnostics,
);
}
}
}
fn na_p1_module_level_declaration(
module_level_declaration: &mut ModuleLevelDeclaration,
symbol_table: &mut SymbolTable,
@ -207,8 +244,6 @@ fn na_p1_function(
symbol_table: &mut SymbolTable,
diagnostics: &mut Vec<DmDiagnostic>,
) -> Option<Rc<RefCell<FunctionSymbol>>> {
symbol_table.push_scope(&format!("FunctionScope {}", function.identifier().name()));
let to_insert = FunctionSymbol::new(
&symbol_table.resolve_fqn(Rc::from(function.identifier().name())),
function.is_public(),
@ -216,28 +251,7 @@ fn na_p1_function(
Some(SourceDefinition::from_identifier(function.identifier())),
);
let function_symbol = match symbol_table.insert_function_symbol(to_insert) {
Ok(function_symbol) => {
{
let mut as_ref_mut = function_symbol.borrow_mut();
// generics
na_p1_generic_parameters(function.generics_mut(), symbol_table, diagnostics);
// parameters
as_ref_mut.set_parameter_symbols(na_p1_parameters(
function.parameters_mut(),
symbol_table,
diagnostics,
));
// return type
let return_type =
na_p1_return_type(function.return_type_mut(), symbol_table, diagnostics);
if let Some(type_symbol) = return_type {
as_ref_mut.set_return_type(type_symbol);
}
}
Some(function_symbol)
}
Ok(function_symbol) => Some(function_symbol),
Err(symbol_insert_error) => {
handle_insert_error(
symbol_insert_error,
@ -250,7 +264,42 @@ fn na_p1_function(
}
};
if function_symbol.is_some() {
let mut as_ref_mut = function_symbol.as_ref().unwrap().borrow_mut();
// push a scope for this function
symbol_table.push_scope(&format!("FunctionScope {}", function.identifier().name()));
// generics
na_p1_generic_parameters(function.generics_mut(), symbol_table, diagnostics);
// parameters
as_ref_mut.set_parameter_symbols(na_p1_parameters(
function.parameters_mut(),
symbol_table,
diagnostics,
));
// return type
let return_type = na_p1_return_type(function.return_type_mut(), symbol_table, diagnostics);
if let Some(type_symbol) = return_type {
as_ref_mut.set_return_type(type_symbol);
}
symbol_table.push_scope(&format!(
"FunctionBodyScope {}",
function.identifier().name()
));
na_p1_function_body(
function.function_body_mut(),
symbol_table,
diagnostics
);
symbol_table.pop_scope();
symbol_table.pop_scope();
}
function_symbol
}
@ -260,7 +309,38 @@ fn na_p1_parameters(
symbol_table: &mut SymbolTable,
diagnostics: &mut Vec<DmDiagnostic>,
) -> Vec<Rc<RefCell<ParameterSymbol>>> {
todo!()
parameters
.parameters_mut()
.map(|parameter| na_p1_parameter(parameter, symbol_table, diagnostics))
.filter(Option::is_some)
.map(Option::unwrap)
.collect()
}
fn na_p1_parameter(
parameter: &mut Parameter,
symbol_table: &mut SymbolTable,
diagnostics: &mut Vec<DmDiagnostic>,
) -> Option<Rc<RefCell<ParameterSymbol>>> {
let parameter_type_symbol = na_p1_type_use(parameter.type_use_mut(), symbol_table, diagnostics);
let to_insert = ParameterSymbol::new(
parameter.identifier().name(),
Some(SourceDefinition::from_identifier(parameter.identifier())),
parameter_type_symbol,
);
match symbol_table.insert_parameter_symbol(to_insert) {
Ok(parameter_symbol) => Some(parameter_symbol),
Err(symbol_insert_error) => {
handle_insert_error(
symbol_insert_error,
parameter.identifier().name(),
parameter.identifier().file_id(),
parameter.identifier().range(),
diagnostics,
);
None
}
}
}
fn na_p1_return_type(
@ -394,5 +474,22 @@ fn na_p1_function_body(
symbol_table: &mut SymbolTable,
diagnostics: &mut Vec<DmDiagnostic>,
) {
todo!()
match function_body {
FunctionBody::FunctionAliasBody(alias_body) => {
// set scope id for pass 2; see below
alias_body.set_scope_id(symbol_table.current_scope_id());
}
FunctionBody::FunctionEqualsBody(equals_body) => {
// see below
equals_body.set_scope_id(symbol_table.current_scope_id());
}
FunctionBody::FunctionBlockBody(block_body) => {
// we need to do all insertion/resolution in pass 2, because we
// might call functions/use classes/etc from the same compilation
// unit which haven't been defined yet. So the strategy is to set
// the scope id for the body and then in pass 2, set the symbol
// table's current scope to that id.
block_body.set_scope_id(symbol_table.current_scope_id());
}
}
}

View File

@ -36,8 +36,11 @@ pub mod symbol;
pub mod symbol_table;
mod util;
pub fn analyze_names<'a, F: Files<'a, FileId = usize, Name = String>>(
compilation_units: &mut Vec<Box<CompilationUnit>>,
pub fn analyze_names<
'a,
F: Files<'a, FileId = usize, Name = &'a str, Source = &'a str> + ?Sized,
>(
compilation_units: &mut Vec<CompilationUnit>,
files: &'a F,
symbol_table: &mut SymbolTable,
) -> Vec<DmDiagnostic> {
@ -46,7 +49,11 @@ pub fn analyze_names<'a, F: Files<'a, FileId = usize, Name = String>>(
// gather symbols
for compilation_unit in compilation_units.iter_mut() {
let file_name = files.name(compilation_unit.file_id()).unwrap();
na_p1_compilation_unit(&file_name, compilation_unit, symbol_table, &mut diagnostics);
na_p1_compilation_unit(file_name, compilation_unit, symbol_table, &mut diagnostics);
}
if !diagnostics.is_empty() {
return diagnostics;
}
// resolve symbols
@ -54,221 +61,160 @@ pub fn analyze_names<'a, F: Files<'a, FileId = usize, Name = String>>(
na_p2_compilation_unit(compilation_unit, symbol_table, &mut diagnostics);
}
diagnostics.into()
diagnostics
}
// #[cfg(test)]
// mod tests {
// use super::*;
// use crate::ast::build::build_ast;
// use crate::ast::children::NodeRef;
// use crate::ast::walk::walk_depth_first;
// use crate::parser::{DeimosParser, Rule};
// use crate::std_core::add_std_core_symbols;
// use codespan_reporting::files::SimpleFiles;
// use codespan_reporting::term;
// use codespan_reporting::term::termcolor::{ColorChoice, StandardStream};
// use indoc::indoc;
// use pest::Parser;
// use std::collections::HashMap;
//
// fn assert_number_of_diagnostics(
// sources: HashMap<&str, &str>,
// symbol_table: &mut SymbolTable,
// n_diagnostics: usize,
// ) -> Vec<CompilationUnit> {
// let mut files = SimpleFiles::new();
// let mut compilation_units = vec![];
//
// for (file_name, source) in sources {
// let file_id = files.add(file_name, source);
// let parse_result = DeimosParser::parse(Rule::CompilationUnit, source);
// if let Err(err) = &parse_result {
// panic!("{}", err);
// }
// let mut pairs = parse_result.unwrap();
// if pairs.as_str().trim() != source.trim() {
// panic!("Parsing did not consume entire input.");
// }
//
// compilation_units.push(build_ast(file_name, file_id, pairs.next().unwrap()));
// }
//
// let diagnostics = analyze_names(&mut compilation_units, symbol_table);
//
// if diagnostics.len() != n_diagnostics {
// let writer = StandardStream::stderr(ColorChoice::Always);
// let config = term::Config::default();
//
// for diagnostic in &diagnostics {
// term::emit(&mut writer.lock(), &config, &files, &diagnostic).unwrap();
// }
//
// eprintln!("{}", symbol_table);
// }
//
// assert_eq!(n_diagnostics, diagnostics.len());
//
// compilation_units
// }
//
// fn assert_no_diagnostics(
// sources: HashMap<&str, &str>,
// symbol_table: &mut SymbolTable,
// ) -> Vec<CompilationUnit> {
// assert_number_of_diagnostics(sources, symbol_table, 0)
// }
//
// fn assert_saved_symbols(compilation_unit: &CompilationUnit) {
// walk_depth_first(compilation_unit, &mut |node_ref| match node_ref {
// NodeRef::Identifier(identifier) => {
// if identifier.saved_symbol().is_none() {
// panic!("{:?} does not have a saved symbol.", identifier)
// }
// }
// NodeRef::FullyQualifiedName(fqn) => {
// if fqn.saved_symbol().is_none() {
// panic!("{:?} does not have a saved symbol.", fqn)
// }
// }
// NodeRef::UseStatement(use_statement) => match use_statement {
// _ => todo!(),
// },
// _ => {}
// })
// }
//
// fn assert_resolved_symbols(compilation_unit: &CompilationUnit) {
// walk_depth_first(compilation_unit, &mut |node_ref| match node_ref {
// NodeRef::UseStatement(use_statement) => match use_statement {
// _ => todo!(),
// },
// _ => {}
// })
// }
//
// #[test]
// fn params_seen() {
// let sources: HashMap<&str, &str> = HashMap::from([(
// "main.dm",
// indoc! {"
// fn main(args: Array<String>) {
// let x = args;
// }"},
// )]);
//
// let cus = assert_no_diagnostics(sources, &mut SymbolTable::new());
// for ref cu in cus {
// assert_saved_symbols(cu);
// }
// }
//
// #[test]
// fn two_files() {
// let sources: HashMap<&str, &str> = HashMap::from([
// (
// "main.dm",
// indoc! {"
// use test::Greeter;
// "},
// ),
// (
// "deps.dm",
// indoc! {"
// ns test;
//
// pub class Greeter {}
// "},
// ),
// ]);
//
// let cus = assert_no_diagnostics(sources, &mut SymbolTable::new());
// for ref cu in cus {
// assert_saved_symbols(cu);
// assert_resolved_symbols(cu);
// }
// }
//
// #[test]
// fn sees_std_core_println() {
// let sources: HashMap<&str, &str> = HashMap::from([(
// "main.dm",
// indoc! {"
// fn main(args: Array<String>) {
// println(args)
// }
// "},
// )]);
//
// let mut symbol_table = SymbolTable::new();
// add_std_core_symbols(&mut symbol_table).expect("Failed to add std::core symbols.");
// let cus = assert_no_diagnostics(sources, &mut symbol_table);
// for ref cu in cus {
// assert_saved_symbols(cu);
// assert_resolved_symbols(cu);
// }
// }
//
// #[test]
// fn sees_duplicate_fn() {
// let sources: HashMap<&str, &str> = HashMap::from([(
// "main.dm",
// indoc! {"
// fn main(args: Array<String>) {}
// fn main(args: Array<String>) {}
// "},
// )]);
// assert_number_of_diagnostics(sources, &mut SymbolTable::new(), 1);
// }
//
// #[test]
// fn use_class_from_other_file() {
// let sources: HashMap<&str, &str> = HashMap::from([
// (
// "main.dm",
// indoc! {"
// use greeter::Greeter;
//
// fn test(greeter: Greeter) {}
// "},
// ),
// (
// "greeter.dm",
// indoc! {"
// ns greeter;
//
// class Greeter {}
// "},
// ),
// ]);
// let mut symbol_table = SymbolTable::new();
// let cus = assert_no_diagnostics(sources, &mut symbol_table);
// for ref cu in cus {
// assert_saved_symbols(cu);
// assert_resolved_symbols(cu);
// }
// }
//
// #[test]
// fn shadow_import() {
// let sources: HashMap<&str, &str> = HashMap::from([
// (
// "main.dm",
// indoc! {"
// use greeter::Greeter;
//
// class Greeter {}
// "},
// ),
// (
// "greeter.dm",
// indoc! {"
// ns greeter;
//
// class Greeter {}
// "},
// ),
// ]);
// assert_number_of_diagnostics(sources, &mut SymbolTable::new(), 1);
// }
// }
#[cfg(test)]
mod tests {
use super::*;
use crate::ast::build::build_ast;
use crate::parser::{DeimosParser, Rule};
use crate::std_core::add_std_core_symbols;
use codespan_reporting::files::SimpleFiles;
use codespan_reporting::term;
use codespan_reporting::term::termcolor::{ColorChoice, StandardStream};
use pest::Parser;
use std::collections::HashMap;
use std::rc::Rc;
use crate::name_analysis::symbol::use_symbol::StarUseSymbol;
fn parse_compilation_units<'a>(
files: &mut SimpleFiles<&'a str, &'a str>,
sources: HashMap<&'a str, &'a str>,
) -> Vec<CompilationUnit> {
let mut compilation_units: Vec<CompilationUnit> = vec![];
for (file_name, source) in sources {
let parse_result = DeimosParser::parse(Rule::CompilationUnit, source);
if let Err(err) = &parse_result {
panic!("{}", err);
}
let mut pairs = parse_result.unwrap();
if pairs.as_str().trim() != source.trim() {
panic!("Parsing did not consume entire input.");
}
let file_id = files.add(file_name, source);
compilation_units.push(build_ast(file_id, &mut pairs));
}
compilation_units
}
fn assert_number_of_diagnostics<'a>(
sources: HashMap<&'a str, &'a str>,
symbol_table: &mut SymbolTable,
number_of_diagnostics: usize,
) -> Vec<CompilationUnit> {
let mut files = SimpleFiles::<&'a str, &'a str>::new();
let mut compilation_units = parse_compilation_units(&mut files, sources);
let diagnostics = analyze_names(&mut compilation_units, &files, symbol_table);
if diagnostics.len() != number_of_diagnostics {
let writer = StandardStream::stderr(ColorChoice::Always);
let config = term::Config::default();
for diagnostic in &diagnostics {
term::emit(&mut writer.lock(), &config, &files, &diagnostic).unwrap();
}
eprintln!("{}", symbol_table);
}
assert_eq!(number_of_diagnostics, diagnostics.len());
compilation_units
}
fn assert_no_diagnostics(
sources: HashMap<&str, &str>,
symbol_table: &mut SymbolTable,
) -> Vec<CompilationUnit> {
assert_number_of_diagnostics(sources, symbol_table, 0)
}
#[test]
fn params_seen() {
let sources = HashMap::from([(
"main.dm",
"
fn main(args: Array<String>)
let x = args
end
",
)]);
assert_no_diagnostics(sources, &mut SymbolTable::new());
}
#[test]
fn two_files() {
let sources = HashMap::from([
(
"main.dm",
"
use test::Greeter
",
),
(
"deps.dm",
"
ns test
pub class Greeter end
",
),
]);
assert_no_diagnostics(sources, &mut SymbolTable::new());
}
#[test]
fn sees_std_core_println() {
let sources: HashMap<&str, &str> = HashMap::from([(
"main.dm",
"
fn main(args: Array<String>)
std::core::println args
end
",
)]);
let mut symbol_table = SymbolTable::new();
add_std_core_symbols(&mut symbol_table).expect("Failed to add std::core symbols.");
assert_no_diagnostics(sources, &mut symbol_table);
}
#[test]
fn sees_duplicate_fn() {
let sources: HashMap<&str, &str> = HashMap::from([(
"main.dm",
"
fn main(args: Array<String>) end
fn main(args: Array<String>) end
",
)]);
assert_number_of_diagnostics(sources, &mut SymbolTable::new(), 1);
}
#[test]
fn sees_println() {
let sources = HashMap::from([(
"main.dm",
"
fn main(args: Array<String>)
println args
end
"
)]);
let mut symbol_table = SymbolTable::new();
let global_std_core_use = StarUseSymbol::new(
&[Rc::from("std"), Rc::from("core")],
None
);
symbol_table.insert_star_use_symbol(global_std_core_use)
.expect("Failed to insert star use symbol.");
add_std_core_symbols(&mut symbol_table).expect("Failed to add std/core symbols.");
assert_no_diagnostics(sources, &mut symbol_table);
}
}

View File

@ -1,27 +1,27 @@
use crate::ast::node::{
CompilationUnit, ConcreteUseStatement, ConcreteUseStatementSuffix, Identifier, UseStatement,
UseStatementIdentifier, UseStatementPrefix,
};
use crate::ast::node::{AssignmentStatement, CompilationUnit, ConcreteUseStatement, ConcreteUseStatementSuffix, Expression, ExpressionStatement, Function, FunctionAliasBody, FunctionBlockBody, FunctionBody, Identifier, LValue, ModuleLevelDeclaration, StarUseStatement, Statement, TypeUse, UseStatement, UseStatementIdentifier, UseStatementPrefix, VariableDeclaration, VariableUse};
use crate::diagnostic::DmDiagnostic;
use crate::name_analysis::symbol::source_definition::SourceDefinition;
use crate::name_analysis::symbol::variable_symbol::VariableSymbol;
use crate::name_analysis::symbol_table::{SymbolLookupError, SymbolTable};
use crate::name_analysis::util::handle_lookup_error;
use crate::name_analysis::util::{handle_insert_error, handle_lookup_error, join_fqn_parts};
use std::rc::Rc;
pub fn na_p2_compilation_unit(
compilation_unit: &mut CompilationUnit,
symbol_table: &SymbolTable,
symbol_table: &mut SymbolTable,
diagnostics: &mut Vec<DmDiagnostic>,
) {
// TODO: check namespace for proper file name
for use_statement in compilation_unit.use_statements_mut() {
na_p2_use_statement(use_statement, symbol_table, diagnostics);
}
// TODO: declarations
for declaration in compilation_unit.module_level_declarations_mut() {
na_p2_module_level_declaration(declaration, symbol_table, diagnostics);
}
}
fn na_p2_use_statement(
use_statement: &mut UseStatement,
symbol_table: &SymbolTable,
symbol_table: &mut SymbolTable,
diagnostics: &mut Vec<DmDiagnostic>,
) {
match use_statement {
@ -29,22 +29,22 @@ fn na_p2_use_statement(
na_p2_concrete_use_statement(concrete_use_statement, symbol_table, diagnostics);
}
UseStatement::StarUseStatement(star_use_statement) => {
todo!()
na_p2_star_use_statement(star_use_statement, symbol_table, diagnostics);
}
}
}
fn na_p2_concrete_use_statement(
concrete_use_statement: &mut ConcreteUseStatement,
symbol_table: &SymbolTable,
symbol_table: &mut SymbolTable,
diagnostics: &mut Vec<DmDiagnostic>,
) {
let base_fqn_parts: Vec<String> = concrete_use_statement
let base_fqn_parts = concrete_use_statement
.prefixes()
.map(UseStatementPrefix::identifier)
.map(Identifier::name)
.map(ToString::to_string)
.collect();
.map(Rc::from)
.collect::<Vec<Rc<str>>>();
match concrete_use_statement.suffix_mut() {
ConcreteUseStatementSuffix::UseStatementIdentifier(use_statement_identifier) => {
@ -69,17 +69,14 @@ fn na_p2_concrete_use_statement(
}
fn handle_concrete_use_statement_identifier(
base_fqn_parts: &[String],
base_fqn_parts: &[Rc<str>],
use_statement_identifier: &mut UseStatementIdentifier,
symbol_table: &SymbolTable,
symbol_table: &mut 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());
let mut all_parts = base_fqn_parts.to_vec();
all_parts.push(Rc::from(use_statement_identifier.identifier().name()));
all_parts
};
@ -93,10 +90,305 @@ fn handle_concrete_use_statement_identifier(
} else {
handle_lookup_error(
SymbolLookupError::NoDefinition,
&fqn_parts.join("::"),
&join_fqn_parts(&fqn_parts),
use_statement_identifier.identifier().file_id(),
use_statement_identifier.identifier().range(),
diagnostics,
);
}
}
fn na_p2_star_use_statement(
star_use_statement: &mut StarUseStatement,
symbol_table: &mut SymbolTable,
diagnostics: &mut Vec<DmDiagnostic>,
) {
let mut symbol_ref_mut = star_use_statement.symbol().unwrap().borrow_mut();
match symbol_table.find_usable_symbols_by_base_fqn(symbol_ref_mut.fqn_parts()) {
Ok(usable_symbols) => {
symbol_ref_mut.set_resolved_symbols(usable_symbols);
}
Err(symbol_lookup_error) => {
handle_lookup_error(
symbol_lookup_error,
&join_fqn_parts(symbol_ref_mut.fqn_parts()),
star_use_statement.file_id(),
star_use_statement.range(),
diagnostics,
);
}
}
}
fn na_p2_module_level_declaration(
module_level_declaration: &mut ModuleLevelDeclaration,
symbol_table: &mut SymbolTable,
diagnostics: &mut Vec<DmDiagnostic>,
) {
match module_level_declaration {
ModuleLevelDeclaration::Module(module_declaration) => {
todo!()
}
ModuleLevelDeclaration::Interface(interface) => {
todo!()
}
ModuleLevelDeclaration::Class(class) => {
todo!()
}
ModuleLevelDeclaration::Function(function) => {
na_p2_function(function, symbol_table, diagnostics);
}
ModuleLevelDeclaration::PlatformFunction(platform_function) => {
todo!()
}
}
}
fn na_p2_function(
function: &mut Function,
symbol_table: &mut SymbolTable,
diagnostics: &mut Vec<DmDiagnostic>,
) {
na_p2_function_body(function.function_body_mut(), symbol_table, diagnostics);
}
fn na_p2_function_body(
function_body: &mut FunctionBody,
symbol_table: &mut SymbolTable,
diagnostics: &mut Vec<DmDiagnostic>,
) {
match function_body {
FunctionBody::FunctionAliasBody(alias_body) => {
na_p2_function_alias_body(alias_body, symbol_table, diagnostics);
}
FunctionBody::FunctionEqualsBody(equals_body) => {}
FunctionBody::FunctionBlockBody(block_body) => {
na_p2_function_block_body(block_body, symbol_table, diagnostics);
}
}
}
fn na_p2_function_alias_body(
function_alias_body: &mut FunctionAliasBody,
symbol_table: &mut SymbolTable,
diagnostics: &mut Vec<DmDiagnostic>,
) {
let maybe_function_symbol = symbol_table.lookup_function_symbol(
function_alias_body.identifier().name(),
*function_alias_body.scope_id().unwrap(),
);
match maybe_function_symbol {
Ok(function_symbol) => {
function_alias_body.set_resolved_function_symbol(function_symbol);
}
Err(symbol_lookup_error) => {
handle_lookup_error(
symbol_lookup_error,
function_alias_body.identifier().name(),
function_alias_body.identifier().file_id(),
function_alias_body.identifier().range(),
diagnostics,
);
}
}
}
fn na_p2_function_block_body(
function_block_body: &mut FunctionBlockBody,
symbol_table: &mut SymbolTable,
diagnostics: &mut Vec<DmDiagnostic>,
) {
symbol_table.set_current_scope(*function_block_body.scope_id().unwrap());
for statement in function_block_body.statements_mut() {
na_p2_statement(statement, symbol_table, diagnostics);
}
}
fn na_p2_statement(
statement: &mut Statement,
symbol_table: &mut SymbolTable,
diagnostics: &mut Vec<DmDiagnostic>,
) {
match statement {
Statement::VariableDeclaration(variable_declaration) => {
na_p2_variable_declaration(variable_declaration, symbol_table, diagnostics);
}
Statement::AssignmentStatement(assignment_statement) => {
na_p2_assignment_statement(assignment_statement, symbol_table, diagnostics);
}
Statement::ExpressionStatement(expression_statement) => {
na_p2_expression_statement(expression_statement, symbol_table, diagnostics);
}
Statement::UseStatement(use_statement) => {
todo!()
}
Statement::IfStatement(if_statement) => {
todo!()
}
Statement::WhileStatement(while_statement) => {
todo!()
}
Statement::ForStatement(for_statement) => {
todo!()
}
}
}
fn na_p2_variable_declaration(
variable_declaration: &mut VariableDeclaration,
symbol_table: &mut SymbolTable,
diagnostics: &mut Vec<DmDiagnostic>,
) {
// handle variable itself
let to_insert = VariableSymbol::new(
variable_declaration.identifier().name(),
variable_declaration.is_mut(),
Some(SourceDefinition::from_identifier(
variable_declaration.identifier(),
)),
);
match symbol_table.insert_variable_symbol(to_insert) {
Ok(variable_symbol) => {
variable_declaration.set_variable_symbol(variable_symbol);
}
Err(symbol_insert_error) => {
handle_insert_error(
symbol_insert_error,
variable_declaration.identifier().name(),
variable_declaration.identifier().file_id(),
variable_declaration.identifier().range(),
diagnostics,
);
}
}
// type-use
if let Some(type_use) = variable_declaration.type_use_mut() {
na_p2_type_use(type_use, symbol_table, diagnostics);
}
// initializer
if let Some(expression) = variable_declaration.expression_mut() {
na_p2_expression(expression, symbol_table, diagnostics);
}
}
fn na_p2_assignment_statement(
assignment_statement: &mut AssignmentStatement,
symbol_table: &mut SymbolTable,
diagnostics: &mut Vec<DmDiagnostic>,
) {
na_p2_l_value(assignment_statement.l_value_mut(), symbol_table, diagnostics);
na_p2_expression(assignment_statement.expression_mut(), symbol_table, diagnostics);
}
fn na_p2_l_value(
l_value: &mut LValue,
symbol_table: &mut SymbolTable,
diagnostics: &mut Vec<DmDiagnostic>,
) {
na_p2_variable_use(l_value.variable_use_mut(), symbol_table, diagnostics);
// TODO: suffixes
}
fn na_p2_expression_statement(
expression_statement: &mut ExpressionStatement,
symbol_table: &mut SymbolTable,
diagnostics: &mut Vec<DmDiagnostic>,
) {
na_p2_expression(expression_statement.expression_mut(), symbol_table, diagnostics);
}
fn na_p2_variable_use(
variable_use: &mut VariableUse,
symbol_table: &mut SymbolTable,
diagnostics: &mut Vec<DmDiagnostic>,
) {
match symbol_table.lookup_lv_symbol(variable_use.identifier().name()) {
Ok(lv_symbol) => {
variable_use.set_lv_symbol(lv_symbol);
}
Err(symbol_lookup_error) => {
handle_lookup_error(
symbol_lookup_error,
variable_use.identifier().name(),
variable_use.identifier().file_id(),
variable_use.identifier().range(),
diagnostics,
);
}
}
}
fn na_p2_expression(
expression: &mut Expression,
symbol_table: &mut SymbolTable,
diagnostics: &mut Vec<DmDiagnostic>,
) {
match expression {
Expression::Ternary(ternary) => {
todo!()
}
Expression::Or(or) => {
todo!()
}
Expression::And(and) => {
todo!()
}
Expression::Comparison(comparison) => {
todo!()
}
Expression::Shift(shift) => {
todo!()
}
Expression::Additive(additive) => {
todo!()
}
Expression::Multiplicative(multiplicative) => {
todo!()
}
Expression::Prefix(prefix) => {
todo!()
}
Expression::Suffix(suffix) => {
todo!()
}
Expression::Literal(literal) => {
todo!()
}
Expression::VariableUse(variable_use) => {
na_p2_variable_use(variable_use, symbol_table, diagnostics);
}
Expression::Fqn(fqn) => {
todo!()
}
Expression::Closure(closure) => {
todo!()
}
Expression::List(list) => {
todo!()
}
}
}
fn na_p2_type_use(
type_use: &mut TypeUse,
symbol_table: &mut SymbolTable,
diagnostics: &mut Vec<DmDiagnostic>,
) {
match type_use {
TypeUse::PrimitiveType(primitive_type_use) => {
todo!()
}
TypeUse::InterfaceOrClassTypeUse(interface_or_class_type_use) => {
todo!()
}
TypeUse::TupleTypeUse(tuple_type_use) => {
todo!()
}
TypeUse::FunctionTypeUse(function_type_use) => {
todo!()
}
}
}

View File

@ -1,4 +1,5 @@
use crate::name_analysis::symbol::source_definition::SourceDefinition;
use crate::name_analysis::symbol::Symbol;
use std::fmt::{Debug, Formatter};
#[derive(Clone)]
@ -35,8 +36,10 @@ impl ClassMemberSymbol {
pub fn declared_name(&self) -> &str {
&self.declared_name
}
}
pub fn source_definition(&self) -> Option<&SourceDefinition> {
impl Symbol for ClassMemberSymbol {
fn source_definition(&self) -> Option<&SourceDefinition> {
self.source_definition.as_ref()
}
}

View File

@ -0,0 +1,28 @@
use std::cell::RefCell;
use std::rc::Rc;
use crate::name_analysis::symbol::class_member_symbol::ClassMemberSymbol;
use crate::name_analysis::symbol::parameter_symbol::ParameterSymbol;
use crate::name_analysis::symbol::Symbol;
use crate::name_analysis::symbol::variable_symbol::VariableSymbol;
pub enum LVSymbol {
ClassMember(Rc<RefCell<ClassMemberSymbol>>),
Parameter(Rc<RefCell<ParameterSymbol>>),
Variable(Rc<RefCell<VariableSymbol>>),
}
impl LVSymbol {
pub fn to_symbol(self) -> Rc<RefCell<dyn Symbol>> {
match self {
LVSymbol::ClassMember(class_member_symbol) => {
class_member_symbol as Rc<RefCell<dyn Symbol>>
}
LVSymbol::Parameter(parameter_symbol) => {
parameter_symbol as Rc<RefCell<dyn Symbol>>
}
LVSymbol::Variable(variable_symbol) => {
variable_symbol as Rc<RefCell<dyn Symbol>>
}
}
}
}

View File

@ -3,6 +3,7 @@ pub mod class_symbol;
pub mod function_symbol;
pub mod generic_type_symbol;
pub mod interface_symbol;
pub mod lv_symbol;
pub mod module_level_symbol;
pub mod module_symbol;
pub mod parameter_symbol;
@ -16,6 +17,13 @@ pub mod variable_symbol;
use crate::name_analysis::symbol::source_definition::SourceDefinition;
use std::fmt::Debug;
pub use self::{
class_member_symbol::*, class_symbol::*, function_symbol::*, function_symbol::*,
generic_type_symbol::*, interface_symbol::*, lv_symbol::*, module_level_symbol::*,
module_symbol::*, parameter_symbol::*, primitive_type_symbol::*, type_symbol::*,
usable_symbol::*, use_symbol::*, variable_symbol::*,
};
pub trait Symbol: Debug {
fn source_definition(&self) -> Option<&SourceDefinition>;
}

View File

@ -1,9 +1,11 @@
use crate::name_analysis::symbol::source_definition::SourceDefinition;
use crate::name_analysis::symbol::type_symbol::TypeSymbol;
use crate::name_analysis::symbol::Symbol;
use std::fmt::{Debug, Formatter};
use std::rc::Rc;
pub struct ParameterSymbol {
declared_name: String,
declared_name: Rc<str>,
source_definition: Option<SourceDefinition>,
type_symbol: Option<TypeSymbol>,
}
@ -14,8 +16,8 @@ impl ParameterSymbol {
source_definition: Option<SourceDefinition>,
type_symbol: Option<TypeSymbol>,
) -> Self {
ParameterSymbol {
declared_name: declared_name.to_string(),
Self {
declared_name: Rc::from(declared_name),
source_definition,
type_symbol,
}
@ -25,7 +27,13 @@ impl ParameterSymbol {
&self.declared_name
}
pub fn source_definition(&self) -> Option<&SourceDefinition> {
pub fn declared_name_owned(&self) -> Rc<str> {
self.declared_name.clone()
}
}
impl Symbol for ParameterSymbol {
fn source_definition(&self) -> Option<&SourceDefinition> {
self.source_definition.as_ref()
}
}

View File

@ -1,4 +1,4 @@
use crate::ast::node::{Identifier, Operator};
use crate::ast::node::{Identifier, Operator, StarUseStatement};
use std::range::Range;
#[derive(Clone, Debug)]
@ -22,6 +22,13 @@ impl SourceDefinition {
}
}
pub fn from_star_use_statement(star_use_statement: &StarUseStatement) -> Self {
Self {
file_id: star_use_statement.file_id(),
range: star_use_statement.range(),
}
}
pub fn file_id(&self) -> usize {
self.file_id
}

View File

@ -5,7 +5,7 @@ use crate::name_analysis::symbol::Symbol;
use std::cell::RefCell;
use std::rc::Rc;
#[derive(Debug)]
#[derive(Debug, Clone)]
pub enum UsableSymbol {
Interface(Rc<RefCell<InterfaceSymbol>>),
Class(Rc<RefCell<ClassSymbol>>),

View File

@ -76,6 +76,7 @@ impl Debug for ConcreteUseSymbol {
pub struct StarUseSymbol {
fqn_parts: Vec<Rc<str>>,
source_definition: Option<SourceDefinition>,
resolved_symbols: Vec<UsableSymbol>,
}
impl StarUseSymbol {
@ -83,12 +84,21 @@ impl StarUseSymbol {
Self {
fqn_parts: fqn_parts.to_vec(),
source_definition,
resolved_symbols: vec![],
}
}
pub fn fqn_parts(&self) -> &[Rc<str>] {
&self.fqn_parts
}
pub fn resolved_symbols(&self) -> &[UsableSymbol] {
&self.resolved_symbols
}
pub fn set_resolved_symbols(&mut self, symbols: Vec<UsableSymbol>) {
self.resolved_symbols = symbols;
}
}
impl Symbol for StarUseSymbol {

View File

@ -1,17 +1,23 @@
use crate::name_analysis::symbol::source_definition::SourceDefinition;
use crate::name_analysis::symbol::Symbol;
use std::fmt::{Debug, Formatter};
use std::rc::Rc;
#[derive(Clone)]
pub struct VariableSymbol {
declared_name: String,
declared_name: Rc<str>,
is_mutable: bool,
source_definition: Option<SourceDefinition>,
}
impl VariableSymbol {
pub fn new(declared_name: &str, is_mutable: bool, source_definition: Option<SourceDefinition>) -> Self {
pub fn new(
declared_name: &str,
is_mutable: bool,
source_definition: Option<SourceDefinition>,
) -> Self {
VariableSymbol {
declared_name: declared_name.to_string(),
declared_name: Rc::from(declared_name),
is_mutable,
source_definition,
}
@ -21,11 +27,17 @@ impl VariableSymbol {
&self.declared_name
}
pub fn declared_name_owned(&self) -> Rc<str> {
self.declared_name.clone()
}
pub fn is_mutable(&self) -> bool {
self.is_mutable
}
}
pub fn source_definition(&self) -> Option<&SourceDefinition> {
impl Symbol for VariableSymbol {
fn source_definition(&self) -> Option<&SourceDefinition> {
self.source_definition.as_ref()
}
}

View File

@ -1,9 +1,11 @@
use crate::name_analysis::symbol::function_symbol::FunctionSymbol;
use crate::name_analysis::symbol::generic_type_symbol::GenericTypeSymbol;
use crate::name_analysis::symbol::module_symbol::ModuleSymbol;
use crate::name_analysis::symbol::parameter_symbol::ParameterSymbol;
use crate::name_analysis::symbol::type_symbol::TypeSymbol;
use crate::name_analysis::symbol::usable_symbol::UsableSymbol;
use crate::name_analysis::symbol::use_symbol::{ConcreteUseSymbol, StarUseSymbol};
use crate::name_analysis::symbol::Symbol;
use crate::name_analysis::symbol::{LVSymbol, 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;
@ -12,7 +14,7 @@ use std::cell::RefCell;
use std::fmt::Display;
use std::ops::Deref;
use std::rc::Rc;
use crate::name_analysis::symbol::generic_type_symbol::GenericTypeSymbol;
use crate::name_analysis::symbol::variable_symbol::VariableSymbol;
pub(self) mod fqn_context;
mod scope;
@ -25,6 +27,7 @@ pub enum SymbolInsertError {
pub enum SymbolLookupError {
NoDefinition,
NoSuchNamespace,
}
#[derive(Debug)]
@ -66,6 +69,10 @@ impl SymbolTable {
}
}
pub fn set_current_scope(&mut self, id: usize) {
self.current_scope_id = id;
}
pub fn set_current_fqn(&mut self, names: &[&str]) {
self.fqn_context = Box::new(FqnContext::new());
for name in names {
@ -95,7 +102,7 @@ impl SymbolTable {
parts
}
pub fn find_usable_symbol(&self, fqn_parts: &[&str]) -> Option<UsableSymbol> {
pub fn find_usable_symbol(&self, fqn_parts: &[Rc<str>]) -> Option<UsableSymbol> {
self.symbol_tree
.find_interface(fqn_parts)
.map(|interface_symbol| UsableSymbol::Interface(interface_symbol))
@ -111,6 +118,17 @@ impl SymbolTable {
})
}
pub fn register_module(&mut self, fqn_parts: &[&str]) {
self.symbol_tree.register_module_by_fqn_parts(fqn_parts);
}
pub fn find_usable_symbols_by_base_fqn(
&self,
fqn_parts: &[Rc<str>],
) -> Result<Vec<UsableSymbol>, SymbolLookupError> {
self.symbol_tree.find_all_by_base_fqn(fqn_parts)
}
fn current_scope(&self) -> &Scope {
&self.scopes[self.current_scope_id]
}
@ -184,10 +202,49 @@ impl SymbolTable {
&mut self,
generic_type_symbol: GenericTypeSymbol,
) -> Result<Rc<RefCell<GenericTypeSymbol>>, SymbolInsertError> {
if let Some(defined_symbol) = self.current_scope().find_type_symbol(generic_type_symbol.declared_name()) {
if let Some(defined_symbol) = self
.current_scope()
.find_type_symbol(generic_type_symbol.declared_name())
{
Err(SymbolAlreadyDefined(defined_symbol.to_symbol()))
} else {
let inserted = self.current_scope_mut().insert_generic_type_symbol(generic_type_symbol);
let inserted = self
.current_scope_mut()
.insert_generic_type_symbol(generic_type_symbol);
Ok(inserted)
}
}
pub fn insert_parameter_symbol(
&mut self,
parameter_symbol: ParameterSymbol,
) -> Result<Rc<RefCell<ParameterSymbol>>, SymbolInsertError> {
if let Some(defined_symbol) = self
.current_scope()
.find_lv_symbol(parameter_symbol.declared_name())
{
Err(SymbolAlreadyDefined(defined_symbol.to_symbol()))
} else {
let inserted = self
.current_scope_mut()
.insert_parameter_symbol(parameter_symbol);
Ok(inserted)
}
}
pub fn insert_variable_symbol(
&mut self,
variable_symbol: VariableSymbol,
) -> Result<Rc<RefCell<VariableSymbol>>, SymbolInsertError> {
if let Some(defined_symbol) = self
.current_scope()
.find_lv_symbol(variable_symbol.declared_name())
{
Err(SymbolAlreadyDefined(defined_symbol.to_symbol()))
} else {
let inserted = self
.current_scope_mut()
.insert_variable_symbol(variable_symbol);
Ok(inserted)
}
}
@ -209,6 +266,34 @@ impl SymbolTable {
pub fn lookup_type_by_fqn(&self, fqn_parts: &[&str]) -> Result<TypeSymbol, SymbolLookupError> {
todo!()
}
pub fn lookup_function_symbol(&self, declared_name: &str, scope_id: usize) -> Result<Rc<RefCell<FunctionSymbol>>, SymbolLookupError> {
let mut current_scope: Option<&Scope> = self.scopes.get(scope_id);
while let Some(scope) = current_scope.take() {
if let Some(function_symbol) = scope.find_function_symbol(declared_name) {
return Ok(function_symbol.clone());
} else {
current_scope = scope
.parent()
.and_then(|parent_id| self.scopes.get(parent_id));
}
}
Err(SymbolLookupError::NoDefinition)
}
pub fn lookup_lv_symbol(&self, declared_name: &str) -> Result<LVSymbol, SymbolLookupError> {
let mut current_scope: Option<&Scope> = Some(self.current_scope());
while let Some(scope) = current_scope.take() {
if let Some(lv_symbol) = scope.find_lv_symbol(declared_name) {
return Ok(lv_symbol)
} else {
current_scope = scope
.parent()
.and_then(|parent_id| self.scopes.get(parent_id));
}
}
Err(SymbolLookupError::NoDefinition)
}
}
impl Display for SymbolTable {

View File

@ -3,6 +3,7 @@ use crate::name_analysis::symbol::class_symbol::ClassSymbol;
use crate::name_analysis::symbol::function_symbol::FunctionSymbol;
use crate::name_analysis::symbol::generic_type_symbol::GenericTypeSymbol;
use crate::name_analysis::symbol::interface_symbol::InterfaceSymbol;
use crate::name_analysis::symbol::lv_symbol::LVSymbol;
use crate::name_analysis::symbol::module_level_symbol::ModuleLevelSymbol;
use crate::name_analysis::symbol::module_symbol::ModuleSymbol;
use crate::name_analysis::symbol::parameter_symbol::ParameterSymbol;
@ -26,9 +27,9 @@ pub struct Scope {
class_symbols: HashMap<Rc<str>, Rc<RefCell<ClassSymbol>>>,
generic_symbols: HashMap<Rc<str>, Rc<RefCell<GenericTypeSymbol>>>,
function_symbols: HashMap<Rc<str>, Rc<RefCell<FunctionSymbol>>>,
parameter_symbols: HashMap<Rc<str>, ParameterSymbol>,
variable_symbols: HashMap<Rc<str>, VariableSymbol>,
class_member_symbols: HashMap<Rc<str>, ClassMemberSymbol>,
parameter_symbols: HashMap<Rc<str>, Rc<RefCell<ParameterSymbol>>>,
variable_symbols: HashMap<Rc<str>, Rc<RefCell<VariableSymbol>>>,
class_member_symbols: HashMap<Rc<str>, Rc<RefCell<ClassMemberSymbol>>>,
debug_name: String,
}
@ -126,11 +127,30 @@ impl Scope {
self.class_symbols.get(declared_name)
}
pub fn insert_generic_type_symbol(&mut self, symbol: GenericTypeSymbol) -> Rc<RefCell<GenericTypeSymbol>> {
pub fn insert_generic_type_symbol(
&mut self,
symbol: GenericTypeSymbol,
) -> Rc<RefCell<GenericTypeSymbol>> {
let key = symbol.declared_name_owned();
insert_symbol!(self.generic_symbols, symbol, key)
}
pub fn insert_parameter_symbol(
&mut self,
symbol: ParameterSymbol,
) -> Rc<RefCell<ParameterSymbol>> {
let key = symbol.declared_name_owned();
insert_symbol!(self.parameter_symbols, symbol, key)
}
pub fn insert_variable_symbol(
&mut self,
symbol: VariableSymbol,
) -> Rc<RefCell<VariableSymbol>> {
let key = symbol.declared_name_owned();
insert_symbol!(self.variable_symbols, symbol, key)
}
pub fn find_module_level_symbol(&self, declared_name: &str) -> Option<ModuleLevelSymbol> {
self.module_symbols
.get(declared_name)
@ -168,6 +188,26 @@ impl Scope {
})
}
pub fn find_lv_symbol(&self, declared_name: &str) -> Option<LVSymbol> {
self.class_member_symbols
.get(declared_name)
.map(|class_member_symbol| LVSymbol::ClassMember(class_member_symbol.clone()))
.or_else(|| {
self.parameter_symbols
.get(declared_name)
.map(|parameter_symbol| LVSymbol::Parameter(parameter_symbol.clone()))
})
.or_else(|| {
self.variable_symbols
.get(declared_name)
.map(|variable_symbol| LVSymbol::Variable(variable_symbol.clone()))
})
}
pub fn find_function_symbol(&self, declared_name: &str) -> Option<&Rc<RefCell<FunctionSymbol>>> {
self.function_symbols.get(declared_name)
}
pub fn debug_name(&self) -> &str {
&self.debug_name
}

View File

@ -2,6 +2,8 @@ use crate::name_analysis::symbol::class_symbol::ClassSymbol;
use crate::name_analysis::symbol::function_symbol::FunctionSymbol;
use crate::name_analysis::symbol::interface_symbol::InterfaceSymbol;
use crate::name_analysis::symbol::module_symbol::ModuleSymbol;
use crate::name_analysis::symbol::usable_symbol::UsableSymbol;
use crate::name_analysis::symbol_table::SymbolLookupError;
use std::cell::RefCell;
use std::collections::HashMap;
use std::rc::Rc;
@ -24,35 +26,35 @@ impl SymbolTree {
}
}
pub fn find_class(&self, fqn_parts: &[&str]) -> Option<Rc<RefCell<ClassSymbol>>> {
pub fn find_class(&self, fqn_parts: &[Rc<str>]) -> Option<Rc<RefCell<ClassSymbol>>> {
match fqn_parts.len() {
0 => None,
1 => self.classes.get(fqn_parts[0]).cloned(),
1 => self.classes.get(&fqn_parts[0]).cloned(),
_ => self
.children
.get(fqn_parts[0])
.get(&fqn_parts[0])
.and_then(|child_tree| child_tree.find_class(&fqn_parts[1..])),
}
}
pub fn find_interface(&self, fqn_parts: &[&str]) -> Option<Rc<RefCell<InterfaceSymbol>>> {
pub fn find_interface(&self, fqn_parts: &[Rc<str>]) -> Option<Rc<RefCell<InterfaceSymbol>>> {
match fqn_parts.len() {
0 => None,
1 => self.interfaces.get(fqn_parts[0]).cloned(),
1 => self.interfaces.get(&fqn_parts[0]).cloned(),
_ => self
.children
.get(fqn_parts[0])
.get(&fqn_parts[0])
.and_then(|child_tree| child_tree.find_interface(&fqn_parts[1..])),
}
}
pub fn find_function(&self, fqn_parts: &[&str]) -> Option<Rc<RefCell<FunctionSymbol>>> {
pub fn find_function(&self, fqn_parts: &[Rc<str>]) -> Option<Rc<RefCell<FunctionSymbol>>> {
match fqn_parts.len() {
0 => None,
1 => self.functions.get(fqn_parts[0]).cloned(),
1 => self.functions.get(&fqn_parts[0]).cloned(),
_ => self
.children
.get(fqn_parts[0])
.get(&fqn_parts[0])
.and_then(|child_tree| child_tree.find_function(&fqn_parts[1..])),
}
}
@ -61,6 +63,15 @@ impl SymbolTree {
self.recurse_register_module(&module_symbol.borrow().fqn_parts());
}
pub fn register_module_by_fqn_parts(&mut self, fqn_parts: &[&str]) {
self.recurse_register_module(
&fqn_parts
.iter()
.map(|part| Rc::from(*part))
.collect::<Vec<Rc<str>>>(),
);
}
fn recurse_register_module(&mut self, fqn_parts: &[Rc<str>]) {
if fqn_parts.len() == 0 {
panic!("Unable to register module fqn with no parts.")
@ -85,9 +96,13 @@ impl SymbolTree {
self.recurse_register_function(function_symbol, &fqn_parts);
}
fn recurse_register_function(&mut self, function_symbol: Rc<RefCell<FunctionSymbol>>, fqn_parts: &[Rc<str>]) {
fn recurse_register_function(
&mut self,
function_symbol: Rc<RefCell<FunctionSymbol>>,
fqn_parts: &[Rc<str>],
) {
if fqn_parts.len() == 0 {
panic!("Unable to register function fqn with no parts.")
panic!("Unable to register function fqn with no parts.");
}
if fqn_parts.len() == 1 {
self.functions.insert(fqn_parts[0].clone(), function_symbol);
@ -101,4 +116,32 @@ impl SymbolTree {
}
}
pub fn find_all_by_base_fqn(
&self,
fqn_parts: &[Rc<str>],
) -> Result<Vec<UsableSymbol>, SymbolLookupError> {
match fqn_parts.len() {
0 => {
let mut all_symbols: Vec<UsableSymbol> = vec![];
for interface_symbol in self.interfaces.values() {
all_symbols.push(UsableSymbol::Interface(interface_symbol.clone()));
}
for class_symbol in self.classes.values() {
all_symbols.push(UsableSymbol::Class(class_symbol.clone()));
}
for function_symbol in self.functions.values() {
all_symbols.push(UsableSymbol::Function(function_symbol.clone()));
}
Ok(all_symbols)
}
_ => {
if self.children.contains_key(fqn_parts[0].as_ref()) {
let child = self.children.get(fqn_parts[0].as_ref()).unwrap();
child.find_all_by_base_fqn(fqn_parts)
} else {
Err(SymbolLookupError::NoSuchNamespace)
}
}
}
}
}

View File

@ -45,11 +45,19 @@ pub fn handle_lookup_error(
match err {
SymbolLookupError::NoDefinition => {
let diagnostic = Diagnostic::error()
.with_message(format!("No such symbol '{}' in scope.", error_symbol_name,))
.with_message(format!("No such symbol '{}' in scope.", error_symbol_name))
.with_label(
Label::primary(error_file_id, error_range).with_message("Symbol used here."),
);
diagnostics.push(diagnostic);
},
SymbolLookupError::NoSuchNamespace => {
let diagnostic = Diagnostic::error()
.with_message(format!("No such namespace '{}' found", error_symbol_name))
.with_label(
Label::primary(error_file_id, error_range).with_message("Namespace used here.")
);
diagnostics.push(diagnostic);
}
}
}

View File

@ -281,6 +281,10 @@ StarUseStatement:
- range:
special:
kind: range
fields:
- symbol:
kind: StarUseSymbol
wrap: rc_ref_cell
UseStatementPrefix:
struct:
children:
@ -605,6 +609,9 @@ FunctionEqualsBody:
struct:
children:
- expression
fields:
- scope_id:
kind: usize
FunctionAliasBody:
struct:
children:
@ -612,6 +619,12 @@ FunctionAliasBody:
skip:
rule: Alias
- identifier
fields:
- scope_id:
kind: usize
- resolved_function_symbol:
kind: FunctionSymbol
wrap: rc_ref_cell
FunctionBlockBody:
struct:
children:
@ -621,6 +634,9 @@ FunctionBlockBody:
- end_kw:
skip:
rule: End
fields:
- scope_id:
kind: usize
# Class constructs
ClassConstructor:
@ -677,6 +693,10 @@ VariableDeclaration:
- expression:
member:
optional: true
fields:
- variable_symbol:
kind: VariableSymbol
wrap: rc_ref_cell
AssignmentStatement:
struct:
children:
@ -782,10 +802,9 @@ VariableUse:
struct:
children:
- identifier
derive:
- PartialEq
- Eq
- Hash
fields:
- lv_symbol:
kind: LVSymbol
# Expressions
Expression:

View File

@ -7,11 +7,16 @@ use std::cell::RefCell;
use std::rc::Rc;
pub fn add_std_core_symbols(symbol_table: &mut SymbolTable) -> Result<(), SymbolInsertError> {
symbol_table.register_module(&["std"]);
symbol_table.register_module(&["std", "core"]);
symbol_table.set_current_fqn(&vec!["std", "core"]);
let println_msg_symbol = ParameterSymbol::new("msg", None, Some(
TypeSymbol::Primitive(PrimitiveTypeSymbol::Any)
));
let println_msg_symbol = ParameterSymbol::new(
"msg",
None,
Some(TypeSymbol::Primitive(PrimitiveTypeSymbol::Any)),
);
let println_symbol = FunctionSymbol::with_parameters_and_return_type(
&symbol_table.resolve_fqn(Rc::from("println")),