summaryrefslogtreecommitdiff
path: root/src/diag.rs
diff options
context:
space:
mode:
authorLaurenz <laurmaedje@gmail.com>2021-07-30 18:04:08 +0200
committerLaurenz <laurmaedje@gmail.com>2021-07-30 18:49:19 +0200
commit1ee1d078e2480ddd08d40915bc7a74a8352acff0 (patch)
tree1e7ff367278a19fead3e404cf06d65bfb80a6cd9 /src/diag.rs
parent42a27b48df427edf8dbb624c51551a90ecf2e7ea (diff)
Fatal errors
- Makes errors fatal, so that a phase is only reached when all previous phases were error-free - Parsing still recovers and can produce multiple errors - Evaluation fails fast and can thus produce only a single error (except for parse errors due to an import) - The single error that could occur during execution is removed for now - Removes Value::Error variant
Diffstat (limited to 'src/diag.rs')
-rw-r--r--src/diag.rs127
1 files changed, 42 insertions, 85 deletions
diff --git a/src/diag.rs b/src/diag.rs
index 6158b5c0..76d7c6b7 100644
--- a/src/diag.rs
+++ b/src/diag.rs
@@ -1,113 +1,70 @@
-//! Diagnostics for source code.
-//!
-//! Errors are never fatal, the document will always compile and yield a layout.
-
-use std::collections::BTreeSet;
-use std::fmt::{self, Display, Formatter};
+//! Diagnostics.
use serde::{Deserialize, Serialize};
+use crate::loading::FileId;
use crate::syntax::Span;
-/// The result of some pass: Some output `T` and diagnostics.
-#[derive(Debug, Clone, Eq, PartialEq, Serialize, Deserialize)]
-pub struct Pass<T> {
- /// The output of this compilation pass.
- pub output: T,
- /// User diagnostics accumulated in this pass.
- pub diags: DiagSet,
-}
-
-impl<T> Pass<T> {
- /// Create a new pass from output and diagnostics.
- pub fn new(output: T, diags: DiagSet) -> Self {
- Self { output, diags }
- }
-}
+/// The result type for typesetting and all its subpasses.
+pub type TypResult<T> = Result<T, Box<Vec<Error>>>;
-/// A set of diagnostics.
-///
-/// Since this is a [`BTreeSet`], there cannot be two equal (up to span)
-/// diagnostics and you can quickly iterate diagnostics in source location
-/// order.
-pub type DiagSet = BTreeSet<Diag>;
+/// A result type with a string error message.
+pub type StrResult<T> = Result<T, String>;
-/// A diagnostic with severity level and message.
+/// An error in a source file.
#[derive(Debug, Clone, Eq, PartialEq, Ord, PartialOrd, Serialize, Deserialize)]
-pub struct Diag {
- /// The source code location.
+pub struct Error {
+ /// The file that contains the error.
+ pub file: FileId,
+ /// The erronous location in the source code.
pub span: Span,
- /// How severe / important the diagnostic is.
- pub level: Level,
- /// A message describing the diagnostic.
+ /// A diagnostic message describing the problem.
pub message: String,
}
-impl Diag {
- /// Create a new diagnostic from message and level.
- pub fn new(span: impl Into<Span>, level: Level, message: impl Into<String>) -> Self {
+impl Error {
+ /// Create a new, bare error.
+ pub fn new(file: FileId, span: impl Into<Span>, message: impl Into<String>) -> Self {
Self {
+ file,
span: span.into(),
- level,
message: message.into(),
}
}
-}
-impl Display for Diag {
- fn fmt(&self, f: &mut Formatter) -> fmt::Result {
- write!(f, "{}: {}", self.level, self.message)
+ /// Create a boxed vector containing one error. The return value is suitable
+ /// as the `Err` variant of a [`TypResult`].
+ pub fn boxed(
+ file: FileId,
+ span: impl Into<Span>,
+ message: impl Into<String>,
+ ) -> Box<Vec<Self>> {
+ Box::new(vec![Self::new(file, span, message)])
}
-}
-
-/// How severe / important a diagnostic is.
-#[derive(Debug, Copy, Clone, Eq, PartialEq, Ord, PartialOrd)]
-#[derive(Serialize, Deserialize)]
-#[serde(rename_all = "kebab-case")]
-pub enum Level {
- Warning,
- Error,
-}
-impl Display for Level {
- fn fmt(&self, f: &mut Formatter) -> fmt::Result {
- f.pad(match self {
- Self::Warning => "warning",
- Self::Error => "error",
- })
+ /// Partially build a vec-boxed error, returning a function that just needs
+ /// the message.
+ ///
+ /// This is useful in to convert from [`StrResult`] to a [`TypResult`] using
+ /// [`map_err`](Result::map_err).
+ pub fn partial(
+ file: FileId,
+ span: impl Into<Span>,
+ ) -> impl FnOnce(String) -> Box<Vec<Self>> {
+ move |message| Self::boxed(file, span, message)
}
}
-/// Construct a diagnostic with [`Error`](Level::Error) level.
-///
-/// ```
-/// # use typst::error;
-/// # use typst::syntax::Span;
-/// # let span = Span::ZERO;
-/// # let thing = "";
-/// let error = error!(span, "there is an error with {}", thing);
-/// ```
+/// Early-return with a vec-boxed [`Error`].
#[macro_export]
-macro_rules! error {
- ($span:expr, $($tts:tt)*) => {
- $crate::diag::Diag::new(
- $span,
- $crate::diag::Level::Error,
- format!($($tts)*),
- )
+macro_rules! bail {
+ ($file:expr, $span:expr, $message:expr $(,)?) => {
+ return Err(Box::new(vec![$crate::diag::Error::new(
+ $file, $span, $message,
+ )]));
};
-}
-/// Construct a diagnostic with [`Warning`](Level::Warning) level.
-///
-/// This works exactly like [`error!`].
-#[macro_export]
-macro_rules! warning {
- ($span:expr, $($tts:tt)*) => {
- $crate::diag::Diag::new(
- $span,
- $crate::diag::Level::Warning,
- format!($($tts)*),
- )
+ ($file:expr, $span:expr, $fmt:expr, $($arg:expr),+ $(,)?) => {
+ $crate::bail!($file, $span, format!($fmt, $($arg),+));
};
}