microcad_lang/diag/
mod.rs

1// Copyright © 2024-2025 The µcad authors <info@ucad.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_handler;
14mod diag_list;
15mod diagnostic;
16mod level;
17
18pub use diag_handler::*;
19pub use diag_list::*;
20pub use diagnostic::*;
21pub use level::*;
22
23use crate::{eval::*, src_ref::*};
24
25/// A trait to add diagnostics with different levels conveniently.
26pub trait PushDiag {
27    /// Push a diagnostic message (must be implemented).
28    fn push_diag(&mut self, diag: Diagnostic) -> EvalResult<()>;
29
30    /// Push new trace message.
31    fn trace(&mut self, src: &impl SrcReferrer, message: String) {
32        self.push_diag(Diagnostic::Trace(Refer::new(message, src.src_ref())))
33            .expect("could not push diagnostic trace message");
34    }
35    /// Push new informative message.
36    fn info(&mut self, src: &impl SrcReferrer, message: String) {
37        self.push_diag(Diagnostic::Info(Refer::new(message, src.src_ref())))
38            .expect("could not push diagnostic info message");
39    }
40    /// Push new warning.
41    fn warning(
42        &mut self,
43        src: &impl SrcReferrer,
44        error: impl std::error::Error + 'static,
45    ) -> EvalResult<()> {
46        self.push_diag(Diagnostic::Warning(Refer::new(error.into(), src.src_ref())))
47    }
48    /// Push new error.
49    fn error(
50        &mut self,
51        src: &impl SrcReferrer,
52        error: impl std::error::Error + 'static,
53    ) -> EvalResult<()> {
54        let err = Diagnostic::Error(Refer::new(error.into(), src.src_ref()));
55        log::error!("{err}");
56        self.push_diag(err)
57    }
58}
59
60/// Diagnosis trait gives access about collected errors.
61pub trait Diag {
62    /// Pretty print all errors.
63    fn fmt_diagnosis(&self, f: &mut dyn std::fmt::Write) -> std::fmt::Result;
64
65    /// Pretty write all errors into a file.
66    fn write_diagnosis(&self, w: &mut dyn std::io::Write) -> std::io::Result<()> {
67        write!(w, "{}", self.diagnosis())
68    }
69
70    /// Get pretty printed errors as string.
71    fn diagnosis(&self) -> String {
72        let mut str = String::new();
73        self.fmt_diagnosis(&mut str).expect("displayable diagnosis");
74        str
75    }
76
77    /// Returns true if there are errors.
78    fn has_errors(&self) -> bool {
79        self.error_count() > 0
80    }
81
82    /// Return number of occurred errors.
83    fn error_count(&self) -> u32;
84
85    /// Return all lines with errors
86    fn error_lines(&self) -> std::collections::HashSet<usize>;
87
88    /// Return all lines with warnings
89    fn warning_lines(&self) -> std::collections::HashSet<usize>;
90}
91
92/// Trait to write something with Display trait into a file.
93pub trait WriteToFile: std::fmt::Display {
94    /// Write something to a file.
95    fn write_to_file(&self, filename: &impl AsRef<std::path::Path>) -> std::io::Result<()> {
96        use std::io::Write;
97        let file = std::fs::File::create(filename)?;
98        let mut writer = std::io::BufWriter::new(file);
99        write!(writer, "{self}")
100    }
101}