test trivial { grammar = { rGrammar = "abc"; } accept {abc} pree={abc} reject {ab} reject {bc} reject {abc;} reject {_abc} } test proxy { grammar = { rGrammar = rABC; rABC = "abc"; } accept {abc} pree={(abc)} reject {ab} reject {bc} reject {abc;} reject {_abc} } test action { // the parsing tree should be identical to the Proxy case above // because assigning an action should not change the tree. grammar = { rABC = "abc"; rGrammar = rABC[&test_action]; } accept {abc} pree={(abc)} reject {ab} reject {bc} reject {abc;} reject {_abc} } test CharSet { grammar = { rGrammar = +(char_set_r("aBcD") - char_set_r("BD")); } accept {a} pree={((a))} accept {aaa} pree={((a),(a),(a))} accept {acaca} pree={((a),(c),(a),(c),(a))} reject {B} reject {aB} reject {Da} reject {aBc} reject {aBcD} } test CharRange { grammar = { rGrammar = +(char_range_r('b', 'y') - char_range_r('e', 'h')); } accept {b} pree={((b))} accept {y} pree={((y))} accept {bbb} pree={((b),(b),(b))} accept {yyy} pree={((y),(y),(y))} accept {bcdwxy} pree={((b),(c),(d),(w),(x),(y))} accept {ybxcwd} pree={((y),(b),(x),(c),(w),(d))} reject {} reject {ab} reject {e} reject {h} reject {eh} reject {be} reject {bcdewxy} } test needleInHaystack { grammar = { rGrammar = *anychar_r >> alpha_r >> "=" >> alpha_r; } accept {a=a} pree={(,a,=,a)} accept {ba=a} pree={((b),a,=,a)} accept {bc=ca=a} pree={((b,c,=,c),a,=,a)} accept {bc=a=a} pree={((b,c,=),a,=,a)} accept {b!a=a} pree={((b,!),a,=,a)} accept {b=!a=a} pree={((b,=,!),a,=,a)} reject {a=a;} } test optionalThings { grammar = { rGrammar = !( !rPart >> "-core-" >> !(+rPart >> ";") ); rPart = +alpha_r >> !digit_r >> "."; } accept {} pree={} accept {-core-} pree={((,-core-,))} accept {part.-core-} pree={(((((p,a,r,t),,.)),-core-,))} accept {part1.-core-} pree={(((((p,a,r,t),(1),.)),-core-,))} accept {-core-p.;} pree={((,-core-,(((((p),,.)),;))))} accept {p.-core-p.;} pree={(((((p),,.)),-core-,(((((p),,.)),;))))} accept {p1.-core-p2.;} pree={(((((p),(1),.)),-core-,(((((p),(2),.)),;))))} accept {p1.-core-p2.p.p4.;} pree={(((((p),(1),.)),-core-,(((((p),(2),.),((p),,.),((p),(4),.)),;))))} reject {p1.} reject {p1.p2.} reject {p12.-core} reject {-core-;} reject {-core-p2.} reject {-core-p2.p3.} reject {-core-p2.;p3.;} } test CommittedEndWithAmbiguity { grammar = { rGrammar = *rPart; rPart = string_r("pfx") | "pfx-sfx"; rGrammar.committed(true); } accept {} pree={} accept {pfx} pree={((pfx))} accept {pfx-sfx} pree={((pfx-sfx))} accept {pfxpfx} pree={((pfx),(pfx))} accept {pfx-sfxpfxpfx-sfxpfxpfx} pree={((pfx-sfx),(pfx),(pfx-sfx),(pfx),(pfx))} reject {pf} reject {pfx.} reject {pfx-sf} reject {pfx-sfx.} } test ReusedStartRule { grammar = { rGrammar = *rPrefix >> ";"; rPrefix = "<" >> rGrammar >> ">" | "code"; } accept {;} pree={(,;)} accept {<;>;} pree={((((<,(,;),>))),;)} accept {;} pree={((((<,(((code)),;),>))),;)} accept {;} pree={((((<,(((code),(code),(code)),;),>))),;)} reject {} reject {<>;} reject {} reject {;} reject {;} } test leftRecursion { grammar = { rGrammar = rExpression; rExpression = rExpression >> "+" >> rExpression | digit_r; } accept {1} pree={((1))} accept {1+2} pree={((((1),+,(2))))} accept {1+2+3} pree={((((((1),+,(2))),+,(3))))} reject {+} reject {12+3} reject {1+2+} reject {+1+2} } test indirectRecursion { grammar = { rGrammar = *A >> "c" | "b"; A = rGrammar | "a"; } accept {c} pree={((,c))} accept {b} pree={(b)} accept {ac} pree={((((a)),c))} accept {bac} pree={(((((b)),(a)),c))} accept {cac} pree={((((((,c))),(a)),c))} accept {ccccc} pree={((((((((((((((((((,c)))),c)))),c)))),c)))),c))} accept {aaaaaac} pree={((((a),(a),(a),(a),(a),(a)),c))} accept {abbabbaac} pree={((((a),((b)),((b)),(a),((b)),((b)),(a),(a)),c))} accept {abbcacbcbaac} pree={((((((((((((((((a),((b)),((b))),c))),(a)),c))),((b))),c))),((b)),(a),(a)),c))} accept {cbbcacbcbaacc} pree={((((((((((((((((((((((,c))),((b)),((b))),c))),(a)),c))),((b))),c))),((b)),(a),(a)),c)))),c))} reject {} reject {a} reject {aaa} reject {bbb} reject {ccca} reject {cccb} reject {cbcbcb} reject {e} reject {ec} reject {abbcacbcbaace} reject {cbbcacbcbaacce} } test UselessRecursion { grammar = { rGrammar = *(A | B) - (+B >> end_r); A = A | "a"; B = "b" | B; rGrammar.trim(*space_r); } accept {} pree={()} accept { } pree={()} accept {a} pree={((((a))))} accept {ab} pree={((((a)),((b))))} accept {ba} pree={((((b)),((a))))} accept {ababababab} pree={((((a)),((b)),((a)),((b)),((a)),((b)),((a)),((b)),((a)),((b))))} accept {b abba bbb bab a} pree={((((b)),((a)),((b)),((b)),((a)),((b)),((b)),((b)),((b)),((a)),((b)),((a))))} reject {b} reject {bbbb} reject {b b b b} } test starStar { grammar = { rGrammar = *rToken; rToken = *rDigit; rDigit = digit_r; } accept {} pree={()} accept {1} pree={((1),)} accept {12} pree={((1,2),)} accept {1234567890} pree={((1,2,3,4,5,6,7,8,9,0),)} reject {a} reject {1.2} } test starStarCompact { grammar = { rGrammar = *(*digit_r); } accept {} pree={()} accept {1} pree={((1),)} accept {12} pree={((1,2),)} accept {1234567890} pree={((1,2,3,4,5,6,7,8,9,0),)} reject {a} reject {1.2} } test unnamed { grammar = { rGrammar = *rStatement; rStatement = *rInstr >> ";"; rInstr = rName | rToken; rName = string_r("description"); rToken = alpha_r >> *alpha_r; // Tokens should not be trimmed inside, but note that // pree will still tell whether rName or rToken matched rToken.verbatim(true); rGrammar.trim(*space_r); } accept {} pree={} accept {;} pree={((,;))} accept {a;} pree={(((((a,))),;))} accept {a b;} pree={(((((a,)),((b,))),;))} accept {a description b ; } pree={(((((a,)),(description),((b,))),;))} reject {a=b;} } test operPrecedence { grammar = { rGrammar = rExpression; rExpression = rTerm >> *("+" >> rTerm); rTerm = rExpression >> +("*" >> rExpression) | digit_r; } accept {1} pree={(((1),))} accept {1+2} pree={(((1),((+,(2)))))} accept {1*2} pree={((((((1),),((*,((2),))))),))} accept {1+2+3} pree={(((1),((+,(2)),(+,(3)))))} accept {1*2*3} pree={(((((((((1),),((*,((2),))))),),((*,((3),))))),))} accept {1*2+3} pree={((((((1),),((*,((2),((+,(3)))))))),))} accept {1+2*3} pree={((((((1),((+,(2)))),((*,((3),))))),))} accept {0*1+2*3+4*5*6+7+8+9} pree={(((((((((((((((0),),((*,((1),((+,(2)))))))),),((*,((3),((+,(4)))))))),),((*,((5),))))),),((*,((6),((+,(7)),(+,(8)),(+,(9)))))))),))} reject {+} reject {12+3} reject {1+2+} reject {+1*2} reject {1+*2} } test selectiveTrim { grammar = { rGrammar = rNum >> rNum >> ";"; rNum = (rFloat | rInt); rFloat = rInt >> "." >> rInt; rInt = +digit_r; rGrammar.trim(*space_r); rFloat.verbatim(true); // but rInt alone should be trimmed rInt.verbatim(true); rFloat.leaf(true); //rInt.leaf(true); // check trimming of verbatim non-terminals } accept {1 2;} pree={(((1)),((2)),;)} accept {1.2 3;} pree={((1.2),((3)),;)} accept { 1.2 3.4 ; } pree={((1.2),(3.4),;)} accept { 12.34 56.78 ; } pree={((12.34),(56.78),;)} reject {1;} reject {1.2;} reject {1. 2 3;} reject {1 2. 3;} reject {1234 57. 78;} reject {1 2 3;} reject {1 2;1} } test GiovanniChallenge { grammar = { rGrammar = rB >> "d"; rB = rA >> "c" | rA >> "c" >> "c"; rA = string_r("ab") | "abb"; } accept {abcd} pree={((((ab),c)),d)} accept {abccd} pree={((((ab),c,c)),d)} accept {abbcd} pree={((((abb),c)),d)} accept {abbccd} pree={((((abb),c,c)),d)} reject {abc} reject {abbc} reject {abccc} reject {aabcd} reject {abcdd} } test propertyInheritance { preamble = {{ static void test_action(Action::Params *) {} }} grammar = { Rule rHead = *string_r("a"); rHead.committed(true); // if ignored, 'a*ab' will be accepted // 'c' is required for rejecting the "ab" input // because it does not allow Hapy to reject +a in rHead, based // just on the min rule size (3) exceeding input length (2) // The min rule size logic limits [futile] greed. Rule rTail = char_r('c') | "ab"; Rule rGrammar = rHead[&test_action] >> rTail; } reject {ab} reject {aab} reject {aaaaaab} reject {a} reject {b} reject {aa} reject {aaba} reject {aabc} } test trimAndRecursion { grammar = { rGrammar = rMany; rMany = *rOne; rOne = rRex | rOther; // The old trimming bug is not exposed if there is no recursion // here because recursion may cause double-rewrite of rOne, // with a loss of the trimming rules due the second rewrite. rRex = "rex" >> rMany; // We should not have to include trimming rule explicitly because // G.trim() call should be enough and will result in the correct // pree without the explicit trim here. rOther = anychar_r; rGrammar.trim(*char_r('w')); } accept {} pree={()} accept {w} pree={()} accept {a} pree={(((a)))} accept {wa} pree={(((a)))} accept {aw} pree={(((a)))} accept {waw} pree={(((a)))} accept {wwwawww} pree={(((a)))} accept {wrexwaw} pree={((((rex,((a))))))} }