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
204
205
206
207
208
209
210
211
212
213
214
215
216
217
218
219
220
221
222
223
224
225
226
227
228
229
230
231
232
233
234
235
236
237
238
239
240
241
242
243
244
245
246
247
248
249
250
251
252
253
254
255
256
257
258
259
260
261
262
263
264
265
266
267
268
269
270
271
272
273
274
275
276
277
278
279
280
281
282
283
284
285
286
287
288
289
290
291
292
293
294
295
296
297
298
299
300
301
302
303
304
305
306
307
308
309
310
311
312
313
314
315
316
317
318
319
320
321
322
323
324
325
326
327
328
329
330
331
332
333
334
335
336
337
338
339
340
341
342
343
344
345
346
347
348
349
350
351
352
353
354
355
356
357
358
359
360
361
362
363
364
365
366
367
368
369
370
371
372
373
374
375
376
377
378
379
380
381
382
383
384
385
386
387
388
389
390
391
392
393
394
395
396
397
398
399
400
401
402
403
404
405
406
407
408
409
410
411
412
|
module CPP.DefaultRules ( translateDefaultRulesAndDetOps )
where
import Distribution ( curryCompiler )
import FilePath ( takeDirectory )
import List ( partition )
import AbstractCurry.Types
import AbstractCurry.Files
import AbstractCurry.Select
import AbstractCurry.Build
import AbstractCurry.Pretty
import DefaultRuleUsage
import System.CurryPath ( modNameToPath )
import TheoremUsage ( determinismTheoremFor, existsProofFor
, getModuleProofFiles, isProofFileNameFor )
import CPP.CompileWithFrontend ( compileImportedModule )
banner :: String
banner = unlines [bannerLine,bannerText,bannerLine]
where
bannerText =
"Transformation Tool for Curry with Default Rules (Version of 11/10/19)"
bannerLine = take (length bannerText) (repeat '=')
data TransScheme = SpecScheme
| NoDupScheme
deriving (Eq,Show)
defaultTransScheme :: TransScheme
defaultTransScheme = if curryCompiler == "kics2"
then SpecScheme
else SpecScheme
translateDefaultRulesAndDetOps :: Int -> [String] -> String -> CurryProg
-> IO (Maybe CurryProg)
translateDefaultRulesAndDetOps verb moreopts _ prog = do
when (verb>1) $ putStr banner
trscm <- processOpts moreopts
when (verb>1) $ putStrLn ("Translation scheme: " ++ show trscm)
mbtransprog <- translateProg verb trscm prog
maybe (return Nothing)
(\ (detfuncnames,newprog) -> do
let mname = progName prog
prfiles <- getModuleProofFiles (takeDirectory (modNameToPath mname)) mname
detfuncnamesWOproofs <- filterProofObligation verb prfiles detfuncnames
when (verb>0) $ printProofObligation detfuncnamesWOproofs
return (Just newprog))
mbtransprog
where
processOpts opts = case opts of
[] -> return defaultTransScheme
[scheme] ->
if scheme == "nodupscheme"
then if curryCompiler == "kics2"
then return SpecScheme
else return NoDupScheme
else if scheme == "specscheme"
then return SpecScheme
else showError
_ -> showError
where
showError = do
putStrLn $ "Unknown options (ignored): " ++ unwords opts
return defaultTransScheme
filterProofObligation :: Int -> [String] -> [QName] -> IO [QName]
filterProofObligation _ _ [] = return []
filterProofObligation verb prooffiles (qf@(mn,fn) : qfs) = do
let dettheoname = (mn, determinismTheoremFor fn)
hasdetproof = existsProofFor dettheoname prooffiles
when (hasdetproof && verb>0) $ putStrLn $
"Proofs for determinism property of " ++ showQName qf ++ " found:\n" ++
unlines (filter (isProofFileNameFor dettheoname) prooffiles)
filterqfs <- filterProofObligation verb prooffiles qfs
return (if hasdetproof then filterqfs else qf : filterqfs)
printProofObligation :: [QName] -> IO ()
printProofObligation qfs = unless (null qfs) $ do
putStrLn line
putStrLn "PROOF OBLIGATIONS:"
mapIO_ (\qn -> putStrLn $ showQName qn ++" is a deterministic operation.") qfs
putStrLn line
where
line = take 70 (repeat '=')
showQName :: QName -> String
showQName (qn,fn) = "'" ++ qn ++ "." ++ fn ++ "'"
translateProg :: Int -> TransScheme -> CurryProg
-> IO (Maybe ([QName],CurryProg))
translateProg verb trscm
prog@(CurryProg mn imps dfltdecl clsdecls instdecls tdecls fdecls ops) = do
let usageerrors = checkDefaultRules prog
unless (null usageerrors) $ do
putStr (unlines $ "ERROR: ILLEGAL USE OF DEFAULT RULES:" :
map (\ ((_,fn),err) -> fn ++ " (module " ++ mn ++ "): " ++ err)
usageerrors)
error "Transformation aborted"
unless (setFunMod `elem` imps) $
compileImportedModule verb setFunMod
return $ if null deffuncs && null detfuncnames
then Nothing
else Just (detfuncnames,
CurryProg mn newimports dfltdecl clsdecls
instdecls tdecls newfdecls ops)
where
newimports = if setFunMod `elem` imps then imps else setFunMod:imps
detfuncnames = map funcName (filter isDetFun fdecls)
undetfuncs = concatMap (transDetFun detfuncnames) fdecls
(deffuncs,funcs) = partition isDefaultFunc undetfuncs
defrules = map func2rule deffuncs
newfdecls = concatMap (transFDecl trscm defrules) funcs
isDetFun :: CFuncDecl -> Bool
isDetFun (CmtFunc _ qf ar vis texp rules) =
isDetFun (CFunc qf ar vis texp rules)
isDetFun (CFunc _ _ _ (CQualType _ texp) _) = hasDetResultType texp
where
hasDetResultType (CTVar _) = False
hasDetResultType (CTCons _) = False
hasDetResultType (CFuncType _ rt) = hasDetResultType rt
hasDetResultType (CTApply tc _) = tc == CTCons (pre "DET")
transDetFun :: [QName] -> CFuncDecl -> [CFuncDecl]
transDetFun detfnames (CmtFunc _ qf ar vis texp rules) =
transDetFun detfnames (CFunc qf ar vis texp rules)
transDetFun detfnames fdecl@(CFunc qf@(mn,fn) ar vis texp rules)
| qf `elem` detfnames
= [CFunc qf ar vis (removeDetResultType texp) [newdetrule],
CFunc neworgname ar Private (removeDetResultType texp) rules]
| isDefaultFunc fdecl && (mn, fromDefaultName fn) `elem` detfnames
= [CFunc (mn, fromDefaultName fn ++ orgsuffix ++ "'default") ar vis texp rules]
| otherwise = [fdecl]
where
neworgname = (mn,fn++orgsuffix)
orgsuffix = "_ORGNDFUN"
newdetrule =
CRule (map CPVar argvars)
(CSimpleRhs (applyF (setFunMod, "selectValue")
[applyF (setFunMod, "set"++show ar)
(CSymbol neworgname : map CVar argvars)])
[])
argvars = map (\i->(i,"x"++show i)) [1..ar]
removeDetResultType :: CQualTypeExpr -> CQualTypeExpr
removeDetResultType (CQualType clsctxt te) = CQualType clsctxt (removeDet te)
where
removeDet tv@(CTVar _) = tv
removeDet tc@(CTCons _) = tc
removeDet (CFuncType t1 t2) = CFuncType t1 (removeDet t2)
removeDet t@(CTApply tc ta) = if tc == CTCons (pre "DET") then ta else t
func2rule :: CFuncDecl -> (QName,(Int,CRule))
func2rule (CFunc (mn,fn) ar _ _ rules) =
((mn, fromDefaultName fn), (ar, head rules))
func2rule (CmtFunc _ qf ar vis texp rules) =
func2rule (CFunc qf ar vis texp rules)
transFDecl :: TransScheme -> [(QName,(Int,CRule))] -> CFuncDecl -> [CFuncDecl]
transFDecl trscm defrules (CmtFunc _ qf ar vis texp rules) =
transFDecl trscm defrules (CFunc qf ar vis texp rules)
transFDecl trscm defrules fdecl@(CFunc qf@(mn,fn) ar vis texp rules) =
maybe [fdecl]
(\ (_,defrule) ->
if trscm == SpecScheme
then [CFunc neworgname ar Private texp rules,
transFDecl2ApplyCond applyname fdecl,
CFunc deffunname ar Private texp
[transDefaultRule applyname ar defrule],
CFunc qf ar vis texp [neworgrule_SpecScheme]]
else
[transFDecl2FunRHS applyname fdecl,
CFunc deffunname ar Private texp [defrule],
CFunc qf ar vis texp [neworgrule_NoDupScheme]]
)
(lookup qf defrules)
where
neworgname = (mn,fn++"_ORGRULES")
applyname = (mn,fn++"_APPLICABLE")
deffunname = (mn,fn++"_DEFAULT")
neworgrule_SpecScheme =
CRule (map CPVar argvars)
(CSimpleRhs (applyF (pre "?")
[applyF neworgname (map CVar argvars),
applyF deffunname (map CVar argvars)])
[])
neworgrule_NoDupScheme =
CRule (map CPVar argvars)
(CSimpleRhs
(CLetDecl [CLocalPat (CPVar (0,"x0"))
(CSimpleRhs
(applyF (setFunMod,"set"++show ar)
(CSymbol applyname : map CVar argvars))
[])]
(applyF (pre "if_then_else")
[applyF (setFunMod,"isEmpty") [CVar (0,"x0")],
applyF deffunname (map CVar argvars),
applyF (setFunMod,"chooseValue")
[CVar (0,"x0"), preUnit]]))
[])
argvars = map (\i->(i,"x"++show i)) [1..ar]
transFDecl2ApplyCond :: QName -> CFuncDecl -> CFuncDecl
transFDecl2ApplyCond nqf (CmtFunc _ qf ar vis texp rules) =
transFDecl2ApplyCond nqf (CFunc qf ar vis texp rules)
transFDecl2ApplyCond nqf (CFunc _ ar _ texp rules) =
CFunc nqf ar Private (adjustResultTypeToUnit texp) (map rule2cond rules)
where
rule2cond (CRule rpats (CSimpleRhs _ rlocals)) =
let singlepatvars = extractSingles (concatMap varsOfPat rpats ++
concatMap varsOfLDecl rlocals)
in CRule (map (anonymPat singlepatvars) rpats)
(CSimpleRhs preUnit rlocals)
rule2cond (CRule rpats (CGuardedRhs gds rlocals)) =
let singlepatvars = extractSingles (concatMap varsOfPat rpats ++
concatMap (varsOfExp . fst) gds ++
concatMap varsOfLDecl rlocals)
in CRule (map (anonymPat singlepatvars) rpats)
(CGuardedRhs (map (\gd -> (fst gd,preUnit)) gds) rlocals)
adjustResultTypeToUnit :: CQualTypeExpr -> CQualTypeExpr
adjustResultTypeToUnit (CQualType clsctxt te) =
CQualType clsctxt (adjustRType te)
where
adjustRType texp =
if texp == preUntyped
then texp
else case texp of
CFuncType te1 te2 -> CFuncType te1 (adjustRType te2)
_ -> unitType
transFDecl2FunRHS :: QName -> CFuncDecl -> CFuncDecl
transFDecl2FunRHS nqf (CmtFunc _ qf ar vis texp rules) =
transFDecl2FunRHS nqf (CFunc qf ar vis texp rules)
transFDecl2FunRHS nqf (CFunc _ ar _ texp rules) =
CFunc nqf ar Private (adjustResultTypeToFunRHS texp) (map rule2funrhs rules)
where
rule2funrhs (CRule rpats (CSimpleRhs rhsexp rlocals)) =
CRule rpats
(CSimpleRhs (CLambda [CPVar (999,"_")] rhsexp) rlocals)
rule2funrhs (CRule rpats (CGuardedRhs gds rlocals)) =
CRule rpats
(CGuardedRhs
(map (\ (gd,rhs) -> (gd,(CLambda [CPVar (999,"_")] rhs))) gds)
rlocals)
adjustResultTypeToFunRHS :: CQualTypeExpr -> CQualTypeExpr
adjustResultTypeToFunRHS (CQualType clsctxt te) =
CQualType clsctxt (adjustRType te)
where
adjustRType texp =
if texp == preUntyped
then texp
else case texp of
CFuncType te1 te2 -> CFuncType te1 (adjustRType te2)
_ -> CFuncType unitType texp
transDefaultRule :: QName -> Int -> CRule -> CRule
transDefaultRule _ _ (CRule _ (CGuardedRhs _ _)) =
error "Cannot yet transform guarded default rules!"
transDefaultRule condfunname ar (CRule pats (CSimpleRhs exp locals)) =
CRule newpats (CGuardedRhs [(checkCond,exp)] locals)
where
checkCond = applyF (setFunMod,"isEmpty")
[applyF (setFunMod,"set"++show ar)
(CSymbol condfunname : args)]
(newpats,args) = unzip (map arg2patexp (zip [1001..] pats))
arg2patexp (i,pat) = case pat of
CPVar v -> if snd v=="_"
then let newvar = (i,"patvar_"++show i)
in (CPVar newvar, CVar newvar)
else (pat, CVar v)
CPAs asv _ -> (pat, CVar asv)
_ -> let newvar = (i,"patvar_"++show i)
in (CPAs newvar pat, CVar newvar)
preUnit :: CExpr
preUnit = CSymbol (pre "()")
preUntyped :: CTypeExpr
preUntyped = CTCons (pre "untyped")
setFunMod :: String
setFunMod = "Control.SetFunctions"
extractSingles :: Eq a => [a] -> [a]
[] = []
extractSingles (x:xs) =
if null (filter (==x) xs)
then x : extractSingles xs
else extractSingles (filter (/=x) xs)
anonymPat :: [(Int,String)] -> CPattern -> CPattern
anonymPat vs (CPVar v) = CPVar (if v `elem` vs then (fst v,"_") else v)
anonymPat _ (CPLit l) = CPLit l
anonymPat vs (CPComb qc pats) = CPComb qc (map (anonymPat vs) pats)
anonymPat vs (CPAs v pat) =
if v `elem` vs then anonymPat vs pat
else CPAs v (anonymPat vs pat)
anonymPat vs (CPFuncComb qf pats) = CPFuncComb qf (map (anonymPat vs) pats)
anonymPat vs (CPLazy pat) = CPLazy (anonymPat vs pat)
anonymPat vs (CPRecord qc recpats) =
CPRecord qc (map (\ (n,p) -> (n, anonymPat vs p)) recpats)
|