summaryrefslogtreecommitdiff
path: root/dhall/src/syntax
diff options
context:
space:
mode:
authorNadrieril Feneanar2020-02-02 18:21:38 +0000
committerGitHub2020-02-02 18:21:38 +0000
commitb7b5a0d27eb0cccdcd0c532a7042b3514eacbe40 (patch)
treea65cf1d2a53d67d2ea8f808c9a8408a8f96713e7 /dhall/src/syntax
parent72a6fef65bb3d34be1f501a1f6de66fb8a54fa04 (diff)
parentf3681f7a32ddb78db4d564769b50b697c54ebeac (diff)
Merge pull request #127 from Nadrieril/nicer-type-errors
Enable multiple locations for type errors
Diffstat (limited to 'dhall/src/syntax')
-rw-r--r--dhall/src/syntax/ast/expr.rs6
-rw-r--r--dhall/src/syntax/ast/span.rs30
-rw-r--r--dhall/src/syntax/text/parser.rs39
3 files changed, 54 insertions, 21 deletions
diff --git a/dhall/src/syntax/ast/expr.rs b/dhall/src/syntax/ast/expr.rs
index 28a0aee..b493fdb 100644
--- a/dhall/src/syntax/ast/expr.rs
+++ b/dhall/src/syntax/ast/expr.rs
@@ -275,6 +275,12 @@ impl<E> Expr<E> {
span: self.span.clone(),
}
}
+ pub fn with_span(self, span: Span) -> Self {
+ Expr {
+ kind: self.kind,
+ span,
+ }
+ }
pub fn traverse_resolve_mut<Err, F1>(
&mut self,
diff --git a/dhall/src/syntax/ast/span.rs b/dhall/src/syntax/ast/span.rs
index f9c7008..ffdd82c 100644
--- a/dhall/src/syntax/ast/span.rs
+++ b/dhall/src/syntax/ast/span.rs
@@ -24,6 +24,20 @@ pub enum Span {
Artificial,
}
+impl ParsedSpan {
+ pub(crate) fn to_input(&self) -> String {
+ self.input.to_string()
+ }
+ /// Convert to a char range for consumption by annotate_snippets.
+ /// This compensates for https://github.com/rust-lang/annotate-snippets-rs/issues/24
+ pub(crate) fn as_char_range(&self) -> (usize, usize) {
+ (
+ char_idx_from_byte_idx(&self.input, self.start),
+ char_idx_from_byte_idx(&self.input, self.end),
+ )
+ }
+}
+
impl Span {
pub(crate) fn make(input: Rc<str>, sp: pest::Span) -> Self {
Span::Parsed(ParsedSpan {
@@ -79,3 +93,19 @@ impl Span {
format!("{}", err)
}
}
+
+/// Convert a byte idx into a string into a char idx for consumption by annotate_snippets.
+fn char_idx_from_byte_idx(input: &str, idx: usize) -> usize {
+ let char_idx = input
+ .char_indices()
+ .enumerate()
+ .find(|(_, (i, _))| *i == idx)
+ .unwrap()
+ .0;
+ // Unix-style newlines are counted as two chars (see
+ // https://github.com/rust-lang/annotate-snippets-rs/issues/24).
+ let nbr_newlines = input[..idx].chars().filter(|c| *c == '\n').count();
+ let nbr_carriage_returns =
+ input[..idx].chars().filter(|c| *c == '\r').count();
+ char_idx + nbr_newlines - nbr_carriage_returns
+}
diff --git a/dhall/src/syntax/text/parser.rs b/dhall/src/syntax/text/parser.rs
index 2ec63e2..8d571c0 100644
--- a/dhall/src/syntax/text/parser.rs
+++ b/dhall/src/syntax/text/parser.rs
@@ -11,7 +11,7 @@ use crate::syntax::ExprKind::*;
use crate::syntax::{
Double, FilePath, FilePrefix, Hash, ImportLocation, ImportMode, Integer,
InterpolatedText, InterpolatedTextContents, Label, NaiveDouble, Natural,
- Scheme, Span, UnspannedExpr, URL, V,
+ Scheme, Span, URL, V,
};
use crate::Normalized;
@@ -21,6 +21,7 @@ use crate::Normalized;
// are here and hopefully you can figure out how they work.
type Expr = syntax::Expr<Normalized>;
+type UnspannedExpr = syntax::UnspannedExpr<Normalized>;
type ParsedText = InterpolatedText<Expr>;
type ParsedTextContents = InterpolatedTextContents<Expr>;
type ParseInput<'input> = pest_consume::Node<'input, Rule, Rc<str>>;
@@ -78,14 +79,10 @@ impl crate::syntax::Builtin {
fn input_to_span(input: ParseInput) -> Span {
Span::make(input.user_data().clone(), input.as_pair().as_span())
}
-fn spanned(input: ParseInput, x: UnspannedExpr<Normalized>) -> Expr {
+fn spanned(input: ParseInput, x: UnspannedExpr) -> Expr {
Expr::new(x, input_to_span(input))
}
-fn spanned_union(
- span1: Span,
- span2: Span,
- x: UnspannedExpr<Normalized>,
-) -> Expr {
+fn spanned_union(span1: Span, span2: Span, x: UnspannedExpr) -> Expr {
Expr::new(x, span1.union(&span2))
}
@@ -845,25 +842,27 @@ impl DhallParser {
[integer_literal(n)] => spanned(input, IntegerLit(n)),
[double_quote_literal(s)] => spanned(input, TextLit(s)),
[single_quote_literal(s)] => spanned(input, TextLit(s)),
+ [record_type_or_literal(e)] => spanned(input, e),
+ [union_type(e)] => spanned(input, e),
[expression(e)] => e,
))
}
- #[alias(expression)]
- fn empty_record_literal(input: ParseInput) -> ParseResult<Expr> {
- Ok(spanned(input, RecordLit(Default::default())))
+ #[alias(record_type_or_literal)]
+ fn empty_record_literal(input: ParseInput) -> ParseResult<UnspannedExpr> {
+ Ok(RecordLit(Default::default()))
}
- #[alias(expression)]
- fn empty_record_type(input: ParseInput) -> ParseResult<Expr> {
- Ok(spanned(input, RecordType(Default::default())))
+ #[alias(record_type_or_literal)]
+ fn empty_record_type(input: ParseInput) -> ParseResult<UnspannedExpr> {
+ Ok(RecordType(Default::default()))
}
- #[alias(expression)]
+ #[alias(record_type_or_literal)]
fn non_empty_record_type_or_literal(
input: ParseInput,
- ) -> ParseResult<Expr> {
- let e = match_nodes!(input.children();
+ ) -> ParseResult<UnspannedExpr> {
+ Ok(match_nodes!(input.children();
[label(first_label), non_empty_record_type(rest)] => {
let (first_expr, mut map) = rest;
map.insert(first_label, first_expr);
@@ -874,8 +873,7 @@ impl DhallParser {
map.insert(first_label, first_expr);
RecordLit(map)
},
- );
- Ok(spanned(input, e))
+ ))
}
fn non_empty_record_type(
@@ -910,13 +908,12 @@ impl DhallParser {
))
}
- #[alias(expression)]
- fn union_type(input: ParseInput) -> ParseResult<Expr> {
+ fn union_type(input: ParseInput) -> ParseResult<UnspannedExpr> {
let map = match_nodes!(input.children();
[empty_union_type(_)] => Default::default(),
[union_type_entry(entries)..] => entries.collect(),
);
- Ok(spanned(input, UnionType(map)))
+ Ok(UnionType(map))
}
fn empty_union_type(_input: ParseInput) -> ParseResult<()> {