Skip to main content

microcad_lang_base/diag/
mod.rs

1// Copyright © 2024-2026 The µcad authors <info@microcad.xyz>
2// SPDX-License-Identifier: AGPL-3.0-or-later
3
4//! Handling of diagnostic errors.
5//!
6//! While *evaluation* µcad is collecting [`Diagnostic`] messages.
7//!
8//! This is done in [`DiagHandler`] by providing the following traits:
9//!
10//! - [`PushDiag`]: Collects error in [`DiagHandler`]
11//! - [`Diag`]: Get diagnostic messages
12
13mod diag_error;
14mod diag_handler;
15mod diag_list;
16mod diagnostic;
17mod level;
18
19pub use diag_error::*;
20pub use diag_handler::*;
21pub use diag_list::*;
22pub use diagnostic::*;
23pub use level::*;
24use miette::Report;
25
26use crate::src_ref::*;
27
28/// A trait to add diagnostics with different levels conveniently.
29pub trait PushDiag {
30    /// Push a diagnostic message (must be implemented).
31    fn push_diag(&mut self, diag: Diagnostic) -> DiagResult<()>;
32
33    /// Push new trace message.
34    fn trace(&mut self, src: &impl SrcReferrer, message: String) {
35        self.push_diag(Diagnostic::Trace(Refer::new(
36            Report::msg(message),
37            src.src_ref(),
38        )))
39        .expect("could not push diagnostic trace message");
40    }
41    /// Push new informative message.
42    fn info(&mut self, src: &impl SrcReferrer, message: String) {
43        self.push_diag(Diagnostic::Info(Refer::new(
44            Report::msg(message),
45            src.src_ref(),
46        )))
47        .expect("could not push diagnostic info message");
48    }
49    /// Push new warning.
50    fn warning(&mut self, src: &impl SrcReferrer, err: impl Into<Report>) -> DiagResult<()> {
51        let err = Diagnostic::Warning(Refer::new(err.into(), src.src_ref()));
52        if cfg!(feature = "ansi-color") {
53            log::warn!("{}", color_print::cformat!("<y,s>{err}</>"));
54        } else {
55            log::warn!("{err}");
56        }
57        self.push_diag(err)
58    }
59    /// Push new error.
60    fn error(&mut self, src: &impl SrcReferrer, err: impl Into<Report>) -> DiagResult<()> {
61        let err = Diagnostic::Error(Refer::new(err.into(), src.src_ref()));
62        if cfg!(feature = "ansi-color") {
63            log::error!("{}", color_print::cformat!("<r,s>{err}</>"));
64        } else {
65            log::error!("{err}");
66        }
67        self.push_diag(err)
68    }
69}
70
71/// Diagnosis trait gives access about collected errors.
72pub trait Diag {
73    /// Pretty print all errors.
74    fn fmt_diagnosis(&self, f: &mut dyn std::fmt::Write) -> std::fmt::Result;
75
76    /// Pretty write all errors into a file.
77    fn write_diagnosis(&self, w: &mut dyn std::io::Write) -> std::io::Result<()> {
78        write!(w, "{}", self.diagnosis())
79    }
80
81    /// Get pretty printed errors as string.
82    fn diagnosis(&self) -> String {
83        let mut str = String::new();
84        self.fmt_diagnosis(&mut str).expect("displayable diagnosis");
85        str
86    }
87
88    /// Returns true if there are warnings.
89    fn has_warnings(&self) -> bool {
90        self.warning_count() > 0
91    }
92
93    /// Return number of occurred warnings.
94    fn warning_count(&self) -> u32;
95
96    /// Returns true if there are errors.
97    fn has_errors(&self) -> bool {
98        self.error_count() > 0
99    }
100
101    /// Return number of occurred errors.
102    fn error_count(&self) -> u32;
103
104    /// Return all lines with errors
105    fn error_lines(&self) -> std::collections::HashSet<usize>;
106
107    /// Return all lines with warnings
108    fn warning_lines(&self) -> std::collections::HashSet<usize>;
109}