Start generalizing evaluator code to be used in both the

concrete and symbolic evaluators.
This commit is contained in:
Rob Dockins 2016-05-15 21:28:21 -07:00
parent 6d681f5bb5
commit 122a147085
7 changed files with 89 additions and 42 deletions

View File

@ -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

View File

@ -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)

View File

@ -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 =

View File

@ -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

View File

@ -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

View File

@ -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

View File

@ -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)