summaryrefslogtreecommitdiff
path: root/dhall/src/error
diff options
context:
space:
mode:
authorNadrieril2020-02-01 22:04:34 +0000
committerNadrieril2020-02-01 22:04:34 +0000
commit70eede4fd012f49dfab0e2e27fb3a4e4bbff6325 (patch)
treef9b4a75b5ffc878f6d5e5a40bd7c13c8de94a9f9 /dhall/src/error
parent72a6fef65bb3d34be1f501a1f6de66fb8a54fa04 (diff)
Implement once nice error using annotate_snippets
Diffstat (limited to 'dhall/src/error')
-rw-r--r--dhall/src/error/builder.rs100
-rw-r--r--dhall/src/error/mod.rs3
2 files changed, 103 insertions, 0 deletions
diff --git a/dhall/src/error/builder.rs b/dhall/src/error/builder.rs
new file mode 100644
index 0000000..e293220
--- /dev/null
+++ b/dhall/src/error/builder.rs
@@ -0,0 +1,100 @@
+use annotate_snippets::{
+ display_list::DisplayList,
+ formatter::DisplayListFormatter,
+ snippet::{Annotation, AnnotationType, Slice, Snippet, SourceAnnotation},
+};
+
+use crate::syntax::Span;
+
+#[derive(Debug, Clone)]
+pub struct ErrorBuilder {
+ message: String,
+ annotation_type: AnnotationType,
+ annotations: Vec<BuilderAnnotation>,
+}
+
+#[derive(Debug, Clone)]
+struct BuilderAnnotation {
+ span: Span,
+ message: String,
+ annotation_type: AnnotationType,
+}
+
+/// A builder that uses the annotate_snippets library to display nice error messages about source
+/// code locations.
+impl ErrorBuilder {
+ pub fn new(message: String) -> Self {
+ ErrorBuilder {
+ message,
+ annotation_type: AnnotationType::Error,
+ annotations: Vec::new(),
+ }
+ }
+ pub fn span_err(span: &Span, message: String) -> Self {
+ let mut builder = Self::new(message.clone());
+ builder.annotate_err(span, message);
+ builder
+ }
+
+ pub fn annotate_err(&mut self, span: &Span, message: String) {
+ self.annotations.push(BuilderAnnotation {
+ span: span.clone(),
+ message,
+ annotation_type: AnnotationType::Error,
+ })
+ }
+ pub fn annotate_info(&mut self, span: &Span, message: String) {
+ self.annotations.push(BuilderAnnotation {
+ span: span.clone(),
+ message,
+ annotation_type: AnnotationType::Help,
+ })
+ }
+
+ // TODO: handle multiple files
+ pub fn format(self) -> String {
+ let mut input = None;
+ let annotations = self
+ .annotations
+ .into_iter()
+ .filter_map(|annot| {
+ let span = match annot.span {
+ Span::Parsed(span) => span,
+ _ => return None,
+ };
+ if input.is_none() {
+ input = Some(span.to_input());
+ }
+ Some(SourceAnnotation {
+ label: annot.message,
+ annotation_type: annot.annotation_type,
+ range: span.as_char_range(),
+ })
+ })
+ .collect();
+
+ let input = match input {
+ Some(input) => input,
+ None => return format!("[unknown location] {}", self.message),
+ };
+
+ let snippet = Snippet {
+ title: Some(Annotation {
+ label: Some(self.message),
+ id: None,
+ annotation_type: self.annotation_type,
+ }),
+ footer: vec![],
+ slices: vec![Slice {
+ source: input,
+ line_start: 1, // TODO
+ origin: Some("<current file>".to_string()),
+ fold: true,
+ annotations,
+ }],
+ };
+ let dl = DisplayList::from(snippet);
+ let dlf = DisplayListFormatter::new(true, false);
+ format!("{}", dlf.format(&dl))
+ }
+}
diff --git a/dhall/src/error/mod.rs b/dhall/src/error/mod.rs
index 4df018d..5b7693e 100644
--- a/dhall/src/error/mod.rs
+++ b/dhall/src/error/mod.rs
@@ -5,6 +5,9 @@ use crate::semantics::Value;
use crate::syntax::{Import, ParseError};
use crate::NormalizedExpr;
+mod builder;
+pub(crate) use builder::*;
+
pub type Result<T> = std::result::Result<T, Error>;
#[derive(Debug)]