-
Notifications
You must be signed in to change notification settings - Fork 63
/
Copy pathSAWTranslation.hs
4931 lines (4373 loc) · 210 KB
/
SAWTranslation.hs
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
413
414
415
416
417
418
419
420
421
422
423
424
425
426
427
428
429
430
431
432
433
434
435
436
437
438
439
440
441
442
443
444
445
446
447
448
449
450
451
452
453
454
455
456
457
458
459
460
461
462
463
464
465
466
467
468
469
470
471
472
473
474
475
476
477
478
479
480
481
482
483
484
485
486
487
488
489
490
491
492
493
494
495
496
497
498
499
500
501
502
503
504
505
506
507
508
509
510
511
512
513
514
515
516
517
518
519
520
521
522
523
524
525
526
527
528
529
530
531
532
533
534
535
536
537
538
539
540
541
542
543
544
545
546
547
548
549
550
551
552
553
554
555
556
557
558
559
560
561
562
563
564
565
566
567
568
569
570
571
572
573
574
575
576
577
578
579
580
581
582
583
584
585
586
587
588
589
590
591
592
593
594
595
596
597
598
599
600
601
602
603
604
605
606
607
608
609
610
611
612
613
614
615
616
617
618
619
620
621
622
623
624
625
626
627
628
629
630
631
632
633
634
635
636
637
638
639
640
641
642
643
644
645
646
647
648
649
650
651
652
653
654
655
656
657
658
659
660
661
662
663
664
665
666
667
668
669
670
671
672
673
674
675
676
677
678
679
680
681
682
683
684
685
686
687
688
689
690
691
692
693
694
695
696
697
698
699
700
701
702
703
704
705
706
707
708
709
710
711
712
713
714
715
716
717
718
719
720
721
722
723
724
725
726
727
728
729
730
731
732
733
734
735
736
737
738
739
740
741
742
743
744
745
746
747
748
749
750
751
752
753
754
755
756
757
758
759
760
761
762
763
764
765
766
767
768
769
770
771
772
773
774
775
776
777
778
779
780
781
782
783
784
785
786
787
788
789
790
791
792
793
794
795
796
797
798
799
800
801
802
803
804
805
806
807
808
809
810
811
812
813
814
815
816
817
818
819
820
821
822
823
824
825
826
827
828
829
830
831
832
833
834
835
836
837
838
839
840
841
842
843
844
845
846
847
848
849
850
851
852
853
854
855
856
857
858
859
860
861
862
863
864
865
866
867
868
869
870
871
872
873
874
875
876
877
878
879
880
881
882
883
884
885
886
887
888
889
890
891
892
893
894
895
896
897
898
899
900
901
902
903
904
905
906
907
908
909
910
911
912
913
914
915
916
917
918
919
920
921
922
923
924
925
926
927
928
929
930
931
932
933
934
935
936
937
938
939
940
941
942
943
944
945
946
947
948
949
950
951
952
953
954
955
956
957
958
959
960
961
962
963
964
965
966
967
968
969
970
971
972
973
974
975
976
977
978
979
980
981
982
983
984
985
986
987
988
989
990
991
992
993
994
995
996
997
998
999
1000
{-# LANGUAGE GADTs #-}
{-# LANGUAGE MultiParamTypeClasses #-}
{-# LANGUAGE FlexibleContexts #-}
{-# LANGUAGE FlexibleInstances #-}
{-# LANGUAGE UndecidableInstances #-}
{-# LANGUAGE KindSignatures #-}
{-# LANGUAGE DataKinds #-}
{-# LANGUAGE PolyKinds #-}
{-# LANGUAGE TypeOperators #-}
{-# LANGUAGE RankNTypes #-}
{-# LANGUAGE ScopedTypeVariables #-}
{-# LANGUAGE TypeApplications #-}
{-# LANGUAGE FunctionalDependencies #-}
{-# LANGUAGE ViewPatterns #-}
{-# LANGUAGE PartialTypeSignatures #-}
{-# LANGUAGE GeneralizedNewtypeDeriving #-}
{-# LANGUAGE RecordWildCards #-}
{-# LANGUAGE TypeFamilies #-}
{-# LANGUAGE TemplateHaskell #-}
{-# LANGUAGE QuasiQuotes #-}
{-# LANGUAGE ConstraintKinds #-}
{-# LANGUAGE OverloadedStrings #-}
{-# LANGUAGE PatternSynonyms #-}
{-# LANGUAGE PatternGuards #-}
{-# LANGUAGE TupleSections #-}
{-# LANGUAGE LambdaCase #-}
{-# LANGUAGE ImplicitParams #-}
module Verifier.SAW.Heapster.SAWTranslation where
import Prelude hiding (pi)
import Data.Maybe
import Numeric.Natural
import Data.List hiding (inits)
import Data.Text (pack)
import GHC.TypeLits
import Data.BitVector.Sized (BV)
import qualified Data.BitVector.Sized as BV
import Data.Functor.Compose
import Control.Applicative
import Control.Lens hiding ((:>), Index, ix, op)
import Control.Monad.Reader hiding (ap)
import Control.Monad.Writer hiding (ap)
import Control.Monad.Trans.Maybe
import qualified Control.Monad.Fail as Fail
import What4.ProgramLoc
import What4.Interface (StringLiteral(..))
import qualified Data.Type.RList as RL
import Data.Binding.Hobbits hiding (sym, trans)
import Data.Binding.Hobbits.Liftable ()
import Prettyprinter as PP
import Prettyprinter.Render.String
import Data.Parameterized.TraversableF
import Lang.Crucible.Types
import Lang.Crucible.LLVM.Extension
import Lang.Crucible.LLVM.MemModel
import Lang.Crucible.LLVM.DataLayout
import Lang.Crucible.CFG.Expr
import qualified Lang.Crucible.CFG.Expr as Expr
import Lang.Crucible.CFG.Core
import Verifier.SAW.OpenTerm
import Verifier.SAW.Term.Functor
import Verifier.SAW.SharedTerm
import Verifier.SAW.Heapster.CruUtil
import Verifier.SAW.Heapster.Permissions
import Verifier.SAW.Heapster.Implication
import Verifier.SAW.Heapster.TypedCrucible
import GHC.Stack
-- | FIXME: document and move to Hobbits
suffixMembers :: prx1 ctx1 -> RAssign prx2 ctx2 ->
RAssign (Member (ctx1 :++: ctx2)) ctx2
suffixMembers _ MNil = MNil
suffixMembers ctx1 (ctx2 :>: _) =
RL.map Member_Step (suffixMembers ctx1 ctx2) :>: Member_Base
----------------------------------------------------------------------
-- * Translation Monads
----------------------------------------------------------------------
-- | Call 'prettyCallStack' and insert a newline in front
nlPrettyCallStack :: CallStack -> String
nlPrettyCallStack = ("\n" ++) . prettyCallStack
-- | The result of translating a type-like construct such as a 'TypeRepr' or a
-- permission, parameterized by the (Haskell) type of the translations of the
-- elements of that type. This are translated to 0 or more SAW types, along with
-- a (Haskell) function for mapping elements of those types their translation
-- construct in Haskell.
data TypeTrans tr = TypeTrans
{ typeTransTypes :: [OpenTerm],
typeTransFun :: [OpenTerm] -> tr }
-- | Apply the 'typeTransFun' of a 'TypeTrans' with the call stack
typeTransF :: HasCallStack => TypeTrans tr -> [OpenTerm] -> tr
typeTransF (TypeTrans tps f) ts | length tps == length ts = f ts
typeTransF (TypeTrans tps _) ts =
error ("Type translation expected " ++ show (length tps) ++
" arguments, but got " ++ show (length ts))
instance Functor TypeTrans where
fmap f (TypeTrans ts tp_f) = TypeTrans ts (f . tp_f)
instance Applicative TypeTrans where
pure = mkTypeTrans0
liftA2 f (TypeTrans tps1 f1) (TypeTrans tps2 f2) =
TypeTrans (tps1 ++ tps2)
(\ts -> f (f1 $ take (length tps1) ts) (f2 $ drop (length tps1) ts))
-- | Build a 'TypeTrans' represented by 0 SAW types
mkTypeTrans0 :: tr -> TypeTrans tr
mkTypeTrans0 tr = TypeTrans [] (\[] -> tr)
-- | Build a 'TypeTrans' represented by 1 SAW type
mkTypeTrans1 :: OpenTerm -> (OpenTerm -> tr) -> TypeTrans tr
mkTypeTrans1 tp f = TypeTrans [tp] (\[t] -> f t)
-- | Extract out the single SAW type associated with a 'TypeTrans', or the unit
-- type if it has 0 SAW types. It is an error if it has 2 or more SAW types.
typeTransType1 :: HasCallStack => TypeTrans tr -> OpenTerm
typeTransType1 (TypeTrans [] _) = unitTypeOpenTerm
typeTransType1 (TypeTrans [tp] _) = tp
typeTransType1 _ = error ("typeTransType1" ++ nlPrettyCallStack callStack)
-- | Build the tuple type @T1 * (T2 * ... * (Tn-1 * Tn))@ of @n@ types, with the
-- special case that 0 types maps to the unit type @#()@ (and 1 type just maps
-- to itself). Note that this is different from 'tupleTypeOpenTerm', which
-- always ends with unit, i.e., which returns @T1*(T2*...*(Tn-1*(Tn*#())))@.
tupleOfTypes :: [OpenTerm] -> OpenTerm
tupleOfTypes [] = unitTypeOpenTerm
tupleOfTypes [tp] = tp
tupleOfTypes (tp:tps) = pairTypeOpenTerm tp $ tupleOfTypes tps
-- | Build the tuple @(t1,(t2,(...,(tn-1,tn))))@ of @n@ terms, with the
-- special case that 0 types maps to the unit value @()@ (and 1 value just maps
-- to itself). Note that this is different from 'tupleOpenTerm', which
-- always ends with unit, i.e., which returns @t1*(t2*...*(tn-1*(tn*())))@.
tupleOfTerms :: [OpenTerm] -> OpenTerm
tupleOfTerms [] = unitOpenTerm
tupleOfTerms [t] = t
tupleOfTerms (t:ts) = pairOpenTerm t $ tupleOfTerms ts
-- | Project the @i@th element from a term of type @'tupleOfTypes' tps@. Note
-- that this requires knowing the length of @tps@.
projTupleOfTypes :: [OpenTerm] -> Integer -> OpenTerm -> OpenTerm
projTupleOfTypes [] _ _ = error "projTupleOfTypes: projection of empty tuple!"
projTupleOfTypes [_] 0 tup = tup
projTupleOfTypes (_:_) 0 tup = pairLeftOpenTerm tup
projTupleOfTypes (_:tps) i tup =
projTupleOfTypes tps (i-1) $ pairRightOpenTerm tup
-- | Map the 'typeTransTypes' field of a 'TypeTrans' to a single type, where a
-- single type is mapped to itself, an empty list of types is mapped to @unit@,
-- and a list of 2 or more types is mapped to a tuple of the types
typeTransTupleType :: TypeTrans tr -> OpenTerm
typeTransTupleType = tupleOfTypes . typeTransTypes
-- | Convert a 'TypeTrans' over 0 or more types to one over the one type
-- returned by 'tupleOfTypes'
tupleTypeTrans :: TypeTrans tr -> TypeTrans tr
tupleTypeTrans ttrans =
let tps = typeTransTypes ttrans in
TypeTrans [tupleOfTypes tps]
(\[t] -> typeTransF ttrans $ map (\i -> projTupleOfTypes tps i t) $
take (length $ typeTransTypes ttrans) [0..])
-- | Convert a 'TypeTrans' over 0 or more types to one over 1 type of the form
-- @#(tp1, #(tp2, ... #(tpn, #()) ...))@. This is "strict" in the sense that
-- even a single type is tupled.
strictTupleTypeTrans :: TypeTrans tr -> TypeTrans tr
strictTupleTypeTrans ttrans =
TypeTrans [tupleTypeOpenTerm $ typeTransTypes ttrans]
(\[t] -> typeTransF ttrans $ map (\i -> projTupleOpenTerm i t) $
take (length $ typeTransTypes ttrans) [0..])
-- | Build a type translation for a list of translations
listTypeTrans :: [TypeTrans tr] -> TypeTrans [tr]
listTypeTrans [] = pure []
listTypeTrans (trans:transs) = liftA2 (:) trans $ listTypeTrans transs
-- | The result of translating a 'PermExpr' at 'CrucibleType' @a@. This is a
-- form of partially static data in the sense of partial evaluation.
data ExprTrans (a :: CrucibleType) where
-- | LLVM pointers have their translations dictated by their permissions, so
-- the translations of their expressions have no computational content
ETrans_LLVM :: ExprTrans (LLVMPointerType w)
-- | LLVM blocks also have no computational content
ETrans_LLVMBlock :: ExprTrans (LLVMBlockType w)
-- | Frames also have no computational content
ETrans_LLVMFrame :: ExprTrans (LLVMFrameType w)
-- | Lifetimes also have no computational content
ETrans_Lifetime :: ExprTrans LifetimeType
-- | Read-write modalities also have no computational content
ETrans_RWModality :: ExprTrans RWModalityType
-- | Structs are translated as a sequence of translations of the fields
ETrans_Struct :: ExprTransCtx (CtxToRList ctx) -> ExprTrans (StructType ctx)
-- | The computational content of functions is in their FunPerms, so functions
-- themselves have no computational content
ETrans_Fun :: ExprTrans (FunctionHandleType args ret)
-- | The unit type has no computational content
ETrans_Unit :: ExprTrans UnitType
-- | The translation for every other expression type is just a SAW term. Note
-- that this construct should not be used for the types handled above.
ETrans_Term :: OpenTerm -> ExprTrans a
-- | A context mapping bound names to their type-level SAW translations
type ExprTransCtx = RAssign ExprTrans
-- | Describes a Haskell type that represents the translation of a term-like
-- construct that corresponds to 0 or more SAW terms
class IsTermTrans tr where
transTerms :: tr -> [OpenTerm]
-- | Build a tuple of the terms contained in a translation, with 0 terms mapping
-- to the unit term and one term mapping to itself. If @ttrans@ is a 'TypeTrans'
-- describing the SAW types associated with a @tr@ translation, then this
-- function returns an element of the type @'tupleTypeTrans' ttrans@.
transTupleTerm :: IsTermTrans tr => tr -> OpenTerm
transTupleTerm (transTerms -> [t]) = t
transTupleTerm tr = tupleOfTerms $ transTerms tr
-- | Build a tuple of the terms contained in a translation. This is "strict" in
-- that it always makes a tuple, even for a single type, unlike
-- 'transTupleTerm'. If @ttrans@ is a 'TypeTrans' describing the SAW types
-- associated with a @tr@ translation, then this function returns an element of
-- the type @'strictTupleTypeTrans' ttrans@.
strictTransTupleTerm :: IsTermTrans tr => tr -> OpenTerm
strictTransTupleTerm tr = tupleOpenTerm $ transTerms tr
-- | Like 'transTupleTerm' but raise an error if there are more than 1 terms
transTerm1 :: HasCallStack => IsTermTrans tr => tr -> OpenTerm
transTerm1 (transTerms -> []) = unitOpenTerm
transTerm1 (transTerms -> [t]) = t
transTerm1 _ = error ("transTerm1" ++ nlPrettyCallStack callStack)
instance IsTermTrans tr => IsTermTrans [tr] where
transTerms = concatMap transTerms
instance IsTermTrans (TypeTrans tr) where
transTerms = typeTransTypes
instance IsTermTrans (ExprTrans tp) where
transTerms ETrans_LLVM = []
transTerms ETrans_LLVMBlock = []
transTerms ETrans_LLVMFrame = []
transTerms ETrans_Lifetime = []
transTerms ETrans_RWModality = []
transTerms (ETrans_Struct etranss) =
concat $ RL.mapToList transTerms etranss
transTerms ETrans_Fun = []
transTerms ETrans_Unit = []
transTerms (ETrans_Term t) = [t]
instance IsTermTrans (ExprTransCtx ctx) where
transTerms MNil = []
transTerms (ctx :>: etrans) = transTerms ctx ++ transTerms etrans
-- | Map a context of expression translations to a list of 'OpenTerm's
exprCtxToTerms :: ExprTransCtx tps -> [OpenTerm]
exprCtxToTerms = concat . RL.mapToList transTerms
-- | Class for valid translation info types, which must contain at least a
-- context of expression translations
class TransInfo info where
infoCtx :: info ctx -> ExprTransCtx ctx
infoEnv :: info ctx -> PermEnv
extTransInfo :: ExprTrans tp -> info ctx -> info (ctx :> tp)
-- | A "translation monad" is a 'Reader' monad with some info type that is
-- parameterized by a translation context
newtype TransM info (ctx :: RList CrucibleType) a =
TransM { unTransM :: Reader (info ctx) a }
deriving (Functor, Applicative, Monad)
instance Fail.MonadFail (TransM info ctx) where
fail = error
-- | The run function for the 'TransM' monad
runTransM :: TransM info ctx a -> info ctx -> a
runTransM (TransM m) = runReader m
instance MonadReader (info ctx) (TransM info ctx) where
ask = TransM ask
local f (TransM m) = TransM $ local f m
-- | Run a translation computation with a modified info object
withInfoM :: (info ctx -> info' ctx') -> TransM info' ctx' a ->
TransM info ctx a
withInfoM f (TransM m) = TransM $ withReader f m
-- | Run a translation computation in an extended context
inExtTransM :: TransInfo info => ExprTrans tp -> TransM info (ctx :> tp) a ->
TransM info ctx a
inExtTransM etrans (TransM m) = TransM $ withReader (extTransInfo etrans) m
-- | Run a translation computation in a context extended with multiple types
inExtMultiTransM :: TransInfo info => ExprTransCtx ctx2 ->
TransM info (ctx :++: ctx2) a ->
TransM info ctx a
inExtMultiTransM MNil m = m
inExtMultiTransM (ctx :>: etrans) m =
inExtMultiTransM ctx $ inExtTransM etrans m
-- | Run a translation computation in an extended context, where we sawLet-bind any
-- term in the supplied expression translation
inExtTransSAWLetBindM :: TransInfo info => TypeTrans (ExprTrans tp) -> OpenTerm ->
ExprTrans tp -> TransM info (ctx :> tp) OpenTerm ->
TransM info ctx OpenTerm
inExtTransSAWLetBindM tp_trans tp_ret etrans m =
sawLetTransMultiM "z" (typeTransTypes tp_trans) tp_ret (transTerms etrans) $ \var_tms ->
inExtTransM (typeTransF tp_trans var_tms) m
-- | Run a translation computation in context @(ctx1 :++: ctx2) :++: ctx2@ by
-- copying the @ctx2@ portion of the current context
inExtMultiTransCopyLastM :: TransInfo info => prx ctx1 -> RAssign any ctx2 ->
TransM info ((ctx1 :++: ctx2) :++: ctx2) a ->
TransM info (ctx1 :++: ctx2) a
inExtMultiTransCopyLastM ctx1 ctx2 m =
do ectx <- infoCtx <$> ask
let (_,ectx2) = RL.split ctx1 ctx2 ectx
inExtMultiTransM ectx2 m
-- | Run a translation computation in a specific context
inCtxTransM :: TransInfo info => ExprTransCtx ctx ->
TransM info ctx a -> TransM info RNil a
inCtxTransM MNil m = m
inCtxTransM (ctx :>: etrans) m = inCtxTransM ctx $ inExtTransM etrans m
-- | Build a multi-binding for the current context
nuMultiTransM :: TransInfo info => (RAssign Name ctx -> b) ->
TransM info ctx (Mb ctx b)
nuMultiTransM f =
do info <- ask
return $ nuMulti (RL.map (\_ -> Proxy) (infoCtx info)) f
-- | Apply the result of a translation to that of another
applyTransM :: TransM info ctx OpenTerm -> TransM info ctx OpenTerm ->
TransM info ctx OpenTerm
applyTransM m1 m2 = applyOpenTerm <$> m1 <*> m2
-- | Apply the result of a translation to the results of multiple translations
applyMultiTransM :: TransM info ctx OpenTerm -> [TransM info ctx OpenTerm] ->
TransM info ctx OpenTerm
applyMultiTransM m ms = foldl applyTransM m ms
-- | Build a lambda-abstraction inside the 'TransM' monad
lambdaOpenTermTransM :: String -> OpenTerm ->
(OpenTerm -> TransM info ctx OpenTerm) ->
TransM info ctx OpenTerm
lambdaOpenTermTransM x tp body_f =
ask >>= \info ->
return (lambdaOpenTerm (pack x) tp $ \t -> runTransM (body_f t) info)
-- | Build a nested lambda-abstraction
--
-- > \x1:tp1 -> ... -> \xn:tpn -> body
--
-- over the types in a 'TypeTrans' inside a translation monad, using the
-- 'String' as a variable name prefix for the @xi@ variables
lambdaTrans :: String -> TypeTrans tr -> (tr -> OpenTerm) -> OpenTerm
lambdaTrans x tps body_f =
lambdaOpenTermMulti
(zipWith (\i tp -> (pack (x ++ show (i :: Integer)), tp)) [0..] $ typeTransTypes tps)
(body_f . typeTransF tps)
-- | Build a nested lambda-abstraction
--
-- > \x1:tp1 -> ... -> \xn:tpn -> body
--
-- over the types in a 'TypeTrans' inside a translation monad, using the
-- 'String' as a variable name prefix for the @xi@ variables
lambdaTransM :: String -> TypeTrans tr -> (tr -> TransM info ctx OpenTerm) ->
TransM info ctx OpenTerm
lambdaTransM x tps body_f =
ask >>= \info ->
return (lambdaOpenTermMulti
(zipWith (\i tp -> (pack (x ++ show (i :: Integer)), tp)) [0..] $ typeTransTypes tps)
(\ts -> runTransM (body_f $ typeTransF tps ts) info))
-- | Build a lambda-abstraction
--
-- > \x1:(tp1, ..., tpn) -> body
--
-- over a tuple of the types in a 'TypeTrans'. Note that this always builds
-- exactly one lambda-abstraction, even if there are 0 types.
lambdaTupleTransM :: String -> TypeTrans tr -> (tr -> TransM info ctx OpenTerm) ->
TransM info ctx OpenTerm
lambdaTupleTransM x ttrans body_f =
lambdaTransM x (tupleTypeTrans ttrans) body_f
-- | Build a pi-abstraction over the types in a 'TypeTrans' inside a
-- translation monad, using the 'String' as a variable name prefix
piTransM :: String -> TypeTrans tr -> (tr -> TransM info ctx OpenTerm) ->
TransM info ctx OpenTerm
piTransM x tps body_f =
ask >>= \info ->
return (piOpenTermMulti
(zipWith (\i tp -> (pack (x ++ show (i :: Integer)), tp)) [0..] $ typeTransTypes tps)
(\ts -> runTransM (body_f $ typeTransF tps ts) info))
-- | Build a let-binding in a translation monad
letTransM :: String -> OpenTerm -> TransM info ctx OpenTerm ->
(OpenTerm -> TransM info ctx OpenTerm) ->
TransM info ctx OpenTerm
letTransM x tp rhs_m body_m =
do r <- ask
return $
letOpenTerm (pack x) tp (runTransM rhs_m r) (\x' -> runTransM (body_m x') r)
-- | Build a sawLet-binding in a translation monad
sawLetTransM :: String -> OpenTerm -> OpenTerm -> TransM info ctx OpenTerm ->
(OpenTerm -> TransM info ctx OpenTerm) ->
TransM info ctx OpenTerm
sawLetTransM x tp tp_ret rhs_m body_m =
do r <- ask
return $
sawLetOpenTerm (pack x) tp tp_ret (runTransM rhs_m r)
(\x' -> runTransM (body_m x') r)
-- | Build 0 or more sawLet-bindings in a translation monad, using the same
-- variable name
sawLetTransMultiM :: String -> [OpenTerm] -> OpenTerm -> [OpenTerm] ->
([OpenTerm] -> TransM info ctx OpenTerm) ->
TransM info ctx OpenTerm
sawLetTransMultiM _ [] _ [] f = f []
sawLetTransMultiM x (tp:tps) ret_tp (rhs:rhss) f =
sawLetTransM x tp ret_tp (return rhs) $ \var_tm ->
sawLetTransMultiM x tps ret_tp rhss (\var_tms -> f (var_tm:var_tms))
sawLetTransMultiM _ _ _ _ _ =
error "sawLetTransMultiM: numbers of types and right-hand sides disagree"
-- | Build a bitvector type in a translation monad
bitvectorTransM :: TransM info ctx OpenTerm -> TransM info ctx OpenTerm
bitvectorTransM m =
applyMultiTransM (return $ globalOpenTerm "Prelude.Vec")
[m, return $ globalOpenTerm "Prelude.Bool"]
-- | Build an @Either@ type in SAW from the 'typeTransTupleType's of the left
-- and right types
eitherTypeTrans :: TypeTrans trL -> TypeTrans trR -> OpenTerm
eitherTypeTrans tp_l tp_r =
dataTypeOpenTerm "Prelude.Either"
[typeTransTupleType tp_l, typeTransTupleType tp_r]
-- | Apply the @Left@ constructor of the @Either@ type in SAW to the
-- 'transTupleTerm' of the input
leftTrans :: IsTermTrans trL => TypeTrans trL -> TypeTrans trR -> trL ->
OpenTerm
leftTrans tp_l tp_r tr =
ctorOpenTerm "Prelude.Left"
[typeTransTupleType tp_l, typeTransTupleType tp_r, transTupleTerm tr]
-- | Apply the @Right@ constructor of the @Either@ type in SAW to the
-- 'transTupleTerm' of the input
rightTrans :: IsTermTrans trR => TypeTrans trL -> TypeTrans trR -> trR ->
OpenTerm
rightTrans tp_l tp_r tr =
ctorOpenTerm "Prelude.Right"
[typeTransTupleType tp_l, typeTransTupleType tp_r, transTupleTerm tr]
-- | Eliminate a SAW @Either@ type
eitherElimTransM :: TypeTrans trL -> TypeTrans trR ->
TypeTrans tr -> (trL -> TransM info ctx OpenTerm) ->
(trR -> TransM info ctx OpenTerm) -> OpenTerm ->
TransM info ctx OpenTerm
eitherElimTransM tp_l tp_r tp_ret fl fr eith =
do fl_trans <- lambdaTupleTransM "x_left" tp_l fl
fr_trans <- lambdaTupleTransM "x_right" tp_r fr
return $ applyOpenTermMulti (globalOpenTerm "Prelude.either")
[ typeTransTupleType tp_l, typeTransTupleType tp_r,
typeTransTupleType tp_ret, fl_trans, fr_trans, eith ]
-- | Build the dependent pair type whose first projection type is the
-- 'typeTransTupleType' of the supplied 'TypeTrans' and whose second projection
-- is the 'typeTransTupleType' of the supplied monadic function. As a special
-- case, just return the latter if the 'TypeTrans' contains 0 types.
sigmaTypeTransM :: String -> TypeTrans trL ->
(trL -> TransM info ctx (TypeTrans trR)) ->
TransM info ctx OpenTerm
sigmaTypeTransM _ ttrans@(typeTransTypes -> []) tp_f =
typeTransTupleType <$> tp_f (typeTransF ttrans [])
sigmaTypeTransM x ttrans tp_f =
do tp_f_trm <- lambdaTupleTransM x ttrans (\tr ->
typeTransTupleType <$> tp_f tr)
return (dataTypeOpenTerm "Prelude.Sigma"
[typeTransTupleType ttrans, tp_f_trm])
-- | Like `sigmaTypeTransM`, but translates `exists x.eq(y)` into just `x`
sigmaTypePermTransM :: TransInfo info => String -> TypeTrans (ExprTrans trL) ->
Mb (ctx :> trL) (ValuePerm trR) ->
TransM info ctx OpenTerm
sigmaTypePermTransM x ttrans p_cbn = case mbMatch p_cbn of
[nuMP| ValPerm_Eq _ |] -> return $ typeTransTupleType ttrans
_ -> sigmaTypeTransM x ttrans (flip inExtTransM $ translate p_cbn)
-- | Build a dependent pair of the type returned by 'sigmaTypeTransM'. Note that
-- the 'TypeTrans' returned by the type-level function will in general be in a
-- larger context than that of the right-hand projection argument, so we allow
-- the representation types to be different to allow for this.
sigmaTransM :: (IsTermTrans trL, IsTermTrans trR2) => String -> TypeTrans trL ->
(trL -> TransM info ctx (TypeTrans trR1)) ->
trL -> TransM info ctx trR2 ->
TransM info ctx OpenTerm
sigmaTransM _ (typeTransTypes -> []) _ _ rhs_m = transTupleTerm <$> rhs_m
sigmaTransM x tp_l tp_r lhs rhs_m =
do tp_r_trm <- lambdaTupleTransM x tp_l ((typeTransTupleType <$>) . tp_r)
rhs <- transTupleTerm <$> rhs_m
return (ctorOpenTerm "Prelude.exists"
[typeTransTupleType tp_l, tp_r_trm, transTupleTerm lhs, rhs])
-- | Like `sigmaTransM`, but translates `exists x.eq(y)` into just `x`
sigmaPermTransM :: (TransInfo info, IsTermTrans trR2) =>
String -> TypeTrans (ExprTrans trL) ->
Mb (ctx :> trL) (ValuePerm trR1) ->
ExprTrans trL -> TransM info ctx trR2 ->
TransM info ctx OpenTerm
sigmaPermTransM x ttrans p_cbn etrans rhs_m = case mbMatch p_cbn of
[nuMP| ValPerm_Eq _ |] -> return $ transTupleTerm etrans
_ -> sigmaTransM x ttrans (flip inExtTransM $ translate p_cbn)
etrans rhs_m
-- | Eliminate a dependent pair of the type returned by 'sigmaTypeTransM'
sigmaElimTransM :: (IsTermTrans trL, IsTermTrans trR) =>
String -> TypeTrans trL ->
(trL -> TransM info ctx (TypeTrans trR)) ->
TransM info ctx (TypeTrans trRet) ->
(trL -> trR -> TransM info ctx OpenTerm) ->
OpenTerm ->
TransM info ctx OpenTerm
sigmaElimTransM _ tp_l@(typeTransTypes -> []) tp_r _ f sigma =
do let proj1 = typeTransF tp_l []
proj2 <- flip (typeTransF . tupleTypeTrans) [sigma] <$> tp_r proj1
f proj1 proj2
sigmaElimTransM x tp_l tp_r _tp_ret_m f sigma =
do let tp_l_trm = typeTransTupleType tp_l
tp_r_trm <- lambdaTupleTransM x tp_l (\tr ->
typeTransTupleType <$> tp_r tr)
let proj_l_trm =
applyOpenTermMulti (globalOpenTerm "Prelude.Sigma_proj1")
[tp_l_trm, tp_r_trm, sigma]
let proj_l = typeTransF (tupleTypeTrans tp_l) [proj_l_trm]
tp_r_app <- tp_r proj_l
let proj_r_trm =
applyOpenTermMulti (globalOpenTerm "Prelude.Sigma_proj2")
[tp_l_trm, tp_r_trm, sigma]
let proj_r = typeTransF (tupleTypeTrans tp_r_app) [proj_r_trm]
f proj_l proj_r
{- NOTE: the following is the version that inserts a Sigma__rec
sigmaElimTransM x tp_l tp_r tp_ret_m f sigma =
do tp_r_trm <- lambdaTupleTransM x tp_l (\tr ->
typeTransTupleType <$> tp_r tr)
sigma_tp <- sigmaTypeTransM x tp_l tp_r
tp_ret <- lambdaTransM x (mkTypeTrans1 sigma_tp id)
(const (typeTransTupleType <$> tp_ret_m))
f_trm <-
lambdaTupleTransM (x ++ "_proj1") tp_l $ \x_l ->
tp_r x_l >>= \tp_r_app ->
lambdaTupleTransM (x ++ "_proj2") tp_r_app (f x_l)
return (applyOpenTermMulti (globalOpenTerm "Prelude.Sigma__rec")
[ typeTransTupleType tp_l, tp_r_trm, tp_ret, f_trm, sigma ])
-}
-- | Like `sigmaElimTransM`, but translates `exists x.eq(y)` into just `x`
sigmaElimPermTransM :: (TransInfo info) =>
String -> TypeTrans (ExprTrans trL) ->
Mb (ctx :> trL) (ValuePerm trR) ->
TransM info ctx (TypeTrans trRet) ->
(ExprTrans trL -> PermTrans (ctx :> trL) trR ->
TransM info ctx OpenTerm) ->
OpenTerm ->
TransM info ctx OpenTerm
sigmaElimPermTransM x tp_l p_cbn tp_ret_m f sigma = case mbMatch p_cbn of
[nuMP| ValPerm_Eq e |] -> f (typeTransF (tupleTypeTrans tp_l) [sigma])
(PTrans_Eq e)
_ -> sigmaElimTransM x tp_l (flip inExtTransM $ translate p_cbn)
tp_ret_m f sigma
-- | The class for translating to SAW
class Translate info ctx a tr | ctx a -> tr where
translate :: Mb ctx a -> TransM info ctx tr
-- | Translate to SAW and then convert to a single SAW term using
-- 'transTupleTerm'
translateToTuple :: (IsTermTrans tr, Translate info ctx a tr) =>
Mb ctx a -> TransM info ctx OpenTerm
translateToTuple a = transTupleTerm <$> translate a
-- | Translate to SAW and then convert to a single SAW term, raising an error if
-- the result has 0 or more than 1 terms
translate1 :: (IsTermTrans tr, Translate info ctx a tr, HasCallStack) =>
Mb ctx a -> TransM info ctx OpenTerm
translate1 a = translate a >>= \tr -> case transTerms tr of
[t] -> return t
ts -> error ("translate1: expected 1 term, found " ++ show (length ts)
++ nlPrettyCallStack callStack)
-- | Translate a "closed" term, that is not in a binding
translateClosed :: (TransInfo info, Translate info ctx a tr) =>
a -> TransM info ctx tr
translateClosed a = nuMultiTransM (const a) >>= translate
instance (Translate info ctx a tr, NuMatching a) =>
Translate info ctx [a] [tr] where
translate = mapM translate . mbList
----------------------------------------------------------------------
-- * Translating Types
----------------------------------------------------------------------
-- | A flag for whether or not to perform checks in the translation. We use this
-- type, rather than just 'Bool', for documentation purposes.
newtype ChecksFlag = ChecksFlag { checksFlagSet :: Bool }
-- | The 'ChecksFlag' specifying not to perform any translation checks
noChecks :: ChecksFlag
noChecks = ChecksFlag False
-- | The 'ChecksFlag' specifying to perform all translation checks
doChecks :: ChecksFlag
doChecks = ChecksFlag True
-- | Translation info for translating types and pure expressions
data TypeTransInfo ctx = TypeTransInfo (ExprTransCtx ctx) PermEnv ChecksFlag
-- | Build an empty 'TypeTransInfo' from a 'PermEnv'
emptyTypeTransInfo :: PermEnv -> ChecksFlag -> TypeTransInfo RNil
emptyTypeTransInfo = TypeTransInfo MNil
instance TransInfo TypeTransInfo where
infoCtx (TypeTransInfo ctx _ _) = ctx
infoEnv (TypeTransInfo _ env _) = env
extTransInfo etrans (TypeTransInfo ctx env checks) =
TypeTransInfo (ctx :>: etrans) env checks
-- | The translation monad specific to translating types and pure expressions
type TypeTransM = TransM TypeTransInfo
-- | Run a 'TypeTransM' computation in the empty translation context
runNilTypeTransM :: PermEnv -> ChecksFlag -> TypeTransM RNil a -> a
runNilTypeTransM env checks m = runTransM m (emptyTypeTransInfo env checks)
-- | Run a translation computation in an empty expression translation context
inEmptyCtxTransM :: TypeTransM RNil a -> TypeTransM ctx a
inEmptyCtxTransM =
withInfoM (\(TypeTransInfo _ env checks) -> TypeTransInfo MNil env checks)
instance TransInfo info => Translate info ctx (NatRepr n) OpenTerm where
translate mb_n = return $ natOpenTerm $ mbLift $ fmap natValue mb_n
-- | Helper for writing the 'Translate' instance for 'TypeRepr'
returnType1 :: OpenTerm -> TransM info ctx (TypeTrans (ExprTrans a))
returnType1 tp = return $ mkTypeTrans1 tp ETrans_Term
-- FIXME: explain this translation
instance TransInfo info =>
Translate info ctx (TypeRepr a) (TypeTrans (ExprTrans a)) where
translate mb_tp = case mbMatch mb_tp of
[nuMP| AnyRepr |] ->
return $ error "Translate: Any"
[nuMP| UnitRepr |] ->
return $ mkTypeTrans0 ETrans_Unit
[nuMP| BoolRepr |] ->
returnType1 $ globalOpenTerm "Prelude.Bool"
[nuMP| NatRepr |] ->
returnType1 $ dataTypeOpenTerm "Prelude.Nat" []
[nuMP| IntegerRepr |] ->
return $ error "translate: IntegerRepr"
[nuMP| RealValRepr |] ->
return $ error "translate: RealValRepr"
[nuMP| ComplexRealRepr |] ->
return $ error "translate: ComplexRealRepr"
[nuMP| SequenceRepr{} |] ->
return $ error "translate: SequenceRepr"
[nuMP| BVRepr w |] ->
returnType1 =<< bitvectorTransM (translate w)
-- Our special-purpose intrinsic types, whose translations do not have
-- computational content
[nuMP| LLVMPointerRepr _ |] ->
return $ mkTypeTrans0 ETrans_LLVM
[nuMP| LLVMBlockRepr _ |] ->
return $ mkTypeTrans0 ETrans_LLVMBlock
[nuMP| LLVMFrameRepr _ |] ->
return $ mkTypeTrans0 ETrans_LLVMFrame
[nuMP| LifetimeRepr |] ->
return $ mkTypeTrans0 ETrans_Lifetime
[nuMP| PermListRepr |] ->
returnType1 (sortOpenTerm $ mkSort 0)
[nuMP| RWModalityRepr |] ->
return $ mkTypeTrans0 ETrans_RWModality
-- Permissions and LLVM shapes translate to types
[nuMP| ValuePermRepr _ |] ->
returnType1 (sortOpenTerm $ mkSort 0)
[nuMP| LLVMShapeRepr _ |] ->
returnType1 (sortOpenTerm $ mkSort 0)
-- We can't handle any other special-purpose types
[nuMP| IntrinsicRepr _ _ |] ->
return $ error "translate: IntrinsicRepr"
[nuMP| RecursiveRepr _ _ |] ->
return $ error "translate: RecursiveRepr"
[nuMP| FloatRepr _ |] ->
returnType1 $ dataTypeOpenTerm "Prelude.Float" []
[nuMP| IEEEFloatRepr _ |] ->
return $ error "translate: IEEEFloatRepr"
[nuMP| CharRepr |] ->
return $ error "translate: CharRepr"
[nuMP| StringRepr UnicodeRepr |] ->
returnType1 stringTypeOpenTerm
[nuMP| StringRepr _ |] ->
return $ error "translate: StringRepr non-unicode"
[nuMP| FunctionHandleRepr _ _ |] ->
-- NOTE: function permissions translate to the SAW function, but the
-- function handle itself has no SAW translation
return $ mkTypeTrans0 ETrans_Fun
[nuMP| MaybeRepr _ |] ->
return $ error "translate: MaybeRepr"
[nuMP| VectorRepr _ |] ->
return $ error "translate: VectorRepr (can't map to Vec without size)"
[nuMP| StructRepr tps |] ->
fmap ETrans_Struct <$> translate (fmap mkCruCtx tps)
[nuMP| VariantRepr _ |] ->
return $ error "translate: VariantRepr"
[nuMP| ReferenceRepr _ |] ->
return $ error "translate: ReferenceRepr"
[nuMP| WordMapRepr _ _ |] ->
return $ error "translate: WordMapRepr"
[nuMP| StringMapRepr _ |] ->
return $ error "translate: StringMapRepr"
[nuMP| SymbolicArrayRepr _ _ |] ->
return $ error "translate: SymbolicArrayRepr"
[nuMP| SymbolicStructRepr _ |] ->
return $ error "translate: SymbolicStructRepr"
instance TransInfo info =>
Translate info ctx (CruCtx as) (TypeTrans (ExprTransCtx as)) where
translate mb_ctx = case mbMatch mb_ctx of
[nuMP| CruCtxNil |] -> return $ mkTypeTrans0 MNil
[nuMP| CruCtxCons ctx tp |] ->
liftA2 (:>:) <$> translate ctx <*> translate tp
-- | Translate all types in a Crucible context and lambda-abstract over them
lambdaExprCtx :: TransInfo info => CruCtx ctx -> TransM info ctx OpenTerm ->
TransM info RNil OpenTerm
lambdaExprCtx ctx m =
translateClosed ctx >>= \tptrans ->
lambdaTransM "e" tptrans (\ectx -> inCtxTransM ectx m)
-- | Translate all types in a Crucible context and pi-abstract over them
piExprCtx :: TransInfo info => CruCtx ctx2 ->
TransM info (ctx :++: ctx2) OpenTerm ->
TransM info ctx OpenTerm
piExprCtx ctx m =
translateClosed ctx >>= \tptrans ->
piTransM "e" tptrans (\ectx -> inExtMultiTransM ectx m)
----------------------------------------------------------------------
-- * Translating Pure Expressions
----------------------------------------------------------------------
-- FIXME HERE: move these OpenTerm operations to OpenTerm.hs
-- | Build a bitvector literal from a 'BV' value
bvBVOpenTerm :: NatRepr w -> BV w -> OpenTerm
bvBVOpenTerm w bv = bvLitOpenTerm (BV.asBitsBE w bv)
bvNatOpenTerm :: Natural -> Natural -> OpenTerm
bvNatOpenTerm w n =
applyOpenTermMulti (globalOpenTerm "Prelude.bvNat")
[natOpenTerm w, natOpenTerm (n `mod` 2 ^ w)]
bvAddOpenTerm :: Natural -> OpenTerm -> OpenTerm -> OpenTerm
bvAddOpenTerm n x y =
applyOpenTermMulti (globalOpenTerm "Prelude.bvAdd")
[natOpenTerm n, x, y]
bvMulOpenTerm :: Natural -> OpenTerm -> OpenTerm -> OpenTerm
bvMulOpenTerm n x y =
applyOpenTermMulti (globalOpenTerm "Prelude.bvMul")
[natOpenTerm n, x, y]
bvSplitOpenTerm :: EndianForm -> OpenTerm -> OpenTerm -> OpenTerm ->
(OpenTerm, OpenTerm)
bvSplitOpenTerm BigEndian sz1 sz2 e =
(applyOpenTermMulti (globalOpenTerm "Prelude.take") [boolTypeOpenTerm,
sz1, sz2, e],
applyOpenTermMulti (globalOpenTerm "Prelude.drop") [boolTypeOpenTerm,
sz1, sz2, e])
bvSplitOpenTerm LittleEndian sz1 sz2 e =
(applyOpenTermMulti (globalOpenTerm "Prelude.drop") [boolTypeOpenTerm,
sz2, sz1, e],
applyOpenTermMulti (globalOpenTerm "Prelude.take") [boolTypeOpenTerm,
sz2, sz1, e])
bvConcatOpenTerm :: EndianForm -> OpenTerm -> OpenTerm ->
OpenTerm -> OpenTerm -> OpenTerm
bvConcatOpenTerm BigEndian sz1 sz2 e1 e2 =
applyOpenTermMulti (globalOpenTerm "Prelude.append")
[sz1, sz2, boolTypeOpenTerm, e1, e2]
bvConcatOpenTerm LittleEndian sz1 sz2 e1 e2 =
applyOpenTermMulti (globalOpenTerm "Prelude.append")
[sz2, sz1, boolTypeOpenTerm, e2, e1]
-- | Translate a variable to a 'Member' proof, raising an error if the variable
-- is unbound
translateVar :: Mb ctx (ExprVar a) -> Member ctx a
translateVar mb_x | Left memb <- mbNameBoundP mb_x = memb
translateVar _ = error "translateVar: unbound variable!"
-- | Get the 'TypeRepr' of an expression
mbExprType :: KnownRepr TypeRepr a => Mb ctx (PermExpr a) -> TypeRepr a
mbExprType _ = knownRepr
-- | Get the 'TypeRepr' bound by a binding
mbBindingType :: KnownRepr TypeRepr tp => Mb ctx (Binding tp a) -> TypeRepr tp
mbBindingType _ = knownRepr
instance TransInfo info =>
Translate info ctx (ExprVar a) (ExprTrans a) where
translate mb_x = RL.get (translateVar mb_x) <$> infoCtx <$> ask
instance TransInfo info =>
Translate info ctx (RAssign ExprVar as) (ExprTransCtx as) where
translate mb_exprs = case mbMatch mb_exprs of
[nuMP| MNil |] -> return MNil
[nuMP| ns :>: n |] ->
(:>:) <$> translate ns <*> translate n
instance TransInfo info =>
Translate info ctx (PermExpr a) (ExprTrans a) where
translate mb_tr = case mbMatch mb_tr of
[nuMP| PExpr_Var x |] -> translate x
[nuMP| PExpr_Unit |] -> return ETrans_Unit
[nuMP| PExpr_Bool True |] ->
return $ ETrans_Term $ globalOpenTerm "Prelude.True"
[nuMP| PExpr_Bool False |] ->
return $ ETrans_Term $ globalOpenTerm "Prelude.False"
[nuMP| PExpr_Nat i |] ->
return $ ETrans_Term $ natOpenTerm $ mbLift i
[nuMP| PExpr_String str |] ->
return $ ETrans_Term $ stringLitOpenTerm $ pack $ mbLift str
[nuMP| PExpr_BV bvfactors@[] off |] ->
let w = natRepr3 bvfactors in
return $ ETrans_Term $ bvBVOpenTerm w $ mbLift off
[nuMP| PExpr_BV bvfactors (BV.BV 0) |] ->
let w = natVal3 bvfactors in
ETrans_Term <$> foldr1 (bvAddOpenTerm w) <$> translate bvfactors
[nuMP| PExpr_BV bvfactors off |] ->
do let w = natRepr3 bvfactors
bv_transs <- translate bvfactors
return $ ETrans_Term $
foldr (bvAddOpenTerm $ natValue w) (bvBVOpenTerm w $ mbLift off) bv_transs
[nuMP| PExpr_Struct args |] ->
ETrans_Struct <$> translate args
[nuMP| PExpr_Always |] ->
return ETrans_Lifetime
[nuMP| PExpr_LLVMWord _ |] -> return ETrans_LLVM
[nuMP| PExpr_LLVMOffset _ _ |] -> return ETrans_LLVM
[nuMP| PExpr_Fun _ |] -> return ETrans_Fun
[nuMP| PExpr_PermListNil |] -> return $ ETrans_Term unitTypeOpenTerm
[nuMP| PExpr_PermListCons _ _ p l |] ->
ETrans_Term <$> (pairTypeOpenTerm <$>
(typeTransTupleType <$> translate p) <*>
(translate1 l))
[nuMP| PExpr_RWModality _ |] -> return ETrans_RWModality
-- LLVM shapes are translated to types
[nuMP| PExpr_EmptyShape |] -> return $ ETrans_Term unitTypeOpenTerm
[nuMP| PExpr_NamedShape _ _ nmsh args |] ->
case mbMatch $ fmap namedShapeBody nmsh of
[nuMP| DefinedShapeBody _ |] ->
translate (mbMap2 unfoldNamedShape nmsh args)
[nuMP| OpaqueShapeBody _ trans_id |] ->
ETrans_Term <$> applyOpenTermMulti (globalOpenTerm $ mbLift trans_id) <$>
transTerms <$> translate args
[nuMP| RecShapeBody _ trans_id _ |] ->
ETrans_Term <$> applyOpenTermMulti (globalOpenTerm $ mbLift trans_id) <$>
transTerms <$> translate args
[nuMP| PExpr_EqShape _ _ |] -> return $ ETrans_Term unitTypeOpenTerm
[nuMP| PExpr_PtrShape _ _ sh |] -> translate sh
[nuMP| PExpr_FieldShape fsh |] ->
ETrans_Term <$> tupleOfTypes <$> translate fsh
[nuMP| PExpr_ArrayShape mb_len _ mb_sh |] ->
do let w = natVal4 mb_len
let w_term = natOpenTerm w
len_term <- translate1 mb_len
elem_tp <- translate1 mb_sh
return $ ETrans_Term $
applyOpenTermMulti (globalOpenTerm "Prelude.BVVec")
[w_term, len_term, elem_tp]
[nuMP| PExpr_SeqShape sh1 sh2 |] ->
ETrans_Term <$> (pairTypeOpenTerm <$> translate1 sh1 <*> translate1 sh2)
[nuMP| PExpr_OrShape sh1 sh2 |] ->
ETrans_Term <$>
((\t1 t2 -> dataTypeOpenTerm "Prelude.Either" [t1,t2])
<$> translate1 sh1 <*> translate1 sh2)
[nuMP| PExpr_ExShape mb_sh |] ->
do tp_trans <- translate $ fmap bindingType mb_sh
tp_f_trm <- lambdaTupleTransM "x_exsh" tp_trans $ \e ->
transTupleTerm <$> inExtTransM e (translate $ mbCombine RL.typeCtxProxies mb_sh)
return $ ETrans_Term (dataTypeOpenTerm "Prelude.Sigma"
[typeTransTupleType tp_trans, tp_f_trm])
[nuMP| PExpr_FalseShape |] ->
return $ ETrans_Term $ globalOpenTerm "Prelude.FalseProp"
[nuMP| PExpr_ValPerm p |] ->
ETrans_Term <$> typeTransTupleType <$> translate p
-- LLVM field shapes translate to the types that the permission they contain
-- translates to
instance TransInfo info =>
Translate info ctx (LLVMFieldShape w) [OpenTerm] where
translate (mbMatch -> [nuMP| LLVMFieldShape p |]) = typeTransTypes <$> translate p
instance TransInfo info =>
Translate info ctx (PermExprs as) (ExprTransCtx as) where
translate mb_exprs = case mbMatch mb_exprs of
[nuMP| PExprs_Nil |] -> return MNil
[nuMP| PExprs_Cons es e |] ->
(:>:) <$> translate es <*> translate e
instance TransInfo info => Translate info ctx (BVFactor w) OpenTerm where
translate mb_f = case mbMatch mb_f of
[nuMP| BVFactor (BV.BV 1) x |] -> translate1 (fmap PExpr_Var x)
[nuMP| BVFactor i x |] ->
let w = natRepr4 x in
bvMulOpenTerm (natValue w) (bvBVOpenTerm w $ mbLift i) <$>
translate1 (fmap PExpr_Var x)
----------------------------------------------------------------------
-- * Translating Permissions to Types
----------------------------------------------------------------------
-- | The result of translating a "proof element" of a permission of type
-- @'ValuePerm' a@. The idea here is that, for a permission implication or typed
-- statement that consumes or emits permission @p@, the translation consumes or
-- emits an element of the SAW type @'translate' p@.
--
-- Another way to look at a @'PermTrans'@ for permission @p@ is that it is a
-- partially static representation (in the sense of the partial evaluation
-- literature) of a SAW expression of type @'translate' p@. Note that we do
-- not include special representations for disjunctions, existentials, or
-- recursive permissions, however, because our type-checker does not
-- generally introduce these forms as intermediate values.
data PermTrans (ctx :: RList CrucibleType) (a :: CrucibleType) where
-- | An @eq(e)@ permission has no computational content
PTrans_Eq :: Mb ctx (PermExpr a) -> PermTrans ctx a
-- | A conjuction of atomic permission translations
PTrans_Conj :: [AtomicPermTrans ctx a] -> PermTrans ctx a
-- | The translation of a defined permission is a wrapper around the
-- translation of what it is defined as
PTrans_Defined :: NamedPermName (DefinedSort b) args a ->
Mb ctx (PermExprs args) -> Mb ctx (PermOffset a) ->
PermTrans ctx a -> PermTrans ctx a
-- | The translation for disjunctive, existential, and named permissions
PTrans_Term :: Mb ctx (ValuePerm a) -> OpenTerm -> PermTrans ctx a
-- | The 'PermTrans' type for atomic permissions
data AtomicPermTrans ctx a where
-- | The translation of an LLVM field permission is just the translation of
-- its contents