{-# LANGUAGE FlexibleContexts #-} module Generics.GPAH.Derive.Analyze where import Generics.GPAH.Derive.Base import qualified Generics.GPAH.Hackage.Base as Hackage import qualified Data.Map as M import Data.Monoid import Language.Haskell.Exts import Language.Haskell.Exts.Comments import Text.ParserCombinators.UU import Text.ParserCombinators.UU.BasicInstances import Text.ParserCombinators.UU.Utils import Generics.SYB analyzeModule :: ParseResult (Module, [Comment]) -> Hackage.Analysis -> Analysis analyzeModule (ParseOk (m, c)) hacPkg = Analysis (runDeriveTH m hacPkg) (runDerivePP c) (runDriftPP c) (runDriftGL c) analyzeModule _ _ = mempty runDeriveTH :: Module -> Hackage.Analysis -> M.Map String Int runDeriveTH m hacPkg | "derive" `elem` (M.keys (Hackage.reverseDeps hacPkg)) = everything (M.unionWith (+)) (mempty `mkQ` thDecl) m where thDecl :: Splice -> M.Map String Int thDecl (ParenSplice (App (App (Var (UnQual (Ident "derive"))) (Var (UnQual (Ident class_)))) (TypQuote (UnQual (Ident dt))))) = M.singleton class_ 1 thDecl (ParenSplice (App (App (Var (UnQual (Ident "derive"))) (Var (UnQual (Ident class_)))) (List dts))) = M.singleton class_ (length dts) thDecl (ParenSplice (App (App (Var (UnQual (Ident "derive"))) (List classes_ids)) (TypQuote (UnQual (Ident dt))))) = let classes = map (\ (Var (UnQual (Ident class_))) -> class_) classes_ids in M.fromList (zip classes (repeat 1)) thDecl (ParenSplice (App (App (Var (UnQual (Ident "derive"))) (List classes_ids)) (List dts))) = let classes = map (\ (Var (UnQual (Ident class_))) -> class_) classes_ids in M.fromList (zip classes (repeat (length dts))) thDecl _ = mempty runDeriveTH _ _ = mempty runDerivePP :: [Comment] -> M.Map String Int runDerivePP cs = foldl (\ m r -> M.insertWith (+) r 1 m) mempty $ concatMap (\ (Comment ml _ s) -> case (ml, execParser pDerivePP s) of (True, (res, [])) -> res _ -> [] -- error in parsing or single-line ) cs runDriftPP :: [Comment] -> M.Map String Int runDriftPP cs = foldl (\ m r -> M.insertWith (+) r 1 m) mempty $ concatMap (\ (Comment _ _ s) -> case execParser pDriftPP s of (res, []) -> res _ -> [] -- error in parsing ) cs runDriftGL :: [Comment] -> M.Map String Int runDriftGL cs =foldl (\ m r -> M.insertWith (+) r 1 m) mempty $ concatMap (\ (Comment _ _ s) -> case execParser pDriftGL s of (res, []) -> res _ -> [] -- error in parsing ) cs pDerivePP :: Parser [String] pDerivePP = deriveStandalone <|> deriveInline where deriveInline :: Parser [String] deriveInline = pSym '!' *> pList1Sep (pSym ',') pcl <* pSpaces <* pSym '!' where pcl :: Parser String pcl =foldl1 (<|>) (map (\ c -> pSpaces *> pToken c) deriveClasses) deriveStandalone :: Parser [String] deriveStandalone = pSym '!' *> pSpaces *> pToken "deriving" *> pSpaces *> pToken "instance" *> pList1Sep (pSym ',') pcl <* pSpaces <* pSym '!' where pcl :: Parser String pcl =foldl1 (<|>) (map (\ c -> pSpaces *> pToken c) deriveClasses) pDriftPP :: Parser [String] pDriftPP = driftInline <|> driftStandalone where driftInline :: Parser [String] driftInline = pSym '!' *> pSpaces *> pToken "derive:" *> pList1Sep (pSym ',') pcl <* pSpaces <* pSym '!' where pcl :: Parser String pcl =foldl1 (<|>) (map (\ c -> pSpaces *> pToken c) driftClasses) driftStandalone :: Parser [String] driftStandalone = pSym '!' *> pSpaces *> pToken "for" *> pSpaces *> pMunch (`notElem` " \n\r") *> pSpaces *> pToken "derive:" *> pList1Sep (pSym ',') pcl <* pSpaces <* pSym '!' where pcl :: Parser String pcl =foldl1 (<|>) (map (\ c -> pSpaces *> pToken c) driftClasses) pDriftGL :: Parser [String] pDriftGL = driftGlobal where driftGlobal :: Parser [String] driftGlobal = pSym '!' *> pSpaces *> pToken "global:" *> pList1Sep (pSym ',') pcl <* pSpaces <* pSym '!' where pcl :: Parser String pcl =foldl1 (<|>) (map (\ c -> pSpaces *> pToken c) driftClasses)