Add utility methods to ParseError

Add three methods .map_loc(), .map_tok() and .map_err()
that transform the locations, tokens and user error values
inside the ParseError.
This commit is contained in:
Joeri van Ruth 2017-08-09 10:51:59 +02:00
parent 08bb4c98b9
commit 7bdb7126b0
2 changed files with 48 additions and 0 deletions

View File

@ -154,6 +154,26 @@ fn expr_intern_tok_test_err() {
}
}
#[test]
fn expr_intern_tok_display_err() {
let expr = "(1+\n(2++3))";
let result = expr_intern_tok::parse_Expr(1, expr);
let err : lalrpop_util::ParseError<usize, (usize, &str),()>
= result.expect_err("expected a syntax error");
// The problem is that (usize,&str) and () do not implement fmt::Display,
// so neither does the ParseError.
// We can fix that by rewriting them to something else, such as a string.
let disp = err.map_tok(|(_,t)|t).map_err(|_| "error");
assert!(disp.to_string().contains("Unrecognized token +"));
// We can even convert the locations to a line number
let line_based = disp.map_loc(|offset| {
format!("line {}", expr[0..offset].lines().count())
});
assert!(line_based.to_string().contains("line 2"));
}
#[test]
fn expr_lifetime_tok1() {
// the problem here was that we were improperly pruning the 'input from the

View File

@ -36,6 +36,34 @@ pub enum ParseError<L,T,E> {
},
}
impl<L, T, E> ParseError<L, T, E> {
fn map_intern<FL,LL,FT,TT,FE,EE>(self, loc_op: FL, tok_op: FT, err_op: FE) -> ParseError<LL,TT,EE>
where FL: Fn(L) -> LL,
FT: Fn(T) -> TT,
FE: Fn(E) -> EE
{
let maptok = |(s,t,e) : (L,T,L)| (loc_op(s), tok_op(t), loc_op(e));
match self {
ParseError::InvalidToken { location } => ParseError::InvalidToken { location: loc_op(location) },
ParseError::UnrecognizedToken { token, expected } => ParseError::UnrecognizedToken { token: token.map(maptok), expected: expected },
ParseError::ExtraToken { token } => ParseError::ExtraToken { token: maptok(token) },
ParseError::User { error } => ParseError::User { error: err_op(error) }
}
}
pub fn map_loc<F,LL>(self, op: F) -> ParseError<LL, T, E> where F: Fn(L) -> LL {
self.map_intern(op, |x|x, |x|x)
}
pub fn map_tok<F,TT>(self, op: F) -> ParseError<L, TT, E> where F: Fn(T) -> TT {
self.map_intern(|x|x, op, |x|x)
}
pub fn map_err<F,EE>(self, op: F) -> ParseError<L, T, EE> where F: Fn(E) -> EE {
self.map_intern(|x|x, |x|x, op)
}
}
impl<L, T, E> fmt::Display for ParseError<L, T, E>
where L: fmt::Display,
T: fmt::Display,