Refactor scopes and symbol table for more resiliency and classes/fields.

This commit is contained in:
Jesse Brault 2026-03-11 15:04:38 -05:00
parent 9790ec6ca6
commit 89f519c45f
32 changed files with 947 additions and 412 deletions

View File

@ -6,7 +6,8 @@ use dmc_lib::ir::ir_return::IrReturn;
use dmc_lib::ir::ir_statement::IrStatement; use dmc_lib::ir::ir_statement::IrStatement;
use dmc_lib::lexer::Lexer; use dmc_lib::lexer::Lexer;
use dmc_lib::parser::parse_expression; 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::symbol_table::SymbolTable;
use dmc_lib::token::TokenKind; use dmc_lib::token::TokenKind;
use dvm_lib::vm::constant::{Constant, StringConstant}; use dvm_lib::vm::constant::{Constant, StringConstant};
@ -100,10 +101,15 @@ fn compile_expression(
let mut expression = parse_result?; let mut expression = parse_result?;
let mut symbol_table = SymbolTable::new(); 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)?; 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.check_name_usages(&symbol_table)?;
expression.type_check(&symbol_table)?; expression.type_check(&symbol_table)?;
@ -125,6 +131,7 @@ fn compile_expression(
// synthesize symbol // synthesize symbol
let fake_function_symbol = Rc::new(RefCell::new(FunctionSymbol::new( let fake_function_symbol = Rc::new(RefCell::new(FunctionSymbol::new(
"__repl", "__repl",
SourceRange::new(0, 0),
false, false,
expression.type_info().clone(), // dubious expression.type_info().clone(), // dubious
))); )));

View File

@ -4,7 +4,9 @@ use crate::diagnostic::Diagnostic;
use crate::ir::ir_call::IrCall; use crate::ir::ir_call::IrCall;
use crate::ir::ir_expression::IrExpression; use crate::ir::ir_expression::IrExpression;
use crate::source_range::SourceRange; 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::symbol_table::SymbolTable;
use crate::type_info::TypeInfo; use crate::type_info::TypeInfo;
use std::cell::RefCell; use std::cell::RefCell;
@ -178,7 +180,7 @@ impl Call {
.collect(); .collect();
let function_symbol = self.get_callee_symbol(); let function_symbol = self.get_callee_symbol();
IrCall::new( IrCall::new(
function_symbol.borrow().name_owned(), function_symbol.borrow().declared_name_owned(),
arguments, arguments,
function_symbol.clone(), function_symbol.clone(),
) )

View File

@ -31,6 +31,9 @@ impl Class {
&mut self, &mut self,
symbol_table: &mut SymbolTable, symbol_table: &mut SymbolTable,
) -> Result<(), Vec<Diagnostic>> { ) -> Result<(), Vec<Diagnostic>> {
// 1. insert class symbol
// 2. gather fields
// 3. gather functions
todo!() todo!()
} }

View File

@ -40,7 +40,7 @@ impl CompilationUnit {
&mut self, &mut self,
symbol_table: &mut SymbolTable, symbol_table: &mut SymbolTable,
) -> Result<(), Vec<Diagnostic>> { ) -> Result<(), Vec<Diagnostic>> {
symbol_table.push_scope("compilation_unit_scope"); symbol_table.push_module_scope("compilation_unit_scope");
let mut diagnostics: Vec<Diagnostic> = vec![]; let mut diagnostics: Vec<Diagnostic> = vec![];
self.functions self.functions

View File

@ -3,7 +3,7 @@ use crate::ast::ir_builder::IrBuilder;
use crate::diagnostic::Diagnostic; use crate::diagnostic::Diagnostic;
use crate::ir::ir_return::IrReturn; use crate::ir::ir_return::IrReturn;
use crate::ir::ir_statement::IrStatement; use crate::ir::ir_statement::IrStatement;
use crate::symbol::FunctionSymbol; use crate::symbol::function_symbol::FunctionSymbol;
use crate::symbol_table::SymbolTable; use crate::symbol_table::SymbolTable;
use std::cell::RefCell; use std::cell::RefCell;
use std::rc::Rc; use std::rc::Rc;

View File

@ -2,7 +2,7 @@ use crate::ast::parameter::Parameter;
use crate::ast::type_use::TypeUse; use crate::ast::type_use::TypeUse;
use crate::diagnostic::Diagnostic; use crate::diagnostic::Diagnostic;
use crate::source_range::SourceRange; use crate::source_range::SourceRange;
use crate::symbol::FunctionSymbol; use crate::symbol::function_symbol::FunctionSymbol;
use crate::symbol_table::{SymbolInsertError, SymbolTable}; use crate::symbol_table::{SymbolInsertError, SymbolTable};
pub struct ExternFunction { pub struct ExternFunction {
@ -39,6 +39,7 @@ impl ExternFunction {
let insert_result = symbol_table.insert_function_symbol(FunctionSymbol::new( let insert_result = symbol_table.insert_function_symbol(FunctionSymbol::new(
&self.declared_name, &self.declared_name,
self.declared_name_source_range.clone(),
true, true,
self.return_type.to_type_info(), self.return_type.to_type_info(),
)); ));
@ -51,7 +52,7 @@ impl ExternFunction {
diagnostics.push(Diagnostic::new( diagnostics.push(Diagnostic::new(
&format!( &format!(
"Function {} already declared in current scope.", "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.start(),
self.declared_name_source_range.end(), 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![]; let mut parameter_symbols = vec![];
for parameter in &mut self.parameters { for parameter in &mut self.parameters {
@ -80,7 +82,7 @@ impl ExternFunction {
.borrow_mut() .borrow_mut()
.set_parameters(parameter_symbols); .set_parameters(parameter_symbols);
symbol_table.pop_scope(); symbol_table.pop_scope(); // function scope
if diagnostics.is_empty() { if diagnostics.is_empty() {
Ok(()) Ok(())

View File

@ -6,7 +6,8 @@ use crate::diagnostic::Diagnostic;
use crate::ir::ir_function::IrFunction; use crate::ir::ir_function::IrFunction;
use crate::ir::ir_parameter::IrParameter; use crate::ir::ir_parameter::IrParameter;
use crate::source_range::SourceRange; 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::symbol_table::{SymbolInsertError, SymbolTable};
use crate::type_info::TypeInfo; use crate::type_info::TypeInfo;
use std::cell::RefCell; use std::cell::RefCell;
@ -60,6 +61,7 @@ impl Function {
// insert function symbol // insert function symbol
let insert_result = symbol_table.insert_function_symbol(FunctionSymbol::new( let insert_result = symbol_table.insert_function_symbol(FunctionSymbol::new(
self.declared_name(), self.declared_name(),
self.declared_name_source_range.clone(),
false, false,
self.return_type self.return_type
.as_ref() .as_ref()
@ -76,7 +78,7 @@ impl Function {
diagnostics.push(Diagnostic::new( diagnostics.push(Diagnostic::new(
&format!( &format!(
"Function {} already declared in current scope", "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.start(),
self.declared_name_source_range.end(), self.declared_name_source_range.end(),
@ -91,7 +93,7 @@ impl Function {
self.function_symbol = Some(function_symbol.clone()); self.function_symbol = Some(function_symbol.clone());
// handle parameters // 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![]; let mut parameter_symbols = vec![];
for parameter in &mut self.parameters { for parameter in &mut self.parameters {
match parameter.gather_declared_names(symbol_table) { match parameter.gather_declared_names(symbol_table) {
@ -107,7 +109,7 @@ impl Function {
.borrow_mut() .borrow_mut()
.set_parameters(parameter_symbols); .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 { for statement in &mut self.statements {
match statement.gather_declared_names(symbol_table) { match statement.gather_declared_names(symbol_table) {
Ok(_) => {} Ok(_) => {}
@ -116,8 +118,8 @@ impl Function {
} }
} }
} }
symbol_table.pop_scope(); // body symbol_table.pop_scope(); // main block scope
symbol_table.pop_scope(); // params symbol_table.pop_scope(); // function scope
if diagnostics.is_empty() { if diagnostics.is_empty() {
Ok(()) Ok(())
@ -204,7 +206,7 @@ impl Function {
let parameter_symbol = parameter.parameter_symbol(); let parameter_symbol = parameter.parameter_symbol();
let stack_offset = (self.parameters.len() as isize).neg() + (i as isize); let stack_offset = (self.parameters.len() as isize).neg() + (i as isize);
let ir_parameter = IrParameter::new( let ir_parameter = IrParameter::new(
parameter_symbol.borrow().name(), parameter_symbol.borrow().declared_name(),
parameter_symbol.borrow().type_info().clone(), parameter_symbol.borrow().type_info().clone(),
stack_offset, stack_offset,
); );

View File

@ -1,6 +1,6 @@
use crate::diagnostic::Diagnostic; use crate::diagnostic::Diagnostic;
use crate::source_range::SourceRange; use crate::source_range::SourceRange;
use crate::symbol::ExpressibleSymbol; use crate::symbol::expressible_symbol::ExpressibleSymbol;
use crate::symbol_table::SymbolTable; use crate::symbol_table::SymbolTable;
use crate::type_info::TypeInfo; use crate::type_info::TypeInfo;

View File

@ -7,13 +7,13 @@ use crate::ir::ir_operation::IrOperation;
use crate::ir::ir_statement::IrStatement; use crate::ir::ir_statement::IrStatement;
use crate::ir::ir_variable::IrVariable; use crate::ir::ir_variable::IrVariable;
use crate::source_range::SourceRange; use crate::source_range::SourceRange;
use crate::symbol::VariableSymbol; use crate::symbol::variable_symbol::VariableSymbol;
use crate::symbol_table::{SymbolInsertError, SymbolTable}; use crate::symbol_table::{SymbolInsertError, SymbolTable};
use std::cell::RefCell; use std::cell::RefCell;
use std::rc::Rc; use std::rc::Rc;
pub struct LetStatement { pub struct LetStatement {
declared_name: String, declared_name: Rc<str>,
declared_name_source_range: SourceRange, declared_name_source_range: SourceRange,
initializer: Box<Expression>, initializer: Box<Expression>,
scope_id: Option<usize>, scope_id: Option<usize>,
@ -26,7 +26,7 @@ impl LetStatement {
initializer: Expression, initializer: Expression,
) -> Self { ) -> Self {
Self { Self {
declared_name: declared_name.to_string(), declared_name: declared_name.into(),
declared_name_source_range, declared_name_source_range,
initializer: initializer.into(), initializer: initializer.into(),
scope_id: None, scope_id: None,
@ -58,15 +58,17 @@ impl LetStatement {
} }
} }
let insert_result = let insert_result = symbol_table.insert_variable_symbol(VariableSymbol::new(
symbol_table.insert_variable_symbol(VariableSymbol::new(self.declared_name())); &self.declared_name,
self.declared_name_source_range.clone(),
));
if let Err(symbol_insert_error) = insert_result { if let Err(symbol_insert_error) = insert_result {
match symbol_insert_error { match symbol_insert_error {
SymbolInsertError::AlreadyDeclared(already_declared) => { SymbolInsertError::AlreadyDeclared(already_declared) => {
diagnostics.push(Diagnostic::new( diagnostics.push(Diagnostic::new(
&format!( &format!(
"Symbol {} already declared in current scope", "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.start(),
self.declared_name_source_range.end(), self.declared_name_source_range.end(),

View File

@ -1,14 +1,14 @@
use crate::ast::type_use::TypeUse; use crate::ast::type_use::TypeUse;
use crate::diagnostic::Diagnostic; use crate::diagnostic::Diagnostic;
use crate::source_range::SourceRange; use crate::source_range::SourceRange;
use crate::symbol::ParameterSymbol; use crate::symbol::parameter_symbol::ParameterSymbol;
use crate::symbol_table::{SymbolInsertError, SymbolTable}; use crate::symbol_table::{SymbolInsertError, SymbolTable};
use crate::type_info::TypeInfo; use crate::type_info::TypeInfo;
use std::cell::RefCell; use std::cell::RefCell;
use std::rc::Rc; use std::rc::Rc;
pub struct Parameter { pub struct Parameter {
declared_name: String, declared_name: Rc<str>,
declared_name_source_range: SourceRange, declared_name_source_range: SourceRange,
type_use: TypeUse, type_use: TypeUse,
parameter_symbol: Option<Rc<RefCell<ParameterSymbol>>>, parameter_symbol: Option<Rc<RefCell<ParameterSymbol>>>,
@ -34,6 +34,7 @@ impl Parameter {
) -> Result<Rc<RefCell<ParameterSymbol>>, Vec<Diagnostic>> { ) -> Result<Rc<RefCell<ParameterSymbol>>, Vec<Diagnostic>> {
let insert_result = symbol_table.insert_parameter_symbol(ParameterSymbol::new( let insert_result = symbol_table.insert_parameter_symbol(ParameterSymbol::new(
&self.declared_name, &self.declared_name,
self.declared_name_source_range.clone(),
TypeInfo::from_declared_name(self.type_use.declared_name()), TypeInfo::from_declared_name(self.type_use.declared_name()),
)); ));
match insert_result { match insert_result {
@ -43,7 +44,10 @@ impl Parameter {
} }
Err(symbol_insert_error) => match symbol_insert_error { Err(symbol_insert_error) => match symbol_insert_error {
SymbolInsertError::AlreadyDeclared(already_declared) => Err(vec![Diagnostic::new( 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.start(),
self.declared_name_source_range.end(), self.declared_name_source_range.end(),
)]), )]),

View File

@ -2,7 +2,7 @@ use crate::ast::expression_statement::ExpressionStatement;
use crate::ast::ir_builder::IrBuilder; use crate::ast::ir_builder::IrBuilder;
use crate::ast::let_statement::LetStatement; use crate::ast::let_statement::LetStatement;
use crate::diagnostic::Diagnostic; use crate::diagnostic::Diagnostic;
use crate::symbol::FunctionSymbol; use crate::symbol::function_symbol::FunctionSymbol;
use crate::symbol_table::SymbolTable; use crate::symbol_table::SymbolTable;
use std::cell::RefCell; use std::cell::RefCell;
use std::rc::Rc; use std::rc::Rc;

View File

@ -3,7 +3,8 @@ use crate::ir::assemble::{Assemble, InstructionsBuilder};
use crate::ir::ir_expression::IrExpression; use crate::ir::ir_expression::IrExpression;
use crate::ir::ir_variable::IrVrVariableDescriptor; use crate::ir::ir_variable::IrVrVariableDescriptor;
use crate::ir::register_allocation::{OffsetCounter, VrUser}; 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 dvm_lib::instruction::Instruction;
use std::cell::RefCell; use std::cell::RefCell;
use std::collections::{HashMap, HashSet}; use std::collections::{HashMap, HashSet};
@ -67,14 +68,14 @@ impl Assemble for IrCall {
.map(|ir_expression| ir_expression.push_operand(constants_table)) .map(|ir_expression| ir_expression.push_operand(constants_table))
.for_each(|push_operand| builder.push(Instruction::Push(push_operand))); .for_each(|push_operand| builder.push(Instruction::Push(push_operand)));
let symbol = self.function_symbol.borrow(); let symbol = self.function_symbol.borrow();
if symbol.is_platform() { if symbol.is_extern() {
builder.push(Instruction::InvokePlatformStatic( builder.push(Instruction::InvokePlatformStatic(
symbol.name_owned(), symbol.declared_name_owned(),
symbol.parameters().len(), symbol.parameters().len(),
)); ));
} else { } else {
builder.push(Instruction::InvokeStatic( builder.push(Instruction::InvokeStatic(
symbol.name_owned(), symbol.declared_name_owned(),
symbol.parameters().len(), symbol.parameters().len(),
)); ));
} }

View File

@ -4,7 +4,8 @@ use crate::ir::ir_block::IrBlock;
use crate::ir::ir_parameter::IrParameter; use crate::ir::ir_parameter::IrParameter;
use crate::ir::ir_variable::IrVrVariableDescriptor; use crate::ir::ir_variable::IrVrVariableDescriptor;
use crate::ir::register_allocation::HasVrUsers; 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 crate::type_info::TypeInfo;
use dvm_lib::vm::function::Function; use dvm_lib::vm::function::Function;
use std::cell::RefCell; use std::cell::RefCell;
@ -46,7 +47,7 @@ impl IrFunction {
self.entry.borrow().assemble(&mut builder, constants_table); self.entry.borrow().assemble(&mut builder, constants_table);
let instructions = builder.take_instructions(); let instructions = builder.take_instructions();
Function::new( Function::new(
self.function_symbol.borrow().name_owned(), self.function_symbol.borrow().declared_name_owned(),
self.parameters.len(), self.parameters.len(),
stack_size, stack_size,
instructions, instructions,
@ -56,7 +57,7 @@ impl IrFunction {
impl Display for IrFunction { impl Display for IrFunction {
fn fmt(&self, f: &mut std::fmt::Formatter<'_>) -> std::fmt::Result { 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() { for (i, parameter) in self.parameters.iter().enumerate() {
write!(f, "{}: {}", parameter, parameter.type_info())?; write!(f, "{}: {}", parameter, parameter.type_info())?;
if i < self.parameters.len() - 1 { if i < self.parameters.len() - 1 {

View File

@ -4,7 +4,7 @@ pub mod diagnostic;
pub mod ir; pub mod ir;
pub mod lexer; pub mod lexer;
pub mod parser; pub mod parser;
pub mod scope; mod scope;
pub mod source_range; pub mod source_range;
pub mod symbol; pub mod symbol;
pub mod symbol_table; pub mod symbol_table;

View File

@ -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<usize>,
function_symbols: HashMap<Rc<str>, Rc<RefCell<FunctionSymbol>>>,
parameter_symbols: HashMap<Rc<str>, Rc<RefCell<ParameterSymbol>>>,
variable_symbols: HashMap<Rc<str>, Rc<RefCell<VariableSymbol>>>,
}
impl Scope {
pub fn new(debug_name: &str, parent_id: Option<usize>) -> 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<str>, Rc<RefCell<FunctionSymbol>>> {
&self.function_symbols
}
pub fn function_symbols_mut(&mut self) -> &mut HashMap<Rc<str>, Rc<RefCell<FunctionSymbol>>> {
&mut self.function_symbols
}
pub fn parameter_symbols(&self) -> &HashMap<Rc<str>, Rc<RefCell<ParameterSymbol>>> {
&self.parameter_symbols
}
pub fn parameter_symbols_mut(&mut self) -> &mut HashMap<Rc<str>, Rc<RefCell<ParameterSymbol>>> {
&mut self.parameter_symbols
}
pub fn variable_symbols(&self) -> &HashMap<Rc<str>, Rc<RefCell<VariableSymbol>>> {
&self.variable_symbols
}
pub fn variable_symbols_mut(&mut self) -> &mut HashMap<Rc<str>, Rc<RefCell<VariableSymbol>>> {
&mut self.variable_symbols
}
pub fn parent_id(&self) -> Option<usize> {
self.parent_id
}
}

View File

@ -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<str>, Rc<RefCell<VariableSymbol>>>,
}
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<str>, Rc<RefCell<VariableSymbol>>> {
&self.variable_symbols
}
pub fn variable_symbols_mut(&mut self) -> &mut HashMap<Rc<str>, Rc<RefCell<VariableSymbol>>> {
&mut self.variable_symbols
}
pub fn parent_id(&self) -> usize {
self.parent_id
}
}

View File

@ -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<str>, Rc<RefCell<ClassSymbol>>>,
field_symbols: HashMap<Rc<str>, Rc<RefCell<FieldSymbol>>>,
function_symbols: HashMap<Rc<str>, Rc<RefCell<FunctionSymbol>>>,
}
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<str>, Rc<RefCell<ClassSymbol>>> {
&self.class_symbols
}
pub fn class_symbols_mut(&mut self) -> &mut HashMap<Rc<str>, Rc<RefCell<ClassSymbol>>> {
&mut self.class_symbols
}
pub fn field_symbols(&self) -> &HashMap<Rc<str>, Rc<RefCell<FieldSymbol>>> {
&self.field_symbols
}
pub fn field_symbols_mut(&mut self) -> &mut HashMap<Rc<str>, Rc<RefCell<FieldSymbol>>> {
&mut self.field_symbols
}
pub fn function_symbols(&self) -> &HashMap<Rc<str>, Rc<RefCell<FunctionSymbol>>> {
&self.function_symbols
}
pub fn function_symbols_mut(&mut self) -> &mut HashMap<Rc<str>, Rc<RefCell<FunctionSymbol>>> {
&mut self.function_symbols
}
pub fn parent_id(&self) -> usize {
self.parent_id
}
}

View File

@ -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<str>, Rc<RefCell<ParameterSymbol>>>,
}
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<str>, Rc<RefCell<ParameterSymbol>>> {
&self.parameter_symbols
}
pub fn parameter_symbols_mut(&mut self) -> &mut HashMap<Rc<str>, Rc<RefCell<ParameterSymbol>>> {
&mut self.parameter_symbols
}
pub fn parent_id(&self) -> usize {
self.parent_id
}
}

27
dmc-lib/src/scope/mod.rs Normal file
View File

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

View File

@ -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<usize>,
class_symbols: HashMap<Rc<str>, Rc<RefCell<ClassSymbol>>>,
function_symbols: HashMap<Rc<str>, Rc<RefCell<FunctionSymbol>>>,
}
impl ModuleScope {
pub fn new(debug_name: &str, parent_id: Option<usize>) -> Self {
Self {
debug_name: debug_name.into(),
parent_id,
class_symbols: HashMap::new(),
function_symbols: HashMap::new(),
}
}
pub fn class_symbols(&self) -> &HashMap<Rc<str>, Rc<RefCell<ClassSymbol>>> {
&self.class_symbols
}
pub fn class_symbols_mut(&mut self) -> &mut HashMap<Rc<str>, Rc<RefCell<ClassSymbol>>> {
&mut self.class_symbols
}
pub fn function_symbols(&self) -> &HashMap<Rc<str>, Rc<RefCell<FunctionSymbol>>> {
&self.function_symbols
}
pub fn function_symbols_mut(&mut self) -> &mut HashMap<Rc<str>, Rc<RefCell<FunctionSymbol>>> {
&mut self.function_symbols
}
pub fn parent_id(&self) -> Option<usize> {
self.parent_id
}
}

View File

@ -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<str>,
is_platform: bool,
parameters: Option<Vec<Rc<RefCell<ParameterSymbol>>>>,
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<str> {
self.name.clone()
}
pub fn set_parameters(&mut self, parameters: Vec<Rc<RefCell<ParameterSymbol>>>) {
self.parameters = Some(parameters);
}
pub fn parameters(&self) -> &[Rc<RefCell<ParameterSymbol>>] {
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<str>,
type_info: TypeInfo,
ir_parameter: Option<Rc<IrParameter>>,
}
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<str> {
self.name.clone()
}
pub fn type_info(&self) -> &TypeInfo {
&self.type_info
}
pub fn set_ir_parameter(&mut self, ir_parameter: Rc<IrParameter>) {
self.ir_parameter = Some(ir_parameter);
}
pub fn ir_parameter(&self) -> &Rc<IrParameter> {
self.ir_parameter.as_ref().unwrap()
}
}
pub struct VariableSymbol {
name: Rc<str>,
type_info: Option<TypeInfo>,
vr_variable: Option<Rc<RefCell<IrVariable>>>,
}
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<str> {
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<RefCell<IrVariable>>) {
self.vr_variable = Some(ir_variable);
}
pub fn vr_variable(&self) -> &Rc<RefCell<IrVariable>> {
self.vr_variable
.as_ref()
.expect("ir_variable not yet initialized")
}
}
pub enum ExpressibleSymbol {
Function(Rc<RefCell<FunctionSymbol>>),
Parameter(Rc<RefCell<ParameterSymbol>>),
Variable(Rc<RefCell<VariableSymbol>>),
}
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())
}
}
}
}

View File

@ -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<str>,
declared_name_source_range: SourceRange,
is_extern: bool,
fields: HashMap<Rc<str>, Rc<RefCell<FieldSymbol>>>,
functions: HashMap<Rc<str>, Rc<RefCell<FunctionSymbol>>>,
}
impl ClassSymbol {
pub fn new(
declared_name: &Rc<str>,
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<str> {
self.declared_name.clone()
}
fn declared_name_source_range(&self) -> &SourceRange {
&self.declared_name_source_range
}
}

View File

@ -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<RefCell<ClassSymbol>>),
Field(Rc<RefCell<FieldSymbol>>),
Function(Rc<RefCell<FunctionSymbol>>),
Parameter(Rc<RefCell<ParameterSymbol>>),
Variable(Rc<RefCell<VariableSymbol>>),
}
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())
}
}
}
}

View File

@ -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<str>,
declared_name_source_range: SourceRange,
type_info: Option<TypeInfo>,
}
impl FieldSymbol {
pub fn new(declared_name: &Rc<str>, 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<str> {
self.declared_name.clone()
}
fn declared_name_source_range(&self) -> &SourceRange {
&self.declared_name_source_range
}
}

View File

@ -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<str>,
declared_name_source_range: SourceRange,
is_extern: bool,
parameters: Option<Vec<Rc<RefCell<ParameterSymbol>>>>,
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<str> {
self.declared_name.clone()
}
pub fn set_parameters(&mut self, parameters: Vec<Rc<RefCell<ParameterSymbol>>>) {
self.parameters = Some(parameters);
}
pub fn parameters(&self) -> &[Rc<RefCell<ParameterSymbol>>] {
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<str> {
self.declared_name.clone()
}
fn declared_name_source_range(&self) -> &SourceRange {
&self.declared_name_source_range
}
}

15
dmc-lib/src/symbol/mod.rs Normal file
View File

@ -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<str>;
fn declared_name_source_range(&self) -> &SourceRange;
}

View File

@ -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<str>,
declared_name_source_range: SourceRange,
type_info: TypeInfo,
ir_parameter: Option<Rc<IrParameter>>,
}
impl ParameterSymbol {
pub fn new(
declared_name: &Rc<str>,
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<IrParameter>) {
self.ir_parameter = Some(ir_parameter);
}
pub fn ir_parameter(&self) -> &Rc<IrParameter> {
self.ir_parameter.as_ref().unwrap()
}
}
impl Symbol for ParameterSymbol {
fn declared_name(&self) -> &str {
&self.declared_name
}
fn declared_name_owned(&self) -> Rc<str> {
self.declared_name.clone()
}
fn declared_name_source_range(&self) -> &SourceRange {
&self.declared_name_source_range
}
}

View File

@ -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<str>,
declared_name_source_range: SourceRange,
type_info: Option<TypeInfo>,
vr_variable: Option<Rc<RefCell<IrVariable>>>,
}
impl VariableSymbol {
pub fn new(name: &Rc<str>, 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<RefCell<IrVariable>>) {
self.vr_variable = Some(ir_variable);
}
pub fn vr_variable(&self) -> &Rc<RefCell<IrVariable>> {
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<str> {
self.declared_name.clone()
}
fn declared_name_source_range(&self) -> &SourceRange {
&self.declared_name_source_range
}
}

View File

@ -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<Scope>,
current_scope_id: Option<usize>,
}
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<Rc<RefCell<FunctionSymbol>>, 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<Rc<RefCell<ParameterSymbol>>, 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<ExpressibleSymbol> {
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<RefCell<VariableSymbol>> {
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
}
}

View File

@ -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<Rc<RefCell<dyn Symbol>>> {
module_scope
.function_symbols()
.get(name)
.map(|symbol| symbol.clone() as Rc<RefCell<dyn Symbol>>)
.or_else(|| {
module_scope
.class_symbols()
.get(name)
.map(|symbol| symbol.clone() as Rc<RefCell<dyn Symbol>>)
})
}
pub fn find_in_class_by_name(
class_scope: &ClassScope,
name: &str,
) -> Option<Rc<RefCell<dyn Symbol>>> {
class_scope
.class_symbols()
.get(name)
.map(|symbol| symbol.clone() as Rc<RefCell<dyn Symbol>>)
.or_else(|| {
class_scope
.function_symbols()
.get(name)
.map(|symbol| symbol.clone() as Rc<RefCell<dyn Symbol>>)
})
.or_else(|| {
class_scope
.field_symbols()
.get(name)
.map(|symbol| symbol.clone() as Rc<RefCell<dyn Symbol>>)
})
}
pub fn find_in_function_by_name(
function_scope: &FunctionScope,
name: &str,
) -> Option<Rc<RefCell<dyn Symbol>>> {
function_scope
.parameter_symbols()
.get(name)
.map(|symbol| symbol.clone() as Rc<RefCell<dyn Symbol>>)
}
pub fn find_in_block_by_name(
block_scope: &BlockScope,
name: &str,
) -> Option<Rc<RefCell<dyn Symbol>>> {
block_scope
.variable_symbols()
.get(name)
.map(|symbol| symbol.clone() as Rc<RefCell<dyn Symbol>>)
}
fn find_expressible_in_module_by_name(
module_scope: &ModuleScope,
name: &str,
) -> Option<ExpressibleSymbol> {
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<ExpressibleSymbol> {
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<ExpressibleSymbol> {
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<ExpressibleSymbol> {
block_scope
.variable_symbols()
.get(name)
.map(|variable_symbol| ExpressibleSymbol::Variable(variable_symbol.clone()))
}
pub fn find_expressible_symbol(scope: &Scope, name: &str) -> Option<ExpressibleSymbol> {
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),
}
}

View File

@ -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<Scope>,
current_scope_id: Option<usize>,
}
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<Rc<RefCell<FunctionSymbol>>, 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<Rc<RefCell<ParameterSymbol>>, 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<ExpressibleSymbol> {
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<RefCell<VariableSymbol>> {
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<RefCell<dyn Symbol>>,
}
impl AlreadyDeclared {
pub fn new(symbol: Rc<RefCell<dyn Symbol>>) -> Self {
Self { symbol }
}
pub fn symbol(&self) -> &Rc<RefCell<dyn Symbol>> {
&self.symbol
}
}

View File

@ -1,4 +1,4 @@
use crate::symbol::FunctionSymbol; use crate::symbol::function_symbol::FunctionSymbol;
use std::cell::RefCell; use std::cell::RefCell;
use std::fmt::{Display, Formatter}; use std::fmt::{Display, Formatter};
use std::rc::Rc; use std::rc::Rc;