From 153f40c447938620f7186885a2eff6b22a4509f6 Mon Sep 17 00:00:00 2001 From: Nadrieril Date: Sun, 3 Mar 2019 01:31:02 +0100 Subject: Handle errors in parser --- Cargo.lock | 1 + dhall/Cargo.toml | 1 + dhall/src/lib.rs | 1 + dhall/src/parser.rs | 91 +++++++++++++++++++---------------------------------- 4 files changed, 36 insertions(+), 58 deletions(-) diff --git a/Cargo.lock b/Cargo.lock index c2e4b55..e5cd07f 100644 --- a/Cargo.lock +++ b/Cargo.lock @@ -136,6 +136,7 @@ version = "0.1.0" dependencies = [ "bytecount 0.5.1 (registry+https://github.com/rust-lang/crates.io-index)", "dhall_parser 0.1.0", + "itertools 0.8.0 (registry+https://github.com/rust-lang/crates.io-index)", "lalrpop 0.16.3 (registry+https://github.com/rust-lang/crates.io-index)", "lalrpop-util 0.16.3 (registry+https://github.com/rust-lang/crates.io-index)", "nom 3.2.1 (registry+https://github.com/rust-lang/crates.io-index)", diff --git a/dhall/Cargo.toml b/dhall/Cargo.toml index 4c6be34..bb3f349 100644 --- a/dhall/Cargo.toml +++ b/dhall/Cargo.toml @@ -10,6 +10,7 @@ lalrpop = "0.16.3" [dependencies] bytecount = "0.5.1" +itertools = "0.8.0" lalrpop-util = "0.16.3" nom = "3.0.0" term-painter = "0.2.3" diff --git a/dhall/src/lib.rs b/dhall/src/lib.rs index ad10cc5..e720ae1 100644 --- a/dhall/src/lib.rs +++ b/dhall/src/lib.rs @@ -1,5 +1,6 @@ #![feature(box_patterns)] #![feature(concat_idents)] +#![feature(transpose_result)] pub mod context; mod core; diff --git a/dhall/src/parser.rs b/dhall/src/parser.rs index 7a4919e..022c964 100644 --- a/dhall/src/parser.rs +++ b/dhall/src/parser.rs @@ -1,64 +1,41 @@ use lalrpop_util; +use itertools::*; +use pest::Parser; +use pest::iterators::Pair; + +use dhall_parser::{DhallParser, Rule}; use crate::grammar; use crate::grammar_util::{BoxExpr, ParsedExpr}; use crate::lexer::{Lexer, LexicalError, Tok}; use crate::core::{bx, Expr, Builtin, V}; -pub type ParseError<'i> = lalrpop_util::ParseError, LexicalError>; - -pub fn parse_expr_lalrpop(s: &str) -> Result { +pub fn parse_expr_lalrpop(s: &str) -> Result> { grammar::ExprParser::new().parse(Lexer::new(s)) } -use pest::Parser; -use pest::error::Error; -use pest::iterators::Pair; -use dhall_parser::{DhallParser, Rule}; +pub type ParseError = pest::error::Error; -fn debug_pair(pair: Pair) { - fn aux(indent: usize, prefix: String, pair: Pair) { - let indent_str = "| ".repeat(indent); - let rule = pair.as_rule(); - let contents = pair.as_str().clone(); - let mut inner = pair.into_inner(); - let mut first = true; - while let Some(p) = inner.next() { - if first { - first = false; - let last = inner.peek().is_none(); - if last && p.as_str() == contents { - let prefix = format!("{}{:?} > ", prefix, rule); - aux(indent, prefix, p); - continue; - } else { - println!(r#"{}{}{:?}: "{}""#, indent_str, prefix, rule, contents); - } - } - aux(indent+1, "".into(), p); - } - if first { - println!(r#"{}{}{:?}: "{}""#, indent_str, prefix, rule, contents); - } - // println!(r#"{}{}{:?}: "{}""#, indent_str, prefix, rule, contents); - // for p in inner { - // aux(indent+1, "".into(), p); - // } - } - aux(0, "".into(), pair) +pub type ParseResult = Result; + +pub fn custom_parse_error(pair: &Pair, msg: String) -> ParseError { + let e = pest::error::ErrorVariant::CustomError{ message: msg }; + pest::error::Error::new_from_span(e, pair.as_span()) } + macro_rules! parse_aux { ($inner:expr, true, $x:ident : $ty:ident $($rest:tt)*) => { - let $x = concat_idents!(parse_, $ty)($inner.next().unwrap()); + let $x = concat_idents!(parse_, $ty)($inner.next().unwrap())?; parse_aux!($inner, true $($rest)*) }; ($inner:expr, true, $x:ident? : $ty:ident $($rest:tt)*) => { - let $x = $inner.next().map(concat_idents!(parse_, $ty)); + let $x = $inner.next().map(concat_idents!(parse_, $ty)).transpose()?; parse_aux!($inner, true $($rest)*) }; ($inner:expr, true, $x:ident* : $ty:ident $($rest:tt)*) => { - let $x = $inner.map(concat_idents!(parse_, $ty)); + #[allow(unused_mut)] + let mut $x = $inner.map(concat_idents!(parse_, $ty)); parse_aux!($inner, false $($rest)*) }; ($inner:expr, false) => {}; @@ -73,37 +50,38 @@ macro_rules! parse { #[allow(unused_mut)] let mut inner = $pair.into_inner(); parse_aux!(inner, true, $($args)*); - $body + Ok($body) } }; } -fn parse_binop<'a, F>(pair: Pair<'a, Rule>, mut f: F) -> BoxExpr<'a> +fn parse_binop<'a, F>(pair: Pair<'a, Rule>, mut f: F) -> ParseResult> where F: FnMut(BoxExpr<'a>, BoxExpr<'a>) -> ParsedExpr<'a> { parse!(pair; (first: expression, rest*: expression) => { - rest.fold(first, |acc, e| bx(f(acc, e))) + rest.fold_results(first, |acc, e| bx(f(acc, e)))? }) } -fn skip_expr(pair: Pair) -> BoxExpr { +fn skip_expr(pair: Pair) -> ParseResult { parse!(pair; (expr: expression) => { expr }) } -fn parse_str(pair: Pair) -> &str { - pair.as_str().trim() +fn parse_str(pair: Pair) -> ParseResult<&str> { + Ok(pair.as_str().trim()) } -// fn parse_natural(pair: Pair) -> Result { -fn parse_natural(pair: Pair) -> usize { - parse_str(pair).parse().unwrap() +fn parse_natural(pair: Pair) -> ParseResult { + parse_str(pair.clone())? + .parse() + .map_err(|e: std::num::ParseIntError| custom_parse_error(&pair, format!("{}", e))) } -fn parse_expression(pair: Pair) -> BoxExpr { +fn parse_expression(pair: Pair) -> ParseResult { match pair.as_rule() { - Rule::natural_literal_raw => bx(Expr::NaturalLit(parse_natural(pair))), + Rule::natural_literal_raw => Ok(bx(Expr::NaturalLit(parse_natural(pair)?))), Rule::annotated_expression => { parse_binop(pair, Expr::Annot) } Rule::import_alt_expression => { skip_expr(pair) } @@ -122,7 +100,7 @@ fn parse_expression(pair: Pair) -> BoxExpr { Rule::selector_expression_raw => parse!(pair; (first: expression, rest*: str) => { - rest.fold(first, |acc, e| bx(Expr::Field(acc, e))) + rest.fold_results(first, |acc, e| bx(Expr::Field(acc, e)))? }), Rule::identifier_raw => @@ -152,19 +130,16 @@ fn parse_expression(pair: Pair) -> BoxExpr { _ => { let rulename = format!("{:?}", pair.as_rule()); parse!(pair; (exprs*: expression) => { - bx(Expr::FailedParse(rulename, exprs.map(|x| *x).collect())) + bx(Expr::FailedParse(rulename, exprs.map_results(|x| *x).collect::>()?)) }) } } } -pub fn parse_expr_pest(s: &str) -> Result> { +pub fn parse_expr_pest(s: &str) -> ParseResult { let parsed_expr = DhallParser::parse(Rule::final_expression, s)?.next().unwrap(); - debug_pair(parsed_expr.clone()); - // println!("{}", parsed_expr.clone()); - - Ok(parse_expression(parsed_expr)) + parse_expression(parsed_expr) } -- cgit v1.2.3