platinum-parsing-0.1.0.0: test/PPTest/Other/LexerDfaParserLr.hs
module PPTest.Other.LexerDfaParserLr (specs) where
import qualified Data.Map.Strict as Map
import PP
import qualified PP.Builders.Lalr as Lalr
import qualified PP.Grammars.Ebnf as Ebnf
import qualified PP.Lexers.Dfa as Dfa
import qualified PP.Parsers.Lr as Lr
import Test.Hspec
import qualified PP.Builders.Nfa as Nfa
-- Grammar
g = "expr=number,{binop,number};\n\
\binop%=\"-|[+]\";\n\
\number%=digit,\"+\";\n\
\digit%=\"[0-9]\";"
Right ast = parseAst g :: To Ebnf.Syntax
-- Tests for chaining the lexer followed by the parser
specs = describe "PPTest.Other.LexerDfaParserLr" $ do
it "should be able to extract rules from the AST" $ do
let e = [Rule "binop" [RegEx "-|[+]",Empty],
Rule "digit" [RegEx "[0-9]",Empty],
Rule "expr" [NonTerm "number",NonTerm "{<binop>,<number>}",Empty],
Rule "number" [NonTerm "digit",RegEx "+",Empty],
Rule "{<binop>,<number>}" [NonTerm "binop",NonTerm "number",NonTerm "{<binop>,<number>}",Empty],
Rule "{<binop>,<number>}" [Empty]]
rules (lexify ast) `shouldBe` e
it "should be able to separate parsing and lexing rules" $ do
let e = ([Rule "expr" [TermToken "number",NonTerm "{<binop>,<number>}",Empty],
Rule "{<binop>,<number>}" [TermToken "binop",TermToken "number",NonTerm "{<binop>,<number>}",Empty],
Rule "{<binop>,<number>}" [Empty]],
[Rule "binop" [RegEx "-|[+]",Empty],
Rule "digit" [RegEx "[0-9]",Empty],
Rule "number" [TermToken "digit",RegEx "+",Empty]])
separate (rules $ lexify ast) `shouldBe` e
it "should be able to create a LALR table" $ do
let Right prs = extend $ fst $ separate $ rules $ lexify ast
let rs = ruleSet prs
let c = collection rs (firstSet rs) :: LrCollection Lalr.LalrItem
let e = [((0,NonTerm "expr"),LrGoto 1),
((0,TermToken "number"),LrShift 2),
((1,Empty),LrAccept),
((2,NonTerm "{<binop>,<number>}"),LrGoto 3),
((2,TermToken "binop"),LrShift 4),
((2,Empty),LrReduce $ Rule "{<binop>,<number>}" [Empty]),
((3,Empty),LrReduce $ Rule "expr" [TermToken "number",NonTerm "{<binop>,<number>}",Empty]),
((4,TermToken "number"),LrShift 5),
((5,NonTerm "{<binop>,<number>}"),LrGoto 6),
((5,TermToken "binop"),LrShift 4),
((5,Empty),LrReduce $ Rule "{<binop>,<number>}" [Empty]),
((6,Empty),LrReduce $ Rule "{<binop>,<number>}" [TermToken "binop",TermToken "number",NonTerm "{<binop>,<number>}",Empty])]
case table c of
Left err -> show err `shouldNotBe` "an error"
Right t -> Map.toList t `shouldBe` e
it "should be able to create the correct tokens" $ do
let i = "123-456+789"
let (_, lrs) = separate $ rules $ lexify ast
let lconfig = Dfa.dfaConfig i $ Dfa.createDfa lrs
let e = [OToken2 "123" "number",
OToken2 "-" "binop",
OToken2 "456" "number",
OToken2 "+" "binop",
OToken2 "789" "number"]
output (consume lconfig) `shouldBe` e
it "should be able to use a lexer and a parser in sequence" $ do
let i = "123-456+789"
let (prs, lrs) = separate $ rules $ lexify ast
let rs = ruleSet $ let Right x = extend prs in x
let c = collection rs (firstSet rs) :: LrCollection Lalr.LalrItem
let Right t = table c
let dfa = Dfa.createDfa lrs
let lconfig = Dfa.dfaConfig i dfa
let tokens = output $ consume lconfig
let pconfig = config t tokens
Lr.lrAction (parse t pconfig) `shouldBe` LrAccept