1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
51
52
53
54
55
56
57
58
59
60
61
62
63
64
65
66
67
68
69
70
71
72
73
74
75
76
77
78
79
80
81
82
83
84
85
86
87
88
89
90
91
92
93
94
95
96
97
98
99
100
101
102
103
104
105
106
107
108
109
110
111
112
113
114
115
116
117
118
119
120
121
122
123
124
125
126
127
128
129
130
131
132
133
134
135
136
137
138
139
140
141
142
143
|
module ImportUsage ( main, showImportCalls )
where
import Data.List ( intercalate, isPrefixOf, nub, sort, union )
import System.Directory ( doesFileExist, getModificationTime )
import System.FilePath ( (</>), takeFileName )
import System.Environment ( getArgs )
import FlatCurry.Types
import FlatCurry.Files
import System.CurryPath ( lookupModuleSourceInLoadPath, runModuleAction )
main :: IO ()
main = do
args <- getArgs
case args of
[prog] -> runModuleAction showAllImportedCalls prog
_ -> putStrLn $ "ERROR: Illegal arguments: " ++ unwords args ++ "\n" ++
"Usage: curry-usedimports <module_name>"
showAllImportedCalls :: String -> IO ()
showAllImportedCalls modname = do
prog <- readCurrentFlatCurry modname
putStrLn $ "Uses of imported types/functions/constructors in module '" ++
modname ++ "':\n"
putStrLn $ showImportCalls prog
showImportCalls :: Prog -> String
showImportCalls = formatImpCalls . getAllImpCalls
formatImpCalls :: [(String,[String])] -> String
formatImpCalls impcalls =
concatMap (\(mod,imps) -> "import " ++ mod ++ "(" ++
intercalate ", " (map showName imps) ++ ")\n")
impcalls
where
showName name = if isAlpha (head name) then name else '(':name++")"
getAllImpCalls :: Prog -> [(String,[String])]
getAllImpCalls (Prog mod imps tdecls funs _) =
groupByModules imps
(foldr union [] (map (allImpFTypes mod) funs ++
map (allImpDTypes mod) tdecls))
(foldr union [] (map (allFunCalls mod) funs))
groupByModules :: [String] -> [QName] -> [QName] -> [(String,[String])]
groupByModules mods typs funs = map callsFromModule mods
where
callsFromModule mod =
(mod,
sort (map snd (filter (\ (m,_) -> m==mod) typs)) ++
sort (map snd (filter (\ (m,_) -> m==mod) funs)))
allFunCalls :: String -> FuncDecl -> [QName]
allFunCalls mod (Func _ _ _ _ rl) =
case rl of Rule _ e -> globalFunsInExpr mod e
External _ -> []
globalFunsInExpr :: String -> Expr -> [QName]
globalFunsInExpr mod exp = funsInExpr exp
where
funsInExpr (Var _) = []
funsInExpr (Lit _) = []
funsInExpr (Comb _ (m,f) es) =
if m==mod || isSpecialName f ||
(m=="Prelude" && f `elem` ["commit","apply","cond"])
then nub (concatMap funsInExpr es)
else nub ((m,f) : concatMap funsInExpr es)
funsInExpr (Free _ e) = funsInExpr e
funsInExpr (Let bs e) = union (nub (concatMap (funsInExpr . snd) bs))
(funsInExpr e)
funsInExpr (Or e1 e2) = union (funsInExpr e1) (funsInExpr e2)
funsInExpr (Case _ e bs) = union (funsInExpr e)
(nub (concatMap funsInBranch bs))
where funsInBranch (Branch _ be) = funsInExpr be
funsInExpr (Typed e _) = funsInExpr e
allImpDTypes :: String -> TypeDecl -> [QName]
allImpDTypes mod (Type _ _ _ cdecls) = nub (concatMap consTypes cdecls)
where
consTypes (Cons _ _ _ texps) = nub (concatMap (importedTypes mod) texps)
allImpDTypes mod (TypeSyn _ _ _ texp) = importedTypes mod texp
allImpDTypes mod (TypeNew _ _ _ (NewCons _ _ texp)) = importedTypes mod texp
allImpFTypes :: String -> FuncDecl -> [QName]
allImpFTypes mod (Func (_,f) _ _ texp _) =
if isSpecialName f
then []
else importedTypes mod texp
importedTypes :: String -> TypeExpr -> [QName]
importedTypes _ (TVar _) = []
importedTypes mod (FuncType t1 t2) =
union (importedTypes mod t1) (importedTypes mod t2)
importedTypes mod (ForallType _ te) = importedTypes mod te
importedTypes mod (TCons tc tes) =
nub (itc tc ++ concatMap (importedTypes mod) tes)
where
itc (m,t) = if m == mod || isSpecialName t
then []
else [(m,t)]
isSpecialName :: String -> Bool
isSpecialName s = "_" `isPrefixOf` s || '#' `elem` s
readCurrentFlatCurry :: String -> IO Prog
readCurrentFlatCurry modname = do
mbdirfn <- lookupModuleSourceInLoadPath modname
let progname = maybe modname snd mbdirfn
fcyprogname = maybe "" (\(d,_) -> d </> flatCurryFileName modname) mbdirfn
fcyexists <- doesFileExist fcyprogname
if not fcyexists
then readFlatCurry modname
else do ctime <- getModificationTime progname
ftime <- getModificationTime fcyprogname
if ctime > ftime
then readFlatCurry modname
else readFlatCurryFile fcyprogname
|