module Text.Peggy.Normalize ( normalize, shouldBind, ) where import Data.List import Text.Peggy.Syntax normalize :: Syntax -> Syntax normalize = map desugarDef . addSkipDelim addSkipDelim :: Syntax -> Syntax addSkipDelim defs = skp ++ dlm ++ defs where skp | hasSkip = [] | otherwise = [defaultSkipImpl] dlm | hasDelim = [] | otherwise = [defaultDelimImpl] hasSkip = not $ null [ () | Definition nont _ _ <- defs , nont == "skip" ] hasDelim = not $ null [ () | Definition nont _ _ <- defs , nont == "delimiter" ] defaultSkipImpl = Definition "skip" "()" $ Primitive "space" defaultDelimImpl = Definition "delimiter" "()" $ Primitive "defaultDelimiter" desugarDef :: Definition -> Definition desugarDef (Definition nont typ expr) = Definition nont typ (desugar expr) where desugar e = case e of Terminals True True str -> Token $ Terminals False False str Terminals {} -> e TerminalSet {} -> e TerminalCmp {} -> e TerminalAny {} -> e NonTerminal {} -> e Primitive {} -> e Empty -> e Named name f -> Named name $ desugar f Choice es -> Choice $ map desugar es Many f -> Many $ desugar f Some f -> Some $ desugar f Optional f -> Optional $ desugar f And f -> And $ desugar f Not f -> Not $ desugar f Sequence es -> desugar $ Semantic (Sequence es) $ defaultCF $ length $ filter shouldBind es Semantic (Sequence es) cf -> Semantic (Sequence $ map desugar es) cf Semantic f cf -> Semantic (Sequence [desugar f]) cf SepBy f g -> desugar (Choice [SepBy1 f g, Semantic Empty [Snippet "[]"]]) SepBy1 f g -> let f' = desugar f in let g' = desugar g in let g'' = desugar $ Semantic g' [Snippet "()"] in Semantic (Sequence [f', (Many (Semantic (Sequence [g'', f']) [Argument 2]))]) [ Argument 1 , Snippet ":" , Argument 2 ] Token f -> Token $ desugar f defaultCF n = [ Snippet "(" ] ++ intersperse (Snippet ",") (map Argument[1..n]) ++ [ Snippet ")" ] shouldBind f = case f of Terminals _ _ _ -> False And _ -> False Not _ -> False Token g -> shouldBind g _ -> True