mod common; mod parsing { use super::common::run_parser; use panfix::parsing::Grammar; use panfix::{juxtapose, op}; #[test] fn test_left_associativity() { let parser = Grammar::new("TestGrammar") .regex("Var", "[a-zA-Z]+") .subgrammar("Expr", |builder| { builder.ops_l(vec![ op!(Plus: _ "+" _), op!(Minus: _ "-" _), op!(ListComprehension: _ "for" Expr "in" _), op!(Not: "!" _), op!(Lambda: "λ" Expr "." _), op!(Div100: _ "%"), op!(Subs: "[" Expr "]" _), op!(ForthDefn: _ ":" Expr ";"), ]) }) .build("Expr"); let parse = |input: &str| run_parser(&parser, input); assert_eq!(parse("x"), "x"); assert_eq!(parse("x+y+z"), "((x + y) + z)"); assert_eq!(parse("a-b+c-d"), "(((a - b) + c) - d)"); assert_eq!(parse("!x%"), "((! x) %)"); assert_eq!(parse("!x+y%"), "(((! x) + y) %)"); assert_eq!(parse("x%+!y"), "((x %) + (! y))"); assert_eq!(parse("x for x in L"), "(x for x in L)"); assert_eq!( parse("x for x in y for y in L"), "((x for x in y) for y in L)" ); assert_eq!(parse("λx.y:z;"), "((λ x . y) : z ;)"); } #[test] fn test_right_associativity() { let parser = Grammar::new("TestGrammar") .regex("Var", "[a-zA-Z]+") .subgrammar("Expr", |builder| { builder.ops_r(vec![ op!(And: _ "&&" _), op!(Or: _ "||" _), op!(Ternary: _ "?" Expr ":" _), op!(Not: "!" _), op!(Lambda: "λ" Expr "." _), op!(Squared: _ "²"), op!(ColonThingy: _ "::" Expr ";"), ]) }) .build("Expr"); let parse = |input: &str| run_parser(&parser, input); assert_eq!(parse("x&&y"), "(x && y)"); assert_eq!(parse("x&&y||z"), "(x && (y || z))"); // look it's what the grammar says assert_eq!(parse("!x²"), "(! (x ²))"); assert_eq!(parse("x²&&!y||!z²"), "((x ²) && (! (y || (! (z ²)))))"); assert_eq!(parse("a?b:c"), "(a ? b : c)"); assert_eq!(parse("a?b:c?d:e"), "(a ? b : (c ? d : e))"); assert_eq!(parse("λx.x"), "(λ x . x)"); assert_eq!(parse("λx.λy.x"), "(λ x . (λ y . x))"); assert_eq!(parse("a::b::c;;"), "(a :: (b :: c ;) ;)"); assert_eq!(parse("λx.y::z;"), "(λ x . (y :: z ;))"); assert_eq!(parse("λx.a?b:c::z;"), "(λ x . (a ? b : (c :: z ;)))"); assert_eq!(parse("λx.a?b::c;:z"), "(λ x . (a ? (b :: c ;) : z))"); } #[test] fn test_infix_iter() { let parser = Grammar::new("TestGrammar") .regex("Var", "[a-zA-Z]+") .subgrammar("Expr", |builder| { builder.op_l(op!(Plus: _ "+" _)).op_r(op!(Comma: _ "," _)) }) .build("Expr"); let source = "a + b, c + d + e, f"; let parsed = parser.parse(source).unwrap(); let visitor = parsed.groups().next().unwrap(); let elems = visitor.iter_right("Comma").collect::>(); assert_eq!(elems.len(), 3); let first = elems[0].iter_left_vec("Plus"); assert_eq!(first.len(), 2); assert_eq!(first[0].text(), "a"); assert_eq!(first[1].text(), "b"); let second = elems[1].iter_left_vec("Plus"); assert_eq!(second.len(), 3); assert_eq!(second[0].text(), "c"); assert_eq!(second[1].text(), "d"); assert_eq!(second[2].text(), "e"); let third = elems[2].iter_left_vec("Plus"); assert_eq!(third.len(), 1); assert_eq!(third[0].text(), "f"); } #[test] fn test_circumfix() { let parser = Grammar::new("TestGrammar") .regex("Var", "[a-zA-Z]+") .subgrammar("Expr", |builder| { builder .op(op!(Parens: "(" Expr ")")) .op_l(op!(Mul: _ "*" _)) .op_l(op!(Add: _ "+" _)) }) .build("Expr"); let parse = |input: &str| run_parser(&parser, input); assert_eq!(parse("a*b+c*d"), "((a * b) + (c * d))"); assert_eq!(parse("a*(b+c)*d"), "((a * (( (b + c) ))) * d)"); } #[test] fn test_variable_precedence() { let parser = Grammar::new("TestGrammar") .regex("Var", "[a-zA-Z]+") .subgrammar("Expr", |builder| { builder .op(op!(Neg: "-" _)) .ops_l(vec![op!(Mul: _ "*" _), op!(Div: _ "/" _)]) .ops_l(vec![op!(Add: _ "+" _), op!(Sub: _ "-" _)]) }) .build("Expr"); let parse = |input: &str| run_parser(&parser, input); assert_eq!(parse("a*a-b*b"), "((a * a) - (b * b))"); assert_eq!(parse("-a*a"), "((- a) * a)"); } #[test] fn test_juxt_prec() { let parser = Grammar::new("TestGrammar") .regex("Var", "[a-zA-Z]+") .subgrammar("Expr", |builder| { builder .op_l(op!(Mul: _ "*" _)) .op_l(juxtapose!()) .op_l(op!(Add: _ "+" _)) }) .build("Expr"); let parse = |input: &str| run_parser(&parser, input); assert_eq!(parse("a+b*c d*e+f"), "((a + ((b * c) ? (d * e))) + f)"); } #[test] fn test_mixed_nonterminals() { let parser = Grammar::new("TestGrammar") .regex("Var", "[a-zA-Z]+") .subgrammar("Braces", |builder| { builder .op(op!(Brace: "{" Brackets "}")) .op_r(op!(Comma: _ "," _)) }) .subgrammar("Brackets", |builder| { builder .op(op!(Bracket: "[" Braces "]")) .op_r(op!(Semi: _ ";" _)) }) .build("Braces"); let parse = |input: &str| run_parser(&parser, input); assert_eq!(parse("{a;b}"), "({ (a ; b) })"); assert_eq!(parse("{[a]}"), "({ ([ a ]) })"); assert_eq!(parse("{[a,{b}];c}"), "({ (([ (a , ({ b })) ]) ; c) })"); } fn parse_c(input: &str) -> String { let parser = Grammar::new("TestGrammar") .regex("Var", "[a-zA-Z]+") .regex("Number", "0|[1-9][0-9]*") .constant("True", "true") .constant("False", "false") .subgrammar("Expr", |builder| { builder.ops_l(vec![ op!(Inc: _ "++" _), op!(Subs: _ "[" Expr "]"), op!(Dot: _ "." _), ]) }) .build("Expr"); run_parser(&parser, input) } #[test] fn test_errors() { assert_eq!(parse_c("x$y"), "LexErr $ 0:2"); assert_eq!(parse_c("x.y]33"), "ExtraSep ] 0:4"); assert_eq!(parse_c("x.y[x.y"), "MissingSep Subs ] 0:4"); } #[test] fn test_c_basics() { assert_eq!(parse_c(" x "), "x"); assert_eq!(parse_c("1"), "1"); assert_eq!(parse_c("44"), "44"); assert_eq!(parse_c("x++"), "(x ++)"); assert_eq!(parse_c("++x"), "(++ x)"); assert_eq!(parse_c("x.y"), "(x . y)"); assert_eq!(parse_c("x[1]"), "(x [ 1 ])"); assert_eq!(parse_c("x.y.z"), "((x . y) . z)"); assert_eq!(parse_c("x[y][z]"), "((x [ y ]) [ z ])"); assert_eq!(parse_c("x[y.z]"), "(x [ (y . z) ])"); assert_eq!(parse_c("x.y[1]"), "((x . y) [ 1 ])"); } #[test] #[should_panic(expected = "The first token of operator Dot")] fn test_bug_1_err() { Grammar::new("TestGrammar") .regex("Var", "[a-zA-Z]+") .subgrammar("Expr", |builder| { builder .op_l(op!(Dot: _ "." _)) .op_r(op!(Comma: _ "," _)) .op(op!(Lambda: "/" Expr "." _)) }) .build("Expr"); } #[test] #[should_panic(expected = "No such subgrammar: Nonsense")] fn test_no_such_nonterminal() { Grammar::new("TestGrammar") .subgrammar("Expr", |builder| builder.op(op!(Parens: "(" Nonsense ")"))) .build("Expr"); } #[test] fn test_bug_1_ok() { let parser = Grammar::new("TestGrammar") .regex("Var", "[a-zA-Z]+") .subgrammar("Args", |builder| builder.op_r(op!(Comma: _ "," _))) .subgrammar("Expr", |builder| { builder .op_l(op!(Dot: _ "." _)) .op(op!(Lambda: "/" Args "." _)) }) .build("Expr"); let parse = |input: &str| run_parser(&parser, input); assert_eq!(parse("x.y"), "(x . y)"); assert_eq!(parse("/x.y"), "(/ x . y)"); assert_eq!(parse("/x,y.x"), "(/ (x , y) . x)"); } }