use std::fmt;
#[derive(Debug, Clone, Copy, PartialEq, Eq, PartialOrd, Ord)]
pub enum Severity {
Hint,
Info,
Warning,
Error,
Fatal,
}
#[derive(Debug, Clone, PartialEq, Eq)]
pub struct DiagnosticLocation {
pub file: String,
pub line: usize,
pub column: usize,
pub span: std::ops::Range<usize>,
}
#[derive(Debug, Clone)]
pub struct Diagnostic {
pub severity: Severity,
pub message: String,
pub location: DiagnosticLocation,
pub hints: Vec<String>,
pub code: Option<String>,
}
impl fmt::Display for Diagnostic {
fn fmt(&self, f: &mut fmt::Formatter<'_>) -> fmt::Result {
let severity_str = match self.severity {
Severity::Hint => "hint",
Severity::Info => "info",
Severity::Warning => "warning",
Severity::Error => "error",
Severity::Fatal => "fatal error",
};
write!(
f,
"{}:{}:{}: {}: {}",
self.location.file,
self.location.line,
self.location.column,
severity_str,
self.message
)?;
if let Some(code) = &self.code {
write!(f, " [{}]", code)?;
}
Ok(())
}
}
pub trait DiagnosticEmitter {
fn emit(&mut self, diagnostic: Diagnostic);
fn emit_error(&mut self, location: DiagnosticLocation, message: &str) {
self.emit(Diagnostic {
severity: Severity::Error,
message: message.to_string(),
location,
hints: vec![],
code: None,
});
}
fn emit_warning(&mut self, location: DiagnosticLocation, message: &str) {
self.emit(Diagnostic {
severity: Severity::Warning,
message: message.to_string(),
location,
hints: vec![],
code: None,
});
}
fn emit_hint(&mut self, location: DiagnosticLocation, message: &str) {
self.emit(Diagnostic {
severity: Severity::Hint,
message: message.to_string(),
location,
hints: vec![],
code: None,
});
}
fn has_errors(&self) -> bool;
fn error_count(&self) -> usize;
fn warning_count(&self) -> usize;
fn clear(&mut self);
fn diagnostics(&self) -> &[Diagnostic];
}
pub trait DiagnosticRenderer {
fn render(&self, diagnostic: &Diagnostic) -> String;
fn render_with_context(&self, diagnostic: &Diagnostic, source: &str) -> String;
fn render_all(&self, diagnostics: &[Diagnostic]) -> String;
fn enable_colors(&mut self, enabled: bool);
}
pub trait DiagnosticErrorReporter {
fn report_error(&mut self, message: &str);
fn report_error_with_location(&mut self, location: DiagnosticLocation, message: &str);
fn report_warning(&mut self, message: &str);
fn report_fatal(&mut self, message: &str) -> !;
fn has_errors(&self) -> bool;
}
pub trait SourceCache {
fn add_source(&mut self, file: String, source: String);
fn get_source(&self, file: &str) -> Option<&str>;
fn get_line(&self, file: &str, line: usize) -> Option<&str>;
fn remove_source(&mut self, file: &str);
}