module Debug.Hoed.TH (debug, obs) where
import Control.Monad
import Data.Generics.Uniplate.Data
import Data.List (group, nub, sort, (\\))
import Data.Text (pack)
import Debug.Hoed
import Debug.Hoed
import Debug.Hoed.Compat
import Language.Haskell.TH
import Language.Haskell.TH.Syntax
obs :: Q [Dec] -> Q [Dec]
obs decs = do
decs <- decs
names <- sequence [ (n,) <$> newName(nameBase n ++ "Obs") | FunD n _ <- decs]
fmap concat $ forM decs $ \dec ->
case dec of
FunD n xx -> do
let Just n' = lookup n names
nb = nameBase n
newDecl <- funD n [clause [] (normalB [| observe (pack nb) $(varE n')|]) []]
return [newDecl, FunD n' xx]
SigD n ty | Just n' <- lookup n names -> do
dec' <- adjustSig n ty
return [dec']
_ ->
return [dec]
debug :: Q [Dec] -> Q [Dec]
debug q = do
decs <- q
names <- sequence [ (n,) <$> newName(nameBase n ++ "Debug") | FunD n _ <- decs]
fmap concat $ forM decs $ \dec ->
case dec of
FunD n clauses -> do
let Just n' = lookup n names
nb = nameBase n
newDecl <- funD n [clause [] (normalB [| observe (pack nb) $(varE n')|]) []]
let clauses' = transformBi adjustValD clauses
return [newDecl, FunD n' clauses']
SigD n ty | Just n' <- lookup n names -> do
dec' <- adjustSig n ty
return [dec']
_ ->
return [dec]
nubOrd :: Ord a => [a] -> [a]
nubOrd = map head . group . sort
kindStar :: Type -> Q [Name]
kindStar t = return $
nubOrd [x | VarT x <- universe t] \\
nubOrd [x | AppT (VarT x) _ <- universe t]
adjustSig name (ForallT vars ctxt typ) = do
vs <- kindStar typ
return $
SigD name $
ForallT vars (nub $ map (addConstraint ''Observable . (:[]) . VarT) vs ++ ctxt) typ
adjustSig name other = adjustSig name $ ForallT [] [] other
adjustValD decl@ValD{} = transformBi adjustPat decl
adjustValD other = other
adjustPat (VarP x) = ViewP (VarE 'observe `AppE` (VarE 'pack `AppE` toLit x)) (VarP x)
adjustPat x = x
toLit (Name (OccName x) _) = LitE $ StringL x