zenith_core/diagnostics.rs
1//! Shared diagnostic types used across all Zenith validation passes.
2//!
3//! Diagnostics are collected without hard-failing — callers push them into a
4//! `Vec<Diagnostic>` and continue resolving what they can. `lib.rs` re-exports
5//! the most-used symbols at the crate root.
6
7use crate::ast::Span;
8
9/// The severity level of a [`Diagnostic`].
10#[derive(Debug, Clone, Copy, PartialEq, Eq, PartialOrd, Ord)]
11pub enum Severity {
12 /// A definite problem that prevents correct output.
13 Error,
14 /// A potential problem or version-relative issue; output may still be
15 /// produced.
16 Warning,
17 /// Informational note; does not block output.
18 Advisory,
19}
20
21/// A single structured diagnostic produced during validation or resolution.
22///
23/// Diagnostics carry a stable `code` that agents and tooling can key on, a
24/// human-readable `message`, an optional source `span`, and an optional
25/// `subject_id` naming the token (or future: node/style) the diagnostic is
26/// about.
27#[derive(Debug, Clone, PartialEq)]
28pub struct Diagnostic {
29 /// Stable dot-separated code, e.g. `"token.cyclic_reference"`.
30 pub code: String,
31 /// Severity classification.
32 pub severity: Severity,
33 /// Human-readable description.
34 pub message: String,
35 /// Source location, when available.
36 pub span: Option<Span>,
37 /// The token ID (or future: node/style ID) the diagnostic concerns.
38 pub subject_id: Option<String>,
39}
40
41impl Diagnostic {
42 /// Construct a new diagnostic with all fields explicit.
43 pub fn new(
44 code: impl Into<String>,
45 severity: Severity,
46 message: impl Into<String>,
47 span: Option<Span>,
48 subject_id: Option<String>,
49 ) -> Self {
50 Self {
51 code: code.into(),
52 severity,
53 message: message.into(),
54 span,
55 subject_id,
56 }
57 }
58
59 /// Shorthand for an [`Severity::Error`]-level diagnostic.
60 pub fn error(
61 code: impl Into<String>,
62 message: impl Into<String>,
63 span: Option<Span>,
64 subject_id: Option<String>,
65 ) -> Self {
66 Self::new(code, Severity::Error, message, span, subject_id)
67 }
68
69 /// Shorthand for a [`Severity::Warning`]-level diagnostic.
70 pub fn warning(
71 code: impl Into<String>,
72 message: impl Into<String>,
73 span: Option<Span>,
74 subject_id: Option<String>,
75 ) -> Self {
76 Self::new(code, Severity::Warning, message, span, subject_id)
77 }
78
79 /// Shorthand for an [`Severity::Advisory`]-level diagnostic.
80 pub fn advisory(
81 code: impl Into<String>,
82 message: impl Into<String>,
83 span: Option<Span>,
84 subject_id: Option<String>,
85 ) -> Self {
86 Self::new(code, Severity::Advisory, message, span, subject_id)
87 }
88}