84 lines
2.8 KiB
Rust
84 lines
2.8 KiB
Rust
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<str>,
|
|
declared_name_source_range: SourceRange,
|
|
is_public: bool,
|
|
is_mut: bool,
|
|
declared_type: Option<Box<TypeUse>>,
|
|
initializer: Option<Box<Expression>>,
|
|
}
|
|
|
|
impl Field {
|
|
pub fn new(
|
|
declared_name: &str,
|
|
declared_name_source_range: SourceRange,
|
|
is_public: bool,
|
|
is_mut: bool,
|
|
declared_type: Option<TypeUse>,
|
|
initializer: Option<Expression>,
|
|
) -> 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<Diagnostic>> {
|
|
// 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<Diagnostic>> {
|
|
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(())
|
|
}
|
|
}
|