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
144
145
146
147
148
149
150
151
152
153
154
155
156
157
158
159
160
161
162
163
164
165
166
167
168
169
170
171
172
173
174
175
176
177
178
179
180
181
182
183
184
185
186
187
188
189
190
191
192
193
194
195
196
197
198
199
|
module Verify.Helpers where
import Data.Char ( isDigit )
import Data.IORef
import Data.List
import Analysis.ProgInfo
import Analysis.Types
import CASS.Server ( analyzeGeneric, analyzePublic )
import Data.Time ( ClockTime )
import FlatCurry.Goodies
import FlatCurry.Files ( flatCurryFileName )
import FlatCurry.Types
import RW.Base
import System.CurryPath ( lookupModuleSourceInLoadPath )
import System.Directory ( getModificationTime, doesFileExist )
import System.FilePath ( (</>) )
import FlatCurry.Build
import Verify.Options ( Options, printWhenStatus )
data AnalysisStore a = AnaStore [(String, ProgInfo a)]
loadAnalysisWithImports :: (Read a, Show a, ReadWrite a) =>
IORef (AnalysisStore a) -> Analysis a -> Options -> Prog -> IO (QName -> a)
loadAnalysisWithImports anastore analysis opts prog = do
maininfo <- getOrAnalyze (progName prog)
impinfos <- mapM getOrAnalyze (progImports prog)
return $ progInfo2Map $
foldr combineProgInfo maininfo (map publicProgInfo impinfos)
where
getOrAnalyze mname = do
AnaStore minfos <- readIORef anastore
maybe (do printWhenStatus opts $ "Getting " ++ analysisName analysis ++
" for '" ++ mname ++ "' via CASS..."
minfo <- fmap (either id error) $ analyzeGeneric analysis mname
writeIORef anastore (AnaStore ((mname,minfo) : minfos))
return minfo)
return
(lookup mname minfos)
progInfo2Map :: ProgInfo a -> (QName -> a)
progInfo2Map proginfo qf =
maybe (error $ "Analysis information of '" ++ snd qf ++ "'' not found!")
id
(lookupProgInfo qf proginfo)
sortFunResults :: [(QName,a)] -> [(QName,a)]
sortFunResults = sortBy (\ct1 ct2 -> fst ct1 <= fst ct2)
showFunResults :: (a -> String) -> [(QName,a)] -> [String]
showFunResults showf = map (\ (qf,r) -> snd qf ++ ": " ++ showf r)
getModuleModTime :: String -> IO ClockTime
getModuleModTime mname =
lookupModuleSourceInLoadPath mname >>=
maybe (error $ "Source file of module '" ++ mname ++ "' not found!")
(\(dir,fn) -> do
mtime <- getModificationTime fn
let fcyfile = dir </> flatCurryFileName mname
exfcy <- doesFileExist fcyfile
if exfcy then do fcytime <- getModificationTime fcyfile
return (if mtime < fcytime then fcytime else mtime)
else return mtime)
patternArgs :: Pattern -> [Int]
patternArgs (Pattern _ vs) = vs
patternArgs (LPattern _) = []
allConsOfTypes :: [TypeDecl] -> [[(QName,Int)]]
allConsOfTypes tdecls = filter (not . null) (map toConss tdecls)
where
toConss (Type _ _ _ cdecls) = map (\ (Cons qc ar _ _) -> (qc,ar)) cdecls
toConss (TypeSyn _ _ _ _) = []
toConss (TypeNew _ _ _ (NewCons qc _ _)) = [(qc,1)]
readQC :: String -> QName
readQC = readMQC []
where
readMQC ms s = let (s1,s2) = break (=='.') s
in case s2 of
"" -> (toMod ms, s1)
[_] -> (toMod ms, "")
_:c:cs -> if isAlpha c && '.' `elem` cs
then readMQC (ms ++ [s1]) (c:cs)
else (toMod (ms ++ [s1]), c:cs)
toMod = intercalate "."
unknownType :: TypeExpr
unknownType = TCons (pre "UNKNOWN") []
funcsInExpr :: Expr -> [QName]
funcsInExpr e =
trExpr (const id) (const id) comb lt fr (.) cas branch const e []
where
comb ct qn = foldr (.) (combtype ct qn)
combtype ct qn = case ct of FuncCall -> (qn:)
FuncPartCall _ -> (qn:)
_ -> id
lt bs exp = exp . foldr (.) id (map (\ (_,ns) -> ns) bs)
fr _ exp = exp
cas _ exp bs = exp . foldr (.) id bs
branch _ exp = exp
funcType2TypedVars :: [Int] -> TypeExpr -> [(Int,TypeExpr)]
funcType2TypedVars [] _ = []
funcType2TypedVars (v:vs) ftype = case ftype of
FuncType t1 t2 -> (v,t1) : funcType2TypedVars vs t2
ForallType _ t -> funcType2TypedVars (v:vs) t
_ -> error "Illegal function type in funcType2TypedVars"
type Pos = [Int]
freshVarPos :: Pos
freshVarPos = []
isFreshVarPos :: Pos -> Bool
isFreshVarPos = null
stdConstructors :: [[QName]]
stdConstructors =
[ [pre "False", pre "True"]
, [pre "[]", pre ":"]
, [pre "Nothing", pre "Just"]
, [pre "Left", pre "Right"]
, [pre "LT", pre "EQ", pre "GT"]
, [pre "IOError", pre "UserError", pre "FailError", pre "NondetError"]
] ++
map (\n -> [pre $ "(" ++ take n (repeat ',') ++ ")"]) [0 .. 8]
isEncSearchOp :: QName -> Bool
isEncSearchOp qf@(mn,_) =
mn `elem` ["Control.Search.Unsafe", "Control.Search.AllValues"] ||
qf `elem` map (\n -> ("Control.AllValues",n))
["allValues", "oneValue", "isFail"]
isSetFunOp :: QName -> Bool
isSetFunOp (mn,fn) =
(mn == "Control.Search.SetFunctions" || mn == "Control.SetFunctions") &&
take 3 fn == "set" &&
all isDigit (drop 3 fn)
isCurryID :: QName -> Bool
isCurryID (_,n) = case n of
[] -> False
x:xs | isAlpha x -> all (\c -> isAlphaNum c || c `elem` "'_") xs
| otherwise -> all (flip elem opChars) n
where
opChars = "~!@#$%^&*+-=<>?./|\\:"
fst3 :: (a,b,c) -> a
fst3 (x,_,_) = x
snd3 :: (a,b,c) -> b
snd3 (_,y,_) = y
trd3 :: (a,b,c) -> c
trd3 (_,_,z) = z
|