mirror of
https://github.com/GaloisInc/cryptol.git
synced 2025-01-07 08:19:12 +03:00
Start generalizing evaluator code to be used in both the
concrete and symbolic evaluators.
This commit is contained in:
parent
6d681f5bb5
commit
122a147085
@ -23,7 +23,7 @@ module Cryptol.Eval (
|
|||||||
import Cryptol.Eval.Env
|
import Cryptol.Eval.Env
|
||||||
import Cryptol.Eval.Monad
|
import Cryptol.Eval.Monad
|
||||||
import Cryptol.Eval.Type
|
import Cryptol.Eval.Type
|
||||||
import Cryptol.Eval.Value
|
import Cryptol.Eval.Value hiding (evalPrim)
|
||||||
import Cryptol.ModuleSystem.Name
|
import Cryptol.ModuleSystem.Name
|
||||||
import Cryptol.TypeCheck.AST
|
import Cryptol.TypeCheck.AST
|
||||||
import Cryptol.TypeCheck.Solver.InfNat(Nat'(..))
|
import Cryptol.TypeCheck.Solver.InfNat(Nat'(..))
|
||||||
@ -41,6 +41,9 @@ import qualified Data.Map.Strict as Map
|
|||||||
import Prelude ()
|
import Prelude ()
|
||||||
import Prelude.Compat
|
import Prelude.Compat
|
||||||
|
|
||||||
|
type EvalEnv = GenEvalEnv Bool BV
|
||||||
|
type ReadEnv = EvalEnv
|
||||||
|
|
||||||
-- Expression Evaluation -------------------------------------------------------
|
-- Expression Evaluation -------------------------------------------------------
|
||||||
|
|
||||||
moduleEnv :: Module -> EvalEnv -> Eval EvalEnv
|
moduleEnv :: Module -> EvalEnv -> Eval EvalEnv
|
||||||
|
@ -29,16 +29,15 @@ import Prelude.Compat
|
|||||||
|
|
||||||
-- Evaluation Environment ------------------------------------------------------
|
-- Evaluation Environment ------------------------------------------------------
|
||||||
|
|
||||||
type ReadEnv = EvalEnv
|
data GenEvalEnv b w = EvalEnv
|
||||||
|
{ envVars :: !(Map.Map Name (Eval (GenValue b w)))
|
||||||
data EvalEnv = EvalEnv
|
|
||||||
{ envVars :: !(Map.Map Name (Eval Value))
|
|
||||||
, envTypes :: !(Map.Map TVar TValue)
|
, envTypes :: !(Map.Map TVar TValue)
|
||||||
} deriving (Generic)
|
} deriving (Generic)
|
||||||
|
|
||||||
instance NFData EvalEnv where rnf = genericRnf
|
instance (NFData b, NFData w) => NFData (GenEvalEnv b w)
|
||||||
|
where rnf = genericRnf
|
||||||
|
|
||||||
instance Monoid EvalEnv where
|
instance Monoid (GenEvalEnv b w) where
|
||||||
mempty = EvalEnv
|
mempty = EvalEnv
|
||||||
{ envVars = Map.empty
|
{ envVars = Map.empty
|
||||||
, envTypes = Map.empty
|
, envTypes = Map.empty
|
||||||
@ -49,22 +48,20 @@ instance Monoid EvalEnv where
|
|||||||
, envTypes = Map.union (envTypes l) (envTypes r)
|
, envTypes = Map.union (envTypes l) (envTypes r)
|
||||||
}
|
}
|
||||||
|
|
||||||
ppEnv :: PPOpts -> EvalEnv -> Eval Doc
|
ppEnv :: BitWord b w => PPOpts -> GenEvalEnv b w -> Eval Doc
|
||||||
ppEnv opts env = brackets . fsep <$> mapM bind (Map.toList (envVars env))
|
ppEnv opts env = brackets . fsep <$> mapM bind (Map.toList (envVars env))
|
||||||
where
|
where
|
||||||
bind (k,v) = do vdoc <- ppValue opts =<< v
|
bind (k,v) = do vdoc <- ppValue opts =<< v
|
||||||
return (pp k <+> text "->" <+> vdoc)
|
return (pp k <+> text "->" <+> vdoc)
|
||||||
|
|
||||||
--instance PP (WithBase EvalEnv) where
|
emptyEnv :: GenEvalEnv b w
|
||||||
-- ppPrec _ (WithBase opts env) = brackets (fsep (map bind (Map.toList (envVars env))))
|
|
||||||
-- where
|
|
||||||
-- bind (k,v) = pp k <+> text "->" <+> ppValue opts v
|
|
||||||
|
|
||||||
emptyEnv :: EvalEnv
|
|
||||||
emptyEnv = mempty
|
emptyEnv = mempty
|
||||||
|
|
||||||
-- | Bind a variable in the evaluation environment.
|
-- | Bind a variable in the evaluation environment.
|
||||||
bindVar :: Name -> Eval Value -> EvalEnv -> Eval EvalEnv
|
bindVar :: Name
|
||||||
|
-> Eval (GenValue b w)
|
||||||
|
-> GenEvalEnv b w
|
||||||
|
-> Eval (GenEvalEnv b w)
|
||||||
bindVar n val env = do
|
bindVar n val env = do
|
||||||
let nm = show $ ppLocName n
|
let nm = show $ ppLocName n
|
||||||
val' <- delay (Just nm) val
|
val' <- delay (Just nm) val
|
||||||
@ -72,15 +69,15 @@ bindVar n val env = do
|
|||||||
|
|
||||||
-- | Lookup a variable in the environment.
|
-- | Lookup a variable in the environment.
|
||||||
{-# INLINE lookupVar #-}
|
{-# INLINE lookupVar #-}
|
||||||
lookupVar :: Name -> EvalEnv -> Maybe (Eval Value)
|
lookupVar :: Name -> GenEvalEnv b w -> Maybe (Eval (GenValue b w))
|
||||||
lookupVar n env = Map.lookup n (envVars env)
|
lookupVar n env = Map.lookup n (envVars env)
|
||||||
|
|
||||||
-- | Bind a type variable of kind *.
|
-- | Bind a type variable of kind *.
|
||||||
{-# INLINE bindType #-}
|
{-# INLINE bindType #-}
|
||||||
bindType :: TVar -> TValue -> EvalEnv -> EvalEnv
|
bindType :: TVar -> TValue -> GenEvalEnv b w -> GenEvalEnv b w
|
||||||
bindType p ty env = env { envTypes = Map.insert p ty (envTypes env) }
|
bindType p ty env = env { envTypes = Map.insert p ty (envTypes env) }
|
||||||
|
|
||||||
-- | Lookup a type variable.
|
-- | Lookup a type variable.
|
||||||
{-# INLINE lookupType #-}
|
{-# INLINE lookupType #-}
|
||||||
lookupType :: TVar -> EvalEnv -> Maybe TValue
|
lookupType :: TVar -> GenEvalEnv b w -> Maybe TValue
|
||||||
lookupType p env = Map.lookup p (envTypes env)
|
lookupType p env = Map.lookup p (envTypes env)
|
||||||
|
@ -22,7 +22,7 @@ import Data.Maybe(fromMaybe)
|
|||||||
-- Type Evaluation -------------------------------------------------------------
|
-- Type Evaluation -------------------------------------------------------------
|
||||||
|
|
||||||
-- | Evaluation for types.
|
-- | Evaluation for types.
|
||||||
evalType :: EvalEnv -> Type -> TValue
|
evalType :: GenEvalEnv b w -> Type -> TValue
|
||||||
evalType env = TValue . go
|
evalType env = TValue . go
|
||||||
where
|
where
|
||||||
go ty =
|
go ty =
|
||||||
|
@ -9,6 +9,7 @@
|
|||||||
{-# LANGUAGE PatternGuards #-}
|
{-# LANGUAGE PatternGuards #-}
|
||||||
{-# LANGUAGE DeriveFunctor #-}
|
{-# LANGUAGE DeriveFunctor #-}
|
||||||
{-# LANGUAGE DeriveGeneric #-}
|
{-# LANGUAGE DeriveGeneric #-}
|
||||||
|
{-# LANGUAGE FunctionalDependencies #-}
|
||||||
{-# LANGUAGE FlexibleInstances #-}
|
{-# LANGUAGE FlexibleInstances #-}
|
||||||
{-# LANGUAGE MultiParamTypeClasses #-}
|
{-# LANGUAGE MultiParamTypeClasses #-}
|
||||||
{-# LANGUAGE Safe #-}
|
{-# LANGUAGE Safe #-}
|
||||||
@ -99,6 +100,17 @@ data BV = BV !Integer !Integer deriving (Generic)
|
|||||||
instance Show BV where
|
instance Show BV where
|
||||||
show = show . bvVal
|
show = show . bvVal
|
||||||
|
|
||||||
|
-- | Apply an integer function to the values of bitvectors.
|
||||||
|
-- This function assumes both bitvectors are the same width,
|
||||||
|
-- and the result of the function will not require masking.
|
||||||
|
binBV :: (Integer -> Integer -> Integer) -> BV -> BV -> BV
|
||||||
|
binBV f (BV w x) (BV _ y) = BV w (f x y)
|
||||||
|
|
||||||
|
-- | Apply an integer function to the values of a bitvector.
|
||||||
|
-- This function assumes the function will not require masking.
|
||||||
|
unaryBV :: (Integer -> Integer) -> BV -> BV
|
||||||
|
unaryBV f (BV w x) = BV w $ f x
|
||||||
|
|
||||||
bvVal :: BV -> Integer
|
bvVal :: BV -> Integer
|
||||||
bvVal (BV _w x) = x
|
bvVal (BV _w x) = x
|
||||||
|
|
||||||
@ -227,10 +239,14 @@ atFst f (x,y) = fmap (,y) $ f x
|
|||||||
atSnd :: Functor f => (a -> f b) -> (c, a) -> f (c, b)
|
atSnd :: Functor f => (a -> f b) -> (c, a) -> f (c, b)
|
||||||
atSnd f (x,y) = fmap (x,) $ f y
|
atSnd f (x,y) = fmap (x,) $ f y
|
||||||
|
|
||||||
ppValue :: PPOpts -> Value -> Eval Doc
|
ppValue :: forall b w
|
||||||
|
. BitWord b w
|
||||||
|
=> PPOpts
|
||||||
|
-> GenValue b w
|
||||||
|
-> Eval Doc
|
||||||
ppValue opts = loop
|
ppValue opts = loop
|
||||||
where
|
where
|
||||||
loop :: Value -> Eval Doc
|
loop :: GenValue b w -> Eval Doc
|
||||||
loop val = case val of
|
loop val = case val of
|
||||||
VRecord fs -> do fs' <- traverse (atSnd (>>=loop)) $ fs
|
VRecord fs -> do fs' <- traverse (atSnd (>>=loop)) $ fs
|
||||||
return $ braces (sep (punctuate comma (map ppField fs')))
|
return $ braces (sep (punctuate comma (map ppField fs')))
|
||||||
@ -238,8 +254,7 @@ ppValue opts = loop
|
|||||||
ppField (f,r) = pp f <+> char '=' <+> r
|
ppField (f,r) = pp f <+> char '=' <+> r
|
||||||
VTuple vals -> do vals' <- traverse (>>=loop) vals
|
VTuple vals -> do vals' <- traverse (>>=loop) vals
|
||||||
return $ parens (sep (punctuate comma vals'))
|
return $ parens (sep (punctuate comma vals'))
|
||||||
VBit b | b -> return $ text "True"
|
VBit b -> return $ ppBit b
|
||||||
| otherwise -> return $ text "False"
|
|
||||||
VSeq sz isWord vals
|
VSeq sz isWord vals
|
||||||
| isWord -> ppWord opts <$> fromVWord "ppValue" val
|
| isWord -> ppWord opts <$> fromVWord "ppValue" val
|
||||||
| otherwise -> ppWordSeq sz vals
|
| otherwise -> ppWordSeq sz vals
|
||||||
@ -252,13 +267,17 @@ ppValue opts = loop
|
|||||||
VFun _ -> return $ text "<function>"
|
VFun _ -> return $ text "<function>"
|
||||||
VPoly _ -> return $ text "<polymorphic value>"
|
VPoly _ -> return $ text "<polymorphic value>"
|
||||||
|
|
||||||
ppWordSeq :: Integer -> SeqValMap -> Eval Doc
|
ppWordSeq :: Integer -> SeqMap b w -> Eval Doc
|
||||||
ppWordSeq sz vals = do
|
ppWordSeq sz vals = do
|
||||||
ws <- sequence (enumerateSeqMap sz vals)
|
ws <- sequence (enumerateSeqMap sz vals)
|
||||||
case ws of
|
case ws of
|
||||||
w : _
|
w : _
|
||||||
| Just l <- vWordLen w, asciiMode opts l ->
|
| Just l <- vWordLen w
|
||||||
text . show . map (integerToChar . bvVal) <$> traverse (fromVWord "ppWordSeq") ws
|
, asciiMode opts l
|
||||||
|
-> do vs <- traverse (fromVWord "ppWordSeq") ws
|
||||||
|
case traverse wordAsChar vs of
|
||||||
|
Just str -> return $ text str
|
||||||
|
_ -> return $ brackets (fsep (punctuate comma $ map (ppWord opts) vs))
|
||||||
_ -> do ws' <- traverse loop ws
|
_ -> do ws' <- traverse loop ws
|
||||||
return $ brackets (fsep (punctuate comma ws'))
|
return $ brackets (fsep (punctuate comma ws'))
|
||||||
|
|
||||||
@ -268,14 +287,9 @@ asciiMode opts width = useAscii opts && (width == 7 || width == 8)
|
|||||||
integerToChar :: Integer -> Char
|
integerToChar :: Integer -> Char
|
||||||
integerToChar = toEnum . fromInteger
|
integerToChar = toEnum . fromInteger
|
||||||
|
|
||||||
--data WithBase a = WithBase PPOpts a
|
|
||||||
-- deriving (Functor)
|
|
||||||
|
|
||||||
--instance PP (WithBase Value) where
|
ppBV :: PPOpts -> BV -> Doc
|
||||||
-- ppPrec _ (WithBase opts v) = ppValue opts v
|
ppBV opts (BV width i)
|
||||||
|
|
||||||
ppWord :: PPOpts -> BV -> Doc
|
|
||||||
ppWord opts (BV width i)
|
|
||||||
| base > 36 = integer i -- not sure how to rule this out
|
| base > 36 = integer i -- not sure how to rule this out
|
||||||
| asciiMode opts width = text (show (toEnum (fromInteger i) :: Char))
|
| asciiMode opts width = text (show (toEnum (fromInteger i) :: Char))
|
||||||
| otherwise = prefix <> text value
|
| otherwise = prefix <> text value
|
||||||
@ -303,7 +317,17 @@ ppWord opts (BV width i)
|
|||||||
|
|
||||||
-- Big-endian Words ------------------------------------------------------------
|
-- Big-endian Words ------------------------------------------------------------
|
||||||
|
|
||||||
class BitWord b w where
|
class BitWord b w | b -> w, w -> b where
|
||||||
|
ppBit :: b -> Doc
|
||||||
|
|
||||||
|
ppWord :: PPOpts -> w -> Doc
|
||||||
|
|
||||||
|
wordAsChar :: w -> Maybe Char
|
||||||
|
|
||||||
|
wordLen :: w -> Integer
|
||||||
|
|
||||||
|
bitLit :: Bool -> b
|
||||||
|
wordLit :: Integer -> Integer -> w
|
||||||
|
|
||||||
-- | NOTE this assumes that the sequence of bits is big-endian and finite, so the
|
-- | NOTE this assumes that the sequence of bits is big-endian and finite, so the
|
||||||
-- first element of the list will be the most significant bit.
|
-- first element of the list will be the most significant bit.
|
||||||
@ -313,6 +337,12 @@ class BitWord b w where
|
|||||||
-- most significant bit is the first element of the list.
|
-- most significant bit is the first element of the list.
|
||||||
unpackWord :: w -> [b]
|
unpackWord :: w -> [b]
|
||||||
|
|
||||||
|
class BitWord b w => EvalPrims b w where
|
||||||
|
evalPrim :: Decl -> GenValue b w
|
||||||
|
iteValue :: b
|
||||||
|
-> Eval (GenValue b w)
|
||||||
|
-> Eval (GenValue b w)
|
||||||
|
-> Eval (GenValue b w)
|
||||||
|
|
||||||
mask :: Integer -- ^ Bit-width
|
mask :: Integer -- ^ Bit-width
|
||||||
-> Integer -- ^ Value
|
-> Integer -- ^ Value
|
||||||
@ -322,6 +352,16 @@ mask w i | w >= Arch.maxBigIntWidth = wordTooWide w
|
|||||||
|
|
||||||
|
|
||||||
instance BitWord Bool BV where
|
instance BitWord Bool BV where
|
||||||
|
wordLen (BV w _) = w
|
||||||
|
wordAsChar (BV _ x) = Just $ integerToChar x
|
||||||
|
|
||||||
|
ppBit b | b = text "True"
|
||||||
|
| otherwise = text "False"
|
||||||
|
|
||||||
|
ppWord = ppBV
|
||||||
|
|
||||||
|
bitLit b = b
|
||||||
|
wordLit = mkBv
|
||||||
|
|
||||||
packWord bits = BV (toInteger w) a
|
packWord bits = BV (toInteger w) a
|
||||||
where
|
where
|
||||||
@ -429,9 +469,9 @@ fromVWord msg val = case val of
|
|||||||
VSeq n isWord bs | isWord -> packWord <$> traverse (fromVBit<$>) (enumerateSeqMap n bs)
|
VSeq n isWord bs | isWord -> packWord <$> traverse (fromVBit<$>) (enumerateSeqMap n bs)
|
||||||
_ -> evalPanic "fromVWord" ["not a word", msg]
|
_ -> evalPanic "fromVWord" ["not a word", msg]
|
||||||
|
|
||||||
vWordLen :: Value -> Maybe Integer
|
vWordLen :: BitWord b w => GenValue b w -> Maybe Integer
|
||||||
vWordLen val = case val of
|
vWordLen val = case val of
|
||||||
VWord (BV n _) -> Just n
|
VWord w -> Just (wordLen w)
|
||||||
VSeq n isWord _ | isWord -> Just n
|
VSeq n isWord _ | isWord -> Just n
|
||||||
_ -> Nothing
|
_ -> Nothing
|
||||||
|
|
||||||
|
@ -18,6 +18,7 @@ import Paths_cryptol (getDataDir)
|
|||||||
#endif
|
#endif
|
||||||
|
|
||||||
import Cryptol.Eval (EvalEnv)
|
import Cryptol.Eval (EvalEnv)
|
||||||
|
import Cryptol.Eval.Value (BV)
|
||||||
import Cryptol.ModuleSystem.Interface
|
import Cryptol.ModuleSystem.Interface
|
||||||
import Cryptol.ModuleSystem.Name (Supply,emptySupply)
|
import Cryptol.ModuleSystem.Name (Supply,emptySupply)
|
||||||
import qualified Cryptol.ModuleSystem.NamingEnv as R
|
import qualified Cryptol.ModuleSystem.NamingEnv as R
|
||||||
|
@ -10,7 +10,9 @@
|
|||||||
{-# LANGUAGE DeriveGeneric #-}
|
{-# LANGUAGE DeriveGeneric #-}
|
||||||
module Cryptol.ModuleSystem.Monad where
|
module Cryptol.ModuleSystem.Monad where
|
||||||
|
|
||||||
import Cryptol.Eval.Env (EvalEnv)
|
import Cryptol.Eval (EvalEnv)
|
||||||
|
import Cryptol.Eval.Value (BV)
|
||||||
|
|
||||||
import qualified Cryptol.Eval.Monad as E
|
import qualified Cryptol.Eval.Monad as E
|
||||||
import Cryptol.ModuleSystem.Env
|
import Cryptol.ModuleSystem.Env
|
||||||
import Cryptol.ModuleSystem.Interface
|
import Cryptol.ModuleSystem.Interface
|
||||||
@ -29,6 +31,7 @@ import Cryptol.Parser.Position (Range)
|
|||||||
import Cryptol.Utils.Ident (interactiveName)
|
import Cryptol.Utils.Ident (interactiveName)
|
||||||
import Cryptol.Utils.PP
|
import Cryptol.Utils.PP
|
||||||
|
|
||||||
|
import Control.Monad.IO.Class
|
||||||
import Control.Exception (IOException)
|
import Control.Exception (IOException)
|
||||||
import Data.Function (on)
|
import Data.Function (on)
|
||||||
import Data.Maybe (isJust)
|
import Data.Maybe (isJust)
|
||||||
@ -278,6 +281,9 @@ instance Monad m => FreshM (ModuleT m) where
|
|||||||
set $! me { meSupply = s' }
|
set $! me { meSupply = s' }
|
||||||
return a
|
return a
|
||||||
|
|
||||||
|
instance MonadIO m => MonadIO (ModuleT m) where
|
||||||
|
liftIO m = lift $ liftIO m
|
||||||
|
|
||||||
runModuleT :: Monad m
|
runModuleT :: Monad m
|
||||||
=> ModuleEnv
|
=> ModuleEnv
|
||||||
-> ModuleT m a
|
-> ModuleT m a
|
||||||
|
@ -32,7 +32,7 @@ import Cryptol.Symbolic.Value
|
|||||||
|
|
||||||
import qualified Cryptol.Eval.Value as Eval
|
import qualified Cryptol.Eval.Value as Eval
|
||||||
import qualified Cryptol.Eval.Type (evalType)
|
import qualified Cryptol.Eval.Type (evalType)
|
||||||
import qualified Cryptol.Eval.Env (EvalEnv(..))
|
import qualified Cryptol.Eval.Env (GenEvalEnv(..))
|
||||||
import Cryptol.TypeCheck.AST
|
import Cryptol.TypeCheck.AST
|
||||||
import Cryptol.TypeCheck.Solver.InfNat (Nat'(..))
|
import Cryptol.TypeCheck.Solver.InfNat (Nat'(..))
|
||||||
import Cryptol.Utils.Ident (Ident)
|
import Cryptol.Utils.Ident (Ident)
|
||||||
|
Loading…
Reference in New Issue
Block a user