Tidy up rebindable syntax for MDo
[ghc-hetmet.git] / compiler / deSugar / Coverage.lhs
1 %
2 % (c) Galois, 2006
3 % (c) University of Glasgow, 2007
4 %
5 \section[Coverage]{@coverage@: the main function}
6
7 \begin{code}
8 module Coverage (addCoverageTicksToBinds) where
9
10 import HsSyn
11 import Module
12 import Outputable
13 import DynFlags
14 import Control.Monad
15 import SrcLoc
16 import ErrUtils
17 import Name
18 import Bag
19 import Id
20 import VarSet
21 import Data.List
22 import FastString
23 import HscTypes 
24 import StaticFlags
25 import TyCon
26 import MonadUtils
27 import Maybes
28
29 import Data.Array
30 import System.Directory ( createDirectoryIfMissing )
31
32 import Trace.Hpc.Mix
33 import Trace.Hpc.Util
34
35 import BreakArray 
36 import Data.HashTable   ( hashString )
37 import Data.Map (Map)
38 import qualified Data.Map as Map
39 \end{code}
40
41
42 %************************************************************************
43 %*                                                                      *
44 %*              The main function: addCoverageTicksToBinds
45 %*                                                                      *
46 %************************************************************************
47
48 \begin{code}
49 addCoverageTicksToBinds
50         :: DynFlags
51         -> Module
52         -> ModLocation          -- of the current module
53         -> [TyCon]              -- type constructor in this module
54         -> LHsBinds Id
55         -> IO (LHsBinds Id, HpcInfo, ModBreaks)
56
57 addCoverageTicksToBinds dflags mod mod_loc tyCons binds = 
58  case ml_hs_file mod_loc of
59  Nothing -> return (binds, emptyHpcInfo False, emptyModBreaks)
60  Just orig_file -> do
61
62   if "boot" `isSuffixOf` orig_file then return (binds, emptyHpcInfo False, emptyModBreaks) else do
63
64   -- Now, we try look for a file generated from a .hsc file to a .hs file, by peeking ahead.
65
66   let top_pos = catMaybes $ foldrBag (\ (L pos _) rest -> srcSpanFileName_maybe pos : rest) [] binds
67   let orig_file2 = case top_pos of
68                      (file_name:_) 
69                        | ".hsc" `isSuffixOf` unpackFS file_name -> unpackFS file_name
70                      _ -> orig_file
71
72   let mod_name = moduleNameString (moduleName mod)
73
74   let (binds1,_,st)
75                  = unTM (addTickLHsBinds binds) 
76                    (TTE
77                        { fileName    = mkFastString orig_file2
78                       , declPath     = []
79                       , inScope      = emptyVarSet
80                       , blackList    = Map.fromList [ (getSrcSpan (tyConName tyCon),()) 
81                                                     | tyCon <- tyCons ]
82                        })
83                    (TT 
84                       { tickBoxCount = 0
85                       , mixEntries   = []
86                       })
87
88   let entries = reverse $ mixEntries st
89
90   -- write the mix entries for this module
91   hashNo <- if opt_Hpc then do
92      let hpc_dir = hpcDir dflags
93
94      let hpc_mod_dir = if modulePackageId mod == mainPackageId 
95                        then hpc_dir
96                        else hpc_dir ++ "/" ++ packageIdString (modulePackageId mod)
97
98      let tabStop = 1 -- <tab> counts as a normal char in GHC's location ranges.
99      createDirectoryIfMissing True hpc_mod_dir
100      modTime <- getModificationTime orig_file2
101      let entries' = [ (hpcPos, box) 
102                     | (span,_,_,box) <- entries, hpcPos <- [mkHpcPos span] ]
103      when (length entries' /= tickBoxCount st) $ do
104        panic "the number of .mix entries are inconsistent"
105      let hashNo = mixHash orig_file2 modTime tabStop entries'
106      mixCreate hpc_mod_dir mod_name 
107                $ Mix orig_file2 modTime (toHash hashNo) tabStop entries'
108      return $ hashNo 
109    else do
110      return $ 0
111
112   -- Todo: use proper src span type
113   breakArray <- newBreakArray $ length entries
114
115   let locsTicks = listArray (0,tickBoxCount st-1) 
116                      [ span | (span,_,_,_) <- entries ]
117       varsTicks = listArray (0,tickBoxCount st-1) 
118                      [ vars | (_,_,vars,_) <- entries ]
119       declsTicks= listArray (0,tickBoxCount st-1) 
120                      [ decls | (_,decls,_,_) <- entries ]
121       modBreaks = emptyModBreaks 
122                   { modBreaks_flags = breakArray 
123                   , modBreaks_locs  = locsTicks 
124                   , modBreaks_vars  = varsTicks
125                   , modBreaks_decls = declsTicks
126                   } 
127
128   doIfSet_dyn dflags  Opt_D_dump_hpc $ do
129           printDump (pprLHsBinds binds1)
130
131   return (binds1, HpcInfo (tickBoxCount st) hashNo, modBreaks)
132 \end{code}
133
134
135 \begin{code}
136 liftL :: (Monad m) => (a -> m a) -> Located a -> m (Located a)
137 liftL f (L loc a) = do
138   a' <- f a
139   return $ L loc a'
140
141 addTickLHsBinds :: LHsBinds Id -> TM (LHsBinds Id)
142 addTickLHsBinds binds = mapBagM addTickLHsBind binds
143
144 addTickLHsBind :: LHsBind Id -> TM (LHsBind Id)
145 addTickLHsBind (L pos bind@(AbsBinds { abs_binds = binds })) = do
146   binds' <- addTickLHsBinds binds
147   return $ L pos $ bind { abs_binds = binds' }
148 addTickLHsBind (L pos (funBind@(FunBind { fun_id = (L _ id)  }))) = do 
149   let name = getOccString id
150   decl_path <- getPathEntry
151
152   (fvs, (MatchGroup matches' ty)) <- 
153         getFreeVars $
154         addPathEntry name $
155         addTickMatchGroup (fun_matches funBind)
156
157   blackListed <- isBlackListed pos
158
159   -- Todo: we don't want redundant ticks on simple pattern bindings
160   -- We don't want to generate code for blacklisted positions
161   if blackListed || (not opt_Hpc && isSimplePatBind funBind)
162      then 
163         return $ L pos $ funBind { fun_matches = MatchGroup matches' ty 
164                                  , fun_tick = Nothing 
165                                  }
166      else do
167         tick_no <- allocATickBox (if null decl_path
168                                      then TopLevelBox [name]
169                                      else LocalBox (decl_path ++ [name])) 
170                                 pos fvs
171
172         return $ L pos $ funBind { fun_matches = MatchGroup matches' ty 
173                                  , fun_tick = tick_no
174                                  }
175    where
176    -- a binding is a simple pattern binding if it is a funbind with zero patterns
177    isSimplePatBind :: HsBind a -> Bool
178    isSimplePatBind funBind = matchGroupArity (fun_matches funBind) == 0
179
180 -- TODO: Revisit this
181 addTickLHsBind (L pos (pat@(PatBind { pat_rhs = rhs }))) = do
182   let name = "(...)"
183   rhs' <- addPathEntry name $ addTickGRHSs False rhs
184 {-
185   decl_path <- getPathEntry
186   tick_me <- allocTickBox (if null decl_path
187                            then TopLevelBox [name]
188                            else LocalBox (name : decl_path))
189 -}                         
190   return $ L pos $ pat { pat_rhs = rhs' }
191
192 -- Only internal stuff, not from source, uses VarBind, so we ignore it.
193 addTickLHsBind var_bind@(L _ (VarBind {})) = return var_bind
194
195 -- Add a tick to the expression no matter what it is.  There is one exception:
196 -- for the debugger, if the expression is a 'let', then we don't want to add
197 -- a tick here because there will definititely be a tick on the body anyway.
198 addTickLHsExprAlways :: LHsExpr Id -> TM (LHsExpr Id)
199 addTickLHsExprAlways (L pos e0)
200   | not opt_Hpc, HsLet _ _ <- e0 = addTickLHsExprNever (L pos e0)
201   | otherwise = allocTickBox (ExpBox False) pos $ addTickHsExpr e0
202
203 addTickLHsExprNeverOrAlways :: LHsExpr Id -> TM (LHsExpr Id)
204 addTickLHsExprNeverOrAlways e
205     | opt_Hpc   = addTickLHsExprNever e
206     | otherwise = addTickLHsExprAlways e
207
208 addTickLHsExprNeverOrMaybe :: LHsExpr Id -> TM (LHsExpr Id)
209 addTickLHsExprNeverOrMaybe e
210     | opt_Hpc   = addTickLHsExprNever e
211     | otherwise = addTickLHsExpr e
212
213 -- version of addTick that does not actually add a tick,
214 -- because the scope of this tick is completely subsumed by 
215 -- another.
216 addTickLHsExprNever :: LHsExpr Id -> TM (LHsExpr Id)
217 addTickLHsExprNever (L pos e0) = do
218     e1 <- addTickHsExpr e0
219     return $ L pos e1
220
221 -- selectively add ticks to interesting expressions
222 addTickLHsExpr :: LHsExpr Id -> TM (LHsExpr Id)
223 addTickLHsExpr (L pos e0) = do
224     if opt_Hpc || isGoodBreakExpr e0
225        then do
226           allocTickBox (ExpBox False) pos $ addTickHsExpr e0
227        else do
228           e1 <- addTickHsExpr e0
229           return $ L pos e1 
230
231 -- general heuristic: expressions which do not denote values are good break points
232 isGoodBreakExpr :: HsExpr Id -> Bool
233 isGoodBreakExpr (HsApp {})     = True
234 isGoodBreakExpr (OpApp {})     = True
235 isGoodBreakExpr (NegApp {})    = True
236 isGoodBreakExpr (HsCase {})    = True
237 isGoodBreakExpr (HsIf {})      = True
238 isGoodBreakExpr (RecordCon {}) = True
239 isGoodBreakExpr (RecordUpd {}) = True
240 isGoodBreakExpr (ArithSeq {})  = True
241 isGoodBreakExpr (PArrSeq {})   = True
242 isGoodBreakExpr _other         = False 
243
244 addTickLHsExprOptAlt :: Bool -> LHsExpr Id -> TM (LHsExpr Id)
245 addTickLHsExprOptAlt oneOfMany (L pos e0)
246   | not opt_Hpc = addTickLHsExpr (L pos e0)
247   | otherwise =
248     allocTickBox (ExpBox oneOfMany) pos $ 
249         addTickHsExpr e0
250
251 addBinTickLHsExpr :: (Bool -> BoxLabel) -> LHsExpr Id -> TM (LHsExpr Id)
252 addBinTickLHsExpr boxLabel (L pos e0) =
253     allocBinTickBox boxLabel pos $
254         addTickHsExpr e0
255
256 addTickHsExpr :: HsExpr Id -> TM (HsExpr Id)
257 addTickHsExpr e@(HsVar id) = do freeVar id; return e
258 addTickHsExpr e@(HsIPVar _) = return e
259 addTickHsExpr e@(HsOverLit _) = return e
260 addTickHsExpr e@(HsLit _) = return e
261 addTickHsExpr (HsLam matchgroup) =
262         liftM HsLam (addTickMatchGroup matchgroup)
263 addTickHsExpr (HsApp e1 e2) = 
264         liftM2 HsApp (addTickLHsExprNever e1) (addTickLHsExpr e2)
265 addTickHsExpr (OpApp e1 e2 fix e3) = 
266         liftM4 OpApp 
267                 (addTickLHsExpr e1) 
268                 (addTickLHsExprNever e2)
269                 (return fix)
270                 (addTickLHsExpr e3)
271 addTickHsExpr (NegApp e neg) =
272         liftM2 NegApp
273                 (addTickLHsExpr e) 
274                 (addTickSyntaxExpr hpcSrcSpan neg)
275 addTickHsExpr (HsPar e) = liftM HsPar (addTickLHsExprNeverOrMaybe e)
276 addTickHsExpr (SectionL e1 e2) = 
277         liftM2 SectionL
278                 (addTickLHsExpr e1)
279                 (addTickLHsExpr e2)
280 addTickHsExpr (SectionR e1 e2) = 
281         liftM2 SectionR
282                 (addTickLHsExpr e1)
283                 (addTickLHsExpr e2)
284 addTickHsExpr (ExplicitTuple es boxity) =
285         liftM2 ExplicitTuple
286                 (mapM addTickTupArg es)
287                 (return boxity)
288 addTickHsExpr (HsCase e mgs) = 
289         liftM2 HsCase
290                 (addTickLHsExpr e) 
291                 (addTickMatchGroup mgs)
292 addTickHsExpr (HsIf cnd e1 e2 e3) = 
293         liftM3 (HsIf cnd)
294                 (addBinTickLHsExpr (BinBox CondBinBox) e1)
295                 (addTickLHsExprOptAlt True e2)
296                 (addTickLHsExprOptAlt True e3)
297 addTickHsExpr (HsLet binds e) =
298         bindLocals (collectLocalBinders binds) $
299         liftM2 HsLet
300                 (addTickHsLocalBinds binds) -- to think about: !patterns.
301                 (addTickLHsExprNeverOrAlways e)
302 addTickHsExpr (HsDo cxt stmts last_exp srcloc) = do
303         (stmts', last_exp') <- addTickLStmts' forQual stmts 
304                                      (addTickLHsExpr last_exp)
305         return (HsDo cxt stmts' last_exp' srcloc)
306   where
307         forQual = case cxt of
308                     ListComp -> Just $ BinBox QualBinBox
309                     _        -> Nothing
310 addTickHsExpr (ExplicitList ty es) = 
311         liftM2 ExplicitList
312                 (return ty)
313                 (mapM (addTickLHsExpr) es)
314 addTickHsExpr (ExplicitPArr ty es) =
315         liftM2 ExplicitPArr
316                 (return ty)
317                 (mapM (addTickLHsExpr) es)
318 addTickHsExpr (RecordCon id ty rec_binds) = 
319         liftM3 RecordCon
320                 (return id)
321                 (return ty)
322                 (addTickHsRecordBinds rec_binds)
323 addTickHsExpr (RecordUpd e rec_binds cons tys1 tys2) =
324         liftM5 RecordUpd
325                 (addTickLHsExpr e)
326                 (addTickHsRecordBinds rec_binds)
327                 (return cons) (return tys1) (return tys2)
328
329 addTickHsExpr (ExprWithTySigOut e ty) =
330         liftM2 ExprWithTySigOut
331                 (addTickLHsExprNever e) -- No need to tick the inner expression
332                                     -- for expressions with signatures
333                 (return ty)
334 addTickHsExpr (ArithSeq  ty arith_seq) =
335         liftM2 ArithSeq 
336                 (return ty)
337                 (addTickArithSeqInfo arith_seq)
338 addTickHsExpr (HsTickPragma _ (L pos e0)) = do
339     e2 <- allocTickBox (ExpBox False) pos $
340                 addTickHsExpr e0
341     return $ unLoc e2
342 addTickHsExpr (PArrSeq   ty arith_seq) =
343         liftM2 PArrSeq  
344                 (return ty)
345                 (addTickArithSeqInfo arith_seq)
346 addTickHsExpr (HsSCC nm e) =
347         liftM2 HsSCC 
348                 (return nm)
349                 (addTickLHsExpr e)
350 addTickHsExpr (HsCoreAnn nm e) = 
351         liftM2 HsCoreAnn 
352                 (return nm)
353                 (addTickLHsExpr e)
354 addTickHsExpr e@(HsBracket     {}) = return e
355 addTickHsExpr e@(HsBracketOut  {}) = return e
356 addTickHsExpr e@(HsSpliceE  {}) = return e
357 addTickHsExpr (HsProc pat cmdtop) =
358         liftM2 HsProc
359                 (addTickLPat pat)
360                 (liftL (addTickHsCmdTop) cmdtop)
361 addTickHsExpr (HsWrap w e) = 
362         liftM2 HsWrap
363                 (return w)
364                 (addTickHsExpr e)       -- explicitly no tick on inside
365 addTickHsExpr (HsArrApp  e1 e2 ty1 arr_ty lr) = 
366         liftM5 HsArrApp
367                (addTickLHsExpr e1)
368                (addTickLHsExpr e2)
369                (return ty1)
370                (return arr_ty)
371                (return lr)
372 addTickHsExpr (HsArrForm e fix cmdtop) = 
373         liftM3 HsArrForm
374                (addTickLHsExpr e)
375                (return fix)
376                (mapM (liftL (addTickHsCmdTop)) cmdtop)
377
378 addTickHsExpr e@(HsType _) = return e
379
380 -- Others dhould never happen in expression content.
381 addTickHsExpr e  = pprPanic "addTickHsExpr" (ppr e)
382
383 addTickTupArg :: HsTupArg Id -> TM (HsTupArg Id)
384 addTickTupArg (Present e)  = do { e' <- addTickLHsExpr e; return (Present e') }
385 addTickTupArg (Missing ty) = return (Missing ty)
386
387 addTickMatchGroup :: MatchGroup Id -> TM (MatchGroup Id)
388 addTickMatchGroup (MatchGroup matches ty) = do
389   let isOneOfMany = matchesOneOfMany matches
390   matches' <- mapM (liftL (addTickMatch isOneOfMany)) matches
391   return $ MatchGroup matches' ty
392
393 addTickMatch :: Bool -> Match Id -> TM (Match Id)
394 addTickMatch isOneOfMany (Match pats opSig gRHSs) =
395   bindLocals (collectPatsBinders pats) $ do
396     gRHSs' <- addTickGRHSs isOneOfMany gRHSs
397     return $ Match pats opSig gRHSs'
398
399 addTickGRHSs :: Bool -> GRHSs Id -> TM (GRHSs Id)
400 addTickGRHSs isOneOfMany (GRHSs guarded local_binds) = do
401   bindLocals binders $ do
402     local_binds' <- addTickHsLocalBinds local_binds
403     guarded' <- mapM (liftL (addTickGRHS isOneOfMany)) guarded
404     return $ GRHSs guarded' local_binds'
405   where
406     binders = collectLocalBinders local_binds
407
408 addTickGRHS :: Bool -> GRHS Id -> TM (GRHS Id)
409 addTickGRHS isOneOfMany (GRHS stmts expr) = do
410   (stmts',expr') <- addTickLStmts' (Just $ BinBox $ GuardBinBox) stmts
411                         (if opt_Hpc then addTickLHsExprOptAlt isOneOfMany expr
412                                     else addTickLHsExprAlways expr)
413   return $ GRHS stmts' expr'
414
415 addTickLStmts :: (Maybe (Bool -> BoxLabel)) -> [LStmt Id] -> TM [LStmt Id]
416 addTickLStmts isGuard stmts = do
417   (stmts, _) <- addTickLStmts' isGuard stmts (return ())
418   return stmts
419
420 addTickLStmts' :: (Maybe (Bool -> BoxLabel)) -> [LStmt Id] -> TM a 
421                -> TM ([LStmt Id], a)
422 addTickLStmts' isGuard lstmts res
423   = bindLocals binders $ do
424         lstmts' <- mapM (liftL (addTickStmt isGuard)) lstmts
425         a <- res
426         return (lstmts', a)
427   where
428         binders = collectLStmtsBinders lstmts
429
430 addTickStmt :: (Maybe (Bool -> BoxLabel)) -> Stmt Id -> TM (Stmt Id)
431 addTickStmt _isGuard (BindStmt pat e bind fail) = do
432         liftM4 BindStmt
433                 (addTickLPat pat)
434                 (addTickLHsExprAlways e)
435                 (addTickSyntaxExpr hpcSrcSpan bind)
436                 (addTickSyntaxExpr hpcSrcSpan fail)
437 addTickStmt isGuard (ExprStmt e bind' ty) = do
438         liftM3 ExprStmt
439                 (addTick isGuard e)
440                 (addTickSyntaxExpr hpcSrcSpan bind')
441                 (return ty)
442 addTickStmt _isGuard (LetStmt binds) = do
443         liftM LetStmt
444                 (addTickHsLocalBinds binds)
445 addTickStmt isGuard (ParStmt pairs) = do
446     liftM ParStmt 
447         (mapM (addTickStmtAndBinders isGuard) pairs)
448
449 addTickStmt isGuard (TransformStmt stmts ids usingExpr maybeByExpr) = do
450     liftM4 TransformStmt 
451         (addTickLStmts isGuard stmts)
452         (return ids)
453         (addTickLHsExprAlways usingExpr)
454         (addTickMaybeByLHsExpr maybeByExpr)
455
456 addTickStmt isGuard (GroupStmt stmts binderMap by using) = do
457     liftM4 GroupStmt 
458         (addTickLStmts isGuard stmts)
459         (return binderMap)
460         (fmapMaybeM  addTickLHsExprAlways by)
461         (fmapEitherM addTickLHsExprAlways (addTickSyntaxExpr hpcSrcSpan) using)
462
463 addTickStmt isGuard stmt@(RecStmt {})
464   = do { stmts' <- addTickLStmts isGuard (recS_stmts stmt)
465        ; ret'   <- addTickSyntaxExpr hpcSrcSpan (recS_ret_fn stmt)
466        ; mfix'  <- addTickSyntaxExpr hpcSrcSpan (recS_mfix_fn stmt)
467        ; bind'  <- addTickSyntaxExpr hpcSrcSpan (recS_bind_fn stmt)
468        ; return (stmt { recS_stmts = stmts', recS_ret_fn = ret'
469                       , recS_mfix_fn = mfix', recS_bind_fn = bind' }) }
470
471 addTick :: Maybe (Bool -> BoxLabel) -> LHsExpr Id -> TM (LHsExpr Id)
472 addTick isGuard e | Just fn <- isGuard = addBinTickLHsExpr fn e
473                   | otherwise          = addTickLHsExprAlways e
474
475 addTickStmtAndBinders :: Maybe (Bool -> BoxLabel) -> ([LStmt Id], a) 
476                       -> TM ([LStmt Id], a)
477 addTickStmtAndBinders isGuard (stmts, ids) = 
478     liftM2 (,) 
479         (addTickLStmts isGuard stmts)
480         (return ids)
481
482 addTickMaybeByLHsExpr :: Maybe (LHsExpr Id) -> TM (Maybe (LHsExpr Id))
483 addTickMaybeByLHsExpr maybeByExpr = 
484     case maybeByExpr of
485         Nothing -> return Nothing
486         Just byExpr -> addTickLHsExprAlways byExpr >>= (return . Just)
487
488 addTickHsLocalBinds :: HsLocalBinds Id -> TM (HsLocalBinds Id)
489 addTickHsLocalBinds (HsValBinds binds) = 
490         liftM HsValBinds 
491                 (addTickHsValBinds binds)
492 addTickHsLocalBinds (HsIPBinds binds)  = 
493         liftM HsIPBinds 
494                 (addTickHsIPBinds binds)
495 addTickHsLocalBinds (EmptyLocalBinds)  = return EmptyLocalBinds
496
497 addTickHsValBinds :: HsValBindsLR Id a -> TM (HsValBindsLR Id b)
498 addTickHsValBinds (ValBindsOut binds sigs) =
499         liftM2 ValBindsOut
500                 (mapM (\ (rec,binds') -> 
501                                 liftM2 (,)
502                                         (return rec)
503                                         (addTickLHsBinds binds'))
504                         binds)
505                 (return sigs)
506 addTickHsValBinds _ = panic "addTickHsValBinds"
507
508 addTickHsIPBinds :: HsIPBinds Id -> TM (HsIPBinds Id)
509 addTickHsIPBinds (IPBinds ipbinds dictbinds) =
510         liftM2 IPBinds
511                 (mapM (liftL (addTickIPBind)) ipbinds)
512                 (return dictbinds)
513
514 addTickIPBind :: IPBind Id -> TM (IPBind Id)
515 addTickIPBind (IPBind nm e) =
516         liftM2 IPBind
517                 (return nm)
518                 (addTickLHsExpr e)
519
520 -- There is no location here, so we might need to use a context location??
521 addTickSyntaxExpr :: SrcSpan -> SyntaxExpr Id -> TM (SyntaxExpr Id)
522 addTickSyntaxExpr pos x = do
523         L _ x' <- addTickLHsExpr (L pos x)
524         return $ x'
525 -- we do not walk into patterns.
526 addTickLPat :: LPat Id -> TM (LPat Id)
527 addTickLPat pat = return pat
528
529 addTickHsCmdTop :: HsCmdTop Id -> TM (HsCmdTop Id)
530 addTickHsCmdTop (HsCmdTop cmd tys ty syntaxtable) =
531         liftM4 HsCmdTop
532                 (addTickLHsCmd cmd)
533                 (return tys)
534                 (return ty)
535                 (return syntaxtable)
536
537 addTickLHsCmd ::  LHsCmd Id -> TM (LHsCmd Id)
538 addTickLHsCmd x = addTickLHsExpr x
539
540 addTickHsRecordBinds :: HsRecordBinds Id -> TM (HsRecordBinds Id)
541 addTickHsRecordBinds (HsRecFields fields dd) 
542   = do  { fields' <- mapM process fields
543         ; return (HsRecFields fields' dd) }
544   where
545     process (HsRecField ids expr doc)
546         = do { expr' <- addTickLHsExpr expr
547              ; return (HsRecField ids expr' doc) }
548
549 addTickArithSeqInfo :: ArithSeqInfo Id -> TM (ArithSeqInfo Id)
550 addTickArithSeqInfo (From e1) =
551         liftM From
552                 (addTickLHsExpr e1)
553 addTickArithSeqInfo (FromThen e1 e2) =
554         liftM2 FromThen
555                 (addTickLHsExpr e1)
556                 (addTickLHsExpr e2)
557 addTickArithSeqInfo (FromTo e1 e2) =
558         liftM2 FromTo
559                 (addTickLHsExpr e1)
560                 (addTickLHsExpr e2)
561 addTickArithSeqInfo (FromThenTo e1 e2 e3) =
562         liftM3 FromThenTo
563                 (addTickLHsExpr e1)
564                 (addTickLHsExpr e2)
565                 (addTickLHsExpr e3)
566 \end{code}
567
568 \begin{code}
569 data TickTransState = TT { tickBoxCount:: Int
570                          , mixEntries  :: [MixEntry_]
571                          }                        
572
573 data TickTransEnv = TTE { fileName      :: FastString
574                         , declPath     :: [String]
575                         , inScope      :: VarSet
576                         , blackList   :: Map SrcSpan ()
577                         }
578
579 --      deriving Show
580
581 type FreeVars = OccEnv Id
582 noFVs :: FreeVars
583 noFVs = emptyOccEnv
584
585 -- Note [freevars]
586 --   For breakpoints we want to collect the free variables of an
587 --   expression for pinning on the HsTick.  We don't want to collect
588 --   *all* free variables though: in particular there's no point pinning
589 --   on free variables that are will otherwise be in scope at the GHCi
590 --   prompt, which means all top-level bindings.  Unfortunately detecting
591 --   top-level bindings isn't easy (collectHsBindsBinders on the top-level
592 --   bindings doesn't do it), so we keep track of a set of "in-scope"
593 --   variables in addition to the free variables, and the former is used
594 --   to filter additions to the latter.  This gives us complete control
595 --   over what free variables we track.
596
597 data TM a = TM { unTM :: TickTransEnv -> TickTransState -> (a,FreeVars,TickTransState) }
598         -- a combination of a state monad (TickTransState) and a writer
599         -- monad (FreeVars).
600
601 instance Monad TM where
602   return a = TM $ \ _env st -> (a,noFVs,st)
603   (TM m) >>= k = TM $ \ env st -> 
604                                 case m env st of
605                                   (r1,fv1,st1) -> 
606                                      case unTM (k r1) env st1 of
607                                        (r2,fv2,st2) -> 
608                                           (r2, fv1 `plusOccEnv` fv2, st2)
609
610 -- getState :: TM TickTransState
611 -- getState = TM $ \ env st -> (st, noFVs, st)
612
613 -- setState :: (TickTransState -> TickTransState) -> TM ()
614 -- setState f = TM $ \ env st -> ((), noFVs, f st)
615
616 getEnv :: TM TickTransEnv
617 getEnv = TM $ \ env st -> (env, noFVs, st)
618
619 withEnv :: (TickTransEnv -> TickTransEnv) -> TM a -> TM a
620 withEnv f (TM m) = TM $ \ env st -> 
621                                  case m (f env) st of
622                                    (a, fvs, st') -> (a, fvs, st')
623
624 getFreeVars :: TM a -> TM (FreeVars, a)
625 getFreeVars (TM m) 
626   = TM $ \ env st -> case m env st of (a, fv, st') -> ((fv,a), fv, st')
627
628 freeVar :: Id -> TM ()
629 freeVar id = TM $ \ env st -> 
630                 if id `elemVarSet` inScope env
631                    then ((), unitOccEnv (nameOccName (idName id)) id, st)
632                    else ((), noFVs, st)
633
634 addPathEntry :: String -> TM a -> TM a
635 addPathEntry nm = withEnv (\ env -> env { declPath = declPath env ++ [nm] })
636
637 getPathEntry :: TM [String]
638 getPathEntry = declPath `liftM` getEnv
639
640 getFileName :: TM FastString
641 getFileName = fileName `liftM` getEnv
642
643 sameFileName :: SrcSpan -> TM a -> TM a -> TM a
644 sameFileName pos out_of_scope in_scope = do
645   file_name <- getFileName
646   case srcSpanFileName_maybe pos of 
647     Just file_name2 
648       | file_name == file_name2 -> in_scope
649     _ -> out_of_scope
650
651 bindLocals :: [Id] -> TM a -> TM a
652 bindLocals new_ids (TM m)
653   = TM $ \ env st -> 
654                  case m env{ inScope = inScope env `extendVarSetList` new_ids } st of
655                    (r, fv, st') -> (r, fv `delListFromOccEnv` occs, st')
656   where occs = [ nameOccName (idName id) | id <- new_ids ] 
657
658 isBlackListed :: SrcSpan -> TM Bool
659 isBlackListed pos = TM $ \ env st -> 
660               case Map.lookup pos (blackList env) of
661                 Nothing -> (False,noFVs,st)
662                 Just () -> (True,noFVs,st)
663
664 -- the tick application inherits the source position of its
665 -- expression argument to support nested box allocations 
666 allocTickBox :: BoxLabel -> SrcSpan -> TM (HsExpr Id) -> TM (LHsExpr Id)
667 allocTickBox boxLabel pos m | isGoodSrcSpan' pos = 
668   sameFileName pos 
669     (do e <- m; return (L pos e)) $ do
670   (fvs, e) <- getFreeVars m
671   TM $ \ env st ->
672     let c = tickBoxCount st
673         ids = occEnvElts fvs
674         mes = mixEntries st
675         me = (pos, declPath env, map (nameOccName.idName) ids, boxLabel)
676     in
677     ( L pos (HsTick c ids (L pos e))
678     , fvs
679     , st {tickBoxCount=c+1,mixEntries=me:mes}
680     )
681 allocTickBox _boxLabel pos m = do e <- m; return (L pos e)
682
683 -- the tick application inherits the source position of its
684 -- expression argument to support nested box allocations 
685 allocATickBox :: BoxLabel -> SrcSpan -> FreeVars -> TM (Maybe (Int,[Id]))
686 allocATickBox boxLabel pos fvs | isGoodSrcSpan' pos = 
687   sameFileName pos 
688     (return Nothing) $ TM $ \ env st ->
689   let mydecl_path
690         | null (declPath env), TopLevelBox x <- boxLabel = x
691         | otherwise = declPath env
692       me = (pos, mydecl_path, map (nameOccName.idName) ids, boxLabel)
693       c = tickBoxCount st
694       mes = mixEntries st
695       ids = occEnvElts fvs
696   in ( Just (c, ids)
697      , noFVs
698      , st {tickBoxCount=c+1, mixEntries=me:mes}
699      )
700 allocATickBox _boxLabel _pos _fvs = return Nothing
701
702 allocBinTickBox :: (Bool -> BoxLabel) -> SrcSpan -> TM (HsExpr Id)
703                 -> TM (LHsExpr Id)
704 allocBinTickBox boxLabel pos m
705  | not opt_Hpc = allocTickBox (ExpBox False) pos m
706  | isGoodSrcSpan' pos =
707  do
708  e <- m
709  TM $ \ env st ->
710   let meT = (pos,declPath env, [],boxLabel True)
711       meF = (pos,declPath env, [],boxLabel False)
712       meE = (pos,declPath env, [],ExpBox False)
713       c = tickBoxCount st
714       mes = mixEntries st
715   in 
716              ( L pos $ HsTick c [] $ L pos $ HsBinTick (c+1) (c+2) (L pos e)
717            -- notice that F and T are reversed,
718            -- because we are building the list in
719            -- reverse...
720              , noFVs
721              , st {tickBoxCount=c+3 , mixEntries=meF:meT:meE:mes}
722              )
723 allocBinTickBox _boxLabel pos m = do e <- m; return (L pos e)
724
725 isGoodSrcSpan' :: SrcSpan -> Bool
726 isGoodSrcSpan' pos
727    | not (isGoodSrcSpan pos) = False
728    | start == end            = False
729    | otherwise               = True
730   where
731    start = srcSpanStart pos
732    end   = srcSpanEnd pos
733
734 mkHpcPos :: SrcSpan -> HpcPos
735 mkHpcPos pos 
736    | not (isGoodSrcSpan' pos) = panic "bad source span; expected such spans to be filtered out"
737    | otherwise                = hpcPos
738   where
739    start = srcSpanStart pos
740    end   = srcSpanEnd pos
741    hpcPos = toHpcPos ( srcLocLine start
742                      , srcLocCol start
743                      , srcLocLine end
744                      , srcLocCol end - 1
745                      )
746
747 hpcSrcSpan :: SrcSpan
748 hpcSrcSpan = mkGeneralSrcSpan (fsLit "Haskell Program Coverage internals")
749 \end{code}
750
751
752 \begin{code}
753 matchesOneOfMany :: [LMatch Id] -> Bool
754 matchesOneOfMany lmatches = sum (map matchCount lmatches) > 1
755   where
756         matchCount (L _ (Match _pats _ty (GRHSs grhss _binds))) = length grhss
757 \end{code}
758
759
760 \begin{code}
761 type MixEntry_ = (SrcSpan, [String], [OccName], BoxLabel)
762
763 -- For the hash value, we hash everything: the file name, 
764 --  the timestamp of the original source file, the tab stop,
765 --  and the mix entries. We cheat, and hash the show'd string.
766 -- This hash only has to be hashed at Mix creation time,
767 -- and is for sanity checking only.
768
769 mixHash :: FilePath -> Integer -> Int -> [MixEntry] -> Int
770 mixHash file tm tabstop entries = fromIntegral $ hashString
771         (show $ Mix file tm 0 tabstop entries)
772 \end{code}