1 module HpcDraft (draft_plugin) where
10 import qualified HpcSet as Set
11 import qualified HpcMap as Map
15 ------------------------------------------------------------------------------
17 [ excludeOpt,includeOpt,hpcDirOpt,hsDirOpt,outputOpt ]
19 draft_plugin = Plugin { name = "draft"
20 , usage = "[OPTION] .. <TIX_FILE>"
21 , options = draft_options
22 , summary = "Generate draft overlay that provides 100% coverage"
23 , implementation = draft_main
24 , init_flags = default_flags
25 , final_flags = default_final_flags
28 ------------------------------------------------------------------------------
30 draft_main :: Flags -> [String] -> IO ()
31 draft_main hpcflags (progName:mods) = do
32 let hpcflags1 = hpcflags
33 { includeMods = Set.fromList mods
35 includeMods hpcflags }
36 let prog = getTixFileName $ progName
39 Just (Tix tickCounts) -> do
41 [ makeDraft hpcflags1 tixModule
42 | tixModule@(TixModule m _ _ _) <- tickCounts
43 , allowModule hpcflags1 m
45 case outputFile hpcflags1 of
46 "-" -> putStrLn (unlines outs)
47 out -> writeFile out (unlines outs)
48 Nothing -> hpcError draft_plugin $ "unable to find tix file for:" ++ progName
51 makeDraft :: Flags -> TixModule -> IO String
52 makeDraft hpcflags tix = do
53 let mod = tixModuleName tix
54 hash = tixModuleHash tix
55 tixs = tixModuleTixs tix
57 mix@(Mix filepath timestamp hash tabstop entries) <- readMix (hpcDirs hpcflags) mod
59 let forest = createMixEntryDom
61 | ((span,box),v) <- zip entries tixs
64 -- let show' (span,stuff) = show (span,stuff,grabHpcPos hsMap span)
65 -- putStrLn $ drawForest $ map (fmap show) $ forest
67 let non_ticked = findNotTickedFromList forest
69 hs <- readFileFromPath filepath (hsDirs hpcflags)
71 let hsMap :: Map.Map Int String
72 hsMap = Map.fromList (zip [1..] $ lines hs)
74 let quoteString = show
76 let firstLine pos = case fromHpcPos pos of
80 let showPleaseTick :: Int -> PleaseTick -> String
81 showPleaseTick d (TickFun str pos) =
82 spaces d ++ "tick function \"" ++ head str ++ "\" "
83 ++ "on line " ++ show (firstLine pos) ++ ";"
84 showPleaseTick d (TickExp pos) =
85 spaces d ++ "tick expression "
87 then "at position " ++ show pos ++ ";"
88 else quoteString txt ++ " " ++ "on line " ++ show (firstLine pos) ++ ";"
91 txt = grabHpcPos hsMap pos
93 showPleaseTick d (TickInside [str] pos pleases) =
94 spaces d ++ "function \"" ++ str ++ "\" {\n" ++
95 showPleaseTicks (d + 2) pleases ++
98 showPleaseTicks d pleases = unlines (map (showPleaseTick d) pleases)
100 spaces d = take d (repeat ' ')
102 return $ "module " ++ show (fixPackageSuffix mod) ++ " {\n" ++
103 showPleaseTicks 2 non_ticked ++ "}"
105 fixPackageSuffix :: String -> String
106 fixPackageSuffix mod = case span (/= '/') mod of
107 (before,'/':after) -> before ++ ":" ++ after
111 = TickFun [String] HpcPos
113 | TickInside [String] HpcPos [PleaseTick]
116 mkTickInside _ _ [] = id
117 mkTickInside nm pos inside = (TickInside nm pos inside :)
119 findNotTickedFromTree :: MixEntryDom [(BoxLabel,Bool)] -> [PleaseTick]
120 findNotTickedFromTree (Node (pos,(ExpBox {},False):_) _) = [TickExp pos]
121 findNotTickedFromTree (Node (pos,(TopLevelBox nm,False):_) _)
123 findNotTickedFromTree (Node (pos,(LocalBox nm,False):_) _)
125 findNotTickedFromTree (Node (pos,(TopLevelBox nm,True):others) children)
126 = mkTickInside nm pos (findNotTickedFromList children) []
127 findNotTickedFromTree (Node (pos,_:others) children) =
128 findNotTickedFromTree (Node (pos,others) children)
129 findNotTickedFromTree (Node (pos,[]) children) = findNotTickedFromList children
131 findNotTickedFromList :: [MixEntryDom [(BoxLabel,Bool)]] -> [PleaseTick]
132 findNotTickedFromList = concatMap findNotTickedFromTree
134 readFileFromPath :: String -> [String] -> IO String
135 readFileFromPath filename@('/':_) _ = readFile filename
136 readFileFromPath filename path0 = readTheFile path0
138 readTheFile :: [String] -> IO String
139 readTheFile [] = error $ "could not find " ++ show filename
140 ++ " in path " ++ show path0
141 readTheFile (dir:dirs) =
142 catch (do str <- readFile (dir ++ "/" ++ filename)
144 (\ _ -> readTheFile dirs)