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
200
201
202
203
|
{-# OPTIONS_FRONTEND -Wno-incomplete-patterns #-}
module Analysis.ProgInfo
( ProgInfo, emptyProgInfo, lookupProgInfo, combineProgInfo
, lists2ProgInfo, publicListFromProgInfo, progInfo2Lists
, mapProgInfo, publicProgInfo
, showProgInfo, equalProgInfo
, readAnalysisFiles, readAnalysisPublicFile, writeAnalysisFiles
) where
import Prelude hiding ( empty, lookup )
import Debug.Profile ( getElapsedTimeNF )
import Data.Map
import Data.Time ( compareClockTime )
import FlatCurry.Types
import RW.Base
import System.Directory ( doesFileExist, getModificationTime, removeFile )
import System.FilePath ( (<.>) )
import System.IO ( hPutChar )
import Analysis.Logging ( DLevel, debugMessage )
data ProgInfo a = ProgInfo (Map QName a) (Map QName a)
emptyProgInfo:: ProgInfo a
emptyProgInfo = ProgInfo empty empty
lookupProgInfo:: QName -> ProgInfo a -> Maybe a
lookupProgInfo key (ProgInfo map1 map2) =
case lookup key map1 of
Just x -> Just x
Nothing -> lookup key map2
combineProgInfo :: ProgInfo a -> ProgInfo a -> ProgInfo a
combineProgInfo (ProgInfo x1 x2) (ProgInfo y1 y2) =
ProgInfo (union x1 y1) (union x2 y2)
lists2ProgInfo :: ([(QName,a)],[(QName,a)]) -> ProgInfo a
lists2ProgInfo (xs,ys) = ProgInfo (fromList xs) (fromList ys)
publicListFromProgInfo:: ProgInfo a -> [(QName,a)]
publicListFromProgInfo (ProgInfo fm1 _) = toList fm1
progInfo2Lists :: ProgInfo a -> ([(QName,a)],[(QName,a)])
progInfo2Lists (ProgInfo map1 map2) = (toList map1, toList map2)
mapProgInfo:: (a -> b) -> ProgInfo a -> ProgInfo b
mapProgInfo func (ProgInfo map1 map2) =
ProgInfo (mapWithKey (\_ b->func b) map1) (mapWithKey (\_ b->func b) map2)
publicProgInfo :: ProgInfo a -> ProgInfo a
publicProgInfo (ProgInfo pub _) = ProgInfo pub empty
showProgInfo :: Show a => ProgInfo a -> String
showProgInfo (ProgInfo fm1 fm2) =
"Public: "++show fm1++"\nPrivate: "++show fm2
equalProgInfo :: Eq a => ProgInfo a -> ProgInfo a -> Bool
equalProgInfo (ProgInfo pi1p pi1v) (ProgInfo pi2p pi2v) =
pi1p == pi2p && pi1v == pi2v
writeAnalysisFiles :: (ReadWrite a, Show a) => DLevel -> String -> ProgInfo a
-> IO ()
writeAnalysisFiles dl basefname (ProgInfo pub priv) = do
debugMessage dl 3 $ "Writing analysis files '" ++ basefname ++ "'..."
writeTermFile dl (basefname <.> "priv") priv
writeTermFile dl (basefname <.> "pub" ) pub
readAnalysisFiles :: (Read a, ReadWrite a) => DLevel -> String
-> IO (ProgInfo a)
readAnalysisFiles dl basefname = do
debugMessage dl 3 $ "Reading analysis files '" ++ basefname ++ "'..."
let pubcontfile = basefname <.> "pub"
privcontfile = basefname <.> "priv"
pubinfo <- readTermFile (fromEnum dl > 2) pubcontfile
privinfo <- readTermFile (fromEnum dl > 2) privcontfile
let pinfo = ProgInfo pubinfo privinfo
catch (return $!! pinfo)
(\err -> do
putStrLn $ "Buggy analysis files detected and removed:\n" ++
basefname
mapM_ removeFile [pubcontfile,privcontfile]
putStrLn "Please try to re-run the analysis!"
ioError err)
readAnalysisPublicFile :: (Read a, ReadWrite a) => DLevel -> String
-> IO (ProgInfo a)
readAnalysisPublicFile dl fname = do
debugMessage dl 3 $ "Reading public analysis file '" ++ fname ++ "'..."
pubinfo <- readTermFile (fromEnum dl > 2) fname
let pinfo = ProgInfo pubinfo empty
catch (return $!! pinfo)
(\err -> do
putStrLn $ "Buggy analysis files detected and removed:\n" ++ fname
removeFile fname
putStrLn "Please try to re-run the analysis!"
ioError err)
writeTermFile :: (ReadWrite a, Show a) => DLevel -> String -> a -> IO ()
writeTermFile _ fname x = do
writeFile fname (show x)
writeDataFile (fname <.> "rw") x
readTermFile :: (ReadWrite a, Read a) => Bool -> String -> IO a
readTermFile reporttimings fname = do
let rwfile = fname <.> "rw"
readtermfile = fmap read (readFile fname)
rwex <- doesFileExist rwfile
if rwex
then do
ftime <- getModificationTime fname
rwftime <- getModificationTime rwfile
if compareClockTime rwftime ftime == LT
then readtermfile
else do
(mbterms,rwtime) <- getElapsedTimeNF (readDataFile rwfile)
maybe (error $ "Illegal data in file " ++ rwfile)
(\rwterms ->
if not reporttimings
then return rwterms
else do
putStrLn $ "\nReading " ++ fname
(_,ttime) <- getElapsedTimeNF readtermfile
putStr $ "Time: " ++ show ttime ++
" msecs / Compact reading: " ++
show rwtime ++ " msecs / speedup: " ++
show (fromInt ttime / fromInt rwtime)
return rwterms )
mbterms
else readtermfile
instance (ReadWrite a,ReadWrite b) => ReadWrite (Map a b) where
readRW _ ('0' : r0) = (Tip,r0)
readRW strs ('1' : r0) = (Bin a' b' c' d' e',r5)
where
(a',r1) = readRW strs r0
(b',r2) = readRW strs r1
(c',r3) = readRW strs r2
(d',r4) = readRW strs r3
(e',r5) = readRW strs r4
showRW _ strs0 Tip = (strs0,showChar '0')
showRW params strs0 (Bin a' b' c' d' e') =
(strs5,showChar '1' . (show1 . (show2 . (show3 . (show4 . show5)))))
where
(strs1,show1) = showRW params strs0 a'
(strs2,show2) = showRW params strs1 b'
(strs3,show3) = showRW params strs2 c'
(strs4,show4) = showRW params strs3 d'
(strs5,show5) = showRW params strs4 e'
writeRW _ h Tip strs = hPutChar h '0' >> return strs
writeRW params h (Bin a' b' c' d' e') strs =
hPutChar h '1'
>> ((((writeRW params h a' strs >>= writeRW params h b')
>>= writeRW params h c')
>>= writeRW params h d')
>>= writeRW params h e')
typeOf n = RWType "Map" [typeOf (get_a n),typeOf (get_b n)]
where
get_a :: Map a' b' -> a'
get_a _ = failed
get_b :: Map a' b' -> b'
get_b _ = failed
|