From 89f519c45f8058529521c7e583d995007eed6924 Mon Sep 17 00:00:00 2001 From: Jesse Brault Date: Wed, 11 Mar 2026 15:04:38 -0500 Subject: [PATCH] Refactor scopes and symbol table for more resiliency and classes/fields. --- dm/src/repl.rs | 15 +- dmc-lib/src/ast/call.rs | 6 +- dmc-lib/src/ast/class.rs | 3 + dmc-lib/src/ast/compilation_unit.rs | 2 +- dmc-lib/src/ast/expression_statement.rs | 2 +- dmc-lib/src/ast/extern_function.rs | 10 +- dmc-lib/src/ast/function.rs | 16 +- dmc-lib/src/ast/identifier.rs | 2 +- dmc-lib/src/ast/let_statement.rs | 14 +- dmc-lib/src/ast/parameter.rs | 10 +- dmc-lib/src/ast/statement.rs | 2 +- dmc-lib/src/ir/ir_call.rs | 9 +- dmc-lib/src/ir/ir_function.rs | 7 +- dmc-lib/src/lib.rs | 2 +- dmc-lib/src/scope.rs | 52 ------ dmc-lib/src/scope/block_scope.rs | 32 ++++ dmc-lib/src/scope/class_scope.rs | 54 ++++++ dmc-lib/src/scope/function_scope.rs | 32 ++++ dmc-lib/src/scope/mod.rs | 27 +++ dmc-lib/src/scope/module_scope.rs | 43 +++++ dmc-lib/src/symbol.rs | 164 ----------------- dmc-lib/src/symbol/class_symbol.rs | 45 +++++ dmc-lib/src/symbol/expressible_symbol.rs | 59 ++++++ dmc-lib/src/symbol/field_symbol.rs | 34 ++++ dmc-lib/src/symbol/function_symbol.rs | 71 +++++++ dmc-lib/src/symbol/mod.rs | 15 ++ dmc-lib/src/symbol/parameter_symbol.rs | 53 ++++++ dmc-lib/src/symbol/variable_symbol.rs | 58 ++++++ dmc-lib/src/symbol_table.rs | 157 ---------------- dmc-lib/src/symbol_table/helpers.rs | 136 ++++++++++++++ dmc-lib/src/symbol_table/mod.rs | 225 +++++++++++++++++++++++ dmc-lib/src/type_info.rs | 2 +- 32 files changed, 947 insertions(+), 412 deletions(-) delete mode 100644 dmc-lib/src/scope.rs create mode 100644 dmc-lib/src/scope/block_scope.rs create mode 100644 dmc-lib/src/scope/class_scope.rs create mode 100644 dmc-lib/src/scope/function_scope.rs create mode 100644 dmc-lib/src/scope/mod.rs create mode 100644 dmc-lib/src/scope/module_scope.rs delete mode 100644 dmc-lib/src/symbol.rs create mode 100644 dmc-lib/src/symbol/class_symbol.rs create mode 100644 dmc-lib/src/symbol/expressible_symbol.rs create mode 100644 dmc-lib/src/symbol/field_symbol.rs create mode 100644 dmc-lib/src/symbol/function_symbol.rs create mode 100644 dmc-lib/src/symbol/mod.rs create mode 100644 dmc-lib/src/symbol/parameter_symbol.rs create mode 100644 dmc-lib/src/symbol/variable_symbol.rs delete mode 100644 dmc-lib/src/symbol_table.rs create mode 100644 dmc-lib/src/symbol_table/helpers.rs create mode 100644 dmc-lib/src/symbol_table/mod.rs diff --git a/dm/src/repl.rs b/dm/src/repl.rs index a162179..f0dce6f 100644 --- a/dm/src/repl.rs +++ b/dm/src/repl.rs @@ -6,7 +6,8 @@ use dmc_lib::ir::ir_return::IrReturn; use dmc_lib::ir::ir_statement::IrStatement; use dmc_lib::lexer::Lexer; use dmc_lib::parser::parse_expression; -use dmc_lib::symbol::FunctionSymbol; +use dmc_lib::source_range::SourceRange; +use dmc_lib::symbol::function_symbol::FunctionSymbol; use dmc_lib::symbol_table::SymbolTable; use dmc_lib::token::TokenKind; use dvm_lib::vm::constant::{Constant, StringConstant}; @@ -100,10 +101,15 @@ fn compile_expression( let mut expression = parse_result?; let mut symbol_table = SymbolTable::new(); - // "fake" scope - symbol_table.push_scope("__repl_enter"); + + // "fake" scopes + symbol_table.push_module_scope("__repl_module"); + symbol_table.push_function_scope("__repl_function"); + expression.gather_declared_names(&mut symbol_table)?; - symbol_table.pop_scope(); + + symbol_table.pop_scope(); // function + symbol_table.pop_scope(); // module expression.check_name_usages(&symbol_table)?; expression.type_check(&symbol_table)?; @@ -125,6 +131,7 @@ fn compile_expression( // synthesize symbol let fake_function_symbol = Rc::new(RefCell::new(FunctionSymbol::new( "__repl", + SourceRange::new(0, 0), false, expression.type_info().clone(), // dubious ))); diff --git a/dmc-lib/src/ast/call.rs b/dmc-lib/src/ast/call.rs index 08e9971..076b483 100644 --- a/dmc-lib/src/ast/call.rs +++ b/dmc-lib/src/ast/call.rs @@ -4,7 +4,9 @@ use crate::diagnostic::Diagnostic; use crate::ir::ir_call::IrCall; use crate::ir::ir_expression::IrExpression; use crate::source_range::SourceRange; -use crate::symbol::{ExpressibleSymbol, FunctionSymbol}; +use crate::symbol::Symbol; +use crate::symbol::expressible_symbol::ExpressibleSymbol; +use crate::symbol::function_symbol::FunctionSymbol; use crate::symbol_table::SymbolTable; use crate::type_info::TypeInfo; use std::cell::RefCell; @@ -178,7 +180,7 @@ impl Call { .collect(); let function_symbol = self.get_callee_symbol(); IrCall::new( - function_symbol.borrow().name_owned(), + function_symbol.borrow().declared_name_owned(), arguments, function_symbol.clone(), ) diff --git a/dmc-lib/src/ast/class.rs b/dmc-lib/src/ast/class.rs index 18095fa..4d51a1d 100644 --- a/dmc-lib/src/ast/class.rs +++ b/dmc-lib/src/ast/class.rs @@ -31,6 +31,9 @@ impl Class { &mut self, symbol_table: &mut SymbolTable, ) -> Result<(), Vec> { + // 1. insert class symbol + // 2. gather fields + // 3. gather functions todo!() } diff --git a/dmc-lib/src/ast/compilation_unit.rs b/dmc-lib/src/ast/compilation_unit.rs index 2deea1e..f3011c7 100644 --- a/dmc-lib/src/ast/compilation_unit.rs +++ b/dmc-lib/src/ast/compilation_unit.rs @@ -40,7 +40,7 @@ impl CompilationUnit { &mut self, symbol_table: &mut SymbolTable, ) -> Result<(), Vec> { - symbol_table.push_scope("compilation_unit_scope"); + symbol_table.push_module_scope("compilation_unit_scope"); let mut diagnostics: Vec = vec![]; self.functions diff --git a/dmc-lib/src/ast/expression_statement.rs b/dmc-lib/src/ast/expression_statement.rs index db2334f..1772320 100644 --- a/dmc-lib/src/ast/expression_statement.rs +++ b/dmc-lib/src/ast/expression_statement.rs @@ -3,7 +3,7 @@ use crate::ast::ir_builder::IrBuilder; use crate::diagnostic::Diagnostic; use crate::ir::ir_return::IrReturn; use crate::ir::ir_statement::IrStatement; -use crate::symbol::FunctionSymbol; +use crate::symbol::function_symbol::FunctionSymbol; use crate::symbol_table::SymbolTable; use std::cell::RefCell; use std::rc::Rc; diff --git a/dmc-lib/src/ast/extern_function.rs b/dmc-lib/src/ast/extern_function.rs index 75d32c2..ea94149 100644 --- a/dmc-lib/src/ast/extern_function.rs +++ b/dmc-lib/src/ast/extern_function.rs @@ -2,7 +2,7 @@ use crate::ast::parameter::Parameter; use crate::ast::type_use::TypeUse; use crate::diagnostic::Diagnostic; use crate::source_range::SourceRange; -use crate::symbol::FunctionSymbol; +use crate::symbol::function_symbol::FunctionSymbol; use crate::symbol_table::{SymbolInsertError, SymbolTable}; pub struct ExternFunction { @@ -39,6 +39,7 @@ impl ExternFunction { let insert_result = symbol_table.insert_function_symbol(FunctionSymbol::new( &self.declared_name, + self.declared_name_source_range.clone(), true, self.return_type.to_type_info(), )); @@ -51,7 +52,7 @@ impl ExternFunction { diagnostics.push(Diagnostic::new( &format!( "Function {} already declared in current scope.", - already_declared.name() + already_declared.symbol().borrow().declared_name() ), self.declared_name_source_range.start(), self.declared_name_source_range.end(), @@ -62,7 +63,8 @@ impl ExternFunction { } }; - symbol_table.push_scope(&format!("extern_function_scope({})", &self.declared_name)); + symbol_table + .push_function_scope(&format!("extern_function_scope({})", &self.declared_name)); let mut parameter_symbols = vec![]; for parameter in &mut self.parameters { @@ -80,7 +82,7 @@ impl ExternFunction { .borrow_mut() .set_parameters(parameter_symbols); - symbol_table.pop_scope(); + symbol_table.pop_scope(); // function scope if diagnostics.is_empty() { Ok(()) diff --git a/dmc-lib/src/ast/function.rs b/dmc-lib/src/ast/function.rs index 804de82..f019fb2 100644 --- a/dmc-lib/src/ast/function.rs +++ b/dmc-lib/src/ast/function.rs @@ -6,7 +6,8 @@ use crate::diagnostic::Diagnostic; use crate::ir::ir_function::IrFunction; use crate::ir::ir_parameter::IrParameter; use crate::source_range::SourceRange; -use crate::symbol::FunctionSymbol; +use crate::symbol::Symbol; +use crate::symbol::function_symbol::FunctionSymbol; use crate::symbol_table::{SymbolInsertError, SymbolTable}; use crate::type_info::TypeInfo; use std::cell::RefCell; @@ -60,6 +61,7 @@ impl Function { // insert function symbol let insert_result = symbol_table.insert_function_symbol(FunctionSymbol::new( self.declared_name(), + self.declared_name_source_range.clone(), false, self.return_type .as_ref() @@ -76,7 +78,7 @@ impl Function { diagnostics.push(Diagnostic::new( &format!( "Function {} already declared in current scope", - already_declared.name() + already_declared.symbol().borrow().declared_name() ), self.declared_name_source_range.start(), self.declared_name_source_range.end(), @@ -91,7 +93,7 @@ impl Function { self.function_symbol = Some(function_symbol.clone()); // handle parameters - symbol_table.push_scope(&format!("parameter_scope({})", self.declared_name)); + symbol_table.push_function_scope(&format!("function_scope({})", self.declared_name)); let mut parameter_symbols = vec![]; for parameter in &mut self.parameters { match parameter.gather_declared_names(symbol_table) { @@ -107,7 +109,7 @@ impl Function { .borrow_mut() .set_parameters(parameter_symbols); - symbol_table.push_scope(&format!("body_scope({})", self.declared_name)); + symbol_table.push_block_scope(&format!("main_block_scope({})", self.declared_name)); for statement in &mut self.statements { match statement.gather_declared_names(symbol_table) { Ok(_) => {} @@ -116,8 +118,8 @@ impl Function { } } } - symbol_table.pop_scope(); // body - symbol_table.pop_scope(); // params + symbol_table.pop_scope(); // main block scope + symbol_table.pop_scope(); // function scope if diagnostics.is_empty() { Ok(()) @@ -204,7 +206,7 @@ impl Function { let parameter_symbol = parameter.parameter_symbol(); let stack_offset = (self.parameters.len() as isize).neg() + (i as isize); let ir_parameter = IrParameter::new( - parameter_symbol.borrow().name(), + parameter_symbol.borrow().declared_name(), parameter_symbol.borrow().type_info().clone(), stack_offset, ); diff --git a/dmc-lib/src/ast/identifier.rs b/dmc-lib/src/ast/identifier.rs index 85efe97..90bc1c2 100644 --- a/dmc-lib/src/ast/identifier.rs +++ b/dmc-lib/src/ast/identifier.rs @@ -1,6 +1,6 @@ use crate::diagnostic::Diagnostic; use crate::source_range::SourceRange; -use crate::symbol::ExpressibleSymbol; +use crate::symbol::expressible_symbol::ExpressibleSymbol; use crate::symbol_table::SymbolTable; use crate::type_info::TypeInfo; diff --git a/dmc-lib/src/ast/let_statement.rs b/dmc-lib/src/ast/let_statement.rs index 90952dc..5c2292f 100644 --- a/dmc-lib/src/ast/let_statement.rs +++ b/dmc-lib/src/ast/let_statement.rs @@ -7,13 +7,13 @@ use crate::ir::ir_operation::IrOperation; use crate::ir::ir_statement::IrStatement; use crate::ir::ir_variable::IrVariable; use crate::source_range::SourceRange; -use crate::symbol::VariableSymbol; +use crate::symbol::variable_symbol::VariableSymbol; use crate::symbol_table::{SymbolInsertError, SymbolTable}; use std::cell::RefCell; use std::rc::Rc; pub struct LetStatement { - declared_name: String, + declared_name: Rc, declared_name_source_range: SourceRange, initializer: Box, scope_id: Option, @@ -26,7 +26,7 @@ impl LetStatement { initializer: Expression, ) -> Self { Self { - declared_name: declared_name.to_string(), + declared_name: declared_name.into(), declared_name_source_range, initializer: initializer.into(), scope_id: None, @@ -58,15 +58,17 @@ impl LetStatement { } } - let insert_result = - symbol_table.insert_variable_symbol(VariableSymbol::new(self.declared_name())); + let insert_result = symbol_table.insert_variable_symbol(VariableSymbol::new( + &self.declared_name, + self.declared_name_source_range.clone(), + )); if let Err(symbol_insert_error) = insert_result { match symbol_insert_error { SymbolInsertError::AlreadyDeclared(already_declared) => { diagnostics.push(Diagnostic::new( &format!( "Symbol {} already declared in current scope", - already_declared.name() + already_declared.symbol().borrow().declared_name() ), self.declared_name_source_range.start(), self.declared_name_source_range.end(), diff --git a/dmc-lib/src/ast/parameter.rs b/dmc-lib/src/ast/parameter.rs index 144d845..daf85ed 100644 --- a/dmc-lib/src/ast/parameter.rs +++ b/dmc-lib/src/ast/parameter.rs @@ -1,14 +1,14 @@ use crate::ast::type_use::TypeUse; use crate::diagnostic::Diagnostic; use crate::source_range::SourceRange; -use crate::symbol::ParameterSymbol; +use crate::symbol::parameter_symbol::ParameterSymbol; use crate::symbol_table::{SymbolInsertError, SymbolTable}; use crate::type_info::TypeInfo; use std::cell::RefCell; use std::rc::Rc; pub struct Parameter { - declared_name: String, + declared_name: Rc, declared_name_source_range: SourceRange, type_use: TypeUse, parameter_symbol: Option>>, @@ -34,6 +34,7 @@ impl Parameter { ) -> Result>, Vec> { let insert_result = symbol_table.insert_parameter_symbol(ParameterSymbol::new( &self.declared_name, + self.declared_name_source_range.clone(), TypeInfo::from_declared_name(self.type_use.declared_name()), )); match insert_result { @@ -43,7 +44,10 @@ impl Parameter { } Err(symbol_insert_error) => match symbol_insert_error { SymbolInsertError::AlreadyDeclared(already_declared) => Err(vec![Diagnostic::new( - &format!("Parameter {} already declared.", already_declared.name()), + &format!( + "Parameter {} already declared.", + already_declared.symbol().borrow().declared_name() + ), self.declared_name_source_range.start(), self.declared_name_source_range.end(), )]), diff --git a/dmc-lib/src/ast/statement.rs b/dmc-lib/src/ast/statement.rs index d251785..03abe73 100644 --- a/dmc-lib/src/ast/statement.rs +++ b/dmc-lib/src/ast/statement.rs @@ -2,7 +2,7 @@ use crate::ast::expression_statement::ExpressionStatement; use crate::ast::ir_builder::IrBuilder; use crate::ast::let_statement::LetStatement; use crate::diagnostic::Diagnostic; -use crate::symbol::FunctionSymbol; +use crate::symbol::function_symbol::FunctionSymbol; use crate::symbol_table::SymbolTable; use std::cell::RefCell; use std::rc::Rc; diff --git a/dmc-lib/src/ir/ir_call.rs b/dmc-lib/src/ir/ir_call.rs index b55fd1e..b6a23ba 100644 --- a/dmc-lib/src/ir/ir_call.rs +++ b/dmc-lib/src/ir/ir_call.rs @@ -3,7 +3,8 @@ use crate::ir::assemble::{Assemble, InstructionsBuilder}; use crate::ir::ir_expression::IrExpression; use crate::ir::ir_variable::IrVrVariableDescriptor; use crate::ir::register_allocation::{OffsetCounter, VrUser}; -use crate::symbol::FunctionSymbol; +use crate::symbol::Symbol; +use crate::symbol::function_symbol::FunctionSymbol; use dvm_lib::instruction::Instruction; use std::cell::RefCell; use std::collections::{HashMap, HashSet}; @@ -67,14 +68,14 @@ impl Assemble for IrCall { .map(|ir_expression| ir_expression.push_operand(constants_table)) .for_each(|push_operand| builder.push(Instruction::Push(push_operand))); let symbol = self.function_symbol.borrow(); - if symbol.is_platform() { + if symbol.is_extern() { builder.push(Instruction::InvokePlatformStatic( - symbol.name_owned(), + symbol.declared_name_owned(), symbol.parameters().len(), )); } else { builder.push(Instruction::InvokeStatic( - symbol.name_owned(), + symbol.declared_name_owned(), symbol.parameters().len(), )); } diff --git a/dmc-lib/src/ir/ir_function.rs b/dmc-lib/src/ir/ir_function.rs index ffc6b12..b183c9b 100644 --- a/dmc-lib/src/ir/ir_function.rs +++ b/dmc-lib/src/ir/ir_function.rs @@ -4,7 +4,8 @@ use crate::ir::ir_block::IrBlock; use crate::ir::ir_parameter::IrParameter; use crate::ir::ir_variable::IrVrVariableDescriptor; use crate::ir::register_allocation::HasVrUsers; -use crate::symbol::FunctionSymbol; +use crate::symbol::Symbol; +use crate::symbol::function_symbol::FunctionSymbol; use crate::type_info::TypeInfo; use dvm_lib::vm::function::Function; use std::cell::RefCell; @@ -46,7 +47,7 @@ impl IrFunction { self.entry.borrow().assemble(&mut builder, constants_table); let instructions = builder.take_instructions(); Function::new( - self.function_symbol.borrow().name_owned(), + self.function_symbol.borrow().declared_name_owned(), self.parameters.len(), stack_size, instructions, @@ -56,7 +57,7 @@ impl IrFunction { impl Display for IrFunction { fn fmt(&self, f: &mut std::fmt::Formatter<'_>) -> std::fmt::Result { - write!(f, "fn {}(", self.function_symbol.borrow().name())?; + write!(f, "fn {}(", self.function_symbol.borrow().declared_name())?; for (i, parameter) in self.parameters.iter().enumerate() { write!(f, "{}: {}", parameter, parameter.type_info())?; if i < self.parameters.len() - 1 { diff --git a/dmc-lib/src/lib.rs b/dmc-lib/src/lib.rs index 14dc205..8902917 100644 --- a/dmc-lib/src/lib.rs +++ b/dmc-lib/src/lib.rs @@ -4,7 +4,7 @@ pub mod diagnostic; pub mod ir; pub mod lexer; pub mod parser; -pub mod scope; +mod scope; pub mod source_range; pub mod symbol; pub mod symbol_table; diff --git a/dmc-lib/src/scope.rs b/dmc-lib/src/scope.rs deleted file mode 100644 index 5804a53..0000000 --- a/dmc-lib/src/scope.rs +++ /dev/null @@ -1,52 +0,0 @@ -use crate::symbol::{FunctionSymbol, ParameterSymbol, VariableSymbol}; -use std::cell::RefCell; -use std::collections::HashMap; -use std::rc::Rc; - -pub struct Scope { - debug_name: String, - parent_id: Option, - function_symbols: HashMap, Rc>>, - parameter_symbols: HashMap, Rc>>, - variable_symbols: HashMap, Rc>>, -} - -impl Scope { - pub fn new(debug_name: &str, parent_id: Option) -> Self { - Self { - debug_name: debug_name.into(), - parent_id, - function_symbols: HashMap::new(), - parameter_symbols: HashMap::new(), - variable_symbols: HashMap::new(), - } - } - - pub fn function_symbols(&self) -> &HashMap, Rc>> { - &self.function_symbols - } - - pub fn function_symbols_mut(&mut self) -> &mut HashMap, Rc>> { - &mut self.function_symbols - } - - pub fn parameter_symbols(&self) -> &HashMap, Rc>> { - &self.parameter_symbols - } - - pub fn parameter_symbols_mut(&mut self) -> &mut HashMap, Rc>> { - &mut self.parameter_symbols - } - - pub fn variable_symbols(&self) -> &HashMap, Rc>> { - &self.variable_symbols - } - - pub fn variable_symbols_mut(&mut self) -> &mut HashMap, Rc>> { - &mut self.variable_symbols - } - - pub fn parent_id(&self) -> Option { - self.parent_id - } -} diff --git a/dmc-lib/src/scope/block_scope.rs b/dmc-lib/src/scope/block_scope.rs new file mode 100644 index 0000000..4c0a40f --- /dev/null +++ b/dmc-lib/src/scope/block_scope.rs @@ -0,0 +1,32 @@ +use crate::symbol::variable_symbol::VariableSymbol; +use std::cell::RefCell; +use std::collections::HashMap; +use std::rc::Rc; + +pub struct BlockScope { + debug_name: String, + parent_id: usize, + variable_symbols: HashMap, Rc>>, +} + +impl BlockScope { + pub fn new(debug_name: &str, parent_id: usize) -> Self { + Self { + debug_name: debug_name.into(), + parent_id, + variable_symbols: HashMap::new(), + } + } + + pub fn variable_symbols(&self) -> &HashMap, Rc>> { + &self.variable_symbols + } + + pub fn variable_symbols_mut(&mut self) -> &mut HashMap, Rc>> { + &mut self.variable_symbols + } + + pub fn parent_id(&self) -> usize { + self.parent_id + } +} diff --git a/dmc-lib/src/scope/class_scope.rs b/dmc-lib/src/scope/class_scope.rs new file mode 100644 index 0000000..b2cfd20 --- /dev/null +++ b/dmc-lib/src/scope/class_scope.rs @@ -0,0 +1,54 @@ +use crate::symbol::class_symbol::ClassSymbol; +use crate::symbol::field_symbol::FieldSymbol; +use crate::symbol::function_symbol::FunctionSymbol; +use std::cell::RefCell; +use std::collections::HashMap; +use std::rc::Rc; + +pub struct ClassScope { + debug_name: String, + parent_id: usize, + class_symbols: HashMap, Rc>>, + field_symbols: HashMap, Rc>>, + function_symbols: HashMap, Rc>>, +} + +impl ClassScope { + pub fn new(debug_name: &str, parent_id: usize) -> Self { + Self { + debug_name: debug_name.into(), + parent_id, + class_symbols: HashMap::new(), + field_symbols: HashMap::new(), + function_symbols: HashMap::new(), + } + } + + pub fn class_symbols(&self) -> &HashMap, Rc>> { + &self.class_symbols + } + + pub fn class_symbols_mut(&mut self) -> &mut HashMap, Rc>> { + &mut self.class_symbols + } + + pub fn field_symbols(&self) -> &HashMap, Rc>> { + &self.field_symbols + } + + pub fn field_symbols_mut(&mut self) -> &mut HashMap, Rc>> { + &mut self.field_symbols + } + + pub fn function_symbols(&self) -> &HashMap, Rc>> { + &self.function_symbols + } + + pub fn function_symbols_mut(&mut self) -> &mut HashMap, Rc>> { + &mut self.function_symbols + } + + pub fn parent_id(&self) -> usize { + self.parent_id + } +} diff --git a/dmc-lib/src/scope/function_scope.rs b/dmc-lib/src/scope/function_scope.rs new file mode 100644 index 0000000..0090041 --- /dev/null +++ b/dmc-lib/src/scope/function_scope.rs @@ -0,0 +1,32 @@ +use crate::symbol::parameter_symbol::ParameterSymbol; +use std::cell::RefCell; +use std::collections::HashMap; +use std::rc::Rc; + +pub struct FunctionScope { + debug_name: String, + parent_id: usize, + parameter_symbols: HashMap, Rc>>, +} + +impl FunctionScope { + pub fn new(debug_name: &str, parent_id: usize) -> Self { + Self { + debug_name: debug_name.into(), + parent_id, + parameter_symbols: HashMap::new(), + } + } + + pub fn parameter_symbols(&self) -> &HashMap, Rc>> { + &self.parameter_symbols + } + + pub fn parameter_symbols_mut(&mut self) -> &mut HashMap, Rc>> { + &mut self.parameter_symbols + } + + pub fn parent_id(&self) -> usize { + self.parent_id + } +} diff --git a/dmc-lib/src/scope/mod.rs b/dmc-lib/src/scope/mod.rs new file mode 100644 index 0000000..d0fa25d --- /dev/null +++ b/dmc-lib/src/scope/mod.rs @@ -0,0 +1,27 @@ +use crate::scope::block_scope::BlockScope; +use crate::scope::class_scope::ClassScope; +use crate::scope::function_scope::FunctionScope; +use crate::scope::module_scope::ModuleScope; + +pub mod block_scope; +pub mod class_scope; +pub mod function_scope; +pub mod module_scope; + +pub enum Scope { + Module(ModuleScope), + Class(ClassScope), + Function(FunctionScope), + Block(BlockScope), +} + +impl Scope { + pub fn parent_id(&self) -> Option { + match self { + Scope::Module(module_scope) => module_scope.parent_id(), + Scope::Class(class_scope) => Some(class_scope.parent_id()), + Scope::Function(function_scope) => Some(function_scope.parent_id()), + Scope::Block(block_scope) => Some(block_scope.parent_id()), + } + } +} diff --git a/dmc-lib/src/scope/module_scope.rs b/dmc-lib/src/scope/module_scope.rs new file mode 100644 index 0000000..0d9644f --- /dev/null +++ b/dmc-lib/src/scope/module_scope.rs @@ -0,0 +1,43 @@ +use crate::symbol::class_symbol::ClassSymbol; +use crate::symbol::function_symbol::FunctionSymbol; +use std::cell::RefCell; +use std::collections::HashMap; +use std::rc::Rc; + +pub struct ModuleScope { + debug_name: String, + parent_id: Option, + class_symbols: HashMap, Rc>>, + function_symbols: HashMap, Rc>>, +} + +impl ModuleScope { + pub fn new(debug_name: &str, parent_id: Option) -> Self { + Self { + debug_name: debug_name.into(), + parent_id, + class_symbols: HashMap::new(), + function_symbols: HashMap::new(), + } + } + + pub fn class_symbols(&self) -> &HashMap, Rc>> { + &self.class_symbols + } + + pub fn class_symbols_mut(&mut self) -> &mut HashMap, Rc>> { + &mut self.class_symbols + } + + pub fn function_symbols(&self) -> &HashMap, Rc>> { + &self.function_symbols + } + + pub fn function_symbols_mut(&mut self) -> &mut HashMap, Rc>> { + &mut self.function_symbols + } + + pub fn parent_id(&self) -> Option { + self.parent_id + } +} diff --git a/dmc-lib/src/symbol.rs b/dmc-lib/src/symbol.rs deleted file mode 100644 index fbf3c30..0000000 --- a/dmc-lib/src/symbol.rs +++ /dev/null @@ -1,164 +0,0 @@ -use crate::ir::ir_expression::IrExpression; -use crate::ir::ir_parameter::IrParameter; -use crate::ir::ir_variable::IrVariable; -use crate::type_info::TypeInfo; -use std::cell::RefCell; -use std::rc::Rc; - -pub struct FunctionSymbol { - name: Rc, - is_platform: bool, - parameters: Option>>>, - return_type: TypeInfo, -} - -impl FunctionSymbol { - pub fn new(name: &str, is_platform: bool, return_type: TypeInfo) -> Self { - Self { - name: name.into(), - is_platform, - parameters: None, - return_type, - } - } - - pub fn name(&self) -> &str { - &self.name - } - - pub fn name_owned(&self) -> Rc { - self.name.clone() - } - - pub fn set_parameters(&mut self, parameters: Vec>>) { - self.parameters = Some(parameters); - } - - pub fn parameters(&self) -> &[Rc>] { - self.parameters.as_ref().unwrap() - } - - pub fn return_type_info(&self) -> &TypeInfo { - &self.return_type - } - - pub fn is_platform(&self) -> bool { - self.is_platform - } -} - -pub struct ParameterSymbol { - name: Rc, - type_info: TypeInfo, - ir_parameter: Option>, -} - -impl ParameterSymbol { - pub fn new(name: &str, type_info: TypeInfo) -> Self { - Self { - name: name.into(), - type_info, - ir_parameter: None, - } - } - - pub fn name(&self) -> &str { - &self.name - } - - pub fn name_owned(&self) -> Rc { - self.name.clone() - } - - pub fn type_info(&self) -> &TypeInfo { - &self.type_info - } - - pub fn set_ir_parameter(&mut self, ir_parameter: Rc) { - self.ir_parameter = Some(ir_parameter); - } - - pub fn ir_parameter(&self) -> &Rc { - self.ir_parameter.as_ref().unwrap() - } -} - -pub struct VariableSymbol { - name: Rc, - type_info: Option, - vr_variable: Option>>, -} - -impl VariableSymbol { - pub fn new(name: &str) -> Self { - Self { - name: name.into(), - type_info: None, - vr_variable: None, - } - } - - pub fn name(&self) -> &str { - &self.name - } - - pub fn name_owned(&self) -> Rc { - self.name.clone() - } - - pub fn set_type_info(&mut self, type_info: TypeInfo) { - self.type_info = Some(type_info); - } - - pub fn type_info(&self) -> &TypeInfo { - self.type_info - .as_ref() - .expect("TypeInfo not initialized. Did you type check?") - } - - pub fn set_vr_variable(&mut self, ir_variable: Rc>) { - self.vr_variable = Some(ir_variable); - } - - pub fn vr_variable(&self) -> &Rc> { - self.vr_variable - .as_ref() - .expect("ir_variable not yet initialized") - } -} - -pub enum ExpressibleSymbol { - Function(Rc>), - Parameter(Rc>), - Variable(Rc>), -} - -impl ExpressibleSymbol { - pub fn type_info(&self) -> TypeInfo { - match self { - ExpressibleSymbol::Function(function_symbol) => { - TypeInfo::Function(function_symbol.clone()) // n.b. not the return type! - } - ExpressibleSymbol::Parameter(parameter_symbol) => { - parameter_symbol.borrow().type_info().clone() - } - ExpressibleSymbol::Variable(variable_symbol) => { - variable_symbol.borrow().type_info().clone() - } - } - } - - pub fn ir_expression(&self) -> IrExpression { - match self { - ExpressibleSymbol::Function(_) => { - panic!("Cannot get ir_variable for FunctionSymbol"); - } - ExpressibleSymbol::Parameter(parameter_symbol) => { - IrExpression::Parameter(parameter_symbol.borrow().ir_parameter().clone()) - } - ExpressibleSymbol::Variable(variable_symbol) => { - IrExpression::Variable(variable_symbol.borrow().vr_variable().clone()) - } - } - } -} diff --git a/dmc-lib/src/symbol/class_symbol.rs b/dmc-lib/src/symbol/class_symbol.rs new file mode 100644 index 0000000..c25181a --- /dev/null +++ b/dmc-lib/src/symbol/class_symbol.rs @@ -0,0 +1,45 @@ +use crate::source_range::SourceRange; +use crate::symbol::Symbol; +use crate::symbol::field_symbol::FieldSymbol; +use crate::symbol::function_symbol::FunctionSymbol; +use std::cell::RefCell; +use std::collections::HashMap; +use std::rc::Rc; + +pub struct ClassSymbol { + declared_name: Rc, + declared_name_source_range: SourceRange, + is_extern: bool, + fields: HashMap, Rc>>, + functions: HashMap, Rc>>, +} + +impl ClassSymbol { + pub fn new( + declared_name: &Rc, + declared_name_source_range: SourceRange, + is_extern: bool, + ) -> Self { + Self { + declared_name: declared_name.clone(), + declared_name_source_range, + is_extern, + fields: HashMap::new(), + functions: HashMap::new(), + } + } +} + +impl Symbol for ClassSymbol { + fn declared_name(&self) -> &str { + &self.declared_name + } + + fn declared_name_owned(&self) -> Rc { + self.declared_name.clone() + } + + fn declared_name_source_range(&self) -> &SourceRange { + &self.declared_name_source_range + } +} diff --git a/dmc-lib/src/symbol/expressible_symbol.rs b/dmc-lib/src/symbol/expressible_symbol.rs new file mode 100644 index 0000000..226cbe8 --- /dev/null +++ b/dmc-lib/src/symbol/expressible_symbol.rs @@ -0,0 +1,59 @@ +use crate::ir::ir_expression::IrExpression; +use crate::symbol::class_symbol::ClassSymbol; +use crate::symbol::field_symbol::FieldSymbol; +use crate::symbol::function_symbol::FunctionSymbol; +use crate::symbol::parameter_symbol::ParameterSymbol; +use crate::symbol::variable_symbol::VariableSymbol; +use crate::type_info::TypeInfo; +use std::cell::RefCell; +use std::rc::Rc; + +pub enum ExpressibleSymbol { + Class(Rc>), + Field(Rc>), + Function(Rc>), + Parameter(Rc>), + Variable(Rc>), +} + +impl ExpressibleSymbol { + pub fn type_info(&self) -> TypeInfo { + match self { + ExpressibleSymbol::Class(class_symbol) => { + todo!() + } + ExpressibleSymbol::Field(field_symbol) => { + todo!() + } + ExpressibleSymbol::Function(function_symbol) => { + TypeInfo::Function(function_symbol.clone()) // n.b. not the return type! + } + ExpressibleSymbol::Parameter(parameter_symbol) => { + parameter_symbol.borrow().type_info().clone() + } + ExpressibleSymbol::Variable(variable_symbol) => { + variable_symbol.borrow().type_info().clone() + } + } + } + + pub fn ir_expression(&self) -> IrExpression { + match self { + ExpressibleSymbol::Class(class_symbol) => { + todo!() + } + ExpressibleSymbol::Field(field_symbol) => { + todo!() + } + ExpressibleSymbol::Function(_) => { + panic!("Cannot get ir_variable for FunctionSymbol"); + } + ExpressibleSymbol::Parameter(parameter_symbol) => { + IrExpression::Parameter(parameter_symbol.borrow().ir_parameter().clone()) + } + ExpressibleSymbol::Variable(variable_symbol) => { + IrExpression::Variable(variable_symbol.borrow().vr_variable().clone()) + } + } + } +} diff --git a/dmc-lib/src/symbol/field_symbol.rs b/dmc-lib/src/symbol/field_symbol.rs new file mode 100644 index 0000000..6b50581 --- /dev/null +++ b/dmc-lib/src/symbol/field_symbol.rs @@ -0,0 +1,34 @@ +use crate::source_range::SourceRange; +use crate::symbol::Symbol; +use crate::type_info::TypeInfo; +use std::rc::Rc; + +pub struct FieldSymbol { + declared_name: Rc, + declared_name_source_range: SourceRange, + type_info: Option, +} + +impl FieldSymbol { + pub fn new(declared_name: &Rc, declared_name_source_range: SourceRange) -> Self { + Self { + declared_name: declared_name.clone(), + declared_name_source_range, + type_info: None, + } + } +} + +impl Symbol for FieldSymbol { + fn declared_name(&self) -> &str { + &self.declared_name + } + + fn declared_name_owned(&self) -> Rc { + self.declared_name.clone() + } + + fn declared_name_source_range(&self) -> &SourceRange { + &self.declared_name_source_range + } +} diff --git a/dmc-lib/src/symbol/function_symbol.rs b/dmc-lib/src/symbol/function_symbol.rs new file mode 100644 index 0000000..f584403 --- /dev/null +++ b/dmc-lib/src/symbol/function_symbol.rs @@ -0,0 +1,71 @@ +use crate::source_range::SourceRange; +use crate::symbol::Symbol; +use crate::symbol::parameter_symbol::ParameterSymbol; +use crate::type_info::TypeInfo; +use std::cell::RefCell; +use std::rc::Rc; + +pub struct FunctionSymbol { + declared_name: Rc, + declared_name_source_range: SourceRange, + is_extern: bool, + parameters: Option>>>, + return_type: TypeInfo, +} + +impl FunctionSymbol { + pub fn new( + declared_name: &str, + declared_name_source_range: SourceRange, + is_extern: bool, + return_type: TypeInfo, + ) -> Self { + Self { + declared_name: declared_name.into(), + declared_name_source_range, + is_extern, + parameters: None, + return_type, + } + } + + #[deprecated(note = "use declared_name")] + pub fn name(&self) -> &str { + &self.declared_name + } + + #[deprecated(note = "use declared_name_owned")] + pub fn name_owned(&self) -> Rc { + self.declared_name.clone() + } + + pub fn set_parameters(&mut self, parameters: Vec>>) { + self.parameters = Some(parameters); + } + + pub fn parameters(&self) -> &[Rc>] { + self.parameters.as_ref().unwrap() + } + + pub fn return_type_info(&self) -> &TypeInfo { + &self.return_type + } + + pub fn is_extern(&self) -> bool { + self.is_extern + } +} + +impl Symbol for FunctionSymbol { + fn declared_name(&self) -> &str { + &self.declared_name + } + + fn declared_name_owned(&self) -> Rc { + self.declared_name.clone() + } + + fn declared_name_source_range(&self) -> &SourceRange { + &self.declared_name_source_range + } +} diff --git a/dmc-lib/src/symbol/mod.rs b/dmc-lib/src/symbol/mod.rs new file mode 100644 index 0000000..2f16e74 --- /dev/null +++ b/dmc-lib/src/symbol/mod.rs @@ -0,0 +1,15 @@ +use crate::source_range::SourceRange; +use std::rc::Rc; + +pub mod class_symbol; +pub mod expressible_symbol; +pub mod field_symbol; +pub mod function_symbol; +pub mod parameter_symbol; +pub mod variable_symbol; + +pub trait Symbol { + fn declared_name(&self) -> &str; + fn declared_name_owned(&self) -> Rc; + fn declared_name_source_range(&self) -> &SourceRange; +} diff --git a/dmc-lib/src/symbol/parameter_symbol.rs b/dmc-lib/src/symbol/parameter_symbol.rs new file mode 100644 index 0000000..aa8b480 --- /dev/null +++ b/dmc-lib/src/symbol/parameter_symbol.rs @@ -0,0 +1,53 @@ +use crate::ir::ir_parameter::IrParameter; +use crate::source_range::SourceRange; +use crate::symbol::Symbol; +use crate::type_info::TypeInfo; +use std::rc::Rc; + +pub struct ParameterSymbol { + declared_name: Rc, + declared_name_source_range: SourceRange, + type_info: TypeInfo, + ir_parameter: Option>, +} + +impl ParameterSymbol { + pub fn new( + declared_name: &Rc, + declared_name_source_range: SourceRange, + type_info: TypeInfo, + ) -> Self { + Self { + declared_name: declared_name.clone(), + declared_name_source_range, + type_info, + ir_parameter: None, + } + } + + pub fn type_info(&self) -> &TypeInfo { + &self.type_info + } + + pub fn set_ir_parameter(&mut self, ir_parameter: Rc) { + self.ir_parameter = Some(ir_parameter); + } + + pub fn ir_parameter(&self) -> &Rc { + self.ir_parameter.as_ref().unwrap() + } +} + +impl Symbol for ParameterSymbol { + fn declared_name(&self) -> &str { + &self.declared_name + } + + fn declared_name_owned(&self) -> Rc { + self.declared_name.clone() + } + + fn declared_name_source_range(&self) -> &SourceRange { + &self.declared_name_source_range + } +} diff --git a/dmc-lib/src/symbol/variable_symbol.rs b/dmc-lib/src/symbol/variable_symbol.rs new file mode 100644 index 0000000..f1e2348 --- /dev/null +++ b/dmc-lib/src/symbol/variable_symbol.rs @@ -0,0 +1,58 @@ +use crate::ir::ir_variable::IrVariable; +use crate::source_range::SourceRange; +use crate::symbol::Symbol; +use crate::type_info::TypeInfo; +use std::cell::RefCell; +use std::rc::Rc; + +pub struct VariableSymbol { + declared_name: Rc, + declared_name_source_range: SourceRange, + type_info: Option, + vr_variable: Option>>, +} + +impl VariableSymbol { + pub fn new(name: &Rc, declared_name_source_range: SourceRange) -> Self { + Self { + declared_name: name.clone(), + declared_name_source_range, + type_info: None, + vr_variable: None, + } + } + + pub fn set_type_info(&mut self, type_info: TypeInfo) { + self.type_info = Some(type_info); + } + + pub fn type_info(&self) -> &TypeInfo { + self.type_info + .as_ref() + .expect("TypeInfo not initialized. Did you type check?") + } + + pub fn set_vr_variable(&mut self, ir_variable: Rc>) { + self.vr_variable = Some(ir_variable); + } + + pub fn vr_variable(&self) -> &Rc> { + self.vr_variable + .as_ref() + .expect("ir_variable not yet initialized") + } +} + +impl Symbol for VariableSymbol { + fn declared_name(&self) -> &str { + &self.declared_name + } + + fn declared_name_owned(&self) -> Rc { + self.declared_name.clone() + } + + fn declared_name_source_range(&self) -> &SourceRange { + &self.declared_name_source_range + } +} diff --git a/dmc-lib/src/symbol_table.rs b/dmc-lib/src/symbol_table.rs deleted file mode 100644 index 4f0bd52..0000000 --- a/dmc-lib/src/symbol_table.rs +++ /dev/null @@ -1,157 +0,0 @@ -use crate::scope::Scope; -use crate::symbol::{ExpressibleSymbol, FunctionSymbol, ParameterSymbol, VariableSymbol}; -use std::cell::RefCell; -use std::rc::Rc; - -pub struct SymbolTable { - scopes: Vec, - current_scope_id: Option, -} - -impl SymbolTable { - pub fn new() -> Self { - Self { - scopes: vec![], - current_scope_id: None, - } - } - - pub fn push_scope(&mut self, debug_name: &str) -> usize { - let scope_id = self.scopes.len(); - let parent_id = self.current_scope_id; - let scope = Scope::new(debug_name, parent_id); - self.scopes.push(scope); - self.current_scope_id = Some(scope_id); - scope_id - } - - pub fn pop_scope(&mut self) { - self.current_scope_id = self.current_scope().parent_id(); - } - - pub fn current_scope_id(&self) -> usize { - self.current_scope_id.unwrap() - } - - fn current_scope(&self) -> &Scope { - &self.scopes[self.current_scope_id.unwrap()] - } - - fn current_scope_mut(&mut self) -> &mut Scope { - &mut self.scopes[self.current_scope_id.unwrap()] - } - - fn current_scope_has_name(&self, name: &str) -> bool { - let current_scope = self.current_scope(); - current_scope.function_symbols().contains_key(name) - || current_scope.parameter_symbols().contains_key(name) - || current_scope.variable_symbols().contains_key(name) - } - - pub fn insert_function_symbol( - &mut self, - function_symbol: FunctionSymbol, - ) -> Result>, SymbolInsertError> { - if self.current_scope_has_name(function_symbol.name()) { - return Err(SymbolInsertError::AlreadyDeclared(AlreadyDeclared::new( - function_symbol.name(), - ))); - } - let name = function_symbol.name_owned(); - let as_rc = Rc::new(RefCell::new(function_symbol)); - - self.current_scope_mut() - .function_symbols_mut() - .insert(name, as_rc.clone()); - Ok(as_rc) - } - - pub fn insert_parameter_symbol( - &mut self, - parameter_symbol: ParameterSymbol, - ) -> Result>, SymbolInsertError> { - if self.current_scope_has_name(parameter_symbol.name()) { - return Err(SymbolInsertError::AlreadyDeclared(AlreadyDeclared::new( - parameter_symbol.name(), - ))); - } - let as_rc = Rc::new(RefCell::new(parameter_symbol)); - self.current_scope_mut() - .parameter_symbols_mut() - .insert(as_rc.borrow().name_owned(), as_rc.clone()); - Ok(as_rc) - } - - pub fn insert_variable_symbol( - &mut self, - variable_symbol: VariableSymbol, - ) -> Result<(), SymbolInsertError> { - if self.current_scope_has_name(variable_symbol.name()) { - return Err(SymbolInsertError::AlreadyDeclared(AlreadyDeclared::new( - variable_symbol.name(), - ))); - } - self.current_scope_mut().variable_symbols_mut().insert( - variable_symbol.name_owned(), - Rc::new(RefCell::new(variable_symbol)), - ); - Ok(()) - } - - pub fn find_expressible_symbol( - &self, - scope_id: usize, - name: &str, - ) -> Option { - let mut maybe_scope = self.scopes.get(scope_id); - if maybe_scope.is_none() { - panic!("Invalid scope_id: {}", scope_id); - } - while let Some(scope) = maybe_scope { - let maybe_expressible_symbol = scope - .variable_symbols() - .get(name) - .map(|variable_symbol| ExpressibleSymbol::Variable(variable_symbol.clone())) - .or_else(|| { - scope - .function_symbols() - .get(name) - .map(|function_symbol| ExpressibleSymbol::Function(function_symbol.clone())) - }) - .or_else(|| { - scope.parameter_symbols().get(name).map(|parameter_symbol| { - ExpressibleSymbol::Parameter(parameter_symbol.clone()) - }) - }); - if maybe_expressible_symbol.is_some() { - return maybe_expressible_symbol; - } else { - maybe_scope = scope.parent_id().map(|id| &self.scopes[id]); - } - } - None - } - - pub fn get_variable_symbol(&self, scope_id: usize, name: &str) -> Rc> { - let scope = self.scopes.get(scope_id).unwrap(); - scope.variable_symbols().get(name).unwrap().clone() - } -} - -pub enum SymbolInsertError { - AlreadyDeclared(AlreadyDeclared), -} - -pub struct AlreadyDeclared { - name: String, -} - -impl AlreadyDeclared { - pub fn new(name: &str) -> Self { - Self { name: name.into() } - } - - pub fn name(&self) -> &str { - &self.name - } -} diff --git a/dmc-lib/src/symbol_table/helpers.rs b/dmc-lib/src/symbol_table/helpers.rs new file mode 100644 index 0000000..7378c01 --- /dev/null +++ b/dmc-lib/src/symbol_table/helpers.rs @@ -0,0 +1,136 @@ +use crate::scope::Scope; +use crate::scope::block_scope::BlockScope; +use crate::scope::class_scope::ClassScope; +use crate::scope::function_scope::FunctionScope; +use crate::scope::module_scope::ModuleScope; +use crate::symbol::Symbol; +use crate::symbol::expressible_symbol::ExpressibleSymbol; +use std::cell::RefCell; +use std::rc::Rc; + +pub fn find_in_module_by_name( + module_scope: &ModuleScope, + name: &str, +) -> Option>> { + module_scope + .function_symbols() + .get(name) + .map(|symbol| symbol.clone() as Rc>) + .or_else(|| { + module_scope + .class_symbols() + .get(name) + .map(|symbol| symbol.clone() as Rc>) + }) +} + +pub fn find_in_class_by_name( + class_scope: &ClassScope, + name: &str, +) -> Option>> { + class_scope + .class_symbols() + .get(name) + .map(|symbol| symbol.clone() as Rc>) + .or_else(|| { + class_scope + .function_symbols() + .get(name) + .map(|symbol| symbol.clone() as Rc>) + }) + .or_else(|| { + class_scope + .field_symbols() + .get(name) + .map(|symbol| symbol.clone() as Rc>) + }) +} + +pub fn find_in_function_by_name( + function_scope: &FunctionScope, + name: &str, +) -> Option>> { + function_scope + .parameter_symbols() + .get(name) + .map(|symbol| symbol.clone() as Rc>) +} + +pub fn find_in_block_by_name( + block_scope: &BlockScope, + name: &str, +) -> Option>> { + block_scope + .variable_symbols() + .get(name) + .map(|symbol| symbol.clone() as Rc>) +} + +fn find_expressible_in_module_by_name( + module_scope: &ModuleScope, + name: &str, +) -> Option { + module_scope + .class_symbols() + .get(name) + .map(|class_symbol| ExpressibleSymbol::Class(class_symbol.clone())) + .or_else(|| { + module_scope + .function_symbols() + .get(name) + .map(|function_symbol| ExpressibleSymbol::Function(function_symbol.clone())) + }) +} + +fn find_expressible_in_class_by_name( + class_scope: &ClassScope, + name: &str, +) -> Option { + class_scope + .class_symbols() + .get(name) + .map(|symbol| ExpressibleSymbol::Class(symbol.clone())) + .or_else(|| { + class_scope + .function_symbols() + .get(name) + .map(|function_symbol| ExpressibleSymbol::Function(function_symbol.clone())) + }) + .or_else(|| { + class_scope + .field_symbols() + .get(name) + .map(|field_symbol| ExpressibleSymbol::Field(field_symbol.clone())) + }) +} + +fn find_expressible_in_function_by_name( + function_scope: &FunctionScope, + name: &str, +) -> Option { + function_scope + .parameter_symbols() + .get(name) + .map(|parameter_symbol| ExpressibleSymbol::Parameter(parameter_symbol.clone())) +} + +fn find_expressible_in_block_by_name( + block_scope: &BlockScope, + name: &str, +) -> Option { + block_scope + .variable_symbols() + .get(name) + .map(|variable_symbol| ExpressibleSymbol::Variable(variable_symbol.clone())) +} + +pub fn find_expressible_symbol(scope: &Scope, name: &str) -> Option { + match scope { + Scope::Module(module_scope) => find_expressible_in_module_by_name(module_scope, name), + Scope::Class(class_scope) => find_expressible_in_class_by_name(class_scope, name), + Scope::Function(function_scope) => { + find_expressible_in_function_by_name(function_scope, name) + } + Scope::Block(block_scope) => find_expressible_in_block_by_name(block_scope, name), + } +} diff --git a/dmc-lib/src/symbol_table/mod.rs b/dmc-lib/src/symbol_table/mod.rs new file mode 100644 index 0000000..f270650 --- /dev/null +++ b/dmc-lib/src/symbol_table/mod.rs @@ -0,0 +1,225 @@ +mod helpers; + +use crate::scope::Scope; +use crate::scope::block_scope::BlockScope; +use crate::scope::class_scope::ClassScope; +use crate::scope::function_scope::FunctionScope; +use crate::scope::module_scope::ModuleScope; +use crate::symbol::Symbol; +use crate::symbol::expressible_symbol::ExpressibleSymbol; +use crate::symbol::function_symbol::FunctionSymbol; +use crate::symbol::parameter_symbol::ParameterSymbol; +use crate::symbol::variable_symbol::VariableSymbol; +use crate::symbol_table::helpers::{ + find_expressible_symbol, find_in_block_by_name, find_in_class_by_name, + find_in_function_by_name, find_in_module_by_name, +}; +use std::cell::RefCell; +use std::rc::Rc; + +pub struct SymbolTable { + scopes: Vec, + current_scope_id: Option, +} + +impl SymbolTable { + pub fn new() -> Self { + Self { + scopes: vec![], + current_scope_id: None, + } + } + + fn new_scope_id(&self) -> usize { + self.scopes.len() + } + + fn push_scope(&mut self, scope: Scope) { + let scope_id = self.new_scope_id(); + self.scopes.push(scope); + self.current_scope_id = Some(scope_id); + } + + pub fn push_module_scope(&mut self, debug_name: &str) { + self.push_scope(Scope::Module(ModuleScope::new( + debug_name, + self.current_scope_id, + ))); + } + + pub fn push_class_scope(&mut self, debug_name: &str) { + self.push_scope(Scope::Class(ClassScope::new( + debug_name, + self.current_scope_id.unwrap(), + ))); + } + + pub fn push_function_scope(&mut self, debug_name: &str) { + self.push_scope(Scope::Function(FunctionScope::new( + debug_name, + self.current_scope_id.unwrap(), + ))); + } + + pub fn push_block_scope(&mut self, debug_name: &str) { + self.push_scope(Scope::Block(BlockScope::new( + debug_name, + self.current_scope_id.unwrap(), + ))); + } + + pub fn pop_scope(&mut self) { + self.current_scope_id = self.current_scope().parent_id(); + } + + pub fn current_scope_id(&self) -> usize { + self.current_scope_id.unwrap() + } + + fn current_scope(&self) -> &Scope { + &self.scopes[self.current_scope_id.unwrap()] + } + + fn current_scope_mut(&mut self) -> &mut Scope { + &mut self.scopes[self.current_scope_id.unwrap()] + } + + pub fn insert_function_symbol( + &mut self, + function_symbol: FunctionSymbol, + ) -> Result>, SymbolInsertError> { + let maybe_already_inserted = match self.current_scope() { + Scope::Module(module_scope) => { + find_in_module_by_name(module_scope, function_symbol.declared_name()) + } + Scope::Class(class_scope) => { + find_in_class_by_name(class_scope, function_symbol.declared_name()) + } + _ => panic!("Attempt to insert FunctionSymbol in incompatible scope"), + }; + + if let Some(already_inserted) = maybe_already_inserted { + return Err(SymbolInsertError::AlreadyDeclared(AlreadyDeclared::new( + already_inserted, + ))); + } + + let name = function_symbol.declared_name_owned(); + let as_rc = Rc::new(RefCell::new(function_symbol)); + let to_return = as_rc.clone(); + + match self.current_scope_mut() { + Scope::Module(module_scope) => { + module_scope.function_symbols_mut().insert(name, as_rc); + } + Scope::Class(class_scope) => { + class_scope.function_symbols_mut().insert(name, as_rc); + } + _ => unreachable!(), + } + Ok(to_return) + } + + pub fn insert_parameter_symbol( + &mut self, + parameter_symbol: ParameterSymbol, + ) -> Result>, SymbolInsertError> { + let maybe_already_inserted = match self.current_scope() { + Scope::Function(function_scope) => { + find_in_function_by_name(function_scope, parameter_symbol.declared_name()) + } + _ => panic!("Attempt to insert ParameterSymbol in incompatible scope"), + }; + if let Some(already_inserted) = maybe_already_inserted { + return Err(SymbolInsertError::AlreadyDeclared(AlreadyDeclared::new( + already_inserted, + ))); + } + + let name = parameter_symbol.declared_name_owned(); + let as_rc = Rc::new(RefCell::new(parameter_symbol)); + let to_return = as_rc.clone(); + + match self.current_scope_mut() { + Scope::Function(function_scope) => { + function_scope.parameter_symbols_mut().insert(name, as_rc); + } + _ => panic!("Attempt to insert ParameterSymbol in incompatible scope"), + } + + Ok(to_return) + } + + pub fn insert_variable_symbol( + &mut self, + variable_symbol: VariableSymbol, + ) -> Result<(), SymbolInsertError> { + let maybe_already_inserted = match self.current_scope() { + Scope::Block(block_scope) => { + find_in_block_by_name(block_scope, variable_symbol.declared_name()) + } + _ => panic!("Attempt to insert VariableSymbol in incompatible scope"), + }; + if let Some(already_inserted) = maybe_already_inserted { + return Err(SymbolInsertError::AlreadyDeclared(AlreadyDeclared::new( + already_inserted, + ))); + } + + match self.current_scope_mut() { + Scope::Block(block_scope) => { + block_scope.variable_symbols_mut().insert( + variable_symbol.declared_name_owned(), + Rc::new(RefCell::new(variable_symbol)), + ); + } + _ => unreachable!(), + } + Ok(()) + } + + pub fn find_expressible_symbol( + &self, + scope_id: usize, + name: &str, + ) -> Option { + let mut maybe_scope = self.scopes.get(scope_id); + if maybe_scope.is_none() { + panic!("Invalid scope_id: {}", scope_id); + } + while let Some(scope) = maybe_scope { + let maybe_expressible_symbol = find_expressible_symbol(scope, name); + if maybe_expressible_symbol.is_some() { + return maybe_expressible_symbol; + } else { + maybe_scope = scope.parent_id().map(|id| &self.scopes[id]); + } + } + None + } + + pub fn get_variable_symbol(&self, scope_id: usize, name: &str) -> Rc> { + match &self.scopes[scope_id] { + Scope::Block(block_scope) => block_scope.variable_symbols().get(name).cloned().unwrap(), + _ => panic!("scope_id {} is not a BlockScope", scope_id), + } + } +} + +pub enum SymbolInsertError { + AlreadyDeclared(AlreadyDeclared), +} + +pub struct AlreadyDeclared { + symbol: Rc>, +} + +impl AlreadyDeclared { + pub fn new(symbol: Rc>) -> Self { + Self { symbol } + } + + pub fn symbol(&self) -> &Rc> { + &self.symbol + } +} diff --git a/dmc-lib/src/type_info.rs b/dmc-lib/src/type_info.rs index b060126..69c4995 100644 --- a/dmc-lib/src/type_info.rs +++ b/dmc-lib/src/type_info.rs @@ -1,4 +1,4 @@ -use crate::symbol::FunctionSymbol; +use crate::symbol::function_symbol::FunctionSymbol; use std::cell::RefCell; use std::fmt::{Display, Formatter}; use std::rc::Rc;