module PPTest.Grammars.Ebnf (specs) where import Data.Either import PP import PP.Grammars.Ebnf import System.IO import Test.Hspec specs = describe "PPTest.Grammars.Ebnf" $ do it "should detect a simple syntax error" $ case parseAst "a = b" :: To Syntax of Left e -> show e `shouldNotBe` "" Right o -> stringify o `shouldBe` "an error" it "should detect bad enclosing" $ case parseAst "a = (b | [c - {d})" :: To Syntax of Left e -> show e `shouldNotBe` "" Right o -> stringify o `shouldBe` "an error" it "should parseAst a simple correct input" $ case parseAst "a = b;" :: To Syntax of Left e -> show e `shouldBe` "not an error" Right o -> stringify o `shouldBe` "=;" it "should parseAst a more complex correct input" $ case parseAst "a = b, (c | d);\ne = 4 * [f];\nh = i | j;" :: To Syntax of Left e -> show e `shouldBe` "not an error" Right o -> stringify o `shouldBe` "=,(|);\n=4*[];\n=|;" it "should parseAst terminal string" $ case parseAst "a = \"h 'w\"; b = \"h \\\"w\";" :: To Syntax of Left e -> show e `shouldBe` "not an error" Right o -> stringify o `shouldBe` "=\"h 'w\";\n=\"h \\\"w\";" it "should parseAst complex meta identifiers" $ case parseAst "a a = b; a = b b; =b; a=;" :: To Syntax of Left e -> show e `shouldBe` "not an error" Right o -> stringify o `shouldBe` "=;\n=;\n=;\n=;" it "should ignore comments" $ case parseAst "(* 1 *) a = b; (* 2 *) c = d; (* 3 *)" :: To Syntax of Left e -> show e `shouldBe` "not an error" Right o -> stringify o `shouldBe` "=;\n=;" it "should deal with any white spaces" $ case parseAst " \t\n a \n = \tb \n\t| c ; \t " :: To Syntax of Left e -> show e `shouldBe` "not an error" Right o -> stringify o `shouldBe` "=|;" it "should parseAst the complete EBNF grammar" $ do g <- readFile "test/res/ebnf.ebnf" m <- readFile "test/res/ebnf.min.ebnf" case parseAst g :: To Syntax of Left e -> show e `shouldBe` "not an error" Right o -> stringify o ++ "\n" `shouldBe` m it "should parseAst the complete minified EBNF grammar" $ do g <- readFile "test/res/ebnf.min.ebnf" m <- readFile "test/res/ebnf.min.ebnf" case parseAst g :: To Syntax of Left e -> show e `shouldBe` "not an error" Right o -> stringify o ++ "\n" `shouldBe` m it "should handle multiple parseAst and stringify" $ case parseAst "a = b;" :: To Syntax of Left e1 -> show e1 `shouldBe` "not an error (e1)" Right o1 -> let s1 = stringify o1 in case parseAst s1 :: To Syntax of Left e2 -> show e2 `shouldBe` "not an error (e2)" Right o2 -> stringify o2 `shouldBe` "=;" it "should handle translation to canonical rules (meta identifiers)" $ let Right ast = parseAst "a = b;" :: To Syntax in rules ast `shouldBe` [Rule "a" [NonTerm "b", PP.Empty]] it "should handle translation to canonical rules (alternatives)" $ let Right ast = parseAst "a = b | c;" :: To Syntax in rules ast `shouldBe` [Rule "a" [NonTerm "b", PP.Empty], Rule "a" [NonTerm "c", PP.Empty]] it "should handle translation to canonical rules (terminal string)" $ let Right ast = parseAst "a = \"hi\";" :: To Syntax in rules ast `shouldBe` [Rule "a" [PP.Term 'h', PP.Term 'i', PP.Empty]] it "should handle translation to canonical rules (optional sequences)" $ let Right ast = parseAst "a = [b];" :: To Syntax in rules ast `shouldBe` [Rule "[]" [NonTerm "b", PP.Empty], Rule "[]" [PP.Empty], Rule "a" [NonTerm "[]", PP.Empty]] it "should handle translation to canonical rules (repeated sequences, left)" $ let Right ast = parseAst "a = {b}, c;" :: To Syntax in rules ast `shouldBe` [Rule "a" [NonTerm "{}", NonTerm "c", PP.Empty], Rule "{}" [NonTerm "b", NonTerm "{}", PP.Empty], Rule "{}" [PP.Empty]] it "should handle translation to canonical rules (repeated sequences, right)"$ let Right ast = parseAst "a = c, {b};" :: To Syntax in rules ast `shouldBe` [Rule "a" [NonTerm "c", NonTerm "{}", PP.Empty], Rule "{}" [NonTerm "b", NonTerm "{}", PP.Empty], Rule "{}" [PP.Empty]] it "should handle translation to canonical rules (grouped sequences)" $ let Right ast = parseAst "a = (b | c), d;" :: To Syntax in rules ast `shouldBe` [Rule "(|)" [NonTerm "b", PP.Empty], Rule "(|)" [NonTerm "c", PP.Empty], Rule "a" [NonTerm "(|)", NonTerm "d", PP.Empty]] it "should handle translation to canonical rules (factor)" $ let Right ast = parseAst "a = 2 * b;" :: To Syntax in rules ast `shouldBe` [Rule "a" [NonTerm "b", NonTerm "b", PP.Empty]] it "should handle translation to canonical rules (exception)" $ let Right ast = parseAst "a = - c;" :: To Syntax in pendingWith "exception not supported yet" it "should handle translation to canonical rules (complex rules)" $ let Right ast = parseAst "a = [(b, c) | {d}], e | (f | g);" :: To Syntax in rules ast `shouldBe` [Rule "(,)" [NonTerm "b",NonTerm "c",PP.Empty], Rule "(|)" [NonTerm "f",PP.Empty], Rule "(|)" [NonTerm "g",PP.Empty], Rule "[(,)|{}]" [NonTerm "(,)",PP.Empty], Rule "[(,)|{}]" [NonTerm "{}",PP.Empty], Rule "[(,)|{}]" [PP.Empty], Rule "a" [NonTerm "(|)",PP.Empty], Rule "a" [NonTerm "[(,)|{}]",NonTerm "e",PP.Empty], Rule "{}" [NonTerm "d",NonTerm "{}",PP.Empty], Rule "{}" [PP.Empty]] it "should handle lexical rules (PP.Grammars.LexicalHelper)" $ let Right ast = parseAst "a = b; b %= c; c = d;" :: To Syntax in rules ast `shouldBe` [Rule "a" [NonTerm "b", PP.Empty], Rule "b" [NonTerm "c", PP.Empty], Rule "c" [NonTerm "d", PP.Empty]] it "should lexify correctly" $ let Right ast = parseAst "d%=\"[0-9]\";\nn%=d,\"+\";\ns=\"ab\",n;" :: To Syntax in stringify (lexify ast) `shouldBe` "__token_ab%=\"ab\";\nd%=\"[0-9]\";\nn%=d,\"+\";\n=<__token_ab>,;"