Skip to content

Commit

Permalink
fix: Emit a span inside the actual source for eof parse errors
Browse files Browse the repository at this point in the history
  • Loading branch information
Marwes committed Jun 5, 2018
1 parent 25b0e9b commit 3d598fb
Show file tree
Hide file tree
Showing 3 changed files with 50 additions and 14 deletions.
36 changes: 27 additions & 9 deletions parser/src/lib.rs
Original file line number Diff line number Diff line change
Expand Up @@ -24,7 +24,7 @@ use base::ast::{Do, Expr, IdentEnv, SpannedExpr, SpannedPattern, TypedIdent, Val
use base::error::{AsDiagnostic, Errors};
use base::fnv::FnvMap;
use base::metadata::Metadata;
use base::pos::{self, BytePos, Span, Spanned};
use base::pos::{self, ByteOffset, BytePos, Span, Spanned};
use base::symbol::Symbol;
use base::types::{ArcType, TypeCache};

Expand Down Expand Up @@ -87,11 +87,17 @@ fn shrink_hidden_spans<Id>(mut expr: SpannedExpr<Id>) -> SpannedExpr<Id> {
expr
}

fn transform_errors<'a, Iter>(errors: Iter) -> Errors<Spanned<Error, BytePos>>
fn transform_errors<'a, Iter>(
source_span: Span<BytePos>,
errors: Iter,
) -> Errors<Spanned<Error, BytePos>>
where
Iter: IntoIterator<Item = LalrpopError<'a>>,
{
errors.into_iter().map(Error::from_lalrpop).collect()
errors
.into_iter()
.map(|err| Error::from_lalrpop(source_span, err))
.collect()
}

struct Expected<'a>(&'a [String]);
Expand Down Expand Up @@ -169,7 +175,7 @@ fn remove_extra_quotes(tokens: &mut [String]) {
}

impl Error {
fn from_lalrpop(err: LalrpopError) -> Spanned<Error, BytePos> {
fn from_lalrpop(source_span: Span<BytePos>, err: LalrpopError) -> Spanned<Error, BytePos> {
use lalrpop_util::ParseError::*;

match err {
Expand All @@ -190,7 +196,11 @@ impl Error {
mut expected,
} => {
remove_extra_quotes(&mut expected);
pos::spanned2(1.into(), 1.into(), Error::UnexpectedEof(expected))
pos::spanned2(
source_span.end(),
source_span.end(),
Error::UnexpectedEof(expected),
)
}
ExtraToken {
token: (lpos, token, rpos),
Expand Down Expand Up @@ -313,6 +323,11 @@ macro_rules! layout {
pub trait ParserSource {
fn src(&self) -> &str;
fn start_index(&self) -> BytePos;

fn span(&self) -> Span<BytePos> {
let start = self.start_index();
Span::new(start, start + ByteOffset::from(self.src().len() as i64))
}
}

impl<'a, S> ParserSource for &'a S
Expand Down Expand Up @@ -379,14 +394,14 @@ where
match result {
Ok(expr) => {
if parse_errors.has_errors() {
Err((Some(expr), transform_errors(parse_errors)))
Err((Some(expr), transform_errors(input.span(), parse_errors)))
} else {
Ok(expr)
}
}
Err(err) => {
parse_errors.push(err);
Err((None, transform_errors(parse_errors)))
Err((None, transform_errors(input.span(), parse_errors)))
}
}
}
Expand Down Expand Up @@ -441,14 +456,17 @@ where
match result {
Ok(let_or_expr) => {
if parse_errors.has_errors() {
Err((Some(let_or_expr), transform_errors(parse_errors)))
Err((
Some(let_or_expr),
transform_errors(input.span(), parse_errors),
))
} else {
Ok(let_or_expr)
}
}
Err(err) => {
parse_errors.push(err);
Err((None, transform_errors(parse_errors)))
Err((None, transform_errors(input.span(), parse_errors)))
}
}
}
Expand Down
18 changes: 18 additions & 0 deletions parser/tests/error_handling.rs
Original file line number Diff line number Diff line change
Expand Up @@ -328,3 +328,21 @@ fn unterminated_char_literal() {
let span = pos::span(BytePos::from(6), BytePos::from(6));
assert_eq!(err, ParseErrors::from(vec![pos::spanned(span, error)]));
}

#[test]
fn missing_close_paren() {
let _ = ::env_logger::try_init();

let expr = r#"
let x =
(1
x
"#;
let result = parse(expr);
assert!(result.is_err());
let (_expr, err) = result.unwrap_err();

let error = Error::UnexpectedEof([")", ",", "]"].iter().map(|s| s.to_string()).collect());
let span = pos::span(BytePos::from(35), BytePos::from(35));
assert_eq!(err, ParseErrors::from(vec![pos::spanned(span, error)]));
}
10 changes: 5 additions & 5 deletions vm/src/api/mod.rs
Original file line number Diff line number Diff line change
Expand Up @@ -130,21 +130,21 @@ enum DataInner<'a> {
pub struct Data<'a>(DataInner<'a>);

impl<'a> Data<'a> {
/// The tag of this variant. If this value is a variant, the tag is the zero-based
/// The tag of this variant. If this value is a variant, the tag is the zero-based
/// index of the variant that is present, in order of the declaration.
///
///
/// Use this method to find out what variant you are dealing with, before extracting
/// data from it.
///
///
/// ## Examples
///
///
/// ```gluon
/// type OneOfFour =
/// | First
/// | Second
/// | Third
/// | Fourth
///
///
/// let val = First // has the tag '0'
/// let val = Fourth // has the tag '3'
/// ```
Expand Down

0 comments on commit 3d598fb

Please sign in to comment.