summaryrefslogtreecommitdiff
path: root/src/problem.rs
diff options
context:
space:
mode:
Diffstat (limited to 'src/problem.rs')
-rw-r--r--src/problem.rs94
1 files changed, 94 insertions, 0 deletions
diff --git a/src/problem.rs b/src/problem.rs
new file mode 100644
index 00000000..3c2d3635
--- /dev/null
+++ b/src/problem.rs
@@ -0,0 +1,94 @@
+//! Problems (errors / warnings) in _Typst_ documents.
+//!
+//! There are no fatal errors in _Typst_. The document will always compile and
+//! yield a layout. However, this is a best effort process and bad things will
+//! still generate errors and warnings.
+
+use serde::Serialize;
+use crate::syntax::span::SpanVec;
+
+
+/// A list of spanned problems.
+pub type Problems = SpanVec<Problem>;
+
+/// A problem that arose in parsing or layouting.
+#[derive(Debug, Clone, Eq, PartialEq, Serialize)]
+pub struct Problem {
+ /// How severe / important the problem is.
+ pub severity: Severity,
+ /// A message describing the problem.
+ pub message: String,
+}
+
+/// How severe / important a problem is.
+#[derive(Debug, Copy, Clone, Eq, PartialEq, Ord, PartialOrd, Hash, Serialize)]
+#[serde(rename_all = "camelCase")]
+pub enum Severity {
+ /// Something in the code is not good.
+ Warning,
+ /// Something in the code is wrong!
+ Error,
+}
+
+impl Problem {
+ /// Create a new problem from message and severity.
+ pub fn new(message: impl Into<String>, severity: Severity) -> Self {
+ Self { message: message.into(), severity }
+ }
+}
+
+/// Construct a problem with `Error` severity.
+///
+/// ```
+/// # use typstc::error;
+/// # use typstc::syntax::span::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!");
+/// ```
+#[macro_export]
+macro_rules! error {
+ ($($tts:tt)*) => {
+ $crate::__impl_problem!($crate::problem::Severity::Error; $($tts)*)
+ };
+}
+
+/// Construct a problem with `Warning` severity.
+///
+/// This works exactly like `error!`. See its documentation for more
+/// information.
+#[macro_export]
+macro_rules! warning {
+ ($($tts:tt)*) => {
+ $crate::__impl_problem!($crate::problem::Severity::Warning; $($tts)*)
+ };
+}
+
+/// Backs the `error!` and `warning!` macros.
+#[macro_export]
+#[doc(hidden)]
+macro_rules! __impl_problem {
+ ($severity:expr; @$feedback:expr, $($tts:tt)*) => {
+ $feedback.problems.push($crate::__impl_problem!($severity; $($tts)*));
+ };
+
+ ($severity:expr; $fmt:literal $($tts:tt)*) => {
+ $crate::problem::Problem::new(format!($fmt $($tts)*), $severity)
+ };
+
+ ($severity:expr; $span:expr, $fmt:literal $($tts:tt)*) => {
+ $crate::syntax::span::Spanned::new(
+ $crate::__impl_problem!($severity; $fmt $($tts)*),
+ $span,
+ )
+ };
+}