{-# LANGUAGE DeriveAnyClass #-}
{-# LANGUAGE DeriveFunctor #-}
{-# LANGUAGE DeriveGeneric #-}
{-# LANGUAGE DoAndIfThenElse #-}
{-# LANGUAGE FunctionalDependencies #-}
{-# LANGUAGE FlexibleInstances #-}
{-# LANGUAGE LambdaCase #-}
{-# LANGUAGE MultiParamTypeClasses #-}
{-# LANGUAGE PatternGuards #-}
{-# LANGUAGE Safe #-}
{-# LANGUAGE ScopedTypeVariables #-}
{-# LANGUAGE TupleSections #-}
{-# LANGUAGE ViewPatterns #-}
module Cryptol.Eval.Value where
import Data.Bits
import Data.IORef
import qualified Data.Sequence as Seq
import qualified Data.Foldable as Fold
import Data.Map.Strict (Map)
import qualified Data.Map.Strict as Map
import MonadLib
import qualified Cryptol.Eval.Arch as Arch
import Cryptol.Eval.Monad
import Cryptol.Eval.Type
import Cryptol.TypeCheck.AST
import Cryptol.TypeCheck.Solver.InfNat(Nat'(..))
import Cryptol.Utils.Ident (Ident,mkIdent)
import Cryptol.Utils.PP
import Cryptol.Utils.Panic(panic)
import Data.List(genericLength, genericIndex, genericDrop)
import qualified Data.Text as T
import Numeric (showIntAtBase)
import GHC.Generics (Generic)
import Control.DeepSeq
data BV = BV !Integer !Integer deriving (Generic, NFData)
instance Show BV where
show = show . bvVal
binBV :: (Integer -> Integer -> Integer) -> BV -> BV -> BV
binBV f (BV w x) (BV _ y) = mkBv w (f x y)
unaryBV :: (Integer -> Integer) -> BV -> BV
unaryBV f (BV w x) = mkBv w $ f x
bvVal :: BV -> Integer
bvVal (BV _w x) = x
mkBv :: Integer -> Integer -> BV
mkBv w i = BV w (mask w i)
data SeqMap b w i
= IndexSeqMap !(Integer -> Eval (GenValue b w i))
| UpdateSeqMap !(Map Integer (Eval (GenValue b w i)))
!(Integer -> Eval (GenValue b w i))
lookupSeqMap :: SeqMap b w i -> Integer -> Eval (GenValue b w i)
lookupSeqMap (IndexSeqMap f) i = f i
lookupSeqMap (UpdateSeqMap m f) i =
case Map.lookup i m of
Just x -> x
Nothing -> f i
type SeqValMap = SeqMap Bool BV Integer
instance NFData (SeqMap b w i) where
rnf x = seq x ()
finiteSeqMap :: [Eval (GenValue b w i)] -> SeqMap b w i
finiteSeqMap xs =
UpdateSeqMap
(Map.fromList (zip [0..] xs))
invalidIndex
infiniteSeqMap :: [Eval (GenValue b w i)] -> Eval (SeqMap b w i)
infiniteSeqMap xs =
memoMap (IndexSeqMap $ \i -> genericIndex xs i)
enumerateSeqMap :: (Integral n) => n -> SeqMap b w i -> [Eval (GenValue b w i)]
enumerateSeqMap n m = [ lookupSeqMap m i | i <- [0 .. (toInteger n)-1] ]
streamSeqMap :: SeqMap b w i -> [Eval (GenValue b w i)]
streamSeqMap m = [ lookupSeqMap m i | i <- [0..] ]
reverseSeqMap :: Integer
-> SeqMap b w i
-> SeqMap b w i
reverseSeqMap n vals = IndexSeqMap $ \i -> lookupSeqMap vals (n - 1 - i)
updateSeqMap :: SeqMap b w i -> Integer -> Eval (GenValue b w i) -> SeqMap b w i
updateSeqMap (UpdateSeqMap m sm) i x = UpdateSeqMap (Map.insert i x m) sm
updateSeqMap (IndexSeqMap f) i x = UpdateSeqMap (Map.singleton i x) f
concatSeqMap :: Integer -> SeqMap b w i -> SeqMap b w i -> SeqMap b w i
concatSeqMap n x y =
IndexSeqMap $ \i ->
if i < n
then lookupSeqMap x i
else lookupSeqMap y (i-n)
splitSeqMap :: Integer -> SeqMap b w i -> (SeqMap b w i, SeqMap b w i)
splitSeqMap n xs = (hd,tl)
where
hd = xs
tl = IndexSeqMap $ \i -> lookupSeqMap xs (i+n)
dropSeqMap :: Integer -> SeqMap b w i -> SeqMap b w i
dropSeqMap 0 xs = xs
dropSeqMap n xs = IndexSeqMap $ \i -> lookupSeqMap xs (i+n)
memoMap :: SeqMap b w i -> Eval (SeqMap b w i)
memoMap x = do
cache <- io $ newIORef $ Map.empty
return $ IndexSeqMap (memo cache)
where
memo cache i = do
mz <- io (Map.lookup i <$> readIORef cache)
case mz of
Just z -> return z
Nothing -> doEval cache i
doEval cache i = do
v <- lookupSeqMap x i
io $ modifyIORef' cache (Map.insert i v)
return v
zipSeqMap :: (GenValue b w i -> GenValue b w i -> Eval (GenValue b w i))
-> SeqMap b w i
-> SeqMap b w i
-> Eval (SeqMap b w i)
zipSeqMap f x y =
memoMap (IndexSeqMap $ \i -> join (f <$> lookupSeqMap x i <*> lookupSeqMap y i))
mapSeqMap :: (GenValue b w i -> Eval (GenValue b w i))
-> SeqMap b w i -> Eval (SeqMap b w i)
mapSeqMap f x =
memoMap (IndexSeqMap $ \i -> f =<< lookupSeqMap x i)
data WordValue b w i
= WordVal !w
| BitsVal !(Seq.Seq (Eval b))
| LargeBitsVal !Integer !(SeqMap b w i )
deriving (Generic, NFData)
largeBitSize :: Integer
largeBitSize = 1 `shiftL` 16
asWordVal :: BitWord b w i => WordValue b w i -> Eval w
asWordVal (WordVal w) = return w
asWordVal (BitsVal bs) = packWord <$> sequence (Fold.toList bs)
asWordVal (LargeBitsVal n xs) = packWord <$> traverse (fromBit =<<) (enumerateSeqMap n xs)
asBitsMap :: BitWord b w i => WordValue b w i -> SeqMap b w i
asBitsMap (WordVal w) = IndexSeqMap $ \i -> ready $ VBit $ wordBit w i
asBitsMap (BitsVal bs) = IndexSeqMap $ \i -> VBit <$> join (checkedSeqIndex bs i)
asBitsMap (LargeBitsVal _ xs) = xs
enumerateWordValue :: BitWord b w i => WordValue b w i -> Eval [b]
enumerateWordValue (WordVal w) = return $ unpackWord w
enumerateWordValue (BitsVal bs) = sequence (Fold.toList bs)
enumerateWordValue (LargeBitsVal n xs) = traverse (fromBit =<<) (enumerateSeqMap n xs)
enumerateWordValueRev :: BitWord b w i => WordValue b w i -> Eval [b]
enumerateWordValueRev (WordVal w) = return $ reverse $ unpackWord w
enumerateWordValueRev (BitsVal bs) = sequence (Fold.toList $ Seq.reverse bs)
enumerateWordValueRev (LargeBitsVal n xs) = traverse (fromBit =<<) (enumerateSeqMap n (reverseSeqMap n xs))
wordValueSize :: BitWord b w i => WordValue b w i -> Integer
wordValueSize (WordVal w) = wordLen w
wordValueSize (BitsVal bs) = toInteger $ Seq.length bs
wordValueSize (LargeBitsVal n _) = n
checkedSeqIndex :: Seq.Seq a -> Integer -> Eval a
checkedSeqIndex xs i =
case Seq.viewl (Seq.drop (fromInteger i) xs) of
x Seq.:< _ -> return x
Seq.EmptyL -> invalidIndex i
checkedIndex :: [a] -> Integer -> Eval a
checkedIndex xs i =
case genericDrop i xs of
(x:_) -> return x
_ -> invalidIndex i
indexWordValue :: BitWord b w i => WordValue b w i -> Integer -> Eval b
indexWordValue (WordVal w) idx
| idx < wordLen w = return $ wordBit w idx
| otherwise = invalidIndex idx
indexWordValue (BitsVal bs) idx = join (checkedSeqIndex bs idx)
indexWordValue (LargeBitsVal n xs) idx
| idx < n = fromBit =<< lookupSeqMap xs idx
| otherwise = invalidIndex idx
updateWordValue :: BitWord b w i => WordValue b w i -> Integer -> Eval b -> Eval (WordValue b w i)
updateWordValue (WordVal w) idx (Ready b)
| idx < wordLen w = return $ WordVal $ wordUpdate w idx b
| otherwise = invalidIndex idx
updateWordValue (WordVal w) idx b
| idx < wordLen w = return $ BitsVal $ Seq.update (fromInteger idx) b $ Seq.fromList $ map ready $ unpackWord w
| otherwise = invalidIndex idx
updateWordValue (BitsVal bs) idx b
| idx < toInteger (Seq.length bs) = return $ BitsVal $ Seq.update (fromInteger idx) b bs
| otherwise = invalidIndex idx
updateWordValue (LargeBitsVal n xs) idx b
| idx < n = return $ LargeBitsVal n $ updateSeqMap xs idx (VBit <$> b)
| otherwise = invalidIndex idx
data GenValue b w i
= VRecord ![(Ident, Eval (GenValue b w i))]
| VTuple ![Eval (GenValue b w i)]
| VBit !b
| VInteger !i
| VSeq !Integer !(SeqMap b w i)
| VWord !Integer !(Eval (WordValue b w i))
| VStream !(SeqMap b w i)
| VFun (Eval (GenValue b w i) -> Eval (GenValue b w i))
| VPoly (TValue -> Eval (GenValue b w i))
| VNumPoly (Nat' -> Eval (GenValue b w i))
deriving (Generic, NFData)
forceWordValue :: WordValue b w i -> Eval ()
forceWordValue (WordVal _w) = return ()
forceWordValue (BitsVal bs) = mapM_ (\b -> const () <$> b) bs
forceWordValue (LargeBitsVal n xs) = mapM_ (\x -> const () <$> x) (enumerateSeqMap n xs)
forceValue :: GenValue b w i -> Eval ()
forceValue v = case v of
VRecord fs -> mapM_ (\x -> forceValue =<< snd x) fs
VTuple xs -> mapM_ (forceValue =<<) xs
VSeq n xs -> mapM_ (forceValue =<<) (enumerateSeqMap n xs)
VBit _b -> return ()
VInteger _i -> return ()
VWord _ wv -> forceWordValue =<< wv
VStream _ -> return ()
VFun _ -> return ()
VPoly _ -> return ()
VNumPoly _ -> return ()
instance (Show b, Show w, Show i) => Show (GenValue b w i) where
show v = case v of
VRecord fs -> "record:" ++ show (map fst fs)
VTuple xs -> "tuple:" ++ show (length xs)
VBit b -> show b
VInteger i -> show i
VSeq n _ -> "seq:" ++ show n
VWord n _ -> "word:" ++ show n
VStream _ -> "stream"
VFun _ -> "fun"
VPoly _ -> "poly"
VNumPoly _ -> "numpoly"
type Value = GenValue Bool BV Integer
defaultPPOpts :: PPOpts
defaultPPOpts = PPOpts { useAscii = False, useBase = 10, useInfLength = 5 }
atFst :: Functor f => (a -> f b) -> (a, c) -> f (b, c)
atFst f (x,y) = fmap (,y) $ f x
atSnd :: Functor f => (a -> f b) -> (c, a) -> f (c, b)
atSnd f (x,y) = fmap (x,) $ f y
ppValue :: forall b w i
. BitWord b w i
=> PPOpts
-> GenValue b w i
-> Eval Doc
ppValue opts = loop
where
loop :: GenValue b w i -> Eval Doc
loop val = case val of
VRecord fs -> do fs' <- traverse (atSnd (>>=loop)) $ fs
return $ braces (sep (punctuate comma (map ppField fs')))
where
ppField (f,r) = pp f <+> char '=' <+> r
VTuple vals -> do vals' <- traverse (>>=loop) vals
return $ parens (sep (punctuate comma vals'))
VBit b -> return $ ppBit b
VInteger i -> return $ ppInteger opts i
VSeq sz vals -> ppWordSeq sz vals
VWord _ wv -> ppWordVal =<< wv
VStream vals -> do vals' <- traverse (>>=loop) $ enumerateSeqMap (useInfLength opts) vals
return $ brackets $ fsep
$ punctuate comma
( vals' ++ [text "..."]
)
VFun _ -> return $ text "<function>"
VPoly _ -> return $ text "<polymorphic value>"
VNumPoly _ -> return $ text "<polymorphic value>"
ppWordVal :: WordValue b w i -> Eval Doc
ppWordVal w = ppWord opts <$> asWordVal w
ppWordSeq :: Integer -> SeqMap b w i -> Eval Doc
ppWordSeq sz vals = do
ws <- sequence (enumerateSeqMap sz vals)
case ws of
w : _
| Just l <- vWordLen w
, asciiMode opts l
-> do vs <- traverse (fromVWord "ppWordSeq") ws
case traverse wordAsChar vs of
Just str -> return $ text (show str)
_ -> return $ brackets (fsep (punctuate comma $ map (ppWord opts) vs))
_ -> do ws' <- traverse loop ws
return $ brackets (fsep (punctuate comma ws'))
asciiMode :: PPOpts -> Integer -> Bool
asciiMode opts width = useAscii opts && (width == 7 || width == 8)
integerToChar :: Integer -> Char
integerToChar = toEnum . fromInteger
ppBV :: PPOpts -> BV -> Doc
ppBV opts (BV width i)
| base > 36 = integer i
| asciiMode opts width = text (show (toEnum (fromInteger i) :: Char))
| otherwise = prefix <.> text value
where
base = useBase opts
padding bitsPerDigit = text (replicate padLen '0')
where
padLen | m > 0 = d + 1
| otherwise = d
(d,m) = (fromInteger width - (length value * bitsPerDigit))
`divMod` bitsPerDigit
prefix = case base of
2 -> text "0b" <.> padding 1
8 -> text "0o" <.> padding 3
10 -> empty
16 -> text "0x" <.> padding 4
_ -> text "0" <.> char '<' <.> int base <.> char '>'
value = showIntAtBase (toInteger base) (digits !!) i ""
digits = "0123456789abcdefghijklmnopqrstuvwxyz"
class BitWord b w i | b -> w, w -> i, i -> b where
ppBit :: b -> Doc
ppWord :: PPOpts -> w -> Doc
ppInteger :: PPOpts -> i -> Doc
wordAsChar :: w -> Maybe Char
wordLen :: w -> Integer
bitLit :: Bool -> b
wordLit :: Integer
-> Integer
-> w
integerLit :: Integer
-> i
wordBit :: w -> Integer -> b
wordUpdate :: w -> Integer -> b -> w
packWord :: [b] -> w
unpackWord :: w -> [b]
joinWord :: w -> w -> w
splitWord :: Integer
-> Integer
-> w
-> (w, w)
extractWord :: Integer
-> Integer
-> w
-> w
wordPlus :: w -> w -> w
wordMinus :: w -> w -> w
wordMult :: w -> w -> w
wordToInt :: w -> i
intPlus :: i -> i -> i
intMinus :: i -> i -> i
intMult :: i -> i -> i
intModPlus :: Integer -> i -> i -> i
intModMinus :: Integer -> i -> i -> i
intModMult :: Integer -> i -> i -> i
wordFromInt :: Integer -> i -> w
class BitWord b w i => EvalPrims b w i where
evalPrim :: Decl -> Maybe (GenValue b w i)
iteValue :: b
-> Eval (GenValue b w i)
-> Eval (GenValue b w i)
-> Eval (GenValue b w i)
mask :: Integer
-> Integer
-> Integer
mask w i | w >= Arch.maxBigIntWidth = wordTooWide w
| otherwise = i .&. ((1 `shiftL` fromInteger w) - 1)
instance BitWord Bool BV Integer where
wordLen (BV w _) = w
wordAsChar (BV _ x) = Just $ integerToChar x
wordBit (BV w x) idx = testBit x (fromInteger (w - 1 - idx))
wordUpdate (BV w x) idx True = BV w (setBit x (fromInteger (w - 1 - idx)))
wordUpdate (BV w x) idx False = BV w (clearBit x (fromInteger (w - 1 - idx)))
ppBit b | b = text "True"
| otherwise = text "False"
ppWord = ppBV
ppInteger _opts i = integer i
bitLit b = b
wordLit = mkBv
integerLit i = i
packWord bits = BV (toInteger w) a
where
w = case length bits of
len | toInteger len >= Arch.maxBigIntWidth -> wordTooWide (toInteger len)
| otherwise -> len
a = foldl setb 0 (zip [w - 1, w - 2 .. 0] bits)
setb acc (n,b) | b = setBit acc n
| otherwise = acc
unpackWord (BV w a) = [ testBit a n | n <- [w' - 1, w' - 2 .. 0] ]
where
w' = fromInteger w
joinWord (BV i x) (BV j y) =
BV (i + j) (shiftL x (fromInteger j) + y)
splitWord leftW rightW (BV _ x) =
( BV leftW (x `shiftR` (fromInteger rightW)), mkBv rightW x )
extractWord n i (BV _ x) = mkBv n (x `shiftR` (fromInteger i))
wordPlus (BV i x) (BV j y)
| i == j = mkBv i (x+y)
| otherwise = panic "Attempt to add words of different sizes: wordPlus" []
wordMinus (BV i x) (BV j y)
| i == j = mkBv i (x-y)
| otherwise = panic "Attempt to subtract words of different sizes: wordMinus" []
wordMult (BV i x) (BV j y)
| i == j = mkBv i (x*y)
| otherwise = panic "Attempt to multiply words of different sizes: wordMult" []
intPlus x y = x + y
intMinus x y = x - y
intMult x y = x * y
intModPlus m x y = (x + y) `mod` m
intModMinus m x y = (x - y) `mod` m
intModMult m x y = (x * y) `mod` m
wordToInt (BV _ x) = x
wordFromInt w x = mkBv w x
word :: BitWord b w i => Integer -> Integer -> GenValue b w i
word n i
| n >= Arch.maxBigIntWidth = wordTooWide n
| otherwise = VWord n $ ready $ WordVal $ wordLit n i
lam :: (Eval (GenValue b w i) -> Eval (GenValue b w i)) -> GenValue b w i
lam = VFun
wlam :: BitWord b w i => (w -> Eval (GenValue b w i)) -> GenValue b w i
wlam f = VFun (\x -> x >>= fromVWord "wlam" >>= f)
tlam :: (TValue -> GenValue b w i) -> GenValue b w i
tlam f = VPoly (return . f)
nlam :: (Nat' -> GenValue b w i) -> GenValue b w i
nlam f = VNumPoly (return . f)
toStream :: [GenValue b w i] -> Eval (GenValue b w i)
toStream vs =
VStream <$> infiniteSeqMap (map ready vs)
toFinSeq :: BitWord b w i
=> Integer -> TValue -> [GenValue b w i] -> GenValue b w i
toFinSeq len elty vs
| isTBit elty = VWord len $ ready $ WordVal $ packWord $ map fromVBit vs
| otherwise = VSeq len $ finiteSeqMap (map ready vs)
boolToWord :: [Bool] -> Value
boolToWord bs = VWord (genericLength bs) $ ready $ WordVal $ packWord bs
toSeq :: BitWord b w i
=> Nat' -> TValue -> [GenValue b w i] -> Eval (GenValue b w i)
toSeq len elty vals = case len of
Nat n -> return $ toFinSeq n elty vals
Inf -> toStream vals
mkSeq :: Nat' -> TValue -> SeqMap b w i -> GenValue b w i
mkSeq len elty vals = case len of
Nat n
| isTBit elty -> VWord n $ return $ BitsVal $ Seq.fromFunction (fromInteger n) $ \i ->
fromVBit <$> lookupSeqMap vals (toInteger i)
| otherwise -> VSeq n vals
Inf -> VStream vals
fromVBit :: GenValue b w i -> b
fromVBit val = case val of
VBit b -> b
_ -> evalPanic "fromVBit" ["not a Bit"]
fromVInteger :: GenValue b w i -> i
fromVInteger val = case val of
VInteger i -> i
_ -> evalPanic "fromVInteger" ["not an Integer"]
fromVSeq :: GenValue b w i -> SeqMap b w i
fromVSeq val = case val of
VSeq _ vs -> vs
_ -> evalPanic "fromVSeq" ["not a sequence"]
fromSeq :: forall b w i. BitWord b w i => String -> GenValue b w i -> Eval (SeqMap b w i)
fromSeq msg val = case val of
VSeq _ vs -> return vs
VStream vs -> return vs
_ -> evalPanic "fromSeq" ["not a sequence", msg]
fromStr :: Value -> Eval String
fromStr (VSeq n vals) =
traverse (\x -> toEnum . fromInteger <$> (fromWord "fromStr" =<< x)) (enumerateSeqMap n vals)
fromStr _ = evalPanic "fromStr" ["Not a finite sequence"]
fromBit :: GenValue b w i -> Eval b
fromBit (VBit b) = return b
fromBit _ = evalPanic "fromBit" ["Not a bit value"]
fromWordVal :: String -> GenValue b w i -> Eval (WordValue b w i)
fromWordVal _msg (VWord _ wval) = wval
fromWordVal msg _ = evalPanic "fromWordVal" ["not a word value", msg]
fromVWord :: BitWord b w i => String -> GenValue b w i -> Eval w
fromVWord _msg (VWord _ wval) = wval >>= asWordVal
fromVWord msg _ = evalPanic "fromVWord" ["not a word", msg]
vWordLen :: BitWord b w i => GenValue b w i -> Maybe Integer
vWordLen val = case val of
VWord n _wv -> Just n
_ -> Nothing
tryFromBits :: BitWord b w i => [Eval (GenValue b w i)] -> Maybe w
tryFromBits = go id
where
go f [] = Just (packWord (f []))
go f (Ready (VBit b) : vs) = go (f . (b :)) vs
go _ (_ : _) = Nothing
fromWord :: String -> Value -> Eval Integer
fromWord msg val = bvVal <$> fromVWord msg val
fromVFun :: GenValue b w i -> (Eval (GenValue b w i) -> Eval (GenValue b w i))
fromVFun val = case val of
VFun f -> f
_ -> evalPanic "fromVFun" ["not a function"]
fromVPoly :: GenValue b w i -> (TValue -> Eval (GenValue b w i))
fromVPoly val = case val of
VPoly f -> f
_ -> evalPanic "fromVPoly" ["not a polymorphic value"]
fromVNumPoly :: GenValue b w i -> (Nat' -> Eval (GenValue b w i))
fromVNumPoly val = case val of
VNumPoly f -> f
_ -> evalPanic "fromVNumPoly" ["not a polymorphic value"]
fromVTuple :: GenValue b w i -> [Eval (GenValue b w i)]
fromVTuple val = case val of
VTuple vs -> vs
_ -> evalPanic "fromVTuple" ["not a tuple"]
fromVRecord :: GenValue b w i -> [(Ident, Eval (GenValue b w i))]
fromVRecord val = case val of
VRecord fs -> fs
_ -> evalPanic "fromVRecord" ["not a record"]
lookupRecord :: Ident -> GenValue b w i -> Eval (GenValue b w i)
lookupRecord f rec = case lookup f (fromVRecord rec) of
Just val -> val
Nothing -> evalPanic "lookupRecord" ["malformed record"]
toExpr :: PrimMap -> Type -> Value -> Eval (Maybe Expr)
toExpr prims t0 v0 = findOne (go t0 v0)
where
prim n = ePrim prims (mkIdent (T.pack n))
go :: Type -> Value -> ChoiceT Eval Expr
go ty val = case (tNoUser ty, val) of
(TRec tfs, VRecord vfs) -> do
let fns = map fst vfs
guard (map fst tfs == fns)
fes <- zipWithM go (map snd tfs) =<< lift (traverse snd vfs)
return $ ERec (zip fns fes)
(TCon (TC (TCTuple tl)) ts, VTuple tvs) -> do
guard (tl == (length tvs))
ETuple `fmap` (zipWithM go ts =<< lift (sequence tvs))
(TCon (TC TCBit) [], VBit True ) -> return (prim "True")
(TCon (TC TCBit) [], VBit False) -> return (prim "False")
(TCon (TC TCInteger) [], VInteger i) ->
return $ ETApp (ETApp (prim "number") (tNum i)) ty
(TCon (TC TCIntMod) [_n], VInteger i) ->
return $ ETApp (ETApp (prim "number") (tNum i)) ty
(TCon (TC TCSeq) [a,b], VSeq 0 _) -> do
guard (a == tZero)
return $ EList [] b
(TCon (TC TCSeq) [a,b], VSeq n svs) -> do
guard (a == tNum n)
ses <- mapM (go b) =<< lift (sequence (enumerateSeqMap n svs))
return $ EList ses b
(TCon (TC TCSeq) [a,(TCon (TC TCBit) [])], VWord _ wval) -> do
BV w v <- lift (asWordVal =<< wval)
guard (a == tNum w)
return $ ETApp (ETApp (prim "number") (tNum v)) ty
(_, VStream _) -> fail "cannot construct infinite expressions"
(_, VFun _) -> fail "cannot convert function values to expressions"
(_, VPoly _) -> fail "cannot convert polymorphic values to expressions"
_ -> do doc <- lift (ppValue defaultPPOpts val)
panic "Cryptol.Eval.Value.toExpr"
["type mismatch:"
, pretty ty
, render doc
]