{-# OPTIONS_GHC -fno-warn-missing-fields #-} module Language.LBNF ( lbnf -- QuasiQuoter for LBNF , bnfc -- Parser meta-generator function , dumpAlex, dumpHappy, dumpHappyM, dumpCode, getCode -- Debug / code generation , module Language.LBNF.Compiletime -- , module Language.LBNF.Grammar ) where import Language.LBNF.CFtoAbstract(absRules,absTokens) import Language.LBNF.CFtoAlex2(cf2alex2, abstractAlex, concreteAlex) import Language.LBNF.CFtoHappy(cf2Happy, abstractHappy, concreteHappy) import Language.LBNF.CFtoQQ(cf2qq) import Language.LBNF.CFtoPrinter import Language.LBNF.Compiletime import Language.LBNF.CF(CF, visibleNames, allCats, isNormal, hasIdent) import Language.LBNF.Grammar import Language.LBNF.GetCF import Language.Haskell.TH as TH import Language.Haskell.TH.Quote import Language.Haskell.TH.Hide import Data.List(isPrefixOf, intersperse) lbnf :: QuasiQuoter lbnf = grammar bnfc :: Grammar -> Q [Dec] bnfc = compile . toCF toCF :: Grammar -> CF toCF g = case getCFofG (return g) of (cf,[]) -> cf (_,msgs) -> error $ unlines msgs compile :: CF -> Q [Dec] compile g = do l <- location -- m <- fmap loc_module location datas <- absRules g tokens <- absTokens g pretty <- cf2Printer g dEp <- cf2qq g dalx <- abstractAlex g dhpy <- abstractHappy l g hide g $ concat [ datas , tokens , pretty , dEp , dalx , dhpy ] hide cf = export (map mkName $ visibleNames cf) where exportList m cf = "(" ++ concat (intersperse "\n , " $ map (m++) ns) ++ ")" where ns = visibleNames cf ++ map (++"(..)") (filter isNormal (allCats cf)) ++ if hasIdent cf then ["Ident(..)"] else [] dumpHappy :: Grammar -> Q [Dec] dumpHappy g = location >>= \l -> dumpHappyM g (loc_module l, loc_package l) >> bnfc g dumpHappyM :: Grammar -> (String,String) -> Q () dumpHappyM g (p,m) = do let cf = toCF g runIO $ writeFile "dump.y" $ cf2Happy (Loc {loc_module = m, loc_package = p}) cf -- compile cf dumpAlex :: Grammar -> Q [Dec] dumpAlex g = do let cf = toCF g runIO $ writeFile "dump.x" $ cf2alex2 cf compile cf dumpCode :: Grammar -> Q [Dec] dumpCode g = do runIO $ getCode ("main","Main") g >>= writeFile "dump.hs" bnfc g getCode :: (String,String) -> Grammar -> IO String getCode (p,m) g = do let cf = toCF g datas <- runQ $ absRules cf tokens <- runQ $ absTokens cf pretty <- runQ $ cf2Printer cf dEp <- runQ $ cf2qq cf let header = unlines [ "{-# OPTIONS_GHC -fno-warn-overlapping-patterns #-}" , "module "++m++exportList (m++".") cf++" where" , "import Language.LBNF.Compiletime" ] res = unlines [ header, uglyPrint $ pprint $ concat [datas , tokens, pretty, dEp], concreteAlex cf, concreteHappy (Loc {loc_module = m, loc_package = p}) cf ] return res uglyPrint = subst "GHC.Base." "" . subst "GHC.Show." "" . subst "Language.LBNF.ParseMonad." "" . subst "Language.LBNF.Runtime." "" . subst "GHC.List." "" . subst "GHC.Classes." "" . subst "GHC.Types." "" test = " 'e'])])\n" ++ "global_aq (AqToken a_10) = Language.LBNF.Runtime.aqFromString ((drop 2 GHC.Base.. (reverse GHC.Base.. (GHC.List.drop 3 GHC.Base.. GHC.List.reverse))) GHC.Base.$ Language.LBNF.Runtime.printTree a_10)" subst _ _ [] = [] subst from to xs@(a:as) = if isPrefixOf from xs then to ++ subst from to (drop (length from) xs) else a : subst from to as