use crate::ast::expression::Expression; use crate::ast::type_use::TypeUse; use crate::diagnostic::Diagnostic; use crate::source_range::SourceRange; use crate::symbol::field_symbol::FieldSymbol; use crate::symbol_table::{SymbolInsertError, SymbolTable}; use std::rc::Rc; pub struct Field { declared_name: Rc, declared_name_source_range: SourceRange, is_public: bool, is_mut: bool, declared_type: Option>, initializer: Option>, } impl Field { pub fn new( declared_name: &str, declared_name_source_range: SourceRange, is_public: bool, is_mut: bool, declared_type: Option, initializer: Option, ) -> Self { Self { declared_name: declared_name.into(), declared_name_source_range, is_public, is_mut, declared_type: declared_type.map(Box::new), initializer: initializer.map(Box::new), } } pub fn gather_declared_names( &mut self, symbol_table: &mut SymbolTable, ) -> Result<(), Vec> { // 1. insert field symbol let to_insert = FieldSymbol::new(&self.declared_name, self.declared_name_source_range.clone()); symbol_table .insert_field_symbol(to_insert) .map_err(|e| match e { SymbolInsertError::AlreadyDeclared(already_declared) => { vec![Diagnostic::new( &format!( "Symbol {} already declared in current scope.", already_declared.symbol().borrow().declared_name() ), self.declared_name_source_range.start(), self.declared_name_source_range.end(), )] } })?; // 2. gather initializer, if present if let Some(initializer) = &mut self.initializer { initializer.gather_declared_names(symbol_table)?; } Ok(()) } pub fn check_name_usages(&mut self, symbol_table: &SymbolTable) -> Result<(), Vec> { if let Some(type_use) = &mut self.declared_type { type_use.check_name_usages(symbol_table)?; } // This is going to get hairy, because users might attempt to use a field in an initializer // (for either this field, or another one) before it's actually initialized. As such, we // need a way to prevent lookup of current class' fields in the initializer. // For now, the following is okay so long as we don't start referencing things in the // initializers. if let Some(initializer) = self.initializer.as_mut() { initializer.check_name_usages(symbol_table)?; } Ok(()) } }