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

View File

@ -2,7 +2,9 @@ use crate::ast::named::Named;
use crate::name_analysis::symbol::Symbol;
use pest::Parser;
use std::borrow::Cow;
use std::cell::RefCell;
use std::range::Range;
use std::rc::Rc;
pub mod build;
pub mod named;
@ -463,8 +465,11 @@ pub struct UseStatement {
symbol: Option<Symbol>,
}
/// First is declared_name, second is fully_qualified_name
pub type UseStatementName = (String, String);
pub struct UseStatementImport<'a> {
pub declared_name: String,
pub fqn: String,
pub identifier: &'a mut Identifier,
}
impl UseStatement {
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 {
match &self.last {
UseStatementLast::Star => true,
@ -552,8 +535,8 @@ impl UseStatement {
#[derive(Debug)]
pub enum UseStatementLast {
Identifier(Identifier),
Identifiers(Vec<Identifier>),
Identifier(Rc<RefCell<Identifier>>),
Identifiers(Vec<Rc<RefCell<Identifier>>>),
Star,
}

View File

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

View File

@ -749,7 +749,7 @@ impl Unparse for UseStatementLast {
UseStatementLast::Identifiers(identifiers) => {
writer.write("{")?;
for (i, identifier) in identifiers.iter().enumerate() {
identifier.unparse(writer)?;
identifier.borrow().unparse(writer)?;
if i != identifiers.len() - 1 {
writer.write(", ")?;
}
@ -757,7 +757,7 @@ impl Unparse for UseStatementLast {
writer.write("}")?;
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 object_file;
pub mod parser;
mod std_core;
pub mod util;
pub mod vm;

View File

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

View File

@ -35,6 +35,7 @@ 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};
@ -61,6 +62,7 @@ mod tests {
}
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);

View File

@ -1,8 +1,8 @@
use crate::ast::named::Named;
use crate::ast::*;
use crate::name_analysis::symbol_table::{SymbolLookupError, SymbolTable};
use codespan_reporting::diagnostic::{Diagnostic, Label};
use crate::diagnostic::DmDiagnostic;
use crate::name_analysis::symbol_table::SymbolTable;
use codespan_reporting::diagnostic::{Diagnostic, Label};
fn resolve_fully_qualified_name(
fully_qualified_name: &mut FullyQualifiedName,
@ -160,30 +160,11 @@ fn resolve_use_statement(
if use_statement.is_star() {
todo!()
}
for (_, fully_qualified_name) in use_statement.names() {
let lookup_result = symbol_table.lookup_usable(
&fully_qualified_name,
use_statement
.scope_id()
.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)),
);
}
},
}
match &use_statement.last {
UseStatementLast::Identifier(identifier) => {}
UseStatementLast::Identifiers(identifiers) => {}
UseStatementLast::Star => panic!(),
}
}

View File

@ -1,6 +1,8 @@
use std::cell::RefCell;
use crate::ast::{Identifier, UseStatement};
use std::fmt::Display;
use std::range::Range;
use std::rc::Rc;
#[derive(Clone, Debug)]
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 {
SourceDefinition {
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)]
pub enum Symbol {
Function(FunctionSymbol),
Variable(VariableSymbol),
Module(ModuleSymbol),
Class(ClassSymbol),
UseStatement(UseStatementSymbol),
UseStatement(Rc<UseStatementSymbol>),
Module(Rc<ModuleSymbol>),
Type(Rc<TypeSymbol>),
Function(Rc<FunctionSymbol>),
Parameter(Rc<ParameterSymbol>),
Variable(Rc<VariableSymbol>),
}
impl Symbol {
pub fn name(&self) -> &str {
match self {
Symbol::Function(s) => s.declared_name.as_str(),
Symbol::Variable(s) => s.name.as_str(),
Symbol::Module(s) => s.declared_name.as_str(),
Symbol::Class(s) => s.declared_name.as_str(),
Symbol::UseStatement(s) => s.declared_name.as_str(),
Symbol::UseStatement(s) => s.declared_name(),
Symbol::Module(s) => s.declared_name(),
Symbol::Type(s) => s.declared_name(),
Symbol::Function(s) => s.declared_name(),
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 {
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::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 {
use Symbol::*;
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),
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)]
pub struct FunctionSymbol {
pub struct UseStatementSymbol {
pub fqn: String,
pub declared_name: String,
pub is_public: bool,
pub is_platform: bool,
definition: SourceDefinition,
definition: Option<SourceDefinition>,
referenced_symbol: Option<Box<Symbol>>
}
impl FunctionSymbol {
pub fn new(
fqn: &str,
declared_name: &str,
is_public: bool,
is_platform: bool,
identifier: &Identifier,
) -> FunctionSymbol {
FunctionSymbol {
impl UseStatementSymbol {
pub fn new(fqn: &str, declared_name: &str, identifier: Option<Rc<RefCell<Identifier>>>) -> Self {
UseStatementSymbol {
fqn: fqn.to_string(),
declared_name: declared_name.to_string(),
is_public,
is_platform,
definition: SourceDefinition::from_identifier(identifier),
definition: identifier.map(SourceDefinition::from_identifier_rc),
referenced_symbol: None,
}
}
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
}
}
impl Display for FunctionSymbol {
impl Display for UseStatementSymbol {
fn fmt(&self, f: &mut std::fmt::Formatter) -> std::fmt::Result {
write!(
f,
"FunctionSymbol(fqn = {}, declared_name = {}, is_public = {})",
self.fqn, self.declared_name, self.is_public
"UseStatementSymbol(fqn = {}, declared_name = {})",
self.fqn, self.declared_name
)
}
}
#[derive(Debug, Clone)]
pub struct VariableSymbol {
pub name: String,
pub is_mutable: bool,
definition: SourceDefinition,
}
impl VariableSymbol {
pub fn new(name: &str, is_mutable: bool, definition: SourceDefinition) -> Self {
VariableSymbol {
name: name.to_string(),
is_mutable,
definition,
}
}
/* Module */
pub fn definition(&self) -> &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.name, self.is_mutable
)
}
}
#[derive(Debug, Clone)]
#[derive(Debug)]
pub struct ModuleSymbol {
pub fqn: String,
pub declared_name: String,
pub is_public: bool,
definition: SourceDefinition,
fqn: String,
declared_name: String,
is_public: bool,
definition: Option<SourceDefinition>,
}
impl ModuleSymbol {
@ -161,17 +170,23 @@ impl ModuleSymbol {
fqn: &str,
declared_name: &str,
is_public: bool,
identifier: &Identifier,
identifier: Option<&Identifier>,
) -> ModuleSymbol {
ModuleSymbol {
fqn: fqn.to_string(),
declared_name: declared_name.to_string(),
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
}
}
@ -186,76 +201,180 @@ impl Display for ModuleSymbol {
}
}
#[derive(Debug, Clone)]
pub struct ClassSymbol {
pub fqn: String,
pub declared_name: String,
pub is_public: bool,
definition: SourceDefinition,
/* Class */
#[derive(Debug)]
pub struct TypeSymbol {
fqn: String,
declared_name: String,
is_public: bool,
definition: Option<SourceDefinition>,
}
impl ClassSymbol {
pub fn new(fqn: &str, declared_name: &str, is_public: bool, identifier: &Identifier) -> Self {
ClassSymbol {
impl TypeSymbol {
pub fn new(fqn: &str, declared_name: &str, is_public: bool, identifier: Option<&Identifier>) -> Self {
TypeSymbol {
fqn: fqn.to_string(),
declared_name: declared_name.to_string(),
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
}
}
impl Display for ClassSymbol {
impl Display for TypeSymbol {
fn fmt(&self, f: &mut std::fmt::Formatter) -> std::fmt::Result {
write!(
f,
"ClassSymbol(fqn = {}, declared_name = {})",
"TypeSymbol(fqn = {}, declared_name = {})",
self.fqn, self.declared_name
)
}
}
#[derive(Debug, Clone)]
pub struct UseStatementSymbol {
pub fqn: String,
pub declared_name: String,
definition: SourceDefinition,
referenced_symbol: Option<Box<Symbol>>
/* Function */
#[derive(Debug)]
pub struct FunctionSymbol {
fqn: String,
declared_name: String,
is_public: bool,
is_platform: bool,
definition: Option<SourceDefinition>,
}
impl UseStatementSymbol {
pub fn new(fqn: &str, declared_name: &str, definition: SourceDefinition) -> Self {
UseStatementSymbol {
impl FunctionSymbol {
pub fn new(
fqn: &str,
declared_name: &str,
is_public: bool,
is_platform: bool,
identifier: Option<&Identifier>,
) -> FunctionSymbol {
FunctionSymbol {
fqn: fqn.to_string(),
declared_name: declared_name.to_string(),
definition,
referenced_symbol: None,
is_public,
is_platform,
definition: identifier.map(SourceDefinition::from_identifier),
}
}
pub fn definition(&self) -> &SourceDefinition {
&self.definition
}
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()
pub fn fqn(&self) -> &str {
&self.fqn
}
}
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 {
write!(
f,
"UseStatementSymbol(fqn = {}, declared_name = {})",
self.fqn, self.declared_name
"FunctionSymbol(fqn = {}, declared_name = {}, is_public = {})",
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::SymbolLookupError::NoDefinition;
use std::collections::HashMap;
use std::fmt::Display;
#[derive(Debug, PartialEq, Clone)]
pub enum ScopeLevel {
Global,
ModuleOrInterfaceOrClass,
Function,
}
use std::rc::Rc;
/* Scope */
#[derive(Debug)]
pub struct Scope {
level: ScopeLevel,
struct Scope {
parent: Option<usize>,
use_statement_symbols: HashMap<String, Symbol>,
module_symbols: HashMap<String, Symbol>,
type_symbols: HashMap<String, Symbol>,
function_symbols: HashMap<String, Symbol>,
variable_symbols: HashMap<String, Symbol>,
use_statement_symbols: HashMap<String, Rc<UseStatementSymbol>>,
module_symbols: HashMap<String, Rc<ModuleSymbol>>,
type_symbols: HashMap<String, Rc<TypeSymbol>>,
function_symbols: HashMap<String, Rc<FunctionSymbol>>,
parameter_symbols: HashMap<String, Rc<ParameterSymbol>>,
variable_symbols: HashMap<String, Rc<VariableSymbol>>,
debug_name: String,
}
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 {
level,
parent,
use_statement_symbols: HashMap::new(),
module_symbols: HashMap::new(),
type_symbols: HashMap::new(),
function_symbols: HashMap::new(),
parameter_symbols: HashMap::new(),
variable_symbols: HashMap::new(),
debug_name,
}
}
pub fn level(&self) -> ScopeLevel {
self.level.clone()
fn get_any_symbol(&self, name: &str) -> Option<Symbol> {
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> {
self.variable_symbols
.get(name)
.or_else(|| self.function_symbols.get(name))
.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."),
fn get_module_symbol_by_declared_name(&self, name: &str) -> Option<Rc<ModuleSymbol>> {
for module_symbol in self.module_symbols.values() {
if module_symbol.declared_name() == name {
return Some(module_symbol.clone());
}
}
None
}
pub fn symbols(&self) -> Vec<&Symbol> {
let mut symbols: Vec<&Symbol> = Vec::new();
symbols.extend(self.use_statement_symbols.values());
symbols.extend(self.module_symbols.values());
symbols.extend(self.type_symbols.values());
symbols.extend(self.function_symbols.values());
symbols.extend(self.variable_symbols.values());
symbols
fn get_usable_symbol_by_fqn(&self, fqn: &str) -> Option<Symbol> {
for function_symbol in self.function_symbols.values() {
if function_symbol.fqn() == fqn {
return Some(Symbol::Function(function_symbol.clone()));
}
}
for type_symbol in self.type_symbols.values() {
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 {
SymbolAlreadyDefined(Symbol),
}
#[derive(Debug)]
pub enum SymbolLookupError {
NoDefinition,
}
@ -103,11 +118,7 @@ pub struct SymbolTable {
impl SymbolTable {
pub fn new() -> Self {
let mut t = SymbolTable {
scopes: vec![Scope::new(
None,
String::from("GlobalScope"),
ScopeLevel::Global,
)],
scopes: vec![Scope::new(None, String::from("GlobalScope"))],
current_scope_id: 0,
};
t
@ -121,12 +132,11 @@ impl SymbolTable {
&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();
self.scopes.push(Scope::new(
Some(self.current_scope_id),
debug_name.to_string(),
level,
));
self.current_scope_id = id;
}
@ -137,65 +147,112 @@ impl SymbolTable {
}
}
pub fn insert(&mut self, name: &str, symbol: Symbol) -> Result<(), SymbolInsertError> {
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(
pub fn insert_use_statement_symbol(
&mut self,
name: &str,
symbol: Symbol,
use_statement_symbol: UseStatementSymbol,
) -> Result<(), SymbolInsertError> {
if let Some(defined_symbol) = self.scopes[self.current_scope_id]
.function_symbols
.get(name)
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(use_statement_symbol.declared_name())
{
Err(SymbolAlreadyDefined(defined_symbol.clone()))
Err(SymbolAlreadyDefined(defined_symbol))
} else {
self.scopes[self.current_scope_id]
.function_symbols
.insert(name.to_string(), symbol);
current_scope.use_statement_symbols.insert(
use_statement_symbol.declared_name().to_string(),
Rc::new(use_statement_symbol),
);
Ok(())
}
}
fn insert_module_or_type(
pub fn insert_module_symbol(
&mut self,
name: &str,
symbol: Symbol,
module_symbol: ModuleSymbol,
) -> Result<(), SymbolInsertError> {
if let Some(defined_symbol) = self.scopes[self.current_scope_id].type_symbols.get(name) {
Err(SymbolAlreadyDefined(defined_symbol.clone()))
let current_scope = self.scopes.get_mut(self.current_scope_id).unwrap();
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 {
self.scopes[self.current_scope_id]
.type_symbols
.insert(name.to_string(), symbol);
current_scope.module_symbols.insert(
module_symbol.declared_name().to_string(),
Rc::new(module_symbol),
);
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,
name: &str,
symbol: Symbol,
function_symbol: FunctionSymbol,
) -> Result<(), SymbolInsertError> {
if let Some(defined_symbol) = self.scopes[self.current_scope_id].get_any_symbol(name) {
Err(SymbolAlreadyDefined(defined_symbol.clone()))
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(function_symbol.declared_name())
{
Err(SymbolAlreadyDefined(defined_symbol))
} else {
self.scopes[self.current_scope_id]
.use_statement_symbols
.insert(name.to_string(), symbol);
current_scope.function_symbols.insert(
function_symbol.declared_name().to_string(),
Rc::new(function_symbol),
);
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]);
while let Some(scope) = scope_opt {
if let Some(symbol) = scope.get_any_symbol(name) {
@ -210,16 +267,13 @@ impl SymbolTable {
Err(NoDefinition)
}
pub fn lookup_usable(
pub fn lookup_usable_by_fqn(
&self,
fully_qualified_name: &str,
scope_id: usize,
) -> Result<&Symbol, SymbolLookupError> {
) -> Result<Symbol, SymbolLookupError> {
for scope in &self.scopes {
if scope.level == ScopeLevel::Function {
continue;
}
if let Some(symbol) = scope.get_usable_symbol(fully_qualified_name) {
if let Some(symbol) = scope.get_usable_symbol_by_fqn(fully_qualified_name) {
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(())
}