1
module Language.Haskell.Extract (
6
import Language.Haskell.TH
7
import Language.Haskell.Exts.Parser
8
import Language.Haskell.Exts (parseFileContentsWithMode)
9
import Language.Haskell.Exts.Syntax
10
import Text.Regex.Posix
13
import Language.Haskell.Exts.Extension
15
extractAllFunctions :: String -> String-> [String]
16
extractAllFunctions pattern file =
17
-- allMatchingFunctions pattern . parsedModule
18
nub $ filter (\f->f=~pattern::Bool) $ map (fst . head . lex) $ lines file
20
-- nub $ filter ("prop_" `isPrefixOf`) $
21
-- map (fst . head . lex) $ lines ct
24
parsedModule moduleCode =
25
let pMod = parseFileContentsWithMode (defaultParseMode { extensions = knownExtensions } ) moduleCode
26
moduleOrDefault (ParseFailed _ _) = Module (SrcLoc "unknown" 1 1) (ModuleName "unknown") [] Nothing Nothing [] []
27
moduleOrDefault (ParseOk m) = m
28
in moduleOrDefault pMod
30
allFunctions = onlyJust extractNameOfFunctionFromDecl . hsModuleDecls
31
allMatchingFunctions pattern = filter (\f->f=~pattern::Bool) . allFunctions
35
extractNameOfFunctionFromDecl :: Decl -> Maybe String
36
extractNameOfFunctionFromDecl (PatBind _ (PVar (Ident n)) _ _ _ ) = Just n
37
extractNameOfFunctionFromDecl (FunBind ms) = Just $ head $ [n | (Language.Haskell.Exts.Syntax.Match _ (Ident n) _ _ _ _) <- ms]
38
extractNameOfFunctionFromDecl _ = Nothing
40
onlyJust f = map fromJust . filter isJust . map f
42
hsModuleDecls (Module _ _ _ _ _ _ d) = d
44
-- | Extract the names and functions from the module where this function is called.
48
-- > bar = $(functionExtractor "oo$")
50
-- will automagically extract the functions ending with "oo" such as
52
-- > bar = [("foo",foo), ("boo",boo)]
53
functionExtractor :: String -> ExpQ
54
functionExtractor pattern =
56
moduleCode <- runIO $ readFile $ loc_filename loc
57
let functions = extractAllFunctions pattern moduleCode
58
makePair n = TupE [ LitE $ StringL n , VarE $ mkName n]
59
return $ ListE $ map makePair functions
62
-- functionExtractor' :: String -> Q [String]
63
-- functionExtractor' pattern =
65
-- moduleCode <- runIO $ readFile $ loc_filename loc
66
-- let functions = extractAllFunctions pattern moduleCode
69
-- | Extract the names and functions from the module and apply a function to every pair.
71
-- Is very useful if the common denominator of the functions is just a type class.
73
-- > secondTypeclassTest =
74
-- > do let expected = ["45", "88.8", "\"hej\""]
75
-- > actual = $(functionExtractorMap "^tc" [|\n f -> show f|] )
76
-- > expected @=? actual
81
-- > tcDouble :: Double
84
-- > tcString :: String
86
functionExtractorMap :: String -> ExpQ -> ExpQ
87
functionExtractorMap pattern funcName =
89
moduleCode <- runIO $ readFile $ loc_filename loc
90
let functions :: [String]
91
functions = extractAllFunctions pattern moduleCode
93
let makePair n = AppE (AppE (fn) (LitE $ StringL n)) (VarE $ mkName n)
94
return $ ListE $ map makePair functions
96
-- functionExtractorExpMap :: String -> (Exp -> ExpQ) -> ExpQ
97
-- functionExtractorExpMap pattern func =
99
-- moduleCode <- runIO $ readFile $ loc_filename loc
100
-- let functions :: [String]
101
-- functions = extractAllFunctions pattern moduleCode
103
-- let makePair n = AppE (AppE (fn) (LitE $ StringL n)) (VarE $ mkName n)
104
-- return $ ListE $ map makePair functions
106
-- | Extract the name of the current module.
107
locationModule :: ExpQ
110
return $ LitE $ StringL $ loc_module loc