diff options
| author | Laurenz <laurmaedje@gmail.com> | 2020-10-04 20:22:11 +0200 |
|---|---|---|
| committer | Laurenz <laurmaedje@gmail.com> | 2020-10-04 20:22:11 +0200 |
| commit | ef8aa763faa59fd62c90c6d6245e8d2c5eece35e (patch) | |
| tree | d36192af0c770b076a5004ba8bcae3c2df728c75 /src/diag.rs | |
| parent | a41d7ab47dda1e30465bdf91fd02bca0e634a38d (diff) | |
Shorten some names ↔
Diffstat (limited to 'src/diag.rs')
| -rw-r--r-- | src/diag.rs | 102 |
1 files changed, 102 insertions, 0 deletions
diff --git a/src/diag.rs b/src/diag.rs new file mode 100644 index 00000000..38f3d0a2 --- /dev/null +++ b/src/diag.rs @@ -0,0 +1,102 @@ +//! Diagnostics for source code. +//! +//! There are no fatal errors. The document will always compile and yield a +//! layout on a best effort process, but diagnostics are nevertheless generated +//! for incorrect things. + +use std::fmt::{self, Display, Formatter}; + +/// A diagnostic that arose in parsing or layouting. +#[derive(Debug, Clone, Eq, PartialEq, Ord, PartialOrd)] +#[cfg_attr(feature = "serialize", derive(serde::Serialize))] +pub struct Diag { + /// How severe / important the diagnostic is. + pub level: Level, + /// A message describing the diagnostic. + pub message: String, +} + +/// How severe / important a diagnostic is. +#[derive(Debug, Copy, Clone, Eq, PartialEq, Ord, PartialOrd, Hash)] +#[cfg_attr(feature = "serialize", derive(serde::Serialize))] +#[cfg_attr(feature = "serialize", serde(rename_all = "camelCase"))] +pub enum Level { + Warning, + Error, +} + +impl Diag { + /// Create a new diagnostic from message and level. + pub fn new(level: Level, message: impl Into<String>) -> Self { + Self { level, message: message.into() } + } +} + +impl Display for Level { + fn fmt(&self, f: &mut Formatter) -> fmt::Result { + f.pad(match self { + Self::Warning => "warning", + Self::Error => "error", + }) + } +} + +/// Construct a diagnostic with [`Error`] level. +/// +/// ``` +/// # use typstc::error; +/// # use typstc::syntax::Span; +/// # use typstc::Feedback; +/// # let span = Span::ZERO; +/// # let mut feedback = Feedback::new(); +/// # let name = ""; +/// // Create formatted error values. +/// let error = error!("expected {}", name); +/// +/// // Create spanned errors. +/// let spanned = error!(span, "there is an error here"); +/// +/// // Create an error and directly add it to existing feedback. +/// error!(@feedback, span, "oh no!"); +/// ``` +/// +/// [`Error`]: diagnostic/enum.Level.html#variant.Error +#[macro_export] +macro_rules! error { + ($($tts:tt)*) => { + $crate::__impl_diagnostic!($crate::diag::Level::Error; $($tts)*) + }; +} + +/// Construct a diagnostic with [`Warning`] level. +/// +/// This works exactly like `error!`. See its documentation for more +/// information. +/// +/// [`Warning`]: diagnostic/enum.Level.html#variant.Warning +#[macro_export] +macro_rules! warning { + ($($tts:tt)*) => { + $crate::__impl_diagnostic!($crate::diag::Level::Warning; $($tts)*) + }; +} + +/// Backs the `error!` and `warning!` macros. +#[macro_export] +#[doc(hidden)] +macro_rules! __impl_diagnostic { + ($level:expr; @$feedback:expr, $($tts:tt)*) => { + $feedback.diags.push($crate::__impl_diagnostic!($level; $($tts)*)); + }; + + ($level:expr; $fmt:literal $($tts:tt)*) => { + $crate::diag::Diag::new($level, format!($fmt $($tts)*)) + }; + + ($level:expr; $span:expr, $fmt:literal $($tts:tt)*) => { + $crate::syntax::Spanned::new( + $crate::__impl_diagnostic!($level; $fmt $($tts)*), + $span, + ) + }; +} |
