// Diagnostic system // // Copyright (C) 2014-2021 Ryan Specialty Group, LLC. // // This file is part of TAME. // // This program is free software: you can redistribute it and/or modify // it under the terms of the GNU General Public License as published by // the Free Software Foundation, either version 3 of the License, or // (at your option) any later version. // // This program is distributed in the hope that it will be useful, // but WITHOUT ANY WARRANTY; without even the implied warranty of // MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the // GNU General Public License for more details. // // You should have received a copy of the GNU General Public License // along with this program. If not, see . //! Diagnostic system for error reporting. //! //! This system is heavily motivated by Rust's. //! While the data structures and organization may differ, //! the diagnostic output is visually similar. mod report; pub use report::{Reporter, VisualReporter}; use core::fmt; use std::{error::Error, fmt::Display}; use crate::span::Span; /// Diagnostic report. /// /// This describes an error condition or other special event using a series /// of [`Span`]s to describe the source, cause, and circumstances around /// an event. pub trait Diagnostic: Error + Sized { /// Produce a series of [`AnnotatedSpan`]s describing the source and /// circumstances of the diagnostic event. fn describe(&self) -> Vec; } /// Diagnostic severity level. /// /// Levels are used both for entire reports and for styling of individual /// [`AnnotatedSpan`]s. #[derive(Debug, PartialEq, Eq, Clone)] pub enum Level { /// An error internal to TAMER that the user cannot resolve, /// but may be able to work around. InternalError, /// A user-resolvable error. /// /// These represent errors resulting from the user's input. Error, /// Useful information that supplements other messages. /// /// This is most often used when multiple spans are in play for a given /// diagnostic report. Note, /// Additional advice to the user that may help in debugging or fixing a /// problem. /// /// These messages may suggest concrete fixes and are intended to /// hopefully replace having to request advice from a human. /// Unlike other severity levels which provide concrete factual /// information, /// help messages may be more speculative. Help, } impl Display for Level { fn fmt(&self, f: &mut fmt::Formatter<'_>) -> fmt::Result { match self { Level::InternalError => write!(f, "internal error"), Level::Error => write!(f, "error"), Level::Note => write!(f, "note"), Level::Help => write!(f, "help"), } } } /// A label associated with a report or [`Span`]. /// /// See [`AnnotatedSpan`]. #[derive(Debug, PartialEq, Eq, Clone)] pub struct Label(String); impl Display for Label { fn fmt(&self, f: &mut fmt::Formatter<'_>) -> fmt::Result { Display::fmt(&self.0, f) } } impl From for Label { fn from(s: String) -> Self { Self(s) } } impl From<&str> for Label { fn from(s: &str) -> Self { String::from(s).into() } } /// A span with an associated severity level and optional label. /// /// Annotated spans are intended to guide users through debugging a /// diagnostic message by describing important source locations that /// contribute to a given diagnostic event. #[derive(Debug, PartialEq, Eq, Clone)] pub struct AnnotatedSpan(Span, Level, Option