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
|
module FCY2SMTLib where
import Char (toLower)
import Data.FiniteMap
import FlatCurry.Annotated.Goodies (argTypes, resultType)
import FlatCurry.Annotated.Pretty (ppQName, ppTypeExp, ppVarIndex)
import FlatCurry.Annotated.Types
import List (isPrefixOf)
import Text.Pretty hiding (compose)
import Bimap
import FCYFunctorInstances
import FlatCurryGoodies
import Language.SMTLIB.Goodies
import Language.SMTLIB.Pretty
import qualified Language.SMTLIB.Types as SMT
import Substitution
import Symbolic ( CoveredCs (..), LConstr (..)
, PathConstr, SymObj (..)
, prelSymCons)
import Utils ((<$>), mapFst, ppFM)
type ConsMap = BM SymObj SMT.Ident
type TypeMap = BM QName SMT.Ident
type TypeEnv = FM VarIndex TypeInfo
data TypeInfo = TypeInfo
{ fcType :: TypeExpr
, smtSort :: SMT.Sort
, args :: [VarIndex]
}
deriving Show
instance Pretty TypeInfo where
pretty (TypeInfo ty s args) =
braces (ppTypeExp ty <+> pretty s <+> list (map ppVarIndex args))
updTypeEnv :: [VarIndex] -> TypeExpr -> [VarIndex] -> SMTTrans ()
updTypeEnv vs cty args = do
cty' <- rnmTVars cty
sub <- foldM mbAdd emptySubst $ zip3 vs (resArgTypes cty') (args : repeat [])
modify $ \s -> s { smtVars = mapFM (specTypes s sub) (smtVars s) }
where
mbAdd sub (v, ty, as) = do
s <- get
if hasTypeInfo v s
then do
let sub' = sub `compose` (unify [(ty, getFCYType v s)])
ty' = subst sub' ty
put s { smtVars = updFM (smtVars s) v (\_ -> typeInfo s ty' as) }
return $ sub'
else do
put s { smtVars = addToFM (smtVars s) v (typeInfo s ty as) }
return sub
hasTypeInfo :: VarIndex -> SMTInfo -> Bool
hasTypeInfo v smtInfo = elemFM v (smtVars smtInfo)
specTypes :: SMTInfo -> TypeSubst -> VarIndex -> TypeInfo -> TypeInfo
specTypes smtInfo sub _ ti@(TypeInfo ty _ args)
| ty == ty' = ti
| otherwise = typeInfo smtInfo ty' args
where ty' = subst sub ty
typeInfo :: SMTInfo -> TypeExpr -> [VarIndex] -> TypeInfo
typeInfo smtInfo ty args = TypeInfo ty (toSort smtInfo ty) args
rnmTVars :: TypeExpr -> SMTTrans TypeExpr
rnmTVars ty = do
let is = getTyVars ty
tes <- map TVar <$> freshTVars (length is)
return (subst (mkSubst is tes) ty)
freshTVars :: Int -> SMTTrans [TVarIndex]
freshTVars n = do
s <- get
let v = smtTVar s
put s { smtTVar = v + n }
return [v .. n-1]
declConst :: VarIndex -> TypeInfo -> SMT.Command
declConst vi (TypeInfo _ s _) = SMT.DeclareConst (var2SMT vi) s
declConsts :: SMTInfo -> [VarIndex] -> [SMT.Command]
declConsts smtInfo vs = map (uncurry declConst) $ fmToList
$ filterFM (\v _ -> v `elem` vs) (smtVars smtInfo)
assertConstr :: SMTInfo -> [PathConstr] -> CoveredCs -> VarIndex -> VarIndex
-> SMT.Command
assertConstr smtInfo pcs cc dv vi = assert $ map (pc2SMT smtInfo) pcs ++ npc
where
npc = case cc of
CConstr lc l -> [tnot $ pc2SMT smtInfo (dv, SymLit lc l, [])]
CCons cs -> snd $ foldr diffThan (vi, []) cs
where
diffThan :: (SymObj, [VarIndex]) -> (VarIndex, [SMT.Term]) -> (VarIndex, [SMT.Term])
diffThan (sobj, args) (i, ineqs) =
let ss = map (getSMTSort smtInfo) args
vn = i - length ss
vs = [i, i - 1 .. vn + 1]
in (vn, forAll vs ss (tvar dv /=% qtcomb (cons2SMT smtInfo sobj dv)
(map tvar vs)) : ineqs)
pc2SMT :: SMTInfo -> PathConstr -> SMT.Term
pc2SMT smtInfo pc = case pc of
(v, tqn@(SymCons _ _), args) -> tvar v =% qtcomb (cons2SMT smtInfo tqn v)
(map tvar args)
(v, SymLit lc l , _) -> (lc2SMT lc) (tvar v) (lit2SMT l)
data SMTInfo = SMTInfo
{ smtDecls :: [SMT.Command]
, smtVars :: TypeEnv
, smtTMap :: TypeMap
, smtCMap :: ConsMap
, smtTVar :: TVarIndex
}
initSMTInfo :: SMTInfo
initSMTInfo = SMTInfo
{ smtDecls = []
, smtVars = emptyFM (<)
, smtTMap = predefTypes
, smtCMap = predefCons
, smtTVar = 0
}
instance Pretty SMTInfo where
pretty (SMTInfo ds vmap tmap cmap tidx) = vsepBlank
[ text "Generated SMTLib datatype declarations"
, vsep (map pretty ds)
, text "Var Map: Mapping SMT variables to FlatCurry types and SMTLib sorts"
, ppFM (\(k, v) -> ppVarIndex k <+> text "\10230" <+> pretty v) vmap
, text "Type Map: Mapping FlatCurry types to SMT sorts"
, ppBM (\(k, v) -> ppQName k <+> text "\10231" <+> text v) tmap
, text "Constructor Map: Mapping FlatCurry constructors to SMT constructors"
, ppBM (\(k, v) -> pretty k <+> text "\10231" <+> text v) cmap
, int tidx
]
data SMTTrans a = SMTTrans { runSMTTrans :: SMTInfo -> (a, SMTInfo) }
instance Monad SMTTrans where
return x = SMTTrans $ \s -> (x, s)
f >>= g = SMTTrans $ \s -> let (x, s') = runSMTTrans f s
in (runSMTTrans (g x)) s'
get :: SMTTrans SMTInfo
get = SMTTrans $ \s -> (s, s)
put :: SMTInfo -> SMTTrans ()
put s = SMTTrans $ \_ -> ((), s)
modify :: (SMTInfo -> SMTInfo) -> SMTTrans ()
modify f = SMTTrans $ \s -> ((), f s)
execSMTTrans :: SMTTrans a -> SMTInfo -> SMTInfo
execSMTTrans act smtInfo = snd $ runSMTTrans act smtInfo
addSMTDecl :: SMT.Command -> SMTTrans ()
addSMTDecl d = modify (\s -> s { smtDecls = d : smtDecls s })
lookupSMTCons :: SymObj -> SMTInfo -> Maybe SMT.Ident
lookupSMTCons tqn smtInfo = lookupBM tqn (smtCMap smtInfo)
lookupFCYCons :: SMT.Ident -> SMTInfo -> Maybe SymObj
lookupFCYCons i smtInfo = lookupBMR i (smtCMap smtInfo)
lookupType :: QName -> SMTInfo -> Maybe SMT.Ident
lookupType qn smtInfo = lookupBM qn (smtTMap smtInfo)
getFCYType :: VarIndex -> SMTInfo -> TypeExpr
getFCYType vi smtInfo = case lookupFM (smtVars smtInfo) vi of
Nothing -> error $ "FCY2SMT.getFCYType: unbound variable " ++ show vi
Just ti -> fcType ti
getSMTSort :: SMTInfo -> VarIndex -> SMT.Sort
getSMTSort smtInfo vi = case lookupFM (smtVars smtInfo) vi of
Nothing -> error $ "FCY2SMT.getSMTSort: unbound variable " ++ show vi
Just ti -> smtSort ti
getArgs :: VarIndex -> SMTInfo -> [VarIndex]
getArgs vi smtInfo = case lookupFM (smtVars smtInfo) vi of
Nothing -> []
Just ti -> args ti
newSMTSort :: QName -> SMTTrans SMT.Symbol
newSMTSort qn@(_, tc) = do
smtInfo <- get
case lookupType qn smtInfo of
Nothing -> do put smtInfo { smtTMap = addToBM qn tc (smtTMap smtInfo) }
return tc
Just tc' -> return tc'
newSMTCons :: SymObj -> SMTTrans ()
newSMTCons tqn@(SymCons qn _) = modify $
\smtInfo -> case lookupSMTCons tqn smtInfo of
Nothing ->
smtInfo { smtCMap = addToBM tqn (map toLower (snd qn)) (smtCMap smtInfo) }
Just _ -> smtInfo
newSMTCons (SymLit _ _) = return ()
fcy2SMT :: [TypeDecl] -> SMTInfo
fcy2SMT ts = execSMTTrans (mapM tdecl2SMT ts) initSMTInfo
tdecl2SMT :: TypeDecl -> SMTTrans ()
tdecl2SMT td = case td of
Type qn@(_, t) _ tvs cs
| not $ any (`isPrefixOf` t) ignoredTypes -> do
s <- newSMTSort qn
cs' <- mapM (cdecl2SMT (TCons qn (map TVar tvs))) cs
addSMTDecl $
SMT.DeclareDatatypes [(SMT.SortDecl s (length tvs), newDT tvs cs')]
_ -> return ()
newDT :: [TVarIndex] -> [SMT.ConsDecl] -> SMT.DTDecl
newDT tvars cs
| null tvars = SMT.MT cs
| otherwise = SMT.PT (map (typeVars !!) tvars) cs
cdecl2SMT :: TypeExpr -> ConsDecl -> SMTTrans SMT.ConsDecl
cdecl2SMT rty (Cons qn@(_, c) _ _ tys) = do
let tqn = SymCons qn (mkFunType tys rty)
newSMTCons tqn
tys' <- mapM ty2SMT tys
let c' = lookupWithDefaultBM (map toLower c) tqn predefCons
return $ SMT.Cons c' (zipWith SMT.SV (map (\n -> c' ++ '_' : show n) [1..]) tys')
ty2SMT :: TypeExpr -> SMTTrans SMT.Sort
ty2SMT (ForallType _ _) = error "FCY2SMT.ty2SMT: ForallType"
ty2SMT (TVar v) = return $ SMT.SComb (typeVars !! v) []
ty2SMT (FuncType ty1 ty2) = SMT.SComb "Func" <$> mapM ty2SMT [ty1, ty2]
ty2SMT (TCons qn@(_, tc) tys) =
SMT.SComb (lookupWithDefaultBM tc qn predefTypes) <$> mapM ty2SMT tys
cons2SMT :: SMTInfo -> SymObj -> VarIndex -> SMT.QIdent
cons2SMT smtInfo tqn v = case lookupSMTCons tqn smtInfo of
Nothing -> error $ "FCY2SMTLib.cons2SMT: No SMT-LIB representation for "
++ show tqn
Just c -> SMT.As c (getSMTSort smtInfo v)
lc2SMT :: LConstr -> SMT.Term -> SMT.Term -> SMT.Term
lc2SMT E = (=%)
lc2SMT NE = (/=%)
lc2SMT L = (<%)
lc2SMT LE = (<=%)
lc2SMT G = (>%)
lc2SMT GE = (>=%)
lit2SMT :: Literal -> SMT.Term
lit2SMT (Intc i) = tint i
lit2SMT (Floatc f) = tfloat f
lit2SMT (Charc _) = error "SMTLib.Goodies.lit2SMT: Characters are not supported"
fromTerm :: SMTInfo -> VarIndex -> SMT.Term -> AExpr TypeAnn
fromTerm smtInfo vi t = fmap extendAnn $ fromTerm' (getFCYType vi smtInfo) t
where
fromTerm' rty t' = case t' of
SMT.TComb qi ts
| i == "tvar" -> AComb unitType ConsCall (prel "()", unitType) []
| otherwise -> case lookupFCYCons i smtInfo of
Just (SymCons qn ty) ->
let ty' = subst (unify [(resultType ty, rty)]) ty
in AComb rty ConsCall (qn, ty') (zipWith fromTerm' (argTypes ty') ts)
_ -> error $ "FCY2SMTLib.fromTerm: No FCY representation for "
++ show qi
where i = unqual qi
SMT.TConst sc -> fromSpecConst sc
_ -> error $ "FCY2SMTLib.fromTerm: " ++ show t'
fromSpecConst :: SMT.SpecConstant -> AExpr TypeExpr
fromSpecConst (SMT.Num i) = ALit intType (Intc i)
fromSpecConst (SMT.Dec f) = ALit floatType (Floatc f)
fromSpecConst (SMT.Str _) = error "FCY2SMTLib.fromSpecConst: strings not supported yet"
toSort :: SMTInfo -> TypeExpr -> SMT.Sort
toSort _ (ForallType _ _) = error "FCY2SMT.toSort"
toSort _ (TVar _) = orderingSort
toSort smtInfo (FuncType t1 t2) = funSC (map (toSort smtInfo) [t1, t2])
toSort smtInfo (TCons qn tys) = case lookupType qn smtInfo of
Nothing -> error $ "Eval.toSort: No SMTLIB representation for type constructor "
++ show qn
Just tc -> scomb tc (map (toSort smtInfo) tys)
typeVars :: [String]
typeVars = [c : if n == 0 then [] else show n | n <- [0 ..], c <- ['a' .. 'z']]
predefTypes :: BM QName SMT.Ident
predefTypes = listToBM (<) (<) $ map (mapFst prel)
[ ("Bool","Bool"), ("Int","Int"), ("Float","Float")
, ("()","Unit"), ("[]","List"), ("(,)","Tuple2"), ("(,,)","Tuple3")
, ("(,,,)","Tuple4"), ("(,,,,)","Tuple5"), ("(,,,,,)","Tuple6")
, ("(,,,,,,)","Tuple7"), ("(,,,,,,,)","Tuple8"), ("(,,,,,,,,)","Tuple9")
, ("(,,,,,,,,,)","Tuple10"), ("(,,,,,,,,,,)","Tuple11")
, ("(,,,,,,,,,,,)","Tuple12"), ("(,,,,,,,,,,,,)","Tuple13")
, ("(,,,,,,,,,,,,,)","Tuple14"), ("(,,,,,,,,,,,,,,)","Tuple15")
]
predefCons :: BM SymObj SMT.Ident
predefCons = listToBM (<) (<) $
[ (prelSymCons "False" boolType,"false")
, (prelSymCons "True" boolType,"true")
, (prelSymCons "[]" (listType (TVar 0)),"nil")
, (prelSymCons ":" (mkFunType [TVar 0, listType (TVar 0)] (listType (TVar 0))),"insert")
, (prelSymCons "()" unitType,"unit")
] ++ map genTpl [2..15]
ignoredTypes :: [String]
ignoredTypes = ["Bool", "Int", "Float", "Char", "_Dict", "IO", "[]", "(->)"]
genTpl :: Int -> (SymObj, SMT.Ident)
genTpl n = (mkTplType ('(' : replicate (n-1) ',' ++ ")") n, "tuple" ++ show n)
mkTplType :: String -> Int -> SymObj
mkTplType n a | a >= 2 = SymCons qn (mkFunType tvars (TCons qn tvars))
where qn = prel n
tvars = map TVar [0 .. a-1]
|