From 54d3f23e68bf6e769d8a96e40a2b0c4426e38507 Mon Sep 17 00:00:00 2001 From: Nadrieril Date: Sat, 2 Mar 2019 22:21:43 +0100 Subject: Add parser/failure tests from spec --- dhall/src/main.rs | 2 +- dhall/src/parser.rs | 163 +++++++++++++++++++++++++------------------------- dhall/tests/macros.rs | 8 ++- dhall/tests/tests.rs | 10 ++++ 4 files changed, 100 insertions(+), 83 deletions(-) (limited to 'dhall') diff --git a/dhall/src/main.rs b/dhall/src/main.rs index cdab3c0..58826bb 100644 --- a/dhall/src/main.rs +++ b/dhall/src/main.rs @@ -52,7 +52,7 @@ fn print_error(message: &str, source: &str, start: usize, end: usize) { fn main() { let mut buffer = String::new(); io::stdin().read_to_string(&mut buffer).unwrap(); - let expr = match parser::parse_expr(&buffer) { + let expr = match parser::parse_expr_lalrpop(&buffer) { Ok(e) => e, Err(lalrpop_util::ParseError::User { error: lexer::LexicalError::Error(pos, e) }) => { print_error(&format!("Unexpected token {:?}", e), &buffer, pos, pos); diff --git a/dhall/src/parser.rs b/dhall/src/parser.rs index 0acfe39..9259dfd 100644 --- a/dhall/src/parser.rs +++ b/dhall/src/parser.rs @@ -7,7 +7,7 @@ use crate::core::{bx, Expr, V}; pub type ParseError<'i> = lalrpop_util::ParseError, LexicalError>; -pub fn parse_expr(s: &str) -> Result { +pub fn parse_expr_lalrpop(s: &str) -> Result { grammar::ExprParser::new().parse(Lexer::new(s)) } @@ -48,80 +48,81 @@ fn debug_pair(pair: Pair) { aux(0, "".into(), pair) } -pub fn parse_expr_pest(s: &str) -> Result> { - let parsed_expr = DhallParser::parse(Rule::final_expression, s)?.next().unwrap(); - debug_pair(parsed_expr.clone()); - // println!("{}", parsed_expr.clone()); - - fn parse_binop<'a, F>(pair: Pair<'a, Rule>, mut f: F) -> BoxExpr<'a> - where F: FnMut(BoxExpr<'a>, BoxExpr<'a>) -> ParsedExpr<'a> { - let mut inner = pair.into_inner().map(parse_expression); - let first_expr = inner.next().unwrap(); - inner.fold(first_expr, |acc, e| bx(f(acc, e))) - } +fn parse_binop<'a, F>(pair: Pair<'a, Rule>, mut f: F) -> BoxExpr<'a> +where F: FnMut(BoxExpr<'a>, BoxExpr<'a>) -> ParsedExpr<'a> { + let mut inner = pair.into_inner().map(parse_expression); + let first_expr = inner.next().unwrap(); + inner.fold(first_expr, |acc, e| bx(f(acc, e))) +} - fn skip_expr(pair: Pair) -> BoxExpr { - let mut inner = pair.into_inner().map(parse_expression); - inner.next().unwrap() - } +fn skip_expr(pair: Pair) -> BoxExpr { + let mut inner = pair.into_inner().map(parse_expression); + inner.next().unwrap() +} - fn parse_str(pair: Pair) -> &str { - pair.as_str().trim() - } +fn parse_str(pair: Pair) -> &str { + pair.as_str().trim() +} - fn parse_natural(pair: Pair) -> Result { - parse_str(pair).parse() - } +fn parse_natural(pair: Pair) -> Result { + parse_str(pair).parse() +} - fn parse_expression(pair: Pair) -> BoxExpr { - match pair.as_rule() { - Rule::natural_literal_raw => bx(Expr::NaturalLit(parse_natural(pair).unwrap())), - - Rule::annotated_expression => { parse_binop(pair, Expr::Annot) } - Rule::import_alt_expression => { skip_expr(pair) } - Rule::or_expression => { parse_binop(pair, Expr::BoolOr) } - Rule::plus_expression => { parse_binop(pair, Expr::NaturalPlus) } - Rule::text_append_expression => { parse_binop(pair, Expr::TextAppend) } - Rule::list_append_expression => { skip_expr(pair) } - Rule::and_expression => { parse_binop(pair, Expr::BoolAnd) } - Rule::combine_expression => { skip_expr(pair) } - Rule::prefer_expression => { skip_expr(pair) } - Rule::combine_types_expression => { skip_expr(pair) } - Rule::times_expression => { parse_binop(pair, Expr::NaturalTimes) } - Rule::equal_expression => { parse_binop(pair, Expr::BoolEQ) } - Rule::not_equal_expression => { parse_binop(pair, Expr::BoolNE) } - Rule::application_expression => { parse_binop(pair, Expr::App) } - - Rule::selector_expression_raw => { - let mut inner = pair.into_inner(); - let first_expr = parse_expression(inner.next().unwrap()); - inner.fold(first_expr, |acc, e| bx(Expr::Field(acc, e.as_str()))) - } +fn parse_expression(pair: Pair) -> BoxExpr { + match pair.as_rule() { + Rule::natural_literal_raw => bx(Expr::NaturalLit(parse_natural(pair).unwrap())), + + Rule::annotated_expression => { parse_binop(pair, Expr::Annot) } + Rule::import_alt_expression => { skip_expr(pair) } + Rule::or_expression => { parse_binop(pair, Expr::BoolOr) } + Rule::plus_expression => { parse_binop(pair, Expr::NaturalPlus) } + Rule::text_append_expression => { parse_binop(pair, Expr::TextAppend) } + Rule::list_append_expression => { skip_expr(pair) } + Rule::and_expression => { parse_binop(pair, Expr::BoolAnd) } + Rule::combine_expression => { skip_expr(pair) } + Rule::prefer_expression => { skip_expr(pair) } + Rule::combine_types_expression => { skip_expr(pair) } + Rule::times_expression => { parse_binop(pair, Expr::NaturalTimes) } + Rule::equal_expression => { parse_binop(pair, Expr::BoolEQ) } + Rule::not_equal_expression => { parse_binop(pair, Expr::BoolNE) } + Rule::application_expression => { parse_binop(pair, Expr::App) } + + Rule::selector_expression_raw => { + let mut inner = pair.into_inner(); + let first_expr = parse_expression(inner.next().unwrap()); + inner.fold(first_expr, |acc, e| bx(Expr::Field(acc, e.as_str()))) + } - Rule::identifier_raw => { - let mut inner = pair.into_inner(); - let name = parse_str(inner.next().unwrap()); - let idx = inner.next().map(parse_natural).unwrap_or(Ok(0)).unwrap(); - bx(Expr::Var(V(name, idx))) - } + Rule::identifier_raw => { + let mut inner = pair.into_inner(); + let name = parse_str(inner.next().unwrap()); + let idx = inner.next().map(parse_natural).unwrap_or(Ok(0)).unwrap(); + bx(Expr::Var(V(name, idx))) + } - // Rule::record_type_or_literal => { - // let mut inner = pair.into_inner(); - // let first_expr = parse_expression(inner.next().unwrap()); - // inner.fold(first_expr, |acc, e| bx(Expr::Field(acc, e.as_str()))) - // } + // Rule::record_type_or_literal => { + // let mut inner = pair.into_inner(); + // let first_expr = parse_expression(inner.next().unwrap()); + // inner.fold(first_expr, |acc, e| bx(Expr::Field(acc, e.as_str()))) + // } - // r => panic!("{:?}", r), - // _ => bx(Expr::BoolLit(false)), + // r => panic!("{:?}", r), + // _ => bx(Expr::BoolLit(false)), - _ => { - let rulename = format!("{:?}", pair.as_rule()); - let mut inner = pair.into_inner().map(parse_expression).map(|x| *x); - bx(Expr::FailedParse(rulename, inner.collect())) - } + _ => { + let rulename = format!("{:?}", pair.as_rule()); + let mut inner = pair.into_inner().map(parse_expression).map(|x| *x); + bx(Expr::FailedParse(rulename, inner.collect())) } } +} + +pub fn parse_expr_pest(s: &str) -> Result> { + 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)) } @@ -133,7 +134,7 @@ fn test_parse() { // let expr = r#"{ x = "foo", y = 4 }.x"#; // let expr = r#"(1 + 2) * 3"#; let expr = r#"if True then 1 + 3 * 5 else 2"#; - println!("{:?}", parse_expr(expr)); + println!("{:?}", parse_expr_lalrpop(expr)); match parse_expr_pest(expr) { Err(e) => { println!("{:?}", e); @@ -144,27 +145,27 @@ fn test_parse() { // assert_eq!(parse_expr_pest(expr).unwrap(), parse_expr(expr).unwrap()); assert!(false); - println!("test {:?}", parse_expr("3 + 5 * 10")); - assert!(parse_expr("22").is_ok()); - assert!(parse_expr("(22)").is_ok()); - assert_eq!(parse_expr("3 + 5 * 10").ok(), + println!("test {:?}", parse_expr_lalrpop("3 + 5 * 10")); + assert!(parse_expr_lalrpop("22").is_ok()); + assert!(parse_expr_lalrpop("(22)").is_ok()); + assert_eq!(parse_expr_lalrpop("3 + 5 * 10").ok(), Some(Box::new(NaturalPlus(Box::new(NaturalLit(3)), Box::new(NaturalTimes(Box::new(NaturalLit(5)), Box::new(NaturalLit(10)))))))); // The original parser is apparently right-associative - assert_eq!(parse_expr("2 * 3 * 4").ok(), + assert_eq!(parse_expr_lalrpop("2 * 3 * 4").ok(), Some(Box::new(NaturalTimes(Box::new(NaturalLit(2)), Box::new(NaturalTimes(Box::new(NaturalLit(3)), Box::new(NaturalLit(4)))))))); - assert!(parse_expr("((((22))))").is_ok()); - assert!(parse_expr("((22)").is_err()); - println!("{:?}", parse_expr("\\(b : Bool) -> b == False")); - assert!(parse_expr("\\(b : Bool) -> b == False").is_ok()); - println!("{:?}", parse_expr("foo.bar")); - assert!(parse_expr("foo.bar").is_ok()); - assert!(parse_expr("[] : List Bool").is_ok()); - - // println!("{:?}", parse_expr("< Left = True | Right : Natural >")); - // println!("{:?}", parse_expr(r#""bl${42}ah""#)); - // assert!(parse_expr("< Left = True | Right : Natural >").is_ok()); + assert!(parse_expr_lalrpop("((((22))))").is_ok()); + assert!(parse_expr_lalrpop("((22)").is_err()); + println!("{:?}", parse_expr_lalrpop("\\(b : Bool) -> b == False")); + assert!(parse_expr_lalrpop("\\(b : Bool) -> b == False").is_ok()); + println!("{:?}", parse_expr_lalrpop("foo.bar")); + assert!(parse_expr_lalrpop("foo.bar").is_ok()); + assert!(parse_expr_lalrpop("[] : List Bool").is_ok()); + + // println!("{:?}", parse_expr_lalrpop("< Left = True | Right : Natural >")); + // println!("{:?}", parse_expr_lalrpop(r#""bl${42}ah""#)); + // assert!(parse_expr_lalrpop("< Left = True | Right : Natural >").is_ok()); } diff --git a/dhall/tests/macros.rs b/dhall/tests/macros.rs index 5ad2ab3..6031a34 100644 --- a/dhall/tests/macros.rs +++ b/dhall/tests/macros.rs @@ -18,7 +18,13 @@ macro_rules! run_spec_test { }; (parser, $path:expr) => { let expr_str = include_test_str!(concat!($path, "A")); - parser::parse_expr(&expr_str).unwrap(); + parser::parse_expr_pest(&expr_str).map_err(|e| println!("{}", e)).unwrap(); + // parser::parse_expr(&expr_str).unwrap(); + }; + (parser_failure, $path:expr) => { + let expr_str = include_test_str!($path); + parser::parse_expr_pest(&expr_str).map_err(|e| println!("{}", e)).unwrap_err(); + // parser::parse_expr(&expr_str).unwrap(); }; } diff --git a/dhall/tests/tests.rs b/dhall/tests/tests.rs index 6a2ada8..0e097b2 100644 --- a/dhall/tests/tests.rs +++ b/dhall/tests/tests.rs @@ -211,3 +211,13 @@ make_spec_test!(parser, spec_parser_success_union, "parser/success/union"); make_spec_test!(parser, spec_parser_success_urls, "parser/success/urls"); make_spec_test!(parser, spec_parser_success_whitespace, "parser/success/whitespace"); make_spec_test!(parser, spec_parser_success_whitespaceBuffet, "parser/success/whitespaceBuffet"); + +make_spec_test!(parser_failure, spec_parser_failure_annotation, "parser/failure/annotation"); +// make_spec_test!(parser_failure, spec_parser_failure_doubleBoundsNeg, "parser/failure/doubleBoundsNeg"); +// make_spec_test!(parser_failure, spec_parser_failure_doubleBoundsPos, "parser/failure/doubleBoundsPos"); +make_spec_test!(parser_failure, spec_parser_failure_importAccess, "parser/failure/importAccess"); +make_spec_test!(parser_failure, spec_parser_failure_incompleteIf, "parser/failure/incompleteIf"); +make_spec_test!(parser_failure, spec_parser_failure_mandatoryNewline, "parser/failure/mandatoryNewline"); +make_spec_test!(parser_failure, spec_parser_failure_missingSpace, "parser/failure/missingSpace"); +make_spec_test!(parser_failure, spec_parser_failure_spaceAfterListAppend, "parser/failure/spaceAfterListAppend"); +// make_spec_test!(parser_failure, spec_parser_failure_boundBuiltin, "parser/failure/boundBuiltin"); -- cgit v1.2.3