module Main (main) where import Data.Char import Data.Foldable import Text.Grammar.Distributor import Test.Hspec expectedRegexGrammar :: [(String, RegEx)] expectedRegexGrammar = [("start",NonTerminal "regex") ,("alternate",Sequence (NonTerminal "sequence") (KleeneStar (Sequence (Terminal "|") (NonTerminal "sequence")))) ,("any",Terminal ".") ,("atom",Alternate (Alternate (Alternate (Alternate (Alternate (Alternate (Alternate (Alternate (NonTerminal "nonterminal") (NonTerminal "fail")) (NonTerminal "class-in")) (NonTerminal "class-not-in")) (NonTerminal "category-in")) (NonTerminal "category-not-in")) (NonTerminal "char")) (NonTerminal "any")) (NonTerminal "parenthesized")) ,("category",Alternate (Alternate (Alternate (Alternate (Alternate (Alternate (Alternate (Alternate (Alternate (Alternate (Alternate (Alternate (Alternate (Alternate (Alternate (Alternate (Alternate (Alternate (Alternate (Alternate (Alternate (Alternate (Alternate (Alternate (Alternate (Alternate (Alternate (Alternate (Alternate (Terminal "Ll") (Terminal "Lu")) (Terminal "Lt")) (Terminal "Lm")) (Terminal "Lo")) (Terminal "Mn")) (Terminal "Mc")) (Terminal "Me")) (Terminal "Nd")) (Terminal "Nl")) (Terminal "No")) (Terminal "Pc")) (Terminal "Pd")) (Terminal "Ps")) (Terminal "Pe")) (Terminal "Pi")) (Terminal "Pf")) (Terminal "Po")) (Terminal "Sm")) (Terminal "Sc")) (Terminal "Sk")) (Terminal "So")) (Terminal "Zs")) (Terminal "Zl")) (Terminal "Zp")) (Terminal "Cc")) (Terminal "Cf")) (Terminal "Cs")) (Terminal "Co")) (Terminal "Cn")) ,("category-in",Sequence (Sequence (Terminal "\\p{") (NonTerminal "category")) (Terminal "}")) ,("category-not-in",Sequence (Sequence (Terminal "\\P{") (NonTerminal "category")) (Terminal "}")) ,("char",Alternate (NonTerminal "char-literal") (NonTerminal "char-escaped")) ,("char-escaped",Sequence (Terminal "\\") (InClass "$()*+.?[\\]^{|}")) ,("char-literal",NotInClass "$()*+.?[\\]^{|}") ,("class-in",Sequence (Sequence (Terminal "[") (KleeneStar (NonTerminal "char"))) (Terminal "]")) ,("class-not-in",Sequence (Sequence (Terminal "[^") (KleeneStar (NonTerminal "char"))) (Terminal "]")) ,("expression",Alternate (Alternate (Alternate (Alternate (NonTerminal "terminal") (NonTerminal "kleene-optional")) (NonTerminal "kleene-star")) (NonTerminal "kleene-plus")) (NonTerminal "atom")) ,("fail",Terminal "\\q") ,("kleene-optional",Sequence (NonTerminal "atom") (Terminal "?")) ,("kleene-plus",Sequence (NonTerminal "atom") (Terminal "+")) ,("kleene-star",Sequence (NonTerminal "atom") (Terminal "*")) ,("nonterminal",Sequence (Sequence (Terminal "\\q{") (KleeneStar (NonTerminal "char"))) (Terminal "}")) ,("parenthesized",Sequence (Sequence (Terminal "(") (NonTerminal "regex")) (Terminal ")")) ,("regex",NonTerminal "alternate") ,("sequence",KleeneStar (NonTerminal "expression")) ,("terminal",KleenePlus (NonTerminal "char")) ] regexExamples :: [(RegEx, String)] regexExamples = [ (Terminal "abc123etc.", "abc123etc\\.") , (Sequence (Terminal "x") (Terminal "y"), "xy") , (Fail, "\\q") , (Alternate (Terminal "x") (Terminal "y"), "x|y") , (KleeneOpt (Terminal "x"), "x?") , (KleeneStar (Terminal "x"), "x*") , (KleenePlus (Terminal "x"), "x+") , (AnyChar, ".") , (InClass "abc", "[abc]") , (NotInClass "abc", "[^abc]") , (InCategory UppercaseLetter, "\\p{Lu}") , (NotInCategory LowercaseLetter, "\\P{Ll}") , (NonTerminal "rule-name", "\\q{rule-name}") , (Terminal "", "") ] main :: IO () main = hspec $ do describe "regexGrammar" $ do it "should generate a correct grammar" $ genGrammar regexGrammar `shouldBe` expectedRegexGrammar for_ regexExamples $ \(rex, str) -> do it ("should print " <> show rex <> " correctly") $ showGrammar regexGrammar rex `shouldBe` Just str for_ regexExamples $ \(rex, str) -> do it ("should parse " <> str <> " correctly") $ readGrammar regexGrammar str `shouldSatisfy` elem rex