deimos-lang/dmc-lib/src/diagnostic_factories.rs
2026-03-27 11:59:59 -05:00

120 lines
3.8 KiB
Rust

use crate::diagnostic::{Diagnostic, SecondaryLabel};
use crate::error_codes::{
CLASS_NO_CONSTRUCTOR, FIELD_NO_TYPE_OR_INIT, OUTER_CLASS_FIELD_USED_IN_INIT,
OUTER_CLASS_METHOD_USED_IN_INIT, SELF_CONSTRUCTOR_USED_IN_INIT, SELF_FIELD_USED_IN_INIT,
SELF_METHOD_USED_IN_INIT, SYMBOL_ALREADY_DECLARED, SYMBOL_NOT_FOUND,
};
use crate::source_range::SourceRange;
use crate::symbol::Symbol;
pub fn symbol_not_found(name: &str, source_range: &SourceRange) -> Diagnostic {
Diagnostic::new(
&format!("Symbol {} not found in scope.", name),
source_range.start(),
source_range.end(),
)
.with_error_code(SYMBOL_NOT_FOUND)
}
pub fn field_has_no_type_or_init(name: &str, source_range: &SourceRange) -> Diagnostic {
Diagnostic::new(
&format!("Field {} has no declared type nor initializer.", name),
source_range.start(),
source_range.end(),
)
.with_error_code(FIELD_NO_TYPE_OR_INIT)
.with_primary_label_message("Declare a type and/or an initializer.")
}
pub fn cannot_reference_field_in_init(name: &str, source_range: &SourceRange) -> Diagnostic {
Diagnostic::new(
&format!("Cannot reference field {} during initialization.", name),
source_range.start(),
source_range.end(),
)
.with_error_code(SELF_FIELD_USED_IN_INIT)
}
pub fn symbol_already_declared(already_inserted: &Symbol, would_insert: &Symbol) -> Diagnostic {
let secondary_label = if let Some(source_range) = already_inserted.declared_name_source_range()
{
Some(SecondaryLabel::new(
source_range.start(),
source_range.end(),
Some("Symbol already declared here.".to_string()),
))
} else {
None
};
let diagnostic = Diagnostic::new(
&format!(
"Symbol {} already declared in current scope.",
would_insert.declared_name()
),
would_insert.declared_name_source_range().unwrap().start(), // unwrap should be okay, since this is user code
would_insert.declared_name_source_range().unwrap().end(),
)
.with_error_code(SYMBOL_ALREADY_DECLARED);
if let Some(secondary_label) = secondary_label {
diagnostic.with_secondary_labels(&[secondary_label])
} else {
diagnostic
}
}
pub fn self_constructor_used_in_init(source_range: &SourceRange) -> Diagnostic {
Diagnostic::new(
"Cannot call Self constructor during initialization.",
source_range.start(),
source_range.end(),
)
.with_error_code(SELF_CONSTRUCTOR_USED_IN_INIT)
}
pub fn self_field_used_in_init(source_range: &SourceRange) -> Diagnostic {
Diagnostic::new(
"Cannot reference Self field during initialization.",
source_range.start(),
source_range.end(),
)
.with_error_code(SELF_FIELD_USED_IN_INIT)
}
pub fn self_method_used_in_init(source_range: &SourceRange) -> Diagnostic {
Diagnostic::new(
"Cannot call Self method during initialization.",
source_range.start(),
source_range.end(),
)
.with_error_code(SELF_METHOD_USED_IN_INIT)
}
pub fn outer_class_field_usage(source_range: &SourceRange) -> Diagnostic {
Diagnostic::new(
"Cannot reference an outer class member.",
source_range.start(),
source_range.end(),
)
.with_error_code(OUTER_CLASS_FIELD_USED_IN_INIT)
}
pub fn outer_class_method_usage(source_range: &SourceRange) -> Diagnostic {
Diagnostic::new(
"Cannot call an outer class method.",
source_range.start(),
source_range.end(),
)
.with_error_code(OUTER_CLASS_METHOD_USED_IN_INIT)
}
pub fn class_has_no_constructor(name: &str, source_range: &SourceRange) -> Diagnostic {
Diagnostic::new(
&format!("Class {} has no constructor.", name),
source_range.start(),
source_range.end(),
)
.with_error_code(CLASS_NO_CONSTRUCTOR)
}