From 75802e6ee4e94604b379ed64b422c8fc254bf8a4 Mon Sep 17 00:00:00 2001 From: Jesse Brault Date: Thu, 12 Mar 2026 16:15:03 -0500 Subject: [PATCH] Expand diagnostic API. --- dm/src/run.rs | 38 +++++++++++++++++-- dmc-lib/src/diagnostic.rs | 80 +++++++++++++++++++++++++++++++++++---- 2 files changed, 107 insertions(+), 11 deletions(-) diff --git a/dm/src/run.rs b/dm/src/run.rs index df4414e..5c273a2 100644 --- a/dm/src/run.rs +++ b/dm/src/run.rs @@ -125,12 +125,42 @@ fn report_and_exit( let writer = StandardStream::stderr(ColorChoice::Always); let config = term::Config::default(); for diagnostic in diagnostics { - let csr_diagnostic = codespan_reporting::diagnostic::Diagnostic::error() + let mut primary_label = + Label::primary(script_file_id, diagnostic.start()..diagnostic.end()); + if let Some(primary_label_message) = diagnostic.primary_label_message() { + primary_label = primary_label.with_message(primary_label_message); + } + + let secondary_labels: Vec> = diagnostic + .secondary_labels() + .iter() + .map(|secondary_label| { + let mut label = Label::secondary( + script_file_id, + secondary_label.start()..secondary_label.end(), + ); + if let Some(message) = secondary_label.message() { + label = label.with_message(message); + } + label + }) + .collect(); + + let mut csr_diagnostic = codespan_reporting::diagnostic::Diagnostic::error() .with_message(diagnostic.message()) - .with_label(Label::primary( - script_file_id, - diagnostic.start()..diagnostic.end(), + .with_label(primary_label) + .with_labels(secondary_labels); + + if let Some(error_code) = diagnostic.error_code() { + csr_diagnostic = csr_diagnostic.with_code(format!("E{}", error_code)); + } + + if let Some((reporter_file, reporter_line)) = diagnostic.reporter() { + csr_diagnostic = csr_diagnostic.with_note(format!( + "Reported by (Rust) source: {}, line {}", + reporter_file, reporter_line )); + } term::emit_to_write_style(&mut writer.lock(), &config, files, &csr_diagnostic).unwrap(); } diff --git a/dmc-lib/src/diagnostic.rs b/dmc-lib/src/diagnostic.rs index 06ee3f8..4044c2f 100644 --- a/dmc-lib/src/diagnostic.rs +++ b/dmc-lib/src/diagnostic.rs @@ -1,20 +1,26 @@ #[derive(Debug)] pub struct Diagnostic { message: String, + primary_label_message: Option, + error_code: Option, start: usize, end: usize, reporter_file: Option<&'static str>, reporter_line: Option, + secondary_labels: Vec, } impl Diagnostic { pub fn new(message: &str, start: usize, end: usize) -> Self { Self { message: message.into(), + primary_label_message: None, + error_code: None, start, end, reporter_line: None, reporter_file: None, + secondary_labels: vec![], } } @@ -22,6 +28,14 @@ impl Diagnostic { &self.message } + pub fn primary_label_message(&self) -> Option<&str> { + self.primary_label_message.as_deref() + } + + pub fn error_code(&self) -> Option { + self.error_code + } + pub fn start(&self) -> usize { self.start } @@ -30,13 +44,65 @@ impl Diagnostic { self.end } - pub fn with_reporter(&self, file: &'static str, line: u32) -> Self { - Self { - message: self.message.clone(), - start: self.start, - end: self.end, - reporter_file: Some(file), - reporter_line: Some(line), + pub fn reporter(&self) -> Option<(&'static str, u32)> { + if let Some(file) = self.reporter_file { + Some((file, self.reporter_line.unwrap())) + } else { + None } } + + pub fn secondary_labels(&self) -> &[SecondaryLabel] { + &self.secondary_labels + } + + pub fn with_error_code(mut self, code: usize) -> Self { + self.error_code = Some(code); + self + } + + pub fn with_primary_label_message(mut self, message: &str) -> Self { + self.primary_label_message = Some(message.into()); + self + } + + pub fn with_reporter(mut self, file: &'static str, line: u32) -> Self { + self.reporter_file = Some(file); + self.reporter_line = Some(line); + self + } + + pub fn with_secondary_labels(mut self, labels: &[SecondaryLabel]) -> Self { + self.secondary_labels.extend_from_slice(labels); + self + } +} + +#[derive(Debug, Clone)] +pub struct SecondaryLabel { + start: usize, + end: usize, + message: Option, +} + +impl SecondaryLabel { + pub fn new(start: usize, end: usize, message: Option) -> Self { + Self { + start, + end, + message, + } + } + + pub fn start(&self) -> usize { + self.start + } + + pub fn end(&self) -> usize { + self.end + } + + pub fn message(&self) -> Option<&str> { + self.message.as_deref() + } }