diff options
author | Nadrieril Feneanar | 2020-02-02 18:21:38 +0000 |
---|---|---|
committer | GitHub | 2020-02-02 18:21:38 +0000 |
commit | b7b5a0d27eb0cccdcd0c532a7042b3514eacbe40 (patch) | |
tree | a65cf1d2a53d67d2ea8f808c9a8408a8f96713e7 /dhall/src/syntax | |
parent | 72a6fef65bb3d34be1f501a1f6de66fb8a54fa04 (diff) | |
parent | f3681f7a32ddb78db4d564769b50b697c54ebeac (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.rs | 6 | ||||
-rw-r--r-- | dhall/src/syntax/ast/span.rs | 30 | ||||
-rw-r--r-- | dhall/src/syntax/text/parser.rs | 39 |
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<()> { |