Major refactor of name analysis and related.

This commit is contained in:
Jesse Brault 2025-05-18 18:03:40 -05:00
parent dcb261fd84
commit 6b6ba1d712
11 changed files with 553 additions and 402 deletions

View File

@ -609,7 +609,7 @@ fn build_platform_function_declaration(
Rule::FunctionModifier => { Rule::FunctionModifier => {
modifier = Some(build_function_modifier(file_id, inner_pair)); modifier = Some(build_function_modifier(file_id, inner_pair));
} }
Rule::Platform | Rule::Fn => {}, Rule::Platform | Rule::Fn => {}
Rule::GenericParameters => { Rule::GenericParameters => {
generics = build_generic_parameters(file_id, inner_pair); generics = build_generic_parameters(file_id, inner_pair);
} }
@ -813,20 +813,20 @@ fn build_use_statement(file_id: usize, use_statement_pair: Pair<Rule>) -> UseSta
)) ))
} else { } else {
last = Some(match inner_pair.as_rule() { last = Some(match inner_pair.as_rule() {
Rule::Identifier => { Rule::Identifier => UseStatementLast::Identifier(Rc::new(RefCell::new(
UseStatementLast::Identifier(build_identifier(file_id, inner_pair)) build_identifier(file_id, inner_pair),
} ))),
Rule::Star => UseStatementLast::Star, Rule::Star => UseStatementLast::Star,
Rule::UseList => UseStatementLast::Identifiers( Rule::UseList => UseStatementLast::Identifiers(
inner_pair inner_pair
.into_inner() .into_inner()
.map(|identifier_pair| { .map(|identifier_pair| {
expect_and_use( Rc::new(RefCell::new(expect_and_use(
file_id, file_id,
identifier_pair, identifier_pair,
Rule::Identifier, Rule::Identifier,
build_identifier, build_identifier,
) )))
}) })
.collect(), .collect(),
), ),
@ -842,7 +842,7 @@ fn build_use_statement(file_id: usize, use_statement_pair: Pair<Rule>) -> UseSta
Range { Range {
start: as_span.start(), start: as_span.start(),
end: as_span.end(), end: as_span.end(),
} },
) )
} }

View File

@ -2,7 +2,9 @@ use crate::ast::named::Named;
use crate::name_analysis::symbol::Symbol; use crate::name_analysis::symbol::Symbol;
use pest::Parser; use pest::Parser;
use std::borrow::Cow; use std::borrow::Cow;
use std::cell::RefCell;
use std::range::Range; use std::range::Range;
use std::rc::Rc;
pub mod build; pub mod build;
pub mod named; pub mod named;
@ -463,8 +465,11 @@ pub struct UseStatement {
symbol: Option<Symbol>, symbol: Option<Symbol>,
} }
/// First is declared_name, second is fully_qualified_name pub struct UseStatementImport<'a> {
pub type UseStatementName = (String, String); pub declared_name: String,
pub fqn: String,
pub identifier: &'a mut Identifier,
}
impl UseStatement { impl UseStatement {
pub fn new( pub fn new(
@ -504,28 +509,6 @@ impl UseStatement {
} }
} }
pub fn names(&self) -> Vec<UseStatementName> {
let base_name = self.base_name();
use UseStatementLast::*;
match &self.last {
Identifier(identifier) => vec![(
identifier.name().to_string(),
base_name.to_string() + "::" + &identifier.name(),
)],
Identifiers(identifiers) => {
let mut names = Vec::new();
for identifier in identifiers {
names.push((
identifier.name().to_string(),
base_name.to_string() + "::" + &identifier.name(),
))
}
names
}
Star => panic!("Cannot call names() on a star UseStatement"),
}
}
pub fn is_star(&self) -> bool { pub fn is_star(&self) -> bool {
match &self.last { match &self.last {
UseStatementLast::Star => true, UseStatementLast::Star => true,
@ -552,8 +535,8 @@ impl UseStatement {
#[derive(Debug)] #[derive(Debug)]
pub enum UseStatementLast { pub enum UseStatementLast {
Identifier(Identifier), Identifier(Rc<RefCell<Identifier>>),
Identifiers(Vec<Identifier>), Identifiers(Vec<Rc<RefCell<Identifier>>>),
Star, Star,
} }

View File

@ -606,10 +606,10 @@ impl PrettyPrint for UseStatementLast {
writer.writeln_indented("UseStatementLast")?; writer.writeln_indented("UseStatementLast")?;
writer.increase_indent(); writer.increase_indent();
match self { match self {
UseStatementLast::Identifier(i) => i.pretty_print(writer)?, UseStatementLast::Identifier(i) => i.borrow().pretty_print(writer)?,
UseStatementLast::Identifiers(is) => { UseStatementLast::Identifiers(is) => {
for i in is { for i in is {
i.pretty_print(writer)?; i.borrow().pretty_print(writer)?;
} }
}, },
UseStatementLast::Star => { UseStatementLast::Star => {

View File

@ -749,7 +749,7 @@ impl Unparse for UseStatementLast {
UseStatementLast::Identifiers(identifiers) => { UseStatementLast::Identifiers(identifiers) => {
writer.write("{")?; writer.write("{")?;
for (i, identifier) in identifiers.iter().enumerate() { for (i, identifier) in identifiers.iter().enumerate() {
identifier.unparse(writer)?; identifier.borrow().unparse(writer)?;
if i != identifiers.len() - 1 { if i != identifiers.len() - 1 {
writer.write(", ")?; writer.write(", ")?;
} }
@ -757,7 +757,7 @@ impl Unparse for UseStatementLast {
writer.write("}")?; writer.write("}")?;
Ok(()) Ok(())
} }
UseStatementLast::Identifier(i) => i.unparse(writer), UseStatementLast::Identifier(i) => i.borrow().unparse(writer),
} }
} }
} }

View File

@ -6,5 +6,6 @@ pub mod module;
pub mod name_analysis; pub mod name_analysis;
pub mod object_file; pub mod object_file;
pub mod parser; pub mod parser;
mod std_core;
pub mod util; pub mod util;
pub mod vm; pub mod vm;

View File

@ -1,11 +1,13 @@
use crate::ast::named::Named; use crate::ast::named::Named;
use crate::ast::*; use crate::ast::*;
use crate::diagnostic::DmDiagnostic;
use crate::name_analysis::fqn_context::FqnContext; use crate::name_analysis::fqn_context::FqnContext;
use crate::name_analysis::symbol::*; use crate::name_analysis::symbol::*;
use crate::name_analysis::symbol_table::{ScopeLevel, SymbolInsertError, SymbolTable}; use crate::name_analysis::symbol_table::{SymbolInsertError, SymbolTable};
use codespan_reporting::diagnostic::{Diagnostic, Label}; use codespan_reporting::diagnostic::{Diagnostic, Label};
use std::cell::RefCell;
use std::range::Range; use std::range::Range;
use crate::diagnostic::DmDiagnostic; use std::rc::Rc;
fn handle_insert_error( fn handle_insert_error(
err: SymbolInsertError, err: SymbolInsertError,
@ -17,25 +19,24 @@ fn handle_insert_error(
) { ) {
match err { match err {
SymbolInsertError::SymbolAlreadyDefined(s) => { SymbolInsertError::SymbolAlreadyDefined(s) => {
let already_defined_definition = s.definition(); let mut diagnostic = Diagnostic::error()
diagnostics.push( .with_message(format!(
Diagnostic::error() "{} symbol '{}' already defined in the current scope.",
.with_message(format!( symbol_types, error_symbol_name,
"{} symbol '{}' already defined in the current scope.", ))
symbol_types, error_symbol_name, .with_label(
)) Label::primary(error_file_id, error_range)
.with_label( .with_message("Symbol duplicated here."),
Label::primary(error_file_id, error_range) );
.with_message("Symbol duplicated here."),
) if let Some(source_definition) = s.definition() {
.with_label( diagnostic = diagnostic.with_label(
Label::secondary( Label::secondary(source_definition.file_id(), source_definition.range())
already_defined_definition.file_id(),
already_defined_definition.range(),
)
.with_message("Symbol defined here."), .with_message("Symbol defined here."),
), );
); }
diagnostics.push(diagnostic);
} }
} }
} }
@ -128,10 +129,7 @@ pub(super) fn gather_compilation_unit(
fqn_context.push(namespace.name().to_string()); fqn_context.push(namespace.name().to_string());
} }
symbol_table.push_scope( symbol_table.push_scope(&format!("FileScope({})", compilation_unit.file_name));
&format!("FileScope({})", compilation_unit.file_name),
ScopeLevel::ModuleOrInterfaceOrClass,
);
for use_statement in &mut compilation_unit.use_statements { for use_statement in &mut compilation_unit.use_statements {
gather_use_statement(use_statement, symbol_table, &mut fqn_context, diagnostics) gather_use_statement(use_statement, symbol_table, &mut fqn_context, diagnostics)
} }
@ -142,6 +140,35 @@ pub(super) fn gather_compilation_unit(
assert_eq!(symbol_table.current_scope_id(), 0); assert_eq!(symbol_table.current_scope_id(), 0);
} }
fn handle_use_statement_import(
symbol_table: &mut SymbolTable,
base_name: &str,
identifier: Rc<RefCell<Identifier>>,
diagnostics: &mut Vec<DmDiagnostic>,
) {
let borrowed_identifier = identifier.borrow();
let declared_name = borrowed_identifier.name().to_string();
let insert_result = symbol_table.insert_use_statement_symbol(UseStatementSymbol::new(
&format!("{}::{}", base_name, &declared_name),
&declared_name,
Some(identifier.clone()),
));
if let Err(err) = insert_result {
handle_insert_error(
err,
&declared_name,
borrowed_identifier.file_id,
borrowed_identifier.range,
"Use statement",
diagnostics,
);
}
drop(borrowed_identifier);
identifier
.borrow_mut()
.set_scope_id(symbol_table.current_scope_id())
}
fn gather_use_statement( fn gather_use_statement(
use_statement: &mut UseStatement, use_statement: &mut UseStatement,
symbol_table: &mut SymbolTable, symbol_table: &mut SymbolTable,
@ -151,38 +178,23 @@ fn gather_use_statement(
if use_statement.is_star() { if use_statement.is_star() {
todo!() todo!()
} }
for (declared_name, fully_qualified_name) in use_statement.names() { let base_name = use_statement.base_name().to_string();
let insert_result = symbol_table.insert( match &mut use_statement.last {
&declared_name, UseStatementLast::Identifier(identifier) => {
Symbol::UseStatement(UseStatementSymbol::new( handle_use_statement_import(symbol_table, &base_name, identifier.clone(), diagnostics)
&fully_qualified_name,
&declared_name,
SourceDefinition::from_use_statement(use_statement),
)),
);
if let Err(err) = insert_result {
handle_insert_error(
err,
&declared_name,
use_statement.file_id,
use_statement.range,
"Use statement",
diagnostics,
);
} }
match &mut use_statement.last { UseStatementLast::Identifiers(identifiers) => {
UseStatementLast::Identifier(identifier) => { for identifier in identifiers {
identifier.set_scope_id(symbol_table.current_scope_id()); handle_use_statement_import(
symbol_table,
&base_name,
identifier.clone(),
diagnostics,
)
} }
UseStatementLast::Identifiers(identifiers) => {
for identifier in identifiers {
identifier.set_scope_id(symbol_table.current_scope_id());
}
}
_ => {}
} }
UseStatementLast::Star => panic!(),
} }
use_statement.set_scope_id(symbol_table.current_scope_id());
} }
fn gather_module_level_declaration( fn gather_module_level_declaration(
@ -228,15 +240,12 @@ fn gather_module_declaration(
let module_name = declaration.identifier.name(); let module_name = declaration.identifier.name();
let insert_result = symbol_table.insert( let insert_result = symbol_table.insert_module_symbol(ModuleSymbol::new(
&fqn_context.resolve(&module_name),
&module_name, &module_name,
Symbol::Module(ModuleSymbol::new( declaration.is_public,
&fqn_context.resolve(&module_name), Some(&declaration.identifier),
&module_name, ));
declaration.is_public,
&declaration.identifier,
)),
);
if let Err(err) = insert_result { if let Err(err) = insert_result {
handle_insert_error( handle_insert_error(
@ -251,10 +260,7 @@ fn gather_module_declaration(
fqn_context.push(module_name.to_string()); fqn_context.push(module_name.to_string());
symbol_table.push_scope( symbol_table.push_scope(&format!("ModuleScope({})", module_name));
&format!("Module '{}' Scope", module_name),
ScopeLevel::ModuleOrInterfaceOrClass,
);
for inner_declaration in &mut declaration.declarations { for inner_declaration in &mut declaration.declarations {
gather_module_level_declaration(inner_declaration, symbol_table, fqn_context, diagnostics); gather_module_level_declaration(inner_declaration, symbol_table, fqn_context, diagnostics);
} }
@ -270,15 +276,12 @@ fn gather_class_declaration(
let declared_name = class_declaration.identifier.name(); let declared_name = class_declaration.identifier.name();
let resolved_name = fqn_context.resolve(&declared_name); let resolved_name = fqn_context.resolve(&declared_name);
let insert_result = symbol_table.insert( let insert_result = symbol_table.insert_type_symbol(TypeSymbol::new(
&resolved_name,
&declared_name, &declared_name,
Symbol::Class(ClassSymbol::new( class_declaration.is_public,
&resolved_name, Some(&class_declaration.identifier),
&declared_name, ));
class_declaration.is_public,
&class_declaration.identifier,
)),
);
if let Err(err) = insert_result { if let Err(err) = insert_result {
handle_insert_error( handle_insert_error(
err, err,
@ -302,16 +305,13 @@ fn gather_function_definition(
let declared_name = function.identifier.name(); let declared_name = function.identifier.name();
let resolved_name = fqn_context.resolve(&declared_name); let resolved_name = fqn_context.resolve(&declared_name);
let insert_result = symbol_table.insert( let insert_result = symbol_table.insert_function_symbol(FunctionSymbol::new(
&resolved_name,
&declared_name, &declared_name,
Symbol::Function(FunctionSymbol::new( function.is_public,
&resolved_name, false,
&declared_name, Some(&function.identifier),
function.is_public, ));
false,
&function.identifier,
)),
);
if let Err(err) = insert_result { if let Err(err) = insert_result {
handle_insert_error( handle_insert_error(
@ -328,10 +328,7 @@ fn gather_function_definition(
.identifier .identifier
.set_scope_id(symbol_table.current_scope_id()); .set_scope_id(symbol_table.current_scope_id());
symbol_table.push_scope( symbol_table.push_scope(&format!("FunctionScope({})", resolved_name));
&format!("FunctionScope({})", resolved_name),
ScopeLevel::Function,
);
gather_parameters( gather_parameters(
&mut function.parameters, &mut function.parameters,
symbol_table, symbol_table,
@ -351,16 +348,13 @@ fn gather_platform_function_definition(
let declared_name = platform_function_declaration.identifier.name(); let declared_name = platform_function_declaration.identifier.name();
let fully_qualified_name = fqn_context.resolve(&declared_name); let fully_qualified_name = fqn_context.resolve(&declared_name);
let insert_result = symbol_table.insert( let insert_result = symbol_table.insert_function_symbol(FunctionSymbol::new(
&fully_qualified_name,
&declared_name, &declared_name,
Symbol::Function(FunctionSymbol::new( platform_function_declaration.is_public,
&fully_qualified_name, true,
&declared_name, Some(&platform_function_declaration.identifier),
platform_function_declaration.is_public, ));
true,
&platform_function_declaration.identifier,
)),
);
if let Err(err) = insert_result { if let Err(err) = insert_result {
handle_insert_error( handle_insert_error(
@ -379,10 +373,7 @@ fn gather_platform_function_definition(
.identifier .identifier
.set_scope_id(symbol_table.current_scope_id()); .set_scope_id(symbol_table.current_scope_id());
symbol_table.push_scope( symbol_table.push_scope(&format!("FunctionScope({})", declared_name_as_string));
&format!("FunctionScope({})", declared_name_as_string),
ScopeLevel::Function,
);
gather_parameters( gather_parameters(
&mut platform_function_declaration.parameters, &mut platform_function_declaration.parameters,
symbol_table, symbol_table,
@ -411,14 +402,10 @@ fn gather_parameter(
) { ) {
let parameter_name = parameter.identifier.name(); let parameter_name = parameter.identifier.name();
let insert_result = symbol_table.insert( let insert_result = symbol_table.insert_parameter_symbol(ParameterSymbol::new(
&parameter_name, &parameter_name,
Symbol::Variable(VariableSymbol::new( Some(&parameter.identifier),
&parameter_name, ));
false,
SourceDefinition::from_identifier(&parameter.identifier),
)),
);
if let Err(err) = insert_result { if let Err(err) = insert_result {
handle_insert_error( handle_insert_error(
@ -462,7 +449,7 @@ fn gather_block_statement(
fqn_context: &mut FqnContext, fqn_context: &mut FqnContext,
diagnostics: &mut Vec<DmDiagnostic>, diagnostics: &mut Vec<DmDiagnostic>,
) { ) {
symbol_table.push_scope("BlockStatementScope", ScopeLevel::Function); symbol_table.push_scope("BlockStatementScope");
gather_block_statement_inner(block, symbol_table, fqn_context, diagnostics); gather_block_statement_inner(block, symbol_table, fqn_context, diagnostics);
symbol_table.pop_scope(); symbol_table.pop_scope();
} }
@ -512,14 +499,11 @@ fn gather_variable_declaration(
) { ) {
let variable_name = variable_declaration.identifier.name(); let variable_name = variable_declaration.identifier.name();
let insert_result = symbol_table.insert( let insert_result = symbol_table.insert_variable_symbol(VariableSymbol::new(
&variable_name, &variable_name,
Symbol::Variable(VariableSymbol::new( variable_declaration.is_mutable,
&variable_name, Some(&variable_declaration.identifier),
variable_declaration.is_mutable, ));
SourceDefinition::from_identifier(&variable_declaration.identifier),
)),
);
if let Err(err) = insert_result { if let Err(err) = insert_result {
handle_insert_error( handle_insert_error(

View File

@ -35,6 +35,7 @@ mod tests {
use super::*; use super::*;
use crate::ast::build::build_ast; use crate::ast::build::build_ast;
use crate::parser::{DeimosParser, Rule}; use crate::parser::{DeimosParser, Rule};
use crate::std_core::add_std_core_symbols;
use codespan_reporting::files::SimpleFiles; use codespan_reporting::files::SimpleFiles;
use codespan_reporting::term; use codespan_reporting::term;
use codespan_reporting::term::termcolor::{ColorChoice, StandardStream}; use codespan_reporting::term::termcolor::{ColorChoice, StandardStream};
@ -61,6 +62,7 @@ mod tests {
} }
let mut symbol_table = SymbolTable::new(); 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, &mut symbol_table); let diagnostics = analyze_names(&mut compilation_units, &mut symbol_table);

View File

@ -1,8 +1,8 @@
use crate::ast::named::Named; use crate::ast::named::Named;
use crate::ast::*; use crate::ast::*;
use crate::name_analysis::symbol_table::{SymbolLookupError, SymbolTable};
use codespan_reporting::diagnostic::{Diagnostic, Label};
use crate::diagnostic::DmDiagnostic; use crate::diagnostic::DmDiagnostic;
use crate::name_analysis::symbol_table::SymbolTable;
use codespan_reporting::diagnostic::{Diagnostic, Label};
fn resolve_fully_qualified_name( fn resolve_fully_qualified_name(
fully_qualified_name: &mut FullyQualifiedName, fully_qualified_name: &mut FullyQualifiedName,
@ -160,30 +160,11 @@ fn resolve_use_statement(
if use_statement.is_star() { if use_statement.is_star() {
todo!() todo!()
} }
for (_, fully_qualified_name) in use_statement.names() {
let lookup_result = symbol_table.lookup_usable( match &use_statement.last {
&fully_qualified_name, UseStatementLast::Identifier(identifier) => {}
use_statement UseStatementLast::Identifiers(identifiers) => {}
.scope_id() UseStatementLast::Star => panic!(),
.expect("UseStatement.scope_id was not set."),
);
match lookup_result {
Ok(referenced_symbol) => {
use_statement.set_symbol(referenced_symbol.clone());
}
Err(err) => match err {
SymbolLookupError::NoDefinition => {
diagnostics.push(
Diagnostic::error()
.with_message(&format!(
"No definition found for symbol '{}'",
fully_qualified_name
))
.with_label(Label::primary(use_statement.file_id, use_statement.range)),
);
}
},
}
} }
} }

View File

@ -1,6 +1,8 @@
use std::cell::RefCell;
use crate::ast::{Identifier, UseStatement}; use crate::ast::{Identifier, UseStatement};
use std::fmt::Display; use std::fmt::Display;
use std::range::Range; use std::range::Range;
use std::rc::Rc;
#[derive(Clone, Debug)] #[derive(Clone, Debug)]
pub struct SourceDefinition { pub struct SourceDefinition {
@ -16,6 +18,15 @@ impl SourceDefinition {
} }
} }
pub fn from_identifier_rc(identifier: Rc<RefCell<Identifier>>) -> Self {
let borrowed = identifier.borrow();
SourceDefinition {
file_id: borrowed.file_id,
range: borrowed.range,
}
}
#[deprecated(note = "Use identifier instead.")]
pub fn from_use_statement(use_statement: &UseStatement) -> Self { pub fn from_use_statement(use_statement: &UseStatement) -> Self {
SourceDefinition { SourceDefinition {
file_id: use_statement.file_id, file_id: use_statement.file_id,
@ -32,33 +43,50 @@ impl SourceDefinition {
} }
} }
pub trait SymbolInner {
fn declared_name(&self) -> &str;
fn definition(&self) -> &Option<SourceDefinition>;
}
/* Symbol */
#[derive(Debug, Clone)] #[derive(Debug, Clone)]
pub enum Symbol { pub enum Symbol {
Function(FunctionSymbol), UseStatement(Rc<UseStatementSymbol>),
Variable(VariableSymbol), Module(Rc<ModuleSymbol>),
Module(ModuleSymbol), Type(Rc<TypeSymbol>),
Class(ClassSymbol), Function(Rc<FunctionSymbol>),
UseStatement(UseStatementSymbol), Parameter(Rc<ParameterSymbol>),
Variable(Rc<VariableSymbol>),
} }
impl Symbol { impl Symbol {
pub fn name(&self) -> &str { pub fn name(&self) -> &str {
match self { match self {
Symbol::Function(s) => s.declared_name.as_str(), Symbol::UseStatement(s) => s.declared_name(),
Symbol::Variable(s) => s.name.as_str(), Symbol::Module(s) => s.declared_name(),
Symbol::Module(s) => s.declared_name.as_str(), Symbol::Type(s) => s.declared_name(),
Symbol::Class(s) => s.declared_name.as_str(), Symbol::Function(s) => s.declared_name(),
Symbol::UseStatement(s) => s.declared_name.as_str(), Symbol::Parameter(s) => s.declared_name(),
Symbol::Variable(s) => s.declared_name(),
} }
} }
pub fn definition(&self) -> &SourceDefinition { pub fn definition(&self) -> &Option<SourceDefinition> {
match self { match self {
Symbol::Function(s) => s.definition(),
Symbol::Module(s) => s.definition(),
Symbol::Variable(s) => s.definition(),
Symbol::Class(s) => s.definition(),
Symbol::UseStatement(s) => s.definition(), Symbol::UseStatement(s) => s.definition(),
Symbol::Module(s) => s.definition(),
Symbol::Type(s) => s.definition(),
Symbol::Function(s) => s.definition(),
Symbol::Parameter(s) => s.definition(),
Symbol::Variable(s) => s.definition(),
}
}
pub fn unwrap_use_statement_symbol(&self) -> &UseStatementSymbol {
match self {
Symbol::UseStatement(s) => s,
_ => panic!("unwrap_use_statement_symbol called on non-use statement symbol"),
} }
} }
} }
@ -67,93 +95,74 @@ impl Display for Symbol {
fn fmt(&self, f: &mut std::fmt::Formatter) -> std::fmt::Result { fn fmt(&self, f: &mut std::fmt::Formatter) -> std::fmt::Result {
use Symbol::*; use Symbol::*;
match self { match self {
Function(function_symbol) => write!(f, "{}", function_symbol),
Variable(variable_symbol) => write!(f, "{}", variable_symbol),
Module(module_symbol) => write!(f, "{}", module_symbol),
Class(class_symbol) => write!(f, "{}", class_symbol),
UseStatement(use_statement_symbol) => write!(f, "{}", use_statement_symbol), UseStatement(use_statement_symbol) => write!(f, "{}", use_statement_symbol),
Module(module_symbol) => write!(f, "{}", module_symbol),
Type(class_symbol) => write!(f, "{}", class_symbol),
Function(function_symbol) => write!(f, "{}", function_symbol),
Parameter(parameter_symbol) => write!(f, "{}", parameter_symbol),
Variable(variable_symbol) => write!(f, "{}", variable_symbol),
} }
} }
} }
/* Use-statement */
#[derive(Debug, Clone)] #[derive(Debug, Clone)]
pub struct FunctionSymbol { pub struct UseStatementSymbol {
pub fqn: String, pub fqn: String,
pub declared_name: String, pub declared_name: String,
pub is_public: bool, definition: Option<SourceDefinition>,
pub is_platform: bool, referenced_symbol: Option<Box<Symbol>>
definition: SourceDefinition,
} }
impl FunctionSymbol { impl UseStatementSymbol {
pub fn new( pub fn new(fqn: &str, declared_name: &str, identifier: Option<Rc<RefCell<Identifier>>>) -> Self {
fqn: &str, UseStatementSymbol {
declared_name: &str,
is_public: bool,
is_platform: bool,
identifier: &Identifier,
) -> FunctionSymbol {
FunctionSymbol {
fqn: fqn.to_string(), fqn: fqn.to_string(),
declared_name: declared_name.to_string(), declared_name: declared_name.to_string(),
is_public, definition: identifier.map(SourceDefinition::from_identifier_rc),
is_platform, referenced_symbol: None,
definition: SourceDefinition::from_identifier(identifier),
} }
} }
fn definition(&self) -> &SourceDefinition { pub fn set_referenced_symbol(&mut self, referenced_symbol: Symbol) {
self.referenced_symbol = Some(Box::new(referenced_symbol));
}
pub fn referenced_symbol(&self) -> Option<Box<Symbol>> {
self.referenced_symbol.clone()
}
}
impl SymbolInner for UseStatementSymbol {
fn declared_name(&self) -> &str {
&self.declared_name
}
fn definition(&self) -> &Option<SourceDefinition> {
&self.definition &self.definition
} }
} }
impl Display for FunctionSymbol { impl Display for UseStatementSymbol {
fn fmt(&self, f: &mut std::fmt::Formatter) -> std::fmt::Result { fn fmt(&self, f: &mut std::fmt::Formatter) -> std::fmt::Result {
write!( write!(
f, f,
"FunctionSymbol(fqn = {}, declared_name = {}, is_public = {})", "UseStatementSymbol(fqn = {}, declared_name = {})",
self.fqn, self.declared_name, self.is_public self.fqn, self.declared_name
) )
} }
} }
#[derive(Debug, Clone)]
pub struct VariableSymbol {
pub name: String,
pub is_mutable: bool,
definition: SourceDefinition,
}
impl VariableSymbol { /* Module */
pub fn new(name: &str, is_mutable: bool, definition: SourceDefinition) -> Self {
VariableSymbol {
name: name.to_string(),
is_mutable,
definition,
}
}
pub fn definition(&self) -> &SourceDefinition { #[derive(Debug)]
&self.definition
}
}
impl Display for VariableSymbol {
fn fmt(&self, f: &mut std::fmt::Formatter) -> std::fmt::Result {
write!(
f,
"VariableSymbol(name = {}, is_mutable = {})",
self.name, self.is_mutable
)
}
}
#[derive(Debug, Clone)]
pub struct ModuleSymbol { pub struct ModuleSymbol {
pub fqn: String, fqn: String,
pub declared_name: String, declared_name: String,
pub is_public: bool, is_public: bool,
definition: SourceDefinition, definition: Option<SourceDefinition>,
} }
impl ModuleSymbol { impl ModuleSymbol {
@ -161,17 +170,23 @@ impl ModuleSymbol {
fqn: &str, fqn: &str,
declared_name: &str, declared_name: &str,
is_public: bool, is_public: bool,
identifier: &Identifier, identifier: Option<&Identifier>,
) -> ModuleSymbol { ) -> ModuleSymbol {
ModuleSymbol { ModuleSymbol {
fqn: fqn.to_string(), fqn: fqn.to_string(),
declared_name: declared_name.to_string(), declared_name: declared_name.to_string(),
is_public, is_public,
definition: SourceDefinition::from_identifier(identifier), definition: identifier.map(SourceDefinition::from_identifier),
} }
} }
}
pub fn definition(&self) -> &SourceDefinition { impl SymbolInner for ModuleSymbol {
fn declared_name(&self) -> &str {
self.declared_name.as_str()
}
fn definition(&self) -> &Option<SourceDefinition> {
&self.definition &self.definition
} }
} }
@ -186,76 +201,180 @@ impl Display for ModuleSymbol {
} }
} }
#[derive(Debug, Clone)] /* Class */
pub struct ClassSymbol {
pub fqn: String, #[derive(Debug)]
pub declared_name: String, pub struct TypeSymbol {
pub is_public: bool, fqn: String,
definition: SourceDefinition, declared_name: String,
is_public: bool,
definition: Option<SourceDefinition>,
} }
impl ClassSymbol { impl TypeSymbol {
pub fn new(fqn: &str, declared_name: &str, is_public: bool, identifier: &Identifier) -> Self { pub fn new(fqn: &str, declared_name: &str, is_public: bool, identifier: Option<&Identifier>) -> Self {
ClassSymbol { TypeSymbol {
fqn: fqn.to_string(), fqn: fqn.to_string(),
declared_name: declared_name.to_string(), declared_name: declared_name.to_string(),
is_public, is_public,
definition: SourceDefinition::from_identifier(identifier), definition: identifier.map(SourceDefinition::from_identifier),
} }
} }
pub fn definition(&self) -> &SourceDefinition { pub fn fqn(&self) -> &str {
&self.fqn
}
pub fn is_public(&self) -> bool {
self.is_public
}
}
impl SymbolInner for TypeSymbol {
fn declared_name(&self) -> &str {
&self.declared_name
}
fn definition(&self) -> &Option<SourceDefinition> {
&self.definition &self.definition
} }
} }
impl Display for ClassSymbol { impl Display for TypeSymbol {
fn fmt(&self, f: &mut std::fmt::Formatter) -> std::fmt::Result { fn fmt(&self, f: &mut std::fmt::Formatter) -> std::fmt::Result {
write!( write!(
f, f,
"ClassSymbol(fqn = {}, declared_name = {})", "TypeSymbol(fqn = {}, declared_name = {})",
self.fqn, self.declared_name self.fqn, self.declared_name
) )
} }
} }
#[derive(Debug, Clone)] /* Function */
pub struct UseStatementSymbol {
pub fqn: String, #[derive(Debug)]
pub declared_name: String, pub struct FunctionSymbol {
definition: SourceDefinition, fqn: String,
referenced_symbol: Option<Box<Symbol>> declared_name: String,
is_public: bool,
is_platform: bool,
definition: Option<SourceDefinition>,
} }
impl UseStatementSymbol { impl FunctionSymbol {
pub fn new(fqn: &str, declared_name: &str, definition: SourceDefinition) -> Self { pub fn new(
UseStatementSymbol { fqn: &str,
declared_name: &str,
is_public: bool,
is_platform: bool,
identifier: Option<&Identifier>,
) -> FunctionSymbol {
FunctionSymbol {
fqn: fqn.to_string(), fqn: fqn.to_string(),
declared_name: declared_name.to_string(), declared_name: declared_name.to_string(),
definition, is_public,
referenced_symbol: None, is_platform,
definition: identifier.map(SourceDefinition::from_identifier),
} }
} }
pub fn definition(&self) -> &SourceDefinition { pub fn fqn(&self) -> &str {
&self.definition &self.fqn
}
pub fn set_referenced_symbol(&mut self, referenced_symbol: Symbol) {
self.referenced_symbol = Some(Box::new(referenced_symbol));
}
pub fn referenced_symbol(&self) -> Option<Box<Symbol>> {
self.referenced_symbol.clone()
} }
} }
impl Display for UseStatementSymbol { impl SymbolInner for FunctionSymbol {
fn declared_name(&self) -> &str {
self.declared_name.as_str()
}
fn definition(&self) -> &Option<SourceDefinition> {
&self.definition
}
}
impl Display for FunctionSymbol {
fn fmt(&self, f: &mut std::fmt::Formatter) -> std::fmt::Result { fn fmt(&self, f: &mut std::fmt::Formatter) -> std::fmt::Result {
write!( write!(
f, f,
"UseStatementSymbol(fqn = {}, declared_name = {})", "FunctionSymbol(fqn = {}, declared_name = {}, is_public = {})",
self.fqn, self.declared_name self.fqn, self.declared_name, self.is_public
)
}
}
/* Parameter */
#[derive(Debug)]
pub struct ParameterSymbol {
declared_name: String,
definition: Option<SourceDefinition>,
}
impl ParameterSymbol {
pub fn new(declared_name: &str, identifier: Option<&Identifier>) -> Self {
ParameterSymbol {
declared_name: declared_name.to_string(),
definition: identifier.map(SourceDefinition::from_identifier),
}
}
}
impl SymbolInner for ParameterSymbol {
fn declared_name(&self) -> &str {
&self.declared_name
}
fn definition(&self) -> &Option<SourceDefinition> {
&self.definition
}
}
impl Display for ParameterSymbol {
fn fmt(&self, f: &mut std::fmt::Formatter) -> std::fmt::Result {
write!(
f,
"ParameterSymbol({})",
self.declared_name
)
}
}
/* Variable */
#[derive(Debug)]
pub struct VariableSymbol {
declared_name: String,
is_mutable: bool,
definition: Option<SourceDefinition>,
}
impl VariableSymbol {
pub fn new(declared_name: &str, is_mutable: bool, identifier: Option<&Identifier>) -> Self {
VariableSymbol {
declared_name: declared_name.to_string(),
is_mutable,
definition: identifier.map(SourceDefinition::from_identifier),
}
}
}
impl SymbolInner for VariableSymbol {
fn declared_name(&self) -> &str {
self.declared_name.as_str()
}
fn definition(&self) -> &Option<SourceDefinition> {
&self.definition
}
}
impl Display for VariableSymbol {
fn fmt(&self, f: &mut std::fmt::Formatter) -> std::fmt::Result {
write!(
f,
"VariableSymbol(name = {}, is_mutable = {})",
self.declared_name, self.is_mutable
) )
} }
} }

View File

@ -1,94 +1,109 @@
use crate::name_analysis::symbol::Symbol; use crate::name_analysis::symbol::{
FunctionSymbol, ModuleSymbol, ParameterSymbol, Symbol, SymbolInner, TypeSymbol,
UseStatementSymbol, VariableSymbol,
};
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 std::collections::HashMap; use std::collections::HashMap;
use std::fmt::Display; use std::fmt::Display;
use std::rc::Rc;
#[derive(Debug, PartialEq, Clone)] /* Scope */
pub enum ScopeLevel {
Global,
ModuleOrInterfaceOrClass,
Function,
}
#[derive(Debug)] #[derive(Debug)]
pub struct Scope { struct Scope {
level: ScopeLevel,
parent: Option<usize>, parent: Option<usize>,
use_statement_symbols: HashMap<String, Symbol>, use_statement_symbols: HashMap<String, Rc<UseStatementSymbol>>,
module_symbols: HashMap<String, Symbol>, module_symbols: HashMap<String, Rc<ModuleSymbol>>,
type_symbols: HashMap<String, Symbol>, type_symbols: HashMap<String, Rc<TypeSymbol>>,
function_symbols: HashMap<String, Symbol>, function_symbols: HashMap<String, Rc<FunctionSymbol>>,
variable_symbols: HashMap<String, Symbol>, parameter_symbols: HashMap<String, Rc<ParameterSymbol>>,
variable_symbols: HashMap<String, Rc<VariableSymbol>>,
debug_name: String, debug_name: String,
} }
impl Scope { impl Scope {
pub fn new(parent: Option<usize>, debug_name: String, level: ScopeLevel) -> Scope { pub fn new(parent: Option<usize>, debug_name: String) -> Scope {
Scope { Scope {
level,
parent, parent,
use_statement_symbols: HashMap::new(), use_statement_symbols: HashMap::new(),
module_symbols: HashMap::new(), module_symbols: HashMap::new(),
type_symbols: HashMap::new(), type_symbols: HashMap::new(),
function_symbols: HashMap::new(), function_symbols: HashMap::new(),
parameter_symbols: HashMap::new(),
variable_symbols: HashMap::new(), variable_symbols: HashMap::new(),
debug_name, debug_name,
} }
} }
pub fn level(&self) -> ScopeLevel { fn get_any_symbol(&self, name: &str) -> Option<Symbol> {
self.level.clone() self.variable_symbols.get(name)
.map(|s| Symbol::Variable(s.clone()))
.or_else(|| self.parameter_symbols.get(name).map(|s| Symbol::Parameter(s.clone())))
.or_else(|| self.function_symbols.get(name).map(|s| Symbol::Function(s.clone())))
.or_else(|| self.type_symbols.get(name).map(|ts| Symbol::Type(ts.clone())))
.or_else(|| self.module_symbols.get(name).map(|ms| Symbol::Module(ms.clone())))
} }
fn get_any_symbol(&self, name: &str) -> Option<&Symbol> { fn get_module_symbol_by_declared_name(&self, name: &str) -> Option<Rc<ModuleSymbol>> {
self.variable_symbols for module_symbol in self.module_symbols.values() {
.get(name) if module_symbol.declared_name() == name {
.or_else(|| self.function_symbols.get(name)) return Some(module_symbol.clone());
.or_else(|| self.type_symbols.get(name))
.or_else(|| self.module_symbols.get(name))
.or_else(|| self.use_statement_symbols.get(name))
}
fn get_usable_symbol(&self, fqn: &str) -> Option<&Symbol> {
for function_symbol in self.function_symbols.values() {
match function_symbol {
Symbol::Function(s) => {
if s.fqn == fqn {
return Some(function_symbol);
}
}
_ => panic!("Cannot have non-function in function_symbols."),
}
}
for type_symbol in self.type_symbols.values() {
match type_symbol {
Symbol::Class(s) => {
if s.fqn == fqn {
return Some(type_symbol);
}
}
_ => panic!("Cannot have non-class in type_symbols."),
} }
} }
None None
} }
pub fn symbols(&self) -> Vec<&Symbol> { fn get_usable_symbol_by_fqn(&self, fqn: &str) -> Option<Symbol> {
let mut symbols: Vec<&Symbol> = Vec::new(); for function_symbol in self.function_symbols.values() {
symbols.extend(self.use_statement_symbols.values()); if function_symbol.fqn() == fqn {
symbols.extend(self.module_symbols.values()); return Some(Symbol::Function(function_symbol.clone()));
symbols.extend(self.type_symbols.values()); }
symbols.extend(self.function_symbols.values()); }
symbols.extend(self.variable_symbols.values()); for type_symbol in self.type_symbols.values() {
symbols if type_symbol.fqn() == fqn {
return Some(Symbol::Type(type_symbol.clone()));
}
}
None
}
fn get_usable_symbol_by_declared_name(&self, declared_name: &str) -> Option<Symbol> {
for function_symbol in self.function_symbols.values() {
if function_symbol.declared_name() == declared_name {
return Some(Symbol::Function(function_symbol.clone()));
}
}
for type_symbol in self.type_symbols.values() {
if type_symbol.declared_name() == declared_name {
return Some(Symbol::Type(type_symbol.clone()));
}
}
None
}
fn get_value_symbol_by_declared_name(&self, declared_name: &str) -> Option<Symbol> {
for variable_symbol in self.variable_symbols.values() {
if variable_symbol.declared_name() == declared_name {
return Some(Symbol::Variable(variable_symbol.clone()));
}
}
for parameter_symbol in self.parameter_symbols.values() {
if parameter_symbol.declared_name() == declared_name {
return Some(Symbol::Parameter(parameter_symbol.clone()));
}
}
None
} }
} }
/* Symbol table */
#[derive(Debug)]
pub enum SymbolInsertError { pub enum SymbolInsertError {
SymbolAlreadyDefined(Symbol), SymbolAlreadyDefined(Symbol),
} }
#[derive(Debug)]
pub enum SymbolLookupError { pub enum SymbolLookupError {
NoDefinition, NoDefinition,
} }
@ -103,11 +118,7 @@ pub struct SymbolTable {
impl SymbolTable { impl SymbolTable {
pub fn new() -> Self { pub fn new() -> Self {
let mut t = SymbolTable { let mut t = SymbolTable {
scopes: vec![Scope::new( scopes: vec![Scope::new(None, String::from("GlobalScope"))],
None,
String::from("GlobalScope"),
ScopeLevel::Global,
)],
current_scope_id: 0, current_scope_id: 0,
}; };
t t
@ -121,12 +132,11 @@ impl SymbolTable {
&self.scopes &self.scopes
} }
pub fn push_scope(&mut self, debug_name: &str, level: ScopeLevel) { pub fn push_scope(&mut self, debug_name: &str) {
let id = self.scopes.len(); let id = self.scopes.len();
self.scopes.push(Scope::new( self.scopes.push(Scope::new(
Some(self.current_scope_id), Some(self.current_scope_id),
debug_name.to_string(), debug_name.to_string(),
level,
)); ));
self.current_scope_id = id; self.current_scope_id = id;
} }
@ -137,65 +147,112 @@ impl SymbolTable {
} }
} }
pub fn insert(&mut self, name: &str, symbol: Symbol) -> Result<(), SymbolInsertError> { pub fn insert_use_statement_symbol(
match symbol {
Symbol::Function(_) | Symbol::Variable(_) => {
self.insert_function_or_variable(name, symbol)
}
Symbol::Module(_) | Symbol::Class(_) => self.insert_module_or_type(name, symbol),
Symbol::UseStatement(_) => self.insert_use_statement_symbol(name, symbol),
}
}
fn insert_function_or_variable(
&mut self, &mut self,
name: &str, use_statement_symbol: UseStatementSymbol,
symbol: Symbol,
) -> Result<(), SymbolInsertError> { ) -> Result<(), SymbolInsertError> {
if let Some(defined_symbol) = self.scopes[self.current_scope_id] let current_scope = self.scopes.get_mut(self.current_scope_id).unwrap();
.function_symbols if let Some(defined_symbol) =
.get(name) current_scope.get_usable_symbol_by_declared_name(use_statement_symbol.declared_name())
{ {
Err(SymbolAlreadyDefined(defined_symbol.clone())) Err(SymbolAlreadyDefined(defined_symbol))
} else { } else {
self.scopes[self.current_scope_id] current_scope.use_statement_symbols.insert(
.function_symbols use_statement_symbol.declared_name().to_string(),
.insert(name.to_string(), symbol); Rc::new(use_statement_symbol),
);
Ok(()) Ok(())
} }
} }
fn insert_module_or_type( pub fn insert_module_symbol(
&mut self, &mut self,
name: &str, module_symbol: ModuleSymbol,
symbol: Symbol,
) -> Result<(), SymbolInsertError> { ) -> Result<(), SymbolInsertError> {
if let Some(defined_symbol) = self.scopes[self.current_scope_id].type_symbols.get(name) { let current_scope = self.scopes.get_mut(self.current_scope_id).unwrap();
Err(SymbolAlreadyDefined(defined_symbol.clone())) if let Some(defined_symbol) =
current_scope.get_module_symbol_by_declared_name(module_symbol.declared_name())
{
Err(SymbolAlreadyDefined(Symbol::Module(defined_symbol.clone())))
} else { } else {
self.scopes[self.current_scope_id] current_scope.module_symbols.insert(
.type_symbols module_symbol.declared_name().to_string(),
.insert(name.to_string(), symbol); Rc::new(module_symbol),
);
Ok(()) Ok(())
} }
} }
fn insert_use_statement_symbol( pub fn insert_type_symbol(&mut self, type_symbol: TypeSymbol) -> Result<(), SymbolInsertError> {
let current_scope = self.scopes.get_mut(self.current_scope_id).unwrap();
if let Some(defined_symbol) =
current_scope.get_usable_symbol_by_declared_name(type_symbol.declared_name())
{
Err(SymbolAlreadyDefined(defined_symbol))
} else {
current_scope.type_symbols.insert(
type_symbol.declared_name().to_string(),
Rc::new(type_symbol),
);
Ok(())
}
}
pub fn insert_function_symbol(
&mut self, &mut self,
name: &str, function_symbol: FunctionSymbol,
symbol: Symbol,
) -> Result<(), SymbolInsertError> { ) -> Result<(), SymbolInsertError> {
if let Some(defined_symbol) = self.scopes[self.current_scope_id].get_any_symbol(name) { let current_scope = self.scopes.get_mut(self.current_scope_id).unwrap();
Err(SymbolAlreadyDefined(defined_symbol.clone())) if let Some(defined_symbol) =
current_scope.get_usable_symbol_by_declared_name(function_symbol.declared_name())
{
Err(SymbolAlreadyDefined(defined_symbol))
} else { } else {
self.scopes[self.current_scope_id] current_scope.function_symbols.insert(
.use_statement_symbols function_symbol.declared_name().to_string(),
.insert(name.to_string(), symbol); Rc::new(function_symbol),
);
Ok(()) Ok(())
} }
} }
pub fn lookup(&self, name: &str, scope_id: usize) -> Result<&Symbol, SymbolLookupError> { pub fn insert_parameter_symbol(
&mut self,
parameter_symbol: ParameterSymbol,
) -> Result<(), SymbolInsertError> {
let current_scope = self.scopes.get_mut(self.current_scope_id).unwrap();
if let Some(defined_symbol) =
current_scope.get_value_symbol_by_declared_name(parameter_symbol.declared_name())
{
Err(SymbolAlreadyDefined(defined_symbol))
} else {
current_scope.parameter_symbols.insert(
parameter_symbol.declared_name().to_string(),
Rc::new(parameter_symbol),
);
Ok(())
}
}
pub fn insert_variable_symbol(
&mut self,
variable_symbol: VariableSymbol,
) -> Result<(), SymbolInsertError> {
let current_scope = self.scopes.get_mut(self.current_scope_id).unwrap();
if let Some(defined_symbol) =
current_scope.get_value_symbol_by_declared_name(variable_symbol.declared_name())
{
Err(SymbolAlreadyDefined(defined_symbol))
} else {
current_scope.variable_symbols.insert(
variable_symbol.declared_name().to_string(),
Rc::new(variable_symbol),
);
Ok(())
}
}
pub fn lookup(&self, name: &str, scope_id: usize) -> Result<Symbol, SymbolLookupError> {
let mut scope_opt = Some(&self.scopes[scope_id]); let mut scope_opt = Some(&self.scopes[scope_id]);
while let Some(scope) = scope_opt { while let Some(scope) = scope_opt {
if let Some(symbol) = scope.get_any_symbol(name) { if let Some(symbol) = scope.get_any_symbol(name) {
@ -210,16 +267,13 @@ impl SymbolTable {
Err(NoDefinition) Err(NoDefinition)
} }
pub fn lookup_usable( pub fn lookup_usable_by_fqn(
&self, &self,
fully_qualified_name: &str, fully_qualified_name: &str,
scope_id: usize, scope_id: usize,
) -> Result<&Symbol, SymbolLookupError> { ) -> Result<Symbol, SymbolLookupError> {
for scope in &self.scopes { for scope in &self.scopes {
if scope.level == ScopeLevel::Function { if let Some(symbol) = scope.get_usable_symbol_by_fqn(fully_qualified_name) {
continue;
}
if let Some(symbol) = scope.get_usable_symbol(fully_qualified_name) {
return Ok(symbol); return Ok(symbol);
} }
} }

27
src/std_core/mod.rs Normal file
View File

@ -0,0 +1,27 @@
use crate::name_analysis::symbol::{FunctionSymbol, Symbol, TypeSymbol};
use crate::name_analysis::symbol_table::{SymbolInsertError, SymbolTable};
pub fn add_std_core_symbols(symbol_table: &mut SymbolTable) -> Result<(), SymbolInsertError> {
symbol_table.insert_type_symbol(
TypeSymbol::new("std::core:Array", "Array", true, None),
)?;
symbol_table.insert_function_symbol(
FunctionSymbol::new(
"std::core::println",
"println",
true,
true,
None,
),
)?;
symbol_table.insert_function_symbol(
FunctionSymbol::new(
"std::core::print",
"print",
true,
true,
None,
),
)?;
Ok(())
}