platinum-parsing-0.1.0.0: test/PPTest/Grammars/Ebnf.hs
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` "<a>=<b>;"
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` "<a>=<b>,(<c>|<d>);\n<e>=4*[<f>];\n<h>=<i>|<j>;"
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` "<a>=\"h 'w\";\n<b>=\"h \\\"w\";"
it "should parseAst complex meta identifiers" $
case parseAst "a a = b; a = b b; <a>=b; a=<b>;" :: To Syntax of
Left e -> show e `shouldBe` "not an error"
Right o -> stringify o `shouldBe` "<a a>=<b>;\n<a>=<b b>;\n<a>=<b>;\n<a>=<b>;"
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` "<a>=<b>;\n<c>=<d>;"
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` "<a>=<b>|<c>;"
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` "<a>=<b>;"
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 "[<b>]" [NonTerm "b", PP.Empty],
Rule "[<b>]" [PP.Empty],
Rule "a" [NonTerm "[<b>]", 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 "{<b>}", NonTerm "c", PP.Empty],
Rule "{<b>}" [NonTerm "b", NonTerm "{<b>}", PP.Empty],
Rule "{<b>}" [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 "{<b>}", PP.Empty],
Rule "{<b>}" [NonTerm "b", NonTerm "{<b>}", PP.Empty],
Rule "{<b>}" [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 "(<b>|<c>)" [NonTerm "b", PP.Empty],
Rule "(<b>|<c>)" [NonTerm "c", PP.Empty],
Rule "a" [NonTerm "(<b>|<c>)", 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 = <b> - 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 "(<b>,<c>)" [NonTerm "b",NonTerm "c",PP.Empty],
Rule "(<f>|<g>)" [NonTerm "f",PP.Empty],
Rule "(<f>|<g>)" [NonTerm "g",PP.Empty],
Rule "[(<b>,<c>)|{<d>}]" [NonTerm "(<b>,<c>)",PP.Empty],
Rule "[(<b>,<c>)|{<d>}]" [NonTerm "{<d>}",PP.Empty],
Rule "[(<b>,<c>)|{<d>}]" [PP.Empty],
Rule "a" [NonTerm "(<f>|<g>)",PP.Empty],
Rule "a" [NonTerm "[(<b>,<c>)|{<d>}]",NonTerm "e",PP.Empty],
Rule "{<d>}" [NonTerm "d",NonTerm "{<d>}",PP.Empty],
Rule "{<d>}" [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<s>=<__token_ab>,<n>;"