cryptol 2.10.0 → 2.11.0
raw patch · 81 files changed
+3775/−2648 lines, 81 filesdep +extradep +optparse-applicativedep +temporarydep ~basedep ~containersdep ~directorynew-component:exe:check-exercisesPVP ok
version bump matches the API change (PVP)
Dependencies added: extra, optparse-applicative, temporary
Dependency ranges changed: base, containers, directory, filepath, libBF, mtl, process, sbv, text, what4
API changes (from Hackage documentation)
- Cryptol.Backend: ppBit :: Backend sym => sym -> SBit sym -> Doc
- Cryptol.Backend: ppFloat :: Backend sym => sym -> PPOpts -> SFloat sym -> Doc
- Cryptol.Backend: ppInteger :: Backend sym => sym -> PPOpts -> SInteger sym -> Doc
- Cryptol.Backend: ppRational :: Backend sym => sym -> PPOpts -> SRational sym -> Doc
- Cryptol.Backend: ppWord :: Backend sym => sym -> PPOpts -> SWord sym -> Doc
- Cryptol.Backend.FloatHelpers: floatFromBits' :: Integer -> Integer -> Integer -> BigFloat
- Cryptol.Backend.Monad: AutoExponent :: PPFloatExp
- Cryptol.Backend.Monad: EvalOpts :: Logger -> PPOpts -> EvalOpts
- Cryptol.Backend.Monad: FloatFixed :: Int -> PPFloatExp -> PPFloatFormat
- Cryptol.Backend.Monad: FloatFrac :: Int -> PPFloatFormat
- Cryptol.Backend.Monad: FloatFree :: PPFloatExp -> PPFloatFormat
- Cryptol.Backend.Monad: ForceExponent :: PPFloatExp
- Cryptol.Backend.Monad: PPOpts :: Bool -> Int -> Int -> Int -> PPFloatFormat -> PPOpts
- Cryptol.Backend.Monad: TypeCannotBeDemoted :: Type -> EvalError
- Cryptol.Backend.Monad: [evalLogger] :: EvalOpts -> Logger
- Cryptol.Backend.Monad: [evalPPOpts] :: EvalOpts -> PPOpts
- Cryptol.Backend.Monad: [useAscii] :: PPOpts -> Bool
- Cryptol.Backend.Monad: [useBase] :: PPOpts -> Int
- Cryptol.Backend.Monad: [useFPBase] :: PPOpts -> Int
- Cryptol.Backend.Monad: [useFPFormat] :: PPOpts -> PPFloatFormat
- Cryptol.Backend.Monad: [useInfLength] :: PPOpts -> Int
- Cryptol.Backend.Monad: asciiMode :: PPOpts -> Integer -> Bool
- Cryptol.Backend.Monad: data EvalOpts
- Cryptol.Backend.Monad: data PPFloatExp
- Cryptol.Backend.Monad: data PPFloatFormat
- Cryptol.Backend.Monad: data PPOpts
- Cryptol.Backend.Monad: defaultPPOpts :: PPOpts
- Cryptol.Backend.Monad: instance Control.Monad.Fail.MonadFail Cryptol.Backend.Monad.Eval
- Cryptol.Backend.Monad: instance Control.Monad.Fix.MonadFix Cryptol.Backend.Monad.Eval
- Cryptol.Backend.Monad: instance GHC.Exception.Type.Exception Cryptol.Backend.Monad.EvalError
- Cryptol.Backend.Monad: typeCannotBeDemoted :: Type -> a
- Cryptol.Backend.What4.SFloat: FPTypeError :: Some BaseTypeRepr -> Some BaseTypeRepr -> FPTypeError
- Cryptol.Backend.What4.SFloat: UnsupportedFloat :: String -> Integer -> UnsupportedFloat
- Cryptol.Backend.What4.SFloat: [SFloat] :: IsExpr (SymExpr sym) => SymFloat sym fpp -> SFloat sym
- Cryptol.Backend.What4.SFloat: [exponentBits, precisionBits] :: UnsupportedFloat -> Integer
- Cryptol.Backend.What4.SFloat: [fpActual] :: FPTypeError -> Some BaseTypeRepr
- Cryptol.Backend.What4.SFloat: [fpExpected] :: FPTypeError -> Some BaseTypeRepr
- Cryptol.Backend.What4.SFloat: [fpWho] :: UnsupportedFloat -> String
- Cryptol.Backend.What4.SFloat: data FPTypeError
- Cryptol.Backend.What4.SFloat: data SFloat sym
- Cryptol.Backend.What4.SFloat: data UnsupportedFloat
- Cryptol.Backend.What4.SFloat: fpAdd :: IsExprBuilder sym => SFloatBinArith sym
- Cryptol.Backend.What4.SFloat: fpDiv :: IsExprBuilder sym => SFloatBinArith sym
- Cryptol.Backend.What4.SFloat: fpEq :: IsExprBuilder sym => SFloatRel sym
- Cryptol.Backend.What4.SFloat: fpEqIEEE :: IsExprBuilder sym => SFloatRel sym
- Cryptol.Backend.What4.SFloat: fpFresh :: IsSymExprBuilder sym => sym -> Integer -> Integer -> IO (SFloat sym)
- Cryptol.Backend.What4.SFloat: fpFromBinary :: IsExprBuilder sym => sym -> Integer -> Integer -> SWord sym -> IO (SFloat sym)
- Cryptol.Backend.What4.SFloat: fpFromInteger :: IsExprBuilder sym => sym -> Integer -> Integer -> RoundingMode -> SymInteger sym -> IO (SFloat sym)
- Cryptol.Backend.What4.SFloat: fpFromRational :: IsExprBuilder sym => sym -> Integer -> Integer -> RoundingMode -> SymInteger sym -> SymInteger sym -> IO (SFloat sym)
- Cryptol.Backend.What4.SFloat: fpFromRationalLit :: IsExprBuilder sym => sym -> Integer -> Integer -> Rational -> IO (SFloat sym)
- Cryptol.Backend.What4.SFloat: fpFromReal :: IsExprBuilder sym => sym -> Integer -> Integer -> RoundingMode -> SymReal sym -> IO (SFloat sym)
- Cryptol.Backend.What4.SFloat: fpGtIEEE :: IsExprBuilder sym => SFloatRel sym
- Cryptol.Backend.What4.SFloat: fpIsInf :: IsExprBuilder sym => sym -> SFloat sym -> IO (Pred sym)
- Cryptol.Backend.What4.SFloat: fpIsNaN :: IsExprBuilder sym => sym -> SFloat sym -> IO (Pred sym)
- Cryptol.Backend.What4.SFloat: fpLtIEEE :: IsExprBuilder sym => SFloatRel sym
- Cryptol.Backend.What4.SFloat: fpMul :: IsExprBuilder sym => SFloatBinArith sym
- Cryptol.Backend.What4.SFloat: fpNaN :: IsExprBuilder sym => sym -> Integer -> Integer -> IO (SFloat sym)
- Cryptol.Backend.What4.SFloat: fpNeg :: IsExprBuilder sym => sym -> SFloat sym -> IO (SFloat sym)
- Cryptol.Backend.What4.SFloat: fpPosInf :: IsExprBuilder sym => sym -> Integer -> Integer -> IO (SFloat sym)
- Cryptol.Backend.What4.SFloat: fpRepr :: Integer -> Integer -> Maybe (Some FloatPrecisionRepr)
- Cryptol.Backend.What4.SFloat: fpReprOf :: IsExpr (SymExpr sym) => sym -> SymFloat sym fpp -> FloatPrecisionRepr fpp
- Cryptol.Backend.What4.SFloat: fpRound :: IsExprBuilder sym => sym -> RoundingMode -> SFloat sym -> IO (SFloat sym)
- Cryptol.Backend.What4.SFloat: fpSize :: SFloat sym -> (Integer, Integer)
- Cryptol.Backend.What4.SFloat: fpSub :: IsExprBuilder sym => SFloatBinArith sym
- Cryptol.Backend.What4.SFloat: fpToBinary :: IsExprBuilder sym => sym -> SFloat sym -> IO (SWord sym)
- Cryptol.Backend.What4.SFloat: fpToRational :: IsSymExprBuilder sym => sym -> SFloat sym -> IO (Pred sym, SymInteger sym, SymInteger sym)
- Cryptol.Backend.What4.SFloat: fpToReal :: IsExprBuilder sym => sym -> SFloat sym -> IO (SymReal sym)
- Cryptol.Backend.What4.SFloat: instance GHC.Exception.Type.Exception Cryptol.Backend.What4.SFloat.FPTypeError
- Cryptol.Backend.What4.SFloat: instance GHC.Exception.Type.Exception Cryptol.Backend.What4.SFloat.UnsupportedFloat
- Cryptol.Backend.What4.SFloat: instance GHC.Show.Show Cryptol.Backend.What4.SFloat.FPTypeError
- Cryptol.Backend.What4.SFloat: instance GHC.Show.Show Cryptol.Backend.What4.SFloat.UnsupportedFloat
- Cryptol.Backend.What4.SFloat: type SFloatBinArith sym = sym -> RoundingMode -> SFloat sym -> SFloat sym -> IO (SFloat sym)
- Cryptol.Backend.What4.SFloat: type SFloatRel sym = sym -> SFloat sym -> SFloat sym -> IO (Pred sym)
- Cryptol.Eval: TypeCannotBeDemoted :: Type -> EvalError
- Cryptol.Eval.Type: type TypeEnv = IntMap (Either Nat' TValue)
- Cryptol.Eval.Value: ppBit :: Backend sym => sym -> SBit sym -> Doc
- Cryptol.Eval.Value: ppFloat :: Backend sym => sym -> PPOpts -> SFloat sym -> Doc
- Cryptol.Eval.Value: ppInteger :: Backend sym => sym -> PPOpts -> SInteger sym -> Doc
- Cryptol.Eval.Value: ppWord :: Backend sym => sym -> PPOpts -> SWord sym -> Doc
- Cryptol.Eval.Value: wlam :: Backend sym => sym -> (SWord sym -> SEval sym (GenValue sym)) -> GenValue sym
- Cryptol.Eval.What4: floatPrims :: IsSymExprBuilder sym => What4 sym -> Map PrimIdent (Value sym)
- Cryptol.ModuleSystem.Name: instance Control.Monad.Fix.MonadFix m => Control.Monad.Fix.MonadFix (Cryptol.ModuleSystem.Name.SupplyT m)
- Cryptol.Testing.Random: TestReport :: TestResult -> String -> Integer -> Maybe Integer -> TestReport
- Cryptol.Testing.Random: [reportProp] :: TestReport -> String
- Cryptol.Testing.Random: [reportResult] :: TestReport -> TestResult
- Cryptol.Testing.Random: [reportTestsPossible] :: TestReport -> Maybe Integer
- Cryptol.Testing.Random: [reportTestsRun] :: TestReport -> Integer
- Cryptol.Testing.Random: data TestReport
- Cryptol.TypeCheck.Monad: instance GHC.Show.Show Cryptol.TypeCheck.Monad.InferInput
- Cryptol.TypeCheck.TCon: TCNewtype :: UserTC -> TC
- Cryptol.TypeCheck.Type: TPOther :: Maybe Name -> TPFlavor
- Cryptol.TypeCheck.Type: newtypeTyCon :: Newtype -> TCon
+ Cryptol.Backend: fpAbs :: Backend sym => sym -> SFloat sym -> SEval sym (SFloat sym)
+ Cryptol.Backend: fpAsLit :: Backend sym => sym -> SFloat sym -> Maybe BF
+ Cryptol.Backend: fpFMA :: Backend sym => sym -> SWord sym -> SFloat sym -> SFloat sym -> SFloat sym -> SEval sym (SFloat sym)
+ Cryptol.Backend: fpFromBits :: Backend sym => sym -> Integer -> Integer -> SWord sym -> SEval sym (SFloat sym)
+ Cryptol.Backend: fpFromRational :: Backend sym => sym -> Integer -> Integer -> SWord sym -> SRational sym -> SEval sym (SFloat sym)
+ Cryptol.Backend: fpIsInf :: Backend sym => sym -> SFloat sym -> SEval sym (SBit sym)
+ Cryptol.Backend: fpIsNaN :: Backend sym => sym -> SFloat sym -> SEval sym (SBit sym)
+ Cryptol.Backend: fpIsNeg :: Backend sym => sym -> SFloat sym -> SEval sym (SBit sym)
+ Cryptol.Backend: fpIsNorm :: Backend sym => sym -> SFloat sym -> SEval sym (SBit sym)
+ Cryptol.Backend: fpIsSubnorm :: Backend sym => sym -> SFloat sym -> SEval sym (SBit sym)
+ Cryptol.Backend: fpIsZero :: Backend sym => sym -> SFloat sym -> SEval sym (SBit sym)
+ Cryptol.Backend: fpNaN :: Backend sym => sym -> Integer -> Integer -> SEval sym (SFloat sym)
+ Cryptol.Backend: fpPosInf :: Backend sym => sym -> Integer -> Integer -> SEval sym (SFloat sym)
+ Cryptol.Backend: fpSqrt :: Backend sym => sym -> SWord sym -> SFloat sym -> SEval sym (SFloat sym)
+ Cryptol.Backend: fpToBits :: Backend sym => sym -> SFloat sym -> SEval sym (SWord sym)
+ Cryptol.Backend: fpToRational :: Backend sym => sym -> SFloat sym -> SEval sym (SRational sym)
+ Cryptol.Backend: iteFloat :: Backend sym => sym -> SBit sym -> SFloat sym -> SFloat sym -> SEval sym (SFloat sym)
+ Cryptol.Backend: sGetCallStack :: Backend sym => sym -> SEval sym CallStack
+ Cryptol.Backend: sModifyCallStack :: Backend sym => sym -> (CallStack -> CallStack) -> SEval sym a -> SEval sym a
+ Cryptol.Backend: sPushFrame :: Backend sym => sym -> Name -> Range -> SEval sym a -> SEval sym a
+ Cryptol.Backend: sWithCallStack :: Backend sym => sym -> CallStack -> SEval sym a -> SEval sym a
+ Cryptol.Backend.Monad: EvalErrorEx :: CallStack -> EvalError -> EvalErrorEx
+ Cryptol.Backend.Monad: combineCallStacks :: CallStack -> CallStack -> CallStack
+ Cryptol.Backend.Monad: data EvalErrorEx
+ Cryptol.Backend.Monad: data WordTooWide
+ Cryptol.Backend.Monad: displayCallStack :: CallStack -> Doc
+ Cryptol.Backend.Monad: getCallStack :: Eval CallStack
+ Cryptol.Backend.Monad: instance Cryptol.Utils.PP.PP Cryptol.Backend.Monad.EvalErrorEx
+ Cryptol.Backend.Monad: instance Cryptol.Utils.PP.PP Cryptol.Backend.Monad.WordTooWide
+ Cryptol.Backend.Monad: instance GHC.Exception.Type.Exception Cryptol.Backend.Monad.EvalErrorEx
+ Cryptol.Backend.Monad: instance GHC.Exception.Type.Exception Cryptol.Backend.Monad.WordTooWide
+ Cryptol.Backend.Monad: instance GHC.Show.Show Cryptol.Backend.Monad.EvalErrorEx
+ Cryptol.Backend.Monad: instance GHC.Show.Show Cryptol.Backend.Monad.WordTooWide
+ Cryptol.Backend.Monad: modifyCallStack :: (CallStack -> CallStack) -> Eval a -> Eval a
+ Cryptol.Backend.Monad: pushCallFrame :: Name -> Range -> CallStack -> CallStack
+ Cryptol.Backend.Monad: type CallStack = Seq (Name, Range)
+ Cryptol.Backend.Monad: withCallStack :: CallStack -> Eval a -> Eval a
+ Cryptol.Eval: EvalErrorEx :: CallStack -> EvalError -> EvalErrorEx
+ Cryptol.Eval: data EvalErrorEx
+ Cryptol.Eval: data WordTooWide
+ Cryptol.Eval: evalNewtypeDecls :: EvalPrims sym => sym -> Map Name Newtype -> GenEvalEnv sym -> SEval sym (GenEvalEnv sym)
+ Cryptol.Eval.Generic: fpConst :: Backend sym => (Integer -> Integer -> SEval sym (SFloat sym)) -> Prim sym
+ Cryptol.Eval.Generic: fromToLessThanV :: Backend sym => sym -> Prim sym
+ Cryptol.Eval.Generic: genericFloatTable :: Backend sym => sym -> Map PrimIdent (Prim sym)
+ Cryptol.Eval.Generic: genericPrimTable :: Backend sym => sym -> IO EvalOpts -> Map PrimIdent (Prim sym)
+ Cryptol.Eval.Prims: PFinPoly :: (Integer -> Prim sym) -> Prim sym
+ Cryptol.Eval.Prims: PFloatFun :: (SFloat sym -> Prim sym) -> Prim sym
+ Cryptol.Eval.Prims: PFun :: (SEval sym (GenValue sym) -> Prim sym) -> Prim sym
+ Cryptol.Eval.Prims: PNumPoly :: (Nat' -> Prim sym) -> Prim sym
+ Cryptol.Eval.Prims: PPrim :: SEval sym (GenValue sym) -> Prim sym
+ Cryptol.Eval.Prims: PStrict :: (GenValue sym -> Prim sym) -> Prim sym
+ Cryptol.Eval.Prims: PTyPoly :: (TValue -> Prim sym) -> Prim sym
+ Cryptol.Eval.Prims: PVal :: GenValue sym -> Prim sym
+ Cryptol.Eval.Prims: PWordFun :: (SWord sym -> Prim sym) -> Prim sym
+ Cryptol.Eval.Prims: data Prim sym
+ Cryptol.Eval.Prims: evalPrim :: Backend sym => sym -> Name -> Prim sym -> SEval sym (GenValue sym)
+ Cryptol.Eval.Type: TVNewtype :: Newtype -> [Either Nat' TValue] -> RecordMap Ident TValue -> TValue
+ Cryptol.Eval.Type: TypeEnv :: IntMap (Either Nat' TValue) -> TypeEnv
+ Cryptol.Eval.Type: [envTypeMap] :: TypeEnv -> IntMap (Either Nat' TValue)
+ Cryptol.Eval.Type: bindTypeVar :: TVar -> Either Nat' TValue -> TypeEnv -> TypeEnv
+ Cryptol.Eval.Type: evalNewtypeBody :: TypeEnv -> Newtype -> [Either Nat' TValue] -> RecordMap Ident TValue
+ Cryptol.Eval.Type: instance GHC.Base.Monoid Cryptol.Eval.Type.TypeEnv
+ Cryptol.Eval.Type: instance GHC.Base.Semigroup Cryptol.Eval.Type.TypeEnv
+ Cryptol.Eval.Type: instance GHC.Classes.Eq Cryptol.Eval.Type.TValue
+ Cryptol.Eval.Type: lookupTypeVar :: TVar -> TypeEnv -> Maybe (Either Nat' TValue)
+ Cryptol.Eval.Type: newtype TypeEnv
+ Cryptol.Eval.Type: tNumTy :: Nat' -> Type
+ Cryptol.Eval.Type: tNumValTy :: Either Nat' TValue -> Type
+ Cryptol.Eval.Value: EvalOpts :: Logger -> PPOpts -> EvalOpts
+ Cryptol.Eval.Value: [evalLogger] :: EvalOpts -> Logger
+ Cryptol.Eval.Value: [evalPPOpts] :: EvalOpts -> PPOpts
+ Cryptol.Eval.Value: data EvalOpts
+ Cryptol.Eval.Value: fpAbs :: Backend sym => sym -> SFloat sym -> SEval sym (SFloat sym)
+ Cryptol.Eval.Value: fpAsLit :: Backend sym => sym -> SFloat sym -> Maybe BF
+ Cryptol.Eval.Value: fpFMA :: Backend sym => sym -> SWord sym -> SFloat sym -> SFloat sym -> SFloat sym -> SEval sym (SFloat sym)
+ Cryptol.Eval.Value: fpFromBits :: Backend sym => sym -> Integer -> Integer -> SWord sym -> SEval sym (SFloat sym)
+ Cryptol.Eval.Value: fpFromRational :: Backend sym => sym -> Integer -> Integer -> SWord sym -> SRational sym -> SEval sym (SFloat sym)
+ Cryptol.Eval.Value: fpIsInf :: Backend sym => sym -> SFloat sym -> SEval sym (SBit sym)
+ Cryptol.Eval.Value: fpIsNaN :: Backend sym => sym -> SFloat sym -> SEval sym (SBit sym)
+ Cryptol.Eval.Value: fpIsNeg :: Backend sym => sym -> SFloat sym -> SEval sym (SBit sym)
+ Cryptol.Eval.Value: fpIsNorm :: Backend sym => sym -> SFloat sym -> SEval sym (SBit sym)
+ Cryptol.Eval.Value: fpIsSubnorm :: Backend sym => sym -> SFloat sym -> SEval sym (SBit sym)
+ Cryptol.Eval.Value: fpIsZero :: Backend sym => sym -> SFloat sym -> SEval sym (SBit sym)
+ Cryptol.Eval.Value: fpNaN :: Backend sym => sym -> Integer -> Integer -> SEval sym (SFloat sym)
+ Cryptol.Eval.Value: fpPosInf :: Backend sym => sym -> Integer -> Integer -> SEval sym (SFloat sym)
+ Cryptol.Eval.Value: fpSqrt :: Backend sym => sym -> SWord sym -> SFloat sym -> SEval sym (SFloat sym)
+ Cryptol.Eval.Value: fpToBits :: Backend sym => sym -> SFloat sym -> SEval sym (SWord sym)
+ Cryptol.Eval.Value: fpToRational :: Backend sym => sym -> SFloat sym -> SEval sym (SRational sym)
+ Cryptol.Eval.Value: iteFloat :: Backend sym => sym -> SBit sym -> SFloat sym -> SFloat sym -> SEval sym (SFloat sym)
+ Cryptol.Eval.Value: sGetCallStack :: Backend sym => sym -> SEval sym CallStack
+ Cryptol.Eval.Value: sModifyCallStack :: Backend sym => sym -> (CallStack -> CallStack) -> SEval sym a -> SEval sym a
+ Cryptol.Eval.Value: sPushFrame :: Backend sym => sym -> Name -> Range -> SEval sym a -> SEval sym a
+ Cryptol.Eval.Value: sWithCallStack :: Backend sym => sym -> CallStack -> SEval sym a -> SEval sym a
+ Cryptol.ModuleSystem: ModuleInput :: Bool -> m EvalOpts -> (FilePath -> m ByteString) -> ModuleEnv -> Solver -> ModuleInput m
+ Cryptol.ModuleSystem: [minpByteReader] :: ModuleInput m -> FilePath -> m ByteString
+ Cryptol.ModuleSystem: [minpCallStacks] :: ModuleInput m -> Bool
+ Cryptol.ModuleSystem: [minpEvalOpts] :: ModuleInput m -> m EvalOpts
+ Cryptol.ModuleSystem: [minpModuleEnv] :: ModuleInput m -> ModuleEnv
+ Cryptol.ModuleSystem: [minpTCSolver] :: ModuleInput m -> Solver
+ Cryptol.ModuleSystem: data ModuleInput m
+ Cryptol.ModuleSystem.Env: loadedNewtypes :: ModuleEnv -> Map Name IfaceNewtype
+ Cryptol.ModuleSystem.Monad: ModuleInput :: Bool -> m EvalOpts -> (FilePath -> m ByteString) -> ModuleEnv -> Solver -> ModuleInput m
+ Cryptol.ModuleSystem.Monad: [minpByteReader] :: ModuleInput m -> FilePath -> m ByteString
+ Cryptol.ModuleSystem.Monad: [minpCallStacks] :: ModuleInput m -> Bool
+ Cryptol.ModuleSystem.Monad: [minpEvalOpts] :: ModuleInput m -> m EvalOpts
+ Cryptol.ModuleSystem.Monad: [minpModuleEnv] :: ModuleInput m -> ModuleEnv
+ Cryptol.ModuleSystem.Monad: [minpTCSolver] :: ModuleInput m -> Solver
+ Cryptol.ModuleSystem.Monad: [roCallStacks] :: RO m -> Bool
+ Cryptol.ModuleSystem.Monad: [roTCSolver] :: RO m -> Solver
+ Cryptol.ModuleSystem.Monad: data ModuleInput m
+ Cryptol.ModuleSystem.Monad: getCallStacks :: Monad m => ModuleT m Bool
+ Cryptol.ModuleSystem.Monad: getEvalOptsAction :: ModuleM (IO EvalOpts)
+ Cryptol.ModuleSystem.Monad: getNewtypes :: ModuleM (Map Name Newtype)
+ Cryptol.ModuleSystem.Monad: getTCSolver :: Monad m => ModuleT m Solver
+ Cryptol.ModuleSystem.Renamer: instance Cryptol.ModuleSystem.Renamer.Rename Cryptol.Parser.AST.FunDesc
+ Cryptol.Parser: [cfgStart] :: Config -> !Position
+ Cryptol.Parser.AST: EFromToLessThan :: Type n -> Type n -> Maybe (Type n) -> Expr n
+ Cryptol.Parser.AST: FunDesc :: Maybe n -> Int -> FunDesc n
+ Cryptol.Parser.AST: [funDescrArgOffset] :: FunDesc n -> Int
+ Cryptol.Parser.AST: [funDescrName] :: FunDesc n -> Maybe n
+ Cryptol.Parser.AST: data FunDesc n
+ Cryptol.Parser.AST: emptyFunDesc :: FunDesc n
+ Cryptol.Parser.AST: instance Control.DeepSeq.NFData n => Control.DeepSeq.NFData (Cryptol.Parser.AST.FunDesc n)
+ Cryptol.Parser.AST: instance GHC.Base.Functor Cryptol.Parser.AST.FunDesc
+ Cryptol.Parser.AST: instance GHC.Classes.Eq n => GHC.Classes.Eq (Cryptol.Parser.AST.FunDesc n)
+ Cryptol.Parser.AST: instance GHC.Generics.Generic (Cryptol.Parser.AST.FunDesc n)
+ Cryptol.Parser.AST: instance GHC.Show.Show n => GHC.Show.Show (Cryptol.Parser.AST.FunDesc n)
+ Cryptol.Parser.Lexer: DotDotLt :: TokenSym
+ Cryptol.Parser.Lexer: Lt :: TokenSym
+ Cryptol.Parser.Lexer: [cfgStart] :: Config -> !Position
+ Cryptol.Parser.Position: rCombMaybe :: Maybe Range -> Maybe Range -> Maybe Range
+ Cryptol.REPL.Command: TestReport :: Doc -> TestResult -> Integer -> Maybe Integer -> TestReport
+ Cryptol.REPL.Command: [reportExpr] :: TestReport -> Doc
+ Cryptol.REPL.Command: [reportResult] :: TestReport -> TestResult
+ Cryptol.REPL.Command: [reportTestsPossible] :: TestReport -> Maybe Integer
+ Cryptol.REPL.Command: [reportTestsRun] :: TestReport -> Integer
+ Cryptol.REPL.Command: data TestReport
+ Cryptol.REPL.Command: qcExpr :: QCMode -> Doc -> Expr -> Schema -> REPL TestReport
+ Cryptol.REPL.Monad: TooWide :: WordTooWide -> REPLException
+ Cryptol.REPL.Monad: [optAliases] :: OptionDescr -> [String]
+ Cryptol.REPL.Monad: getCallStacks :: REPL Bool
+ Cryptol.REPL.Monad: getEvalOptsAction :: REPL (IO EvalOpts)
+ Cryptol.REPL.Monad: getPPValOpts :: REPL PPOpts
+ Cryptol.REPL.Monad: userOptionsWithAliases :: OptionMap
+ Cryptol.Symbolic: FTNewtype :: Newtype -> [Either Nat' TValue] -> RecordMap Ident FinType -> FinType
+ Cryptol.TypeCheck: BadParameterKind :: TParam -> Kind -> Error
+ Cryptol.TypeCheck: BareTypeApp :: Error
+ Cryptol.TypeCheck: [inpCallStacks] :: InferInput -> Bool
+ Cryptol.TypeCheck: [inpSolver] :: InferInput -> Solver
+ Cryptol.TypeCheck.AST: ELocated :: Range -> Expr -> Expr
+ Cryptol.TypeCheck.AST: instance Cryptol.Parser.Position.HasLoc Cryptol.TypeCheck.AST.Expr
+ Cryptol.TypeCheck.Error: BadParameterKind :: TParam -> Kind -> Error
+ Cryptol.TypeCheck.Error: BareTypeApp :: Error
+ Cryptol.TypeCheck.InferTypes: [literalLessThanGoals] :: Goals -> Map TVar LitGoal
+ Cryptol.TypeCheck.InferTypes: goalToLitLessThanGoal :: Goal -> Maybe (TVar, LitGoal)
+ Cryptol.TypeCheck.InferTypes: litLessThanGoalToGoal :: (TVar, LitGoal) -> Goal
+ Cryptol.TypeCheck.Monad: [iCallStacks] :: RO -> Bool
+ Cryptol.TypeCheck.Monad: [inpCallStacks] :: InferInput -> Bool
+ Cryptol.TypeCheck.Monad: [inpSolver] :: InferInput -> Solver
+ Cryptol.TypeCheck.Monad: checkParamKind :: TParam -> TPFlavor -> Kind -> InferM ()
+ Cryptol.TypeCheck.Monad: getCallStacks :: InferM Bool
+ Cryptol.TypeCheck.Solver.Class: solveLiteralLessThanInst :: Type -> Type -> Solved
+ Cryptol.TypeCheck.Solver.SMT: startSolver :: SolverConfig -> IO Solver
+ Cryptol.TypeCheck.Solver.SMT: stopSolver :: Solver -> IO ()
+ Cryptol.TypeCheck.TCon: PLiteralLessThan :: PC
+ Cryptol.TypeCheck.Type: TNewtype :: !Newtype -> ![Type] -> Type
+ Cryptol.TypeCheck.Type: TPNewtypeParam :: Name -> TPFlavor
+ Cryptol.TypeCheck.Type: TPPrimParam :: Name -> TPFlavor
+ Cryptol.TypeCheck.Type: TPPropSynParam :: Name -> TPFlavor
+ Cryptol.TypeCheck.Type: TPSchemaParam :: Name -> TPFlavor
+ Cryptol.TypeCheck.Type: TPTySynParam :: Name -> TPFlavor
+ Cryptol.TypeCheck.Type: TPUnifyVar :: TPFlavor
+ Cryptol.TypeCheck.Type: instance GHC.Classes.Eq Cryptol.TypeCheck.Type.Newtype
+ Cryptol.TypeCheck.Type: instance GHC.Classes.Ord Cryptol.TypeCheck.Type.Newtype
+ Cryptol.TypeCheck.Type: pIsLiteralLessThan :: Prop -> Maybe (Type, Type)
+ Cryptol.TypeCheck.Type: pLiteralLessThan :: Type -> Type -> Prop
+ Cryptol.TypeCheck.Type: tNewtype :: Newtype -> [Type] -> Type
+ Cryptol.TypeCheck.TypeMap: [tnewtype] :: TypeMap a -> Map Newtype (List TypeMap a)
+ Cryptol.TypeCheck.TypePat: aLiteralLessThan :: Pat Prop (Type, Type)
+ Cryptol.Utils.PP: AutoExponent :: PPFloatExp
+ Cryptol.Utils.PP: FloatFixed :: Int -> PPFloatExp -> PPFloatFormat
+ Cryptol.Utils.PP: FloatFrac :: Int -> PPFloatFormat
+ Cryptol.Utils.PP: FloatFree :: PPFloatExp -> PPFloatFormat
+ Cryptol.Utils.PP: ForceExponent :: PPFloatExp
+ Cryptol.Utils.PP: PPOpts :: Bool -> Int -> Int -> Int -> PPFloatFormat -> PPOpts
+ Cryptol.Utils.PP: [useAscii] :: PPOpts -> Bool
+ Cryptol.Utils.PP: [useBase] :: PPOpts -> Int
+ Cryptol.Utils.PP: [useFPBase] :: PPOpts -> Int
+ Cryptol.Utils.PP: [useFPFormat] :: PPOpts -> PPFloatFormat
+ Cryptol.Utils.PP: [useInfLength] :: PPOpts -> Int
+ Cryptol.Utils.PP: asciiMode :: PPOpts -> Integer -> Bool
+ Cryptol.Utils.PP: data PPFloatExp
+ Cryptol.Utils.PP: data PPFloatFormat
+ Cryptol.Utils.PP: data PPOpts
+ Cryptol.Utils.PP: defaultPPOpts :: PPOpts
+ Cryptol.Utils.PP: instance GHC.Show.Show Cryptol.Utils.PP.PPFloatExp
+ Cryptol.Utils.PP: instance GHC.Show.Show Cryptol.Utils.PP.PPFloatFormat
+ Cryptol.Utils.PP: instance GHC.Show.Show Cryptol.Utils.PP.PPOpts
- Cryptol.Backend: sDelay :: Backend sym => sym -> Maybe String -> SEval sym a -> SEval sym (SEval sym a)
+ Cryptol.Backend: sDelay :: Backend sym => sym -> SEval sym a -> SEval sym (SEval sym a)
- Cryptol.Backend: sDelayFill :: Backend sym => sym -> SEval sym a -> SEval sym a -> SEval sym (SEval sym a)
+ Cryptol.Backend: sDelayFill :: Backend sym => sym -> SEval sym a -> Maybe (SEval sym a) -> String -> SEval sym (SEval sym a)
- Cryptol.Backend.FloatHelpers: BF :: Integer -> Integer -> BigFloat -> BF
+ Cryptol.Backend.FloatHelpers: BF :: !Integer -> !Integer -> !BigFloat -> BF
- Cryptol.Backend.FloatHelpers: [bfExpWidth] :: BF -> Integer
+ Cryptol.Backend.FloatHelpers: [bfExpWidth] :: BF -> !Integer
- Cryptol.Backend.FloatHelpers: [bfPrecWidth] :: BF -> Integer
+ Cryptol.Backend.FloatHelpers: [bfPrecWidth] :: BF -> !Integer
- Cryptol.Backend.FloatHelpers: [bfValue] :: BF -> BigFloat
+ Cryptol.Backend.FloatHelpers: [bfValue] :: BF -> !BigFloat
- Cryptol.Backend.Monad: Eval :: !IO a -> Eval a
+ Cryptol.Backend.Monad: Eval :: !CallStack -> IO a -> Eval a
- Cryptol.Backend.Monad: WordTooWide :: Integer -> EvalError
+ Cryptol.Backend.Monad: WordTooWide :: Integer -> WordTooWide
- Cryptol.Backend.Monad: delayFill :: Eval a -> Eval a -> Eval (Eval a)
+ Cryptol.Backend.Monad: delayFill :: Eval a -> Maybe (Eval a) -> String -> Eval (Eval a)
- Cryptol.Backend.Monad: runEval :: Eval a -> IO a
+ Cryptol.Backend.Monad: runEval :: CallStack -> Eval a -> IO a
- Cryptol.Backend.SBV: SBVError :: !EvalError -> SBVResult a
+ Cryptol.Backend.SBV: SBVError :: !EvalErrorEx -> SBVResult a
- Cryptol.Backend.What4: W4Error :: !EvalError -> W4Result sym a
+ Cryptol.Backend.What4: W4Error :: !EvalErrorEx -> W4Result sym a
- Cryptol.Eval: WordTooWide :: Integer -> EvalError
+ Cryptol.Eval: WordTooWide :: Integer -> WordTooWide
- Cryptol.Eval: evalExpr :: EvalPrims sym => sym -> GenEvalEnv sym -> Expr -> SEval sym (GenValue sym)
+ Cryptol.Eval: evalExpr :: (?range :: Range, EvalPrims sym) => sym -> GenEvalEnv sym -> Expr -> SEval sym (GenValue sym)
- Cryptol.Eval: evalSel :: EvalPrims sym => sym -> GenValue sym -> Selector -> SEval sym (GenValue sym)
+ Cryptol.Eval: evalSel :: Backend sym => sym -> GenValue sym -> Selector -> SEval sym (GenValue sym)
- Cryptol.Eval: evalSetSel :: forall sym. EvalPrims sym => sym -> TValue -> GenValue sym -> Selector -> SEval sym (GenValue sym) -> SEval sym (GenValue sym)
+ Cryptol.Eval: evalSetSel :: forall sym. Backend sym => sym -> TValue -> GenValue sym -> Selector -> SEval sym (GenValue sym) -> SEval sym (GenValue sym)
- Cryptol.Eval: runEval :: Eval a -> IO a
+ Cryptol.Eval: runEval :: CallStack -> Eval a -> IO a
- Cryptol.Eval.Concrete: primTable :: EvalOpts -> Map PrimIdent Value
+ Cryptol.Eval.Concrete: primTable :: IO EvalOpts -> Map PrimIdent (Prim Concrete)
- Cryptol.Eval.Concrete: toExpr :: PrimMap -> Type -> Value -> Eval (Maybe Expr)
+ Cryptol.Eval.Concrete: toExpr :: PrimMap -> TValue -> Value -> Eval (Maybe Expr)
- Cryptol.Eval.Env: EvalEnv :: !IntMap (SEval sym (GenValue sym)) -> !TypeEnv -> GenEvalEnv sym
+ Cryptol.Eval.Env: EvalEnv :: !IntMap (Either (Prim sym) (SEval sym (GenValue sym))) -> !TypeEnv -> GenEvalEnv sym
- Cryptol.Eval.Env: [envVars] :: GenEvalEnv sym -> !IntMap (SEval sym (GenValue sym))
+ Cryptol.Eval.Env: [envVars] :: GenEvalEnv sym -> !IntMap (Either (Prim sym) (SEval sym (GenValue sym)))
- Cryptol.Eval.Env: bindVarDirect :: Backend sym => Name -> GenValue sym -> GenEvalEnv sym -> GenEvalEnv sym
+ Cryptol.Eval.Env: bindVarDirect :: Backend sym => Name -> Prim sym -> GenEvalEnv sym -> GenEvalEnv sym
- Cryptol.Eval.Env: lookupVar :: Name -> GenEvalEnv sym -> Maybe (SEval sym (GenValue sym))
+ Cryptol.Eval.Env: lookupVar :: Name -> GenEvalEnv sym -> Maybe (Either (Prim sym) (SEval sym (GenValue sym)))
- Cryptol.Eval.Generic: binary :: Backend sym => Binary sym -> GenValue sym
+ Cryptol.Eval.Generic: binary :: Backend sym => Binary sym -> Prim sym
- Cryptol.Eval.Generic: ecFractionV :: Backend sym => sym -> GenValue sym
+ Cryptol.Eval.Generic: ecFractionV :: Backend sym => sym -> Prim sym
- Cryptol.Eval.Generic: ecNumberV :: Backend sym => sym -> GenValue sym
+ Cryptol.Eval.Generic: ecNumberV :: Backend sym => sym -> Prim sym
- Cryptol.Eval.Generic: ecSplitV :: Backend sym => sym -> GenValue sym
+ Cryptol.Eval.Generic: ecSplitV :: Backend sym => sym -> Prim sym
- Cryptol.Eval.Generic: expV :: Backend sym => sym -> GenValue sym
+ Cryptol.Eval.Generic: expV :: Backend sym => sym -> Prim sym
- Cryptol.Eval.Generic: fieldDivideV :: Backend sym => sym -> GenValue sym
+ Cryptol.Eval.Generic: fieldDivideV :: Backend sym => sym -> Prim sym
- Cryptol.Eval.Generic: foldl'V :: Backend sym => sym -> GenValue sym
+ Cryptol.Eval.Generic: foldl'V :: Backend sym => sym -> Prim sym
- Cryptol.Eval.Generic: foldlV :: Backend sym => sym -> GenValue sym
+ Cryptol.Eval.Generic: foldlV :: Backend sym => sym -> Prim sym
- Cryptol.Eval.Generic: fpBinArithV :: Backend sym => sym -> FPArith2 sym -> GenValue sym
+ Cryptol.Eval.Generic: fpBinArithV :: Backend sym => sym -> FPArith2 sym -> Prim sym
- Cryptol.Eval.Generic: fromIntegerV :: Backend sym => sym -> GenValue sym
+ Cryptol.Eval.Generic: fromIntegerV :: Backend sym => sym -> Prim sym
- Cryptol.Eval.Generic: fromThenToV :: Backend sym => sym -> GenValue sym
+ Cryptol.Eval.Generic: fromThenToV :: Backend sym => sym -> Prim sym
- Cryptol.Eval.Generic: fromToV :: Backend sym => sym -> GenValue sym
+ Cryptol.Eval.Generic: fromToV :: Backend sym => sym -> Prim sym
- Cryptol.Eval.Generic: fromZV :: Backend sym => sym -> GenValue sym
+ Cryptol.Eval.Generic: fromZV :: Backend sym => sym -> Prim sym
- Cryptol.Eval.Generic: indexPrim :: Backend sym => sym -> (Nat' -> TValue -> SeqMap sym -> TValue -> SInteger sym -> SEval sym (GenValue sym)) -> (Nat' -> TValue -> SeqMap sym -> TValue -> [SBit sym] -> SEval sym (GenValue sym)) -> (Nat' -> TValue -> SeqMap sym -> TValue -> SWord sym -> SEval sym (GenValue sym)) -> GenValue sym
+ Cryptol.Eval.Generic: indexPrim :: Backend sym => sym -> (Nat' -> TValue -> SeqMap sym -> TValue -> SInteger sym -> SEval sym (GenValue sym)) -> (Nat' -> TValue -> SeqMap sym -> TValue -> [SBit sym] -> SEval sym (GenValue sym)) -> (Nat' -> TValue -> SeqMap sym -> TValue -> SWord sym -> SEval sym (GenValue sym)) -> Prim sym
- Cryptol.Eval.Generic: infFromThenV :: Backend sym => sym -> GenValue sym
+ Cryptol.Eval.Generic: infFromThenV :: Backend sym => sym -> Prim sym
- Cryptol.Eval.Generic: infFromV :: Backend sym => sym -> GenValue sym
+ Cryptol.Eval.Generic: infFromV :: Backend sym => sym -> Prim sym
- Cryptol.Eval.Generic: lg2V :: Backend sym => sym -> GenValue sym
+ Cryptol.Eval.Generic: lg2V :: Backend sym => sym -> Prim sym
- Cryptol.Eval.Generic: logicShift :: Backend sym => sym -> String -> (sym -> Nat' -> TValue -> SInteger sym -> SEval sym (SInteger sym)) -> (SWord sym -> SWord sym -> SEval sym (SWord sym)) -> (SWord sym -> SWord sym -> SEval sym (SWord sym)) -> (Nat' -> Integer -> Integer -> Maybe Integer) -> (Nat' -> Integer -> Integer -> Maybe Integer) -> GenValue sym
+ Cryptol.Eval.Generic: logicShift :: Backend sym => sym -> String -> (sym -> Nat' -> TValue -> SInteger sym -> SEval sym (SInteger sym)) -> (SWord sym -> SWord sym -> SEval sym (SWord sym)) -> (SWord sym -> SWord sym -> SEval sym (SWord sym)) -> (Nat' -> Integer -> Integer -> Maybe Integer) -> (Nat' -> Integer -> Integer -> Maybe Integer) -> Prim sym
- Cryptol.Eval.Generic: parmapV :: Backend sym => sym -> GenValue sym
+ Cryptol.Eval.Generic: parmapV :: Backend sym => sym -> Prim sym
- Cryptol.Eval.Generic: ratioV :: Backend sym => sym -> GenValue sym
+ Cryptol.Eval.Generic: ratioV :: Backend sym => sym -> Prim sym
- Cryptol.Eval.Generic: recipV :: Backend sym => sym -> GenValue sym
+ Cryptol.Eval.Generic: recipV :: Backend sym => sym -> Prim sym
- Cryptol.Eval.Generic: sdivV :: Backend sym => sym -> GenValue sym
+ Cryptol.Eval.Generic: sdivV :: Backend sym => sym -> Prim sym
- Cryptol.Eval.Generic: smodV :: Backend sym => sym -> GenValue sym
+ Cryptol.Eval.Generic: smodV :: Backend sym => sym -> Prim sym
- Cryptol.Eval.Generic: toIntegerV :: Backend sym => sym -> GenValue sym
+ Cryptol.Eval.Generic: toIntegerV :: Backend sym => sym -> Prim sym
- Cryptol.Eval.Generic: unary :: Backend sym => Unary sym -> GenValue sym
+ Cryptol.Eval.Generic: unary :: Backend sym => Unary sym -> Prim sym
- Cryptol.Eval.Generic: updatePrim :: Backend sym => sym -> (Nat' -> TValue -> WordValue sym -> Either (SInteger sym) (WordValue sym) -> SEval sym (GenValue sym) -> SEval sym (WordValue sym)) -> (Nat' -> TValue -> SeqMap sym -> Either (SInteger sym) (WordValue sym) -> SEval sym (GenValue sym) -> SEval sym (SeqMap sym)) -> GenValue sym
+ Cryptol.Eval.Generic: updatePrim :: Backend sym => sym -> (Nat' -> TValue -> WordValue sym -> Either (SInteger sym) (WordValue sym) -> SEval sym (GenValue sym) -> SEval sym (WordValue sym)) -> (Nat' -> TValue -> SeqMap sym -> Either (SInteger sym) (WordValue sym) -> SEval sym (GenValue sym) -> SEval sym (SeqMap sym)) -> Prim sym
- Cryptol.Eval.Generic: wordValUnaryOp :: Backend sym => (SBit sym -> SEval sym (SBit sym)) -> (SWord sym -> SEval sym (SWord sym)) -> WordValue sym -> SEval sym (WordValue sym)
+ Cryptol.Eval.Generic: wordValUnaryOp :: Backend sym => sym -> (SBit sym -> SEval sym (SBit sym)) -> (SWord sym -> SEval sym (SWord sym)) -> WordValue sym -> SEval sym (WordValue sym)
- Cryptol.Eval.SBV: primTable :: SBV -> Map PrimIdent Value
+ Cryptol.Eval.SBV: primTable :: SBV -> IO EvalOpts -> Map PrimIdent (Prim SBV)
- Cryptol.Eval.Value: VFun :: (SEval sym (GenValue sym) -> SEval sym (GenValue sym)) -> GenValue sym
+ Cryptol.Eval.Value: VFun :: CallStack -> (SEval sym (GenValue sym) -> SEval sym (GenValue sym)) -> GenValue sym
- Cryptol.Eval.Value: VNumPoly :: (Nat' -> SEval sym (GenValue sym)) -> GenValue sym
+ Cryptol.Eval.Value: VNumPoly :: CallStack -> (Nat' -> SEval sym (GenValue sym)) -> GenValue sym
- Cryptol.Eval.Value: VPoly :: (TValue -> SEval sym (GenValue sym)) -> GenValue sym
+ Cryptol.Eval.Value: VPoly :: CallStack -> (TValue -> SEval sym (GenValue sym)) -> GenValue sym
- Cryptol.Eval.Value: finiteSeqMap :: Backend sym => sym -> [SEval sym (GenValue sym)] -> SeqMap sym
+ Cryptol.Eval.Value: finiteSeqMap :: [SEval sym (GenValue sym)] -> SeqMap sym
- Cryptol.Eval.Value: flam :: Backend sym => (SFloat sym -> SEval sym (GenValue sym)) -> GenValue sym
+ Cryptol.Eval.Value: flam :: Backend sym => sym -> (SFloat sym -> SEval sym (GenValue sym)) -> SEval sym (GenValue sym)
- Cryptol.Eval.Value: fromVFun :: GenValue sym -> SEval sym (GenValue sym) -> SEval sym (GenValue sym)
+ Cryptol.Eval.Value: fromVFun :: Backend sym => sym -> GenValue sym -> SEval sym (GenValue sym) -> SEval sym (GenValue sym)
- Cryptol.Eval.Value: fromVNumPoly :: GenValue sym -> Nat' -> SEval sym (GenValue sym)
+ Cryptol.Eval.Value: fromVNumPoly :: Backend sym => sym -> GenValue sym -> Nat' -> SEval sym (GenValue sym)
- Cryptol.Eval.Value: fromVPoly :: GenValue sym -> TValue -> SEval sym (GenValue sym)
+ Cryptol.Eval.Value: fromVPoly :: Backend sym => sym -> GenValue sym -> TValue -> SEval sym (GenValue sym)
- Cryptol.Eval.Value: ilam :: Backend sym => (Integer -> GenValue sym) -> GenValue sym
+ Cryptol.Eval.Value: ilam :: Backend sym => sym -> (Integer -> SEval sym (GenValue sym)) -> SEval sym (GenValue sym)
- Cryptol.Eval.Value: infiniteSeqMap :: Backend sym => [SEval sym (GenValue sym)] -> SEval sym (SeqMap sym)
+ Cryptol.Eval.Value: infiniteSeqMap :: Backend sym => sym -> [SEval sym (GenValue sym)] -> SEval sym (SeqMap sym)
- Cryptol.Eval.Value: lam :: (SEval sym (GenValue sym) -> SEval sym (GenValue sym)) -> GenValue sym
+ Cryptol.Eval.Value: lam :: Backend sym => sym -> (SEval sym (GenValue sym) -> SEval sym (GenValue sym)) -> SEval sym (GenValue sym)
- Cryptol.Eval.Value: mapSeqMap :: Backend sym => (GenValue sym -> SEval sym (GenValue sym)) -> SeqMap sym -> SEval sym (SeqMap sym)
+ Cryptol.Eval.Value: mapSeqMap :: Backend sym => sym -> (GenValue sym -> SEval sym (GenValue sym)) -> SeqMap sym -> SEval sym (SeqMap sym)
- Cryptol.Eval.Value: memoMap :: (MonadIO m, Backend sym) => SeqMap sym -> m (SeqMap sym)
+ Cryptol.Eval.Value: memoMap :: Backend sym => sym -> SeqMap sym -> SEval sym (SeqMap sym)
- Cryptol.Eval.Value: nlam :: Backend sym => (Nat' -> GenValue sym) -> GenValue sym
+ Cryptol.Eval.Value: nlam :: Backend sym => sym -> (Nat' -> SEval sym (GenValue sym)) -> SEval sym (GenValue sym)
- Cryptol.Eval.Value: sDelayFill :: Backend sym => sym -> SEval sym a -> SEval sym a -> SEval sym (SEval sym a)
+ Cryptol.Eval.Value: sDelayFill :: Backend sym => sym -> SEval sym a -> Maybe (SEval sym a) -> String -> SEval sym (SEval sym a)
- Cryptol.Eval.Value: tlam :: Backend sym => (TValue -> GenValue sym) -> GenValue sym
+ Cryptol.Eval.Value: tlam :: Backend sym => sym -> (TValue -> SEval sym (GenValue sym)) -> SEval sym (GenValue sym)
- Cryptol.Eval.Value: toStream :: Backend sym => [GenValue sym] -> SEval sym (GenValue sym)
+ Cryptol.Eval.Value: toStream :: Backend sym => sym -> [GenValue sym] -> SEval sym (GenValue sym)
- Cryptol.Eval.Value: zipSeqMap :: Backend sym => (GenValue sym -> GenValue sym -> SEval sym (GenValue sym)) -> SeqMap sym -> SeqMap sym -> SEval sym (SeqMap sym)
+ Cryptol.Eval.Value: zipSeqMap :: Backend sym => sym -> (GenValue sym -> GenValue sym -> SEval sym (GenValue sym)) -> SeqMap sym -> SeqMap sym -> SEval sym (SeqMap sym)
- Cryptol.Eval.What4: primTable :: IsSymExprBuilder sym => What4 sym -> Map PrimIdent (Value sym)
+ Cryptol.Eval.What4: primTable :: IsSymExprBuilder sym => What4 sym -> IO EvalOpts -> Map PrimIdent (Prim (What4 sym))
- Cryptol.ModuleSystem: type ModuleCmd a = (EvalOpts, FilePath -> IO ByteString, ModuleEnv) -> IO (ModuleRes a)
+ Cryptol.ModuleSystem: type ModuleCmd a = ModuleInput IO -> IO (ModuleRes a)
- Cryptol.ModuleSystem.Base: TCLinter :: (o -> InferInput -> Either Error [ProofObligation]) -> Maybe ModName -> TCLinter o
+ Cryptol.ModuleSystem.Base: TCLinter :: (o -> InferInput -> Either (Range, Error) [ProofObligation]) -> Maybe ModName -> TCLinter o
- Cryptol.ModuleSystem.Base: [lintCheck] :: TCLinter o -> o -> InferInput -> Either Error [ProofObligation]
+ Cryptol.ModuleSystem.Base: [lintCheck] :: TCLinter o -> o -> InferInput -> Either (Range, Error) [ProofObligation]
- Cryptol.ModuleSystem.Monad: RO :: [ImportSource] -> EvalOpts -> (FilePath -> m ByteString) -> RO m
+ Cryptol.ModuleSystem.Monad: RO :: [ImportSource] -> m EvalOpts -> Bool -> (FilePath -> m ByteString) -> Solver -> RO m
- Cryptol.ModuleSystem.Monad: [roEvalOpts] :: RO m -> EvalOpts
+ Cryptol.ModuleSystem.Monad: [roEvalOpts] :: RO m -> m EvalOpts
- Cryptol.ModuleSystem.Monad: emptyRO :: EvalOpts -> (FilePath -> m ByteString) -> RO m
+ Cryptol.ModuleSystem.Monad: emptyRO :: ModuleInput m -> RO m
- Cryptol.ModuleSystem.Monad: runModuleM :: (EvalOpts, FilePath -> IO ByteString, ModuleEnv) -> ModuleM a -> IO (Either ModuleError (a, ModuleEnv), [ModuleWarning])
+ Cryptol.ModuleSystem.Monad: runModuleM :: ModuleInput IO -> ModuleM a -> IO (Either ModuleError (a, ModuleEnv), [ModuleWarning])
- Cryptol.ModuleSystem.Monad: runModuleT :: Monad m => (EvalOpts, FilePath -> m ByteString, ModuleEnv) -> ModuleT m a -> m (Either ModuleError (a, ModuleEnv), [ModuleWarning])
+ Cryptol.ModuleSystem.Monad: runModuleT :: Monad m => ModuleInput m -> ModuleT m a -> m (Either ModuleError (a, ModuleEnv), [ModuleWarning])
- Cryptol.Parser: Config :: !FilePath -> !Layout -> PreProc -> [FilePath] -> Bool -> Config
+ Cryptol.Parser: Config :: !FilePath -> !Position -> !Layout -> PreProc -> [FilePath] -> Bool -> Config
- Cryptol.Parser: HappyErrorMsg :: Range -> String -> ParseError
+ Cryptol.Parser: HappyErrorMsg :: Range -> [String] -> ParseError
- Cryptol.Parser.AST: EFun :: [Pattern n] -> Expr n -> Expr n
+ Cryptol.Parser.AST: EFun :: FunDesc n -> [Pattern n] -> Expr n -> Expr n
- Cryptol.Parser.AST: Newtype :: Located name -> [TParam name] -> [Named (Type name)] -> Newtype name
+ Cryptol.Parser.AST: Newtype :: Located name -> [TParam name] -> Rec (Type name) -> Newtype name
- Cryptol.Parser.AST: [nBody] :: Newtype name -> [Named (Type name)]
+ Cryptol.Parser.AST: [nBody] :: Newtype name -> Rec (Type name)
- Cryptol.Parser.Lexer: Config :: !FilePath -> !Layout -> PreProc -> [FilePath] -> Bool -> Config
+ Cryptol.Parser.Lexer: Config :: !FilePath -> !Position -> !Layout -> PreProc -> [FilePath] -> Bool -> Config
- Cryptol.REPL.Command: Command :: REPL () -> Command
+ Cryptol.REPL.Command: Command :: (Int -> Maybe FilePath -> REPL ()) -> Command
- Cryptol.REPL.Command: ExprArg :: (String -> REPL ()) -> CommandBody
+ Cryptol.REPL.Command: ExprArg :: (String -> (Int, Int) -> Maybe FilePath -> REPL ()) -> CommandBody
- Cryptol.REPL.Command: FileExprArg :: (FilePath -> String -> REPL ()) -> CommandBody
+ Cryptol.REPL.Command: FileExprArg :: (FilePath -> String -> (Int, Int) -> Maybe FilePath -> REPL ()) -> CommandBody
- Cryptol.REPL.Command: offlineProveSat :: String -> QueryType -> String -> Maybe FilePath -> REPL ()
+ Cryptol.REPL.Command: offlineProveSat :: String -> QueryType -> Expr -> Schema -> Maybe FilePath -> REPL ()
- Cryptol.REPL.Command: onlineProveSat :: String -> QueryType -> String -> Maybe FilePath -> REPL (Maybe String, ProverResult, ProverStats)
+ Cryptol.REPL.Command: onlineProveSat :: String -> QueryType -> Expr -> Schema -> Maybe FilePath -> REPL (Maybe String, ProverResult, ProverStats)
- Cryptol.REPL.Command: proveCmd :: String -> REPL ()
+ Cryptol.REPL.Command: proveCmd :: String -> (Int, Int) -> Maybe FilePath -> REPL ()
- Cryptol.REPL.Command: qcCmd :: QCMode -> String -> REPL [TestReport]
+ Cryptol.REPL.Command: qcCmd :: QCMode -> String -> (Int, Int) -> Maybe FilePath -> REPL ()
- Cryptol.REPL.Command: replParseExpr :: String -> REPL (Expr PName)
+ Cryptol.REPL.Command: replParseExpr :: String -> (Int, Int) -> Maybe FilePath -> REPL (Expr PName)
- Cryptol.REPL.Command: runCommand :: Command -> REPL CommandExitCode
+ Cryptol.REPL.Command: runCommand :: Int -> Maybe FilePath -> Command -> REPL CommandExitCode
- Cryptol.REPL.Command: satCmd :: String -> REPL ()
+ Cryptol.REPL.Command: satCmd :: String -> (Int, Int) -> Maybe FilePath -> REPL ()
- Cryptol.REPL.Command: splitCommand :: String -> Maybe (String, String)
+ Cryptol.REPL.Command: splitCommand :: String -> Maybe (Int, String, String)
- Cryptol.REPL.Monad: EvalError :: EvalError -> REPLException
+ Cryptol.REPL.Monad: EvalError :: EvalErrorEx -> REPLException
- Cryptol.REPL.Monad: OptionDescr :: String -> EnvVal -> Checker -> String -> (EnvVal -> REPL ()) -> OptionDescr
+ Cryptol.REPL.Monad: OptionDescr :: String -> [String] -> EnvVal -> Checker -> String -> (EnvVal -> REPL ()) -> OptionDescr
- Cryptol.REPL.Monad: getPropertyNames :: REPL ([Name], NameDisp)
+ Cryptol.REPL.Monad: getPropertyNames :: REPL ([(Name, IfaceDecl)], NameDisp)
- Cryptol.REPL.Monad: runREPL :: Bool -> Logger -> REPL a -> IO a
+ Cryptol.REPL.Monad: runREPL :: Bool -> Bool -> Logger -> REPL a -> IO a
- Cryptol.Symbolic: FTSeq :: Int -> FinType -> FinType
+ Cryptol.Symbolic: FTSeq :: Integer -> FinType -> FinType
- Cryptol.Symbolic: ThmResult :: [Type] -> ProverResult
+ Cryptol.Symbolic: ThmResult :: [TValue] -> ProverResult
- Cryptol.Symbolic: computeModel :: PrimMap -> [FinType] -> [VarShape Concrete] -> [(Type, Expr, Value)]
+ Cryptol.Symbolic: computeModel :: PrimMap -> [FinType] -> [VarShape Concrete] -> [(TValue, Expr, Value)]
- Cryptol.Symbolic: unFinType :: FinType -> Type
+ Cryptol.Symbolic: unFinType :: FinType -> TValue
- Cryptol.Testing.Random: FailError :: EvalError -> [Value] -> TestResult
+ Cryptol.Testing.Random: FailError :: EvalErrorEx -> [Value] -> TestResult
- Cryptol.TypeCheck: InferInput :: Range -> Map Name Schema -> Map Name TySyn -> Map Name Newtype -> Map Name AbstractType -> !Map Name ModTParam -> ![Located Prop] -> !Map Name ModVParam -> NameSeeds -> Bool -> SolverConfig -> [FilePath] -> !PrimMap -> !Supply -> InferInput
+ Cryptol.TypeCheck: InferInput :: Range -> Map Name Schema -> Map Name TySyn -> Map Name Newtype -> Map Name AbstractType -> !Map Name ModTParam -> ![Located Prop] -> !Map Name ModVParam -> NameSeeds -> Bool -> Bool -> SolverConfig -> [FilePath] -> !PrimMap -> !Supply -> Solver -> InferInput
- Cryptol.TypeCheck.Depends: orderTyDecls :: [TyDecl] -> InferM [TyDecl]
+ Cryptol.TypeCheck.Depends: orderTyDecls :: [TyDecl] -> InferM (Either Error [TyDecl])
- Cryptol.TypeCheck.InferTypes: Goals :: Set Goal -> Set Prop -> Map TVar LitGoal -> Goals
+ Cryptol.TypeCheck.InferTypes: Goals :: Set Goal -> Set Prop -> Map TVar LitGoal -> Map TVar LitGoal -> Goals
- Cryptol.TypeCheck.Monad: InferInput :: Range -> Map Name Schema -> Map Name TySyn -> Map Name Newtype -> Map Name AbstractType -> !Map Name ModTParam -> ![Located Prop] -> !Map Name ModVParam -> NameSeeds -> Bool -> SolverConfig -> [FilePath] -> !PrimMap -> !Supply -> InferInput
+ Cryptol.TypeCheck.Monad: InferInput :: Range -> Map Name Schema -> Map Name TySyn -> Map Name Newtype -> Map Name AbstractType -> !Map Name ModTParam -> ![Located Prop] -> !Map Name ModVParam -> NameSeeds -> Bool -> Bool -> SolverConfig -> [FilePath] -> !PrimMap -> !Supply -> Solver -> InferInput
- Cryptol.TypeCheck.Monad: RO :: Range -> Map Name VarType -> [TParam] -> Map Name (DefLoc, TySyn) -> Map Name (DefLoc, Newtype) -> Map Name (DefLoc, AbstractType) -> Map Name ModTParam -> [Located Prop] -> Map Name ModVParam -> Map Int HasGoalSln -> Bool -> Solver -> !PrimMap -> !IORef Int -> RO
+ Cryptol.TypeCheck.Monad: RO :: Range -> Map Name VarType -> [TParam] -> Map Name (DefLoc, TySyn) -> Map Name (DefLoc, Newtype) -> Map Name (DefLoc, AbstractType) -> Map Name ModTParam -> [Located Prop] -> Map Name ModVParam -> Map Int HasGoalSln -> Bool -> Bool -> Solver -> !PrimMap -> !IORef Int -> RO
- Cryptol.TypeCheck.Sanity: tcDecls :: InferInput -> [DeclGroup] -> Either Error [ProofObligation]
+ Cryptol.TypeCheck.Sanity: tcDecls :: InferInput -> [DeclGroup] -> Either (Range, Error) [ProofObligation]
- Cryptol.TypeCheck.Sanity: tcExpr :: InferInput -> Expr -> Either Error (Schema, [ProofObligation])
+ Cryptol.TypeCheck.Sanity: tcExpr :: InferInput -> Expr -> Either (Range, Error) (Schema, [ProofObligation])
- Cryptol.TypeCheck.Sanity: tcModule :: InferInput -> Module -> Either Error [ProofObligation]
+ Cryptol.TypeCheck.Sanity: tcModule :: InferInput -> Module -> Either (Range, Error) [ProofObligation]
- Cryptol.TypeCheck.Type: Newtype :: Name -> [TParam] -> [Prop] -> [(Ident, Type)] -> Maybe Text -> Newtype
+ Cryptol.TypeCheck.Type: Newtype :: Name -> [TParam] -> [Prop] -> RecordMap Ident Type -> Maybe Text -> Newtype
- Cryptol.TypeCheck.Type: [ntFields] :: Newtype -> [(Ident, Type)]
+ Cryptol.TypeCheck.Type: [ntFields] :: Newtype -> RecordMap Ident Type
- Cryptol.TypeCheck.TypeMap: TM :: Map TVar a -> Map TCon (List TypeMap a) -> Map [Ident] (List TypeMap a) -> TypeMap a
+ Cryptol.TypeCheck.TypeMap: TM :: Map TVar a -> Map TCon (List TypeMap a) -> Map [Ident] (List TypeMap a) -> Map Newtype (List TypeMap a) -> TypeMap a
Files
- CHANGES.md +50/−0
- cryptol.cabal +31/−8
- cryptol/CheckExercises.hs +371/−0
- cryptol/Main.hs +31/−8
- cryptol/REPL/Haskeline.hs +52/−31
- cryptol/REPL/Logo.hs +2/−0
- lib/Cryptol.cry +18/−2
- lib/Float.cry +48/−4
- src/Cryptol/Backend.hs +65/−50
- src/Cryptol/Backend/Concrete.hs +51/−20
- src/Cryptol/Backend/FloatHelpers.hs +23/−93
- src/Cryptol/Backend/Monad.hs +156/−95
- src/Cryptol/Backend/SBV.hs +58/−36
- src/Cryptol/Backend/What4.hs +41/−26
- src/Cryptol/Backend/What4/SFloat.hs +0/−362
- src/Cryptol/Eval.hs +139/−82
- src/Cryptol/Eval/Concrete.hs +159/−361
- src/Cryptol/Eval/Env.hs +16/−16
- src/Cryptol/Eval/Generic.hs +627/−278
- src/Cryptol/Eval/Prims.hs +39/−0
- src/Cryptol/Eval/Reference.lhs +56/−14
- src/Cryptol/Eval/SBV.hs +14/−150
- src/Cryptol/Eval/Type.hs +45/−11
- src/Cryptol/Eval/Value.hs +179/−73
- src/Cryptol/Eval/What4.hs +73/−251
- src/Cryptol/IR/FreeVars.hs +4/−6
- src/Cryptol/ModuleSystem.hs +6/−8
- src/Cryptol/ModuleSystem/Base.hs +24/−11
- src/Cryptol/ModuleSystem/Env.hs +6/−0
- src/Cryptol/ModuleSystem/InstantiateModule.hs +3/−2
- src/Cryptol/ModuleSystem/Monad.hs +52/−16
- src/Cryptol/ModuleSystem/Name.hs +0/−4
- src/Cryptol/ModuleSystem/Renamer.hs +14/−11
- src/Cryptol/Parser.y +20/−12
- src/Cryptol/Parser/AST.hs +31/−8
- src/Cryptol/Parser/Lexer.x +5/−1
- src/Cryptol/Parser/LexerUtils.hs +4/−0
- src/Cryptol/Parser/Names.hs +5/−2
- src/Cryptol/Parser/NoPat.hs +24/−13
- src/Cryptol/Parser/ParserUtils.hs +115/−53
- src/Cryptol/Parser/Position.hs +5/−1
- src/Cryptol/REPL/Command.hs +310/−204
- src/Cryptol/REPL/Monad.hs +90/−40
- src/Cryptol/REPL/Trie.hs +6/−5
- src/Cryptol/Symbolic.hs +70/−44
- src/Cryptol/Symbolic/SBV.hs +48/−16
- src/Cryptol/Symbolic/What4.hs +25/−17
- src/Cryptol/Testing/Random.hs +67/−42
- src/Cryptol/Transform/AddModParams.hs +8/−11
- src/Cryptol/Transform/MonoValues.hs +1/−0
- src/Cryptol/Transform/Specialize.hs +4/−3
- src/Cryptol/TypeCheck.hs +5/−1
- src/Cryptol/TypeCheck/AST.hs +8/−2
- src/Cryptol/TypeCheck/CheckModuleInstance.hs +1/−1
- src/Cryptol/TypeCheck/Default.hs +6/−3
- src/Cryptol/TypeCheck/Depends.hs +8/−11
- src/Cryptol/TypeCheck/Error.hs +32/−5
- src/Cryptol/TypeCheck/Infer.hs +39/−12
- src/Cryptol/TypeCheck/InferTypes.hs +32/−2
- src/Cryptol/TypeCheck/Instantiate.hs +3/−3
- src/Cryptol/TypeCheck/Kind.hs +13/−14
- src/Cryptol/TypeCheck/Monad.hs +56/−15
- src/Cryptol/TypeCheck/Parseable.hs +1/−0
- src/Cryptol/TypeCheck/Sanity.hs +28/−7
- src/Cryptol/TypeCheck/SimpType.hs +1/−0
- src/Cryptol/TypeCheck/SimpleSolver.hs +2/−0
- src/Cryptol/TypeCheck/Solver/Class.hs +76/−4
- src/Cryptol/TypeCheck/Solver/Improve.hs +2/−1
- src/Cryptol/TypeCheck/Solver/SMT.hs +22/−19
- src/Cryptol/TypeCheck/Solver/Selector.hs +11/−14
- src/Cryptol/TypeCheck/Solver/Utils.hs +3/−0
- src/Cryptol/TypeCheck/Subst.hs +4/−1
- src/Cryptol/TypeCheck/TCon.hs +4/−3
- src/Cryptol/TypeCheck/Type.hs +56/−16
- src/Cryptol/TypeCheck/TypeMap.hs +15/−3
- src/Cryptol/TypeCheck/TypeOf.hs +8/−4
- src/Cryptol/TypeCheck/TypePat.hs +6/−1
- src/Cryptol/TypeCheck/Unify.hs +3/−0
- src/Cryptol/Utils/PP.hs +32/−0
- src/GitRev.hs +0/−1
- utils/CryHtml.hs +7/−4
CHANGES.md view
@@ -1,3 +1,53 @@+# 2.11.0++## Language changes++* The `newtype` construct, which has existed in the interpreter in an+ incomplete and undocumented form for quite a while, is now fullly+ supported. The construct is documented in section 1.22 of [Programming+ Cryptol](https://cryptol.net/files/ProgrammingCryptol.pdf). Note,+ however, that the `cryptol-remote-api` RPC server currently does not+ include full support for referring to `newtype` names, though it can+ work with implementations that use `newtype` internally.++## New features++* By default, the interpreter will now track source locations of+ expressions being evaluated, and retain call stack information.+ This information is incorporated into error messages arising from+ runtime errors. This additional bookkeeping incurs significant+ runtime overhead, but may be disabled using the `--no-call-stacks`+ command-line option.++* The `:exhaust` command now works for floating-point types and the+ `:check` command now uses more representative sampling of+ floating-point input values to test.++* The `cryptol-remote-api` RPC server now has methods corresponding to+ the `:prove` and `:sat` commands in the REPL.++* The `cryptol-eval-server` executable is a new, stateless server+ providing a subset of the functionality of `cryptol-remote-api`+ dedicated entirely to invoking Cryptol functions on concrete inputs.++## Internal changes++* A single running instance of the SMT solver used for type checking+ (Z3) is now used to check a larger number of type correctness queries.+ This means that fewer solver instances are invoked, and type checking+ should generally be faster.++* The Cryptol interpreter now builds against `libBF` version 0.6, which+ fixes a few bugs in the evaluation of floating-point operations.++## Bug fixes++* Closed issues #118, #398, #426, #470, #491, #567, #594, #639, #656,+ #698, #743, #810, #858, #870, #905, #915, #917, #962, #973, #975,+ #980, #984, #986, #990, #996, #997, #1002, #1006, #1009, #1012, #1024,+ #1030, #1035, #1036, #1039, #1040, #1044, #1045, #1049, #1050, #1051,+ #1052, #1063, #1092, #1093, #1094, and #1100.+ # 2.10.0 ## Language changes
cryptol.cabal view
@@ -1,6 +1,6 @@ Cabal-version: 2.4 Name: cryptol-Version: 2.10.0+Version: 2.11.0 Synopsis: Cryptol: The Language of Cryptography Description: Cryptol is a domain-specific language for specifying cryptographic algorithms. A Cryptol implementation of an algorithm resembles its mathematical specification more closely than an implementation in a general purpose language. For more, see <http://www.cryptol.net/>. License: BSD-3-Clause@@ -25,7 +25,7 @@ source-repository this type: git location: https://github.com/GaloisInc/cryptol.git- tag: 2.10.0+ tag: 2.11.0 flag static@@ -56,7 +56,7 @@ GraphSCC >= 1.0.4, heredoc >= 0.2, integer-gmp >= 1.0 && < 1.1,- libBF >= 0.5.1,+ libBF >= 0.6 && < 0.7, MemoTrie >= 0.6 && < 0.7, monad-control >= 1.0, monadLib >= 3.7.2,@@ -64,7 +64,7 @@ pretty >= 1.1, process >= 1.2, random >= 1.0.1,- sbv >= 8.6 && < 8.8,+ sbv >= 8.6 && < 8.13, simple-smt >= 0.7.1, stm >= 2.4, strict,@@ -74,7 +74,7 @@ mtl >= 2.2.1, time >= 1.6.0.1, panic >= 0.3,- what4 >= 1.0 && < 1.1+ what4 >= 1.1 && < 1.2 Build-tool-depends: alex:alex, happy:happy hs-source-dirs: src@@ -164,12 +164,12 @@ Cryptol.Backend.Monad, Cryptol.Backend.SBV, Cryptol.Backend.What4,- Cryptol.Backend.What4.SFloat, Cryptol.Eval, Cryptol.Eval.Concrete, Cryptol.Eval.Env, Cryptol.Eval.Generic,+ Cryptol.Eval.Prims, Cryptol.Eval.Reference, Cryptol.Eval.SBV, Cryptol.Eval.Type,@@ -232,7 +232,8 @@ ghc-options: -Wno-redundant-constraints if os(linux) && flag(static)- ld-options: -static -pthread+ ld-options: -static -pthread+ ghc-options: -optl-fuse-ld=bfd executable cryptol-html Default-language:@@ -242,6 +243,27 @@ build-depends: base, text, cryptol, blaze-html GHC-options: -Wall + if os(linux) && flag(static)+ ld-options: -static -pthread+ ghc-options: -optl-fuse-ld=bfd++executable check-exercises+ Default-language:+ Haskell2010+ Main-is: CheckExercises.hs+ hs-source-dirs: cryptol+ build-depends: ansi-terminal+ , base+ , containers+ , directory+ , extra+ , filepath+ , mtl+ , optparse-applicative+ , process+ , temporary+ , text+ GHC-options: -Wall benchmark cryptol-bench type: exitcode-stdio-1.0 main-is: Main.hs@@ -251,7 +273,8 @@ if impl(ghc >= 8.0.1) ghc-options: -Wno-redundant-constraints if os(linux) && flag(static)- ld-options: -static -pthread+ ld-options: -static -pthread+ ghc-options: -optl-fuse-ld=bfd build-depends: base , criterion , cryptol
+ cryptol/CheckExercises.hs view
@@ -0,0 +1,371 @@+{-# LANGUAGE CPP #-}+{-# LANGUAGE MultiWayIf #-}+{-# LANGUAGE RecordWildCards #-}+{-# LANGUAGE ViewPatterns #-}++module Main(main) where++import Control.Monad.State+import Options.Applicative+import Data.Char (isSpace, isAlpha)+import Data.Foldable (traverse_)+import Data.List (isInfixOf, isPrefixOf, stripPrefix)+import Data.Maybe (fromMaybe)+import qualified Data.Sequence as Seq+import Numeric.Natural+import qualified System.Process as P+import System.Directory+import System.Exit+import System.IO.Temp+import Data.Foldable (toList)++data Opts = Opts { latexFile :: FilePath+ -- ^ The latex file we are going to check+ , cryptolExe :: Maybe FilePath+ -- ^ Path to cryptol executable (default: cabal v2-exec cryptol)+ , tempDir :: Maybe FilePath+ -- ^ Path to store temporary files and log files+ }+ deriving Show++optsParser :: Parser Opts+optsParser = Opts+ <$> strArgument ( help "path to latex file"+ <> metavar "PATH"+ )+ <*> ( optional $ strOption+ ( long "exe"+ <> short 'e'+ <> metavar "PATH"+ <> help "Path to cryptol executable (defaults to 'cabal v2-exec cryptol')"+ ) )+ <*> ( optional $ strOption+ ( long "log-dir"+ <> short 'l'+ <> metavar "PATH"+ <> help "Directory for log files in case of failure (defaults to .)"+ ) )++-- | Trim whitespace off both ends of a string+trim :: String -> String+trim = f . f+ where f = reverse . dropWhile isSpace++----------------------------------------------------------------------+-- LaTeX processing state monad+--+-- We process the text-by-line. The behavior of the state monad on a line is+-- governed by the mode it is currently in. The current mode dictates how to+-- interpret each line, and which mode to transition to next.+--+-- There are four modes: AwaitingReplMode, ReplinMode, ReploutMode, and+-- ReplPromptMode. Below we describe the behavior of each mode.+--+-- AwaitingReplMode: When in this mode, we are anticipating "replin" or+-- "replout" lines; that is, lines that will be issued as input to the repl or+-- expected as output from the repl.. When we see a \begin{replinVerb}, we+-- transition to ReplinMode. When we see a \begin{reploutVerb}, we transition to+-- ReploutMode. When we see a \begin{replPromptVerb}, we transition to+-- ReplPromptMode. When we see an inline \replin{..} command, we add the content+-- to the list of replin lines without changing modes. When we see an inline+-- \replout{..} command, we add the content to the list of replout lines without+-- changing modes.+--+-- ReplinMode: When in this mode, we are inside of a "\begin{replinVerb}"+-- section. When we see a \end{replinVerb} line, we transition to+-- AwaitingReplMode. Otherwise, we simply add the entire line to the list of+-- replin lines.+--+-- ReploutMode: Like ReplinMode, except we add each line to the expected output.+--+-- ReplPromptMode: A combination of ReplinMode and ReploutMode. Each line is+-- either added to input or expected output. If the line starts with a prompt+-- like "Cryptol>" or "Float>", it is added to expected input. Otherwise it is+-- added to expected output.++data PMode = AwaitingReplMode+ | ReplinMode+ | ReploutMode+ | ReplPromptMode+ deriving (Eq, Show)++data Line = Line { lineNum :: Natural+ , lineText :: String+ }+ deriving (Eq, Show)++-- | REPL input and expected output, with line number annotations.+data ReplData = ReplData { rdReplin :: Seq.Seq Line+ , rdReplout :: Seq.Seq Line+ }+ deriving (Eq, Show)++-- | Latex processing state+data PState = PState { pMode :: PMode+ -- ^ current mode+ , pCompletedReplData :: Seq.Seq ReplData+ -- ^ list of all completed REPL input/output pairs to be+ -- validated (thus far)+ , pReplin :: Seq.Seq Line+ -- ^ list of replin lines (so far) for unfinished ReplData+ , pReplout :: Seq.Seq Line+ -- ^ list of replout lines (so far) for unfinished ReplData+ , pCurrentLine :: Natural+ }+ deriving (Eq, Show)++initPState :: PState+initPState = PState AwaitingReplMode Seq.empty Seq.empty Seq.empty 1++-- | P monad for reading in lines+type P = State PState++first3 :: (a -> a') -> (a, b, c) -> (a', b, c)+first3 f (a, b, c) = (f a, b, c)++-- | Like 'stripPrefix', but takes a list of prefixes rather than a single+-- prefix. Returns the first prefix that matches the start of the list along+-- with the remainder of the list.+stripPrefixOneOf :: Eq a => [[a]] -> [a] -> Maybe ([a], [a])+stripPrefixOneOf [] _ = Nothing+stripPrefixOneOf (p:ps) as = case stripPrefix p as of+ Nothing -> stripPrefixOneOf ps as+ Just as' -> Just (p, as')++-- | Like 'stripInfix', but takes a list of infixes. Returns the infix that+-- matches at the earliest index.+stripInfixOneOf :: Eq a => [[a]] -> [a] -> Maybe ([a], [a], [a])+stripInfixOneOf needles haystack+ | Just (needle, suffix) <- stripPrefixOneOf needles haystack+ = Just ([], needle, suffix)+stripInfixOneOf _ [] = Nothing+stripInfixOneOf needles (x:xs) = first3 (x:) <$> stripInfixOneOf needles xs++data InlineRepl = InlineReplin | InlineReplout++-- | Extracts the first inline repl command returns the type of command, its+-- contents, and the remainder of the string.+inlineRepl :: String -> Maybe (InlineRepl, String, String)+inlineRepl s+ | Just (_, ir, s1) <- stripInfixOneOf [ "\\replin|"+ , "\\replout|"+ , "\\hidereplin|"+ , "\\hidereplout|"] s+ , (s2, s3) <- break (=='|') s1 = case ir of+ "\\replin|" -> Just (InlineReplin, s2, s3)+ "\\replout|" -> Just (InlineReplout, s2, s3)+ "\\hidereplin|" -> Just (InlineReplin, s2, s3)+ "\\hidereplout|" -> Just (InlineReplout, s2, s3)+ _ -> error "PANIC: CheckExercises.inlineRepl"+ | otherwise = Nothing++addReplData :: P ()+addReplData = do+ replin <- gets pReplin+ replout <- gets pReplout+ completedReplData <- gets pCompletedReplData+ let completedReplData' = completedReplData Seq.|> ReplData replin replout+ when (not (Seq.null replin && Seq.null replout)) $+ modify' $ \st -> st { pCompletedReplData = completedReplData'+ , pReplin = Seq.empty+ , pReplout = Seq.empty+ }++addReplin :: String -> P ()+addReplin s = do+ ln <- gets pCurrentLine+ replin <- gets pReplin+ modify' $ \st -> st { pReplin = replin Seq.|> Line ln s }++addReplout :: String -> P ()+addReplout s = do+ ln <- gets pCurrentLine+ replout <- gets pReplout+ modify' $ \st -> st { pReplout = replout Seq.|> Line ln s }++nextLine :: P ()+nextLine = modify' $ \st -> st { pCurrentLine = pCurrentLine st + 1 }++stripPrompt :: String -> Maybe String+stripPrompt s = case span isAlpha s of+ (_:_, '>':s') -> Just s'+ _ -> Nothing++-- | The main function for our monad. Input is a single line.+processLine :: String -> P ()+processLine s = do+ let s_nocomment = takeWhile (not . (== '%')) s+ s_nowhitespace = filter (not . isSpace) s_nocomment+ m <- gets pMode+ ln <- gets pCurrentLine+ case m of+ AwaitingReplMode+ | "\\begin{replinVerb}" `isInfixOf` s_nowhitespace -> do+ modify' $ \st -> st { pMode = ReplinMode }+ nextLine+ | "\\begin{reploutVerb}" `isInfixOf` s_nowhitespace -> do+ modify' $ \st -> st { pMode = ReploutMode }+ nextLine+ | "\\begin{replPrompt}" `isInfixOf` s_nowhitespace -> do+ modify' $ \st -> st { pMode = ReplPromptMode }+ nextLine+ | "\\restartrepl" `isInfixOf` s_nowhitespace -> do+ -- This is a command that acts as the barrier between discrete+ -- input/output pairs. When we see it, we commit the current pair,+ -- begin a brand new pair, and advance to the next line.+ addReplData+ nextLine+ | Just (InlineReplin, cmd, rst) <- inlineRepl s -> do+ addReplin cmd+ processLine rst+ | Just (InlineReplout, cmd, rst) <- inlineRepl s -> do+ addReplout cmd+ processLine rst+ | otherwise -> nextLine+ ReplinMode+ | "\\end{replinVerb}" `isInfixOf` s_nowhitespace -> do+ -- Switching from ingesting repl input to awaiting repl input.+ modify' $ \st -> st { pMode = AwaitingReplMode }+ nextLine+ | otherwise -> do+ -- Ingest the current line, and stay in ReplinMode.+ replin <- gets pReplin+ let replin' = replin Seq.|> Line ln s -- use the full input since %+ -- isn't a comment in verbatim+ -- mode.+ modify' $ \st -> st { pReplin = replin' }+ nextLine+ ReploutMode+ | "\\end{reploutVerb}" `isInfixOf` s_nowhitespace -> do+ -- Switching from ingesting repl output to awaiting repl output.+ modify' $ \st -> st { pMode = AwaitingReplMode }+ nextLine+ | otherwise -> do+ -- Ingest the current line, and stay in ReploutMode.+ replout <- gets pReplout+ let replout' = replout Seq.|> Line ln s -- use the full input since %+ -- isn't a comment in verbatim+ -- mode.+ modify' $ \st -> st { pReplout = replout' }+ nextLine+ ReplPromptMode+ | "\\end{replPrompt}" `isInfixOf` s_nowhitespace -> do+ -- Switching from ingesting repl input/output to awaiting repl+ -- input.+ modify' $ \st -> st { pMode = AwaitingReplMode }+ nextLine+ | Just input <- stripPrompt (trim s) -> do+ replin <- gets pReplin+ let input' = trim input+ replin' = replin Seq.|> Line ln input' -- use the full input since+ -- % isn't a comment in+ -- verbatim mode.+ modify $ \st -> st { pReplin = replin' }+ nextLine+ | otherwise -> do+ replout <- gets pReplout+ let replout' = replout Seq.|> Line ln s -- use the full input since %+ -- isn't a comment in verbatim+ -- mode.+ modify $ \st -> st { pReplout = replout' }+ nextLine++main :: IO ()+main = do+ opts <- execParser p+ allLines <- lines <$> readFile (latexFile opts)+ let PState {..} = flip execState initPState $ do+ -- Process every line+ traverse_ processLine allLines+ -- Insert the final ReplData upon completion+ addReplData+ let allReplData = toList pCompletedReplData+ dir = fromMaybe "." (tempDir opts)++ forM_ allReplData $ \rd -> do+ let inText = unlines $ fmap (trim . lineText) $ toList $ rdReplin rd+ inFileNameTemplate = "in.icry"+ inFile <- writeTempFile dir inFileNameTemplate inText++ let exe = fromMaybe "./cry run" (cryptolExe opts)++ if Seq.null (rdReplout rd)+ then do let cryCmd = (P.shell (exe ++ " --interactive-batch " ++ inFile ++ " -e"))+ (cryEC, cryOut, _) <- P.readCreateProcessWithExitCode cryCmd ""+++ Line lnReplinStart _ Seq.:<| _ <- return $ rdReplin rd+ _ Seq.:|> Line lnReplinEnd _ <- return $ rdReplin rd+ case cryEC of+ ExitFailure _ -> do+ putStrLn $ "REPL error (replin lines " +++ show lnReplinStart ++ "-" ++ show lnReplinEnd ++ ")."+ putStr cryOut+ exitFailure+ ExitSuccess -> do+ -- remove temporary input file+ removeFile inFile+ else do let outExpectedText = unlines $ filter (not . null) $+ fmap (trim . lineText) $ toList $ rdReplout rd+ outExpectedFileNameTemplate = "out-expected.icry"+ outFileNameTemplate = "out.icry"+ cryCmd = (P.shell (exe ++ " --interactive-batch " ++ inFile))+ outExpectedFile <- writeTempFile dir outExpectedFileNameTemplate outExpectedText+ outFile <- emptyTempFile dir outFileNameTemplate++ (_, cryOut, _) <- P.readCreateProcessWithExitCode cryCmd ""++ -- remove temporary input file+ removeFile inFile++ let outText = unlines $ filter (not . null) $ trim <$> (dropWhile ("Loading module" `isPrefixOf`) $ lines cryOut)++ writeFile outFile outText++ let diffCmd = (P.shell ("diff -u " ++ outExpectedFile ++ " " ++ outFile))++ (diffEC, diffOut, _) <- P.readCreateProcessWithExitCode diffCmd ""+ case diffEC of+ ExitSuccess -> do+ -- Remove temporary output files+ removeFile outExpectedFile+ removeFile outFile+ ExitFailure _ -> do+ Line lnReplinStart _ Seq.:<| _ <- return $ rdReplin rd+ _ Seq.:|> Line lnReplinEnd _ <- return $ rdReplin rd+ Line lnReploutStart _ Seq.:<| _ <- return $ rdReplout rd+ _ Seq.:|> Line lnReploutEnd _ <- return $ rdReplout rd++ putStrLn $ "REPL output mismatch in " ++ latexFile opts+ putStrLn $ " (replin lines " +++ show lnReplinStart ++ "-" ++ show lnReplinEnd +++ ", replout lines " ++ show lnReploutStart ++ "-" +++ show lnReploutEnd ++ ")."+ putStrLn $ "Diff output:"+ putStr diffOut++ let outExpectedFileName = dir ++ "/" ++ outExpectedFileNameTemplate+ outFileName = dir ++ "/" ++ outFileNameTemplate++ putStrLn ""+ putStrLn $ "Expected output written to: " ++ outExpectedFileName+ putStrLn $ "Actual output written to: " ++ outFileName++ -- Write to log files+ writeFile outExpectedFileName outExpectedText+ writeFile outFileName outText++ -- Remove temporary output files and exit+ removeFile outExpectedFile+ removeFile outFile+ exitFailure++ putStrLn $ "Successfully checked " ++ show (length allReplData) ++ " repl examples in " ++ latexFile opts++ return ()++ where p = info (optsParser <**> helper)+ ( fullDesc+ <> progDesc "Test the exercises in a cryptol LaTeX file"+ <> header "check-exercises -- test cryptol exercises"+ )
cryptol/Main.hs view
@@ -26,7 +26,6 @@ import Cryptol.Version (displayVersion) import Control.Monad (when)-import Data.Maybe (isJust) import GHC.IO.Encoding (setLocaleEncoding, utf8) import System.Console.GetOpt (OptDescr(..),ArgOrder(..),ArgDescr(..),getOpt,usageInfo)@@ -47,7 +46,8 @@ { optLoad :: [FilePath] , optVersion :: Bool , optHelp :: Bool- , optBatch :: Maybe FilePath+ , optBatch :: ReplMode+ , optCallStacks :: Bool , optCommands :: [String] , optColorMode :: ColorMode , optCryptolrc :: Cryptolrc@@ -61,7 +61,8 @@ { optLoad = [] , optVersion = False , optHelp = False- , optBatch = Nothing+ , optBatch = InteractiveRepl+ , optCallStacks = True , optCommands = [] , optColorMode = AutoColor , optCryptolrc = CryrcDefault@@ -75,6 +76,9 @@ [ Option "b" ["batch"] (ReqArg setBatchScript "FILE") "run the script provided and exit" + , Option "" ["interactive-batch"] (ReqArg setInteractiveBatchScript "FILE")+ "run the script provided and exit, but behave as if running an interactive session"+ , Option "e" ["stop-on-error"] (NoArg setStopOnError) "stop script execution as soon as an error occurs." @@ -95,6 +99,9 @@ , Option "h" ["help"] (NoArg setHelp) "display this message" + , Option "" ["no-call-stacks"] (NoArg setNoCallStacks)+ "Disable tracking of call stack information, which reduces interpreter overhead"+ , Option "" ["no-unicode-logo"] (NoArg setNoUnicodeLogo) "Don't use unicode characters in the REPL logo" @@ -124,8 +131,12 @@ -- | Set a batch script to be run. setBatchScript :: String -> OptParser Options-setBatchScript path = modify $ \ opts -> opts { optBatch = Just path }+setBatchScript path = modify $ \ opts -> opts { optBatch = Batch path } +-- | Set an interactive batch script+setInteractiveBatchScript :: String -> OptParser Options+setInteractiveBatchScript path = modify $ \ opts -> opts { optBatch = InteractiveBatch path }+ -- | Set the color mode of the terminal output. setColorMode :: String -> OptParser Options setColorMode "auto" = modify $ \ opts -> opts { optColorMode = AutoColor }@@ -149,6 +160,10 @@ setCryrcDisabled :: OptParser Options setCryrcDisabled = modify $ \ opts -> opts { optCryptolrc = CryrcDisabled } +-- | Disable call stack tracking+setNoCallStacks :: OptParser Options+setNoCallStacks = modify $ \opts -> opts { optCallStacks = False }+ -- | Add another file to read as a @.cryptolrc@ file, unless @.cryptolrc@ -- files have been disabled addCryrc :: String -> OptParser Options@@ -180,9 +195,15 @@ , "addition to the default locations" ] )+ , ( "EDITOR"+ , [ "Sets the editor executable to use when opening an editor"+ , "via the `:edit` command"+ ]+ ) , ( "SBV_{ABC,BOOLECTOR,CVC4,MATHSAT,YICES,Z3}_OPTIONS" , [ "A string of command-line arguments to be passed to the" , "corresponding solver invoked for `:sat` and `:prove`"+ , "when using a prover via SBV" ] ) ]@@ -206,6 +227,7 @@ (opts', mCleanup) <- setupCmdScript opts status <- repl (optCryptolrc opts') (optBatch opts')+ (optCallStacks opts') (optStopOnError opts') (setupREPL opts') case mCleanup of@@ -225,9 +247,9 @@ (path, h) <- openTempFile tmpdir "cmds.icry" hPutStr h (unlines cmds) hClose h- when (isJust (optBatch opts)) $+ when (optBatch opts /= InteractiveRepl) $ putStrLn "[warning] --command argument specified; ignoring batch file"- return (opts { optBatch = Just path }, Just path)+ return (opts { optBatch = InteractiveBatch path }, Just path) setupREPL :: Options -> REPL () setupREPL opts = do@@ -261,9 +283,10 @@ setUpdateREPLTitle (shouldSetREPLTitle >>= \b -> when b setREPLTitle) updateREPLTitle case optBatch opts of- Nothing -> return () -- add the directory containing the batch file to the module search path- Just file -> prependSearchPath [ takeDirectory file ]+ Batch file -> prependSearchPath [ takeDirectory file ]+ _ -> return ()+ case optLoad opts of [] -> loadPrelude `REPL.catch` \x -> io $ print $ pp x [l] -> loadCmd l `REPL.catch` \x -> do
cryptol/REPL/Haskeline.hs view
@@ -29,7 +29,6 @@ import Data.Char (isAlphaNum, isSpace) import Data.Function (on) import Data.List (isPrefixOf,nub,sortBy,sort)-import Data.Maybe(isJust) import qualified Data.Set as Set import qualified Data.Text as T (unpack) import System.Console.ANSI (setTitle, hSupportsANSI)@@ -44,42 +43,57 @@ import Prelude.Compat +data ReplMode+ = InteractiveRepl -- ^ Interactive terminal session+ | Batch FilePath -- ^ Execute from a batch file+ | InteractiveBatch FilePath+ -- ^ Execute from a batch file, but behave as though+ -- lines are entered in an interactive session.+ deriving (Show, Eq)+ -- | One REPL invocation, either from a file or from the terminal.-crySession :: Maybe FilePath -> Bool -> REPL CommandExitCode-crySession mbBatch stopOnError =+crySession :: ReplMode -> Bool -> REPL CommandExitCode+crySession replMode stopOnError = do settings <- io (setHistoryFile (replSettings isBatch))- let act = runInputTBehavior behavior settings (withInterrupt loop)+ let act = runInputTBehavior behavior settings (withInterrupt (loop 1)) if isBatch then asBatch act else act where- (isBatch,behavior) = case mbBatch of- Nothing -> (False,defaultBehavior)- Just path -> (True,useFile path)+ (isBatch,behavior) = case replMode of+ InteractiveRepl -> (False, defaultBehavior)+ Batch path -> (True, useFile path)+ InteractiveBatch path -> (False, useFile path) - loop :: InputT REPL CommandExitCode- loop =+ loop :: Int -> InputT REPL CommandExitCode+ loop lineNum = do ln <- getInputLines =<< MTL.lift getPrompt case ln of NoMoreLines -> return CommandOk Interrupted | isBatch && stopOnError -> return CommandError- | otherwise -> loop- NextLine line- | all isSpace line -> loop- | otherwise -> doCommand line+ | otherwise -> loop lineNum+ NextLine ls+ | all (all isSpace) ls -> loop (lineNum + length ls)+ | otherwise -> doCommand lineNum ls - doCommand txt =- case parseCommand findCommandExact txt of- Nothing | isBatch && stopOnError -> return CommandError- | otherwise -> loop -- say somtething?+ run lineNum cmd =+ case replMode of+ InteractiveRepl -> runCommand lineNum Nothing cmd+ InteractiveBatch _ -> runCommand lineNum Nothing cmd+ Batch path -> runCommand lineNum (Just path) cmd++ doCommand lineNum txt =+ case parseCommand findCommandExact (unlines txt) of+ Nothing | isBatch && stopOnError -> return CommandError+ | otherwise -> loop (lineNum + length txt) -- say somtething? Just cmd -> join $ MTL.lift $- do status <- handleInterrupt (handleCtrlC CommandError) (runCommand cmd)+ do status <- handleInterrupt (handleCtrlC CommandError) (run lineNum cmd) case status of CommandError | isBatch && stopOnError -> return (return status) _ -> do goOn <- shouldContinue- return (if goOn then loop else return status)+ return (if goOn then loop (lineNum + length txt) else return status) -data NextLine = NextLine String | NoMoreLines | Interrupted+data NextLine = NextLine [String] | NoMoreLines | Interrupted getInputLines :: String -> InputT REPL NextLine getInputLines = handleInterrupt (MTL.lift (handleCtrlC Interrupted)) . loop []@@ -91,7 +105,7 @@ Nothing -> return NoMoreLines Just l | not (null l) && last l == '\\' -> loop (init l : ls) newPropmpt- | otherwise -> return $ NextLine $ unlines $ reverse $ l : ls+ | otherwise -> return $ NextLine $ reverse $ l : ls loadCryRC :: Cryptolrc -> REPL CommandExitCode loadCryRC cryrc =@@ -106,25 +120,32 @@ let file = dir </> ".cryptolrc" present <- io (doesFileExist file) if present- then crySession (Just file) True+ then crySession (Batch file) True else check others loadMany [] = return CommandOk- loadMany (f : fs) = do status <- crySession (Just f) True+ loadMany (f : fs) = do status <- crySession (Batch f) True case status of CommandOk -> loadMany fs _ -> return status -- | Haskeline-specific repl implementation.-repl :: Cryptolrc -> Maybe FilePath -> Bool -> REPL () -> IO CommandExitCode-repl cryrc mbBatch stopOnError begin =- runREPL (isJust mbBatch) stdoutLogger $- do status <- loadCryRC cryrc- case status of- CommandOk -> begin >> crySession mbBatch stopOnError- _ -> return status+repl :: Cryptolrc -> ReplMode -> Bool -> Bool -> REPL () -> IO CommandExitCode+repl cryrc replMode callStacks stopOnError begin =+ runREPL isBatch callStacks stdoutLogger replAction + where+ -- this flag is used to suppress the logo and prompts+ isBatch = case replMode of+ InteractiveRepl -> False+ Batch _ -> True+ InteractiveBatch _ -> True + replAction =+ do status <- loadCryRC cryrc+ case status of+ CommandOk -> begin >> crySession replMode stopOnError+ _ -> return status -- | Try to set the history file. setHistoryFile :: Settings REPL -> IO (Settings REPL)@@ -201,7 +222,7 @@ cryptolCommand :: CompletionFunc REPL cryptolCommand cursor@(l,r) | ":" `isPrefixOf` l'- , Just (cmd,rest) <- splitCommand l' = case nub (findCommand cmd) of+ , Just (_,cmd,rest) <- splitCommand l' = case nub (findCommand cmd) of [c] | null rest && not (any isSpace l') -> do return (l, cmdComp cmd c)
cryptol/REPL/Logo.hs view
@@ -14,6 +14,8 @@ import Cryptol.Version (commitShortHash,commitDirty) import Data.Version (showVersion) import System.Console.ANSI+import Prelude ()+import Prelude.Compat type Version = String
lib/Cryptol.cry view
@@ -168,6 +168,13 @@ primitive type Literal : # -> * -> Prop /**+ * 'LiteralLessThan n a' asserts that the type 'a' contains all the+ * natural numbers strictly below 'n'. Note that we may have 'n = inf',+ * in which case the type 'a' must be unbounded.+ */+primitive type LiteralLessThan : # -> * -> Prop++/** * The value corresponding to a numeric type. */ primitive number : {val, rep} Literal val rep => rep@@ -195,6 +202,15 @@ [1 + (last - first)]a /**+ * A possibly infinite sequence counting up from 'first' up to (but not including) 'bound'.+ *+ * Note that if 'first' = 'bound' then the sequence will be empty.+ */+primitive fromToLessThan :+ {first, bound, a} (fin first, bound >= first, LiteralLessThan bound a) => [bound - first]a+++/** * A finite arithmetic sequence starting with 'first' and 'next', * stopping when the values reach or would skip over 'last'. *@@ -879,8 +895,8 @@ * Declarations of the form 'x @ i = e' are syntactic sugar for * 'x = generate (\i -> e)'. */-generate : {n, a, ix} (fin n, n >= 1, Integral ix, Literal (n-1) ix) => (ix -> a) -> [n]a-generate f = [ f i | i <- [0 .. n-1] ]+generate : {n, a, ix} (Integral ix, LiteralLessThan n ix) => (ix -> a) -> [n]a+generate f = [ f i | i <- [0 .. <n] ] // GF_2^n polynomial computations -------------------------------------------
lib/Float.cry view
@@ -79,6 +79,7 @@ primitive fpPosInf : {e,p} ValidFloat e p => Float e p +/** Negative infinity. */ fpNegInf : {e,p} ValidFloat e p => Float e p fpNegInf = - fpPosInf @@ -133,13 +134,33 @@ infix 20 =.= +/** Test if this value is not-a-number (NaN). */+primitive fpIsNaN : {e,p} ValidFloat e p => Float e p -> Bool -/* Returns true for numbers that are not an infinity or NaN. */-primitive- fpIsFinite : {e,p} ValidFloat e p => Float e p -> Bool+/** Test if this value is positive or negative infinity. */+primitive fpIsInf : {e,p} ValidFloat e p => Float e p -> Bool +/** Test if this value is positive or negative zero. */+primitive fpIsZero : {e,p} ValidFloat e p => Float e p -> Bool +/** Test if this value is negative. */+primitive fpIsNeg : {e,p} ValidFloat e p => Float e p -> Bool +/** Test if this value is normal (not NaN, not infinite, not zero, and not subnormal). */+primitive fpIsNormal : {e,p} ValidFloat e p => Float e p -> Bool++/**+ * Test if this value is subnormal. Subnormal values are nonzero+ * values with magnitudes smaller than can be represented with the+ * normal implicit leading bit convention.+ */+primitive fpIsSubnormal : {e,p} ValidFloat e p => Float e p -> Bool++/* Returns true for numbers that are not an infinity or NaN. */+fpIsFinite : {e,p} ValidFloat e p => Float e p -> Bool+fpIsFinite f = ~ (fpIsNaN f \/ fpIsInf f )++ /* ---------------------------------------------------------------------- * Arithmetic * ---------------------------------------------------------------------- */@@ -165,7 +186,31 @@ fpDiv : {e,p} ValidFloat e p => RoundingMode -> Float e p -> Float e p -> Float e p +/**+ * Fused-multiply-add. 'fpFMA r x y z' computes the value '(x*y)+z',+ * rounding the result according to mode 'r' only after performing both+ * operations.+ */+primitive+ fpFMA : {e,p} ValidFloat e p =>+ RoundingMode -> Float e p -> Float e p -> Float e p -> Float e p +/**+ * Absolute value of a floating-point value.+ */+primitive+ fpAbs : {e,p} ValidFloat e p =>+ Float e p -> Float e p++/**+ * Square root of a floating-point value. The square root of+ * a negative value yiels NaN, except that the sqaure root of+ * '-0.0' is '-0.0'.+ */+primitive+ fpSqrt : {e,p} ValidFloat e p =>+ RoundingMode -> Float e p -> Float e p+ /* ------------------------------------------------------------ * * Rationals * * ------------------------------------------------------------ */@@ -181,4 +226,3 @@ primitive fpFromRational : {e,p} ValidFloat e p => RoundingMode -> Rational -> Float e p-
src/Cryptol/Backend.hs view
@@ -27,39 +27,32 @@ , rationalLessThan , rationalGreaterThan , iteRational- , ppRational ) where import Control.Monad.IO.Class import Data.Kind (Type)-import Data.Ratio ( (%), numerator, denominator ) import Cryptol.Backend.FloatHelpers (BF)-import Cryptol.Backend.Monad ( PPOpts(..), EvalError(..) )-import Cryptol.TypeCheck.AST(Name)-import Cryptol.Utils.PP-+import Cryptol.Backend.Monad+ ( EvalError(..), CallStack, pushCallFrame )+import Cryptol.ModuleSystem.Name(Name)+import Cryptol.Parser.Position invalidIndex :: Backend sym => sym -> Integer -> SEval sym a-invalidIndex sym = raiseError sym . InvalidIndex . Just+invalidIndex sym i = raiseError sym (InvalidIndex (Just i)) cryUserError :: Backend sym => sym -> String -> SEval sym a-cryUserError sym = raiseError sym . UserError+cryUserError sym msg = raiseError sym (UserError msg) cryNoPrimError :: Backend sym => sym -> Name -> SEval sym a-cryNoPrimError sym = raiseError sym . NoPrim-+cryNoPrimError sym nm = raiseError sym (NoPrim nm) {-# INLINE sDelay #-} -- | Delay the given evaluation computation, returning a thunk -- which will run the computation when forced. Raise a loop -- error if the resulting thunk is forced during its own evaluation.-sDelay :: Backend sym => sym -> Maybe String -> SEval sym a -> SEval sym (SEval sym a)-sDelay sym msg m =- let msg' = maybe "" ("while evaluating "++) msg- retry = raiseError sym (LoopError msg')- in sDelayFill sym m retry-+sDelay :: Backend sym => sym -> SEval sym a -> SEval sym (SEval sym a)+sDelay sym m = sDelayFill sym m Nothing "" -- | Representation of rational numbers. -- Invariant: denominator is not 0@@ -198,16 +191,6 @@ iteRational sym p (SRational a b) (SRational c d) = SRational <$> iteInteger sym p a c <*> iteInteger sym p b d -ppRational :: Backend sym => sym -> PPOpts -> SRational sym -> Doc-ppRational sym opts (SRational n d)- | Just ni <- integerAsLit sym n- , Just di <- integerAsLit sym d- = let q = ni % di in- text "(ratio" <+> integer (numerator q) <+> (integer (denominator q) <> text ")")-- | otherwise- = text "(ratio" <+> ppInteger sym opts n <+> (ppInteger sym opts d <> text ")")- -- | This type class defines a collection of operations on bits, words and integers that -- are necessary to define generic evaluator primitives that operate on both concrete -- and symbolic values uniformly.@@ -234,13 +217,27 @@ -- which will run the computation when forced. Run the 'retry' -- computation instead if the resulting thunk is forced during -- its own evaluation.- sDelayFill :: sym -> SEval sym a -> SEval sym a -> SEval sym (SEval sym a)+ sDelayFill :: sym -> SEval sym a -> Maybe (SEval sym a) -> String -> SEval sym (SEval sym a) -- | Begin evaluating the given computation eagerly in a separate thread -- and return a thunk which will await the completion of the given computation -- when forced. sSpark :: sym -> SEval sym a -> SEval sym (SEval sym a) + -- | Push a call frame on to the current call stack while evaluating the given action+ sPushFrame :: sym -> Name -> Range -> SEval sym a -> SEval sym a+ sPushFrame sym nm rng m = sModifyCallStack sym (pushCallFrame nm rng) m++ -- | Use the given call stack while evaluating the given action+ sWithCallStack :: sym -> CallStack -> SEval sym a -> SEval sym a+ sWithCallStack sym stk m = sModifyCallStack sym (\_ -> stk) m++ -- | Apply the given function to the current call stack while evaluating the given action+ sModifyCallStack :: sym -> (CallStack -> CallStack) -> SEval sym a -> SEval sym a++ -- | Retrieve the current evaluation call stack+ sGetCallStack :: sym -> SEval sym CallStack+ -- | Merge the two given computations according to the predicate. mergeEval :: sym ->@@ -257,21 +254,6 @@ -- | Indiciate that an error condition exists raiseError :: sym -> EvalError -> SEval sym a -- -- ==== Pretty printing ====- -- | Pretty-print an individual bit- ppBit :: sym -> SBit sym -> Doc-- -- | Pretty-print a word value- ppWord :: sym -> PPOpts -> SWord sym -> Doc-- -- | Pretty-print an integer value- ppInteger :: sym -> PPOpts -> SInteger sym -> Doc-- -- | Pretty-print a floating-point value- ppFloat :: sym -> PPOpts -> SFloat sym -> Doc-- -- ==== Identifying literal values ==== -- | Determine if this symbolic bit is a boolean literal@@ -291,6 +273,9 @@ -- | Determine if this symbolic integer is a literal integerAsLit :: sym -> SInteger sym -> Maybe Integer + -- | Determine if this symbolic floating-point value is a literal+ fpAsLit :: sym -> SFloat sym -> Maybe BF+ -- ==== Creating literal values ==== -- | Construct a literal bit value from a boolean.@@ -325,6 +310,7 @@ iteBit :: sym -> SBit sym -> SBit sym -> SBit sym -> SEval sym (SBit sym) iteWord :: sym -> SBit sym -> SWord sym -> SWord sym -> SEval sym (SWord sym) iteInteger :: sym -> SBit sym -> SInteger sym -> SInteger sym -> SEval sym (SInteger sym)+ iteFloat :: sym -> SBit sym -> SFloat sym -> SFloat sym -> SEval sym (SFloat sym) -- ==== Bit operations ==== bitEq :: sym -> SBit sym -> SBit sym -> SEval sym (SBit sym)@@ -333,7 +319,6 @@ bitXor :: sym -> SBit sym -> SBit sym -> SEval sym (SBit sym) bitComplement :: sym -> SBit sym -> SEval sym (SBit sym) - -- ==== Word operations ==== -- | Extract the numbered bit from the word.@@ -674,7 +659,7 @@ SInteger sym -> SEval sym (SBit sym) - -- | Multiplicitive inverse in (Z n).+ -- | Multiplicative inverse in (Z n). -- PRECONDITION: the modulus is a prime znRecip :: sym ->@@ -689,21 +674,51 @@ fpLogicalEq :: sym -> SFloat sym -> SFloat sym -> SEval sym (SBit sym) + fpNaN :: sym -> Integer {- ^ exponent bits -} -> Integer {- ^ precision bits -} -> SEval sym (SFloat sym)+ fpPosInf :: sym -> Integer {- ^ exponent bits -} -> Integer {- ^ precision bits -} -> SEval sym (SFloat sym)+ fpPlus, fpMinus, fpMult, fpDiv :: FPArith2 sym- fpNeg :: sym -> SFloat sym -> SEval sym (SFloat sym)+ fpNeg, fpAbs :: sym -> SFloat sym -> SEval sym (SFloat sym)+ fpSqrt :: sym -> SWord sym -> SFloat sym -> SEval sym (SFloat sym) + fpFMA :: sym -> SWord sym -> SFloat sym -> SFloat sym -> SFloat sym -> SEval sym (SFloat sym)++ fpIsZero, fpIsNeg, fpIsNaN, fpIsInf, fpIsNorm, fpIsSubnorm :: sym -> SFloat sym -> SEval sym (SBit sym)++ fpToBits :: sym -> SFloat sym -> SEval sym (SWord sym)+ fpFromBits ::+ sym ->+ Integer {- ^ exponent bits -} ->+ Integer {- ^ precision bits -} ->+ SWord sym ->+ SEval sym (SFloat sym)+ fpToInteger :: sym -> String {- ^ Name of the function for error reporting -} ->- SWord sym {-^ Rounding mode -} ->- SFloat sym -> SEval sym (SInteger sym)+ SWord sym {- ^ Rounding mode -} ->+ SFloat sym ->+ SEval sym (SInteger sym) fpFromInteger :: sym ->- Integer {- exp width -} ->- Integer {- prec width -} ->+ Integer {- ^ exp width -} ->+ Integer {- ^ prec width -} -> SWord sym {- ^ rounding mode -} ->- SInteger sym {- ^ the integeer to use -} ->+ SInteger sym {- ^ the integer to use -} ->+ SEval sym (SFloat sym)++ fpToRational ::+ sym ->+ SFloat sym ->+ SEval sym (SRational sym)++ fpFromRational ::+ sym ->+ Integer {- ^ exp width -} ->+ Integer {- ^ prec width -} ->+ SWord sym {- ^ rounding mode -} ->+ SRational sym -> SEval sym (SFloat sym) type FPArith2 sym =
src/Cryptol/Backend/Concrete.hs view
@@ -37,6 +37,7 @@ import qualified Control.Exception as X import Data.Bits+import Data.Ratio import Numeric (showIntAtBase) import qualified LibBF as FP import qualified GHC.Integer.GMP.Internals as Integer@@ -136,10 +137,12 @@ type SFloat Concrete = FP.BF type SEval Concrete = Eval - raiseError _ err = io (X.throwIO err)+ raiseError _ err =+ do stk <- getCallStack+ io (X.throwIO (EvalErrorEx stk err)) assertSideCondition _ True _ = return ()- assertSideCondition _ False err = io (X.throwIO err)+ assertSideCondition sym False err = raiseError sym err wordLen _ (BV w _) = w wordAsChar _ (BV _ x) = Just $! integerToChar x@@ -160,15 +163,8 @@ sDeclareHole _ = blackhole sDelayFill _ = delayFill sSpark _ = evalSpark-- ppBit _ b | b = text "True"- | otherwise = text "False"-- ppWord _ = ppBV-- ppInteger _ _opts i = integer i-- ppFloat _ = FP.fpPP+ sModifyCallStack _ f m = modifyCallStack f m+ sGetCallStack _ = getCallStack bitLit _ b = b bitAsLit _ b = Just b@@ -182,6 +178,7 @@ iteBit _ b x y = pure $! if b then x else y iteWord _ b x y = pure $! if b then x else y iteInteger _ b x y = pure $! if b then x else y+ iteFloat _ b x y = pure $! if b then x else y wordLit _ w i = pure $! mkBv w i wordAsLit _ (BV w i) = Just (w,i)@@ -331,6 +328,11 @@ ------------------------------------------------------------------------ -- Floating Point fpLit _sym e p rat = pure (FP.fpLit e p rat)++ fpNaN _sym e p = pure (FP.BF e p FP.bfNaN)+ fpPosInf _sym e p = pure (FP.BF e p FP.bfPosInf)++ fpAsLit _ f = Just f fpExactLit _sym bf = pure bf fpEq _sym x y = pure (FP.bfValue x == FP.bfValue y) fpLogicalEq _sym x y = pure (FP.bfCompare (FP.bfValue x) (FP.bfValue y) == EQ)@@ -340,17 +342,51 @@ fpMinus = fpBinArith FP.bfSub fpMult = fpBinArith FP.bfMul fpDiv = fpBinArith FP.bfDiv- fpNeg _ x = pure x { FP.bfValue = FP.bfNeg (FP.bfValue x) }+ fpNeg _ x = pure $! x { FP.bfValue = FP.bfNeg (FP.bfValue x) }++ fpAbs _ x = pure $! x { FP.bfValue = FP.bfAbs (FP.bfValue x) }+ fpSqrt sym r x =+ do r' <- fpRoundMode sym r+ let opts = FP.fpOpts (FP.bfExpWidth x) (FP.bfPrecWidth x) r'+ pure $! x{ FP.bfValue = FP.fpCheckStatus (FP.bfSqrt opts (FP.bfValue x)) }++ fpFMA sym r x y z =+ do r' <- fpRoundMode sym r+ let opts = FP.fpOpts (FP.bfExpWidth x) (FP.bfPrecWidth x) r'+ pure $! x { FP.bfValue = FP.fpCheckStatus (FP.bfFMA opts (FP.bfValue x) (FP.bfValue y) (FP.bfValue z)) }++ fpIsZero _ x = pure (FP.bfIsZero (FP.bfValue x))+ fpIsNeg _ x = pure (FP.bfIsNeg (FP.bfValue x))+ fpIsNaN _ x = pure (FP.bfIsNaN (FP.bfValue x))+ fpIsInf _ x = pure (FP.bfIsInf (FP.bfValue x))+ fpIsNorm _ x =+ let opts = FP.fpOpts (FP.bfExpWidth x) (FP.bfPrecWidth x) FP.NearEven+ in pure (FP.bfIsNormal opts (FP.bfValue x))+ fpIsSubnorm _ x =+ let opts = FP.fpOpts (FP.bfExpWidth x) (FP.bfPrecWidth x) FP.NearEven+ in pure (FP.bfIsSubnormal opts (FP.bfValue x))++ fpFromBits _sym e p bv = pure (FP.floatFromBits e p (bvVal bv))+ fpToBits _sym (FP.BF e p v) = pure (mkBv (e+p) (FP.floatToBits e p v))+ fpFromInteger sym e p r x =- do opts <- FP.fpOpts e p <$> fpRoundMode sym r+ do r' <- fpRoundMode sym r pure FP.BF { FP.bfExpWidth = e , FP.bfPrecWidth = p , FP.bfValue = FP.fpCheckStatus $- FP.bfRoundInt opts (FP.bfFromInteger x)+ FP.bfRoundInt r' (FP.bfFromInteger x) } fpToInteger = fpCvtToInteger + fpFromRational sym e p r x =+ do mode <- fpRoundMode sym r+ pure (FP.floatFromRational e p mode (sNum x % sDenom x)) + fpToRational sym fp =+ case FP.floatToRational "fpToRational" fp of+ Left err -> raiseError sym err+ Right r -> pure $ SRational { sNum = numerator r, sDenom = denominator r }+ {-# INLINE liftBinIntMod #-} liftBinIntMod :: Monad m => (Integer -> Integer -> Integer) -> Integer -> Integer -> Integer -> m Integer@@ -371,7 +407,7 @@ fpBinArith fun = \sym r x y -> do opts <- FP.fpOpts (FP.bfExpWidth x) (FP.bfPrecWidth x) <$> fpRoundMode sym r- pure x { FP.bfValue = FP.fpCheckStatus+ pure $! x { FP.bfValue = FP.fpCheckStatus (fun opts (FP.bfValue x) (FP.bfValue y)) } fpCvtToInteger ::@@ -391,8 +427,3 @@ case FP.fpRound (bvVal w) of Left err -> raiseError sym err Right a -> pure a-----
src/Cryptol/Backend/FloatHelpers.hs view
@@ -2,22 +2,19 @@ {-# Language BangPatterns #-} module Cryptol.Backend.FloatHelpers where +import Data.Char (isDigit) import Data.Ratio(numerator,denominator)-import Data.Int(Int64)-import Data.Bits(testBit,setBit,shiftL,shiftR,(.&.),(.|.)) import LibBF import Cryptol.Utils.PP import Cryptol.Utils.Panic(panic)-import Cryptol.Backend.Monad( EvalError(..)- , PPOpts(..), PPFloatFormat(..), PPFloatExp(..)- )+import Cryptol.Backend.Monad( EvalError(..) ) data BF = BF- { bfExpWidth :: Integer- , bfPrecWidth :: Integer- , bfValue :: BigFloat+ { bfExpWidth :: !Integer+ , bfPrecWidth :: !Integer+ , bfValue :: !BigFloat } @@ -86,19 +83,32 @@ str = bfToString base fmt num fmt = addPrefix <> showRnd NearEven <> case useFPFormat opts of- FloatFree e -> withExp e $ showFreeMin+ FloatFree e -> withExp e $ showFree $ Just $ fromInteger precW FloatFixed n e -> withExp e $ showFixed $ fromIntegral n FloatFrac n -> showFrac $ fromIntegral n -- non-base 10 literals are not overloaded so we add an explicit- -- .0 if one is not present. + -- .0 if one is not present. Moreover, we trim any extra zeros+ -- that appear in a decimal representation. hacStr- | base == 10 || elem '.' str = str+ | base == 10 = trimZeros+ | elem '.' str = str | otherwise = case break (== 'p') str of (xs,ys) -> xs ++ ".0" ++ ys + trimZeros =+ case break (== '.') str of+ (xs,'.':ys) ->+ case break (not . isDigit) ys of+ (frac, suffix) -> xs ++ '.' : processFraction frac ++ suffix+ _ -> str + processFraction frac =+ case dropWhile (== '0') (reverse frac) of+ [] -> "0"+ zs -> reverse zs+ -- | Make a literal fpLit :: Integer {- ^ Exponent width -} ->@@ -152,97 +162,17 @@ ["Unexpected rounding mode", show r] -- floatFromBits :: Integer {- ^ Exponent width -} -> Integer {- ^ Precision widht -} -> Integer {- ^ Raw bits -} -> BF-floatFromBits e p bv = BF { bfValue = floatFromBits' e p bv+floatFromBits e p bv = BF { bfValue = bfFromBits (fpOpts e p NearEven) bv , bfExpWidth = e, bfPrecWidth = p } ---- | Make a float using "raw" bits.-floatFromBits' ::- Integer {- ^ Exponent width -} ->- Integer {- ^ Precision widht -} ->- Integer {- ^ Raw bits -} ->- BigFloat--floatFromBits' e p bits- | expoBiased == 0 && mant == 0 = -- zero- if isNeg then bfNegZero else bfPosZero-- | expoBiased == eMask && mant == 0 = -- infinity- if isNeg then bfNegInf else bfPosInf-- | expoBiased == eMask = bfNaN -- NaN-- | expoBiased == 0 = -- Subnormal- case bfMul2Exp opts (bfFromInteger mant) (expoVal + 1) of- (num,Ok) -> if isNeg then bfNeg num else num- (_,s) -> panic "floatFromBits" [ "Unexpected status: " ++ show s ]-- | otherwise = -- Normal- case bfMul2Exp opts (bfFromInteger mantVal) expoVal of- (num,Ok) -> if isNeg then bfNeg num else num- (_,s) -> panic "floatFromBits" [ "Unexpected status: " ++ show s ]-- where- opts = expBits e' <> precBits (p' + 1) <> allowSubnormal-- e' = fromInteger e :: Int- p' = fromInteger p - 1 :: Int- eMask = (1 `shiftL` e') - 1 :: Int64- pMask = (1 `shiftL` p') - 1 :: Integer-- isNeg = testBit bits (e' + p')-- mant = pMask .&. bits :: Integer- mantVal = mant `setBit` p' :: Integer- -- accounts for the implicit 1 bit-- expoBiased = eMask .&. fromInteger (bits `shiftR` p') :: Int64- bias = eMask `shiftR` 1 :: Int64- expoVal = expoBiased - bias - fromIntegral p' :: Int64-- -- | Turn a float into raw bits. -- @NaN@ is represented as a positive "quiet" @NaN@ -- (most significant bit in the significand is set, the rest of it is 0) floatToBits :: Integer -> Integer -> BigFloat -> Integer-floatToBits e p bf = (isNeg `shiftL` (e' + p'))- .|. (expBiased `shiftL` p')- .|. (mant `shiftL` 0)- where- e' = fromInteger e :: Int- p' = fromInteger p - 1 :: Int-- eMask = (1 `shiftL` e') - 1 :: Integer- pMask = (1 `shiftL` p') - 1 :: Integer-- (isNeg, expBiased, mant) =- case bfToRep bf of- BFNaN -> (0, eMask, 1 `shiftL` (p' - 1))- BFRep s num -> (sign, be, ma)- where- sign = case s of- Neg -> 1- Pos -> 0-- (be,ma) =- case num of- Zero -> (0,0)- Num i ev- | ex == 0 -> (0, i `shiftL` (p' - m -1))- | otherwise -> (ex, (i `shiftL` (p' - m)) .&. pMask)- where- m = msb 0 i - 1- bias = eMask `shiftR` 1- ex = toInteger ev + bias + toInteger m-- Inf -> (eMask,0)-- msb !n j = if j == 0 then n else msb (n+1) (j `shiftR` 1)+floatToBits e p bf = bfToBits (fpOpts e p NearEven) bf
src/Cryptol/Backend/Monad.hs view
@@ -1,6 +1,6 @@ -- |--- Module : Cryptol.Eval.Monad--- Copyright : (c) 2013-2016 Galois, Inc.+-- Module : Cryptol.Backend.Monad+-- Copyright : (c) 2013-2020 Galois, Inc. -- License : BSD3 -- Maintainer : cryptol@galois.com -- Stability : provisional@@ -16,80 +16,97 @@ ( -- * Evaluation monad Eval(..) , runEval-, EvalOpts(..)-, PPOpts(..)-, asciiMode-, PPFloatFormat(..)-, PPFloatExp(..)-, defaultPPOpts , io , delayFill , ready , blackhole , evalSpark , maybeReady+ -- * Call stacks+, CallStack+, getCallStack+, withCallStack+, modifyCallStack+, combineCallStacks+, pushCallFrame+, displayCallStack -- * Error reporting , Unsupported(..) , EvalError(..)+, EvalErrorEx(..) , evalPanic , wordTooWide-, typeCannotBeDemoted+, WordTooWide(..) ) where import Control.Concurrent import Control.Concurrent.STM import Control.Monad-import qualified Control.Monad.Fail as Fail-import Control.Monad.Fix import Control.Monad.IO.Class+import Data.Foldable (toList)+import Data.Sequence (Seq)+import qualified Data.Sequence as Seq import Data.Typeable (Typeable) import qualified Control.Exception as X +import Cryptol.Parser.Position import Cryptol.Utils.Panic import Cryptol.Utils.PP-import Cryptol.Utils.Logger(Logger)-import Cryptol.TypeCheck.AST(Type,Name)+import Cryptol.TypeCheck.AST(Name) -- | A computation that returns an already-evaluated value. ready :: a -> Eval a ready a = Ready a --- | How to pretty print things when evaluating-data PPOpts = PPOpts- { useAscii :: Bool- , useBase :: Int- , useInfLength :: Int- , useFPBase :: Int- , useFPFormat :: PPFloatFormat- } -asciiMode :: PPOpts -> Integer -> Bool-asciiMode opts width = useAscii opts && (width == 7 || width == 8)+-- | The type of dynamic call stacks for the interpreter.+-- New frames are pushed onto the right side of the sequence.+type CallStack = Seq (Name, Range) -data PPFloatFormat =- FloatFixed Int PPFloatExp -- ^ Use this many significant digis- | FloatFrac Int -- ^ Show this many digits after floating point- | FloatFree PPFloatExp -- ^ Use the correct number of digits+-- | Pretty print a call stack with each call frame on a separate+-- line, with most recent call frames at the top.+displayCallStack :: CallStack -> Doc+displayCallStack = vcat . map f . toList . Seq.reverse+ where+ f (nm,rng)+ | rng == emptyRange = pp nm+ | otherwise = pp nm <+> text "called at" <+> pp rng -data PPFloatExp = ForceExponent -- ^ Always show an exponent- | AutoExponent -- ^ Only show exponent when needed +-- | Combine the call stack of a function value with the call+-- stack of the current calling context. This algorithm is+-- the same one GHC uses to compute profiling calling contexts.+--+-- The algorithm is as follows.+--+-- ccs ++> ccsfn = ccs ++ dropCommonPrefix ccs ccsfn+--+-- where+--+-- dropCommonPrefix A B+-- -- returns the suffix of B after removing any prefix common+-- -- to both A and B.+combineCallStacks ::+ CallStack {- ^ call stack of the application context -} ->+ CallStack {- ^ call stack of the function being applied -} ->+ CallStack+combineCallStacks appstk fnstk = appstk <> dropCommonPrefix appstk fnstk+ where+ dropCommonPrefix _ Seq.Empty = Seq.Empty+ dropCommonPrefix Seq.Empty fs = fs+ dropCommonPrefix (a Seq.:<| as) xs@(f Seq.:<| fs)+ | a == f = dropCommonPrefix as fs+ | otherwise = xs -defaultPPOpts :: PPOpts-defaultPPOpts = PPOpts { useAscii = False, useBase = 10, useInfLength = 5- , useFPBase = 16- , useFPFormat = FloatFree AutoExponent- }+-- | Add a call frame to the top of a call stack+pushCallFrame :: Name -> Range -> CallStack -> CallStack+pushCallFrame nm rng stk@( _ Seq.:|> (nm',rng'))+ | nm == nm', rng == rng' = stk+pushCallFrame nm rng stk = stk Seq.:|> (nm,rng) --- | Some options for evalutaion-data EvalOpts = EvalOpts- { evalLogger :: Logger -- ^ Where to print stuff (e.g., for @trace@)- , evalPPOpts :: PPOpts -- ^ How to pretty print things.- }- -- | The monad for Cryptol evaluation. -- A computation is either "ready", which means it represents -- only trivial computation, or is an "eval" action which must@@ -97,7 +114,7 @@ -- represents a delayed, shared computation. data Eval a = Ready !a- | Eval !(IO a)+ | Eval !(CallStack -> IO a) | Thunk !(TVar (ThunkState a)) -- | This datastructure tracks the lifecycle of a thunk.@@ -107,7 +124,7 @@ -- cryptol expression that is bound to a name, and is not -- already obviously a value (and in a few other places as -- well) will get turned into a thunk in order to avoid--- recomputations. These thunks will start in the `Unforced`+-- recomputation. These thunks will start in the `Unforced` -- state, and have a backup computation that just raises -- the `LoopError` exception. --@@ -129,16 +146,20 @@ data ThunkState a = Void !String -- ^ This thunk has not yet been initialized- | Unforced !(IO a) !(IO a)+ | Unforced !(IO a) !(Maybe (IO a)) !String !CallStack -- ^ This thunk has not yet been forced. We keep track of the "main"- -- computation to run and a "backup" computation to run if we+ -- computation to run and an optional "backup" computation to run if we -- detect a tight loop when evaluating the first one.- | UnderEvaluation !ThreadId !(IO a)+ -- The final two arguments are used to throw a loop exception+ -- if the backup computation also causes a tight loop.+ | UnderEvaluation !ThreadId !(Maybe (IO a)) !String !CallStack -- ^ This thunk is currently being evaluated by the thread with the given- -- thread ID. We track the "backup" computation to run if we detect+ -- thread ID. We track an optional "backup" computation to run if we detect -- a tight loop evaluating this thunk. If the thunk is being evaluated -- by some other thread, the current thread will await its completion.- | ForcedErr !EvalError+ -- The final two arguments are used to throw a loop exception+ -- if the backup computation also causes a tight loop.+ | ForcedErr !EvalErrorEx -- ^ This thunk has been forced, and its evaluation results in an exception | Forced !a -- ^ This thunk has been forced to the given value@@ -148,7 +169,7 @@ -- it requires no computation to return. maybeReady :: Eval a -> Eval (Maybe a) maybeReady (Ready a) = pure (Just a)-maybeReady (Thunk tv) = Eval $+maybeReady (Thunk tv) = Eval $ \_ -> readTVarIO tv >>= \case Forced a -> pure (Just a) _ -> pure Nothing@@ -163,11 +184,13 @@ -- its own evaluation. delayFill :: Eval a {- ^ Computation to delay -} ->- Eval a {- ^ Backup computation to run if a tight loop is detected -} ->+ Maybe (Eval a) {- ^ Optional backup computation to run if a tight loop is detected -} ->+ String {- ^ message for the <<loop>> exception if a tight loop is detected -} -> Eval (Eval a)-delayFill e@(Ready _) _ = return e-delayFill e@(Thunk _) _ = return e-delayFill (Eval x) backup = Eval (Thunk <$> newTVarIO (Unforced x (runEval backup)))+delayFill e@(Ready _) _ _ = return e+delayFill e@(Thunk _) _ _ = return e+delayFill (Eval x) backup msg =+ Eval (\stk -> Thunk <$> newTVarIO (Unforced (x stk) (runEval stk <$> backup) msg stk)) -- | Begin executing the given operation in a separate thread, -- returning a thunk which will await the completion of@@ -183,24 +206,24 @@ -- been forced. If so, return the result. Otherwise, -- fork a thread to force this computation and return -- the thunk.-evalSpark (Thunk tv) = Eval $+evalSpark (Thunk tv) = Eval $ \_stk -> readTVarIO tv >>= \case Forced x -> return (Ready x)- ForcedErr ex -> return (Eval (X.throwIO ex))+ ForcedErr ex -> return (Eval $ \_ -> (X.throwIO ex)) _ -> do _ <- forkIO (sparkThunk tv) return (Thunk tv) -- If the computation is nontrivial but not already a thunk, -- create a thunk and fork a thread to force it.-evalSpark (Eval x) = Eval $- do tv <- newTVarIO (Unforced x (X.throwIO (LoopError "")))+evalSpark (Eval x) = Eval $ \stk ->+ do tv <- newTVarIO (Unforced (x stk) Nothing "" stk) _ <- forkIO (sparkThunk tv) return (Thunk tv) -- | To the work of forcing a thunk. This is the worker computation--- that is foked off via @evalSpark@.+-- that is forked off via @evalSpark@. sparkThunk :: TVar (ThunkState a) -> IO () sparkThunk tv = do tid <- myThreadId@@ -212,13 +235,13 @@ do st <- readTVar tv case st of Void _ -> retry- Unforced _ backup -> writeTVar tv (UnderEvaluation tid backup)+ Unforced _ backup msg stk -> writeTVar tv (UnderEvaluation tid backup msg stk) _ -> return () return st -- If we successfully claimed the thunk to work on, run the computation and -- update the thunk state with the result. case st of- Unforced work _ ->+ Unforced work _ _ _ -> X.try work >>= \case Left err -> atomically (writeTVar tv (ForcedErr err)) Right a -> atomically (writeTVar tv (Forced a))@@ -232,10 +255,10 @@ blackhole :: String {- ^ A name to associate with this thunk. -} -> Eval (Eval a, Eval a -> Eval ())-blackhole msg = Eval $+blackhole msg = Eval $ \stk -> do tv <- newTVarIO (Void msg) let set (Ready x) = io $ atomically (writeTVar tv (Forced x))- set m = io $ atomically (writeTVar tv (Unforced (runEval m) (X.throwIO (LoopError msg))))+ set m = io $ atomically (writeTVar tv (Unforced (runEval stk m) Nothing msg stk)) return (Thunk tv, set) -- | Force a thunk to get the result.@@ -254,16 +277,19 @@ case res of -- In this case, we claim the thunk. Update the state to indicate -- that we are working on it.- Unforced _ backup -> writeTVar tv (UnderEvaluation tid backup)+ Unforced _ backup msg stk -> writeTVar tv (UnderEvaluation tid backup msg stk) -- In this case, the thunk is already being evaluated. If it is -- under evaluation by this thread, we have to run the backup computation, -- and "consume" it by updating the backup computation to one that throws -- a loop error. If some other thread is evaluating, reset the -- transaction to await completion of the thunk.- UnderEvaluation t _- | tid == t -> writeTVar tv (UnderEvaluation tid (X.throwIO (LoopError "")))- | otherwise -> retry -- wait, if some other thread is evaualting+ UnderEvaluation t backup msg stk+ | tid == t ->+ case backup of+ Just _ -> writeTVar tv (UnderEvaluation tid Nothing msg stk)+ Nothing -> writeTVar tv (ForcedErr (EvalErrorEx stk (LoopError msg)))+ | otherwise -> retry -- wait, if some other thread is evaluating _ -> return () -- Return the original thunk state so we can decide what work to do@@ -283,25 +309,43 @@ Void msg -> evalPanic "unDelay" ["Thunk forced before it was initialized", msg] Forced x -> pure x ForcedErr e -> X.throwIO e- UnderEvaluation _ backup -> doWork backup -- this thread was already evaluating this thunk- Unforced work _ -> doWork work+ -- this thread was already evaluating this thunk+ UnderEvaluation _ (Just backup) _ _ -> doWork backup+ UnderEvaluation _ Nothing msg stk -> X.throwIO (EvalErrorEx stk (LoopError msg))+ Unforced work _ _ _ -> doWork work +-- | Get the current call stack+getCallStack :: Eval CallStack+getCallStack = Eval (\stk -> pure stk)++-- | Execute the action with the given call stack+withCallStack :: CallStack -> Eval a -> Eval a+withCallStack stk m = Eval (\_ -> runEval stk m)++-- | Run the given action with a modify call stack+modifyCallStack :: (CallStack -> CallStack) -> Eval a -> Eval a+modifyCallStack f m =+ Eval $ \stk ->+ do let stk' = f stk+ -- putStrLn $ unwords ["Pushing call stack", show (displayCallStack stk')]+ runEval stk' m+ -- | Execute the given evaluation action.-runEval :: Eval a -> IO a-runEval (Ready a) = return a-runEval (Eval x) = x-runEval (Thunk tv) = unDelay tv+runEval :: CallStack -> Eval a -> IO a+runEval _ (Ready a) = return a+runEval stk (Eval x) = x stk+runEval _ (Thunk tv) = unDelay tv {-# INLINE evalBind #-} evalBind :: Eval a -> (a -> Eval b) -> Eval b evalBind (Ready a) f = f a-evalBind (Eval x) f = Eval (x >>= runEval . f)-evalBind (Thunk x) f = Eval (unDelay x >>= runEval . f)+evalBind (Eval x) f = Eval (\stk -> x stk >>= runEval stk . f)+evalBind (Thunk x) f = Eval (\stk -> unDelay x >>= runEval stk . f) instance Functor Eval where fmap f (Ready x) = Ready (f x)- fmap f (Eval m) = Eval (f <$> m)- fmap f (Thunk tv) = Eval (f <$> unDelay tv)+ fmap f (Eval m) = Eval (\stk -> f <$> m stk)+ fmap f (Thunk tv) = Eval (\_ -> f <$> unDelay tv) {-# INLINE fmap #-} instance Applicative Eval where@@ -316,18 +360,12 @@ {-# INLINE return #-} {-# INLINE (>>=) #-} -instance Fail.MonadFail Eval where- fail x = Eval (fail x)- instance MonadIO Eval where liftIO = io -instance MonadFix Eval where- mfix f = Eval $ mfix (\x -> runEval (f x))- -- | Lift an 'IO' computation into the 'Eval' monad. io :: IO a -> Eval a-io m = Eval m+io m = Eval (\_stk -> m) {-# INLINE io #-} @@ -341,37 +379,53 @@ -- | Data type describing errors that can occur during evaluation. data EvalError = InvalidIndex (Maybe Integer) -- ^ Out-of-bounds index- | TypeCannotBeDemoted Type -- ^ Non-numeric type passed to @number@ function | DivideByZero -- ^ Division or modulus by 0 | NegativeExponent -- ^ Exponentiation by negative integer | LogNegative -- ^ Logarithm of a negative integer- | WordTooWide Integer -- ^ Bitvector too large | UserError String -- ^ Call to the Cryptol @error@ primitive | LoopError String -- ^ Detectable nontermination | NoPrim Name -- ^ Primitive with no implementation | BadRoundingMode Integer -- ^ Invalid rounding mode | BadValue String -- ^ Value outside the domain of a partial function.- deriving (Typeable,Show)+ deriving Typeable instance PP EvalError where ppPrec _ e = case e of InvalidIndex (Just i) -> text "invalid sequence index:" <+> integer i InvalidIndex Nothing -> text "invalid sequence index"- TypeCannotBeDemoted t -> text "type cannot be demoted:" <+> pp t DivideByZero -> text "division by 0" NegativeExponent -> text "negative exponent" LogNegative -> text "logarithm of negative"- WordTooWide w ->- text "word too wide for memory:" <+> integer w <+> text "bits" UserError x -> text "Run-time error:" <+> text x- LoopError x -> text "<<loop>>" <+> text x+ LoopError x -> vcat [ text "<<loop>>" <+> text x+ , text "This usually occurs due to an improper recursive definition,"+ , text "but may also result from retrying a previously interrupted"+ , text "computation (e.g., after CTRL^C). In that case, you may need to"+ , text "`:reload` the current module to reset to a good state."+ ] BadRoundingMode r -> "invalid rounding mode" <+> integer r BadValue x -> "invalid input for" <+> backticks (text x) NoPrim x -> text "unimplemented primitive:" <+> pp x -instance X.Exception EvalError+instance Show EvalError where+ show = show . pp +data EvalErrorEx =+ EvalErrorEx CallStack EvalError+ deriving Typeable +instance PP EvalErrorEx where+ ppPrec _ (EvalErrorEx stk ex) = vcat ([ pp ex ] ++ callStk)++ where+ callStk | Seq.null stk = []+ | otherwise = [ text "-- Backtrace --", displayCallStack stk ]++instance Show EvalErrorEx where+ show = show . pp++instance X.Exception EvalErrorEx+ data Unsupported = UnsupportedSymbolicOp String -- ^ Operation cannot be supported in the symbolic simulator deriving (Typeable,Show)@@ -382,13 +436,20 @@ instance X.Exception Unsupported ---- | For things like @`(inf)@ or @`(0-1)@.-typeCannotBeDemoted :: Type -> a-typeCannotBeDemoted t = X.throw (TypeCannotBeDemoted t)- -- | For when we know that a word is too wide and will exceed gmp's -- limits (though words approaching this size will probably cause the -- system to crash anyway due to lack of memory). wordTooWide :: Integer -> a wordTooWide w = X.throw (WordTooWide w)++data WordTooWide = WordTooWide Integer -- ^ Bitvector too large+ deriving Typeable++instance PP WordTooWide where+ ppPrec _ (WordTooWide w) =+ text "word too wide for memory:" <+> integer w <+> text "bits"++instance Show WordTooWide where+ show = show . pp++instance X.Exception WordTooWide
src/Cryptol/Backend/SBV.hs view
@@ -6,6 +6,7 @@ -- Stability : provisional -- Portability : portable +{-# LANGUAGE CPP #-} {-# LANGUAGE DeriveFunctor #-} {-# LANGUAGE FlexibleInstances #-} {-# LANGUAGE GeneralizedNewtypeDeriving #-}@@ -43,14 +44,14 @@ import qualified Data.SBV.Internals as SBV import Cryptol.Backend-import Cryptol.Backend.Concrete ( integerToChar, ppBV, BV(..) )+import Cryptol.Backend.Concrete ( integerToChar ) import Cryptol.Backend.Monad ( Eval(..), blackhole, delayFill, evalSpark- , EvalError(..), Unsupported(..)+ , EvalError(..), EvalErrorEx(..), Unsupported(..)+ , modifyCallStack, getCallStack ) import Cryptol.Utils.Panic (panic)-import Cryptol.Utils.PP data SBV = SBV@@ -73,23 +74,30 @@ literalSWord :: Int -> Integer -> SWord SBV literalSWord w i = svInteger (KBounded False w) i +svMkSymVar_ :: Maybe Quantifier -> Kind -> Maybe String -> SBV.State -> IO SVal+#if MIN_VERSION_sbv(8,8,0)+svMkSymVar_ = svMkSymVar . SBV.NonQueryVar+#else+svMkSymVar_ = svMkSymVar+#endif+ freshBV_ :: SBV -> Int -> IO (SWord SBV) freshBV_ (SBV stateVar _) w =- withMVar stateVar (svMkSymVar Nothing (KBounded False w) Nothing)+ withMVar stateVar (svMkSymVar_ Nothing (KBounded False w) Nothing) freshSBool_ :: SBV -> IO (SBit SBV) freshSBool_ (SBV stateVar _) =- withMVar stateVar (svMkSymVar Nothing KBool Nothing)+ withMVar stateVar (svMkSymVar_ Nothing KBool Nothing) freshSInteger_ :: SBV -> IO (SInteger SBV) freshSInteger_ (SBV stateVar _) =- withMVar stateVar (svMkSymVar Nothing KUnbounded Nothing)+ withMVar stateVar (svMkSymVar_ Nothing KUnbounded Nothing) -- SBV Evaluation monad ------------------------------------------------------- data SBVResult a- = SBVError !EvalError+ = SBVError !EvalErrorEx | SBVResult !SVal !a -- safety predicate and result instance Functor SBVResult where@@ -146,17 +154,19 @@ type SFloat SBV = () -- XXX: not implemented type SEval SBV = SBVEval - raiseError _ err = SBVEval (pure (SBVError err))+ raiseError _ err = SBVEval $+ do stk <- getCallStack+ pure (SBVError (EvalErrorEx stk err)) - assertSideCondition _ cond err- | Just False <- svAsBool cond = SBVEval (pure (SBVError err))+ assertSideCondition sym cond err+ | Just False <- svAsBool cond = raiseError sym err | otherwise = SBVEval (pure (SBVResult cond ())) isReady _ (SBVEval (Ready _)) = True isReady _ _ = False - sDelayFill _ m retry = SBVEval $- do m' <- delayFill (sbvEval m) (sbvEval retry)+ sDelayFill _ m retry msg = SBVEval $+ do m' <- delayFill (sbvEval m) (sbvEval <$> retry) msg pure (pure (SBVEval m')) sSpark _ m = SBVEval $@@ -167,6 +177,11 @@ do (hole, fill) <- blackhole msg pure (pure (SBVEval hole, \m -> SBVEval (fmap pure $ fill (sbvEval m)))) + sModifyCallStack _ f (SBVEval m) = SBVEval $+ modifyCallStack f m++ sGetCallStack _ = SBVEval (pure <$> getCallStack)+ mergeEval _sym f c mx my = SBVEval $ do rx <- sbvEval mx ry <- sbvEval my@@ -187,16 +202,6 @@ wordLen _ v = toInteger (intSizeOf v) wordAsChar _ v = integerToChar <$> svAsInteger v - ppBit _ v- | Just b <- svAsBool v = text $! if b then "True" else "False"- | otherwise = text "?"- ppWord sym opts v- | Just x <- svAsInteger v = ppBV opts (BV (wordLen sym v) x)- | otherwise = text "[?]"- ppInteger _ _opts v- | Just x <- svAsInteger v = integer x- | otherwise = text "[?]"- iteBit _ b x y = pure $! svSymbolicMerge KBool True b x y iteWord _ b x y = pure $! svSymbolicMerge (kindOf x) True b x y iteInteger _ b x y = pure $! svSymbolicMerge KUnbounded True b x y@@ -319,20 +324,37 @@ znNegate sym m a = sModNegate sym m a znRecip = sModRecip - ppFloat _ _ _ = text "[?]"- fpExactLit _ _ = unsupported "fpExactLit"- fpLit _ _ _ _ = unsupported "fpLit"- fpLogicalEq _ _ _ = unsupported "fpLogicalEq"- fpEq _ _ _ = unsupported "fpEq"- fpLessThan _ _ _ = unsupported "fpLessThan"- fpGreaterThan _ _ _ = unsupported "fpGreaterThan"- fpPlus _ _ _ _ = unsupported "fpPlus"- fpMinus _ _ _ _ = unsupported "fpMinus"- fpMult _ _ _ _ = unsupported "fpMult"- fpDiv _ _ _ _ = unsupported "fpDiv"- fpNeg _ _ = unsupported "fpNeg"- fpFromInteger _ _ _ _ _ = unsupported "fpFromInteger"- fpToInteger _ _ _ _ = unsupported "fpToInteger"+ fpAsLit _ _ = Nothing+ iteFloat _ _ _ _ = unsupported "iteFloat"+ fpNaN _ _ _ = unsupported "fpNaN"+ fpPosInf _ _ _ = unsupported "fpPosInf"+ fpExactLit _ _ = unsupported "fpExactLit"+ fpLit _ _ _ _ = unsupported "fpLit"+ fpLogicalEq _ _ _ = unsupported "fpLogicalEq"+ fpEq _ _ _ = unsupported "fpEq"+ fpLessThan _ _ _ = unsupported "fpLessThan"+ fpGreaterThan _ _ _ = unsupported "fpGreaterThan"+ fpPlus _ _ _ _ = unsupported "fpPlus"+ fpMinus _ _ _ _ = unsupported "fpMinus"+ fpMult _ _ _ _ = unsupported "fpMult"+ fpDiv _ _ _ _ = unsupported "fpDiv"+ fpAbs _ _ = unsupported "fpAbs"+ fpSqrt _ _ _ = unsupported "fpSqrt"+ fpFMA _ _ _ _ _ = unsupported "fpFMA"+ fpNeg _ _ = unsupported "fpNeg"+ fpFromInteger _ _ _ _ _ = unsupported "fpFromInteger"+ fpToInteger _ _ _ _ = unsupported "fpToInteger"+ fpIsZero _ _ = unsupported "fpIsZero"+ fpIsInf _ _ = unsupported "fpIsInf"+ fpIsNeg _ _ = unsupported "fpIsNeg"+ fpIsNaN _ _ = unsupported "fpIsNaN"+ fpIsNorm _ _ = unsupported "fpIsNorm"+ fpIsSubnorm _ _ = unsupported "fpIsSubnorm"+ fpToBits _ _ = unsupported "fpToBits"+ fpFromBits _ _ _ _ = unsupported "fpFromBits"+ fpToRational _ _ = unsupported "fpToRational"+ fpFromRational _ _ _ _ _ = unsupported "fpFromRational"+ unsupported :: String -> SEval SBV a unsupported x = liftIO (X.throw (UnsupportedSymbolicOp x))
src/Cryptol/Backend/What4.hs view
@@ -32,18 +32,16 @@ import qualified What4.Interface as W4 import qualified What4.SWord as SW--import qualified Cryptol.Backend.What4.SFloat as FP+import qualified What4.SFloat as FP import Cryptol.Backend-import Cryptol.Backend.Concrete( BV(..), ppBV ) import Cryptol.Backend.FloatHelpers import Cryptol.Backend.Monad- ( Eval(..), EvalError(..), Unsupported(..)- , delayFill, blackhole, evalSpark+ ( Eval(..), EvalError(..), EvalErrorEx(..)+ , Unsupported(..), delayFill, blackhole, evalSpark+ , modifyCallStack, getCallStack ) import Cryptol.Utils.Panic-import Cryptol.Utils.PP data What4 sym =@@ -72,7 +70,7 @@ -- | The symbolic value we computed. data W4Result sym a- = W4Error !EvalError+ = W4Error !EvalErrorEx -- ^ A malformed value | W4Result !(W4.Pred sym) !a@@ -186,7 +184,9 @@ -- | A fully undefined symbolic value evalError :: W4.IsSymExprBuilder sym => EvalError -> W4Eval sym a-evalError err = W4Eval (pure (W4Error err))+evalError err = W4Eval $ W4Conn $ \_sym ->+ do stk <- getCallStack+ pure (W4Error (EvalErrorEx stk err)) -------------------------------------------------------------------------------- @@ -220,17 +220,21 @@ Ready _ -> True _ -> False - sDelayFill _ m retry =+ sDelayFill _ m retry msg = total do sym <- getSym- doEval (w4Thunk <$> delayFill (w4Eval m sym) (w4Eval retry sym))+ doEval (w4Thunk <$> delayFill (w4Eval m sym) (w4Eval <$> retry <*> pure sym) msg) sSpark _ m = total do sym <- getSym doEval (w4Thunk <$> evalSpark (w4Eval m sym)) + sModifyCallStack _ f (W4Eval (W4Conn m)) =+ W4Eval (W4Conn \sym -> modifyCallStack f (m sym)) + sGetCallStack _ = total (doEval getCallStack)+ sDeclareHole _ msg = total do (hole, fill) <- doEval (blackhole msg)@@ -288,25 +292,10 @@ integerAsLit _ v = W4.asInteger v - ppBit _ v- | Just b <- W4.asConstantPred v = text $! if b then "True" else "False"- | otherwise = text "?"-- ppWord _ opts v- | Just x <- SW.bvAsUnsignedInteger v- = ppBV opts (BV (SW.bvWidth v) x)-- | otherwise = text "[?]"-- ppInteger _ _opts v- | Just x <- W4.asInteger v = integer x- | otherwise = text "[?]"-- ppFloat _ _opts _ = text "[?]"- iteBit sym c x y = liftIO (W4.itePred (w4 sym) c x y) iteWord sym c x y = liftIO (SW.bvIte (w4 sym) c x y) iteInteger sym c x y = liftIO (W4.intIte (w4 sym) c x y)+ iteFloat sym p x y = liftIO (FP.fpIte (w4 sym) p x y) bitEq sym x y = liftIO (W4.eqPred (w4 sym) x y) bitAnd sym x y = liftIO (W4.andPred (w4 sym) x y)@@ -443,10 +432,18 @@ -------------------------------------------------------------- fpLit sym e p r = liftIO $ FP.fpFromRationalLit (w4 sym) e p r+ fpAsLit _ f = BF e p <$> FP.fpAsLit f+ where (e,p) = FP.fpSize f fpExactLit sym BF{ bfExpWidth = e, bfPrecWidth = p, bfValue = bf } = liftIO (FP.fpFromBinary (w4 sym) e p =<< SW.bvLit (w4 sym) (e+p) (floatToBits e p bf)) + fpNaN sym e p = liftIO (FP.fpNaN (w4 sym) e p)+ fpPosInf sym e p = liftIO (FP.fpPosInf (w4 sym) e p)++ fpToBits sym f = liftIO (FP.fpToBinary (w4 sym) f)+ fpFromBits sym e p w = liftIO (FP.fpFromBinary (w4 sym) e p w)+ fpEq sym x y = liftIO $ FP.fpEqIEEE (w4 sym) x y fpLessThan sym x y = liftIO $ FP.fpLtIEEE (w4 sym) x y fpGreaterThan sym x y = liftIO $ FP.fpGtIEEE (w4 sym) x y@@ -458,12 +455,30 @@ fpDiv = fpBinArith FP.fpDiv fpNeg sym x = liftIO $ FP.fpNeg (w4 sym) x+ fpAbs sym x = liftIO $ FP.fpAbs (w4 sym) x+ fpSqrt sym r x =+ do rm <- fpRoundingMode sym r+ liftIO $ FP.fpSqrt (w4 sym) rm x + fpFMA sym r x y z =+ do rm <- fpRoundingMode sym r+ liftIO $ FP.fpFMA (w4 sym) rm x y z++ fpIsZero sym x = liftIO $ FP.fpIsZero (w4 sym) x+ fpIsNeg sym x = liftIO $ FP.fpIsNeg (w4 sym) x+ fpIsNaN sym x = liftIO $ FP.fpIsNaN (w4 sym) x+ fpIsInf sym x = liftIO $ FP.fpIsInf (w4 sym) x+ fpIsNorm sym x = liftIO $ FP.fpIsNorm (w4 sym) x+ fpIsSubnorm sym x = liftIO $ FP.fpIsSubnorm (w4 sym) x+ fpFromInteger sym e p r x = do rm <- fpRoundingMode sym r liftIO $ FP.fpFromInteger (w4 sym) e p rm x fpToInteger = fpCvtToInteger++ fpFromRational = fpCvtFromRational+ fpToRational = fpCvtToRational sModAdd :: W4.IsSymExprBuilder sym => sym -> Integer -> W4.SymInteger sym -> W4.SymInteger sym -> IO (W4.SymInteger sym)
− src/Cryptol/Backend/What4/SFloat.hs
@@ -1,362 +0,0 @@-{-# Language DataKinds #-}-{-# Language FlexibleContexts #-}-{-# Language GADTs #-}-{-# Language RankNTypes #-}-{-# Language TypeApplications #-}-{-# Language TypeOperators #-}--- | Working with floats of dynamic sizes.--- This should probably be moved to What4 one day.-module Cryptol.Backend.What4.SFloat- ( -- * Interface- SFloat(..)- , fpReprOf- , fpSize- , fpRepr-- -- * Constants- , fpFresh- , fpNaN- , fpPosInf- , fpFromRationalLit-- -- * Interchange formats- , fpFromBinary- , fpToBinary-- -- * Relations- , SFloatRel- , fpEq- , fpEqIEEE- , fpLtIEEE- , fpGtIEEE-- -- * Arithmetic- , SFloatBinArith- , fpNeg- , fpAdd- , fpSub- , fpMul- , fpDiv-- -- * Conversions- , fpRound- , fpToReal- , fpFromReal- , fpFromRational- , fpToRational- , fpFromInteger-- -- * Queries- , fpIsInf, fpIsNaN-- -- * Exceptions- , UnsupportedFloat(..)- , FPTypeError(..)- ) where--import Control.Exception--import Data.Parameterized.Some-import Data.Parameterized.NatRepr--import What4.BaseTypes-import What4.Panic(panic)-import What4.SWord-import What4.Interface---- | Symbolic floating point numbers.-data SFloat sym where- SFloat :: IsExpr (SymExpr sym) => SymFloat sym fpp -> SFloat sym---------------------------------------------------------------------------------------- | This exception is thrown if the operations try to create a--- floating point value we do not support-data UnsupportedFloat =- UnsupportedFloat { fpWho :: String, exponentBits, precisionBits :: Integer }- deriving Show----- | Throw 'UnsupportedFloat' exception-unsupported ::- String {- ^ Label -} ->- Integer {- ^ Exponent width -} ->- Integer {- ^ Precision width -} ->- IO a-unsupported l e p =- throwIO UnsupportedFloat { fpWho = l- , exponentBits = e- , precisionBits = p }--instance Exception UnsupportedFloat---- | This exceptoin is throws if the types don't match.-data FPTypeError =- FPTypeError { fpExpected :: Some BaseTypeRepr- , fpActual :: Some BaseTypeRepr- }- deriving Show--instance Exception FPTypeError--fpTypeMismatch :: BaseTypeRepr t1 -> BaseTypeRepr t2 -> IO a-fpTypeMismatch expect actual =- throwIO FPTypeError { fpExpected = Some expect- , fpActual = Some actual- }-fpTypeError :: FloatPrecisionRepr t1 -> FloatPrecisionRepr t2 -> IO a-fpTypeError t1 t2 =- fpTypeMismatch (BaseFloatRepr t1) (BaseFloatRepr t2)-------------------------------------------------------------------------------------- | Construct the 'FloatPrecisionRepr' with the given parameters.-fpRepr ::- Integer {- ^ Exponent width -} ->- Integer {- ^ Precision width -} ->- Maybe (Some FloatPrecisionRepr)-fpRepr iE iP =- do Some e <- someNat iE- LeqProof <- testLeq (knownNat @2) e- Some p <- someNat iP- LeqProof <- testLeq (knownNat @2) p- pure (Some (FloatingPointPrecisionRepr e p))--fpReprOf ::- IsExpr (SymExpr sym) => sym -> SymFloat sym fpp -> FloatPrecisionRepr fpp-fpReprOf _ e =- case exprType e of- BaseFloatRepr r -> r--fpSize :: SFloat sym -> (Integer,Integer)-fpSize (SFloat f) =- case exprType f of- BaseFloatRepr (FloatingPointPrecisionRepr e p) -> (intValue e, intValue p)-------------------------------------------------------------------------------------- Constants---- | A fresh variable of the given type.-fpFresh ::- IsSymExprBuilder sym =>- sym ->- Integer ->- Integer ->- IO (SFloat sym)-fpFresh sym e p- | Just (Some fpp) <- fpRepr e p =- SFloat <$> freshConstant sym emptySymbol (BaseFloatRepr fpp)- | otherwise = unsupported "fpFresh" e p---- | Not a number-fpNaN ::- IsExprBuilder sym =>- sym ->- Integer {- ^ Exponent width -} ->- Integer {- ^ Precision width -} ->- IO (SFloat sym)-fpNaN sym e p- | Just (Some fpp) <- fpRepr e p = SFloat <$> floatNaN sym fpp- | otherwise = unsupported "fpNaN" e p----- | Positive infinity-fpPosInf ::- IsExprBuilder sym =>- sym ->- Integer {- ^ Exponent width -} ->- Integer {- ^ Precision width -} ->- IO (SFloat sym)-fpPosInf sym e p- | Just (Some fpp) <- fpRepr e p = SFloat <$> floatPInf sym fpp- | otherwise = unsupported "fpPosInf" e p---- | A floating point number corresponding to the given rations.-fpFromRationalLit ::- IsExprBuilder sym =>- sym ->- Integer {- ^ Exponent width -} ->- Integer {- ^ Precision width -} ->- Rational ->- IO (SFloat sym)-fpFromRationalLit sym e p r- | Just (Some fpp) <- fpRepr e p = SFloat <$> floatLit sym fpp r- | otherwise = unsupported "fpFromRational" e p----- | Make a floating point number with the given bit representation.-fpFromBinary ::- IsExprBuilder sym =>- sym ->- Integer {- ^ Exponent width -} ->- Integer {- ^ Precision width -} ->- SWord sym ->- IO (SFloat sym)-fpFromBinary sym e p swe- | DBV sw <- swe- , Just (Some fpp) <- fpRepr e p- , FloatingPointPrecisionRepr ew pw <- fpp- , let expectW = addNat ew pw- , actual@(BaseBVRepr actualW) <- exprType sw =- case testEquality expectW actualW of- Just Refl -> SFloat <$> floatFromBinary sym fpp sw- Nothing -- we want to report type correct type errors! :-)- | Just LeqProof <- testLeq (knownNat @1) expectW ->- fpTypeMismatch (BaseBVRepr expectW) actual- | otherwise -> panic "fpFromBits" [ "1 >= 2" ]- | otherwise = unsupported "fpFromBits" e p--fpToBinary :: IsExprBuilder sym => sym -> SFloat sym -> IO (SWord sym)-fpToBinary sym (SFloat f)- | FloatingPointPrecisionRepr e p <- fpReprOf sym f- , Just LeqProof <- testLeq (knownNat @1) (addNat e p)- = DBV <$> floatToBinary sym f- | otherwise = panic "fpToBinary" [ "we messed up the types" ]-------------------------------------------------------------------------------------- Arithmetic--fpNeg :: IsExprBuilder sym => sym -> SFloat sym -> IO (SFloat sym)-fpNeg sym (SFloat fl) = SFloat <$> floatNeg sym fl--fpBinArith ::- IsExprBuilder sym =>- (forall t.- sym ->- RoundingMode ->- SymFloat sym t ->- SymFloat sym t ->- IO (SymFloat sym t)- ) ->- sym -> RoundingMode -> SFloat sym -> SFloat sym -> IO (SFloat sym)-fpBinArith fun sym r (SFloat x) (SFloat y) =- let t1 = sym `fpReprOf` x- t2 = sym `fpReprOf` y- in- case testEquality t1 t2 of- Just Refl -> SFloat <$> fun sym r x y- _ -> fpTypeError t1 t2--type SFloatBinArith sym =- sym -> RoundingMode -> SFloat sym -> SFloat sym -> IO (SFloat sym)--fpAdd :: IsExprBuilder sym => SFloatBinArith sym-fpAdd = fpBinArith floatAdd--fpSub :: IsExprBuilder sym => SFloatBinArith sym-fpSub = fpBinArith floatSub--fpMul :: IsExprBuilder sym => SFloatBinArith sym-fpMul = fpBinArith floatMul--fpDiv :: IsExprBuilder sym => SFloatBinArith sym-fpDiv = fpBinArith floatDiv---------------------------------------------------------------------------------------fpRel ::- IsExprBuilder sym =>- (forall t.- sym ->- SymFloat sym t ->- SymFloat sym t ->- IO (Pred sym)- ) ->- sym -> SFloat sym -> SFloat sym -> IO (Pred sym)-fpRel fun sym (SFloat x) (SFloat y) =- let t1 = sym `fpReprOf` x- t2 = sym `fpReprOf` y- in- case testEquality t1 t2 of- Just Refl -> fun sym x y- _ -> fpTypeError t1 t2-----type SFloatRel sym =- sym -> SFloat sym -> SFloat sym -> IO (Pred sym)--fpEq :: IsExprBuilder sym => SFloatRel sym-fpEq = fpRel floatEq--fpEqIEEE :: IsExprBuilder sym => SFloatRel sym-fpEqIEEE = fpRel floatFpEq--fpLtIEEE :: IsExprBuilder sym => SFloatRel sym-fpLtIEEE = fpRel floatLt--fpGtIEEE :: IsExprBuilder sym => SFloatRel sym-fpGtIEEE = fpRel floatGt------------------------------------------------------------------------------------fpRound ::- IsExprBuilder sym => sym -> RoundingMode -> SFloat sym -> IO (SFloat sym)-fpRound sym r (SFloat x) = SFloat <$> floatRound sym r x---- | This is undefined on "special" values (NaN,infinity)-fpToReal :: IsExprBuilder sym => sym -> SFloat sym -> IO (SymReal sym)-fpToReal sym (SFloat x) = floatToReal sym x--fpFromReal ::- IsExprBuilder sym =>- sym -> Integer -> Integer -> RoundingMode -> SymReal sym -> IO (SFloat sym)-fpFromReal sym e p r x- | Just (Some repr) <- fpRepr e p = SFloat <$> realToFloat sym repr r x- | otherwise = unsupported "fpFromReal" e p---fpFromInteger ::- IsExprBuilder sym =>- sym -> Integer -> Integer -> RoundingMode -> SymInteger sym -> IO (SFloat sym)-fpFromInteger sym e p r x = fpFromReal sym e p r =<< integerToReal sym x---fpFromRational ::- IsExprBuilder sym =>- sym -> Integer -> Integer -> RoundingMode ->- SymInteger sym -> SymInteger sym -> IO (SFloat sym)-fpFromRational sym e p r x y =- do num <- integerToReal sym x- den <- integerToReal sym y- res <- realDiv sym num den- fpFromReal sym e p r res--{- | Returns a predicate and two integers, @x@ and @y@.-If the the predicate holds, then @x / y@ is a rational representing-the floating point number. Assumes the FP number is not one of the-special ones that has no real representation. -}-fpToRational ::- IsSymExprBuilder sym =>- sym ->- SFloat sym ->- IO (Pred sym, SymInteger sym, SymInteger sym)-fpToRational sym fp =- do r <- fpToReal sym fp- x <- freshConstant sym emptySymbol BaseIntegerRepr- y <- freshConstant sym emptySymbol BaseIntegerRepr- num <- integerToReal sym x- den <- integerToReal sym y- res <- realDiv sym num den- same <- realEq sym r res- pure (same, x, y)-------------------------------------------------------------------------------------fpIsInf :: IsExprBuilder sym => sym -> SFloat sym -> IO (Pred sym)-fpIsInf sym (SFloat x) = floatIsInf sym x--fpIsNaN :: IsExprBuilder sym => sym -> SFloat sym -> IO (Pred sym)-fpIsNaN sym (SFloat x) = floatIsNaN sym x---
src/Cryptol/Eval.hs view
@@ -27,10 +27,13 @@ , emptyEnv , evalExpr , evalDecls+ , evalNewtypeDecls , evalSel , evalSetSel , EvalError(..)+ , EvalErrorEx(..) , Unsupported(..)+ , WordTooWide(..) , forceValue ) where @@ -39,9 +42,11 @@ import Cryptol.Backend.Monad import Cryptol.Eval.Generic ( iteValue ) import Cryptol.Eval.Env+import Cryptol.Eval.Prims import Cryptol.Eval.Type import Cryptol.Eval.Value import Cryptol.ModuleSystem.Name+import Cryptol.Parser.Position import Cryptol.Parser.Selector(ppSelector) import Cryptol.TypeCheck.AST import Cryptol.TypeCheck.Solver.InfNat(Nat'(..))@@ -63,9 +68,10 @@ type EvalEnv = GenEvalEnv Concrete type EvalPrims sym =- ( Backend sym, ?evalPrim :: PrimIdent -> Maybe (Either Expr (GenValue sym)) )+ ( Backend sym, ?callStacks :: Bool, ?evalPrim :: PrimIdent -> Maybe (Either Expr (Prim sym)) ) -type ConcPrims = ?evalPrim :: PrimIdent -> Maybe (Either Expr (GenValue Concrete))+type ConcPrims =+ (?callStacks :: Bool, ?evalPrim :: PrimIdent -> Maybe (Either Expr (Prim Concrete))) -- Expression Evaluation ------------------------------------------------------- @@ -85,10 +91,10 @@ Module {- ^ Module containing declarations to evaluate -} -> GenEvalEnv sym {- ^ Environment to extend -} -> SEval sym (GenEvalEnv sym)-moduleEnv sym m env = evalDecls sym (mDecls m) =<< evalNewtypes sym (mNewtypes m) env+moduleEnv sym m env = evalDecls sym (mDecls m) =<< evalNewtypeDecls sym (mNewtypes m) env {-# SPECIALIZE evalExpr ::- ConcPrims =>+ (?range :: Range, ConcPrims) => Concrete -> GenEvalEnv Concrete -> Expr ->@@ -99,13 +105,17 @@ -- by the `EvalPrims` class, which defines the behavior of bits and words, in -- addition to providing implementations for all the primitives. evalExpr ::- EvalPrims sym =>+ (?range :: Range, EvalPrims sym) => sym -> GenEvalEnv sym {- ^ Evaluation environment -} -> Expr {- ^ Expression to evaluate -} -> SEval sym (GenValue sym) evalExpr sym env expr = case expr of + ELocated r e ->+ let ?range = r in+ evalExpr sym env e+ -- Try to detect when the user has directly written a finite sequence of -- literal bit values and pack these into a word. EList es ty@@ -115,22 +125,22 @@ return $ VWord len $ case tryFromBits sym vs of Just w -> WordVal <$> w- Nothing -> do xs <- mapM (sDelay sym Nothing) vs- return $ LargeBitsVal len $ finiteSeqMap sym xs+ Nothing -> do xs <- mapM (sDelay sym) vs+ return $ LargeBitsVal len $ finiteSeqMap xs | otherwise -> {-# SCC "evalExpr->EList" #-} do- xs <- mapM (sDelay sym Nothing) vs- return $ VSeq len $ finiteSeqMap sym xs+ xs <- mapM (sDelay sym) vs+ return $ VSeq len $ finiteSeqMap xs where tyv = evalValType (envTypes env) ty vs = map eval es len = genericLength es ETuple es -> {-# SCC "evalExpr->ETuple" #-} do- xs <- mapM (sDelay sym Nothing . eval) es+ xs <- mapM (sDelay sym . eval) es return $ VTuple xs ERec fields -> {-# SCC "evalExpr->ERec" #-} do- xs <- traverse (sDelay sym Nothing . eval) fields+ xs <- traverse (sDelay sym . eval) fields return $ VRecord xs ESel e sel -> {-# SCC "evalExpr->ESel" #-} do@@ -153,7 +163,15 @@ EVar n -> {-# SCC "evalExpr->EVar" #-} do case lookupVar n env of- Just val -> val+ Just (Left p)+ | ?callStacks -> sPushFrame sym n ?range (cacheCallStack sym =<< evalPrim sym n p)+ | otherwise -> evalPrim sym n p+ Just (Right val)+ | ?callStacks ->+ case nameInfo n of+ Declared{} -> sPushFrame sym n ?range (cacheCallStack sym =<< val)+ Parameter -> cacheCallStack sym =<< val+ | otherwise -> val Nothing -> do envdoc <- ppEnv sym defaultPPOpts env panic "[Eval] evalExpr"@@ -163,14 +181,14 @@ ETAbs tv b -> {-# SCC "evalExpr->ETAbs" #-} case tpKind tv of- KType -> return $ VPoly $ \ty -> evalExpr sym (bindType (tpVar tv) (Right ty) env) b- KNum -> return $ VNumPoly $ \n -> evalExpr sym (bindType (tpVar tv) (Left n) env) b+ KType -> tlam sym $ \ty -> evalExpr sym (bindType (tpVar tv) (Right ty) env) b+ KNum -> nlam sym $ \n -> evalExpr sym (bindType (tpVar tv) (Left n) env) b k -> panic "[Eval] evalExpr" ["invalid kind on type abstraction", show k] ETApp e ty -> {-# SCC "evalExpr->ETApp" #-} do eval e >>= \case- VPoly f -> f $! (evalValType (envTypes env) ty)- VNumPoly f -> f $! (evalNumType (envTypes env) ty)+ f@VPoly{} -> fromVPoly sym f $! (evalValType (envTypes env) ty)+ f@VNumPoly{} -> fromVNumPoly sym f $! (evalNumType (envTypes env) ty) val -> do vdoc <- ppV val panic "[Eval] evalExpr" ["expected a polymorphic value"@@ -179,13 +197,13 @@ EApp f v -> {-# SCC "evalExpr->EApp" #-} do eval f >>= \case- VFun f' -> f' (eval v)- it -> do itdoc <- ppV it- panic "[Eval] evalExpr" ["not a function", show itdoc ]+ f'@VFun {} -> fromVFun sym f' (eval v)+ it -> do itdoc <- ppV it+ panic "[Eval] evalExpr" ["not a function", show itdoc ] EAbs n _ty b -> {-# SCC "evalExpr->EAbs" #-}- return $ VFun (\v -> do env' <- bindVar sym n v env- evalExpr sym env' b)+ lam sym (\v -> do env' <- bindVar sym n v env+ evalExpr sym env' b) -- XXX these will likely change once there is an evidence value EProofAbs _ e -> eval e@@ -202,9 +220,31 @@ ppV = ppValue sym defaultPPOpts +-- | Capure the current call stack from the evaluation monad and+-- annotate function values. When arguments are later applied+-- to the function, the call stacks will be combined together.+cacheCallStack ::+ Backend sym =>+ sym ->+ GenValue sym ->+ SEval sym (GenValue sym)+cacheCallStack sym v = case v of+ VFun fnstk f ->+ do stk <- sGetCallStack sym+ pure (VFun (combineCallStacks stk fnstk) f)+ VPoly fnstk f ->+ do stk <- sGetCallStack sym+ pure (VPoly (combineCallStacks stk fnstk) f)+ VNumPoly fnstk f ->+ do stk <- sGetCallStack sym+ pure (VNumPoly (combineCallStacks stk fnstk) f)++ -- non-function types don't get annotated+ _ -> pure v+ -- Newtypes -------------------------------------------------------------------- -{-# SPECIALIZE evalNewtypes ::+{-# SPECIALIZE evalNewtypeDecls :: ConcPrims => Concrete -> Map.Map Name Newtype ->@@ -212,28 +252,34 @@ SEval Concrete (GenEvalEnv Concrete) #-} -evalNewtypes ::+evalNewtypeDecls :: EvalPrims sym => sym -> Map.Map Name Newtype -> GenEvalEnv sym -> SEval sym (GenEvalEnv sym)-evalNewtypes sym nts env = foldM (flip (evalNewtype sym)) env $ Map.elems nts+evalNewtypeDecls sym nts env = foldM (flip (evalNewtypeDecl sym)) env $ Map.elems nts -- | Introduce the constructor function for a newtype.-evalNewtype ::+evalNewtypeDecl :: EvalPrims sym => sym -> Newtype -> GenEvalEnv sym -> SEval sym (GenEvalEnv sym)-evalNewtype sym nt = bindVar sym (ntName nt) (return (foldr tabs con (ntParams nt)))+evalNewtypeDecl _sym nt = pure . bindVarDirect (ntName nt) (foldr tabs con (ntParams nt)) where- tabs _tp body = tlam (\ _ -> body)- con = VFun id-{-# INLINE evalNewtype #-}+ con = PFun PPrim + tabs tp body =+ case tpKind tp of+ KType -> PTyPoly (\ _ -> body)+ KNum -> PNumPoly (\ _ -> body)+ k -> evalPanic "evalNewtypeDecl" ["illegal newtype parameter kind", show (pp k)] +{-# INLINE evalNewtypeDecl #-}++ -- Declarations ---------------------------------------------------------------- {-# SPECIALIZE evalDecls ::@@ -274,7 +320,7 @@ -- declare a "hole" for each declaration -- and extend the evaluation environment holes <- mapM (declHole sym) ds- let holeEnv = IntMap.fromList $ [ (nameUnique nm, h) | (nm,_,h,_) <- holes ]+ let holeEnv = IntMap.fromList $ [ (nameUnique nm, Right h) | (nm,_,h,_) <- holes ] let env' = env `mappend` emptyEnv{ envVars = holeEnv } -- evaluate the declaration bodies, building a new evaluation environment@@ -318,12 +364,16 @@ SEval sym () fillHole sym env (nm, sch, _, fill) = do case lookupVar nm env of- Nothing -> evalPanic "fillHole" ["Recursive definition not completed", show (ppLocName nm)]- Just v- | isValueType env sch -> fill =<< sDelayFill sym v (etaDelay sym (show (ppLocName nm)) env sch v)- | otherwise -> fill (etaDelay sym (show (ppLocName nm)) env sch v)+ Just (Right v)+ | isValueType env sch ->+ fill =<< sDelayFill sym v+ (Just (etaDelay sym env sch v))+ (show (ppLocName nm)) + | otherwise -> fill (etaDelay sym env sch v) + _ -> evalPanic "fillHole" ["Recursive definition not completed", show (ppLocName nm)]+ -- | 'Value' types are non-polymorphic types recursive constructed from -- bits, finite sequences, tuples and records. Types of this form can -- be implemented rather more efficiently than general types because we can@@ -337,6 +387,7 @@ go (TVSeq _ x) = go x go (TVTuple xs) = and (map go xs) go (TVRec xs) = and (fmap go xs)+ go (TVNewtype _ _ xs) = and (fmap go xs) go _ = False isValueType _ _ = False@@ -357,14 +408,13 @@ SEval sym (GenValue sym) -> SEval sym (WordValue sym) etaWord sym n val = do- w <- sDelay sym Nothing (fromWordVal "during eta-expansion" =<< val)- xs <- memoMap $ IndexSeqMap $ \i ->+ w <- sDelay sym (fromWordVal "during eta-expansion" =<< val)+ xs <- memoMap sym $ IndexSeqMap $ \i -> do w' <- w; VBit <$> indexWordValue sym w' i pure $ LargeBitsVal n xs {-# SPECIALIZE etaDelay :: Concrete ->- String -> GenEvalEnv Concrete -> Schema -> SEval Concrete (GenValue Concrete) ->@@ -380,23 +430,24 @@ etaDelay :: Backend sym => sym ->- String -> GenEvalEnv sym -> Schema -> SEval sym (GenValue sym) -> SEval sym (GenValue sym)-etaDelay sym msg env0 Forall{ sVars = vs0, sType = tp0 } = goTpVars env0 vs0+etaDelay sym env0 Forall{ sVars = vs0, sType = tp0 } = goTpVars env0 vs0 where- goTpVars env [] val = go (evalValType (envTypes env) tp0) val+ goTpVars env [] val =+ do stk <- sGetCallStack sym+ go stk (evalValType (envTypes env) tp0) val goTpVars env (v:vs) val = case tpKind v of- KType -> return $ VPoly $ \t ->- goTpVars (bindType (tpVar v) (Right t) env) vs ( ($t) . fromVPoly =<< val )- KNum -> return $ VNumPoly $ \n ->- goTpVars (bindType (tpVar v) (Left n) env) vs ( ($n) . fromVNumPoly =<< val )+ KType -> tlam sym $ \t ->+ goTpVars (bindType (tpVar v) (Right t) env) vs ( ($t) . fromVPoly sym =<< val )+ KNum -> nlam sym $ \n ->+ goTpVars (bindType (tpVar v) (Left n) env) vs ( ($n) . fromVNumPoly sym =<< val ) k -> panic "[Eval] etaDelay" ["invalid kind on type abstraction", show k] - go tp x | isReady sym x = x >>= \case+ go stk tp x | isReady sym x = x >>= \case VBit{} -> x VInteger{} -> x VWord{} -> x@@ -404,33 +455,39 @@ VFloat{} -> x VSeq n xs -> case tp of- TVSeq _nt el -> return $ VSeq n $ IndexSeqMap $ \i -> go el (lookupSeqMap xs i)+ TVSeq _nt el -> return $ VSeq n $ IndexSeqMap $ \i -> go stk el (lookupSeqMap xs i) _ -> evalPanic "type mismatch during eta-expansion" ["Expected sequence type, but got " ++ show tp] VStream xs -> case tp of- TVStream el -> return $ VStream $ IndexSeqMap $ \i -> go el (lookupSeqMap xs i)+ TVStream el -> return $ VStream $ IndexSeqMap $ \i -> go stk el (lookupSeqMap xs i) _ -> evalPanic "type mismatch during eta-expansion" ["Expected stream type, but got " ++ show tp] VTuple xs -> case tp of- TVTuple ts | length ts == length xs -> return $ VTuple (zipWith go ts xs)+ TVTuple ts | length ts == length xs -> return $ VTuple (zipWith (go stk) ts xs) _ -> evalPanic "type mismatch during eta-expansion" ["Expected tuple type with " ++ show (length xs) ++ " elements, but got " ++ show tp] VRecord fs -> case tp of+ TVNewtype _ _ fts ->+ do let res = zipRecords (\_ v t -> go stk t v) fs fts+ case res of+ Left (Left f) -> evalPanic "type mismatch during eta-expansion" ["missing field " ++ show f]+ Left (Right f) -> evalPanic "type mismatch during eta-expansion" ["unexpected field " ++ show f]+ Right fs' -> return (VRecord fs') TVRec fts ->- do let res = zipRecords (\_ v t -> go t v) fs fts+ do let res = zipRecords (\_ v t -> go stk t v) fs fts case res of Left (Left f) -> evalPanic "type mismatch during eta-expansion" ["missing field " ++ show f] Left (Right f) -> evalPanic "type mismatch during eta-expansion" ["unexpected field " ++ show f] Right fs' -> return (VRecord fs') _ -> evalPanic "type mismatch during eta-expansion" ["Expected record type, but got " ++ show tp] - VFun f ->+ f@VFun{} -> case tp of- TVFun _t1 t2 -> return $ VFun $ \a -> go t2 (f a)+ TVFun _t1 t2 -> lam sym $ \a -> go stk t2 (fromVFun sym f a) _ -> evalPanic "type mismatch during eta-expansion" ["Expected function type but got " ++ show tp] VPoly{} ->@@ -439,7 +496,7 @@ VNumPoly{} -> evalPanic "type mismatch during eta-expansion" ["Encountered numeric polymorphic value"] - go tp v =+ go stk tp v = sWithCallStack sym stk $ case tp of TVBit -> v TVInteger -> v@@ -449,40 +506,41 @@ TVArray{} -> v TVSeq n TVBit ->- do w <- sDelayFill sym (fromWordVal "during eta-expansion" =<< v) (etaWord sym n v)+ do w <- sDelayFill sym (fromWordVal "during eta-expansion" =<< v) (Just (etaWord sym n v)) "" return $ VWord n w TVSeq n el ->- do x' <- sDelay sym (Just msg) (fromSeq "during eta-expansion" =<< v)+ do x' <- sDelay sym (fromSeq "during eta-expansion" =<< v) return $ VSeq n $ IndexSeqMap $ \i -> do- go el (flip lookupSeqMap i =<< x')+ go stk el (flip lookupSeqMap i =<< x') TVStream el ->- do x' <- sDelay sym (Just msg) (fromSeq "during eta-expansion" =<< v)+ do x' <- sDelay sym (fromSeq "during eta-expansion" =<< v) return $ VStream $ IndexSeqMap $ \i ->- go el (flip lookupSeqMap i =<< x')+ go stk el (flip lookupSeqMap i =<< x') TVFun _t1 t2 ->- do v' <- sDelay sym (Just msg) (fromVFun <$> v)- return $ VFun $ \a -> go t2 ( ($a) =<< v' )+ do v' <- sDelay sym (fromVFun sym <$> v)+ lam sym $ \a -> go stk t2 ( ($a) =<< v' ) TVTuple ts -> do let n = length ts- v' <- sDelay sym (Just msg) (fromVTuple <$> v)+ v' <- sDelay sym (fromVTuple <$> v) return $ VTuple $- [ go t =<< (flip genericIndex i <$> v')+ [ go stk t =<< (flip genericIndex i <$> v') | i <- [0..(n-1)] | t <- ts ] TVRec fs ->- do v' <- sDelay sym (Just msg) (fromVRecord <$> v)+ do v' <- sDelay sym (fromVRecord <$> v) let err f = evalPanic "expected record value with field" [show f]- let eta f t = go t =<< (fromMaybe (err f) . lookupField f <$> v')+ let eta f t = go stk t =<< (fromMaybe (err f) . lookupField f <$> v') return $ VRecord (mapWithFieldName eta fs) TVAbstract {} -> v + TVNewtype _ _ body -> go stk (TVRec body) v {-# SPECIALIZE declHole :: Concrete ->@@ -504,7 +562,7 @@ where nm = dName d sch = dSignature d- msg = unwords ["<<loop>> while evaluating", show (pp nm)]+ msg = unwords ["while evaluating", show (pp nm)] -- | Evaluate a declaration, extending the evaluation environment.@@ -522,10 +580,11 @@ Decl {- ^ The declaration to evaluate -} -> SEval sym (GenEvalEnv sym) evalDecl sym renv env d =+ let ?range = nameLoc (dName d) in case dDefinition d of DPrim -> case ?evalPrim =<< asPrim (dName d) of- Just (Right v) -> pure (bindVarDirect (dName d) v env)+ Just (Right p) -> pure $ bindVarDirect (dName d) p env Just (Left ex) -> bindVar sym (dName d) (evalExpr sym renv ex) env Nothing -> bindVar sym (dName d) (cryNoPrimError sym (dName d)) env @@ -535,7 +594,6 @@ -- Selectors ------------------------------------------------------------------- {-# SPECIALIZE evalSel ::- ConcPrims => Concrete -> GenValue Concrete -> Selector ->@@ -546,7 +604,7 @@ -- tuple and record selections pointwise down into other value constructs -- (e.g., streams and functions). evalSel ::- EvalPrims sym =>+ Backend sym => sym -> GenValue sym -> Selector ->@@ -584,12 +642,11 @@ [ "Unexpected value in list selection" , show vdoc ] {-# SPECIALIZE evalSetSel ::- ConcPrims => Concrete -> TValue -> GenValue Concrete -> Selector -> SEval Concrete (GenValue Concrete) -> SEval Concrete (GenValue Concrete) #-} evalSetSel :: forall sym.- EvalPrims sym =>+ Backend sym => sym -> TValue -> GenValue sym -> Selector -> SEval sym (GenValue sym) -> SEval sym (GenValue sym)@@ -645,7 +702,7 @@ data ListEnv sym = ListEnv { leVars :: !(IntMap.IntMap (Integer -> SEval sym (GenValue sym))) -- ^ Bindings whose values vary by position- , leStatic :: !(IntMap.IntMap (SEval sym (GenValue sym)))+ , leStatic :: !(IntMap.IntMap (Either (Prim sym) (SEval sym (GenValue sym)))) -- ^ Bindings whose values are constant , leTypes :: !TypeEnv }@@ -654,14 +711,14 @@ l <> r = ListEnv { leVars = IntMap.union (leVars l) (leVars r) , leStatic = IntMap.union (leStatic l) (leStatic r)- , leTypes = IntMap.union (leTypes l) (leTypes r)+ , leTypes = leTypes l <> leTypes r } instance Monoid (ListEnv sym) where mempty = ListEnv { leVars = IntMap.empty , leStatic = IntMap.empty- , leTypes = IntMap.empty+ , leTypes = mempty } mappend l r = l <> r@@ -680,7 +737,7 @@ -- locations. evalListEnv :: ListEnv sym -> Integer -> GenEvalEnv sym evalListEnv (ListEnv vm st tm) i =- let v = fmap ($i) vm+ let v = fmap (Right . ($i)) vm in EvalEnv{ envVars = IntMap.union v st , envTypes = tm }@@ -698,7 +755,7 @@ -- List Comprehensions --------------------------------------------------------- {-# SPECIALIZE evalComp ::- ConcPrims =>+ (?range :: Range, ConcPrims) => Concrete -> GenEvalEnv Concrete -> Nat' ->@@ -709,7 +766,7 @@ #-} -- | Evaluate a comprehension. evalComp ::- EvalPrims sym =>+ (?range :: Range, EvalPrims sym) => sym -> GenEvalEnv sym {- ^ Starting evaluation environment -} -> Nat' {- ^ Length of the comprehension -} ->@@ -719,11 +776,11 @@ SEval sym (GenValue sym) evalComp sym env len elty body ms = do lenv <- mconcat <$> mapM (branchEnvs sym (toListEnv env)) ms- mkSeq len elty <$> memoMap (IndexSeqMap $ \i -> do+ mkSeq len elty <$> memoMap sym (IndexSeqMap $ \i -> do evalExpr sym (evalListEnv lenv i) body) {-# SPECIALIZE branchEnvs ::- ConcPrims =>+ (?range :: Range, ConcPrims) => Concrete -> ListEnv Concrete -> [Match] ->@@ -732,7 +789,7 @@ -- | Turn a list of matches into the final environments for each iteration of -- the branch. branchEnvs ::- EvalPrims sym =>+ (?range :: Range, EvalPrims sym) => sym -> ListEnv sym -> [Match] ->@@ -740,7 +797,7 @@ branchEnvs sym env matches = foldM (evalMatch sym) env matches {-# SPECIALIZE evalMatch ::- ConcPrims =>+ (?range :: Range, ConcPrims) => Concrete -> ListEnv Concrete -> Match ->@@ -749,7 +806,7 @@ -- | Turn a match into the list of environments it represents. evalMatch ::- EvalPrims sym =>+ (?range :: Range, EvalPrims sym) => sym -> ListEnv sym -> Match ->@@ -762,7 +819,7 @@ -- Select from a sequence of finite length. This causes us to 'stutter' -- through our previous choices `nLen` times. Nat nLen -> do- vss <- memoMap $ IndexSeqMap $ \i -> evalExpr sym (evalListEnv lenv i) expr+ vss <- memoMap sym $ IndexSeqMap $ \i -> evalExpr sym (evalListEnv lenv i) expr let stutter xs = \i -> xs (i `div` nLen) let lenv' = lenv { leVars = fmap stutter (leVars lenv) } let vs i = do let (q, r) = i `divMod` nLen@@ -778,7 +835,7 @@ -- `leVars` elements of the comprehension environment into `leStatic` elements -- by selecting out the 0th element. Inf -> do- let allvars = IntMap.union (fmap ($0) (leVars lenv)) (leStatic lenv)+ let allvars = IntMap.union (fmap (Right . ($0)) (leVars lenv)) (leStatic lenv) let lenv' = lenv { leVars = IntMap.empty , leStatic = allvars }
src/Cryptol/Eval/Concrete.hs view
@@ -25,9 +25,9 @@ , toExpr ) where -import Control.Monad (join, guard, zipWithM, foldM)+import Control.Monad (guard, zipWithM, foldM, mzero) import Data.Bits (Bits(..))-import Data.Ratio((%),numerator,denominator)+import Data.Ratio(numerator,denominator) import Data.Word(Word32, Word64) import MonadLib( ChoiceT, findOne, lift ) import qualified LibBF as FP@@ -44,6 +44,7 @@ import Cryptol.Backend.Monad import Cryptol.Eval.Generic hiding (logicShift)+import Cryptol.Eval.Prims import Cryptol.Eval.Type import Cryptol.Eval.Value import qualified Cryptol.SHA as SHA@@ -54,7 +55,6 @@ import Cryptol.Utils.Panic (panic) import Cryptol.Utils.Ident (PrimIdent,prelPrim,floatPrim,suiteBPrim,primeECPrim) import Cryptol.Utils.PP-import Cryptol.Utils.Logger(logPrint) import Cryptol.Utils.RecordMap type Value = GenValue Concrete@@ -63,57 +63,68 @@ -- | Given an expected type, returns an expression that evaluates to -- this value, if we can determine it.-toExpr :: PrimMap -> AST.Type -> Value -> Eval (Maybe AST.Expr)+toExpr :: PrimMap -> TValue -> Value -> Eval (Maybe AST.Expr) toExpr prims t0 v0 = findOne (go t0 v0) where prim n = ePrim prims (prelPrim n) - go :: AST.Type -> Value -> ChoiceT Eval Expr+ go :: TValue -> Value -> ChoiceT Eval Expr go ty val =- case val of- VRecord vfs ->- do tfs <- maybe mismatch pure (tIsRec ty)- -- NB, vfs first argument to keep their display order+ case (ty,val) of+ (TVRec tfs, VRecord vfs) ->+ do -- NB, vfs first argument to keep their display order res <- zipRecordsM (\_lbl v t -> go t =<< lift v) vfs tfs case res of Left _ -> mismatch -- different fields Right efs -> pure (ERec efs)- VTuple tvs ->- do ts <- maybe mismatch pure (tIsTuple ty)- guard (length ts == length tvs)++ (TVNewtype nt ts tfs, VRecord vfs) ->+ do -- NB, vfs first argument to keep their display order+ res <- zipRecordsM (\_lbl v t -> go t =<< lift v) vfs tfs+ case res of+ Left _ -> mismatch -- different fields+ Right efs ->+ let f = foldl (\x t -> ETApp x (tNumValTy t)) (EVar (ntName nt)) ts+ in pure (EApp f (ERec efs))++ (TVTuple ts, VTuple tvs) ->+ do guard (length ts == length tvs) ETuple <$> (zipWithM go ts =<< lift (sequence tvs))- VBit b ->+ (TVBit, VBit b) -> pure (prim (if b then "True" else "False"))- VInteger i ->- -- This works uniformly for values of type Integer or Z n- pure $ ETApp (ETApp (prim "number") (tNum i)) ty- VRational (SRational n d) ->+ (TVInteger, VInteger i) ->+ pure $ ETApp (ETApp (prim "number") (tNum i)) tInteger+ (TVIntMod n, VInteger i) ->+ pure $ ETApp (ETApp (prim "number") (tNum i)) (tIntMod (tNum n))++ (TVRational, VRational (SRational n d)) -> do let n' = ETApp (ETApp (prim "number") (tNum n)) tInteger let d' = ETApp (ETApp (prim "number") (tNum d)) tInteger pure $ EApp (EApp (prim "ratio") n') d'- VFloat i ->- do (eT, pT) <- maybe mismatch pure (tIsFloat ty)- pure (floatToExpr prims eT pT (bfValue i))- VSeq n svs ->- do (_a, b) <- maybe mismatch pure (tIsSeq ty)- ses <- traverse (go b) =<< lift (sequence (enumerateSeqMap n svs))- pure $ EList ses b- VWord _ wval ->++ (TVFloat e p, VFloat i) ->+ pure (floatToExpr prims (tNum e) (tNum p) (bfValue i))+ (TVSeq _ b, VSeq n svs) ->+ do ses <- traverse (go b) =<< lift (sequence (enumerateSeqMap n svs))+ pure $ EList ses (tValTy b)+ (TVSeq n TVBit, VWord _ wval) -> do BV _ v <- lift (asWordVal Concrete =<< wval)- pure $ 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"- VNumPoly _ -> fail "cannot convert polymorphic values to expressions"+ pure $ ETApp (ETApp (prim "number") (tNum v)) (tWord (tNum n))++ (_,VStream{}) -> mzero+ (_,VFun{}) -> mzero+ (_,VPoly{}) -> mzero+ (_,VNumPoly{}) -> mzero+ _ -> mismatch where mismatch :: forall a. ChoiceT Eval a mismatch = do doc <- lift (ppValue Concrete defaultPPOpts val) panic "Cryptol.Eval.Concrete.toExpr" ["type mismatch:"- , pretty ty+ , pretty (tValTy ty) , render doc ] @@ -139,153 +150,18 @@ -- Primitives ------------------------------------------------------------------ -primTable :: EvalOpts -> Map PrimIdent Value-primTable eOpts = let sym = Concrete in- Map.union (floatPrims sym) $+primTable :: IO EvalOpts -> Map PrimIdent (Prim Concrete)+primTable getEOpts = let sym = Concrete in+ Map.union (genericPrimTable sym getEOpts) $+ Map.union (genericFloatTable sym) $ Map.union suiteBPrims $ Map.union primeECPrims $ Map.fromList $ map (\(n, v) -> (prelPrim n, v)) - [ -- Literals- ("True" , VBit (bitLit sym True))- , ("False" , VBit (bitLit sym False))- , ("number" , {-# SCC "Prelude::number" #-}- ecNumberV sym)- , ("ratio" , {-# SCC "Prelude::ratio" #-}- ratioV sym)- , ("fraction" , ecFractionV sym)--- -- Zero- , ("zero" , {-# SCC "Prelude::zero" #-}- VPoly (zeroV sym))-- -- Logic- , ("&&" , {-# SCC "Prelude::(&&)" #-}- binary (andV sym))- , ("||" , {-# SCC "Prelude::(||)" #-}- binary (orV sym))- , ("^" , {-# SCC "Prelude::(^)" #-}- binary (xorV sym))- , ("complement" , {-# SCC "Prelude::complement" #-}- unary (complementV sym))-- -- Ring- , ("fromInteger", {-# SCC "Prelude::fromInteger" #-}- fromIntegerV sym)- , ("+" , {-# SCC "Prelude::(+)" #-}- binary (addV sym))- , ("-" , {-# SCC "Prelude::(-)" #-}- binary (subV sym))- , ("*" , {-# SCC "Prelude::(*)" #-}- binary (mulV sym))- , ("negate" , {-# SCC "Prelude::negate" #-}- unary (negateV sym))-- -- Integral- , ("toInteger" , {-# SCC "Prelude::toInteger" #-}- toIntegerV sym)- , ("/" , {-# SCC "Prelude::(/)" #-}- binary (divV sym))- , ("%" , {-# SCC "Prelude::(%)" #-}- binary (modV sym))- , ("^^" , {-# SCC "Prelude::(^^)" #-}- expV sym)- , ("infFrom" , {-# SCC "Prelude::infFrom" #-}- infFromV sym)- , ("infFromThen", {-# SCC "Prelude::infFromThen" #-}- infFromThenV sym)-- -- Field- , ("recip" , {-# SCC "Prelude::recip" #-}- recipV sym)- , ("/." , {-# SCC "Prelude::(/.)" #-}- fieldDivideV sym)-- -- Round- , ("floor" , {-# SCC "Prelude::floor" #-}- unary (floorV sym))- , ("ceiling" , {-# SCC "Prelude::ceiling" #-}- unary (ceilingV sym))- , ("trunc" , {-# SCC "Prelude::trunc" #-}- unary (truncV sym))- , ("roundAway" , {-# SCC "Prelude::roundAway" #-}- unary (roundAwayV sym))- , ("roundToEven", {-# SCC "Prelude::roundToEven" #-}- unary (roundToEvenV sym))-- -- Bitvector specific operations- , ("/$" , {-# SCC "Prelude::(/$)" #-}- sdivV sym)- , ("%$" , {-# SCC "Prelude::(%$)" #-}- smodV sym)- , ("lg2" , {-# SCC "Prelude::lg2" #-}- lg2V sym)- , (">>$" , {-# SCC "Prelude::(>>$)" #-}+ [ (">>$" , {-# SCC "Prelude::(>>$)" #-} sshrV) - -- Cmp- , ("<" , {-# SCC "Prelude::(<)" #-}- binary (lessThanV sym))- , (">" , {-# SCC "Prelude::(>)" #-}- binary (greaterThanV sym))- , ("<=" , {-# SCC "Prelude::(<=)" #-}- binary (lessThanEqV sym))- , (">=" , {-# SCC "Prelude::(>=)" #-}- binary (greaterThanEqV sym))- , ("==" , {-# SCC "Prelude::(==)" #-}- binary (eqV sym))- , ("!=" , {-# SCC "Prelude::(!=)" #-}- binary (distinctV sym))-- -- SignedCmp- , ("<$" , {-# SCC "Prelude::(<$)" #-}- binary (signedLessThanV sym))-- -- Finite enumerations- , ("fromTo" , {-# SCC "Prelude::fromTo" #-}- fromToV sym)- , ("fromThenTo" , {-# SCC "Prelude::fromThenTo" #-}- fromThenToV sym)-- -- Sequence manipulations- , ("#" , {-# SCC "Prelude::(#)" #-}- nlam $ \ front ->- nlam $ \ back ->- tlam $ \ elty ->- lam $ \ l -> return $- lam $ \ r -> join (ccatV sym front back elty <$> l <*> r))--- , ("join" , {-# SCC "Prelude::join" #-}- nlam $ \ parts ->- nlam $ \ (finNat' -> each) ->- tlam $ \ a ->- lam $ \ x ->- joinV sym parts each a =<< x)-- , ("split" , {-# SCC "Prelude::split" #-}- ecSplitV sym)-- , ("splitAt" , {-# SCC "Prelude::splitAt" #-}- nlam $ \ front ->- nlam $ \ back ->- tlam $ \ a ->- lam $ \ x ->- splitAtV sym front back a =<< x)-- , ("reverse" , {-# SCC "Prelude::reverse" #-}- nlam $ \_a ->- tlam $ \_b ->- lam $ \xs -> reverseV sym =<< xs)-- , ("transpose" , {-# SCC "Prelude::transpose" #-}- nlam $ \a ->- nlam $ \b ->- tlam $ \c ->- lam $ \xs -> transposeV sym a b c =<< xs)- -- Shifts and rotates , ("<<" , {-# SCC "Prelude::(<<)" #-} logicShift shiftLW shiftLS)@@ -308,56 +184,12 @@ , ("updateEnd" , {-# SCC "Prelude::updateEnd" #-} updatePrim sym updateBack_word updateBack) - -- Misc- , ("foldl" , {-# SCC "Prelude::foldl" #-}- foldlV sym)-- , ("foldl'" , {-# SCC "Prelude::foldl'" #-}- foldl'V sym)-- , ("deepseq" , {-# SCC "Prelude::deepseq" #-}- tlam $ \_a ->- tlam $ \_b ->- lam $ \x -> pure $- lam $ \y ->- do _ <- forceValue =<< x- y)-- , ("parmap" , {-# SCC "Prelude::parmap" #-}- parmapV sym)-- , ("fromZ" , {-# SCC "Prelude::fromZ" #-}- fromZV sym)-- , ("error" , {-# SCC "Prelude::error" #-}- tlam $ \a ->- nlam $ \_ ->- lam $ \s -> errorV sym a =<< (valueToString sym =<< s))-- , ("random" , {-# SCC "Prelude::random" #-}- tlam $ \a ->- wlam sym $ \(bvVal -> x) -> randomV sym a x)-- , ("trace" , {-# SCC "Prelude::trace" #-}- nlam $ \_n ->- tlam $ \_a ->- tlam $ \_b ->- lam $ \s -> return $- lam $ \x -> return $- lam $ \y -> do- msg <- valueToString sym =<< s- let EvalOpts { evalPPOpts, evalLogger } = eOpts- doc <- ppValue sym evalPPOpts =<< x- yv <- y- io $ logPrint evalLogger- $ if null msg then doc else text msg <+> doc- return yv)- , ("pmult",- ilam $ \u ->- ilam $ \v ->- wlam Concrete $ \(BV _ x) -> return $- wlam Concrete $ \(BV _ y) ->+ PFinPoly \u ->+ PFinPoly \v ->+ PWordFun \(BV _ x) ->+ PWordFun \(BV _ y) ->+ PPrim let z = if u <= v then F2.pmult (fromInteger (u+1)) x y else@@ -365,56 +197,62 @@ in return . VWord (1+u+v) . pure . WordVal . mkBv (1+u+v) $! z) , ("pmod",- ilam $ \_u ->- ilam $ \v ->- wlam Concrete $ \(BV w x) -> return $- wlam Concrete $ \(BV _ m) ->+ PFinPoly \_u ->+ PFinPoly \v ->+ PWordFun \(BV w x) ->+ PWordFun \(BV _ m) ->+ PPrim do assertSideCondition sym (m /= 0) DivideByZero return . VWord v . pure . WordVal . mkBv v $! F2.pmod (fromInteger w) x m) , ("pdiv",- ilam $ \_u ->- ilam $ \_v ->- wlam Concrete $ \(BV w x) -> return $- wlam Concrete $ \(BV _ m) ->+ PFinPoly \_u ->+ PFinPoly \_v ->+ PWordFun \(BV w x) ->+ PWordFun \(BV _ m) ->+ PPrim do assertSideCondition sym (m /= 0) DivideByZero return . VWord w . pure . WordVal . mkBv w $! F2.pdiv (fromInteger w) x m) ] -primeECPrims :: Map.Map PrimIdent Value+primeECPrims :: Map.Map PrimIdent (Prim Concrete) primeECPrims = Map.fromList $ map (\(n,v) -> (primeECPrim n, v)) [ ("ec_double", {-# SCC "PrimeEC::ec_double" #-}- ilam $ \p ->- lam $ \s ->+ PFinPoly \p ->+ PFun \s ->+ PPrim do s' <- toProjectivePoint =<< s let r = PrimeEC.ec_double (PrimeEC.primeModulus p) s' fromProjectivePoint $! r) , ("ec_add_nonzero", {-# SCC "PrimeEC::ec_add_nonzero" #-}- ilam $ \p ->- lam $ \s -> pure $- lam $ \t ->+ PFinPoly \p ->+ PFun \s ->+ PFun \t ->+ PPrim do s' <- toProjectivePoint =<< s t' <- toProjectivePoint =<< t let r = PrimeEC.ec_add_nonzero (PrimeEC.primeModulus p) s' t' fromProjectivePoint $! r) , ("ec_mult", {-# SCC "PrimeEC::ec_mult" #-}- ilam $ \p ->- lam $ \d -> pure $- lam $ \s ->+ PFinPoly \p ->+ PFun \d ->+ PFun \s ->+ PPrim do d' <- fromVInteger <$> d s' <- toProjectivePoint =<< s let r = PrimeEC.ec_mult (PrimeEC.primeModulus p) d' s' fromProjectivePoint $! r) , ("ec_twin_mult", {-# SCC "PrimeEC::ec_twin_mult" #-}- ilam $ \p ->- lam $ \d0 -> pure $- lam $ \s -> pure $- lam $ \d1 -> pure $- lam $ \t ->+ PFinPoly \p ->+ PFun \d0 ->+ PFun \s ->+ PFun \d1 ->+ PFun \t ->+ PPrim do d0' <- fromVInteger <$> d0 s' <- toProjectivePoint =<< s d1' <- fromVInteger <$> d1@@ -436,59 +274,64 @@ -suiteBPrims :: Map.Map PrimIdent Value+suiteBPrims :: Map.Map PrimIdent (Prim Concrete) suiteBPrims = Map.fromList $ map (\(n, v) -> (suiteBPrim n, v)) [ ("processSHA2_224", {-# SCC "SuiteB::processSHA2_224" #-}- ilam $ \n ->- lam $ \xs ->- do blks <- enumerateSeqMap n . fromVSeq <$> xs- (SHA.SHA256S w0 w1 w2 w3 w4 w5 w6 _) <-- foldM (\st blk -> seq st (SHA.processSHA256Block st <$> (toSHA256Block =<< blk)))- SHA.initialSHA224State blks- let f :: Word32 -> Eval Value- f = pure . VWord 32 . pure . WordVal . BV 32 . toInteger- zs = finiteSeqMap Concrete (map f [w0,w1,w2,w3,w4,w5,w6])- seq zs (pure (VSeq 7 zs)))+ PFinPoly \n ->+ PFun \xs ->+ PPrim+ do blks <- enumerateSeqMap n . fromVSeq <$> xs+ (SHA.SHA256S w0 w1 w2 w3 w4 w5 w6 _) <-+ foldM (\st blk -> seq st (SHA.processSHA256Block st <$> (toSHA256Block =<< blk)))+ SHA.initialSHA224State blks+ let f :: Word32 -> Eval Value+ f = pure . VWord 32 . pure . WordVal . BV 32 . toInteger+ zs = finiteSeqMap (map f [w0,w1,w2,w3,w4,w5,w6])+ seq zs (pure (VSeq 7 zs))) , ("processSHA2_256", {-# SCC "SuiteB::processSHA2_256" #-}- ilam $ \n ->- lam $ \xs ->- do blks <- enumerateSeqMap n . fromVSeq <$> xs- (SHA.SHA256S w0 w1 w2 w3 w4 w5 w6 w7) <-- foldM (\st blk -> seq st (SHA.processSHA256Block st <$> (toSHA256Block =<< blk)))- SHA.initialSHA256State blks- let f :: Word32 -> Eval Value- f = pure . VWord 32 . pure . WordVal . BV 32 . toInteger- zs = finiteSeqMap Concrete (map f [w0,w1,w2,w3,w4,w5,w6,w7])- seq zs (pure (VSeq 8 zs)))+ PFinPoly \n ->+ PFun \xs ->+ PPrim+ do blks <- enumerateSeqMap n . fromVSeq <$> xs+ (SHA.SHA256S w0 w1 w2 w3 w4 w5 w6 w7) <-+ foldM (\st blk -> seq st (SHA.processSHA256Block st <$> (toSHA256Block =<< blk)))+ SHA.initialSHA256State blks+ let f :: Word32 -> Eval Value+ f = pure . VWord 32 . pure . WordVal . BV 32 . toInteger+ zs = finiteSeqMap (map f [w0,w1,w2,w3,w4,w5,w6,w7])+ seq zs (pure (VSeq 8 zs))) , ("processSHA2_384", {-# SCC "SuiteB::processSHA2_384" #-}- ilam $ \n ->- lam $ \xs ->- do blks <- enumerateSeqMap n . fromVSeq <$> xs- (SHA.SHA512S w0 w1 w2 w3 w4 w5 _ _) <-- foldM (\st blk -> seq st (SHA.processSHA512Block st <$> (toSHA512Block =<< blk)))- SHA.initialSHA384State blks- let f :: Word64 -> Eval Value- f = pure . VWord 64 . pure . WordVal . BV 64 . toInteger- zs = finiteSeqMap Concrete (map f [w0,w1,w2,w3,w4,w5])- seq zs (pure (VSeq 6 zs)))+ PFinPoly \n ->+ PFun \xs ->+ PPrim+ do blks <- enumerateSeqMap n . fromVSeq <$> xs+ (SHA.SHA512S w0 w1 w2 w3 w4 w5 _ _) <-+ foldM (\st blk -> seq st (SHA.processSHA512Block st <$> (toSHA512Block =<< blk)))+ SHA.initialSHA384State blks+ let f :: Word64 -> Eval Value+ f = pure . VWord 64 . pure . WordVal . BV 64 . toInteger+ zs = finiteSeqMap (map f [w0,w1,w2,w3,w4,w5])+ seq zs (pure (VSeq 6 zs))) , ("processSHA2_512", {-# SCC "SuiteB::processSHA2_512" #-}- ilam $ \n ->- lam $ \xs ->- do blks <- enumerateSeqMap n . fromVSeq <$> xs- (SHA.SHA512S w0 w1 w2 w3 w4 w5 w6 w7) <-- foldM (\st blk -> seq st (SHA.processSHA512Block st <$> (toSHA512Block =<< blk)))- SHA.initialSHA512State blks- let f :: Word64 -> Eval Value- f = pure . VWord 64 . pure . WordVal . BV 64 . toInteger- zs = finiteSeqMap Concrete (map f [w0,w1,w2,w3,w4,w5,w6,w7])- seq zs (pure (VSeq 8 zs)))+ PFinPoly \n ->+ PFun \xs ->+ PPrim+ do blks <- enumerateSeqMap n . fromVSeq <$> xs+ (SHA.SHA512S w0 w1 w2 w3 w4 w5 w6 w7) <-+ foldM (\st blk -> seq st (SHA.processSHA512Block st <$> (toSHA512Block =<< blk)))+ SHA.initialSHA512State blks+ let f :: Word64 -> Eval Value+ f = pure . VWord 64 . pure . WordVal . BV 64 . toInteger+ zs = finiteSeqMap (map f [w0,w1,w2,w3,w4,w5,w6,w7])+ seq zs (pure (VSeq 8 zs))) , ("AESKeyExpand", {-# SCC "SuiteB::AESKeyExpand" #-}- ilam $ \k ->- lam $ \seed ->+ PFinPoly \k ->+ PFun \seed ->+ PPrim do ss <- fromVSeq <$> seed let toWord :: Integer -> Eval Word32 toWord i = fromInteger. bvVal <$> (fromVWord Concrete "AESInfKeyExpand" =<< lookupSeqMap ss i)@@ -497,10 +340,11 @@ kws <- mapM toWord [0 .. k-1] let ws = AES.keyExpansionWords k kws let len = 4*(k+7)- pure (VSeq len (finiteSeqMap Concrete (map fromWord ws))))+ pure (VSeq len (finiteSeqMap (map fromWord ws)))) , ("AESInvMixColumns", {-# SCC "SuiteB::AESInvMixColumns" #-}- lam $ \st ->+ PFun \st ->+ PPrim do ss <- fromVSeq <$> st let toWord :: Integer -> Eval Word32 toWord i = fromInteger. bvVal <$> (fromVWord Concrete "AESInvMixColumns" =<< lookupSeqMap ss i)@@ -508,10 +352,11 @@ fromWord = pure . VWord 32 . pure . WordVal . BV 32 . toInteger ws <- mapM toWord [0,1,2,3] let ws' = AES.invMixColumns ws- pure . VSeq 4 . finiteSeqMap Concrete . map fromWord $ ws')+ pure . VSeq 4 . finiteSeqMap . map fromWord $ ws') , ("AESEncRound", {-# SCC "SuiteB::AESEncRound" #-}- lam $ \st ->+ PFun \st ->+ PPrim do ss <- fromVSeq <$> st let toWord :: Integer -> Eval Word32 toWord i = fromInteger. bvVal <$> (fromVWord Concrete "AESEncRound" =<< lookupSeqMap ss i)@@ -519,10 +364,11 @@ fromWord = pure . VWord 32 . pure . WordVal . BV 32 . toInteger ws <- mapM toWord [0,1,2,3] let ws' = AES.aesRound ws- pure . VSeq 4 . finiteSeqMap Concrete . map fromWord $ ws')+ pure . VSeq 4 . finiteSeqMap . map fromWord $ ws') , ("AESEncFinalRound", {-# SCC "SuiteB::AESEncFinalRound" #-}- lam $ \st ->+ PFun \st ->+ PPrim do ss <- fromVSeq <$> st let toWord :: Integer -> Eval Word32 toWord i = fromInteger. bvVal <$> (fromVWord Concrete "AESEncFinalRound" =<< lookupSeqMap ss i)@@ -530,10 +376,11 @@ fromWord = pure . VWord 32 . pure . WordVal . BV 32 . toInteger ws <- mapM toWord [0,1,2,3] let ws' = AES.aesFinalRound ws- pure . VSeq 4 . finiteSeqMap Concrete . map fromWord $ ws')+ pure . VSeq 4 . finiteSeqMap . map fromWord $ ws') , ("AESDecRound", {-# SCC "SuiteB::AESDecRound" #-}- lam $ \st ->+ PFun \st ->+ PPrim do ss <- fromVSeq <$> st let toWord :: Integer -> Eval Word32 toWord i = fromInteger. bvVal <$> (fromVWord Concrete "AESDecRound" =<< lookupSeqMap ss i)@@ -541,10 +388,11 @@ fromWord = pure . VWord 32 . pure . WordVal . BV 32 . toInteger ws <- mapM toWord [0,1,2,3] let ws' = AES.aesInvRound ws- pure . VSeq 4 . finiteSeqMap Concrete . map fromWord $ ws')+ pure . VSeq 4 . finiteSeqMap . map fromWord $ ws') , ("AESDecFinalRound", {-# SCC "SuiteB::AESDecFinalRound" #-}- lam $ \st ->+ PFun \st ->+ PPrim do ss <- fromVSeq <$> st let toWord :: Integer -> Eval Word32 toWord i = fromInteger. bvVal <$> (fromVWord Concrete "AESDecFinalRound" =<< lookupSeqMap ss i)@@ -552,7 +400,7 @@ fromWord = pure . VWord 32 . pure . WordVal . BV 32 . toInteger ws <- mapM toWord [0,1,2,3] let ws' = AES.aesInvFinalRound ws- pure . VSeq 4 . finiteSeqMap Concrete . map fromWord $ ws')+ pure . VSeq 4 . finiteSeqMap . map fromWord $ ws') ] @@ -603,12 +451,13 @@ -------------------------------------------------------------------------------- -sshrV :: Value+sshrV :: Prim Concrete sshrV =- nlam $ \_n ->- tlam $ \ix ->- wlam Concrete $ \(BV w x) -> return $- lam $ \y ->+ PNumPoly \_n ->+ PTyPoly \ix ->+ PWordFun \(BV w x) ->+ PFun \y ->+ PPrim do idx <- y >>= asIndex Concrete ">>$" ix >>= \case Left idx -> pure idx Right wv -> bvVal <$> asWordVal Concrete wv@@ -618,14 +467,15 @@ -- ^ The function may assume its arguments are masked. -- It is responsible for masking its result if needed. -> (Nat' -> TValue -> SeqMap Concrete -> Integer -> SeqMap Concrete)- -> Value-logicShift opW opS- = nlam $ \ a ->- tlam $ \ _ix ->- tlam $ \ c ->- lam $ \ l -> return $- lam $ \ r -> do- i <- r >>= \case+ -> Prim Concrete+logicShift opW opS =+ PNumPoly \a ->+ PTyPoly \_ix ->+ PTyPoly \c ->+ PFun \l ->+ PFun \r ->+ PPrim+ do i <- r >>= \case VInteger i -> pure i VWord _ wval -> bvVal <$> (asWordVal Concrete =<< wval) _ -> evalPanic "logicShift" ["not an index"]@@ -795,55 +645,3 @@ updateBack_word (Nat n) _eltTy bs (Right w) val = do idx <- bvVal <$> asWordVal Concrete w updateWordValue Concrete bs (n - idx - 1) (fromVBit <$> val)---floatPrims :: Concrete -> Map PrimIdent Value-floatPrims sym = Map.fromList [ (floatPrim i,v) | (i,v) <- nonInfixTable ]- where- (~>) = (,)- nonInfixTable =- [ "fpNaN" ~> ilam \e -> ilam \p ->- VFloat BF { bfValue = FP.bfNaN- , bfExpWidth = e, bfPrecWidth = p }-- , "fpPosInf" ~> ilam \e -> ilam \p ->- VFloat BF { bfValue = FP.bfPosInf- , bfExpWidth = e, bfPrecWidth = p }-- , "fpFromBits" ~> ilam \e -> ilam \p -> wlam sym \bv ->- pure $ VFloat $ floatFromBits e p $ bvVal bv-- , "fpToBits" ~> ilam \e -> ilam \p -> flam \x ->- pure $ word sym (e + p)- $ floatToBits e p- $ bfValue x- , "=.=" ~> ilam \_ -> ilam \_ -> flam \x -> pure $ flam \y ->- pure $ VBit- $ bitLit sym- $ FP.bfCompare (bfValue x) (bfValue y) == EQ-- , "fpIsFinite" ~> ilam \_ -> ilam \_ -> flam \x ->- pure $ VBit $ bitLit sym $ FP.bfIsFinite $ bfValue x-- -- From Backend class- , "fpAdd" ~> fpBinArithV sym fpPlus- , "fpSub" ~> fpBinArithV sym fpMinus- , "fpMul" ~> fpBinArithV sym fpMult- , "fpDiv" ~> fpBinArithV sym fpDiv-- , "fpFromRational" ~>- ilam \e -> ilam \p -> wlam sym \r -> pure $ lam \x ->- do rat <- fromVRational <$> x- VFloat <$> do mode <- fpRoundMode sym r- pure $ floatFromRational e p mode- $ sNum rat % sDenom rat- , "fpToRational" ~>- ilam \_e -> ilam \_p -> flam \fp ->- case floatToRational "fpToRational" fp of- Left err -> raiseError sym err- Right r -> pure $- VRational- SRational { sNum = numerator r, sDenom = denominator r }- ]--
src/Cryptol/Eval/Env.hs view
@@ -16,8 +16,7 @@ import Cryptol.Backend -import Cryptol.Backend.Monad( PPOpts )-+import Cryptol.Eval.Prims import Cryptol.Eval.Type import Cryptol.Eval.Value import Cryptol.ModuleSystem.Name@@ -25,7 +24,6 @@ import Cryptol.TypeCheck.Solver.InfNat import Cryptol.Utils.PP - import qualified Data.IntMap.Strict as IntMap import Data.Semigroup @@ -37,29 +35,31 @@ -- Evaluation Environment ------------------------------------------------------ data GenEvalEnv sym = EvalEnv- { envVars :: !(IntMap.IntMap (SEval sym (GenValue sym)))+ { envVars :: !(IntMap.IntMap (Either (Prim sym) (SEval sym (GenValue sym)))) , envTypes :: !TypeEnv } deriving Generic instance Semigroup (GenEvalEnv sym) where l <> r = EvalEnv { envVars = IntMap.union (envVars l) (envVars r)- , envTypes = IntMap.union (envTypes l) (envTypes r)+ , envTypes = envTypes l <> envTypes r } instance Monoid (GenEvalEnv sym) where mempty = EvalEnv { envVars = IntMap.empty- , envTypes = IntMap.empty+ , envTypes = mempty }- mappend l r = l <> r ppEnv :: Backend sym => sym -> PPOpts -> GenEvalEnv sym -> SEval sym Doc ppEnv sym opts env = brackets . fsep <$> mapM bind (IntMap.toList (envVars env)) where- bind (k,v) = do vdoc <- ppValue sym opts =<< v- return (int k <+> text "->" <+> vdoc)+ bind (k,Left _) =+ do return (int k <+> text "<<prim>>")+ bind (k,Right v) =+ do vdoc <- ppValue sym opts =<< v+ return (int k <+> text "->" <+> vdoc) -- | Evaluation environment with no bindings emptyEnv :: GenEvalEnv sym@@ -75,32 +75,32 @@ SEval sym (GenEvalEnv sym) bindVar sym n val env = do let nm = show $ ppLocName n- val' <- sDelay sym (Just nm) val- return $ env{ envVars = IntMap.insert (nameUnique n) val' (envVars env) }+ val' <- sDelayFill sym val Nothing nm+ return $ env{ envVars = IntMap.insert (nameUnique n) (Right val') (envVars env) } -- | Bind a variable to a value in the evaluation environment, without -- creating a thunk. bindVarDirect :: Backend sym => Name ->- GenValue sym ->+ Prim sym -> GenEvalEnv sym -> GenEvalEnv sym bindVarDirect n val env = do- env{ envVars = IntMap.insert (nameUnique n) (pure val) (envVars env) }+ env{ envVars = IntMap.insert (nameUnique n) (Left val) (envVars env) } -- | Lookup a variable in the environment. {-# INLINE lookupVar #-}-lookupVar :: Name -> GenEvalEnv sym -> Maybe (SEval sym (GenValue sym))+lookupVar :: Name -> GenEvalEnv sym -> Maybe (Either (Prim sym) (SEval sym (GenValue sym))) lookupVar n env = IntMap.lookup (nameUnique n) (envVars env) -- | Bind a type variable of kind *. {-# INLINE bindType #-} bindType :: TVar -> Either Nat' TValue -> GenEvalEnv sym -> GenEvalEnv sym-bindType p ty env = env { envTypes = IntMap.insert (tvUnique p) ty (envTypes env) }+bindType p ty env = env{ envTypes = bindTypeVar p ty (envTypes env) } -- | Lookup a type variable. {-# INLINE lookupType #-} lookupType :: TVar -> GenEvalEnv sym -> Maybe (Either Nat' TValue)-lookupType p env = IntMap.lookup (tvUnique p) (envTypes env)+lookupType p env = lookupTypeVar p (envTypes env)
src/Cryptol/Eval/Generic.hs view
@@ -11,6 +11,7 @@ {-# LANGUAGE FlexibleContexts #-} {-# LANGUAGE TupleSections #-} {-# LANGUAGE MultiParamTypeClasses #-}+{-# LANGUAGE OverloadedStrings #-} {-# LANGUAGE RecordWildCards #-} {-# LANGUAGE NamedFieldPuns #-} {-# LANGUAGE Rank2Types #-}@@ -27,24 +28,28 @@ import System.Random.TF.Gen (seedTFGen) import Data.Bits (testBit, (.&.), shiftR)- import Data.Maybe (fromMaybe)+import qualified Data.Map.Strict as Map+import Data.Map(Map) import Data.Ratio ((%)) import Cryptol.TypeCheck.AST import Cryptol.TypeCheck.Solver.InfNat (Nat'(..),nMul,widthInteger) import Cryptol.Backend import Cryptol.Backend.Concrete (Concrete(..))-import Cryptol.Backend.Monad ( Eval, evalPanic, EvalError(..), Unsupported(..) )+import Cryptol.Backend.Monad( Eval, evalPanic, EvalError(..), Unsupported(..) ) import Cryptol.Testing.Random( randomValue ) +import Cryptol.Eval.Prims import Cryptol.Eval.Type import Cryptol.Eval.Value+import Cryptol.Utils.Ident (PrimIdent, prelPrim, floatPrim)+import Cryptol.Utils.Logger(logPrint) import Cryptol.Utils.Panic (panic)+import Cryptol.Utils.PP import Cryptol.Utils.RecordMap - {-# SPECIALIZE mkLit :: Concrete -> TValue -> Integer -> Eval (GenValue Concrete) #-} @@ -63,14 +68,15 @@ _ -> evalPanic "Cryptol.Eval.Prim.evalConst" [ "Invalid type for number" ] -{-# SPECIALIZE ecNumberV :: Concrete -> GenValue Concrete+{-# SPECIALIZE ecNumberV :: Concrete -> Prim Concrete #-} -- | Make a numeric constant.-ecNumberV :: Backend sym => sym -> GenValue sym+ecNumberV :: Backend sym => sym -> Prim sym ecNumberV sym =- nlam $ \valT ->- VPoly $ \ty ->+ PNumPoly \valT ->+ PTyPoly \ty ->+ PPrim case valT of Nat v -> mkLit sym ty v _ -> evalPanic "Cryptol.Eval.Prim.evalConst"@@ -80,32 +86,38 @@ ] - {-# SPECIALIZE intV :: Concrete -> Integer -> TValue -> Eval (GenValue Concrete) #-} intV :: Backend sym => sym -> SInteger sym -> TValue -> SEval sym (GenValue sym)-intV sym i = ringNullary sym (\w -> wordFromInt sym w i) (pure i) (\m -> intToZn sym m i) (intToRational sym i)- (\e p -> fpRndMode sym >>= \r -> fpFromInteger sym e p r i)+intV sym i =+ ringNullary sym+ (\w -> wordFromInt sym w i)+ (pure i)+ (\m -> intToZn sym m i)+ (intToRational sym i)+ (\e p -> fpRndMode sym >>= \r -> fpFromInteger sym e p r i) -{-# SPECIALIZE ratioV :: Concrete -> GenValue Concrete #-}-ratioV :: Backend sym => sym -> GenValue sym+{-# SPECIALIZE ratioV :: Concrete -> Prim Concrete #-}+ratioV :: Backend sym => sym -> Prim sym ratioV sym =- lam $ \x -> return $- lam $ \y ->+ PFun \x ->+ PFun \y ->+ PPrim do x' <- fromVInteger <$> x y' <- fromVInteger <$> y VRational <$> ratio sym x' y' -{-# SPECIALIZE ecFractionV :: Concrete -> GenValue Concrete+{-# SPECIALIZE ecFractionV :: Concrete -> Prim Concrete #-}-ecFractionV :: Backend sym => sym -> GenValue sym+ecFractionV :: Backend sym => sym -> Prim sym ecFractionV sym =- ilam \n ->- ilam \d ->- ilam \_r ->- VPoly \ty ->+ PFinPoly \n ->+ PFinPoly \d ->+ PFinPoly \_r ->+ PTyPoly \ty ->+ PPrim case ty of- TVFloat e p -> VFloat <$> fpLit sym e p (n % d)+ TVFloat e p -> VFloat <$> fpLit sym e p (n % d) TVRational -> do x <- integerLit sym n y <- integerLit sym d@@ -116,34 +128,38 @@ -{-# SPECIALIZE fromZV :: Concrete -> GenValue Concrete #-}-fromZV :: Backend sym => sym -> GenValue sym+{-# SPECIALIZE fromZV :: Concrete -> Prim Concrete #-}+fromZV :: Backend sym => sym -> Prim sym fromZV sym =- nlam $ \(finNat' -> n) ->- lam $ \v -> VInteger <$> (znToInt sym n . fromVInteger =<< v)+ PFinPoly \n ->+ PFun \v ->+ PPrim+ (VInteger <$> (znToInt sym n . fromVInteger =<< v)) -- Operation Lifting ----------------------------------------------------------- type Binary sym = TValue -> GenValue sym -> GenValue sym -> SEval sym (GenValue sym) -{-# SPECIALIZE binary :: Binary Concrete -> GenValue Concrete+{-# SPECIALIZE binary :: Binary Concrete -> Prim Concrete #-}-binary :: Backend sym => Binary sym -> GenValue sym-binary f = tlam $ \ ty ->- lam $ \ a -> return $- lam $ \ b -> do- --io $ putStrLn "Entering a binary function"- join (f ty <$> a <*> b)+binary :: Backend sym => Binary sym -> Prim sym+binary f = PTyPoly \ty ->+ PFun \a ->+ PFun \b ->+ PPrim $+ do x <- a+ y <- b+ f ty x y type Unary sym = TValue -> GenValue sym -> SEval sym (GenValue sym) -{-# SPECIALIZE unary :: Unary Concrete -> GenValue Concrete+{-# SPECIALIZE unary :: Unary Concrete -> Prim Concrete #-}-unary :: Backend sym => Unary sym -> GenValue sym-unary f = tlam $ \ ty ->- lam $ \ a -> f ty =<< a-+unary :: Backend sym => Unary sym -> Prim sym+unary f = PTyPoly \ty ->+ PFun \a ->+ PPrim (f ty =<< a) type BinWord sym = Integer -> SWord sym -> SWord sym -> SEval sym (SWord sym) @@ -200,37 +216,41 @@ | isTBit a -> do lw <- fromVWord sym "ringLeft" l rw <- fromVWord sym "ringRight" r- return $ VWord w (WordVal <$> opw w lw rw)- | otherwise -> VSeq w <$> (join (zipSeqMap (loop a) <$>+ stk <- sGetCallStack sym+ return $ VWord w (WordVal <$> (sWithCallStack sym stk (opw w lw rw)))+ | otherwise -> VSeq w <$> (join (zipSeqMap sym (loop a) <$> (fromSeq "ringBinary left" l) <*> (fromSeq "ringBinary right" r))) TVStream a -> -- streams- VStream <$> (join (zipSeqMap (loop a) <$>+ VStream <$> (join (zipSeqMap sym (loop a) <$> (fromSeq "ringBinary left" l) <*> (fromSeq "ringBinary right" r))) -- functions TVFun _ ety ->- return $ lam $ \ x -> loop' ety (fromVFun l x) (fromVFun r x)+ lam sym $ \ x -> loop' ety (fromVFun sym l x) (fromVFun sym r x) -- tuples TVTuple tys ->- do ls <- mapM (sDelay sym Nothing) (fromVTuple l)- rs <- mapM (sDelay sym Nothing) (fromVTuple r)+ do ls <- mapM (sDelay sym) (fromVTuple l)+ rs <- mapM (sDelay sym) (fromVTuple r) return $ VTuple (zipWith3 loop' tys ls rs) -- records TVRec fs -> do VRecord <$> traverseRecordMap- (\f fty -> sDelay sym Nothing (loop' fty (lookupRecord f l) (lookupRecord f r)))+ (\f fty -> sDelay sym (loop' fty (lookupRecord f l) (lookupRecord f r))) fs TVAbstract {} -> evalPanic "ringBinary" ["Abstract type not in `Ring`"] + TVNewtype {} ->+ evalPanic "ringBinary" ["Newtype not in `Ring`"]+ type UnaryWord sym = Integer -> SWord sym -> SEval sym (SWord sym) @@ -282,30 +302,34 @@ -- words and finite sequences | isTBit a -> do wx <- fromVWord sym "ringUnary" v- return $ VWord w (WordVal <$> opw w wx)- | otherwise -> VSeq w <$> (mapSeqMap (loop a) =<< fromSeq "ringUnary" v)+ stk <- sGetCallStack sym+ return $ VWord w (WordVal <$> sWithCallStack sym stk (opw w wx))+ | otherwise -> VSeq w <$> (mapSeqMap sym (loop a) =<< fromSeq "ringUnary" v) TVStream a ->- VStream <$> (mapSeqMap (loop a) =<< fromSeq "ringUnary" v)+ VStream <$> (mapSeqMap sym (loop a) =<< fromSeq "ringUnary" v) -- functions TVFun _ ety ->- return $ lam $ \ y -> loop' ety (fromVFun v y)+ lam sym $ \ y -> loop' ety (fromVFun sym v y) -- tuples TVTuple tys ->- do as <- mapM (sDelay sym Nothing) (fromVTuple v)+ do as <- mapM (sDelay sym) (fromVTuple v) return $ VTuple (zipWith loop' tys as) -- records TVRec fs -> VRecord <$> traverseRecordMap- (\f fty -> sDelay sym Nothing (loop' fty (lookupRecord f v)))+ (\f fty -> sDelay sym (loop' fty (lookupRecord f v))) fs TVAbstract {} -> evalPanic "ringUnary" ["Abstract type not in `Ring`"] + TVNewtype {} -> evalPanic "ringUnary" ["Newtype not in `Ring`"]++ {-# SPECIALIZE ringNullary :: Concrete -> (Integer -> SEval Concrete (SWord Concrete)) ->@@ -346,30 +370,35 @@ TVSeq w a -- words and finite sequences- | isTBit a -> pure $ VWord w $ (WordVal <$> opw w)+ | isTBit a ->+ do stk <- sGetCallStack sym+ pure $ VWord w $ (WordVal <$> sWithCallStack sym stk (opw w)) | otherwise ->- do v <- sDelay sym Nothing (loop a)- pure $ VSeq w $ IndexSeqMap $ const v+ do v <- sDelay sym (loop a)+ pure $ VSeq w $ IndexSeqMap \_i -> v TVStream a ->- do v <- sDelay sym Nothing (loop a)- pure $ VStream $ IndexSeqMap $ const v+ do v <- sDelay sym (loop a)+ pure $ VStream $ IndexSeqMap \_i -> v TVFun _ b ->- do v <- sDelay sym Nothing (loop b)- pure $ lam $ const $ v+ do v <- sDelay sym (loop b)+ lam sym (const v) TVTuple tys ->- do xs <- mapM (sDelay sym Nothing . loop) tys+ do xs <- mapM (sDelay sym . loop) tys pure $ VTuple xs TVRec fs ->- do xs <- traverse (sDelay sym Nothing . loop) fs+ do xs <- traverse (sDelay sym . loop) fs pure $ VRecord xs TVAbstract {} -> evalPanic "ringNullary" ["Abstract type not in `Ring`"] + TVNewtype {} ->+ evalPanic "ringNullary" ["Newtype not in `Ring`"]+ {-# SPECIALIZE integralBinary :: Concrete -> BinWord Concrete -> (SInteger Concrete -> SInteger Concrete -> SEval Concrete (SInteger Concrete)) -> Binary Concrete@@ -390,7 +419,8 @@ | isTBit a -> do wl <- fromVWord sym "integralBinary left" l wr <- fromVWord sym "integralBinary right" r- return $ VWord w (WordVal <$> opw w wl wr)+ stk <- sGetCallStack sym+ return $ VWord w (WordVal <$> sWithCallStack sym stk (opw w wl wr)) _ -> evalPanic "integralBinary" [show ty ++ " not int class `Integral`"] @@ -398,15 +428,16 @@ --------------------------------------------------------------------------- -- Ring -{-# SPECIALIZE fromIntegerV :: Concrete -> GenValue Concrete+{-# SPECIALIZE fromIntegerV :: Concrete -> Prim Concrete #-} -- | Convert an unbounded integer to a value in Ring-fromIntegerV :: Backend sym => sym -> GenValue sym+fromIntegerV :: Backend sym => sym -> Prim sym fromIntegerV sym =- tlam $ \ a ->- lam $ \ v ->- do i <- fromVInteger <$> v- intV sym i a+ PTyPoly \a ->+ PFun \v ->+ PPrim+ do i <- fromVInteger <$> v+ intV sym i a {-# INLINE addV #-} addV :: Backend sym => sym -> Binary sym@@ -458,13 +489,14 @@ opw _w x y = wordDiv sym x y opi x y = intDiv sym x y -{-# SPECIALIZE expV :: Concrete -> GenValue Concrete #-}-expV :: Backend sym => sym -> GenValue sym+{-# SPECIALIZE expV :: Concrete -> Prim Concrete #-}+expV :: Backend sym => sym -> Prim sym expV sym =- tlam $ \aty ->- tlam $ \ety ->- lam $ \am -> return $- lam $ \em ->+ PTyPoly \aty ->+ PTyPoly \ety ->+ PFun \am ->+ PFun \em ->+ PPrim do a <- am e <- em case ety of@@ -522,12 +554,13 @@ opw _w x y = wordMod sym x y opi x y = intMod sym x y -{-# SPECIALIZE toIntegerV :: Concrete -> GenValue Concrete #-}+{-# SPECIALIZE toIntegerV :: Concrete -> Prim Concrete #-} -- | Convert a word to a non-negative integer.-toIntegerV :: Backend sym => sym -> GenValue sym+toIntegerV :: Backend sym => sym -> Prim sym toIntegerV sym =- tlam $ \a ->- lam $ \v ->+ PTyPoly \a ->+ PFun \v ->+ PPrim case a of TVSeq _w el | isTBit el -> VInteger <$> (wordToInt sym =<< (fromVWord sym "toInteger" =<< v))@@ -537,11 +570,12 @@ ----------------------------------------------------------------------------- -- Field -{-# SPECIALIZE recipV :: Concrete -> GenValue Concrete #-}-recipV :: Backend sym => sym -> GenValue sym+{-# SPECIALIZE recipV :: Concrete -> Prim Concrete #-}+recipV :: Backend sym => sym -> Prim sym recipV sym =- tlam $ \a ->- lam $ \x ->+ PTyPoly \a ->+ PFun \x ->+ PPrim case a of TVRational -> VRational <$> (rationalRecip sym . fromVRational =<< x) TVFloat e p ->@@ -552,12 +586,13 @@ TVIntMod m -> VInteger <$> (znRecip sym m . fromVInteger =<< x) _ -> evalPanic "recip" [show a ++ "is not a Field"] -{-# SPECIALIZE fieldDivideV :: Concrete -> GenValue Concrete #-}-fieldDivideV :: Backend sym => sym -> GenValue sym+{-# SPECIALIZE fieldDivideV :: Concrete -> Prim Concrete #-}+fieldDivideV :: Backend sym => sym -> Prim sym fieldDivideV sym =- tlam $ \a ->- lam $ \x -> return $- lam $ \y ->+ PTyPoly \a ->+ PFun \x ->+ PFun \y ->+ PPrim case a of TVRational -> do x' <- fromVRational <$> x@@ -656,27 +691,27 @@ -- Bitvector signed div and modulus {-# INLINE lg2V #-}-lg2V :: Backend sym => sym -> GenValue sym+lg2V :: Backend sym => sym -> Prim sym lg2V sym =- nlam $ \(finNat' -> w) ->- wlam sym $ \x -> return $- VWord w (WordVal <$> wordLg2 sym x)+ PFinPoly \w ->+ PWordFun \x ->+ PVal (VWord w (WordVal <$> wordLg2 sym x)) -{-# SPECIALIZE sdivV :: Concrete -> GenValue Concrete #-}-sdivV :: Backend sym => sym -> GenValue sym+{-# SPECIALIZE sdivV :: Concrete -> Prim Concrete #-}+sdivV :: Backend sym => sym -> Prim sym sdivV sym =- nlam $ \(finNat' -> w) ->- wlam sym $ \x -> return $- wlam sym $ \y -> return $- VWord w (WordVal <$> wordSignedDiv sym x y)+ PFinPoly \w ->+ PWordFun \x ->+ PWordFun \y ->+ PVal (VWord w (WordVal <$> wordSignedDiv sym x y)) -{-# SPECIALIZE smodV :: Concrete -> GenValue Concrete #-}-smodV :: Backend sym => sym -> GenValue sym+{-# SPECIALIZE smodV :: Concrete -> Prim Concrete #-}+smodV :: Backend sym => sym -> Prim sym smodV sym =- nlam $ \(finNat' -> w) ->- wlam sym $ \x -> return $- wlam sym $ \y -> return $- VWord w (WordVal <$> wordSignedMod sym x y)+ PFinPoly \w ->+ PWordFun \x ->+ PWordFun \y ->+ PVal (VWord w (WordVal <$> wordSignedMod sym x y)) -- Cmp ------------------------------------------------------------------------- @@ -733,6 +768,9 @@ TVAbstract {} -> evalPanic "cmpValue" [ "Abstract type not in `Cmp`" ] + TVNewtype {} -> evalPanic "cmpValue"+ [ "Newtype not in `Cmp`" ]+ cmpValues (t : ts) (x1 : xs1) (x2 : xs2) k = do x1' <- x1 x2' <- x2@@ -879,30 +917,32 @@ TVSeq w ety | isTBit ety -> pure $ word sym w 0 | otherwise ->- do z <- sDelay sym Nothing (zeroV sym ety)- pure $ VSeq w (IndexSeqMap $ const z)+ do z <- sDelay sym (zeroV sym ety)+ pure $ VSeq w (IndexSeqMap \_i -> z) TVStream ety ->- do z <- sDelay sym Nothing (zeroV sym ety)- pure $ VStream (IndexSeqMap $ const z)+ do z <- sDelay sym (zeroV sym ety)+ pure $ VStream (IndexSeqMap \_i -> z) -- functions TVFun _ bty ->- do z <- sDelay sym Nothing (zeroV sym bty)- pure $ lam (const z)+ do z <- sDelay sym (zeroV sym bty)+ lam sym (const z) -- tuples TVTuple tys ->- do xs <- mapM (sDelay sym Nothing . zeroV sym) tys+ do xs <- mapM (sDelay sym . zeroV sym) tys pure $ VTuple xs -- records TVRec fields ->- do xs <- traverse (sDelay sym Nothing . zeroV sym) fields+ do xs <- traverse (sDelay sym . zeroV sym) fields pure $ VRecord xs TVAbstract {} -> evalPanic "zeroV" [ "Abstract type not in `Zero`" ] + TVNewtype {} -> evalPanic "zeroV" [ "Newtype not in `Zero`" ]+ -- | otherwise = evalPanic "zeroV" ["invalid type for zero"] {-# INLINE joinWordVal #-}@@ -936,7 +976,7 @@ where loop :: SEval sym (WordValue sym) -> [SEval sym (GenValue sym)] -> SEval sym (GenValue sym) loop !wv [] =- VWord (nParts * nEach) <$> sDelay sym Nothing wv+ VWord (nParts * nEach) <$> sDelay sym wv loop !wv (w : ws) = w >>= \case VWord _ w' ->@@ -1038,24 +1078,24 @@ case back of Nat rightWidth | aBit -> do- ws <- sDelay sym Nothing (splitWordVal sym leftWidth rightWidth =<< fromWordVal "splitAtV" val)+ ws <- sDelay sym (splitWordVal sym leftWidth rightWidth =<< fromWordVal "splitAtV" val) return $ VTuple [ VWord leftWidth . pure . fst <$> ws , VWord rightWidth . pure . snd <$> ws ] Inf | aBit -> do- vs <- sDelay sym Nothing (fromSeq "splitAtV" val)- ls <- sDelay sym Nothing (fst . splitSeqMap leftWidth <$> vs)- rs <- sDelay sym Nothing (snd . splitSeqMap leftWidth <$> vs)+ vs <- sDelay sym (fromSeq "splitAtV" val)+ ls <- sDelay sym (fst . splitSeqMap leftWidth <$> vs)+ rs <- sDelay sym (snd . splitSeqMap leftWidth <$> vs) return $ VTuple [ return $ VWord leftWidth (LargeBitsVal leftWidth <$> ls) , VStream <$> rs ] _ -> do- vs <- sDelay sym Nothing (fromSeq "splitAtV" val)- ls <- sDelay sym Nothing (fst . splitSeqMap leftWidth <$> vs)- rs <- sDelay sym Nothing (snd . splitSeqMap leftWidth <$> vs)+ vs <- sDelay sym (fromSeq "splitAtV" val)+ ls <- sDelay sym (fst . splitSeqMap leftWidth <$> vs)+ rs <- sDelay sym (snd . splitSeqMap leftWidth <$> vs) return $ VTuple [ VSeq leftWidth <$> ls , mkSeq back a <$> rs ]@@ -1093,19 +1133,20 @@ {-# INLINE ecSplitV #-} -- | Split implementation.-ecSplitV :: Backend sym => sym -> GenValue sym+ecSplitV :: Backend sym => sym -> Prim sym ecSplitV sym =- nlam $ \ parts ->- nlam $ \ each ->- tlam $ \ a ->- lam $ \ val ->+ PNumPoly \parts ->+ PNumPoly \each ->+ PTyPoly \a ->+ PFun \val ->+ PPrim case (parts, each) of (Nat p, Nat e) | isTBit a -> do ~(VWord _ val') <- val return $ VSeq p $ IndexSeqMap $ \i -> pure $ VWord e (extractWordVal sym e ((p-i-1)*e) =<< val') (Inf, Nat e) | isTBit a -> do- val' <- sDelay sym Nothing (fromSeq "ecSplitV" =<< val)+ val' <- sDelay sym (fromSeq "ecSplitV" =<< val) return $ VStream $ IndexSeqMap $ \i -> return $ VWord e $ return $ LargeBitsVal e $ IndexSeqMap $ \j -> let idx = i*e + toInteger j@@ -1113,13 +1154,13 @@ xs <- val' lookupSeqMap xs idx (Nat p, Nat e) -> do- val' <- sDelay sym Nothing (fromSeq "ecSplitV" =<< val)+ val' <- sDelay sym (fromSeq "ecSplitV" =<< val) return $ VSeq p $ IndexSeqMap $ \i -> return $ VSeq e $ IndexSeqMap $ \j -> do xs <- val' lookupSeqMap xs (e * i + j) (Inf , Nat e) -> do- val' <- sDelay sym Nothing (fromSeq "ecSplitV" =<< val)+ val' <- sDelay sym (fromSeq "ecSplitV" =<< val) return $ VStream $ IndexSeqMap $ \i -> return $ VSeq e $ IndexSeqMap $ \j -> do xs <- val'@@ -1157,7 +1198,8 @@ | isTBit c, Nat na <- a = -- Fin a => [a][b]Bit -> [b][a]Bit return $ bseq $ IndexSeqMap $ \bi -> return $ VWord na $ return $ LargeBitsVal na $ IndexSeqMap $ \ai ->- do ys <- flip lookupSeqMap (toInteger ai) =<< fromSeq "transposeV" xs+ do xs' <- fromSeq "transposeV" xs+ ys <- lookupSeqMap xs' ai case ys of VStream ys' -> lookupSeqMap ys' bi VWord _ wv -> VBit <$> (flip (indexWordValue sym) bi =<< wv)@@ -1166,7 +1208,8 @@ | isTBit c, Inf <- a = -- [inf][b]Bit -> [b][inf]Bit return $ bseq $ IndexSeqMap $ \bi -> return $ VStream $ IndexSeqMap $ \ai ->- do ys <- flip lookupSeqMap ai =<< fromSeq "transposeV" xs+ do xs' <- fromSeq "transposeV" xs+ ys <- lookupSeqMap xs' ai case ys of VStream ys' -> lookupSeqMap ys' bi VWord _ wv -> VBit <$> (flip (indexWordValue sym) bi =<< wv)@@ -1175,8 +1218,9 @@ | otherwise = -- [a][b]c -> [b][a]c return $ bseq $ IndexSeqMap $ \bi -> return $ aseq $ IndexSeqMap $ \ai -> do- ys <- flip lookupSeqMap ai =<< fromSeq "transposeV 1" xs- z <- flip lookupSeqMap bi =<< fromSeq "transposeV 2" ys+ xs' <- fromSeq "transposeV 1" xs+ ys <- fromSeq "transposeV 2" =<< lookupSeqMap xs' ai+ z <- lookupSeqMap ys bi return z where@@ -1206,7 +1250,7 @@ return $ VWord (m+n) (join (joinWordVal sym <$> l <*> r)) ccatV sym _front _back _elty (VWord m l) (VStream r) = do- l' <- sDelay sym Nothing l+ l' <- sDelay sym l return $ VStream $ IndexSeqMap $ \i -> if i < m then VBit <$> (flip (indexWordValue sym) i =<< l')@@ -1214,8 +1258,8 @@ lookupSeqMap r (i-m) ccatV sym front back elty l r = do- l'' <- sDelay sym Nothing (fromSeq "ccatV left" l)- r'' <- sDelay sym Nothing (fromSeq "ccatV right" r)+ l'' <- sDelay sym (fromSeq "ccatV left" l)+ r'' <- sDelay sym (fromSeq "ccatV right" r) let Nat n = front mkSeq (evalTF TCAdd [front,back]) elty <$> return (IndexSeqMap $ \i -> if i < n then do@@ -1238,7 +1282,7 @@ wordValLogicOp _sym _ wop (WordVal w1) (WordVal w2) = WordVal <$> wop w1 w2 wordValLogicOp sym bop _ w1 w2 = LargeBitsVal (wordValueSize sym w1) <$> zs- where zs = memoMap $ IndexSeqMap $ \i -> join (op <$> (lookupSeqMap xs i) <*> (lookupSeqMap ys i))+ where zs = memoMap sym $ IndexSeqMap $ \i -> join (op <$> (lookupSeqMap xs i) <*> (lookupSeqMap ys i)) xs = asBitsMap sym w1 ys = asBitsMap sym w2 op x y = VBit <$> (bop (fromVBit x) (fromVBit y))@@ -1281,7 +1325,7 @@ TVSeq w aty -- words | isTBit aty- -> do v <- sDelay sym Nothing $ join+ -> do v <- sDelay sym $ join (wordValLogicOp sym opb opw <$> fromWordVal "logicBinary l" l <*> fromWordVal "logicBinary r" r)@@ -1289,41 +1333,45 @@ -- finite sequences | otherwise -> VSeq w <$>- (join (zipSeqMap (loop aty) <$>+ (join (zipSeqMap sym (loop aty) <$> (fromSeq "logicBinary left" l) <*> (fromSeq "logicBinary right" r))) TVStream aty ->- VStream <$> (join (zipSeqMap (loop aty) <$>+ VStream <$> (join (zipSeqMap sym (loop aty) <$> (fromSeq "logicBinary left" l) <*> (fromSeq "logicBinary right" r))) TVTuple etys -> do- ls <- mapM (sDelay sym Nothing) (fromVTuple l)- rs <- mapM (sDelay sym Nothing) (fromVTuple r)+ ls <- mapM (sDelay sym) (fromVTuple l)+ rs <- mapM (sDelay sym) (fromVTuple r) return $ VTuple $ zipWith3 loop' etys ls rs TVFun _ bty ->- return $ lam $ \ a -> loop' bty (fromVFun l a) (fromVFun r a)+ lam sym $ \ a -> loop' bty (fromVFun sym l a) (fromVFun sym r a) TVRec fields -> VRecord <$> traverseRecordMap- (\f fty -> sDelay sym Nothing (loop' fty (lookupRecord f l) (lookupRecord f r)))+ (\f fty -> sDelay sym (loop' fty (lookupRecord f l) (lookupRecord f r))) fields TVAbstract {} -> evalPanic "logicBinary" [ "Abstract type not in `Logic`" ] + TVNewtype {} -> evalPanic "logicBinary"+ [ "Newtype not in `Logic`" ]+ {-# INLINE wordValUnaryOp #-} wordValUnaryOp :: Backend sym =>+ sym -> (SBit sym -> SEval sym (SBit sym)) -> (SWord sym -> SEval sym (SWord sym)) -> WordValue sym -> SEval sym (WordValue sym)-wordValUnaryOp _ wop (WordVal w) = WordVal <$> (wop w)-wordValUnaryOp bop _ (LargeBitsVal n xs) = LargeBitsVal n <$> mapSeqMap f xs+wordValUnaryOp _ _ wop (WordVal w) = WordVal <$> (wop w)+wordValUnaryOp sym bop _ (LargeBitsVal n xs) = LargeBitsVal n <$> mapSeqMap sym f xs where f x = VBit <$> (bop (fromVBit x)) {-# SPECIALIZE logicUnary ::@@ -1357,32 +1405,33 @@ TVSeq w ety -- words | isTBit ety- -> do v <- sDelay sym Nothing (wordValUnaryOp opb opw =<< fromWordVal "logicUnary" val)+ -> do v <- sDelay sym (wordValUnaryOp sym opb opw =<< fromWordVal "logicUnary" val) return $ VWord w v -- finite sequences | otherwise- -> VSeq w <$> (mapSeqMap (loop ety) =<< fromSeq "logicUnary" val)+ -> VSeq w <$> (mapSeqMap sym (loop ety) =<< fromSeq "logicUnary" val) -- streams TVStream ety ->- VStream <$> (mapSeqMap (loop ety) =<< fromSeq "logicUnary" val)+ VStream <$> (mapSeqMap sym (loop ety) =<< fromSeq "logicUnary" val) TVTuple etys ->- do as <- mapM (sDelay sym Nothing) (fromVTuple val)+ do as <- mapM (sDelay sym) (fromVTuple val) return $ VTuple (zipWith loop' etys as) TVFun _ bty ->- return $ lam $ \ a -> loop' bty (fromVFun val a)+ lam sym $ \ a -> loop' bty (fromVFun sym val a) TVRec fields -> VRecord <$> traverseRecordMap- (\f fty -> sDelay sym Nothing (loop' fty (lookupRecord f val)))+ (\f fty -> sDelay sym (loop' fty (lookupRecord f val))) fields TVAbstract {} -> evalPanic "logicUnary" [ "Abstract type not in `Logic`" ] + TVNewtype {} -> evalPanic "logicUnary" [ "Newtype not in `Logic`" ] {-# SPECIALIZE bitsValueLessThan :: Concrete ->@@ -1471,14 +1520,15 @@ (Nat' -> TValue -> SeqMap sym -> TValue -> SInteger sym -> SEval sym (GenValue sym)) -> (Nat' -> TValue -> SeqMap sym -> TValue -> [SBit sym] -> SEval sym (GenValue sym)) -> (Nat' -> TValue -> SeqMap sym -> TValue -> SWord sym -> SEval sym (GenValue sym)) ->- GenValue sym+ Prim sym indexPrim sym int_op bits_op word_op =- nlam $ \ len ->- tlam $ \ eltTy ->- tlam $ \ ix ->- lam $ \ xs -> return $- lam $ \ idx -> do- vs <- xs >>= \case+ PNumPoly \len ->+ PTyPoly \eltTy ->+ PTyPoly \ix ->+ PFun \xs ->+ PFun \idx ->+ PPrim+ do vs <- xs >>= \case VWord _ w -> w >>= \w' -> return $ IndexSeqMap (\i -> VBit <$> indexWordValue sym w' i) VSeq _ vs -> return vs VStream vs -> return vs@@ -1486,7 +1536,7 @@ idx' <- asIndex sym "index" ix =<< idx assertIndexInBounds sym len idx' case idx' of- Left i -> int_op len eltTy vs ix i+ Left i -> int_op len eltTy vs ix i Right (WordVal w') -> word_op len eltTy vs ix w' Right (LargeBitsVal m bs) -> bits_op len eltTy vs ix =<< traverse (fromVBit <$>) (enumerateSeqMap m bs) @@ -1497,31 +1547,33 @@ sym -> (Nat' -> TValue -> WordValue sym -> Either (SInteger sym) (WordValue sym) -> SEval sym (GenValue sym) -> SEval sym (WordValue sym)) -> (Nat' -> TValue -> SeqMap sym -> Either (SInteger sym) (WordValue sym) -> SEval sym (GenValue sym) -> SEval sym (SeqMap sym)) ->- GenValue sym+ Prim sym updatePrim sym updateWord updateSeq =- nlam $ \len ->- tlam $ \eltTy ->- tlam $ \ix ->- lam $ \xs -> return $- lam $ \idx -> return $- lam $ \val -> do- idx' <- asIndex sym "update" ix =<< idx- assertIndexInBounds sym len idx'- xs >>= \case- VWord l w -> do w' <- sDelay sym Nothing w- return $ VWord l (w' >>= \w'' -> updateWord len eltTy w'' idx' val)- VSeq l vs -> VSeq l <$> updateSeq len eltTy vs idx' val- VStream vs -> VStream <$> updateSeq len eltTy vs idx' val- _ -> evalPanic "Expected sequence value" ["updatePrim"]+ PNumPoly \len ->+ PTyPoly \eltTy ->+ PTyPoly \ix ->+ PFun \xs ->+ PFun \idx ->+ PFun \val ->+ PPrim+ do idx' <- asIndex sym "update" ix =<< idx+ assertIndexInBounds sym len idx'+ xs >>= \case+ VWord l w -> do w' <- sDelay sym w+ return $ VWord l (w' >>= \w'' -> updateWord len eltTy w'' idx' val)+ VSeq l vs -> VSeq l <$> updateSeq len eltTy vs idx' val+ VStream vs -> VStream <$> updateSeq len eltTy vs idx' val+ _ -> evalPanic "Expected sequence value" ["updatePrim"] {-# INLINE fromToV #-} -- @[ 0 .. 10 ]@-fromToV :: Backend sym => sym -> GenValue sym+fromToV :: Backend sym => sym -> Prim sym fromToV sym =- nlam $ \ first ->- nlam $ \ lst ->- tlam $ \ ty ->+ PNumPoly \first ->+ PNumPoly \lst ->+ PTyPoly \ty ->+ PVal let !f = mkLit sym ty in case (first, lst) of (Nat first', Nat lst') ->@@ -1529,16 +1581,32 @@ in VSeq len $ IndexSeqMap $ \i -> f (first' + i) _ -> evalPanic "fromToV" ["invalid arguments"] +{-# INLINE fromToLessThanV #-}++-- @[ 0 .. <10 ]@+fromToLessThanV :: Backend sym => sym -> Prim sym+fromToLessThanV sym =+ PFinPoly \first ->+ PNumPoly \bound ->+ PTyPoly \ty ->+ PVal+ let !f = mkLit sym ty+ ss = IndexSeqMap $ \i -> f (first + i)+ in case bound of+ Inf -> VStream ss+ Nat bound' -> VSeq (bound' - first) ss+ {-# INLINE fromThenToV #-} -- @[ 0, 1 .. 10 ]@-fromThenToV :: Backend sym => sym -> GenValue sym+fromThenToV :: Backend sym => sym -> Prim sym fromThenToV sym =- nlam $ \ first ->- nlam $ \ next ->- nlam $ \ lst ->- tlam $ \ ty ->- nlam $ \ len ->+ PNumPoly \first ->+ PNumPoly \next ->+ PNumPoly \lst ->+ PTyPoly \ty ->+ PNumPoly \len ->+ PVal let !f = mkLit sym ty in case (first, next, lst, len) of (Nat first', Nat next', Nat _lst', Nat len') ->@@ -1547,31 +1615,33 @@ _ -> evalPanic "fromThenToV" ["invalid arguments"] {-# INLINE infFromV #-}-infFromV :: Backend sym => sym -> GenValue sym+infFromV :: Backend sym => sym -> Prim sym infFromV sym =- tlam $ \ ty ->- lam $ \ x ->- do mx <- sDelay sym Nothing x- return $ VStream $ IndexSeqMap $ \i ->- do x' <- mx- i' <- integerLit sym i- addV sym ty x' =<< intV sym i' ty+ PTyPoly \ty ->+ PFun \x ->+ PPrim+ do mx <- sDelay sym x+ return $ VStream $ IndexSeqMap $ \i ->+ do x' <- mx+ i' <- integerLit sym i+ addV sym ty x' =<< intV sym i' ty {-# INLINE infFromThenV #-}-infFromThenV :: Backend sym => sym -> GenValue sym+infFromThenV :: Backend sym => sym -> Prim sym infFromThenV sym =- tlam $ \ ty ->- lam $ \ first -> return $- lam $ \ next ->- do mxd <- sDelay sym Nothing- (do x <- first- y <- next- d <- subV sym ty y x- pure (x,d))- return $ VStream $ IndexSeqMap $ \i -> do- (x,d) <- mxd- i' <- integerLit sym i- addV sym ty x =<< mulV sym ty d =<< intV sym i' ty+ PTyPoly \ty ->+ PFun \first ->+ PFun \next ->+ PPrim+ do mxd <- sDelay sym+ (do x <- first+ y <- next+ d <- subV sym ty y x+ pure (x,d))+ return $ VStream $ IndexSeqMap $ \i -> do+ (x,d) <- mxd+ i' <- integerLit sym i+ addV sym ty x =<< mulV sym ty d =<< intV sym i' ty -- Shifting --------------------------------------------------- @@ -1596,7 +1666,7 @@ | otherwise = do x_shft <- shift_op x (2 ^ length bs)- x' <- memoMap (mergeSeqMap sym b x_shft x)+ x' <- memoMap sym (mergeSeqMap sym b x_shft x) go x' bs {-# INLINE shiftLeftReindex #-}@@ -1670,13 +1740,14 @@ {- ^ reindexing operation for positive indices (sequence size, starting index, shift amount -} -> (Nat' -> Integer -> Integer -> Maybe Integer) {- ^ reindexing operation for negative indices (sequence size, starting index, shift amount -} ->- GenValue sym+ Prim sym logicShift sym nm shrinkRange wopPos wopNeg reindexPos reindexNeg =- nlam $ \m ->- tlam $ \ix ->- tlam $ \a ->- VFun $ \xs -> return $- VFun $ \y ->+ PNumPoly \m ->+ PTyPoly \ix ->+ PTyPoly \a ->+ PFun \xs ->+ PFun \y ->+ PPrim do xs' <- xs y' <- asIndex sym "shift" ix =<< y case y' of@@ -1701,7 +1772,7 @@ SEval sym (GenValue sym) intShifter sym nm wop reindex m ix a xs idx = do let shiftOp vs shft =- memoMap $ IndexSeqMap $ \i ->+ memoMap sym $ IndexSeqMap $ \i -> case reindex m i shft of Nothing -> zeroV sym a Just i' -> lookupSeqMap vs i'@@ -1737,7 +1808,7 @@ SEval sym (GenValue sym) wordShifter sym nm wop reindex m a xs idx = let shiftOp vs shft =- memoMap $ IndexSeqMap $ \i ->+ memoMap sym $ IndexSeqMap $ \i -> case reindex m i shft of Nothing -> zeroV sym a Just i' -> lookupSeqMap vs i'@@ -1789,37 +1860,38 @@ TValue -> String -> SEval sym (GenValue sym)-errorV sym ty msg = case ty of- -- bits- TVBit -> cryUserError sym msg- TVInteger -> cryUserError sym msg- TVIntMod _ -> cryUserError sym msg- TVRational -> cryUserError sym msg- TVArray{} -> cryUserError sym msg- TVFloat {} -> cryUserError sym msg+errorV sym ty0 msg =+ do stk <- sGetCallStack sym+ loop stk ty0+ where+ err stk = sWithCallStack sym stk (cryUserError sym msg) - -- sequences- TVSeq w ety- | isTBit ety -> return $ VWord w $ return $ LargeBitsVal w $ IndexSeqMap $ \_ -> cryUserError sym msg- | otherwise -> return $ VSeq w (IndexSeqMap $ \_ -> errorV sym ety msg)+ loop stk = \case+ TVBit -> err stk+ TVInteger -> err stk+ TVIntMod _ -> err stk+ TVRational -> err stk+ TVArray{} -> err stk+ TVFloat {} -> err stk - TVStream ety ->- return $ VStream (IndexSeqMap $ \_ -> errorV sym ety msg)+ -- sequences+ TVSeq w ety+ | isTBit ety -> return $ VWord w $ return $ LargeBitsVal w $ IndexSeqMap $ \_ -> err stk+ | otherwise -> return $ VSeq w $ IndexSeqMap $ \_ -> loop stk ety - -- functions- TVFun _ bty ->- return $ lam (\ _ -> errorV sym bty msg)+ TVStream ety -> return $ VStream $ IndexSeqMap $ \_ -> loop stk ety - -- tuples- TVTuple tys ->- return $ VTuple (map (\t -> errorV sym t msg) tys)+ -- functions+ TVFun _ bty -> lam sym (\ _ -> loop stk bty) - -- records- TVRec fields ->- return $ VRecord $ fmap (\t -> errorV sym t msg) $ fields+ -- tuples+ TVTuple tys -> return $ VTuple (map (\t -> loop stk t) tys) - TVAbstract {} -> cryUserError sym msg+ -- records+ TVRec fields -> return $ VRecord $ fmap (\t -> loop stk t) $ fields + TVAbstract {} -> err stk+ TVNewtype {} -> err stk {-# INLINE valueToChar #-} @@ -1862,7 +1934,7 @@ mergeWord sym c (WordVal w1) (WordVal w2) = WordVal <$> iteWord sym c w1 w2 mergeWord sym c w1 w2 =- LargeBitsVal (wordValueSize sym w1) <$> memoMap (mergeSeqMap sym c (asBitsMap sym w1) (asBitsMap sym w2))+ LargeBitsVal (wordValueSize sym w1) <$> memoMap sym (mergeSeqMap sym c (asBitsMap sym w1) (asBitsMap sym w2)) {-# INLINE mergeWord' #-} mergeWord' :: Backend sym =>@@ -1900,11 +1972,12 @@ (VBit b1 , VBit b2 ) -> VBit <$> iteBit sym c b1 b2 (VInteger i1 , VInteger i2 ) -> VInteger <$> iteInteger sym c i1 i2 (VRational q1, VRational q2) -> VRational <$> iteRational sym c q1 q2+ (VFloat f1 , VFloat f2) -> VFloat <$> iteFloat sym c f1 f2 (VWord n1 w1 , VWord n2 w2 ) | n1 == n2 -> pure $ VWord n1 $ mergeWord' sym c w1 w2- (VSeq n1 vs1 , VSeq n2 vs2 ) | n1 == n2 -> VSeq n1 <$> memoMap (mergeSeqMap sym c vs1 vs2)- (VStream vs1 , VStream vs2 ) -> VStream <$> memoMap (mergeSeqMap sym c vs1 vs2)- (VFun f1 , VFun f2 ) -> pure $ VFun $ \x -> mergeValue' sym c (f1 x) (f2 x)- (VPoly f1 , VPoly f2 ) -> pure $ VPoly $ \x -> mergeValue' sym c (f1 x) (f2 x)+ (VSeq n1 vs1 , VSeq n2 vs2 ) | n1 == n2 -> VSeq n1 <$> memoMap sym (mergeSeqMap sym c vs1 vs2)+ (VStream vs1 , VStream vs2 ) -> VStream <$> memoMap sym (mergeSeqMap sym c vs1 vs2)+ (f1@VFun{} , f2@VFun{} ) -> lam sym $ \x -> mergeValue' sym c (fromVFun sym f1 x) (fromVFun sym f2 x)+ (f1@VPoly{} , f2@VPoly{} ) -> tlam sym $ \x -> mergeValue' sym c (fromVPoly sym f1 x) (fromVPoly sym f2 x) (_ , _ ) -> panic "Cryptol.Eval.Generic" [ "mergeValue: incompatible values" ] @@ -1921,53 +1994,55 @@ -foldlV :: Backend sym => sym -> GenValue sym+foldlV :: Backend sym => sym -> Prim sym foldlV sym =- ilam $ \_n ->- tlam $ \_a ->- tlam $ \_b ->- lam $ \f -> pure $- lam $ \z -> pure $- lam $ \v ->- v >>= \case+ PNumPoly \_n ->+ PTyPoly \_a ->+ PTyPoly \_b ->+ PFun \f ->+ PFun \z ->+ PStrict \v ->+ PPrim+ case v of VSeq n m -> go0 f z (enumerateSeqMap n m) VWord _n wv -> go0 f z . map (pure . VBit) =<< (enumerateWordValue sym =<< wv) _ -> panic "Cryptol.Eval.Generic.foldlV" ["Expected finite sequence"] where go0 _f a [] = a go0 f a bs =- do f' <- fromVFun <$> f+ do f' <- fromVFun sym <$> f go1 f' a bs go1 _f a [] = a go1 f a (b:bs) =- do f' <- fromVFun <$> (f a)+ do f' <- fromVFun sym <$> (f a) go1 f (f' b) bs -foldl'V :: Backend sym => sym -> GenValue sym+foldl'V :: Backend sym => sym -> Prim sym foldl'V sym =- ilam $ \_n ->- tlam $ \_a ->- tlam $ \_b ->- lam $ \f -> pure $- lam $ \z -> pure $- lam $ \v ->- v >>= \case+ PNumPoly \_n ->+ PTyPoly \_a ->+ PTyPoly \_b ->+ PFun \f ->+ PFun \z ->+ PStrict \v ->+ PPrim+ case v of VSeq n m -> go0 f z (enumerateSeqMap n m) VWord _n wv -> go0 f z . map (pure . VBit) =<< (enumerateWordValue sym =<< wv) _ -> panic "Cryptol.Eval.Generic.foldlV" ["Expected finite sequence"] where go0 _f a [] = a go0 f a bs =- do f' <- fromVFun <$> f- a' <- sDelay sym Nothing a+ do f' <- fromVFun sym <$> f+ a' <- sDelay sym a forceValue =<< a' go1 f' a' bs go1 _f a [] = a go1 f a (b:bs) =- do f' <- fromVFun <$> (f a)- a' <- sDelay sym Nothing (f' b)+ do f' <- fromVFun sym <$> (f a)+ a' <- sDelay sym (f' b) forceValue =<< a' go1 f a' bs @@ -1994,14 +2069,15 @@ -------------------------------------------------------------------------------- -- Experimental parallel primitives -parmapV :: Backend sym => sym -> GenValue sym+parmapV :: Backend sym => sym -> Prim sym parmapV sym =- tlam $ \_a ->- tlam $ \_b ->- ilam $ \_n ->- lam $ \f -> pure $- lam $ \xs ->- do f' <- fromVFun <$> f+ PTyPoly \_a ->+ PTyPoly \_b ->+ PFinPoly \_n ->+ PFun \f ->+ PFun \xs ->+ PPrim+ do f' <- fromVFun sym <$> f xs' <- xs case xs' of VWord n w ->@@ -2022,25 +2098,35 @@ SeqMap sym -> SEval sym (SeqMap sym) sparkParMap sym f n m =- finiteSeqMap sym <$> mapM (sSpark sym . g) (enumerateSeqMap n m)+ finiteSeqMap <$> mapM (sSpark sym . g) (enumerateSeqMap n m) where g x =- do z <- sDelay sym Nothing (f x)+ do z <- sDelay sym (f x) forceValue =<< z z -------------------------------------------------------------------------------- -- Floating Point Operations +-- | A helper for definitng floating point constants.+fpConst ::+ Backend sym =>+ (Integer -> Integer -> SEval sym (SFloat sym)) ->+ Prim sym+fpConst mk =+ PFinPoly \e ->+ PNumPoly \ ~(Nat p) ->+ PPrim (VFloat <$> mk e p)+ -- | Make a Cryptol value for a binary arithmetic function.-fpBinArithV :: Backend sym => sym -> FPArith2 sym -> GenValue sym+fpBinArithV :: Backend sym => sym -> FPArith2 sym -> Prim sym fpBinArithV sym fun =- ilam \_ ->- ilam \_ ->- wlam sym \r ->- pure $ flam \x ->- pure $ flam \y ->- VFloat <$> fun sym r x y+ PFinPoly \_e ->+ PFinPoly \_p ->+ PWordFun \r ->+ PFloatFun \x ->+ PFloatFun \y ->+ PPrim (VFloat <$> fun sym r x y) -- | Rounding mode used in FP operations that do not specify it explicitly. fpRndMode, fpRndRNE, fpRndRNA, fpRndRTP, fpRndRTN, fpRndRTZ ::@@ -2051,3 +2137,266 @@ fpRndRTP sym = wordLit sym 3 2 {- to +inf -} fpRndRTN sym = wordLit sym 3 3 {- to -inf -} fpRndRTZ sym = wordLit sym 3 4 {- to 0 -}+++{-# SPECIALIZE genericFloatTable :: Concrete -> Map PrimIdent (Prim Concrete) #-}++genericFloatTable :: Backend sym => sym -> Map PrimIdent (Prim sym)+genericFloatTable sym =+ let (~>) = (,) in+ Map.fromList $ map (\(n, v) -> (floatPrim n, v))+ [ "fpNaN" ~> fpConst (fpNaN sym)+ , "fpPosInf" ~> fpConst (fpPosInf sym)+ , "fpFromBits" ~> PFinPoly \e -> PFinPoly \p -> PWordFun \w ->+ PPrim (VFloat <$> fpFromBits sym e p w)+ , "fpToBits" ~> PFinPoly \e -> PFinPoly \p -> PFloatFun \x -> PVal+ $ VWord (e+p)+ $ WordVal <$> fpToBits sym x+ , "=.=" ~> PFinPoly \_ -> PFinPoly \_ -> PFloatFun \x -> PFloatFun \y ->+ PPrim (VBit <$> fpLogicalEq sym x y)++ , "fpIsNaN" ~> PFinPoly \_ -> PFinPoly \_ -> PFloatFun \x ->+ PPrim (VBit <$> fpIsNaN sym x)+ , "fpIsInf" ~> PFinPoly \_ -> PFinPoly \_ -> PFloatFun \x ->+ PPrim (VBit <$> fpIsInf sym x)+ , "fpIsZero" ~> PFinPoly \_ -> PFinPoly \_ -> PFloatFun \x ->+ PPrim (VBit <$> fpIsZero sym x)+ , "fpIsNeg" ~> PFinPoly \_ -> PFinPoly \_ -> PFloatFun \x ->+ PPrim (VBit <$> fpIsNeg sym x)+ , "fpIsNormal" ~> PFinPoly \_ -> PFinPoly \_ -> PFloatFun \x ->+ PPrim (VBit <$> fpIsNorm sym x)+ , "fpIsSubnormal" ~> PFinPoly \_ -> PFinPoly \_ -> PFloatFun \x ->+ PPrim (VBit <$> fpIsSubnorm sym x)++ , "fpAdd" ~> fpBinArithV sym fpPlus+ , "fpSub" ~> fpBinArithV sym fpMinus+ , "fpMul" ~> fpBinArithV sym fpMult+ , "fpDiv" ~> fpBinArithV sym fpDiv+ , "fpFMA" ~> PFinPoly \_ -> PFinPoly \_ -> PWordFun \r ->+ PFloatFun \x -> PFloatFun \y -> PFloatFun \z ->+ PPrim (VFloat <$> fpFMA sym r x y z)++ , "fpAbs" ~> PFinPoly \_ -> PFinPoly \_ ->+ PFloatFun \x ->+ PPrim (VFloat <$> fpAbs sym x)++ , "fpSqrt" ~> PFinPoly \_ -> PFinPoly \_ ->+ PWordFun \r -> PFloatFun \x ->+ PPrim (VFloat <$> fpSqrt sym r x)++ , "fpToRational" ~>+ PFinPoly \_e -> PFinPoly \_p -> PFloatFun \x ->+ PPrim (VRational <$> fpToRational sym x)++ , "fpFromRational" ~>+ PFinPoly \e -> PFinPoly \p -> PWordFun \r -> PFun \x ->+ PPrim+ do rat <- fromVRational <$> x+ VFloat <$> fpFromRational sym e p r rat++ ]+++{-# SPECIALIZE genericPrimTable :: Concrete -> IO EvalOpts -> Map PrimIdent (Prim Concrete) #-}++genericPrimTable :: Backend sym => sym -> IO EvalOpts -> Map PrimIdent (Prim sym)+genericPrimTable sym getEOpts =+ Map.fromList $ map (\(n, v) -> (prelPrim n, v))++ [ -- Literals+ ("True" , PVal $ VBit (bitLit sym True))+ , ("False" , PVal $ VBit (bitLit sym False))+ , ("number" , {-# SCC "Prelude::number" #-}+ ecNumberV sym)+ , ("ratio" , {-# SCC "Prelude::ratio" #-}+ ratioV sym)+ , ("fraction" , ecFractionV sym)++ -- Zero+ , ("zero" , {-# SCC "Prelude::zero" #-}+ PTyPoly \ty ->+ PPrim (zeroV sym ty))++ -- Logic+ , ("&&" , {-# SCC "Prelude::(&&)" #-}+ binary (andV sym))+ , ("||" , {-# SCC "Prelude::(||)" #-}+ binary (orV sym))+ , ("^" , {-# SCC "Prelude::(^)" #-}+ binary (xorV sym))+ , ("complement" , {-# SCC "Prelude::complement" #-}+ unary (complementV sym))++ -- Ring+ , ("fromInteger", {-# SCC "Prelude::fromInteger" #-}+ fromIntegerV sym)+ , ("+" , {-# SCC "Prelude::(+)" #-}+ binary (addV sym))+ , ("-" , {-# SCC "Prelude::(-)" #-}+ binary (subV sym))+ , ("*" , {-# SCC "Prelude::(*)" #-}+ binary (mulV sym))+ , ("negate" , {-# SCC "Prelude::negate" #-}+ unary (negateV sym))++ -- Integral+ , ("toInteger" , {-# SCC "Prelude::toInteger" #-}+ toIntegerV sym)+ , ("/" , {-# SCC "Prelude::(/)" #-}+ binary (divV sym))+ , ("%" , {-# SCC "Prelude::(%)" #-}+ binary (modV sym))+ , ("^^" , {-# SCC "Prelude::(^^)" #-}+ expV sym)+ , ("infFrom" , {-# SCC "Prelude::infFrom" #-}+ infFromV sym)+ , ("infFromThen", {-# SCC "Prelude::infFromThen" #-}+ infFromThenV sym)++ -- Field+ , ("recip" , {-# SCC "Prelude::recip" #-}+ recipV sym)+ , ("/." , {-# SCC "Prelude::(/.)" #-}+ fieldDivideV sym)++ -- Round+ , ("floor" , {-# SCC "Prelude::floor" #-}+ unary (floorV sym))+ , ("ceiling" , {-# SCC "Prelude::ceiling" #-}+ unary (ceilingV sym))+ , ("trunc" , {-# SCC "Prelude::trunc" #-}+ unary (truncV sym))+ , ("roundAway" , {-# SCC "Prelude::roundAway" #-}+ unary (roundAwayV sym))+ , ("roundToEven", {-# SCC "Prelude::roundToEven" #-}+ unary (roundToEvenV sym))++ -- Bitvector specific operations+ , ("/$" , {-# SCC "Prelude::(/$)" #-}+ sdivV sym)+ , ("%$" , {-# SCC "Prelude::(%$)" #-}+ smodV sym)+ , ("lg2" , {-# SCC "Prelude::lg2" #-}+ lg2V sym)++ -- Cmp+ , ("<" , {-# SCC "Prelude::(<)" #-}+ binary (lessThanV sym))+ , (">" , {-# SCC "Prelude::(>)" #-}+ binary (greaterThanV sym))+ , ("<=" , {-# SCC "Prelude::(<=)" #-}+ binary (lessThanEqV sym))+ , (">=" , {-# SCC "Prelude::(>=)" #-}+ binary (greaterThanEqV sym))+ , ("==" , {-# SCC "Prelude::(==)" #-}+ binary (eqV sym))+ , ("!=" , {-# SCC "Prelude::(!=)" #-}+ binary (distinctV sym))++ -- SignedCmp+ , ("<$" , {-# SCC "Prelude::(<$)" #-}+ binary (signedLessThanV sym))++ -- Finite enumerations+ , ("fromTo" , {-# SCC "Prelude::fromTo" #-}+ fromToV sym)++ , ("fromThenTo" , {-# SCC "Prelude::fromThenTo" #-}+ fromThenToV sym)++ , ("fromToLessThan"+ , {-# SCC "Prelude::fromToLessThan" #-}+ fromToLessThanV sym)++ -- Sequence manipulations+ , ("#" , {-# SCC "Prelude::(#)" #-}+ PFinPoly \front ->+ PNumPoly \back ->+ PTyPoly \elty ->+ PFun \l ->+ PFun \r ->+ PPrim (join (ccatV sym (Nat front) back elty <$> l <*> r)))++ , ("join" , {-# SCC "Prelude::join" #-}+ PNumPoly \parts ->+ PFinPoly \each ->+ PTyPoly \a ->+ PStrict \x ->+ PPrim $ joinV sym parts each a x)++ , ("split" , {-# SCC "Prelude::split" #-}+ ecSplitV sym)++ , ("splitAt" , {-# SCC "Prelude::splitAt" #-}+ PNumPoly \front ->+ PNumPoly \back ->+ PTyPoly \a ->+ PStrict \x ->+ PPrim $ splitAtV sym front back a x)++ , ("reverse" , {-# SCC "Prelude::reverse" #-}+ PFinPoly \_a ->+ PTyPoly \_b ->+ PStrict \xs ->+ PPrim $ reverseV sym xs)++ , ("transpose" , {-# SCC "Prelude::transpose" #-}+ PNumPoly \a ->+ PNumPoly \b ->+ PTyPoly \c ->+ PStrict \xs ->+ PPrim $ transposeV sym a b c xs)++ -- Misc++ -- {at,len} (fin len) => [len][8] -> at+ , ("error" , {-# SCC "Prelude::error" #-}+ PTyPoly \a ->+ PFinPoly \_ ->+ PStrict \s ->+ PPrim (errorV sym a =<< valueToString sym s))++ , ("trace" , {-# SCC "Prelude::trace" #-}+ PNumPoly \_n ->+ PTyPoly \_a ->+ PTyPoly \_b ->+ PFun \s ->+ PFun \x ->+ PFun \y ->+ PPrim+ do msg <- valueToString sym =<< s+ EvalOpts { evalPPOpts, evalLogger } <- liftIO getEOpts+ doc <- ppValue sym evalPPOpts =<< x+ liftIO $ logPrint evalLogger+ $ if null msg then doc else text msg <+> doc+ y)++ , ("random" , {-# SCC "Prelude::random" #-}+ PTyPoly \a ->+ PWordFun \x ->+ PPrim+ case wordAsLit sym x of+ Just (_,i) -> randomV sym a i+ Nothing -> liftIO (X.throw (UnsupportedSymbolicOp "random")))++ , ("foldl" , {-# SCC "Prelude::foldl" #-}+ foldlV sym)++ , ("foldl'" , {-# SCC "Prelude::foldl'" #-}+ foldl'V sym)++ , ("deepseq" , {-# SCC "Prelude::deepseq" #-}+ PTyPoly \_a ->+ PTyPoly \_b ->+ PFun \x ->+ PFun \y ->+ PPrim do _ <- forceValue =<< x+ y)++ , ("parmap" , {-# SCC "Prelude::parmap" #-}+ parmapV sym)++ , ("fromZ" , {-# SCC "Prelude::fromZ" #-}+ fromZV sym)++ ]
+ src/Cryptol/Eval/Prims.hs view
@@ -0,0 +1,39 @@+{-# LANGUAGE ImplicitParams #-}+{-# LANGUAGE LambdaCase #-}+module Cryptol.Eval.Prims where++import Cryptol.Backend+import Cryptol.Eval.Type+import Cryptol.Eval.Value+import Cryptol.ModuleSystem.Name+import Cryptol.TypeCheck.Solver.InfNat(Nat'(..))+import Cryptol.Utils.Panic++-- | This type provides a lightweight syntactic framework for defining+-- Cryptol primitives. The main purpose of this type is to provide+-- an abstraction barrier that insulates the definitions of primitives+-- from possible changes in the representation of values.+data Prim sym+ = PFun (SEval sym (GenValue sym) -> Prim sym)+ | PStrict (GenValue sym -> Prim sym)+ | PWordFun (SWord sym -> Prim sym)+ | PFloatFun (SFloat sym -> Prim sym)+ | PTyPoly (TValue -> Prim sym)+ | PNumPoly (Nat' -> Prim sym)+ | PFinPoly (Integer -> Prim sym)+ | PPrim (SEval sym (GenValue sym))+ | PVal (GenValue sym)++-- | Evaluate a primitive into a value computation+evalPrim :: Backend sym => sym -> Name -> Prim sym -> SEval sym (GenValue sym)+evalPrim sym nm p = case p of+ PFun f -> lam sym (evalPrim sym nm . f)+ PStrict f -> lam sym (\x -> evalPrim sym nm . f =<< x)+ PWordFun f -> lam sym (\x -> evalPrim sym nm . f =<< (fromVWord sym (show nm) =<< x))+ PFloatFun f -> flam sym (evalPrim sym nm . f)+ PTyPoly f -> tlam sym (evalPrim sym nm . f)+ PNumPoly f -> nlam sym (evalPrim sym nm . f)+ PFinPoly f -> nlam sym (\case Inf -> panic "PFin" ["Unexpected `inf`", show nm];+ Nat n -> evalPrim sym nm (f n))+ PPrim m -> m+ PVal v -> pure v
src/Cryptol/Eval/Reference.lhs view
@@ -28,7 +28,6 @@ > import Data.Ord (comparing) > import Data.Map (Map) > import qualified Data.Map as Map-> import qualified Data.IntMap as IntMap > import qualified Data.Text as T (pack) > import LibBF (BigFloat) > import qualified LibBF as FP@@ -39,8 +38,9 @@ > import Cryptol.TypeCheck.AST > import Cryptol.Backend.FloatHelpers (BF(..)) > import qualified Cryptol.Backend.FloatHelpers as FP-> import Cryptol.Backend.Monad (EvalError(..), PPOpts(..))-> import Cryptol.Eval.Type (TValue(..), isTBit, evalValType, evalNumType, TypeEnv)+> import Cryptol.Backend.Monad (EvalError(..))+> import Cryptol.Eval.Type+> (TValue(..), isTBit, evalValType, evalNumType, TypeEnv, bindTypeVar) > import Cryptol.Eval.Concrete (mkBv, ppBV, lg2) > import Cryptol.Utils.Ident (Ident,PrimIdent, prelPrim, floatPrim) > import Cryptol.Utils.Panic (panic)@@ -48,7 +48,7 @@ > import Cryptol.Utils.RecordMap > > import qualified Cryptol.ModuleSystem as M-> import qualified Cryptol.ModuleSystem.Env as M (loadedModules)+> import qualified Cryptol.ModuleSystem.Env as M (loadedModules,loadedNewtypes) Overview ========@@ -250,14 +250,14 @@ > > instance Semigroup Env where > l <> r = Env-> { envVars = Map.union (envVars l) (envVars r)-> , envTypes = IntMap.union (envTypes l) (envTypes r)+> { envVars = envVars l <> envVars r+> , envTypes = envTypes l <> envTypes r > } > > instance Monoid Env where > mempty = Env-> { envVars = Map.empty-> , envTypes = IntMap.empty+> { envVars = mempty+> , envTypes = mempty > } > mappend l r = l <> r >@@ -267,7 +267,7 @@ > > -- | Bind a type variable of kind # or *. > bindType :: TVar -> Either Nat' TValue -> Env -> Env-> bindType p ty env = env { envTypes = IntMap.insert (tvUnique p) ty (envTypes env) }+> bindType p ty env = env { envTypes = bindTypeVar p ty (envTypes env) } Evaluation@@ -284,6 +284,8 @@ > evalExpr env expr = > case expr of >+> ELocated _ e -> evalExpr env e+> > EList es _ty -> > pure $ VList (Nat (genericLength es)) [ evalExpr env e | e <- es ] >@@ -340,13 +342,15 @@ --------- Apply the the given selector form to the given value.+Note that record selectors work uniformly on both record+types and on newtypes. > evalSel :: Selector -> Value -> E Value > evalSel sel val = > case sel of > TupleSel n _ -> tupleSel n val > RecordSel n _ -> recordSel n val-> ListSel n _ -> listSel n val+> ListSel n _ -> listSel n val > where > tupleSel n v = > case v of@@ -366,12 +370,15 @@ Update the given value using the given selector and new value.+Note that record selectors work uniformly on both record+types and on newtypes. > evalSet :: TValue -> E Value -> Selector -> E Value -> E Value > evalSet tyv val sel fval = > case (tyv, sel) of > (TVTuple ts, TupleSel n _) -> updTupleAt ts n > (TVRec fs, RecordSel n _) -> updRecAt fs n+> (TVNewtype _ _ fs, RecordSel n _) -> updRecAt fs n > (TVSeq len _, ListSel n _) -> updSeqAt len n > (_, _) -> evalPanic "evalSet" ["type/selector mismatch", show tyv, show sel] > where@@ -463,7 +470,8 @@ > -> Expr -- ^ Head expression of the comprehension > -> [[Match]] -- ^ List of parallel comprehension branches > -> E Value-> evalComp env expr branches = pure $ VList len [ evalExpr e expr | e <- envs ]+> evalComp env expr branches =+> pure $ VList len [ evalExpr e expr | e <- envs ] > where > -- Generate a new environment for each iteration of each > -- parallel branch.@@ -504,8 +512,27 @@ > case dDefinition d of > DPrim -> (dName d, pure (evalPrim (dName d))) > DExpr e -> (dName d, evalExpr env e)+> +Newtypes+-------- +At runtime, newtypes values are represented in exactly+the same way as records. The constructor function for+newtypes is thus basically just an identity function+that consumes and ignores its type arguments.++> evalNewtypeDecl :: Env -> Newtype -> Env+> evalNewtypeDecl env nt = bindVar (ntName nt, pure val) env +> where+> val = foldr tabs con (ntParams nt)+> con = VFun (\x -> x)+> tabs tp body =+> case tpKind tp of+> KType -> VPoly (\_ -> pure body)+> KNum -> VNumPoly (\_ -> pure body)+> k -> evalPanic "evalNewtypeDecl" ["illegal newtype parameter kind", show k]+ Primitives ========== @@ -909,7 +936,7 @@ > | (f, fty) <- canonicalFields fields ] > zero (TVFun _ bty) = VFun (\_ -> pure (zero bty)) > zero (TVAbstract{}) = evalPanic "zero" ["Abstract type not in `Zero`"]-+> zero (TVNewtype{}) = evalPanic "zero" ["Newtype not in `Zero`"] Literals --------@@ -978,6 +1005,7 @@ > TVRational -> evalPanic "logicUnary" ["Rational not in class Logic"] > TVFloat{} -> evalPanic "logicUnary" ["Float not in class Logic"] > TVAbstract{} -> evalPanic "logicUnary" ["Abstract type not in `Logic`"]+> TVNewtype{} -> evalPanic "logicUnary" ["Newtype not in `Logic`"] > logicBinary :: (Bool -> Bool -> Bool) -> TValue -> E Value -> E Value -> E Value > logicBinary op = go@@ -1016,6 +1044,7 @@ > TVRational -> evalPanic "logicBinary" ["Rational not in class Logic"] > TVFloat{} -> evalPanic "logicBinary" ["Float not in class Logic"] > TVAbstract{} -> evalPanic "logicBinary" ["Abstract type not in `Logic`"]+> TVNewtype{} -> evalPanic "logicBinary" ["Newtype not in `Logic`"] Ring Arithmetic@@ -1063,6 +1092,8 @@ > pure $ VRecord [ (f, go fty) | (f, fty) <- canonicalFields fs ] > TVAbstract {} -> > evalPanic "arithNullary" ["Abstract type not in `Ring`"]+> TVNewtype {} ->+> evalPanic "arithNullary" ["Newtype type not in `Ring`"] > ringUnary :: > (Integer -> E Integer) ->@@ -1101,6 +1132,8 @@ > | (f, fty) <- canonicalFields fs ] > TVAbstract {} -> > evalPanic "arithUnary" ["Abstract type not in `Ring`"]+> TVNewtype {} ->+> evalPanic "arithUnary" ["Newtype not in `Ring`"] > ringBinary :: > (Integer -> Integer -> E Integer) ->@@ -1149,6 +1182,8 @@ > | (f, fty) <- canonicalFields fs ] > TVAbstract {} -> > evalPanic "arithBinary" ["Abstract type not in class `Ring`"]+> TVNewtype {} ->+> evalPanic "arithBinary" ["Newtype not in class `Ring`"] Integral@@ -1325,6 +1360,8 @@ > lexList (zipWith3 lexCompare tys ls rs) > TVAbstract {} -> > evalPanic "lexCompare" ["Abstract type not in `Cmp`"]+> TVNewtype {} ->+> evalPanic "lexCompare" ["Newtype not in `Cmp`"] > > lexList :: [E Ordering] -> E Ordering > lexList [] = pure EQ@@ -1379,6 +1416,8 @@ > lexList (zipWith3 lexSignedCompare tys ls rs) > TVAbstract {} -> > evalPanic "lexSignedCompare" ["Abstract type not in `Cmp`"]+> TVNewtype {} ->+> evalPanic "lexSignedCompare" ["Newtype type not in `Cmp`"] Sequences@@ -1690,7 +1729,10 @@ running the reference evaluator on an expression. > evaluate :: Expr -> M.ModuleCmd (E Value)-> evaluate expr (_, _, modEnv) = return (Right (evalExpr env expr, modEnv), [])+> evaluate expr minp = return (Right (val, modEnv), []) > where+> modEnv = M.minpModuleEnv minp > extDgs = concatMap mDecls (M.loadedModules modEnv)-> env = foldl evalDeclGroup mempty extDgs+> nts = Map.elems (M.loadedNewtypes modEnv)+> env = foldl evalDeclGroup (foldl evalNewtypeDecl mempty nts) extDgs+> val = evalExpr env expr
src/Cryptol/Eval/SBV.hs view
@@ -6,6 +6,7 @@ -- Stability : provisional -- Portability : portable +{-# LANGUAGE BlockArguments #-} {-# LANGUAGE DeriveFunctor #-} {-# LANGUAGE FlexibleInstances #-} {-# LANGUAGE GeneralizedNewtypeDeriving #-}@@ -21,7 +22,6 @@ ) where import qualified Control.Exception as X-import Control.Monad (join) import Control.Monad.IO.Class (MonadIO(..)) import Data.Bits (bit, shiftL) import qualified Data.Map as Map@@ -33,8 +33,9 @@ import Cryptol.Backend.Monad ( EvalError(..), Unsupported(..) ) import Cryptol.Backend.SBV -import Cryptol.Eval.Type (TValue(..), finNat')+import Cryptol.Eval.Type (TValue(..)) import Cryptol.Eval.Generic+import Cryptol.Eval.Prims import Cryptol.Eval.Value import Cryptol.TypeCheck.Solver.InfNat (Nat'(..), widthInteger) import Cryptol.Utils.Ident@@ -46,106 +47,12 @@ -- Primitives ------------------------------------------------------------------ -- See also Cryptol.Eval.Concrete.primTable-primTable :: SBV -> Map.Map PrimIdent Value-primTable sym =+primTable :: SBV -> IO EvalOpts -> Map.Map PrimIdent (Prim SBV)+primTable sym getEOpts =+ Map.union (genericPrimTable sym getEOpts) $ Map.fromList $ map (\(n, v) -> (prelPrim (T.pack n), v)) - [ -- Literals- ("True" , VBit (bitLit sym True))- , ("False" , VBit (bitLit sym False))- , ("number" , ecNumberV sym) -- Converts a numeric type into its corresponding value.- -- { val, rep } (Literal val rep) => rep- , ("fraction" , ecFractionV sym)- , ("ratio" , ratioV sym)-- -- Zero- , ("zero" , VPoly (zeroV sym))-- -- Logic- , ("&&" , binary (andV sym))- , ("||" , binary (orV sym))- , ("^" , binary (xorV sym))- , ("complement" , unary (complementV sym))-- -- Ring- , ("fromInteger" , fromIntegerV sym)- , ("+" , binary (addV sym))- , ("-" , binary (subV sym))- , ("negate" , unary (negateV sym))- , ("*" , binary (mulV sym))-- -- Integral- , ("toInteger" , toIntegerV sym)- , ("/" , binary (divV sym))- , ("%" , binary (modV sym))- , ("^^" , expV sym)- , ("infFrom" , infFromV sym)- , ("infFromThen" , infFromThenV sym)-- -- Field- , ("recip" , recipV sym)- , ("/." , fieldDivideV sym)-- -- Round- , ("floor" , unary (floorV sym))- , ("ceiling" , unary (ceilingV sym))- , ("trunc" , unary (truncV sym))- , ("roundAway" , unary (roundAwayV sym))- , ("roundToEven" , unary (roundToEvenV sym))-- -- Word operations- , ("/$" , sdivV sym)- , ("%$" , smodV sym)- , ("lg2" , lg2V sym)- , (">>$" , sshrV sym)-- -- Cmp- , ("<" , binary (lessThanV sym))- , (">" , binary (greaterThanV sym))- , ("<=" , binary (lessThanEqV sym))- , (">=" , binary (greaterThanEqV sym))- , ("==" , binary (eqV sym))- , ("!=" , binary (distinctV sym))-- -- SignedCmp- , ("<$" , binary (signedLessThanV sym))-- -- Finite enumerations- , ("fromTo" , fromToV sym)- , ("fromThenTo" , fromThenToV sym)-- -- Sequence manipulations- , ("#" , -- {a,b,d} (fin a) => [a] d -> [b] d -> [a + b] d- nlam $ \ front ->- nlam $ \ back ->- tlam $ \ elty ->- lam $ \ l -> return $- lam $ \ r -> join (ccatV sym front back elty <$> l <*> r))-- , ("join" ,- nlam $ \ parts ->- nlam $ \ (finNat' -> each) ->- tlam $ \ a ->- lam $ \ x ->- joinV sym parts each a =<< x)-- , ("split" , ecSplitV sym)-- , ("splitAt" ,- nlam $ \ front ->- nlam $ \ back ->- tlam $ \ a ->- lam $ \ x ->- splitAtV sym front back a =<< x)-- , ("reverse" , nlam $ \_a ->- tlam $ \_b ->- lam $ \xs -> reverseV sym =<< xs)-- , ("transpose" , nlam $ \a ->- nlam $ \b ->- tlam $ \c ->- lam $ \xs -> transposeV sym a b c =<< xs)+ [ (">>$" , sshrV sym) -- Shifts and rotates , ("<<" , logicShift sym "<<"@@ -179,52 +86,8 @@ , ("update" , updatePrim sym (updateFrontSym_word sym) (updateFrontSym sym)) , ("updateEnd" , updatePrim sym (updateBackSym_word sym) (updateBackSym sym)) - -- Misc-- , ("fromZ" , fromZV sym)-- , ("foldl" , foldlV sym)- , ("foldl'" , foldl'V sym)-- , ("deepseq" ,- tlam $ \_a ->- tlam $ \_b ->- lam $ \x -> pure $- lam $ \y ->- do _ <- forceValue =<< x- y)-- , ("parmap" , parmapV sym)-- -- {at,len} (fin len) => [len][8] -> at- , ("error" ,- tlam $ \a ->- nlam $ \_ ->- VFun $ \s -> errorV sym a =<< (valueToString sym =<< s))-- , ("random" ,- tlam $ \a ->- wlam sym $ \x ->- case integerAsLit sym x of- Just i -> randomV sym a i- Nothing -> cryUserError sym "cannot evaluate 'random' with symbolic inputs")-- -- The trace function simply forces its first two- -- values before returing the third in the symbolic- -- evaluator.- , ("trace",- nlam $ \_n ->- tlam $ \_a ->- tlam $ \_b ->- lam $ \s -> return $- lam $ \x -> return $- lam $ \y -> do- _ <- s- _ <- x- y) ] - indexFront :: SBV -> Nat' ->@@ -468,13 +331,14 @@ go f (WordVal x :vs) = go (f . (x:)) vs go _f (LargeBitsVal _ _ : _) = Nothing -sshrV :: SBV -> Value+sshrV :: SBV -> Prim SBV sshrV sym =- nlam $ \n ->- tlam $ \ix ->- wlam sym $ \x -> return $- lam $ \y ->- y >>= asIndex sym ">>$" ix >>= \case+ PNumPoly \n ->+ PTyPoly \ix ->+ PWordFun \x ->+ PStrict \y ->+ PPrim $+ asIndex sym ">>$" ix y >>= \case Left idx -> do let w = toInteger (SBV.intSizeOf x) let pneg = svLessThan idx (svInteger KUnbounded 0)
src/Cryptol/Eval/Type.hs view
@@ -11,7 +11,7 @@ {-# LANGUAGE DeriveGeneric #-} module Cryptol.Eval.Type where -import Cryptol.Backend.Monad (evalPanic, typeCannotBeDemoted)+import Cryptol.Backend.Monad (evalPanic) import Cryptol.TypeCheck.AST import Cryptol.TypeCheck.PP(pp) import Cryptol.TypeCheck.Solver.InfNat@@ -38,8 +38,11 @@ | TVTuple [TValue] -- ^ @ (a, b, c )@ | TVRec (RecordMap Ident TValue) -- ^ @ { x : a, y : b, z : c } @ | TVFun TValue TValue -- ^ @ a -> b @+ | TVNewtype Newtype+ [Either Nat' TValue]+ (RecordMap Ident TValue) -- ^ a named newtype | TVAbstract UserTC [Either Nat' TValue] -- ^ an abstract type- deriving (Generic, NFData)+ deriving (Generic, NFData, Eq) -- | Convert a type value back into a regular type tValTy :: TValue -> Type@@ -56,13 +59,17 @@ TVTuple ts -> tTuple (map tValTy ts) TVRec fs -> tRec (fmap tValTy fs) TVFun t1 t2 -> tFun (tValTy t1) (tValTy t2)- TVAbstract u vs -> tAbstract u (map arg vs)- where arg x = case x of- Left Inf -> tInf- Left (Nat n) -> tNum n- Right v -> tValTy v+ TVNewtype nt vs _ -> tNewtype nt (map tNumValTy vs)+ TVAbstract u vs -> tAbstract u (map tNumValTy vs) +tNumTy :: Nat' -> Type+tNumTy Inf = tInf+tNumTy (Nat n) = tNum n +tNumValTy :: Either Nat' TValue -> Type+tNumValTy = either tNumTy tValTy++ instance Show TValue where showsPrec p v = showsPrec p (tValTy v) @@ -90,20 +97,38 @@ -- Type Evaluation ------------------------------------------------------------- -type TypeEnv = IntMap.IntMap (Either Nat' TValue)+newtype TypeEnv =+ TypeEnv+ { envTypeMap :: IntMap.IntMap (Either Nat' TValue) } +instance Monoid TypeEnv where+ mempty = TypeEnv mempty +instance Semigroup TypeEnv where+ l <> r = TypeEnv+ { envTypeMap = IntMap.union (envTypeMap l) (envTypeMap r) }++lookupTypeVar :: TVar -> TypeEnv -> Maybe (Either Nat' TValue)+lookupTypeVar tv env = IntMap.lookup (tvUnique tv) (envTypeMap env)++bindTypeVar :: TVar -> Either Nat' TValue -> TypeEnv -> TypeEnv+bindTypeVar tv ty env = env{ envTypeMap = IntMap.insert (tvUnique tv) ty (envTypeMap env) }+ -- | Evaluation for types (kind * or #). evalType :: TypeEnv -> Type -> Either Nat' TValue evalType env ty = case ty of TVar tv ->- case IntMap.lookup (tvUnique tv) env of+ case lookupTypeVar tv env of Just v -> v Nothing -> evalPanic "evalType" ["type variable not bound", show tv] TUser _ _ ty' -> evalType env ty' TRec fields -> Right $ TVRec (fmap val fields)++ TNewtype nt ts -> Right $ TVNewtype nt tvs $ evalNewtypeBody env nt tvs+ where tvs = map (evalType env) ts+ TCon (TC c) ts -> case (c, ts) of (TCBit, []) -> Right $ TVBit@@ -128,7 +153,6 @@ , "*** Name: " ++ show (pp u) ] - -- FIXME: What about TCNewtype? _ -> evalPanic "evalType" ["not a value type", show ty] TCon (TF f) ts -> Left $ evalTF f (map num ts) TCon (PC p) _ -> evalPanic "evalType" ["invalid predicate symbol", show p]@@ -142,6 +166,16 @@ Inf -> evalPanic "evalType" ["Expecting a finite size, but got `inf`"] +-- | Evaluate the body of a newtype, given evaluated arguments+evalNewtypeBody :: TypeEnv -> Newtype -> [Either Nat' TValue] -> RecordMap Ident TValue+evalNewtypeBody env0 nt args = fmap (evalValType env') (ntFields nt)+ where+ env' = loop env0 (ntParams nt) args++ loop env [] [] = env+ loop env (p:ps) (a:as) = loop (bindTypeVar (TVBound p) a env) ps as+ loop _ _ _ = evalPanic "evalNewtype" ["type parameter/argument mismatch"]+ -- | Evaluation for value types (kind *). evalValType :: TypeEnv -> Type -> TValue evalValType env ty =@@ -175,5 +209,5 @@ | otherwise = evalPanic "evalTF" ["Unexpected type function:", show ty] - where mb = fromMaybe (typeCannotBeDemoted ty)+ where mb = fromMaybe (evalPanic "evalTF" ["type cannot be demoted", show (pp ty)]) ty = TCon (TF f) (map tNat' vs)
src/Cryptol/Eval/Value.hs view
@@ -30,10 +30,11 @@ , forceValue , Backend(..) , asciiMode++ , EvalOpts(..) -- ** Value introduction operations , word , lam- , wlam , flam , tlam , nlam@@ -95,16 +96,21 @@ import Data.Bits import Data.IORef import Data.Map.Strict (Map)+import Data.Ratio import qualified Data.Map.Strict as Map import MonadLib+import Numeric (showIntAtBase) import Cryptol.Backend import qualified Cryptol.Backend.Arch as Arch-import Cryptol.Backend.Monad ( PPOpts(..), evalPanic, wordTooWide, defaultPPOpts, asciiMode )+import Cryptol.Backend.Monad+ ( evalPanic, wordTooWide, CallStack, combineCallStacks )+import Cryptol.Backend.FloatHelpers (fpPP) import Cryptol.Eval.Type import Cryptol.TypeCheck.Solver.InfNat(Nat'(..)) import Cryptol.Utils.Ident (Ident)+import Cryptol.Utils.Logger(Logger) import Cryptol.Utils.Panic(panic) import Cryptol.Utils.PP import Cryptol.Utils.RecordMap@@ -113,6 +119,12 @@ import GHC.Generics (Generic) +-- | Some options for evalutaion+data EvalOpts = EvalOpts+ { evalLogger :: Logger -- ^ Where to print stuff (e.g., for @trace@)+ , evalPPOpts :: PPOpts -- ^ How to pretty print things.+ }+ -- Values ---------------------------------------------------------------------- -- | A sequence map represents a mapping from nonnegative integer indices@@ -135,22 +147,22 @@ largeBitSize = 1 `shiftL` 48 -- | Generate a finite sequence map from a list of values-finiteSeqMap :: Backend sym => sym -> [SEval sym (GenValue sym)] -> SeqMap sym-finiteSeqMap sym xs =+finiteSeqMap :: [SEval sym (GenValue sym)] -> SeqMap sym+finiteSeqMap xs = UpdateSeqMap (Map.fromList (zip [0..] xs))- (invalidIndex sym)+ (\i -> panic "finiteSeqMap" ["Out of bounds access of finite seq map", "length: " ++ show (length xs), show i]) -- | Generate an infinite sequence map from a stream of values-infiniteSeqMap :: Backend sym => [SEval sym (GenValue sym)] -> SEval sym (SeqMap sym)-infiniteSeqMap xs =+infiniteSeqMap :: Backend sym => sym -> [SEval sym (GenValue sym)] -> SEval sym (SeqMap sym)+infiniteSeqMap sym xs = -- TODO: use an int-trie?- memoMap (IndexSeqMap $ \i -> genericIndex xs i)+ memoMap sym (IndexSeqMap $ \i -> genericIndex xs i) -- | Create a finite list of length @n@ of the values from @[0..n-1]@ in -- the given the sequence emap. enumerateSeqMap :: (Integral n) => n -> SeqMap sym -> [SEval sym (GenValue sym)]-enumerateSeqMap n m = [ lookupSeqMap m i | i <- [0 .. (toInteger n)-1] ]+enumerateSeqMap n m = [ lookupSeqMap m i | i <- [0 .. (toInteger n)-1] ] -- | Create an infinite stream of all the values in a sequence map streamSeqMap :: SeqMap sym -> [SEval sym (GenValue sym)]@@ -191,17 +203,18 @@ -- | Given a sequence map, return a new sequence map that is memoized using -- a finite map memo table.-memoMap :: (MonadIO m, Backend sym) => SeqMap sym -> m (SeqMap sym)-memoMap x = do+memoMap :: Backend sym => sym -> SeqMap sym -> SEval sym (SeqMap sym)+memoMap sym x = do+ stk <- sGetCallStack sym cache <- liftIO $ newIORef $ Map.empty- return $ IndexSeqMap (memo cache)+ return $ IndexSeqMap (memo cache stk) where- memo cache i = do+ memo cache stk i = do mz <- liftIO (Map.lookup i <$> readIORef cache) case mz of Just z -> return z- Nothing -> doEval cache i+ Nothing -> sWithCallStack sym stk (doEval cache i) doEval cache i = do v <- lookupSeqMap x i@@ -212,20 +225,22 @@ -- sequence maps. zipSeqMap :: Backend sym =>+ sym -> (GenValue sym -> GenValue sym -> SEval sym (GenValue sym)) -> SeqMap sym -> SeqMap sym -> SEval sym (SeqMap sym)-zipSeqMap f x y =- memoMap (IndexSeqMap $ \i -> join (f <$> lookupSeqMap x i <*> lookupSeqMap y i))+zipSeqMap sym f x y =+ memoMap sym (IndexSeqMap $ \i -> join (f <$> lookupSeqMap x i <*> lookupSeqMap y i)) -- | Apply the given function to each value in the given sequence map mapSeqMap :: Backend sym =>+ sym -> (GenValue sym -> SEval sym (GenValue sym)) -> SeqMap sym -> SEval sym (SeqMap sym)-mapSeqMap f x =- memoMap (IndexSeqMap $ \i -> f =<< lookupSeqMap x i)+mapSeqMap sym f x =+ memoMap sym (IndexSeqMap $ \i -> f =<< lookupSeqMap x i) -- | For efficiency reasons, we handle finite sequences of bits as special cases -- in the evaluator. In cases where we know it is safe to do so, we prefer to@@ -280,7 +295,8 @@ -- | Produce a new 'WordValue' from the one given by updating the @i@th bit with the -- given bit value.-updateWordValue :: Backend sym => sym -> WordValue sym -> Integer -> SEval sym (SBit sym) -> SEval sym (WordValue sym)+updateWordValue :: Backend sym =>+ sym -> WordValue sym -> Integer -> SEval sym (SBit sym) -> SEval sym (WordValue sym) updateWordValue sym (WordVal w) idx b | idx < 0 || idx >= wordLen sym w = invalidIndex sym idx | isReady sym b = WordVal <$> (wordUpdate sym w idx =<< b)@@ -308,9 +324,9 @@ -- Invariant: VSeq is never a sequence of bits | VWord !Integer !(SEval sym (WordValue sym)) -- ^ @ [n]Bit @ | VStream !(SeqMap sym) -- ^ @ [inf]a @- | VFun (SEval sym (GenValue sym) -> SEval sym (GenValue sym)) -- ^ functions- | VPoly (TValue -> SEval sym (GenValue sym)) -- ^ polymorphic values (kind *)- | VNumPoly (Nat' -> SEval sym (GenValue sym)) -- ^ polymorphic values (kind #)+ | VFun CallStack (SEval sym (GenValue sym) -> SEval sym (GenValue sym)) -- ^ functions+ | VPoly CallStack (TValue -> SEval sym (GenValue sym)) -- ^ polymorphic values (kind *)+ | VNumPoly CallStack (Nat' -> SEval sym (GenValue sym)) -- ^ polymorphic values (kind #) deriving Generic @@ -331,9 +347,9 @@ VFloat f -> seq f (return ()) VWord _ wv -> forceWordValue =<< wv VStream _ -> return ()- VFun _ -> return ()- VPoly _ -> return ()- VNumPoly _ -> return ()+ VFun{} -> return ()+ VPoly{} -> return ()+ VNumPoly{} -> return () @@ -348,9 +364,9 @@ VSeq n _ -> "seq:" ++ show n VWord n _ -> "word:" ++ show n VStream _ -> "stream"- VFun _ -> "fun"- VPoly _ -> "poly"- VNumPoly _ -> "numpoly"+ VFun{} -> "fun"+ VPoly{} -> "poly"+ VNumPoly{} -> "numpoly" -- Pretty Printing -------------------------------------------------------------@@ -371,10 +387,10 @@ ppField (f,r) = pp f <+> char '=' <+> r VTuple vals -> do vals' <- traverse (>>=loop) vals return $ parens (sep (punctuate comma vals'))- VBit b -> return $ ppBit x b- VInteger i -> return $ ppInteger x opts i- VRational q -> return $ ppRational x opts q- VFloat i -> return $ ppFloat x opts i+ VBit b -> ppSBit x b+ VInteger i -> ppSInteger x i+ VRational q -> ppSRational x q+ VFloat i -> ppSFloat x opts i VSeq sz vals -> ppWordSeq sz vals VWord _ wv -> ppWordVal =<< wv VStream vals -> do vals' <- traverse (>>=loop) $ enumerateSeqMap (useInfLength opts) vals@@ -382,12 +398,12 @@ $ punctuate comma ( vals' ++ [text "..."] )- VFun _ -> return $ text "<function>"- VPoly _ -> return $ text "<polymorphic value>"- VNumPoly _ -> return $ text "<polymorphic value>"+ VFun{} -> return $ text "<function>"+ VPoly{} -> return $ text "<polymorphic value>"+ VNumPoly{} -> return $ text "<polymorphic value>" ppWordVal :: WordValue sym -> SEval sym Doc- ppWordVal w = ppWord x opts <$> asWordVal x w+ ppWordVal w = ppSWord x opts =<< asWordVal x w ppWordSeq :: Integer -> SeqMap sym -> SEval sym Doc ppWordSeq sz vals = do@@ -399,11 +415,102 @@ -> do vs <- traverse (fromVWord x "ppWordSeq") ws case traverse (wordAsChar x) vs of Just str -> return $ text (show str)- _ -> return $ brackets (fsep (punctuate comma $ map (ppWord x opts) vs))+ _ -> do vs' <- mapM (ppSWord x opts) vs+ return $ brackets (fsep (punctuate comma vs')) _ -> do ws' <- traverse loop ws return $ brackets (fsep (punctuate comma ws')) +ppSBit :: Backend sym => sym -> SBit sym -> SEval sym Doc+ppSBit sym b =+ case bitAsLit sym b of+ Just True -> pure (text "True")+ Just False -> pure (text "False")+ Nothing -> pure (text "?") +ppSInteger :: Backend sym => sym -> SInteger sym -> SEval sym Doc+ppSInteger sym x =+ case integerAsLit sym x of+ Just i -> pure (integer i)+ Nothing -> pure (text "[?]")++ppSFloat :: Backend sym => sym -> PPOpts -> SFloat sym -> SEval sym Doc+ppSFloat sym opts x =+ case fpAsLit sym x of+ Just fp -> pure (fpPP opts fp)+ Nothing -> pure (text "[?]")++ppSRational :: Backend sym => sym -> SRational sym -> SEval sym Doc+ppSRational sym (SRational n d)+ | Just ni <- integerAsLit sym n+ , Just di <- integerAsLit sym d+ = let q = ni % di in+ pure (text "(ratio" <+> integer (numerator q) <+> (integer (denominator q) <> text ")"))++ | otherwise+ = do n' <- ppSInteger sym n+ d' <- ppSInteger sym d+ pure (text "(ratio" <+> n' <+> (d' <> text ")"))++ppSWord :: Backend sym => sym -> PPOpts -> SWord sym -> SEval sym Doc+ppSWord sym opts bv+ | asciiMode opts width =+ case wordAsLit sym bv of+ Just (_,i) -> pure (text (show (toEnum (fromInteger i) :: Char)))+ Nothing -> pure (text "?")++ | otherwise =+ case wordAsLit sym bv of+ Just (_,i) ->+ let val = value i in+ pure (prefix (length val) <.> text val)+ Nothing+ | base == 2 -> sliceDigits 1 "0b"+ | base == 8 -> sliceDigits 3 "0o"+ | base == 16 -> sliceDigits 4 "0x"+ | otherwise -> pure (text "[?]")++ where+ width = wordLen sym bv++ base = if useBase opts > 36 then 10 else useBase opts++ padding bitsPerDigit len = text (replicate padLen '0')+ where+ padLen | m > 0 = d + 1+ | otherwise = d++ (d,m) = (fromInteger width - (len * bitsPerDigit))+ `divMod` bitsPerDigit++ prefix len = case base of+ 2 -> text "0b" <.> padding 1 len+ 8 -> text "0o" <.> padding 3 len+ 10 -> empty+ 16 -> text "0x" <.> padding 4 len+ _ -> text "0" <.> char '<' <.> int base <.> char '>'++ value i = showIntAtBase (toInteger base) (digits !!) i ""+ digits = "0123456789abcdefghijklmnopqrstuvwxyz"++ toDigit w =+ case wordAsLit sym w of+ Just (_,i) | i <= 36 -> digits !! fromInteger i+ _ -> '?'++ sliceDigits bits pfx =+ do ws <- goDigits bits [] bv+ let ds = map toDigit ws+ pure (text pfx <.> text ds)++ goDigits bits ds w+ | wordLen sym w > bits =+ do (hi,lo) <- splitWord sym (wordLen sym w - bits) bits w+ goDigits bits (lo:ds) hi++ | wordLen sym w > 0 = pure (w:ds)++ | otherwise = pure ds+ -- Value Constructors ---------------------------------------------------------- -- | Create a packed word of n bits.@@ -413,45 +520,41 @@ | otherwise = VWord n (WordVal <$> wordLit sym n i) -lam :: (SEval sym (GenValue sym) -> SEval sym (GenValue sym)) -> GenValue sym-lam = VFun---- | Functions that assume word inputs-wlam :: Backend sym => sym -> (SWord sym -> SEval sym (GenValue sym)) -> GenValue sym-wlam sym f = VFun (\arg -> arg >>= fromVWord sym "wlam" >>= f)+-- | Construct a function value+lam :: Backend sym => sym -> (SEval sym (GenValue sym) -> SEval sym (GenValue sym)) -> SEval sym (GenValue sym)+lam sym f = VFun <$> sGetCallStack sym <*> pure f -- | Functions that assume floating point inputs-flam :: Backend sym =>- (SFloat sym -> SEval sym (GenValue sym)) -> GenValue sym-flam f = VFun (\arg -> arg >>= f . fromVFloat)--+flam :: Backend sym => sym ->+ (SFloat sym -> SEval sym (GenValue sym)) -> SEval sym (GenValue sym)+flam sym f = VFun <$> sGetCallStack sym <*> pure (\arg -> arg >>= f . fromVFloat) -- | A type lambda that expects a 'Type'.-tlam :: Backend sym => (TValue -> GenValue sym) -> GenValue sym-tlam f = VPoly (return . f)+tlam :: Backend sym => sym -> (TValue -> SEval sym (GenValue sym)) -> SEval sym (GenValue sym)+tlam sym f = VPoly <$> sGetCallStack sym <*> pure f -- | A type lambda that expects a 'Type' of kind #.-nlam :: Backend sym => (Nat' -> GenValue sym) -> GenValue sym-nlam f = VNumPoly (return . f)+nlam :: Backend sym => sym -> (Nat' -> SEval sym (GenValue sym)) -> SEval sym (GenValue sym)+nlam sym f = VNumPoly <$> sGetCallStack sym <*> pure f -- | A type lambda that expects a finite numeric type.-ilam :: Backend sym => (Integer -> GenValue sym) -> GenValue sym-ilam f = nlam (\n -> case n of- Nat i -> f i- Inf -> panic "ilam" [ "Unexpected `inf`" ])+ilam :: Backend sym => sym -> (Integer -> SEval sym (GenValue sym)) -> SEval sym (GenValue sym)+ilam sym f =+ nlam sym (\n -> case n of+ Nat i -> f i+ Inf -> panic "ilam" [ "Unexpected `inf`" ]) -- | Generate a stream.-toStream :: Backend sym => [GenValue sym] -> SEval sym (GenValue sym)-toStream vs =- VStream <$> infiniteSeqMap (map pure vs)+toStream :: Backend sym => sym -> [GenValue sym] -> SEval sym (GenValue sym)+toStream sym vs =+ VStream <$> infiniteSeqMap sym (map pure vs) toFinSeq :: Backend sym => sym -> Integer -> TValue -> [GenValue sym] -> GenValue sym toFinSeq sym len elty vs | isTBit elty = VWord len (WordVal <$> packWord sym (map fromVBit vs))- | otherwise = VSeq len $ finiteSeqMap sym (map pure vs)+ | otherwise = VSeq len $ finiteSeqMap (map pure vs) -- | Construct either a finite sequence, or a stream. In the finite case, -- record whether or not the elements were bits, to aid pretty-printing.@@ -460,7 +563,7 @@ sym -> Nat' -> TValue -> [GenValue sym] -> SEval sym (GenValue sym) toSeq sym len elty vals = case len of Nat n -> return $ toFinSeq sym n elty vals- Inf -> toStream vals+ Inf -> toStream sym vals -- | Construct either a finite sequence, or a stream. In the finite case,@@ -537,22 +640,25 @@ go _ (_ : _) = Nothing -- | Extract a function from a value.-fromVFun :: GenValue sym -> (SEval sym (GenValue sym) -> SEval sym (GenValue sym))-fromVFun val = case val of- VFun f -> f- _ -> evalPanic "fromVFun" ["not a function"]+fromVFun :: Backend sym => sym -> GenValue sym -> (SEval sym (GenValue sym) -> SEval sym (GenValue sym))+fromVFun sym val = case val of+ VFun fnstk f ->+ \x -> sModifyCallStack sym (\stk -> combineCallStacks stk fnstk) (f x)+ _ -> evalPanic "fromVFun" ["not a function"] -- | Extract a polymorphic function from a value.-fromVPoly :: GenValue sym -> (TValue -> SEval sym (GenValue sym))-fromVPoly val = case val of- VPoly f -> f- _ -> evalPanic "fromVPoly" ["not a polymorphic value"]+fromVPoly :: Backend sym => sym -> GenValue sym -> (TValue -> SEval sym (GenValue sym))+fromVPoly sym val = case val of+ VPoly fnstk f ->+ \x -> sModifyCallStack sym (\stk -> combineCallStacks stk fnstk) (f x)+ _ -> evalPanic "fromVPoly" ["not a polymorphic value"] -- | Extract a polymorphic function from a value.-fromVNumPoly :: GenValue sym -> (Nat' -> SEval sym (GenValue sym))-fromVNumPoly val = case val of- VNumPoly f -> f- _ -> evalPanic "fromVNumPoly" ["not a polymorphic value"]+fromVNumPoly :: Backend sym => sym -> GenValue sym -> (Nat' -> SEval sym (GenValue sym))+fromVNumPoly sym val = case val of+ VNumPoly fnstk f ->+ \x -> sModifyCallStack sym (\stk -> combineCallStacks stk fnstk) (f x)+ _ -> evalPanic "fromVNumPoly" ["not a polymorphic value"] -- | Extract a tuple from a value. fromVTuple :: GenValue sym -> [SEval sym (GenValue sym)]
src/Cryptol/Eval/What4.hs view
@@ -18,22 +18,20 @@ module Cryptol.Eval.What4 ( Value , primTable- , floatPrims ) where import qualified Control.Exception as X import Control.Concurrent.MVar-import Control.Monad (join,foldM)+import Control.Monad (foldM) import Control.Monad.IO.Class import Data.Bits import qualified Data.Map as Map-import Data.Map (Map) import qualified Data.Set as Set import Data.Text (Text) import qualified Data.Text as Text import Data.Parameterized.Context-import Data.Parameterized.Some import Data.Parameterized.TraversableFC+import Data.Parameterized.Some import qualified Data.BitVector.Sized as BV import qualified What4.Interface as W4@@ -43,10 +41,10 @@ import Cryptol.Backend import Cryptol.Backend.Monad ( EvalError(..), Unsupported(..) ) import Cryptol.Backend.What4-import qualified Cryptol.Backend.What4.SFloat as W4 import Cryptol.Eval.Generic-import Cryptol.Eval.Type (finNat', TValue(..))+import Cryptol.Eval.Prims+import Cryptol.Eval.Type (TValue(..)) import Cryptol.Eval.Value import qualified Cryptol.SHA as SHA@@ -60,111 +58,17 @@ type Value sym = GenValue (What4 sym) -- See also Cryptol.Prims.Eval.primTable-primTable :: W4.IsSymExprBuilder sym => What4 sym -> Map.Map PrimIdent (Value sym)-primTable sym =+primTable :: W4.IsSymExprBuilder sym => What4 sym -> IO EvalOpts -> Map.Map PrimIdent (Prim (What4 sym))+primTable sym getEOpts = let w4sym = w4 sym in- Map.union (floatPrims sym) $ Map.union (suiteBPrims sym) $ Map.union (primeECPrims sym) $+ Map.union (genericFloatTable sym) $+ Map.union (genericPrimTable sym getEOpts) $ Map.fromList $ map (\(n, v) -> (prelPrim n, v)) - [ -- Literals- ("True" , VBit (bitLit sym True))- , ("False" , VBit (bitLit sym False))- , ("number" , ecNumberV sym) -- Converts a numeric type into its corresponding value.- -- { val, rep } (Literal val rep) => rep- , ("fraction" , ecFractionV sym)- , ("ratio" , ratioV sym)-- -- Zero- , ("zero" , VPoly (zeroV sym))-- -- Logic- , ("&&" , binary (andV sym))- , ("||" , binary (orV sym))- , ("^" , binary (xorV sym))- , ("complement" , unary (complementV sym))-- -- Ring- , ("fromInteger" , fromIntegerV sym)- , ("+" , binary (addV sym))- , ("-" , binary (subV sym))- , ("negate" , unary (negateV sym))- , ("*" , binary (mulV sym))-- -- Integral- , ("toInteger" , toIntegerV sym)- , ("/" , binary (divV sym))- , ("%" , binary (modV sym))- , ("^^" , expV sym)- , ("infFrom" , infFromV sym)- , ("infFromThen" , infFromThenV sym)-- -- Field- , ("recip" , recipV sym)- , ("/." , fieldDivideV sym)-- -- Round- , ("floor" , unary (floorV sym))- , ("ceiling" , unary (ceilingV sym))- , ("trunc" , unary (truncV sym))- , ("roundAway" , unary (roundAwayV sym))- , ("roundToEven" , unary (roundToEvenV sym))-- -- Word operations- , ("/$" , sdivV sym)- , ("%$" , smodV sym)- , ("lg2" , lg2V sym)- , (">>$" , sshrV sym)-- -- Cmp- , ("<" , binary (lessThanV sym))- , (">" , binary (greaterThanV sym))- , ("<=" , binary (lessThanEqV sym))- , (">=" , binary (greaterThanEqV sym))- , ("==" , binary (eqV sym))- , ("!=" , binary (distinctV sym))-- -- SignedCmp- , ("<$" , binary (signedLessThanV sym))-- -- Finite enumerations- , ("fromTo" , fromToV sym)- , ("fromThenTo" , fromThenToV sym)-- -- Sequence manipulations- , ("#" , -- {a,b,d} (fin a) => [a] d -> [b] d -> [a + b] d- nlam $ \ front ->- nlam $ \ back ->- tlam $ \ elty ->- lam $ \ l -> return $- lam $ \ r -> join (ccatV sym front back elty <$> l <*> r))-- , ("join" ,- nlam $ \ parts ->- nlam $ \ (finNat' -> each) ->- tlam $ \ a ->- lam $ \ x ->- joinV sym parts each a =<< x)-- , ("split" , ecSplitV sym)-- , ("splitAt" ,- nlam $ \ front ->- nlam $ \ back ->- tlam $ \ a ->- lam $ \ x ->- splitAtV sym front back a =<< x)-- , ("reverse" , nlam $ \_a ->- tlam $ \_b ->- lam $ \xs -> reverseV sym =<< xs)-- , ("transpose" , nlam $ \a ->- nlam $ \b ->- tlam $ \c ->- lam $ \xs -> transposeV sym a b c =<< xs)+ [ (">>$" , sshrV sym) -- Shifts and rotates , ("<<" , logicShift sym "<<" shiftShrink@@ -187,52 +91,9 @@ , ("update" , updatePrim sym (updateFrontSym_word sym) (updateFrontSym sym)) , ("updateEnd" , updatePrim sym (updateBackSym_word sym) (updateBackSym sym)) - -- Misc-- , ("foldl" , foldlV sym)- , ("foldl'" , foldl'V sym)-- , ("deepseq" ,- tlam $ \_a ->- tlam $ \_b ->- lam $ \x -> pure $- lam $ \y ->- do _ <- forceValue =<< x- y)-- , ("parmap" , parmapV sym)-- , ("fromZ" , fromZV sym)-- -- {at,len} (fin len) => [len][8] -> at- , ("error" ,- tlam $ \a ->- nlam $ \_ ->- VFun $ \s -> errorV sym a =<< (valueToString sym =<< s))-- , ("random" ,- tlam $ \a ->- wlam sym $ \x ->- case wordAsLit sym x of- Just (_,i) -> randomV sym a i- Nothing -> cryUserError sym "cannot evaluate 'random' with symbolic inputs")-- -- The trace function simply forces its first two- -- values before returing the third in the symbolic- -- evaluator.- , ("trace",- nlam $ \_n ->- tlam $ \_a ->- tlam $ \_b ->- lam $ \s -> return $- lam $ \x -> return $- lam $ \y -> do- _ <- s- _ <- x- y) ] -primeECPrims :: W4.IsSymExprBuilder sym => What4 sym -> Map.Map PrimIdent (Value sym)+primeECPrims :: W4.IsSymExprBuilder sym => What4 sym -> Map.Map PrimIdent (Prim (What4 sym)) primeECPrims sym = Map.fromList $ [ (primeECPrim n, v) | (n,v) <- prims ] where (~>) = (,)@@ -240,8 +101,9 @@ prims = [ -- {p} (prime p, p > 3) => ProjectivePoint p -> ProjectivePoint p "ec_double" ~>- ilam \p ->- lam \s ->+ PFinPoly \p ->+ PFun \s ->+ PPrim do p' <- integerLit sym p s' <- toProjectivePoint sym =<< s addUninterpWarning sym "Prime ECC"@@ -252,9 +114,10 @@ -- {p} (prime p, p > 3) => ProjectivePoint p -> ProjectivePoint p -> ProjectivePoint p , "ec_add_nonzero" ~>- ilam \p ->- lam \s -> pure $- lam \t ->+ PFinPoly \p ->+ PFun \s ->+ PFun \t ->+ PPrim do p' <- integerLit sym p s' <- toProjectivePoint sym =<< s t' <- toProjectivePoint sym =<< t@@ -266,9 +129,10 @@ -- {p} (prime p, p > 3) => Z p -> ProjectivePoint p -> ProjectivePoint p , "ec_mult" ~>- ilam \p ->- lam \k -> pure $- lam \s ->+ PFinPoly \p ->+ PFun \k ->+ PFun \s ->+ PPrim do p' <- integerLit sym p k' <- fromVInteger <$> k s' <- toProjectivePoint sym =<< s@@ -280,11 +144,12 @@ -- {p} (prime p, p > 3) => Z p -> ProjectivePoint p -> Z p -> ProjectivePoint p -> ProjectivePoint p , "ec_twin_mult" ~>- ilam \p ->- lam \j -> pure $- lam \s -> pure $- lam \k -> pure $- lam \t ->+ PFinPoly \p ->+ PFun \j ->+ PFun \s ->+ PFun \k ->+ PFun \t ->+ PPrim do p' <- integerLit sym p j' <- fromVInteger <$> j s' <- toProjectivePoint sym =<< s@@ -299,7 +164,6 @@ fromProjectivePoint sym z ] - type ProjectivePoint = W4.BaseStructType (EmptyCtx ::> W4.BaseIntegerType ::> W4.BaseIntegerType ::> W4.BaseIntegerType) projectivePointRepr :: W4.BaseTypeRepr ProjectivePoint@@ -321,37 +185,44 @@ z <- VInteger <$> W4.structField (w4 sym) p (natIndex @2) pure $ VRecord $ recordFromFields [ (packIdent "x",pure x), (packIdent "y",pure y),(packIdent "z",pure z) ] -suiteBPrims :: W4.IsSymExprBuilder sym => What4 sym -> Map.Map PrimIdent (Value sym)++suiteBPrims :: W4.IsSymExprBuilder sym => What4 sym -> Map.Map PrimIdent (Prim (What4 sym)) suiteBPrims sym = Map.fromList $ [ (suiteBPrim n, v) | (n,v) <- prims ] where (~>) = (,) prims = [ "AESEncRound" ~>- lam \st ->+ PFun \st ->+ PPrim do addUninterpWarning sym "AES encryption" applyAESStateFunc sym "AESEncRound" =<< st , "AESEncFinalRound" ~>- lam \st ->+ PFun \st ->+ PPrim do addUninterpWarning sym "AES encryption" applyAESStateFunc sym "AESEncFinalRound" =<< st , "AESDecRound" ~>- lam \st ->+ PFun \st ->+ PPrim do addUninterpWarning sym "AES decryption" applyAESStateFunc sym "AESDecRound" =<< st , "AESDecFinalRound" ~>- lam \st ->+ PFun \st ->+ PPrim do addUninterpWarning sym "AES decryption" applyAESStateFunc sym "AESDecFinalRound" =<< st , "AESInvMixColumns" ~>- lam \st ->+ PFun \st ->+ PPrim do addUninterpWarning sym "AES key expansion" applyAESStateFunc sym "AESInvMixColumns" =<< st -- {k} (fin k, k >= 4, 8 >= k) => [k][32] -> [4*(k+7)][32] , "AESKeyExpand" ~>- ilam \k ->- lam \st ->+ PFinPoly \k ->+ PFun \st ->+ PPrim do ss <- fromVSeq <$> st -- pack the arguments into a k-tuple of 32-bit values Some ws <- generateSomeM (fromInteger k) (\i -> Some <$> toWord32 sym "AESKeyExpand" ss (toInteger i))@@ -368,12 +239,13 @@ case intIndex (fromInteger i) (size ret) of Just (Some idx) | Just W4.Refl <- W4.testEquality (ret!idx) (W4.BaseBVRepr (W4.knownNat @32)) -> fromWord32 =<< liftIO (W4.structField (w4 sym) z idx)- _ -> invalidIndex sym i+ _ -> evalPanic "AESKeyExpand" ["Index out of range", show k, show i] -- {n} (fin n) => [n][16][32] -> [7][32] , "processSHA2_224" ~>- ilam \n ->- lam \xs ->+ PFinPoly \n ->+ PFun \xs ->+ PPrim do blks <- enumerateSeqMap n . fromVSeq <$> xs addUninterpWarning sym "SHA-224" initSt <- liftIO (mkSHA256InitialState sym SHA.initialSHA224State)@@ -384,13 +256,14 @@ do z <- liftIO $ W4.structField (w4 sym) finalSt idx case W4.testEquality (W4.exprType z) (W4.BaseBVRepr (W4.knownNat @32)) of Just W4.Refl -> fromWord32 z- Nothing -> invalidIndex sym i- Nothing -> invalidIndex sym i+ Nothing -> evalPanic "processSHA2_224" ["Index out of range", show i]+ Nothing -> evalPanic "processSHA2_224" ["Index out of range", show i] -- {n} (fin n) => [n][16][32] -> [8][32] , "processSHA2_256" ~>- ilam \n ->- lam \xs ->+ PFinPoly \n ->+ PFun \xs ->+ PPrim do blks <- enumerateSeqMap n . fromVSeq <$> xs addUninterpWarning sym "SHA-256" initSt <- liftIO (mkSHA256InitialState sym SHA.initialSHA256State)@@ -401,13 +274,14 @@ do z <- liftIO $ W4.structField (w4 sym) finalSt idx case W4.testEquality (W4.exprType z) (W4.BaseBVRepr (W4.knownNat @32)) of Just W4.Refl -> fromWord32 z- Nothing -> invalidIndex sym i- Nothing -> invalidIndex sym i+ Nothing -> evalPanic "processSHA2_256" ["Index out of range", show i]+ Nothing -> evalPanic "processSHA2_256" ["Index out of range", show i] -- {n} (fin n) => [n][16][64] -> [6][64] , "processSHA2_384" ~>- ilam \n ->- lam \xs ->+ PFinPoly \n ->+ PFun \xs ->+ PPrim do blks <- enumerateSeqMap n . fromVSeq <$> xs addUninterpWarning sym "SHA-384" initSt <- liftIO (mkSHA512InitialState sym SHA.initialSHA384State)@@ -418,13 +292,14 @@ do z <- liftIO $ W4.structField (w4 sym) finalSt idx case W4.testEquality (W4.exprType z) (W4.BaseBVRepr (W4.knownNat @64)) of Just W4.Refl -> fromWord64 z- Nothing -> invalidIndex sym i- Nothing -> invalidIndex sym i+ Nothing -> evalPanic "processSHA2_384" ["Index out of range", show i]+ Nothing -> evalPanic "processSHA2_384" ["Index out of range", show i] -- {n} (fin n) => [n][16][64] -> [8][64] , "processSHA2_512" ~>- ilam \n ->- lam \xs ->+ PFinPoly \n ->+ PFun \xs ->+ PPrim do blks <- enumerateSeqMap n . fromVSeq <$> xs addUninterpWarning sym "SHA-512" initSt <- liftIO (mkSHA512InitialState sym SHA.initialSHA512State)@@ -435,8 +310,8 @@ do z <- liftIO $ W4.structField (w4 sym) finalSt idx case W4.testEquality (W4.exprType z) (W4.BaseBVRepr (W4.knownNat @64)) of Just W4.Refl -> fromWord64 z- Nothing -> invalidIndex sym i- Nothing -> invalidIndex sym i+ Nothing -> evalPanic "processSHA2_512" ["Index out of range", show i]+ Nothing -> evalPanic "processSHA2_512" ["Index out of range", show i] ] @@ -626,7 +501,7 @@ | i == 1 -> fromWord32 =<< liftIO (W4.structField (w4 sym) z (natIndex @1)) | i == 2 -> fromWord32 =<< liftIO (W4.structField (w4 sym) z (natIndex @2)) | i == 3 -> fromWord32 =<< liftIO (W4.structField (w4 sym) z (natIndex @3))- | otherwise -> invalidIndex sym i+ | otherwise -> evalPanic "applyAESStateFunc" ["Index out of range", show funNm, show i] where nm = Text.unpack funNm@@ -636,13 +511,14 @@ argCtx = W4.knownRepr -sshrV :: W4.IsSymExprBuilder sym => What4 sym -> Value sym+sshrV :: W4.IsSymExprBuilder sym => What4 sym -> Prim (What4 sym) sshrV sym =- nlam $ \(Nat n) ->- tlam $ \ix ->- wlam sym $ \x -> return $- lam $ \y ->- y >>= asIndex sym ">>$" ix >>= \case+ PFinPoly \n ->+ PTyPoly \ix ->+ PWordFun \x ->+ PStrict \y ->+ PPrim $+ asIndex sym ">>$" ix y >>= \case Left i -> do pneg <- intLessThan sym i =<< integerLit sym 0 zneg <- do i' <- shiftShrink sym (Nat n) ix =<< intNegate sym i@@ -864,7 +740,7 @@ WordVal w | Just j <- SW.bvAsUnsignedInteger w -> return $ updateSeqMap vs j val _ ->- memoMap $ IndexSeqMap $ \i ->+ memoMap sym $ IndexSeqMap $ \i -> do b <- wordValueEqualsInteger sym wv i iteValue sym b val (lookupSeqMap vs i) @@ -891,7 +767,7 @@ WordVal w | Just j <- SW.bvAsUnsignedInteger w -> return $ updateSeqMap vs (n - 1 - j) val _ ->- memoMap $ IndexSeqMap $ \i ->+ memoMap sym $ IndexSeqMap $ \i -> do b <- wordValueEqualsInteger sym wv (n - 1 - i) iteValue sym b val (lookupSeqMap vs i) @@ -980,57 +856,3 @@ _ -> LargeBitsVal (wordValueSize sym wv) <$> updateBackSym sym (Nat n) eltTy (asBitsMap sym bv) (Right wv) val------- | Table of floating point primitives-floatPrims :: W4.IsSymExprBuilder sym => What4 sym -> Map PrimIdent (Value sym)-floatPrims sym =- Map.fromList [ (floatPrim i,v) | (i,v) <- nonInfixTable ]- where- w4sym = w4 sym- (~>) = (,)-- nonInfixTable =- [ "fpNaN" ~> fpConst (W4.fpNaN w4sym)- , "fpPosInf" ~> fpConst (W4.fpPosInf w4sym)- , "fpFromBits" ~> ilam \e -> ilam \p -> wlam sym \w ->- VFloat <$> liftIO (W4.fpFromBinary w4sym e p w)- , "fpToBits" ~> ilam \e -> ilam \p -> flam \x ->- pure $ VWord (e+p)- $ WordVal <$> liftIO (W4.fpToBinary w4sym x)- , "=.=" ~> ilam \_ -> ilam \_ -> flam \x -> pure $ flam \y ->- VBit <$> liftIO (W4.fpEq w4sym x y)- , "fpIsFinite" ~> ilam \_ -> ilam \_ -> flam \x ->- VBit <$> liftIO do inf <- W4.fpIsInf w4sym x- nan <- W4.fpIsNaN w4sym x- weird <- W4.orPred w4sym inf nan- W4.notPred w4sym weird-- , "fpAdd" ~> fpBinArithV sym fpPlus- , "fpSub" ~> fpBinArithV sym fpMinus- , "fpMul" ~> fpBinArithV sym fpMult- , "fpDiv" ~> fpBinArithV sym fpDiv-- , "fpFromRational" ~>- ilam \e -> ilam \p -> wlam sym \r -> pure $ lam \x ->- do rat <- fromVRational <$> x- VFloat <$> fpCvtFromRational sym e p r rat-- , "fpToRational" ~>- ilam \_e -> ilam \_p -> flam \fp ->- VRational <$> fpCvtToRational sym fp- ]------ | A helper for definitng floating point constants.-fpConst ::- W4.IsSymExprBuilder sym =>- (Integer -> Integer -> IO (W4.SFloat sym)) ->- Value sym-fpConst mk =- ilam \ e ->- VNumPoly \ ~(Nat p) ->- VFloat <$> liftIO (mk e p)
src/Cryptol/IR/FreeVars.hs view
@@ -99,6 +99,7 @@ instance FreeVars Expr where freeVars expr = case expr of+ ELocated _r t -> freeVars t EList es t -> freeVars es <> freeVars t ETuple es -> freeVars es ERec fs -> freeVars (recordElements fs)@@ -139,7 +140,7 @@ TUser _ _ t -> freeVars t TRec fs -> freeVars (recordElements fs)-+ TNewtype nt ts -> freeVars nt <> freeVars ts instance FreeVars TVar where freeVars tv = case tv of@@ -147,14 +148,11 @@ _ -> mempty instance FreeVars TCon where- freeVars tc =- case tc of- TC (TCNewtype (UserTC n _)) -> mempty { tyDeps = Set.singleton n }- _ -> mempty+ freeVars _tc = mempty instance FreeVars Newtype where freeVars nt = foldr rmTParam base (ntParams nt)- where base = freeVars (ntConstraints nt) <> freeVars (map snd (ntFields nt))+ where base = freeVars (ntConstraints nt) <> freeVars (recordElements (ntFields nt)) --------------------------------------------------------------------------------
src/Cryptol/ModuleSystem.hs view
@@ -14,6 +14,7 @@ , DynamicEnv(..) , ModuleError(..), ModuleWarning(..) , ModuleCmd, ModuleRes+ , ModuleInput(..) , findModule , loadModuleByPath , loadModuleByName@@ -32,7 +33,6 @@ , IfaceTySyn, IfaceDecl(..) ) where -import qualified Cryptol.Eval as E import qualified Cryptol.Eval.Concrete as Concrete import Cryptol.ModuleSystem.Env import Cryptol.ModuleSystem.Interface@@ -46,11 +46,9 @@ import qualified Cryptol.TypeCheck.AST as T import qualified Cryptol.Utils.Ident as M -import Data.ByteString (ByteString)- -- Public Interface ------------------------------------------------------------ -type ModuleCmd a = (E.EvalOpts, FilePath -> IO ByteString, ModuleEnv) -> IO (ModuleRes a)+type ModuleCmd a = ModuleInput IO -> IO (ModuleRes a) type ModuleRes a = (Either ModuleError (a,ModuleEnv), [ModuleWarning]) @@ -63,8 +61,8 @@ -- | Load the module contained in the given file. loadModuleByPath :: FilePath -> ModuleCmd (ModulePath,T.Module)-loadModuleByPath path (evo, byteReader, env) =- runModuleM (evo, byteReader, resetModuleEnv env) $ do+loadModuleByPath path minp =+ runModuleM minp{ minpModuleEnv = resetModuleEnv (minpModuleEnv minp) } $ do unloadModule ((InFile path ==) . lmFilePath) m <- Base.loadModuleByPath path setFocusedModule (T.mName m)@@ -72,8 +70,8 @@ -- | Load the given parsed module. loadModuleByName :: P.ModName -> ModuleCmd (ModulePath,T.Module)-loadModuleByName n (evo, byteReader, env) =- runModuleM (evo, byteReader, resetModuleEnv env) $ do+loadModuleByName n minp =+ runModuleM minp{ minpModuleEnv = resetModuleEnv (minpModuleEnv minp) } $ do unloadModule ((n ==) . lmName) (path,m') <- Base.loadModuleFrom False (FromModule n) setFocusedModule (T.mName m')
src/Cryptol/ModuleSystem/Base.hs view
@@ -26,7 +26,6 @@ , ModContext(..) , ModulePath(..), modulePathLabel) import qualified Cryptol.Eval as E- import qualified Cryptol.Eval.Concrete as Concrete import Cryptol.Eval.Concrete (Concrete(..)) import qualified Cryptol.ModuleSystem.NamingEnv as R@@ -41,6 +40,7 @@ import qualified Cryptol.TypeCheck.AST as T import qualified Cryptol.TypeCheck.PP as T import qualified Cryptol.TypeCheck.Sanity as TcSanity+ import Cryptol.Transform.AddModParams (addModParams) import Cryptol.Utils.Ident ( preludeName, floatName, arrayName, suiteBName, primeECName , preludeReferenceName, interactiveName, modNameChunks@@ -203,8 +203,10 @@ tcm <- optionalInstantiate =<< checkModule isrc path pm -- extend the eval env, unless a functor.- tbl <- Concrete.primTable <$> getEvalOpts+ tbl <- Concrete.primTable <$> getEvalOptsAction let ?evalPrim = \i -> Right <$> Map.lookup i tbl+ callStacks <- getCallStacks+ let ?callStacks = callStacks unless (T.isParametrizedModule tcm) $ modifyEvalEnv (E.moduleEnv Concrete tcm) loadedModule path fp tcm @@ -453,7 +455,7 @@ data TCLinter o = TCLinter { lintCheck ::- o -> T.InferInput -> Either TcSanity.Error [TcSanity.ProofObligation]+ o -> T.InferInput -> Either (Range, TcSanity.Error) [TcSanity.ProofObligation] , lintModule :: Maybe P.ModName } @@ -465,7 +467,9 @@ Left err -> Left err Right (s1,os) | TcSanity.same s s1 -> Right os- | otherwise -> Left (TcSanity.TypeMismatch "exprLinter" s s1)+ | otherwise -> Left ( fromMaybe emptyRange (getLoc e')+ , TcSanity.TypeMismatch "exprLinter" s s1+ ) , lintModule = Nothing } @@ -524,14 +528,15 @@ typeCheckingFailed nameMap errs -- | Generate input for the typechecker.-genInferInput :: Range -> PrimMap ->- IfaceParams -> IfaceDecls -> ModuleM T.InferInput+genInferInput :: Range -> PrimMap -> IfaceParams -> IfaceDecls -> ModuleM T.InferInput genInferInput r prims params env = do seeds <- getNameSeeds monoBinds <- getMonoBinds cfg <- getSolverConfig+ solver <- getTCSolver supply <- getSupply searchPath <- getSearchPath+ callStacks <- getCallStacks -- TODO: include the environment needed by the module return T.InferInput@@ -542,6 +547,7 @@ , T.inpAbstractTypes = ifAbstractTypes env , T.inpNameSeeds = seeds , T.inpMonoBinds = monoBinds+ , T.inpCallStacks = callStacks , T.inpSolverConfig = cfg , T.inpSearchPath = searchPath , T.inpSupply = supply@@ -549,30 +555,37 @@ , T.inpParamTypes = ifParamTypes params , T.inpParamConstraints = ifParamConstraints params , T.inpParamFuns = ifParamFuns params+ , T.inpSolver = solver } - -- Evaluation ------------------------------------------------------------------ evalExpr :: T.Expr -> ModuleM Concrete.Value evalExpr e = do env <- getEvalEnv denv <- getDynEnv- evopts <- getEvalOpts+ evopts <- getEvalOptsAction let tbl = Concrete.primTable evopts let ?evalPrim = \i -> Right <$> Map.lookup i tbl- io $ E.runEval $ (E.evalExpr Concrete (env <> deEnv denv) e)+ let ?range = emptyRange+ callStacks <- getCallStacks+ let ?callStacks = callStacks + io $ E.runEval mempty (E.evalExpr Concrete (env <> deEnv denv) e)+ evalDecls :: [T.DeclGroup] -> ModuleM () evalDecls dgs = do env <- getEvalEnv denv <- getDynEnv- evOpts <- getEvalOpts+ evOpts <- getEvalOptsAction let env' = env <> deEnv denv let tbl = Concrete.primTable evOpts let ?evalPrim = \i -> Right <$> Map.lookup i tbl- deEnv' <- io $ E.runEval $ E.evalDecls Concrete dgs env'+ callStacks <- getCallStacks+ let ?callStacks = callStacks++ deEnv' <- io $ E.runEval mempty (E.evalDecls Concrete dgs env') let denv' = denv { deDecls = deDecls denv ++ dgs , deEnv = deEnv' }
src/Cryptol/ModuleSystem/Env.hs view
@@ -177,6 +177,12 @@ loadedNonParamModules :: ModuleEnv -> [T.Module] loadedNonParamModules = map lmModule . lmLoadedModules . meLoadedModules +loadedNewtypes :: ModuleEnv -> Map Name IfaceNewtype+loadedNewtypes menv = Map.unions+ [ ifNewtypes (ifPublic i) <> ifNewtypes (ifPrivate i)+ | i <- map lmInterface (getLoadedModules (meLoadedModules menv))+ ]+ -- | Are any parameterized modules loaded? hasParamModules :: ModuleEnv -> Bool hasParamModules = not . null . lmLoadedParamModules . meLoadedModules
src/Cryptol/ModuleSystem/InstantiateModule.hs view
@@ -183,6 +183,7 @@ Just y -> EVar y _ -> expr + ELocated r e -> ELocated r (inst env e) EList xs t -> EList (inst env xs) (inst env t) ETuple es -> ETuple (inst env es) ERec xs -> ERec (fmap go xs)@@ -243,6 +244,7 @@ TUser x ts t -> TUser y (inst env ts) (inst env t) where y = Map.findWithDefault x x (tyNameMap env) TRec fs -> TRec (fmap (inst env) fs)+ TNewtype nt ts -> TNewtype (inst env nt) (inst env ts) instance Inst TCon where inst env tc =@@ -253,7 +255,6 @@ instance Inst TC where inst env tc = case tc of- TCNewtype x -> TCNewtype (inst env x) TCAbstract x -> TCAbstract (inst env x) _ -> tc @@ -281,7 +282,7 @@ inst env nt = Newtype { ntName = instTyName env x , ntParams = ntParams nt , ntConstraints = inst env (ntConstraints nt)- , ntFields = [ (f,inst env t) | (f,t) <- ntFields nt ]+ , ntFields = fmap (inst env) (ntFields nt) , ntDoc = ntDoc nt } where x = ntName nt
src/Cryptol/ModuleSystem/Monad.hs view
@@ -29,6 +29,8 @@ import qualified Cryptol.Parser.NoInclude as NoInc import qualified Cryptol.TypeCheck as T import qualified Cryptol.TypeCheck.AST as T+import qualified Cryptol.TypeCheck.Solver.SMT as SMT+ import Cryptol.Parser.Position (Range) import Cryptol.Utils.Ident (interactiveName, noModuleName) import Cryptol.Utils.PP@@ -39,6 +41,7 @@ import Control.Exception (IOException) import Data.ByteString (ByteString) import Data.Function (on)+import Data.Map (Map) import Data.Maybe (isJust) import Data.Text.Encoding.Error (UnicodeException) import MonadLib@@ -300,13 +303,20 @@ data RO m = RO { roLoading :: [ImportSource]- , roEvalOpts :: EvalOpts+ , roEvalOpts :: m EvalOpts+ , roCallStacks :: Bool , roFileReader :: FilePath -> m ByteString+ , roTCSolver :: SMT.Solver } -emptyRO :: EvalOpts -> (FilePath -> m ByteString) -> RO m-emptyRO ev fileReader =- RO { roLoading = [], roEvalOpts = ev, roFileReader = fileReader }+emptyRO :: ModuleInput m -> RO m+emptyRO minp =+ RO { roLoading = []+ , roEvalOpts = minpEvalOpts minp+ , roCallStacks = minpCallStacks minp+ , roFileReader = minpByteReader minp+ , roTCSolver = minpTCSolver minp+ } newtype ModuleT m a = ModuleT { unModuleT :: ReaderT (RO m)@@ -351,21 +361,34 @@ instance MonadIO m => MonadIO (ModuleT m) where liftIO m = lift $ liftIO m -runModuleT :: Monad m- => (EvalOpts, FilePath -> m ByteString, ModuleEnv)- -> ModuleT m a- -> m (Either ModuleError (a, ModuleEnv), [ModuleWarning])-runModuleT (ev, byteReader, env) m =++data ModuleInput m =+ ModuleInput+ { minpCallStacks :: Bool+ , minpEvalOpts :: m EvalOpts+ , minpByteReader :: FilePath -> m ByteString+ , minpModuleEnv :: ModuleEnv+ , minpTCSolver :: SMT.Solver+ }++runModuleT ::+ Monad m =>+ ModuleInput m ->+ ModuleT m a ->+ m (Either ModuleError (a, ModuleEnv), [ModuleWarning])+runModuleT minp m = runWriterT $ runExceptionT- $ runStateT env- $ runReaderT (emptyRO ev byteReader)+ $ runStateT (minpModuleEnv minp)+ $ runReaderT (emptyRO minp) $ unModuleT m type ModuleM = ModuleT IO -runModuleM :: (EvalOpts, FilePath -> IO ByteString, ModuleEnv) -> ModuleM a- -> IO (Either ModuleError (a,ModuleEnv),[ModuleWarning])+runModuleM ::+ ModuleInput IO ->+ ModuleM a ->+ IO (Either ModuleError (a,ModuleEnv),[ModuleWarning]) runModuleM = runModuleT @@ -377,6 +400,9 @@ RO { roFileReader = readFileBytes } <- ask return readFileBytes +getCallStacks :: Monad m => ModuleT m Bool+getCallStacks = ModuleT (roCallStacks <$> ask)+ readBytes :: Monad m => FilePath -> ModuleT m ByteString readBytes fn = do fileReader <- getByteReader@@ -385,6 +411,9 @@ getModuleEnv :: Monad m => ModuleT m ModuleEnv getModuleEnv = ModuleT get +getTCSolver :: Monad m => ModuleT m SMT.Solver+getTCSolver = ModuleT (roTCSolver <$> ask)+ setModuleEnv :: Monad m => ModuleEnv -> ModuleT m () setModuleEnv = ModuleT . set @@ -489,15 +518,23 @@ modifyEvalEnv f = ModuleT $ do env <- get let evalEnv = meEvalEnv env- evalEnv' <- inBase $ E.runEval (f evalEnv)+ evalEnv' <- inBase $ E.runEval mempty (f evalEnv) set $! env { meEvalEnv = evalEnv' } getEvalEnv :: ModuleM EvalEnv getEvalEnv = ModuleT (meEvalEnv `fmap` get) +getEvalOptsAction :: ModuleM (IO EvalOpts)+getEvalOptsAction = ModuleT (roEvalOpts `fmap` ask)+ getEvalOpts :: ModuleM EvalOpts-getEvalOpts = ModuleT (roEvalOpts `fmap` ask)+getEvalOpts =+ do act <- getEvalOptsAction+ liftIO act +getNewtypes :: ModuleM (Map T.Name T.Newtype)+getNewtypes = ModuleT (loadedNewtypes <$> get)+ getFocusedModule :: ModuleM (Maybe P.ModName) getFocusedModule = ModuleT (meFocusedModule `fmap` get) @@ -547,4 +584,3 @@ withLogger :: (Logger -> a -> IO b) -> a -> ModuleM b withLogger f a = do l <- getEvalOpts io (f (evalLogger l) a)-
src/Cryptol/ModuleSystem/Name.hs view
@@ -57,7 +57,6 @@ import Control.DeepSeq-import Control.Monad.Fix (MonadFix(mfix)) import qualified Data.Map as Map import qualified Data.Monoid as M import Data.Ord (comparing)@@ -294,9 +293,6 @@ instance RunM m (a,Supply) r => RunM (SupplyT m) a (Supply -> r) where runM (SupplyT m) s = runM m s {-# INLINE runM #-}--instance MonadFix m => MonadFix (SupplyT m) where- mfix f = SupplyT (mfix (unSupply . f)) -- | Retrieve the next unique from the supply. nextUniqueM :: FreshM m => m Int
src/Cryptol/ModuleSystem/Renamer.hs view
@@ -501,7 +501,7 @@ name' <- rnLocated renameType (nName n) shadowNames (nParams n) $ do ps' <- traverse rename (nParams n)- body' <- traverse (rnNamed rename) (nBody n)+ body' <- traverse (traverse rename) (nBody n) return Newtype { nName = name' , nParams = ps' , nBody = body' }@@ -693,13 +693,18 @@ case more of [] -> case h of UpdSet -> UpdField UpdSet [l] <$> rename e- UpdFun -> UpdField UpdFun [l] <$> rename (EFun [PVar p] e)+ UpdFun -> UpdField UpdFun [l] <$> rename (EFun emptyFunDesc [PVar p] e) where p = UnQual . selName <$> last ls _ -> UpdField UpdFun [l] <$> rename (EUpd Nothing [ UpdField h more e]) [] -> panic "rename@UpdField" [ "Empty label list." ] +instance Rename FunDesc where+ rename (FunDesc nm offset) =+ do nm' <- traverse renameVar nm+ pure (FunDesc nm' offset)+ instance Rename Expr where rename expr = case expr of EVar n -> EVar <$> renameVar n@@ -719,6 +724,10 @@ <*> traverse rename n <*> rename e <*> traverse rename t+ EFromToLessThan s e t ->+ EFromToLessThan <$> rename s+ <*> rename e+ <*> traverse rename t EInfFrom a b -> EInfFrom<$> rename a <*> traverse rename b EComp e' bs -> do arms' <- traverse renameArm bs let (envs,bs') = unzip arms'@@ -733,10 +742,11 @@ EWhere <$> rename e' <*> traverse rename ds ETyped e' ty -> ETyped <$> rename e' <*> rename ty ETypeVal ty -> ETypeVal<$> rename ty- EFun ps e' -> do (env,ps') <- renamePats ps+ EFun desc ps e' -> do desc' <- rename desc+ (env,ps') <- renamePats ps -- NOTE: renamePats will generate warnings, so we don't -- need to duplicate them here- shadowNames' CheckNone env (EFun ps' <$> rename e')+ shadowNames' CheckNone env (EFun desc' ps' <$> rename e') ELocated e' r -> withLoc r $ ELocated <$> rename e' <*> pure r @@ -966,10 +976,3 @@ <*> pure f <*> traverse rename ps <*> traverse rename cs----- Utilities ---------------------------------------------------------------------rnNamed :: (a -> RenameM b) -> Named a -> RenameM (Named b)-rnNamed = traverse-{-# INLINE rnNamed #-}
src/Cryptol/Parser.y view
@@ -27,6 +27,7 @@ import Control.Applicative as A import Data.Maybe(fromMaybe)+import Data.List.NonEmpty ( NonEmpty(..), cons ) import Data.Text(Text) import qualified Data.Text as T import Control.Monad(liftM2,msum)@@ -37,6 +38,7 @@ import Cryptol.Parser.ParserUtils import Cryptol.Parser.Unlit(PreProc(..), guessPreProc) import Cryptol.Utils.Ident(paramInstModName)+import Cryptol.Utils.RecordMap(RecordMap) import Paths_cryptol }@@ -91,7 +93,9 @@ '<-' { Located $$ (Token (Sym ArrL ) _)} '..' { Located $$ (Token (Sym DotDot ) _)} '...' { Located $$ (Token (Sym DotDotDot) _)}+ '..<' { Located $$ (Token (Sym DotDotLt) _)} '|' { Located $$ (Token (Sym Bar ) _)}+ '<' { Located $$ (Token (Sym Lt ) _)} '(' { Located $$ (Token (Sym ParenL ) _)} ')' { Located $$ (Token (Sym ParenR ) _)}@@ -325,13 +329,13 @@ newtype :: { Newtype PName } : 'newtype' qname '=' newtype_body- { Newtype { nName = $2, nParams = [], nBody = $4 } }+ { Newtype $2 [] (thing $4) } | 'newtype' qname tysyn_params '=' newtype_body- { Newtype { nName = $2, nParams = $3, nBody = $5 } }+ { Newtype $2 (reverse $3) (thing $5) } -newtype_body :: { [Named (Type PName)] }- : '{' '}' { [] }- | '{' field_types '}' { $2 }+newtype_body :: { Located (RecordMap Ident (Range, Type PName)) }+ : '{' '}' {% mkRecord (rComb $1 $2) (Located emptyRange) [] }+ | '{' field_types '}' {% mkRecord (rComb $1 $3) (Located emptyRange) $2 } vars_comma :: { [ LPName ] } : var { [ $1] }@@ -402,6 +406,7 @@ | '-' { Located $1 $ mkUnqual $ mkInfix "-" } | '~' { Located $1 $ mkUnqual $ mkInfix "~" } | '^^' { Located $1 $ mkUnqual $ mkInfix "^^" }+ | '<' { Located $1 $ mkUnqual $ mkInfix "<" } other_op :: { LPName }@@ -424,7 +429,7 @@ -- | An expression without a `where` clause exprNoWhere :: { Expr PName }- : simpleExpr qop longRHS { at ($1,$3) (binOp $1 $2 $3) }+ : simpleExpr qop longRHS { binOp $1 $2 $3 } | longRHS { $1 } | typedExpr { $1 } @@ -441,13 +446,13 @@ -- A possibly infix expression (no where, no long application, no type annot) simpleExpr :: { Expr PName }- : simpleExpr qop simpleRHS { at ($1,$3) (binOp $1 $2 $3) }+ : simpleExpr qop simpleRHS { binOp $1 $2 $3 } | simpleRHS { $1 } -- An expression without an obvious end marker longExpr :: { Expr PName } : 'if' ifBranches 'else' exprNoWhere { at ($1,$4) $ mkIf (reverse $2) $4 }- | '\\' apats '->' exprNoWhere { at ($1,$4) $ EFun (reverse $2) $4 }+ | '\\' apats '->' exprNoWhere { at ($1,$4) $ EFun emptyFunDesc (reverse $2) $4 } ifBranches :: { [(Expr PName, Expr PName)] } : ifBranch { [$1] }@@ -469,7 +474,7 @@ -- Prefix application expression, ends with an atom. simpleApp :: { Expr PName }- : aexprs { mkEApp $1 }+ : aexprs {% mkEApp $1 } -- Prefix application expression, may end with a long expression longApp :: { Expr PName }@@ -477,9 +482,9 @@ | longExpr { $1 } | simpleApp { $1 } -aexprs :: { [Expr PName] }- : aexpr { [$1] }- | aexprs aexpr { $2 : $1 }+aexprs :: { NonEmpty (Expr PName) }+ : aexpr { $1 :| [] }+ | aexprs aexpr { cons $2 $1 } -- Expression atom (needs no parens)@@ -567,6 +572,9 @@ | expr '..' expr {% eFromTo $2 $1 Nothing $3 } | expr ',' expr '..' expr {% eFromTo $4 $1 (Just $3) $5 }++ | expr '..' '<' expr {% eFromToLessThan $2 $1 $4 }+ | expr '..<' expr {% eFromToLessThan $2 $1 $3 } | expr '...' { EInfFrom $1 Nothing } | expr ',' expr '...' { EInfFrom $1 (Just $3) }
src/Cryptol/Parser/AST.hs view
@@ -68,6 +68,8 @@ , TypeInst(..) , UpdField(..) , UpdHow(..)+ , FunDesc(..)+ , emptyFunDesc -- * Positions , Located(..)@@ -246,7 +248,7 @@ data Newtype name = Newtype { nName :: Located name -- ^ Type name , nParams :: [TParam name] -- ^ Type params- , nBody :: [Named (Type name)] -- ^ Constructor+ , nBody :: Rec (Type name) -- ^ Body } deriving (Eq, Show, Generic, NFData) -- | A declaration for a type with no implementation.@@ -312,6 +314,9 @@ | EList [Expr n] -- ^ @ [1,2,3] @ | EFromTo (Type n) (Maybe (Type n)) (Type n) (Maybe (Type n)) -- ^ @ [1, 5 .. 117 : t] @+ | EFromToLessThan (Type n) (Type n) (Maybe (Type n))+ -- ^ @ [ 1 .. < 10 : t ] @+ | EInfFrom (Expr n) (Maybe (Expr n))-- ^ @ [1, 3 ...] @ | EComp (Expr n) [[Match n]] -- ^ @ [ 1 | x <- xs ] @ | EApp (Expr n) (Expr n) -- ^ @ f x @@@ -320,7 +325,7 @@ | EWhere (Expr n) [Decl n] -- ^ @ 1 + x where { x = 2 } @ | ETyped (Expr n) (Type n) -- ^ @ 1 : [8] @ | ETypeVal (Type n) -- ^ @ `(x + 1)@, @x@ is a type- | EFun [Pattern n] (Expr n) -- ^ @ \\x y -> x @+ | EFun (FunDesc n) [Pattern n] (Expr n) -- ^ @ \\x y -> x @ | ELocated (Expr n) Range -- ^ position annotation | ESplit (Expr n) -- ^ @ splitAt x @ (Introduced by NoPat)@@ -328,6 +333,19 @@ | EInfix (Expr n) (Located n) Fixity (Expr n)-- ^ @ a + b @ (Removed by Fixity) deriving (Eq, Show, Generic, NFData, Functor) +-- | Description of functions. Only trivial information is provided here+-- by the parser. The NoPat pass fills this in as required.+data FunDesc n =+ FunDesc+ { funDescrName :: Maybe n -- ^ Name of this function, if it has one+ , funDescrArgOffset :: Int -- ^ number of previous arguments to this function+ -- bound in surrounding lambdas (defaults to 0)+ }+ deriving (Eq, Show, Generic, NFData, Functor)++emptyFunDesc :: FunDesc n+emptyFunDesc = FunDesc Nothing 0+ data UpdField n = UpdField UpdHow [Located Selector] (Expr n) -- ^ non-empty list @ x.y = e@ deriving (Eq, Show, Generic, NFData, Functor)@@ -394,7 +412,8 @@ instance AddLoc (Expr n) where- addLoc = ELocated+ addLoc x@ELocated{} _ = x+ addLoc x r = ELocated x r dropLoc (ELocated e _) = dropLoc e dropLoc e = e@@ -496,7 +515,7 @@ | null locs = Nothing | otherwise = Just (rCombs locs) where- locs = catMaybes [ getLoc (nName n), getLoc (nBody n) ]+ locs = catMaybes ([ getLoc (nName n)] ++ map (Just . fst . snd) (displayFields (nBody n))) --------------------------------------------------------------------------------@@ -575,7 +594,7 @@ instance PPName name => PP (Newtype name) where ppPrec _ nt = hsep [ text "newtype", ppL (nName nt), hsep (map pp (nParams nt)), char '='- , braces (commaSep (map (ppNamed ":") (nBody nt))) ]+ , braces (commaSep (map (ppNamed' ":") (displayFields (nBody nt)))) ] instance PP Import where ppPrec _ d = text "import" <+> sep [ pp (iModule d), mbAs, mbSpec ]@@ -732,6 +751,9 @@ EFromTo e1 e2 e3 t1 -> brackets (pp e1 <.> step <+> text ".." <+> end) where step = maybe empty (\e -> comma <+> pp e) e2 end = maybe (pp e3) (\t -> pp e3 <+> colon <+> pp t) t1+ EFromToLessThan e1 e2 t1 -> brackets (strt <+> text ".. <" <+> end)+ where strt = maybe (pp e1) (\t -> pp e1 <+> colon <+> pp t) t1+ end = pp e2 EInfFrom e1 e2 -> brackets (pp e1 <.> step <+> text "...") where step = maybe empty (\e -> comma <+> pp e) e2 EComp e mss -> brackets (pp e <+> vcat (map arm mss))@@ -744,7 +766,7 @@ ESel e l -> ppPrec 4 e <.> text "." <.> pp l -- low prec- EFun xs e -> wrap n 0 ((text "\\" <.> hsep (map (ppPrec 3) xs)) <+>+ EFun _ xs e -> wrap n 0 ((text "\\" <.> hsep (map (ppPrec 3) xs)) <+> text "->" <+> pp e) EIf e1 e2 e3 -> wrap n 0 $ sep [ text "if" <+> pp e1@@ -938,7 +960,7 @@ instance NoPos (Newtype name) where noPos n = Newtype { nName = noPos (nName n) , nParams = nParams n- , nBody = noPos (nBody n)+ , nBody = fmap noPos (nBody n) } instance NoPos (Bind name) where@@ -979,6 +1001,7 @@ EUpd x y -> EUpd (noPos x) (noPos y) EList x -> EList (noPos x) EFromTo x y z t -> EFromTo (noPos x) (noPos y) (noPos z) (noPos t)+ EFromToLessThan x y t -> EFromToLessThan (noPos x) (noPos y) (noPos t) EInfFrom x y -> EInfFrom (noPos x) (noPos y) EComp x y -> EComp (noPos x) (noPos y) EApp x y -> EApp (noPos x) (noPos y)@@ -987,7 +1010,7 @@ EWhere x y -> EWhere (noPos x) (noPos y) ETyped x y -> ETyped (noPos x) (noPos y) ETypeVal x -> ETypeVal (noPos x)- EFun x y -> EFun (noPos x) (noPos y)+ EFun dsc x y -> EFun dsc (noPos x) (noPos y) ELocated x _ -> noPos x ESplit x -> ESplit (noPos x)
src/Cryptol/Parser/Lexer.x view
@@ -142,6 +142,7 @@ "`" { emit $ Sym BackTick } ".." { emit $ Sym DotDot } "..." { emit $ Sym DotDotDot }+"..<" { emit $ Sym DotDotLt } "|" { emit $ Sym Bar } "(" { emit $ Sym ParenL } ")" { emit $ Sym ParenR }@@ -161,6 +162,9 @@ "*" { emit (Op Mul ) } "^^" { emit (Op Exp ) } +-- < can appear in the enumeration syntax `[ x .. < y ]+"<" { emit $ Sym Lt }+ -- hash is used as a kind, and as a pattern "#" { emit (Op Hash ) } @@ -202,7 +206,7 @@ primLexer :: Config -> Text -> ([Located Token], Position) primLexer cfg cs = run inp Normal where- inp = Inp { alexPos = start+ inp = Inp { alexPos = cfgStart cfg , alexInputPrevChar = '\n' , input = unLit (cfgPreProc cfg) cs }
src/Cryptol/Parser/LexerUtils.hs view
@@ -32,6 +32,7 @@ data Config = Config { cfgSource :: !FilePath -- ^ File that we are working on+ , cfgStart :: !Position -- ^ Starting position for the parser , cfgLayout :: !Layout -- ^ Settings for layout processing , cfgPreProc :: PreProc -- ^ Preprocessor settings , cfgAutoInclude :: [FilePath] -- ^ Implicit includes@@ -43,6 +44,7 @@ defaultConfig :: Config defaultConfig = Config { cfgSource = ""+ , cfgStart = start , cfgLayout = Layout , cfgPreProc = None , cfgAutoInclude = []@@ -522,12 +524,14 @@ | Dot | DotDot | DotDotDot+ | DotDotLt | Colon | BackTick | ParenL | ParenR | BracketL | BracketR | CurlyL | CurlyR | TriL | TriR+ | Lt | Underscore deriving (Eq, Show, Generic, NFData)
src/Cryptol/Parser/Names.hs view
@@ -84,6 +84,7 @@ in Set.unions (e : map namesUF fs) EList es -> Set.unions (map namesE es) EFromTo{} -> Set.empty+ EFromToLessThan{} -> Set.empty EInfFrom e e' -> Set.union (namesE e) (maybe Set.empty namesE e') EComp e arms -> let (dss,uss) = unzip (map namesArm arms) in Set.union (boundLNames (concat dss) (namesE e))@@ -95,7 +96,7 @@ in Set.union (boundLNames bs (namesE e)) xs ETyped e _ -> namesE e ETypeVal _ -> Set.empty- EFun ps e -> boundLNames (namesPs ps) (namesE e)+ EFun _ ps e -> boundLNames (namesPs ps) (namesE e) ELocated e _ -> namesE e ESplit e -> namesE e@@ -203,6 +204,8 @@ `Set.union` maybe Set.empty tnamesT b `Set.union` tnamesT c `Set.union` maybe Set.empty tnamesT t+ EFromToLessThan a b t -> tnamesT a `Set.union` tnamesT b+ `Set.union` maybe Set.empty tnamesT t EInfFrom e e' -> Set.union (tnamesE e) (maybe Set.empty tnamesE e') EComp e mss -> Set.union (tnamesE e) (Set.unions (map tnamesM (concat mss))) EApp e1 e2 -> Set.union (tnamesE e1) (tnamesE e2)@@ -212,7 +215,7 @@ in Set.union (boundLNames bs (tnamesE e)) xs ETyped e t -> Set.union (tnamesE e) (tnamesT t) ETypeVal t -> tnamesT t- EFun ps e -> Set.union (Set.unions (map tnamesP ps)) (tnamesE e)+ EFun _ ps e -> Set.union (Set.unions (map tnamesP ps)) (tnamesE e) ELocated e _ -> tnamesE e ESplit e -> tnamesE e
src/Cryptol/Parser/NoPat.hs view
@@ -154,6 +154,7 @@ EUpd mb fs -> EUpd <$> traverse noPatE mb <*> traverse noPatUF fs EList es -> EList <$> mapM noPatE es EFromTo {} -> return expr+ EFromToLessThan{} -> return expr EInfFrom e e' -> EInfFrom <$> noPatE e <*> traverse noPatE e' EComp e mss -> EComp <$> noPatE e <*> mapM noPatArm mss EApp e1 e2 -> EApp <$> noPatE e1 <*> noPatE e2@@ -162,8 +163,7 @@ EWhere e ds -> EWhere <$> noPatE e <*> noPatDs ds ETyped e t -> ETyped <$> noPatE e <*> return t ETypeVal {} -> return expr- EFun ps e -> do (ps1,e1) <- noPatFun ps e- return (EFun ps1 e1)+ EFun desc ps e -> noPatFun (funDescrName desc) (funDescrArgOffset desc) ps e ELocated e r1 -> ELocated <$> inRange r1 (noPatE e) <*> return r1 ESplit e -> ESplit <$> noPatE e@@ -174,15 +174,26 @@ noPatUF :: UpdField PName -> NoPatM (UpdField PName) noPatUF (UpdField h ls e) = UpdField h ls <$> noPatE e -noPatFun :: [Pattern PName] -> Expr PName -> NoPatM ([Pattern PName], Expr PName)-noPatFun ps e =- do (xs,bs) <- unzip <$> mapM noPat ps- e1 <- noPatE e- let body = case concat bs of- [] -> e1- ds -> EWhere e1 $ map DBind ds- return (xs, body)-+-- Desugar lambdas with multiple patterns into a sequence of+-- lambdas with a single, simple pattern each. Bindings required+-- to simplify patterns are placed inside "where" blocks that are+-- interspersed into the lambdas to ensure that the lexical+-- structure is reliable, with names on the right shadowing names+-- on the left.+noPatFun :: Maybe PName -> Int -> [Pattern PName] -> Expr PName -> NoPatM (Expr PName)+noPatFun _ _ [] e = noPatE e+noPatFun mnm offset (p:ps) e =+ do (p',ds) <- noPat p+ e' <- noPatFun mnm (offset+1) ps e+ let body = case ds of+ [] -> e'+ _ -> EWhere e' $ map DBind (reverse ds)+ -- ^+ -- This reverse isn't strictly necessary, but yields more sensible+ -- variable ordering results from type inference. I'm not entirely+ -- sure why.+ let desc = FunDesc mnm offset+ return (EFun desc [p'] body) noPatArm :: [Match PName] -> NoPatM [Match PName] noPatArm ms = concat <$> mapM noPatM ms@@ -203,8 +214,8 @@ , show b ] DExpr e ->- do (ps,e') <- noPatFun (bParams b) e- return b { bParams = ps, bDef = DExpr e' <$ bDef b }+ do e' <- noPatFun (Just (thing (bName b))) 0 (bParams b) e+ return b { bParams = [], bDef = DExpr e' <$ bDef b } noMatchD :: Decl PName -> NoPatM [Decl PName] noMatchD decl =
src/Cryptol/Parser/ParserUtils.hs view
@@ -17,6 +17,8 @@ import Data.Maybe(fromMaybe) import Data.Bits(testBit,setBit)+import Data.List.NonEmpty ( NonEmpty(..) )+import qualified Data.List.NonEmpty as NE import Control.Monad(liftM,ap,unless,guard) import qualified Control.Monad.Fail as Fail import Data.Text(Text)@@ -65,7 +67,7 @@ case sTokens s of t : _ | Err e <- tokenType it -> Left $ HappyErrorMsg (srcRange t) $- case e of+ [case e of UnterminatedComment -> "unterminated comment" UnterminatedString -> "unterminated string" UnterminatedChar -> "unterminated character"@@ -79,6 +81,7 @@ T.unpack (tokenText it) MalformedSelector -> "malformed selector: " ++ T.unpack (tokenText it)+ ] where it = thing t t : more -> unP (k t) cfg p s { sPrevTok = Just t, sTokens = more }@@ -86,7 +89,7 @@ data ParseError = HappyError FilePath {- Name of source file -} (Located Token) {- Offending token -}- | HappyErrorMsg Range String+ | HappyErrorMsg Range [String] | HappyUnexpected FilePath (Maybe (Located Token)) String | HappyOutOfTokens FilePath Position deriving (Show, Generic, NFData)@@ -123,7 +126,7 @@ text "Unexpected end of file at:" <+> text path <.> char ':' <.> pp pos -ppError (HappyErrorMsg p x) = text "Parse error at" <+> pp p $$ nest 2 (text x)+ppError (HappyErrorMsg p xs) = text "Parse error at" <+> pp p $$ nest 2 (vcat (map text xs)) ppError (HappyUnexpected path ltok e) = text "Parse error at" <+>@@ -159,13 +162,13 @@ case sPrevTok s of Just t -> Left (HappyError (cfgSource cfg) t) Nothing ->- Left (HappyErrorMsg emptyRange "Parse error at the beginning of the file")+ Left (HappyErrorMsg emptyRange ["Parse error at the beginning of the file"]) -errorMessage :: Range -> String -> ParseM a-errorMessage r x = P $ \_ _ _ -> Left (HappyErrorMsg r x)+errorMessage :: Range -> [String] -> ParseM a+errorMessage r xs = P $ \_ _ _ -> Left (HappyErrorMsg r xs) customError :: String -> Located Token -> ParseM a-customError x t = P $ \_ _ _ -> Left (HappyErrorMsg (srcRange t) x)+customError x t = P $ \_ _ _ -> Left (HappyErrorMsg (srcRange t) [x]) expected :: String -> ParseM a expected x = P $ \cfg _ s ->@@ -231,19 +234,19 @@ intVal tok = case tokenType (thing tok) of Num x _ _ -> return x- _ -> errorMessage (srcRange tok) "Expected an integer"+ _ -> errorMessage (srcRange tok) ["Expected an integer"] mkFixity :: Assoc -> Located Token -> [LPName] -> ParseM (Decl PName) mkFixity assoc tok qns = do l <- intVal tok unless (l >= 1 && l <= 100)- (errorMessage (srcRange tok) "Fixity levels must be between 1 and 100")+ (errorMessage (srcRange tok) ["Fixity levels must be between 1 and 100"]) return (DFixity (Fixity assoc (fromInteger l)) qns) fromStrLit :: Located Token -> ParseM (Located String) fromStrLit loc = case tokenType (thing loc) of StrLit str -> return loc { thing = str }- _ -> errorMessage (srcRange loc) "Expected a string literal"+ _ -> errorMessage (srcRange loc) ["Expected a string literal"] validDemotedType :: Range -> Type PName -> ParseM (Type PName)@@ -264,14 +267,14 @@ TParens t -> validDemotedType rng t TInfix{} -> ok - where bad x = errorMessage rng (x ++ " cannot be demoted.")+ where bad x = errorMessage rng [x ++ " cannot be demoted."] ok = return $ at rng ty -- | Input fields are reversed! mkRecord :: AddLoc b => Range -> (RecordMap Ident (Range, a) -> b) -> [Named a] -> ParseM b mkRecord rng f xs = case res of- Left (nm,(nmRng,_)) -> errorMessage nmRng ("Record has repeated field: " ++ show (pp nm))+ Left (nm,(nmRng,_)) -> errorMessage nmRng ["Record has repeated field: " ++ show (pp nm)] Right r -> pure $ at rng (f r) where@@ -280,11 +283,14 @@ -- | Input expression are reversed-mkEApp :: [Expr PName] -> Expr PName-mkEApp es@(eLast : _) = at (eFirst,eLast) $ foldl EApp f xs+mkEApp :: NonEmpty (Expr PName) -> ParseM (Expr PName)++mkEApp es@(eLast :| _) =+ do f :| xs <- cvtTypeParams eFirst rest+ pure (at (eFirst,eLast) $ foldl EApp f xs)+ where- eFirst : rest = reverse es- f : xs = cvtTypeParams eFirst rest+ eFirst :| rest = NE.reverse es {- Type applications are parsed as `ETypeVal (TTyApp fs)` expressions. Here we associate them with their corresponding functions,@@ -293,23 +299,62 @@ [ f, x, `{ a = 2 }, y ] becomes [ f, x ` { a = 2 }, y ]++ The parser associates field and tuple projectors that follow an+ explicit type application onto the TTyApp term, so we also+ have to unwind those projections and reapply them. For example:++ [ f, x, `{ a = 2 }.f.2, y ]+ becomes+ [ f, (x`{ a = 2 }).f.2, y ]+ -}- cvtTypeParams e [] = [e]+ cvtTypeParams e [] = pure (e :| []) cvtTypeParams e (p : ps) =- case toTypeParam p of- Just fs -> cvtTypeParams (EAppT e fs) ps- Nothing -> e : cvtTypeParams p ps+ case toTypeParam p Nothing of+ Nothing -> NE.cons e <$> cvtTypeParams p ps - toTypeParam e =- case dropLoc e of- ETypeVal t -> case dropLoc t of- TTyApp fs -> Just (map mkTypeInst fs)- _ -> Nothing- _ -> Nothing+ Just (fs,ss,rng) ->+ if checkAppExpr e then+ let e' = foldr (flip ESel) (EAppT e fs) ss+ e'' = case rCombMaybe (getLoc e) rng of+ Just r -> ELocated e' r+ Nothing -> e'+ in cvtTypeParams e'' ps+ else+ errorMessage (fromMaybe emptyRange (getLoc e))+ [ "Explicit type applications can only be applied to named values."+ , "Unexpected: " ++ show (pp e)+ ] -mkEApp es = panic "[Parser] mkEApp" ["Unexpected:", show es]+ {- Check if the given expression is a legal target for explicit type application.+ This is basically only variables, but we also allow the parenthesis and+ the phantom "located" AST node.+ -}+ checkAppExpr e =+ case e of+ ELocated e' _ -> checkAppExpr e'+ EParens e' -> checkAppExpr e'+ EVar{} -> True+ _ -> False + {- Look under a potential chain of selectors to see if we have a TTyApp.+ If so, return the ty app information and the collected selectors+ to reapply.+ -}+ toTypeParam e mr =+ case e of+ ELocated e' rng -> toTypeParam e' (rCombMaybe mr (Just rng))+ ETypeVal t -> toTypeParam' t mr+ ESel e' s -> ( \(fs,ss,r) -> (fs,s:ss,r) ) <$> toTypeParam e' mr+ _ -> Nothing + toTypeParam' t mr =+ case t of+ TLocated t' rng -> toTypeParam' t' (rCombMaybe mr (Just rng))+ TTyApp fs -> Just (map mkTypeInst fs, [], mr)+ _ -> Nothing+ unOp :: Expr PName -> Expr PName -> Expr PName unOp f x = at (f,x) $ EApp f x @@ -325,12 +370,13 @@ (Nothing, Just (e2', t), Nothing) -> eFromToType r e1 (Just e2') e3 (Just t) (Nothing, Nothing, Just (e3', t)) -> eFromToType r e1 e2 e3' (Just t) (Nothing, Nothing, Nothing) -> eFromToType r e1 e2 e3 Nothing- _ -> errorMessage r "A sequence enumeration may have at most one element type annotation."- where- asETyped (ELocated e _) = asETyped e- asETyped (ETyped e t) = Just (e, t)- asETyped _ = Nothing+ _ -> errorMessage r ["A sequence enumeration may have at most one element type annotation."] +asETyped :: Expr n -> Maybe (Expr n, Type n)+asETyped (ELocated e _) = asETyped e+asETyped (ETyped e t) = Just (e, t)+asETyped _ = Nothing+ eFromToType :: Range -> Expr PName -> Maybe (Expr PName) -> Expr PName -> Maybe (Type PName) -> ParseM (Expr PName) eFromToType r e1 e2 e3 t =@@ -339,22 +385,40 @@ <*> exprToNumT r e3 <*> pure t +eFromToLessThan ::+ Range -> Expr PName -> Expr PName -> ParseM (Expr PName)+eFromToLessThan r e1 e2 =+ case asETyped e2 of+ Just _ -> errorMessage r ["The exclusive upper bound of an enumeration may not have a type annotation."]+ Nothing ->+ case asETyped e1 of+ Nothing -> eFromToLessThanType r e1 e2 Nothing+ Just (e1',t) -> eFromToLessThanType r e1' e2 (Just t)++eFromToLessThanType ::+ Range -> Expr PName -> Expr PName -> Maybe (Type PName) -> ParseM (Expr PName)+eFromToLessThanType r e1 e2 t =+ EFromToLessThan+ <$> exprToNumT r e1+ <*> exprToNumT r e2+ <*> pure t+ exprToNumT :: Range -> Expr PName -> ParseM (Type PName) exprToNumT r expr = case translateExprToNumT expr of Just t -> return t Nothing -> bad where- bad = errorMessage (fromMaybe r (getLoc expr)) $ unlines+ bad = errorMessage (fromMaybe r (getLoc expr)) [ "The boundaries of .. sequences should be valid numeric types."- , "The expression `" ++ show expr ++ "` is not."+ , "The expression `" ++ show (pp expr) ++ "` is not." ] -- | WARNING: This is a bit of a hack. -- It is used to represent anonymous type applications. anonTyApp :: Maybe Range -> [Type PName] -> Type PName-anonTyApp ~(Just r) ts = TTyApp (map toField ts)+anonTyApp ~(Just r) ts = TLocated (TTyApp (map toField ts)) r where noName = Located { srcRange = r, thing = mkIdent (T.pack "") } toField t = Named { name = noName, value = t } @@ -413,13 +477,13 @@ mkTParam :: Located Ident -> Maybe Kind -> ParseM (TParam PName) mkTParam Located { srcRange = rng, thing = n } k- | n == widthIdent = errorMessage rng "`width` is not a valid type parameter name."+ | n == widthIdent = errorMessage rng ["`width` is not a valid type parameter name."] | otherwise = return (TParam (mkUnqual n) k (Just rng)) mkTySyn :: Located PName -> [TParam PName] -> Type PName -> ParseM (Decl PName) mkTySyn ln ps b | getIdent (thing ln) == widthIdent =- errorMessage (srcRange ln) "`width` is not a valid type synonym name."+ errorMessage (srcRange ln) ["`width` is not a valid type synonym name."] | otherwise = return $ DType $ TySyn ln Nothing ps b@@ -427,7 +491,7 @@ mkPropSyn :: Located PName -> [TParam PName] -> Type PName -> ParseM (Decl PName) mkPropSyn ln ps b | getIdent (thing ln) == widthIdent =- errorMessage (srcRange ln) "`width` is not a valid constraint synonym name."+ errorMessage (srcRange ln) ["`width` is not a valid constraint synonym name."] | otherwise = DProp . PropSyn ln Nothing ps . thing <$> mkProp b@@ -436,12 +500,12 @@ polyTerm rng k p | k == 0 = return (False, p) | k == 1 = return (True, p)- | otherwise = errorMessage rng "Invalid polynomial coefficient"+ | otherwise = errorMessage rng ["Invalid polynomial coefficient"] mkPoly :: Range -> [ (Bool,Integer) ] -> ParseM (Expr PName) mkPoly rng terms | w <= toInteger (maxBound :: Int) = mk 0 (map fromInteger bits)- | otherwise = errorMessage rng ("Polynomial literal too large: " ++ show w)+ | otherwise = errorMessage rng ["Polynomial literal too large: " ++ show w] where w = case terms of@@ -455,8 +519,7 @@ mk res (n : ns) | testBit res n = errorMessage rng- ("Polynomial contains multiple terms with exponent "- ++ show n)+ ["Polynomial contains multiple terms with exponent " ++ show n] | otherwise = mk (setBit res n) ns @@ -495,11 +558,11 @@ mkIndexedExpr :: ([Pattern PName], [Pattern PName]) -> Expr PName -> Expr PName mkIndexedExpr (ps, ixs) body | null ps = mkGenerate (reverse ixs) body- | otherwise = EFun (reverse ps) (mkGenerate (reverse ixs) body)+ | otherwise = EFun emptyFunDesc (reverse ps) (mkGenerate (reverse ixs) body) mkGenerate :: [Pattern PName] -> Expr PName -> Expr PName mkGenerate pats body =- foldr (\pat e -> EGenerate (EFun [pat] e)) body pats+ foldr (\pat e -> EGenerate (EFun emptyFunDesc [pat] e)) body pats mkIf :: [(Expr PName, Expr PName)] -> Expr PName -> Expr PName mkIf ifThens theElse = foldr addIfThen theElse ifThens@@ -540,17 +603,17 @@ Just (n,xs) -> do vs <- mapM tpK as unless (distinct (map fst vs)) $- errorMessage schema_rng "Repeated parameters."+ errorMessage schema_rng ["Repeated parameters."] let kindMap = Map.fromList vs lkp v = case Map.lookup (thing v) kindMap of Just (k,tp) -> pure (k,tp) Nothing -> errorMessage (srcRange v)- ("Undefined parameter: " ++ show (pp (thing v)))+ ["Undefined parameter: " ++ show (pp (thing v))] (as',ins) <- unzip <$> mapM lkp xs unless (length vs == length xs) $- errorMessage schema_rng "All parameters should appear in the type."+ errorMessage schema_rng ["All parameters should appear in the type."] let ki = finK { thing = foldr KFun (thing finK) ins } @@ -565,7 +628,7 @@ } ] - Nothing -> errorMessage schema_rng "Invalid primitive signature"+ Nothing -> errorMessage schema_rng ["Invalid primitive signature"] where splitT r ty = case ty of@@ -592,7 +655,7 @@ Just k -> pure (tpName tp, (tp,k)) Nothing -> case tpRange tp of- Just r -> errorMessage r "Parameters need a kind annotation"+ Just r -> errorMessage r ["Parameters need a kind annotation"] Nothing -> panic "mkPrimTypeDecl" [ "Missing range on schema parameter." ] @@ -671,7 +734,7 @@ TTyApp{} -> err where- err = errorMessage r "Invalid constraint"+ err = errorMessage r ["Invalid constraint"] -- | Make an ordinary module mkModule :: Located ModName ->@@ -708,7 +771,7 @@ (UpdSet, [l]) | RecordSel i Nothing <- thing l -> pure Named { name = l { thing = i }, value = e } _ -> errorMessage (srcRange (head ls))- "Invalid record field. Perhaps you meant to update a record?"+ ["Invalid record field. Perhaps you meant to update a record?"] exprToFieldPath :: Expr PName -> ParseM [Located Selector] exprToFieldPath e0 = reverse <$> go noLoc e0@@ -744,7 +807,7 @@ } ] - _ -> errorMessage loc "Invalid label in record update."+ _ -> errorMessage loc ["Invalid label in record update."] mkSelector :: Token -> Selector@@ -754,4 +817,3 @@ Selector (RecordSelectorTok t) -> RecordSel (mkIdent t) Nothing _ -> panic "mkSelector" [ "Unexpected selector token", show tok ]-
src/Cryptol/Parser/Position.hs view
@@ -57,6 +57,11 @@ where rFrom = min (from r1) (from r2) rTo = max (to r1) (to r2) +rCombMaybe :: Maybe Range -> Maybe Range -> Maybe Range+rCombMaybe Nothing y = y+rCombMaybe x Nothing = x+rCombMaybe (Just x) (Just y) = Just (rComb x y)+ rCombs :: [Range] -> Range rCombs = foldl1 rComb @@ -123,5 +128,4 @@ combLoc f l1 l2 = Located { srcRange = rComb (srcRange l1) (srcRange l2) , thing = f (thing l1) (thing l2) }-
src/Cryptol/REPL/Command.hs view
@@ -6,6 +6,8 @@ -- Stability : provisional -- Portability : portable +{-# LANGUAGE BangPatterns #-}+{-# LANGUAGE BlockArguments #-} {-# LANGUAGE FlexibleContexts #-} {-# LANGUAGE LambdaCase #-} {-# LANGUAGE MultiWayIf #-}@@ -34,7 +36,8 @@ , replCheckExpr -- Check, SAT, and prove- , qcCmd, QCMode(..)+ , TestReport(..)+ , qcExpr, qcCmd, QCMode(..) , satCmd , proveCmd , onlineProveSat@@ -72,6 +75,7 @@ import Cryptol.Parser (parseExprWith,parseReplWith,ParseError(),Config(..),defaultConfig ,parseModName,parseHelpName)+import Cryptol.Parser.Position (Position(..),Range(..),HasLoc(..)) import qualified Cryptol.TypeCheck.AST as T import qualified Cryptol.TypeCheck.Error as T import qualified Cryptol.TypeCheck.Parseable as T@@ -135,7 +139,7 @@ -- | Commands. data Command- = Command (REPL ()) -- ^ Successfully parsed command+ = Command (Int -> Maybe FilePath -> REPL ()) -- ^ Successfully parsed command | Ambiguous String [String] -- ^ Ambiguous command, list of conflicting -- commands | Unknown String -- ^ The unknown command@@ -159,8 +163,8 @@ compare = compare `on` cNames data CommandBody- = ExprArg (String -> REPL ())- | FileExprArg (FilePath -> String -> REPL ())+ = ExprArg (String -> (Int,Int) -> Maybe FilePath -> REPL ())+ | FileExprArg (FilePath -> String -> (Int,Int) -> Maybe FilePath -> REPL ()) | DeclsArg (String -> REPL ()) | ExprTypeArg (String -> REPL ()) | ModNameArg (String -> REPL ())@@ -214,10 +218,10 @@ , CommandDescr [ ":s", ":set" ] ["[ OPTION [ = VALUE ] ]"] (OptionArg setOptionCmd) "Set an environmental option (:set on its own displays current values)." ""- , CommandDescr [ ":check" ] ["[ EXPR ]"] (ExprArg (void . qcCmd QCRandom))+ , CommandDescr [ ":check" ] ["[ EXPR ]"] (ExprArg (qcCmd QCRandom)) "Use random testing to check that the argument always returns true.\n(If no argument, check all properties.)" ""- , CommandDescr [ ":exhaust" ] ["[ EXPR ]"] (ExprArg (void . qcCmd QCExhaust))+ , CommandDescr [ ":exhaust" ] ["[ EXPR ]"] (ExprArg (qcCmd QCExhaust)) "Use exhaustive testing to prove that the argument always returns\ntrue. (If no argument, check all properties.)" "" , CommandDescr [ ":prove" ] ["[ EXPR ]"] (ExprArg proveCmd)@@ -295,10 +299,10 @@ -- Command Evaluation ---------------------------------------------------------- -- | Run a command.-runCommand :: Command -> REPL CommandExitCode-runCommand c = case c of+runCommand :: Int -> Maybe FilePath -> Command -> REPL CommandExitCode+runCommand lineNum mbBatch c = case c of - Command cmd -> (cmd >> return CommandOk) `Cryptol.REPL.Monad.catch` handler+ Command cmd -> (cmd lineNum mbBatch >> return CommandOk) `Cryptol.REPL.Monad.catch` handler where handler re = rPutStrLn "" >> rPrint (pp re) >> return CommandError @@ -311,36 +315,9 @@ return CommandError --- Get the setting we should use for displaying values.-getPPValOpts :: REPL E.PPOpts-getPPValOpts =- do base <- getKnownUser "base"- ascii <- getKnownUser "ascii"- infLength <- getKnownUser "infLength"-- fpBase <- getKnownUser "fp-base"- fpFmtTxt <- getKnownUser "fp-format"- let fpFmt = case parsePPFloatFormat fpFmtTxt of- Just f -> f- Nothing -> panic "getPPValOpts"- [ "Failed to parse fp-format" ]-- return E.PPOpts { E.useBase = base- , E.useAscii = ascii- , E.useInfLength = infLength- , E.useFPBase = fpBase- , E.useFPFormat = fpFmt- }--getEvalOpts :: REPL E.EvalOpts-getEvalOpts =- do ppOpts <- getPPValOpts- l <- getLogger- return E.EvalOpts { E.evalPPOpts = ppOpts, E.evalLogger = l }--evalCmd :: String -> REPL ()-evalCmd str = do- ri <- replParseInput str+evalCmd :: String -> Int -> Maybe FilePath -> REPL ()+evalCmd str lineNum mbBatch = do+ ri <- replParseInput str lineNum mbBatch case ri of P.ExprInput expr -> do (val,_ty) <- replEvalExpr expr@@ -363,27 +340,25 @@ -- comment or empty input does nothing pure () -printCounterexample :: CounterExampleType -> P.Expr P.PName -> [Concrete.Value] -> REPL ()-printCounterexample cexTy pexpr vs =+printCounterexample :: CounterExampleType -> Doc -> [Concrete.Value] -> REPL ()+printCounterexample cexTy exprDoc vs = do ppOpts <- getPPValOpts docs <- mapM (rEval . E.ppValue Concrete ppOpts) vs- let doc = ppPrec 3 pexpr -- function application has precedence 3- rPrint $ hang doc 2 (sep docs) <+>+ rPrint $ hang exprDoc 2 (sep docs) <+> case cexTy of SafetyViolation -> text "~> ERROR" PredicateFalsified -> text "= False" -printSatisfyingModel :: P.Expr P.PName -> [Concrete.Value] -> REPL ()-printSatisfyingModel pexpr vs =+printSatisfyingModel :: Doc -> [Concrete.Value] -> REPL ()+printSatisfyingModel exprDoc vs = do ppOpts <- getPPValOpts docs <- mapM (rEval . E.ppValue Concrete ppOpts) vs- let doc = ppPrec 3 pexpr -- function application has precedence 3- rPrint $ hang doc 2 (sep docs) <+> text ("= True")+ rPrint $ hang exprDoc 2 (sep docs) <+> text ("= True") -dumpTestsCmd :: FilePath -> String -> REPL ()-dumpTestsCmd outFile str =- do expr <- replParseExpr str+dumpTestsCmd :: FilePath -> String -> (Int,Int) -> Maybe FilePath -> REPL ()+dumpTestsCmd outFile str pos fnm =+ do expr <- replParseExpr str pos fnm (val, ty) <- replEvalExpr expr ppopts <- getPPValOpts testNum <- getKnownUser "tests" :: REPL Int@@ -409,28 +384,54 @@ data QCMode = QCRandom | QCExhaust deriving (Eq, Show) + -- | Randomly test a property, or exhaustively check it if the number -- of values in the type under test is smaller than the @tests@ -- environment variable, or we specify exhaustive testing.-qcCmd :: QCMode -> String -> REPL [TestReport]-qcCmd qcMode "" =+qcCmd :: QCMode -> String -> (Int,Int) -> Maybe FilePath -> REPL ()+qcCmd qcMode "" _pos _fnm = do (xs,disp) <- getPropertyNames let nameStr x = show (fixNameDisp disp (pp x)) if null xs- then rPutStrLn "There are no properties in scope." *> return []- else concat <$> (forM xs $ \x ->+ then rPutStrLn "There are no properties in scope."+ else forM_ xs $ \(x,d) -> do let str = nameStr x rPutStr $ "property " ++ str ++ " "- qcCmd qcMode str)+ let texpr = T.EVar x+ let schema = M.ifDeclSig d+ nd <- M.mctxNameDisp <$> getFocusedEnv+ let doc = fixNameDisp nd (pp texpr)+ void (qcExpr qcMode doc texpr schema) -qcCmd qcMode str =- do expr <- replParseExpr str- (val,ty) <- replEvalExpr expr+qcCmd qcMode str pos fnm =+ do expr <- replParseExpr str pos fnm+ (_,texpr,schema) <- replCheckExpr expr+ nd <- M.mctxNameDisp <$> getFocusedEnv+ let doc = fixNameDisp nd (ppPrec 3 expr) -- function application has precedence 3+ void (qcExpr qcMode doc texpr schema)+++data TestReport = TestReport+ { reportExpr :: Doc+ , reportResult :: TestResult+ , reportTestsRun :: Integer+ , reportTestsPossible :: Maybe Integer+ }++qcExpr ::+ QCMode ->+ Doc ->+ T.Expr ->+ T.Schema ->+ REPL TestReport+qcExpr qcMode exprDoc texpr schema =+ do (val,ty) <- replEvalCheckedExpr texpr schema testNum <- (toInteger :: Int -> Integer) <$> getKnownUser "tests" tenv <- E.envTypes . M.deEnv <$> getDynEnv let tyv = E.evalValType tenv ty percentRef <- io $ newIORef Nothing testsRef <- io $ newIORef 0+ case testableType tyv of Just (Just sz,tys,vss,_gens) | qcMode == QCExhaust || sz <= testNum -> do rPutStrLn "Using exhaustive testing."@@ -440,15 +441,15 @@ val vss) (\ex -> do rPutStrLn "\nTest interrupted..." num <- io $ readIORef testsRef- let report = TestReport Pass str num (Just sz)- ppReport (map E.tValTy tys) expr False report+ let report = TestReport exprDoc Pass num (Just sz)+ ppReport tys False report rPutStrLn $ interruptedExhaust num sz Ex.throwM (ex :: Ex.SomeException))- let report = TestReport res str num (Just sz)+ let report = TestReport exprDoc res num (Just sz) delProgress delTesting- ppReport (map E.tValTy tys) expr True report- return [report]+ ppReport tys True report+ return report Just (sz,tys,_,gens) | qcMode == QCRandom -> do rPutStrLn "Using random testing."@@ -459,20 +460,20 @@ testNum val gens g) (\ex -> do rPutStrLn "\nTest interrupted..." num <- io $ readIORef testsRef- let report = TestReport Pass str num sz- ppReport (map E.tValTy tys) expr False report+ let report = TestReport exprDoc Pass num sz+ ppReport tys False report case sz of Just n -> rPutStrLn $ coverageString num n _ -> return () Ex.throwM (ex :: Ex.SomeException))- let report = TestReport res str num sz+ let report = TestReport exprDoc res num sz delProgress delTesting- ppReport (map E.tValTy tys) expr False report+ ppReport tys False report case sz of Just n | isPass res -> rPutStrLn $ coverageString testNum n _ -> return ()- return [report]+ return report _ -> raise (TypeNotTestable ty) where@@ -502,7 +503,6 @@ ++ showValNum ++ " values)" - totProgressWidth = 4 -- 100% lg2 :: Integer -> Integer@@ -512,7 +512,6 @@ in round $ logBase 2 valNumD :: Integer prt msg = rPutStr msg >> io (hFlush stdout)- prtLn msg = rPutStrLn msg >> io (hFlush stdout) ppProgress percentRef testsRef this tot = do io $ writeIORef testsRef this@@ -536,34 +535,45 @@ delTesting = del (length testingMsg) delProgress = del totProgressWidth - ppReport _tys _expr isExhaustive (TestReport Pass _str testNum _testPossible) =- do prtLn $ "Passed " ++ show testNum ++ " tests."++ppReport :: [E.TValue] -> Bool -> TestReport -> REPL ()+ppReport _tys isExhaustive (TestReport _exprDoc Pass testNum _testPossible) =+ do rPutStrLn ("Passed " ++ show testNum ++ " tests.") when isExhaustive (rPutStrLn "Q.E.D.")- ppReport tys expr _ (TestReport failure _str _testNum _testPossible) =- ppFailure tys expr failure+ppReport tys _ (TestReport exprDoc failure _testNum _testPossible) =+ do ppFailure tys exprDoc failure - ppFailure tys pexpr failure = do- opts <- getPPValOpts- case failure of- FailFalse vs -> do- printCounterexample PredicateFalsified pexpr vs- case (tys,vs) of- ([t],[v]) -> bindItVariableVal t v- _ -> let fs = [ M.packIdent ("arg" ++ show (i::Int)) | i <- [ 1 .. ] ]- t = T.TRec (recordFromFields (zip fs tys))- v = E.VRecord (recordFromFields (zip fs (map return vs)))- in bindItVariableVal t v+ppFailure :: [E.TValue] -> Doc -> TestResult -> REPL ()+ppFailure tys exprDoc failure = do+ ~(EnvBool showEx) <- getUser "showExamples" - FailError err [] -> do- prtLn "ERROR"- rPrint (pp err)- FailError err vs -> do- prtLn "ERROR for the following inputs:"- mapM_ (\v -> rPrint =<< (rEval $ E.ppValue Concrete opts v)) vs- rPrint (pp err)- Pass -> panic "Cryptol.REPL.Command" ["unexpected Test.Pass"]+ vs <- case failure of+ FailFalse vs ->+ do rPutStrLn "Counterexample"+ when showEx (printCounterexample PredicateFalsified exprDoc vs)+ pure vs+ FailError err vs+ | null vs || not showEx ->+ do rPutStrLn "ERROR"+ rPrint (pp err)+ pure vs+ | otherwise ->+ do rPutStrLn "ERROR for the following inputs:"+ printCounterexample SafetyViolation exprDoc vs+ rPrint (pp err)+ pure vs + Pass -> panic "Cryptol.REPL.Command" ["unexpected Test.Pass"] + -- bind the 'it' variable+ case (tys,vs) of+ ([t],[v]) -> bindItVariableVal t v+ _ -> let fs = [ M.packIdent ("arg" ++ show (i::Int)) | i <- [ 1 .. ] ]+ t = E.TVRec (recordFromFields (zip fs tys))+ v = E.VRecord (recordFromFields (zip fs (map return vs)))+ in bindItVariableVal t v++ -- | This function computes the expected coverage percentage and -- expected number of unique test vectors when using random testing. --@@ -606,7 +616,7 @@ proportion = negate (expm1 (numD * log1p (negate (recip szD)))) -satCmd, proveCmd :: String -> REPL ()+satCmd, proveCmd :: String -> (Int,Int) -> Maybe FilePath -> REPL () satCmd = cmdProveSat True proveCmd = cmdProveSat False @@ -628,16 +638,22 @@ ] -- | Attempts to prove the given term is safe for all inputs-safeCmd :: String -> REPL ()-safeCmd str = do+safeCmd :: String -> (Int,Int) -> Maybe FilePath -> REPL ()+safeCmd str pos fnm = do proverName <- getKnownUser "prover"- fileName <- getKnownUser "smtfile"+ fileName <- getKnownUser "smtFile" let mfile = if fileName == "-" then Nothing else Just fileName+ pexpr <- replParseExpr str pos fnm+ nd <- M.mctxNameDisp <$> getFocusedEnv+ let exprDoc = fixNameDisp nd (ppPrec 3 pexpr) -- function application has precedence 3 + let rng = fromMaybe (mkInteractiveRange pos fnm) (getLoc pexpr)+ (_,texpr,schema) <- replCheckExpr pexpr+ if proverName `elem` ["offline","sbv-offline","w4-offline"] then- offlineProveSat proverName SafetyQuery str mfile+ offlineProveSat proverName SafetyQuery texpr schema mfile else- do (firstProver,result,stats) <- rethrowErrorCall (onlineProveSat proverName SafetyQuery str mfile)+ do (firstProver,result,stats) <- rethrowErrorCall (onlineProveSat proverName SafetyQuery texpr schema mfile) case result of EmptyResult -> panic "REPL.Command" [ "got EmptyResult for online prover query" ]@@ -651,11 +667,11 @@ let tes = map ( \(t,e,_) -> (t,e)) tevs vs = map ( \(_,_,v) -> v) tevs - (t,e) <- mkSolverResult "counterexample" False (Right tes)- pexpr <- replParseExpr str+ (t,e) <- mkSolverResult "counterexample" rng False (Right tes) - ~(EnvBool yes) <- getUser "show-examples"- when yes $ printCounterexample cexType pexpr vs+ ~(EnvBool yes) <- getUser "showExamples"+ when yes $ printCounterexample cexType exprDoc vs+ when yes $ printSafetyViolation texpr schema vs void $ bindItVariable t e @@ -670,30 +686,50 @@ -- console, and binds the @it@ variable to a record whose form depends -- on the expression given. See ticket #66 for a discussion of this -- design.-cmdProveSat :: Bool -> String -> REPL ()-cmdProveSat isSat "" =+cmdProveSat :: Bool -> String -> (Int,Int) -> Maybe FilePath -> REPL ()+cmdProveSat isSat "" _pos _fnm = do (xs,disp) <- getPropertyNames let nameStr x = show (fixNameDisp disp (pp x)) if null xs then rPutStrLn "There are no properties in scope."- else forM_ xs $ \x ->+ else forM_ xs $ \(x,d) -> do let str = nameStr x if isSat then rPutStr $ ":sat " ++ str ++ "\n\t" else rPutStr $ ":prove " ++ str ++ "\n\t"- cmdProveSat isSat str-cmdProveSat isSat str = do+ let texpr = T.EVar x+ let schema = M.ifDeclSig d+ nd <- M.mctxNameDisp <$> getFocusedEnv+ let doc = fixNameDisp nd (pp texpr)+ proveSatExpr isSat (M.nameLoc x) doc texpr schema++cmdProveSat isSat str pos fnm = do+ pexpr <- replParseExpr str pos fnm+ nd <- M.mctxNameDisp <$> getFocusedEnv+ let doc = fixNameDisp nd (ppPrec 3 pexpr) -- function application has precedence 3+ (_,texpr,schema) <- replCheckExpr pexpr+ let rng = fromMaybe (mkInteractiveRange pos fnm) (getLoc pexpr)+ proveSatExpr isSat rng doc texpr schema++proveSatExpr ::+ Bool ->+ Range ->+ Doc ->+ T.Expr ->+ T.Schema ->+ REPL ()+proveSatExpr isSat rng exprDoc texpr schema = do let cexStr | isSat = "satisfying assignment" | otherwise = "counterexample" qtype <- if isSat then SatQuery <$> getUserSatNum else pure ProveQuery proverName <- getKnownUser "prover"- fileName <- getKnownUser "smtfile"+ fileName <- getKnownUser "smtFile" let mfile = if fileName == "-" then Nothing else Just fileName if proverName `elem` ["offline","sbv-offline","w4-offline"] then- offlineProveSat proverName qtype str mfile+ offlineProveSat proverName qtype texpr schema mfile else- do (firstProver,result,stats) <- rethrowErrorCall (onlineProveSat proverName qtype str mfile)+ do (firstProver,result,stats) <- rethrowErrorCall (onlineProveSat proverName qtype texpr schema mfile) case result of EmptyResult -> panic "REPL.Command" [ "got EmptyResult for online prover query" ]@@ -702,7 +738,7 @@ ThmResult ts -> do rPutStrLn (if isSat then "Unsatisfiable" else "Q.E.D.")- (t, e) <- mkSolverResult cexStr (not isSat) (Left ts)+ (t, e) <- mkSolverResult cexStr rng (not isSat) (Left ts) void $ bindItVariable t e CounterExample cexType tevs -> do@@ -710,19 +746,24 @@ let tes = map ( \(t,e,_) -> (t,e)) tevs vs = map ( \(_,_,v) -> v) tevs - (t,e) <- mkSolverResult cexStr isSat (Right tes)- pexpr <- replParseExpr str+ (t,e) <- mkSolverResult cexStr rng isSat (Right tes) - ~(EnvBool yes) <- getUser "show-examples"- when yes $ printCounterexample cexType pexpr vs+ ~(EnvBool yes) <- getUser "showExamples"+ when yes $ printCounterexample cexType exprDoc vs + -- if there's a safety violation, evalute the counterexample to+ -- find and print the actual concrete error+ case cexType of+ SafetyViolation -> when yes $ printSafetyViolation texpr schema vs+ _ -> return ()+ void $ bindItVariable t e AllSatResult tevss -> do rPutStrLn "Satisfiable" let tess = map (map $ \(t,e,_) -> (t,e)) tevss vss = map (map $ \(_,_,v) -> v) tevss- resultRecs <- mapM (mkSolverResult cexStr isSat . Right) tess+ resultRecs <- mapM (mkSolverResult cexStr rng isSat . Right) tess let collectTes tes = (t, es) where (ts, es) = unzip tes@@ -736,32 +777,42 @@ [ "no satisfying assignments after mkSolverResult" ] [(t, e)] -> (t, [e]) _ -> collectTes resultRecs- pexpr <- replParseExpr str - ~(EnvBool yes) <- getUser "show-examples"- when yes $ forM_ vss (printSatisfyingModel pexpr)+ ~(EnvBool yes) <- getUser "showExamples"+ when yes $ forM_ vss (printSatisfyingModel exprDoc) - case (ty, exprs) of- (t, [e]) -> void $ bindItVariable t e- (t, es ) -> bindItVariables t es+ case exprs of+ [e] -> void $ bindItVariable ty e+ _ -> bindItVariables ty exprs seeStats <- getUserShowProverStats when seeStats (showProverStats firstProver stats) -onlineProveSat :: String- -> QueryType- -> String -> Maybe FilePath- -> REPL (Maybe String,ProverResult,ProverStats)-onlineProveSat proverName qtype str mfile = do++printSafetyViolation :: T.Expr -> T.Schema -> [E.GenValue Concrete] -> REPL ()+printSafetyViolation texpr schema vs =+ catch+ (do (fn,_) <- replEvalCheckedExpr texpr schema+ rEval (E.forceValue =<< foldM (\f v -> E.fromVFun Concrete f (pure v)) fn vs))+ (\case+ EvalError eex -> rPutStrLn (show (pp eex))+ ex -> raise ex)++onlineProveSat ::+ String ->+ QueryType ->+ T.Expr ->+ T.Schema ->+ Maybe FilePath ->+ REPL (Maybe String,ProverResult,ProverStats)+onlineProveSat proverName qtype expr schema mfile = do verbose <- getKnownUser "debug" modelValidate <- getUserProverValidate- parseExpr <- replParseExpr str- (_, expr, schema) <- replCheckExpr parseExpr validEvalContext expr validEvalContext schema decls <- fmap M.deDecls getDynEnv timing <- io (newIORef 0)- ~(EnvBool ignoreSafety) <- getUser "ignore-safety"+ ~(EnvBool ignoreSafety) <- getUser "ignoreSafety" let cmd = ProverCommand { pcQueryType = qtype , pcProverName = proverName@@ -777,22 +828,21 @@ (firstProver, res) <- getProverConfig >>= \case Left sbvCfg -> liftModuleCmd $ SBV.satProve sbvCfg cmd Right w4Cfg ->- do ~(EnvBool hashConsing) <- getUser "hash-consing"+ do ~(EnvBool hashConsing) <- getUser "hashConsing" ~(EnvBool warnUninterp) <- getUser "warnUninterp" liftModuleCmd $ W4.satProve w4Cfg hashConsing warnUninterp cmd stas <- io (readIORef timing) return (firstProver,res,stas) -offlineProveSat :: String -> QueryType -> String -> Maybe FilePath -> REPL ()-offlineProveSat proverName qtype str mfile = do+offlineProveSat :: String -> QueryType -> T.Expr -> T.Schema -> Maybe FilePath -> REPL ()+offlineProveSat proverName qtype expr schema mfile = do verbose <- getKnownUser "debug" modelValidate <- getUserProverValidate- parseExpr <- replParseExpr str- (_, expr, schema) <- replCheckExpr parseExpr+ decls <- fmap M.deDecls getDynEnv timing <- io (newIORef 0)- ~(EnvBool ignoreSafety) <- getUser "ignore-safety"+ ~(EnvBool ignoreSafety) <- getUser "ignoreSafety" let cmd = ProverCommand { pcQueryType = qtype , pcProverName = proverName@@ -832,7 +882,7 @@ Nothing -> rPutStr smtlib Right w4Cfg ->- do ~(EnvBool hashConsing) <- getUser "hash-consing"+ do ~(EnvBool hashConsing) <- getUser "hashConsing" ~(EnvBool warnUninterp) <- getUser "warnUninterp" result <- liftModuleCmd $ W4.satProveOffline w4Cfg hashConsing warnUninterp cmd $ \f -> do displayMsg@@ -855,13 +905,15 @@ -- | Make a type/expression pair that is suitable for binding to @it@ -- after running @:sat@ or @:prove@-mkSolverResult :: String- -> Bool- -> Either [T.Type] [(T.Type, T.Expr)]- -> REPL (T.Type, T.Expr)-mkSolverResult thing result earg =+mkSolverResult ::+ String ->+ Range ->+ Bool ->+ Either [E.TValue] [(E.TValue, T.Expr)] ->+ REPL (E.TValue, T.Expr)+mkSolverResult thing rng result earg = do prims <- getPrimMap- let addError t = (t, T.eError prims t ("no " ++ thing ++ " available"))+ let addError t = (t, T.ELocated rng (T.eError prims (E.tValTy t) ("no " ++ thing ++ " available"))) argF = case earg of Left ts -> mkArgs (map addError ts)@@ -871,7 +923,7 @@ eFalse = T.ePrim prims (M.prelPrim "False") resultE = if result then eTrue else eFalse - rty = T.TRec (recordFromFields $ [(rIdent, T.tBit )] ++ map fst argF)+ rty = E.TVRec (recordFromFields $ [(rIdent, E.TVBit)] ++ map fst argF) re = T.ERec (recordFromFields $ [(rIdent, resultE)] ++ map snd argF) return (rty, re)@@ -882,9 +934,9 @@ let argName = M.packIdent ("arg" ++ show n) in ((argName,t),(argName,e)) -specializeCmd :: String -> REPL ()-specializeCmd str = do- parseExpr <- replParseExpr str+specializeCmd :: String -> (Int,Int) -> Maybe FilePath -> REPL ()+specializeCmd str pos fnm = do+ parseExpr <- replParseExpr str pos fnm (_, expr, schema) <- replCheckExpr parseExpr spexpr <- replSpecExpr expr rPutStrLn "Expression type:"@@ -894,9 +946,9 @@ rPutStrLn "Specialized expression:" rPutStrLn $ dump spexpr -refEvalCmd :: String -> REPL ()-refEvalCmd str = do- parseExpr <- replParseExpr str+refEvalCmd :: String -> (Int,Int) -> Maybe FilePath -> REPL ()+refEvalCmd str pos fnm = do+ parseExpr <- replParseExpr str pos fnm (_, expr, schema) <- replCheckExpr parseExpr validEvalContext expr validEvalContext schema@@ -904,9 +956,9 @@ opts <- getPPValOpts rPrint $ R.ppEValue opts val -astOfCmd :: String -> REPL ()-astOfCmd str = do- expr <- replParseExpr str+astOfCmd :: String -> (Int,Int) -> Maybe FilePath -> REPL ()+astOfCmd str pos fnm = do+ expr <- replParseExpr str pos fnm (re,_,_) <- replCheckExpr (P.noPos expr) rPrint (fmap M.nameUnique re) @@ -915,10 +967,10 @@ me <- getModuleEnv rPrint $ T.showParseable $ concatMap T.mDecls $ M.loadedModules me -typeOfCmd :: String -> REPL ()-typeOfCmd str = do+typeOfCmd :: String -> (Int,Int) -> Maybe FilePath -> REPL ()+typeOfCmd str pos fnm = do - expr <- replParseExpr str+ expr <- replParseExpr str pos fnm (_re,def,sig) <- replCheckExpr expr -- XXX need more warnings from the module system@@ -942,7 +994,7 @@ let t = T.tWord (T.tNum (toInteger len * 8)) let x = T.EProofApp (T.ETApp (T.ETApp number (T.tNum val)) t) let expr = T.EApp f x- void $ bindItVariable (T.tString len) expr+ void $ bindItVariable (E.TVSeq (toInteger len) (E.TVSeq 8 E.TVBit)) expr -- | Convert a 'ByteString' (big-endian) of length @n@ to an 'Integer' -- with @8*n@ bits. This function uses a balanced binary fold to@@ -963,9 +1015,9 @@ x1 = byteStringToInteger bs1 x2 = byteStringToInteger bs2 -writeFileCmd :: FilePath -> String -> REPL ()-writeFileCmd file str = do- expr <- replParseExpr str+writeFileCmd :: FilePath -> String -> (Int,Int) -> Maybe FilePath -> REPL ()+writeFileCmd file str pos fnm = do+ expr <- replParseExpr str pos fnm (val,ty) <- replEvalExpr expr if not (tIsByteSeq ty) then rPrint $ "Cannot write expression of types other than [n][8]."@@ -990,10 +1042,10 @@ rEval :: E.Eval a -> REPL a-rEval m = io (E.runEval m)+rEval m = io (E.runEval mempty m) rEvalRethrow :: E.Eval a -> REPL a-rEvalRethrow m = io $ rethrowEvalError $ E.runEval m+rEvalRethrow m = io $ rethrowEvalError $ E.runEval mempty m reloadCmd :: REPL () reloadCmd = do@@ -1348,9 +1400,9 @@ | null cmd = mapM_ rPutStrLn (genHelp commandList) | cmd0 : args <- words cmd, ":" `isPrefixOf` cmd0 = case findCommandExact cmd0 of- [] -> void $ runCommand (Unknown cmd0)+ [] -> void $ runCommand 1 Nothing (Unknown cmd0) [c] -> showCmdHelp c args- cs -> void $ runCommand (Ambiguous cmd0 (concatMap cNames cs))+ cs -> void $ runCommand 1 Nothing (Ambiguous cmd0 (concatMap cNames cs)) | otherwise = case parseHelpName cmd of Just qname ->@@ -1557,12 +1609,34 @@ Right a -> return a Left e -> raise (ParseError e) -replParseInput :: String -> REPL (P.ReplInput P.PName)-replParseInput = replParse (parseReplWith interactiveConfig . T.pack)+replParseInput :: String -> Int -> Maybe FilePath -> REPL (P.ReplInput P.PName)+replParseInput str lineNum fnm = replParse (parseReplWith cfg . T.pack) str+ where+ cfg = case fnm of+ Nothing -> interactiveConfig{ cfgStart = Position lineNum 1 }+ Just f -> defaultConfig+ { cfgSource = f+ , cfgStart = Position lineNum 1+ } -replParseExpr :: String -> REPL (P.Expr P.PName)-replParseExpr = replParse (parseExprWith interactiveConfig . T.pack)+replParseExpr :: String -> (Int,Int) -> Maybe FilePath -> REPL (P.Expr P.PName)+replParseExpr str (l,c) fnm = replParse (parseExprWith cfg. T.pack) str+ where+ cfg = case fnm of+ Nothing -> interactiveConfig{ cfgStart = Position l c }+ Just f -> defaultConfig+ { cfgSource = f+ , cfgStart = Position l c+ } +mkInteractiveRange :: (Int,Int) -> Maybe FilePath -> Range+mkInteractiveRange (l,c) mb = Range p p src+ where+ p = Position l c+ src = case mb of+ Nothing -> "<interactive>"+ Just b -> b+ interactiveConfig :: Config interactiveConfig = defaultConfig { cfgSource = "<interactive>" } @@ -1571,9 +1645,19 @@ liftModuleCmd :: M.ModuleCmd a -> REPL a liftModuleCmd cmd =- do evo <- getEvalOpts+ do evo <- getEvalOptsAction env <- getModuleEnv- moduleCmdResult =<< io (cmd (evo, BS.readFile, env))+ callStacks <- getCallStacks+ let cfg = M.meSolverConfig env+ let minp s =+ M.ModuleInput+ { minpCallStacks = callStacks+ , minpEvalOpts = evo+ , minpByteReader = BS.readFile+ , minpModuleEnv = env+ , minpTCSolver = s+ }+ moduleCmdResult =<< io (SMT.withSolver cfg (cmd . minp)) moduleCmdResult :: M.ModuleRes a -> REPL a moduleCmdResult (res,ws0) = do@@ -1644,8 +1728,13 @@ replEvalExpr :: P.Expr P.PName -> REPL (Concrete.Value, T.Type) replEvalExpr expr = do (_,def,sig) <- replCheckExpr expr- validEvalContext def+ replEvalCheckedExpr def sig++replEvalCheckedExpr :: T.Expr -> T.Schema -> REPL (Concrete.Value, T.Type)+replEvalCheckedExpr def sig =+ do validEvalContext def validEvalContext sig+ me <- getModuleEnv let cfg = M.meSolverConfig me mbDef <- io $ SMT.withSolver cfg (\s -> defaultReplExpr s def sig)@@ -1658,12 +1747,20 @@ let su = T.listParamSubst tys return (def1, T.apSubst su (T.sType sig)) + whenDebug (rPutStrLn (dump def1))++ tenv <- E.envTypes . M.deEnv <$> getDynEnv+ let tyv = E.evalValType tenv ty+ -- add "it" to the namespace via a new declaration- itVar <- bindItVariable ty def1+ itVar <- bindItVariable tyv def1 + let itExpr = case getLoc def of+ Nothing -> T.EVar itVar+ Just rng -> T.ELocated rng (T.EVar itVar)+ -- evaluate the it variable- val <- liftModuleCmd (rethrowEvalError . M.evalExpr (T.EVar itVar))- whenDebug (rPutStrLn (dump def1))+ val <- liftModuleCmd (rethrowEvalError . M.evalExpr itExpr) return (val,ty) where warnDefaults ts =@@ -1692,12 +1789,12 @@ -- | Creates a fresh binding of "it" to the expression given, and adds -- it to the current dynamic environment. The fresh name generated -- is returned.-bindItVariable :: T.Type -> T.Expr -> REPL T.Name+bindItVariable :: E.TValue -> T.Expr -> REPL T.Name bindItVariable ty expr = do freshIt <- freshName itIdent M.UserName let schema = T.Forall { T.sVars = [] , T.sProps = []- , T.sType = ty+ , T.sType = E.tValTy ty } decl = T.Decl { T.dName = freshIt , T.dSignature = schema@@ -1718,7 +1815,7 @@ -- | Extend the dynamic environment with a fresh binding for "it", -- as defined by the given value. If we cannot determine the definition -- of the value, then we don't bind `it`.-bindItVariableVal :: T.Type -> Concrete.Value -> REPL ()+bindItVariableVal :: E.TValue -> Concrete.Value -> REPL () bindItVariableVal ty val = do prims <- getPrimMap mb <- rEval (Concrete.toExpr prims ty val)@@ -1730,12 +1827,12 @@ -- | Creates a fresh binding of "it" to a finite sequence of -- expressions of the same type, and adds that sequence to the current -- dynamic environment-bindItVariables :: T.Type -> [T.Expr] -> REPL ()+bindItVariables :: E.TValue -> [T.Expr] -> REPL () bindItVariables ty exprs = void $ bindItVariable seqTy seqExpr where len = length exprs- seqTy = T.tSeq (T.tNum len) ty- seqExpr = T.EList exprs ty+ seqTy = E.TVSeq (toInteger len) ty+ seqExpr = T.EList exprs (E.tValTy ty) replEvalDecl :: P.Decl P.PName -> REPL () replEvalDecl decl = do@@ -1770,19 +1867,26 @@ trim = sanitizeEnd . sanitize -- | Split at the first word boundary.-splitCommand :: String -> Maybe (String,String)-splitCommand txt =- case sanitize txt of- ':' : more+splitCommand :: String -> Maybe (Int,String,String)+splitCommand = go 0+ where+ go !len (c : more)+ | isSpace c = go (len+1) more++ go !len (':': more) | (as,bs) <- span (\x -> isPunctuation x || isSymbol x) more- , not (null as) -> Just (':' : as, sanitize bs)+ , (ws,cs) <- span isSpace bs+ , not (null as) = Just (len+1+length as+length ws, ':' : as, cs) | (as,bs) <- break isSpace more- , not (null as) -> Just (':' : as, sanitize bs)+ , (ws,cs) <- span isSpace bs+ , not (null as) = Just (len+1+length as+length ws, ':' : as, cs) - | otherwise -> Nothing+ | otherwise = Nothing - expr -> guard (not (null expr)) >> return (expr,[])+ go !len expr+ | null expr = Nothing+ | otherwise = Just (len+length expr, expr, []) -- | Uncons a list. uncons :: [a] -> Maybe (a,[a])@@ -1807,23 +1911,24 @@ -- | Parse a line as a command. parseCommand :: (String -> [CommandDescr]) -> String -> Maybe Command parseCommand findCmd line = do- (cmd,args) <- splitCommand line+ (cmdLen,cmd,args) <- splitCommand line let args' = sanitizeEnd args case findCmd cmd of [c] -> case cBody c of- ExprArg body -> Just (Command (body args'))- DeclsArg body -> Just (Command (body args'))- ExprTypeArg body -> Just (Command (body args'))- ModNameArg body -> Just (Command (body args'))- FilenameArg body -> Just (Command (body =<< expandHome args'))- OptionArg body -> Just (Command (body args'))- ShellArg body -> Just (Command (body args'))- HelpArg body -> Just (Command (body args'))- NoArg body -> Just (Command body)+ ExprArg body -> Just (Command \l fp -> (body args' (l,cmdLen+1) fp))+ DeclsArg body -> Just (Command \_ _ -> (body args'))+ ExprTypeArg body -> Just (Command \_ _ -> (body args'))+ ModNameArg body -> Just (Command \_ _ -> (body args'))+ FilenameArg body -> Just (Command \_ _ -> (body =<< expandHome args'))+ OptionArg body -> Just (Command \_ _ -> (body args'))+ ShellArg body -> Just (Command \_ _ -> (body args'))+ HelpArg body -> Just (Command \_ _ -> (body args'))+ NoArg body -> Just (Command \_ _ -> body) FileExprArg body ->- case extractFilePath args' of- Just (fp,expr) -> Just (Command (expandHome fp >>= flip body expr))- Nothing -> Nothing+ do (fpLen,fp,expr) <- extractFilePath args'+ Just (Command \l fp' -> do let col = cmdLen + fpLen + 1+ hm <- expandHome fp+ body hm expr (l,col) fp') [] -> case uncons cmd of Just (':',_) -> Just (Unknown cmd) Just _ -> Just (Command (evalCmd line))@@ -1839,9 +1944,10 @@ _ -> return path extractFilePath ipt =- let quoted q = (\(a,b) -> (a, drop 1 b)) . break (== q)+ let quoted q = (\(a,b) -> (length a + 2, a, drop 1 b)) . break (== q) in case ipt of "" -> Nothing '\'':rest -> Just $ quoted '\'' rest '"':rest -> Just $ quoted '"' rest- _ -> Just $ break isSpace ipt+ _ -> let (a,b) = break isSpace ipt in+ if null a then Nothing else Just (length a, a, b)
src/Cryptol/REPL/Monad.hs view
@@ -35,8 +35,11 @@ , getFocusedEnv , getModuleEnv, setModuleEnv , getDynEnv, setDynEnv+ , getCallStacks , uniqify, freshName , whenDebug+ , getEvalOptsAction+ , getPPValOpts , getExprNames , getTypeNames , getPropertyNames@@ -57,6 +60,7 @@ , OptionDescr(..) , setUser, getUser, getKnownUser, tryGetUser , userOptions+ , userOptionsWithAliases , getUserSatNum , getUserShowProverStats , getUserProverValidate@@ -76,7 +80,7 @@ import Cryptol.REPL.Trie -import Cryptol.Eval (EvalError, Unsupported)+import Cryptol.Eval (EvalErrorEx, Unsupported, WordTooWide,EvalOpts(..)) import qualified Cryptol.ModuleSystem as M import qualified Cryptol.ModuleSystem.Env as M import qualified Cryptol.ModuleSystem.Name as M@@ -96,7 +100,6 @@ import Cryptol.Symbolic (SatNum(..)) import Cryptol.Symbolic.SBV (SBVPortfolioException) import Cryptol.Symbolic.What4 (W4Exception)-import Cryptol.Backend.Monad(PPFloatFormat(..),PPFloatExp(..)) import qualified Cryptol.Symbolic.SBV as SBV (proverNames, setupProver, defaultProver, SBVProverConfig) import qualified Cryptol.Symbolic.What4 as W4 (proverNames, setupProver, W4ProverConfig) @@ -155,6 +158,8 @@ , eLogger :: Logger -- ^ Use this to send messages to the user + , eCallStacks :: Bool+ , eUpdateTitle :: REPL () -- ^ Execute this every time we load a module. -- This is used to change the title of terminal when loading a module.@@ -163,8 +168,8 @@ } -- | Initial, empty environment.-defaultRW :: Bool -> Logger -> IO RW-defaultRW isBatch l = do+defaultRW :: Bool -> Bool ->Logger -> IO RW+defaultRW isBatch callStacks l = do env <- M.initialModuleEnv return RW { eLoadedMod = Nothing@@ -174,6 +179,7 @@ , eModuleEnv = env , eUserEnv = mkUserEnv userOptions , eLogger = l+ , eCallStacks = callStacks , eUpdateTitle = return () , eProverConfig = Left SBV.defaultProver }@@ -220,9 +226,9 @@ newtype REPL a = REPL { unREPL :: IORef RW -> IO a } -- | Run a REPL action with a fresh environment.-runREPL :: Bool -> Logger -> REPL a -> IO a-runREPL isBatch l m = do- ref <- newIORef =<< defaultRW isBatch l+runREPL :: Bool -> Bool -> Logger -> REPL a -> IO a+runREPL isBatch callStacks l m = do+ ref <- newIORef =<< defaultRW isBatch callStacks l unREPL m ref instance Functor REPL where@@ -289,7 +295,8 @@ | DirectoryNotFound FilePath | NoPatError [Error] | NoIncludeError [IncludeError]- | EvalError EvalError+ | EvalError EvalErrorEx+ | TooWide WordTooWide | Unsupported Unsupported | ModuleSystemError NameDisp M.ModuleError | EvalPolyError T.Schema@@ -319,6 +326,7 @@ ModuleSystemError ns me -> fixNameDisp ns (pp me) EvalError e -> pp e Unsupported e -> pp e+ TooWide e -> pp e EvalPolyError s -> text "Cannot evaluate polymorphic value." $$ text "Type:" <+> pp s TypeNotTestable t -> text "The expression is not of a testable type."@@ -344,15 +352,21 @@ rethrowEvalError :: IO a -> IO a-rethrowEvalError m = run `X.catch` rethrow `X.catch` rethrowUnsupported+rethrowEvalError m =+ run `X.catch` rethrow+ `X.catch` rethrowTooWide+ `X.catch` rethrowUnsupported where run = do a <- m return $! a - rethrow :: EvalError -> IO a+ rethrow :: EvalErrorEx -> IO a rethrow exn = X.throwIO (EvalError exn) + rethrowTooWide :: WordTooWide -> IO a+ rethrowTooWide exn = X.throwIO (TooWide exn)+ rethrowUnsupported :: Unsupported -> IO a rethrowUnsupported exn = X.throwIO (Unsupported exn) @@ -376,6 +390,36 @@ getPrompt :: REPL String getPrompt = mkPrompt `fmap` getRW +getCallStacks :: REPL Bool+getCallStacks = eCallStacks <$> getRW++-- Get the setting we should use for displaying values.+getPPValOpts :: REPL PPOpts+getPPValOpts =+ do base <- getKnownUser "base"+ ascii <- getKnownUser "ascii"+ infLength <- getKnownUser "infLength"++ fpBase <- getKnownUser "fpBase"+ fpFmtTxt <- getKnownUser "fpFormat"+ let fpFmt = case parsePPFloatFormat fpFmtTxt of+ Just f -> f+ Nothing -> panic "getPPOpts"+ [ "Failed to parse fp-format" ]++ return PPOpts { useBase = base+ , useAscii = ascii+ , useInfLength = infLength+ , useFPBase = fpBase+ , useFPFormat = fpFmt+ }++getEvalOptsAction :: REPL (IO EvalOpts)+getEvalOptsAction = REPL $ \rwRef -> pure $+ do ppOpts <- unREPL getPPValOpts rwRef+ l <- unREPL getLogger rwRef+ return EvalOpts { evalPPOpts = ppOpts, evalLogger = l }+ clearLoadedMod :: REPL () clearLoadedMod = do modifyRW_ (\rw -> rw { eLoadedMod = upd <$> eLoadedMod rw }) updateREPLTitle@@ -513,12 +557,12 @@ return (map (show . pp) (Map.keys (M.neTypes fNames))) -- | Return a list of property names, sorted by position in the file.-getPropertyNames :: REPL ([M.Name],NameDisp)+getPropertyNames :: REPL ([(M.Name,M.IfaceDecl)],NameDisp) getPropertyNames = do fe <- getFocusedEnv let xs = M.ifDecls (M.mctxDecls fe)- ps = sortBy (comparing (from . M.nameLoc))- [ x | (x,d) <- Map.toList xs,+ ps = sortBy (comparing (from . M.nameLoc . fst))+ [ (x,d) | (x,d) <- Map.toList xs, T.PragmaProperty `elem` M.ifDeclPragmas d ] return (ps, M.mctxNameDisp fe)@@ -594,7 +638,7 @@ -- | Set a user option. setUser :: String -> String -> REPL ()-setUser name val = case lookupTrieExact name userOptions of+setUser name val = case lookupTrieExact name userOptionsWithAliases of [opt] -> setUserOpt opt [] -> rPutStrLn ("Unknown env value `" ++ name ++ "`")@@ -697,10 +741,10 @@ getUserShowProverStats :: REPL Bool-getUserShowProverStats = getKnownUser "prover-stats"+getUserShowProverStats = getKnownUser "proverStats" getUserProverValidate :: REPL Bool-getUserProverValidate = getKnownUser "prover-validate"+getUserProverValidate = getKnownUser "proverValidate" -- Environment Options --------------------------------------------------------- @@ -722,47 +766,53 @@ data OptionDescr = OptionDescr { optName :: String+ , optAliases :: [String] , optDefault :: EnvVal , optCheck :: Checker , optHelp :: String , optEff :: EnvVal -> REPL () } -simpleOpt :: String -> EnvVal -> Checker -> String -> OptionDescr-simpleOpt optName optDefault optCheck optHelp =+simpleOpt :: String -> [String] -> EnvVal -> Checker -> String -> OptionDescr+simpleOpt optName optAliases optDefault optCheck optHelp = OptionDescr { optEff = \ _ -> return (), .. } +userOptionsWithAliases :: OptionMap+userOptionsWithAliases = foldl insert userOptions (leaves userOptions)+ where+ insert m d = foldl (\m' n -> insertTrie n d m') m (optAliases d)+ userOptions :: OptionMap userOptions = mkOptionMap- [ simpleOpt "base" (EnvNum 16) checkBase+ [ simpleOpt "base" [] (EnvNum 16) checkBase "The base to display words at (2, 8, 10, or 16)."- , simpleOpt "debug" (EnvBool False) noCheck+ , simpleOpt "debug" [] (EnvBool False) noCheck "Enable debugging output."- , simpleOpt "ascii" (EnvBool False) noCheck+ , simpleOpt "ascii" [] (EnvBool False) noCheck "Whether to display 7- or 8-bit words using ASCII notation."- , simpleOpt "infLength" (EnvNum 5) checkInfLength+ , simpleOpt "infLength" ["inf-length"] (EnvNum 5) checkInfLength "The number of elements to display for infinite sequences."- , simpleOpt "tests" (EnvNum 100) noCheck+ , simpleOpt "tests" [] (EnvNum 100) noCheck "The number of random tests to try with ':check'."- , simpleOpt "satNum" (EnvString "1") checkSatNum+ , simpleOpt "satNum" ["sat-num"] (EnvString "1") checkSatNum "The maximum number of :sat solutions to display (\"all\" for no limit)."- , simpleOpt "prover" (EnvString "z3") checkProver $+ , simpleOpt "prover" [] (EnvString "z3") checkProver $ "The external SMT solver for ':prove' and ':sat'\n(" ++ proverListString ++ ")."- , simpleOpt "warnDefaulting" (EnvBool False) noCheck+ , simpleOpt "warnDefaulting" ["warn-defaulting"] (EnvBool False) noCheck "Choose whether to display warnings when defaulting."- , simpleOpt "warnShadowing" (EnvBool True) noCheck+ , simpleOpt "warnShadowing" ["warn-shadowing"] (EnvBool True) noCheck "Choose whether to display warnings when shadowing symbols."- , simpleOpt "warnUninterp" (EnvBool True) noCheck+ , simpleOpt "warnUninterp" ["warn-uninterp"] (EnvBool True) noCheck "Choose whether to issue a warning when uninterpreted functions are used to implement primitives in the symbolic simulator."- , simpleOpt "smtfile" (EnvString "-") noCheck+ , simpleOpt "smtFile" ["smt-file"] (EnvString "-") noCheck "The file to use for SMT-Lib scripts (for debugging or offline proving).\nUse \"-\" for stdout."- , OptionDescr "mono-binds" (EnvBool True) noCheck+ , OptionDescr "monoBinds" ["mono-binds"] (EnvBool True) noCheck "Whether or not to generalize bindings in a 'where' clause." $ \case EnvBool b -> do me <- getModuleEnv setModuleEnv me { M.meMonoBinds = b } _ -> return () - , OptionDescr "tc-solver" (EnvProg "z3" [ "-smt2", "-in" ])+ , OptionDescr "tcSolver" ["tc-solver"] (EnvProg "z3" [ "-smt2", "-in" ]) noCheck -- TODO: check for the program in the path "The solver that will be used by the type checker." $ \case EnvProg prog args -> do me <- getModuleEnv@@ -772,7 +822,7 @@ , T.solverArgs = args } } _ -> return () - , OptionDescr "tc-debug" (EnvNum 0)+ , OptionDescr "tcDebug" ["tc-debug"] (EnvNum 0) noCheck (unlines [ "Enable type-checker debugging output:"@@ -783,7 +833,7 @@ let cfg = M.meSolverConfig me setModuleEnv me { M.meSolverConfig = cfg{ T.solverVerbose = n } } _ -> return ()- , OptionDescr "core-lint" (EnvBool False)+ , OptionDescr "coreLint" ["core-lint"] (EnvBool False) noCheck "Enable sanity checking of type-checker." $ let setIt x = do me <- getModuleEnv@@ -792,22 +842,22 @@ EnvBool False -> setIt M.NoCoreLint _ -> return () - , simpleOpt "hash-consing" (EnvBool True) noCheck+ , simpleOpt "hashConsing" ["hash-consing"] (EnvBool True) noCheck "Enable hash-consing in the What4 symbolic backends." - , simpleOpt "prover-stats" (EnvBool True) noCheck+ , simpleOpt "proverStats" ["prover-stats"] (EnvBool True) noCheck "Enable prover timing statistics." - , simpleOpt "prover-validate" (EnvBool False) noCheck+ , simpleOpt "proverValidate" ["prover-validate"] (EnvBool False) noCheck "Validate :sat examples and :prove counter-examples for correctness." - , simpleOpt "show-examples" (EnvBool True) noCheck+ , simpleOpt "showExamples" ["show-examples"] (EnvBool True) noCheck "Print the (counter) example after :sat or :prove" - , simpleOpt "fp-base" (EnvNum 16) checkBase+ , simpleOpt "fpBase" ["fp-base"] (EnvNum 16) checkBase "The base to display floating point numbers at (2, 8, 10, or 16)." - , simpleOpt "fp-format" (EnvString "free") checkPPFloatFormat+ , simpleOpt "fpFormat" ["fp-format"] (EnvString "free") checkPPFloatFormat $ unlines [ "Specifies the format to use when showing floating point numbers:" , " * free show using as many digits as needed"@@ -817,7 +867,7 @@ , " * NUM+exp like NUM but always show exponent" ] - , simpleOpt "ignore-safety" (EnvBool False) noCheck+ , simpleOpt "ignoreSafety" ["ignore-safety"] (EnvBool False) noCheck "Ignore safety predicates when performing :sat or :prove checks" ]
src/Cryptol/REPL/Trie.hs view
@@ -9,6 +9,7 @@ module Cryptol.REPL.Trie where import Cryptol.Utils.Panic (panic)+import Data.Char (toLower) import qualified Data.Map as Map import Data.Maybe (fromMaybe,maybeToList) @@ -20,13 +21,13 @@ emptyTrie :: Trie a emptyTrie = Node Map.empty Nothing --- | Insert a value into the Trie. Will call `panic` if a value already exists--- with that key.+-- | Insert a value into the Trie, forcing the key value to lower case.+-- Will call `panic` if a value already exists with that key. insertTrie :: String -> a -> Trie a -> Trie a insertTrie k a = loop k where loop key (Node m mb) = case key of- c:cs -> Node (Map.alter (Just . loop cs . fromMaybe emptyTrie) c m) mb+ c:cs -> Node (Map.alter (Just . loop cs . fromMaybe emptyTrie) (toLower c) m) mb [] -> case mb of Nothing -> Node m (Just a) Just _ -> panic "[REPL] Trie" ["key already exists:", "\t" ++ k]@@ -35,7 +36,7 @@ lookupTrie :: String -> Trie a -> [a] lookupTrie key t@(Node mp _) = case key of - c:cs -> case Map.lookup c mp of+ c:cs -> case Map.lookup (toLower c) mp of Just m' -> lookupTrie cs m' Nothing -> [] @@ -47,7 +48,7 @@ lookupTrieExact [] (Node _ (Just x)) = return x lookupTrieExact [] t = leaves t lookupTrieExact (c:cs) (Node mp _) =- case Map.lookup c mp of+ case Map.lookup (toLower c) mp of Just m' -> lookupTrieExact cs m' Nothing -> []
src/Cryptol/Symbolic.hs view
@@ -54,7 +54,8 @@ import qualified Cryptol.Eval.Concrete as Concrete import Cryptol.Eval.Value import Cryptol.TypeCheck.AST-import Cryptol.Eval.Type (TValue(..), evalType)+import Cryptol.TypeCheck.Solver.InfNat+import Cryptol.Eval.Type (TValue(..), evalType,tValTy,tNumValTy) import Cryptol.Utils.Ident (Ident,prelPrim,floatPrim) import Cryptol.Utils.RecordMap import Cryptol.Utils.Panic@@ -65,7 +66,7 @@ import Prelude.Compat import Data.Time (NominalDiffTime) -type SatResult = [(Type, Expr, Concrete.Value)]+type SatResult = [(TValue, Expr, Concrete.Value)] data SatNum = AllSat | SomeSat Int deriving (Show)@@ -108,7 +109,7 @@ -- for the offline prover), a counterexample or a lazy list of -- satisfying assignments. data ProverResult = AllSatResult [SatResult] -- LAZY- | ThmResult [Type]+ | ThmResult [TValue] | CounterExample CounterExampleType SatResult | EmptyResult | ProverError String@@ -141,41 +142,57 @@ | FTIntMod Integer | FTRational | FTFloat Integer Integer- | FTSeq Int FinType+ | FTSeq Integer FinType | FTTuple [FinType] | FTRecord (RecordMap Ident FinType)--numType :: Integer -> Maybe Int-numType n- | 0 <= n && n <= toInteger (maxBound :: Int) = Just (fromInteger n)- | otherwise = Nothing+ | FTNewtype Newtype [Either Nat' TValue] (RecordMap Ident FinType) finType :: TValue -> Maybe FinType finType ty = case ty of- TVBit -> Just FTBit- TVInteger -> Just FTInteger- TVIntMod n -> Just (FTIntMod n)- TVRational -> Just FTRational- TVFloat e p -> Just (FTFloat e p)- TVSeq n t -> FTSeq <$> numType n <*> finType t- TVTuple ts -> FTTuple <$> traverse finType ts- TVRec fields -> FTRecord <$> traverse finType fields- TVAbstract {} -> Nothing- _ -> Nothing+ TVBit -> Just FTBit+ TVInteger -> Just FTInteger+ TVIntMod n -> Just (FTIntMod n)+ TVRational -> Just FTRational+ TVFloat e p -> Just (FTFloat e p)+ TVSeq n t -> FTSeq n <$> finType t+ TVTuple ts -> FTTuple <$> traverse finType ts+ TVRec fields -> FTRecord <$> traverse finType fields+ TVNewtype u ts body -> FTNewtype u ts <$> traverse finType body+ TVAbstract {} -> Nothing+ TVArray{} -> Nothing+ TVStream{} -> Nothing+ TVFun{} -> Nothing -unFinType :: FinType -> Type-unFinType fty =+finTypeToType :: FinType -> Type+finTypeToType fty = case fty of- FTBit -> tBit- FTInteger -> tInteger- FTIntMod n -> tIntMod (tNum n)- FTRational -> tRational- FTFloat e p -> tFloat (tNum e) (tNum p)- FTSeq l ety -> tSeq (tNum l) (unFinType ety)- FTTuple ftys -> tTuple (unFinType <$> ftys)- FTRecord fs -> tRec (unFinType <$> fs)+ FTBit -> tBit+ FTInteger -> tInteger+ FTIntMod n -> tIntMod (tNum n)+ FTRational -> tRational+ FTFloat e p -> tFloat (tNum e) (tNum p)+ FTSeq l ety -> tSeq (tNum l) (finTypeToType ety)+ FTTuple ftys -> tTuple (finTypeToType <$> ftys)+ FTRecord fs -> tRec (finTypeToType <$> fs)+ FTNewtype u ts _ -> tNewtype u (map unArg ts)+ where+ unArg (Left Inf) = tInf+ unArg (Left (Nat n)) = tNum n+ unArg (Right t) = tValTy t +unFinType :: FinType -> TValue+unFinType fty =+ case fty of+ FTBit -> TVBit+ FTInteger -> TVInteger+ FTIntMod n -> TVIntMod n+ FTRational -> TVRational+ FTFloat e p -> TVFloat e p+ FTSeq n ety -> TVSeq n (unFinType ety)+ FTTuple ftys -> TVTuple (unFinType <$> ftys)+ FTRecord fs -> TVRec (unFinType <$> fs)+ FTNewtype u ts fs -> TVNewtype u ts (unFinType <$> fs) data VarShape sym = VarBit (SBit sym)@@ -188,12 +205,11 @@ | VarRecord (RecordMap Ident (VarShape sym)) ppVarShape :: Backend sym => sym -> VarShape sym -> Doc-ppVarShape sym (VarBit b) = ppBit sym b-ppVarShape sym (VarInteger i) = ppInteger sym defaultPPOpts i-ppVarShape sym (VarFloat f) = ppFloat sym defaultPPOpts f-ppVarShape sym (VarRational n d) =- text "(ratio" <+> ppInteger sym defaultPPOpts n <+> ppInteger sym defaultPPOpts d <+> text ")"-ppVarShape sym (VarWord w) = ppWord sym defaultPPOpts w+ppVarShape _sym (VarBit _b) = text "<bit>"+ppVarShape _sym (VarInteger _i) = text "<integer>"+ppVarShape _sym (VarFloat _f) = text "<float>"+ppVarShape _sym (VarRational _n _d) = text "<rational>"+ppVarShape sym (VarWord w) = text "<word:" <> integer (wordLen sym w) <> text ">" ppVarShape sym (VarFinSeq _ xs) = brackets (fsep (punctuate comma (map (ppVarShape sym) xs))) ppVarShape sym (VarTuple xs) =@@ -212,7 +228,7 @@ VarRational n d -> VRational (SRational n d) VarWord w -> VWord (wordLen sym w) (return (WordVal w)) VarFloat f -> VFloat f- VarFinSeq n vs -> VSeq n (finiteSeqMap sym (map (pure . varShapeToValue sym) vs))+ VarFinSeq n vs -> VSeq n (finiteSeqMap (map (pure . varShapeToValue sym) vs)) VarTuple vs -> VTuple (map (pure . varShapeToValue sym) vs) VarRecord fs -> VRecord (fmap (pure . varShapeToValue sym) fs) @@ -225,7 +241,8 @@ } freshVar :: Backend sym => FreshVarFns sym -> FinType -> IO (VarShape sym)-freshVar fns tp = case tp of+freshVar fns tp =+ case tp of FTBit -> VarBit <$> freshBitVar fns FTInteger -> VarInteger <$> freshIntegerVar fns Nothing Nothing FTRational -> VarRational@@ -234,16 +251,17 @@ FTIntMod 0 -> panic "freshVariable" ["0 modulus not allowed"] FTIntMod m -> VarInteger <$> freshIntegerVar fns (Just 0) (Just (m-1)) FTFloat e p -> VarFloat <$> freshFloatVar fns e p- FTSeq n FTBit | n > 0 -> VarWord <$> freshWordVar fns (toInteger n)+ FTSeq n FTBit -> VarWord <$> freshWordVar fns (toInteger n) FTSeq n t -> VarFinSeq (toInteger n) <$> sequence (genericReplicate n (freshVar fns t)) FTTuple ts -> VarTuple <$> mapM (freshVar fns) ts FTRecord fs -> VarRecord <$> traverse (freshVar fns) fs+ FTNewtype _ _ fs -> VarRecord <$> traverse (freshVar fns) fs computeModel :: PrimMap -> [FinType] -> [VarShape Concrete.Concrete] ->- [(Type, Expr, Concrete.Value)]+ [(TValue, Expr, Concrete.Value)] computeModel _ [] [] = [] computeModel primMap (t:ts) (v:vs) = do let v' = varShapeToValue Concrete.Concrete v@@ -304,6 +322,14 @@ go :: FinType -> VarShape Concrete.Concrete -> Expr go ty val = case (ty,val) of+ (FTNewtype nt ts tfs, VarRecord vfs) ->+ let res = zipRecords (\_lbl v t -> go t v) vfs tfs+ in case res of+ Left _ -> mismatch -- different fields+ Right efs ->+ let f = foldl (\x t -> ETApp x (tNumValTy t)) (EVar (ntName nt)) ts+ in EApp f (ERec efs)+ (FTRecord tfs, VarRecord vfs) -> let res = zipRecords (\_lbl v t -> go t v) vfs tfs in case res of@@ -317,11 +343,11 @@ (FTInteger, VarInteger i) -> -- This works uniformly for values of type Integer or Z n- ETApp (ETApp (prim "number") (tNum i)) (unFinType ty)+ ETApp (ETApp (prim "number") (tNum i)) (finTypeToType ty) (FTIntMod _, VarInteger i) -> -- This works uniformly for values of type Integer or Z n- ETApp (ETApp (prim "number") (tNum i)) (unFinType ty)+ ETApp (ETApp (prim "number") (tNum i)) (finTypeToType ty) (FTRational, VarRational n d) -> let n' = ETApp (ETApp (prim "number") (tNum n)) tInteger@@ -332,17 +358,17 @@ floatToExpr prims e p (bfValue f) (FTSeq _ FTBit, VarWord (Concrete.BV _ v)) ->- ETApp (ETApp (prim "number") (tNum v)) (unFinType ty)+ ETApp (ETApp (prim "number") (tNum v)) (finTypeToType ty) (FTSeq _ t, VarFinSeq _ svs) ->- EList (map (go t) svs) (unFinType t)+ EList (map (go t) svs) (finTypeToType t) _ -> mismatch where mismatch = panic "Cryptol.Symbolic.varToExpr" ["type mismatch:"- , show (pp (unFinType ty))+ , show (pp (finTypeToType ty)) , show (ppVarShape Concrete.Concrete val) ]
src/Cryptol/Symbolic/SBV.hs view
@@ -6,6 +6,7 @@ -- Stability : provisional -- Portability : portable +{-# LANGUAGE CPP #-} {-# LANGUAGE FlexibleContexts #-} {-# LANGUAGE ImplicitParams #-} {-# LANGUAGE LambdaCase #-}@@ -57,6 +58,7 @@ import qualified Cryptol.Eval.Concrete as Concrete import qualified Cryptol.Eval.Value as Eval import Cryptol.Eval.SBV+import Cryptol.Parser.Position (emptyRange) import Cryptol.Symbolic import Cryptol.TypeCheck.AST import Cryptol.Utils.Ident (preludeReferenceName, prelPrim, identText)@@ -70,7 +72,7 @@ doSBVEval :: MonadIO m => SBVEval a -> m (SBV.SVal, a) doSBVEval m =- (liftIO $ Eval.runEval (sbvEval m)) >>= \case+ (liftIO $ Eval.runEval mempty (sbvEval m)) >>= \case SBVError err -> liftIO (X.throwIO err) SBVResult p x -> pure (p, x) @@ -124,7 +126,11 @@ setupProver :: String -> IO (Either String ([String], SBVProverConfig)) setupProver nm | nm `elem` ["any","sbv-any"] =+#if MIN_VERSION_sbv(8,9,0)+ do ps <- SBV.getAvailableSolvers+#else do ps <- SBV.sbvAvailableSolvers+#endif case ps of [] -> pure (Left "SBV could not find any provers") _ -> let msg = "SBV found the following solvers: " ++ show (map (SBV.name . SBV.solver) ps) in@@ -155,14 +161,18 @@ satSMTResults (SBV.SatResult r) = [r] allSatSMTResults :: SBV.AllSatResult -> [SBV.SMTResult]+#if MIN_VERSION_sbv(8,8,0)+allSatSMTResults (SBV.AllSatResult {allSatResults = rs}) = rs+#else allSatSMTResults (SBV.AllSatResult (_, _, _, rs)) = rs+#endif thmSMTResults :: SBV.ThmResult -> [SBV.SMTResult] thmSMTResults (SBV.ThmResult r) = [r] proverError :: String -> M.ModuleCmd (Maybe String, ProverResult)-proverError msg (_, _, modEnv) =- return (Right ((Nothing, ProverError msg), modEnv), [])+proverError msg minp =+ return (Right ((Nothing, ProverError msg), M.minpModuleEnv minp), []) isFailedResult :: [SBV.SMTResult] -> Maybe String@@ -297,6 +307,13 @@ modEnv <- M.getModuleEnv let extDgs = M.allDeclGroups modEnv ++ pcExtraDecls + callStacks <- M.getCallStacks+ let ?callStacks = callStacks++ getEOpts <- M.getEvalOptsAction++ ntEnv <- M.getNewtypes+ -- The `addAsm` function is used to combine assumptions that -- arise from the types of symbolic variables (e.g. Z n values -- are assumed to be integers in the range `0 <= x < n`) with@@ -316,9 +333,11 @@ stateMVar <- liftIO (newMVar sbvState) defRelsVar <- liftIO (newMVar SBV.svTrue) let sym = SBV stateMVar defRelsVar- let tbl = primTable sym+ let tbl = primTable sym getEOpts let ?evalPrim = \i -> (Right <$> Map.lookup i tbl) <|> (Left <$> Map.lookup i ds)+ let ?range = emptyRange+ -- Compute the symbolic inputs, and any domain constraints needed -- according to their types. args <- map (pure . varShapeToValue sym) <$>@@ -327,9 +346,10 @@ -- evaluation environment, then we compute the value, finally -- we apply it to the symbolic inputs. (safety,b) <- doSBVEval $- do env <- Eval.evalDecls sym extDgs mempty+ do env <- Eval.evalDecls sym extDgs =<<+ Eval.evalNewtypeDecls sym ntEnv mempty v <- Eval.evalExpr sym env pcExpr- appliedVal <- foldM Eval.fromVFun v args+ appliedVal <- foldM (Eval.fromVFun sym) v args case pcQueryType of SafetyQuery -> do Eval.forceValue appliedVal@@ -389,7 +409,11 @@ -- otherwise something is wrong _ -> return $ ProverError (rshow results)+#if MIN_VERSION_sbv(8,8,0)+ where rshow | isSat = show . (SBV.AllSatResult False False False False)+#else where rshow | isSat = show . SBV.AllSatResult . (False,False,False,)+#endif | otherwise = show . SBV.ThmResult . head where@@ -398,7 +422,7 @@ -- to always be the first value in the model assignment list. let Right (_, (safetyCV : cvs)) = SBV.getModelAssignment result safety = SBV.cvToBool safetyCV- (vs, []) = parseValues ts cvs+ (vs, _) = parseValues ts cvs mdl = computeModel prims ts vs return (safety, mdl) @@ -409,10 +433,10 @@ -- solver that completes the given query (if any) along with the result -- of executing the query. satProve :: SBVProverConfig -> ProverCommand -> M.ModuleCmd (Maybe String, ProverResult)-satProve proverCfg pc@ProverCommand {..} =- protectStack proverError $ \(evo, byteReader, modEnv) ->-- M.runModuleM (evo, byteReader, modEnv) $ do+satProve proverCfg pc =+ protectStack proverError $ \minp ->+ M.runModuleM minp $ do+ evo <- liftIO (M.minpEvalOpts minp) let lPutStrLn = logPutStrLn (Eval.evalLogger evo) @@ -431,12 +455,13 @@ -- the SMT input file corresponding to the given prover command. satProveOffline :: SBVProverConfig -> ProverCommand -> M.ModuleCmd (Either String String) satProveOffline _proverCfg pc@ProverCommand {..} =- protectStack (\msg (_,_,modEnv) -> return (Right (Left msg, modEnv), [])) $- \(evo, byteReader, modEnv) -> M.runModuleM (evo,byteReader,modEnv) $+ protectStack (\msg minp -> return (Right (Left msg, M.minpModuleEnv minp), [])) $+ \minp -> M.runModuleM minp $ do let isSat = case pcQueryType of ProveQuery -> False SafetyQuery -> False SatQuery _ -> True+ evo <- liftIO (M.minpEvalOpts minp) prepareQuery evo pc >>= \case Left msg -> return (Left msg)@@ -479,11 +504,11 @@ return (VarRational n d, cvs'') parseValue (FTSeq 0 FTBit) cvs = (VarWord (Concrete.mkBv 0 0), cvs) parseValue (FTSeq n FTBit) cvs =- case SBV.genParse (SBV.KBounded False n) cvs of+ case SBV.genParse (SBV.KBounded False (fromInteger n)) cvs of Just (x, cvs') -> (VarWord (Concrete.mkBv (toInteger n) x), cvs') Nothing -> panic "Cryptol.Symbolic.parseValue" ["no bitvector"] parseValue (FTSeq n t) cvs = (VarFinSeq (toInteger n) vs, cvs')- where (vs, cvs') = parseValues (replicate n t) cvs+ where (vs, cvs') = parseValues (replicate (fromInteger n) t) cvs parseValue (FTTuple ts) cvs = (VarTuple vs, cvs') where (vs, cvs') = parseValues ts cvs parseValue (FTRecord r) cvs = (VarRecord r', cvs')@@ -492,6 +517,8 @@ fs = zip ns vs r' = recordFromFieldsWithDisplay (displayOrder r) fs +parseValue (FTNewtype _ _ r) cvs = parseValue (FTRecord r) cvs+ parseValue (FTFloat e p) cvs = (VarFloat FH.BF { FH.bfValue = bfNaN , FH.bfExpWidth = e@@ -513,11 +540,16 @@ Nothing -> pure () return x +freshBitvector :: SBV -> Integer -> IO SBV.SVal+freshBitvector sym w+ | w == 0 = pure (SBV.svInteger (SBV.KBounded False 0) 0)+ | otherwise = freshBV_ sym (fromInteger w)+ sbvFreshFns :: SBV -> FreshVarFns SBV sbvFreshFns sym = FreshVarFns { freshBitVar = freshSBool_ sym- , freshWordVar = freshBV_ sym . fromInteger+ , freshWordVar = freshBitvector sym , freshIntegerVar = freshBoundedInt sym , freshFloatVar = \_ _ -> return () -- TODO }
src/Cryptol/Symbolic/What4.hs view
@@ -56,12 +56,12 @@ import qualified Cryptol.Backend.FloatHelpers as FH import Cryptol.Backend.What4-import qualified Cryptol.Backend.What4.SFloat as W4 import qualified Cryptol.Eval as Eval import qualified Cryptol.Eval.Concrete as Concrete import qualified Cryptol.Eval.Value as Eval import Cryptol.Eval.What4+import Cryptol.Parser.Position (emptyRange) import Cryptol.Symbolic import Cryptol.TypeCheck.AST import Cryptol.Utils.Logger(logPutStrLn,logPutStr,Logger)@@ -72,6 +72,7 @@ import qualified What4.Expr.Builder as W4 import qualified What4.Expr.GroundEval as W4 import qualified What4.SatResult as W4+import qualified What4.SFloat as W4 import qualified What4.SWord as SW import What4.Solver import qualified What4.Solver.Adapter as W4@@ -123,7 +124,7 @@ (W4.IsExprBuilder sym, MonadIO m) => sym -> W4Eval sym a -> m (W4.Pred sym, a) doW4Eval sym m =- do res <- liftIO $ Eval.runEval (w4Eval m sym)+ do res <- liftIO $ Eval.runEval mempty (w4Eval m sym) case res of W4Error err -> liftIO (X.throwIO err) W4Result p x -> pure (p,x)@@ -198,8 +199,8 @@ proverError :: String -> M.ModuleCmd (Maybe String, ProverResult)-proverError msg (_, _, modEnv) =- return (Right ((Nothing, ProverError msg), modEnv), [])+proverError msg minp =+ return (Right ((Nothing, ProverError msg), M.minpModuleEnv minp), []) data CryptolState t = CryptolState@@ -234,12 +235,13 @@ M.ModuleT IO (Either String ([FinType],[VarShape (What4 sym)],W4.Pred sym, W4.Pred sym) )-prepareQuery sym ProverCommand { .. } =+prepareQuery sym ProverCommand { .. } = do+ ntEnv <- M.getNewtypes case predArgTypes pcQueryType pcSchema of Left msg -> pure (Left msg) Right ts -> do args <- liftIO (mapM (freshVar (what4FreshFns (w4 sym))) ts)- (safety,b) <- simulate args+ (safety,b) <- simulate ntEnv args liftIO do -- Ignore the safety condition if the flag is set let safety' = if pcIgnoreSafety then W4.truePred (w4 sym) else safety@@ -263,7 +265,7 @@ q' <- W4.andPred (w4 sym) defs q pure (ts,args,safety',q') where- simulate args =+ simulate ntEnv args = do let lPutStrLn = M.withLogger logPutStrLn when pcVerbose (lPutStrLn "Simulating...") @@ -273,18 +275,24 @@ let ds = Map.fromList [ (prelPrim (identText (M.nameIdent nm)), EWhere (EVar nm) decls) | nm <- nms ] pure ds - let tbl = primTable sym+ getEOpts <- M.getEvalOptsAction+ let tbl = primTable sym getEOpts let ?evalPrim = \i -> (Right <$> Map.lookup i tbl) <|> (Left <$> Map.lookup i ds)+ let ?range = emptyRange+ callStacks <- M.getCallStacks+ let ?callStacks = callStacks modEnv <- M.getModuleEnv let extDgs = M.allDeclGroups modEnv ++ pcExtraDecls doW4Eval (w4 sym)- do env <- Eval.evalDecls sym extDgs mempty+ do env <- Eval.evalDecls sym extDgs =<<+ Eval.evalNewtypeDecls sym ntEnv mempty+ v <- Eval.evalExpr sym env pcExpr appliedVal <-- foldM Eval.fromVFun v (map (pure . varShapeToValue sym) args)+ foldM (Eval.fromVFun sym) v (map (pure . varShapeToValue sym) args) case pcQueryType of SafetyQuery ->@@ -302,8 +310,8 @@ M.ModuleCmd (Maybe String, ProverResult) satProve solverCfg hashConsing warnUninterp ProverCommand {..} =- protectStack proverError \(evo, byteReader, modEnv) ->- M.runModuleM (evo, byteReader, modEnv)+ protectStack proverError \modIn ->+ M.runModuleM modIn do w4sym <- liftIO makeSym defVar <- liftIO (newMVar (W4.truePred w4sym)) funVar <- liftIO (newMVar mempty)@@ -374,8 +382,8 @@ satProveOffline (W4ProverConfig p) hashConsing warnUninterp cmd outputContinuation satProveOffline (W4ProverConfig (AnAdapter adpt)) hashConsing warnUninterp ProverCommand {..} outputContinuation =- protectStack onError \(evo,byteReader,modEnv) ->- M.runModuleM (evo,byteReader,modEnv)+ protectStack onError \modIn ->+ M.runModuleM modIn do w4sym <- liftIO makeSym defVar <- liftIO (newMVar (W4.truePred w4sym)) funVar <- liftIO (newMVar mempty)@@ -400,7 +408,7 @@ when hashConsing (W4.startCaching sym) pure sym - onError msg (_,_,modEnv) = pure (Right (Just msg, modEnv), [])+ onError msg minp = pure (Right (Just msg, M.minpModuleEnv minp), []) decSatNum :: SatNum -> SatNum@@ -545,8 +553,8 @@ let w = W4.intValue (W4.bvWidth x) in VarWord . Concrete.mkBv w . BV.asUnsigned <$> W4.groundEval evalFn x VarFloat fv@(W4.SFloat f) ->- do let (e,p) = W4.fpSize fv- VarFloat . FH.floatFromBits e p . BV.asUnsigned <$> W4.groundEval evalFn f+ let (e,p) = W4.fpSize fv+ in VarFloat . FH.BF e p <$> W4.groundEval evalFn f VarFinSeq n vs -> VarFinSeq n <$> mapM (varShapeToConcrete evalFn) vs VarTuple vs ->
src/Cryptol/Testing/Random.hs view
@@ -10,6 +10,7 @@ {-# LANGUAGE BangPatterns #-} {-# LANGUAGE FlexibleContexts #-}+{-# LANGUAGE MultiWayIf #-} {-# LANGUAGE RecordWildCards #-} {-# LANGUAGE ScopedTypeVariables #-} {-# LANGUAGE Trustworthy #-}@@ -19,7 +20,6 @@ , randomValue , dumpableType , testableType-, TestReport(..) , TestResult(..) , isPass , returnTests@@ -28,21 +28,23 @@ ) where import qualified Control.Exception as X-import Control.Monad (join, liftM2)+import Control.Monad (liftM2) import Control.Monad.IO.Class (MonadIO(..))-import Data.Ratio ((%))+import Data.Bits import Data.List (unfoldr, genericTake, genericIndex, genericReplicate) import qualified Data.Sequence as Seq import System.Random (RandomGen, split, random, randomR) import Cryptol.Backend (Backend(..), SRational(..))-import Cryptol.Backend.Monad (runEval,Eval,EvalError(..))+import Cryptol.Backend.FloatHelpers (floatFromBits)+import Cryptol.Backend.Monad (runEval,Eval,EvalErrorEx(..)) import Cryptol.Backend.Concrete import Cryptol.Eval.Type (TValue(..)) import Cryptol.Eval.Value (GenValue(..),SeqMap(..), WordValue(..),- ppValue, defaultPPOpts, finiteSeqMap)+ ppValue, defaultPPOpts, finiteSeqMap, fromVFun)+import Cryptol.TypeCheck.Solver.InfNat (widthInteger) import Cryptol.Utils.Ident (Ident) import Cryptol.Utils.Panic (panic) import Cryptol.Utils.RecordMap@@ -68,7 +70,7 @@ runOneTest fun argGens sz g0 = do let (args, g1) = foldr mkArg ([], g0) argGens mkArg argGen (as, g) = let (a, g') = argGen sz g in (a:as, g')- args' <- runEval (sequence args)+ args' <- runEval mempty (sequence args) result <- evalTest fun args' return (result, g1) @@ -81,12 +83,14 @@ returnOneTest fun argGens sz g0 = do let (args, g1) = foldr mkArg ([], g0) argGens mkArg argGen (as, g) = let (a, g') = argGen sz g in (a:as, g')- args' <- runEval (sequence args)- result <- runEval (go fun args')+ args' <- runEval mempty (sequence args)+ result <- runEval mempty (go fun args') return (args', result, g1) where- go (VFun f) (v : vs) = join (go <$> (f (pure v)) <*> pure vs)- go (VFun _) [] = panic "Cryptol.Testing.Random" ["Not enough arguments to function while generating tests"]+ go f@VFun{} (v : vs) =+ do f' <- fromVFun Concrete f (pure v)+ go f' vs+ go VFun{} [] = panic "Cryptol.Testing.Random" ["Not enough arguments to function while generating tests"] go _ (_ : _) = panic "Cryptol.Testing.Random" ["Too many arguments to function while generating tests"] go v [] = return v @@ -147,7 +151,9 @@ TVRec fs -> do gs <- traverse (randomValue sym) fs return (randomRecord gs)-+ TVNewtype _ _ fs ->+ do gs <- traverse (randomValue sym) fs+ return (randomRecord gs) TVArray{} -> Nothing TVFun{} -> Nothing TVAbstract{} -> Nothing@@ -226,7 +232,8 @@ let f g = let (x,g') = mkElem sz g in seq x (Just (x, g')) let xs = Seq.fromList $ genericTake w $ unfoldr f g1- seq xs (pure $ VSeq w $ IndexSeqMap $ (Seq.index xs . fromInteger), g2)+ let v = VSeq w $ IndexSeqMap $ \i -> Seq.index xs (fromInteger i)+ seq xs (pure v, g2) {-# INLINE randomTuple #-} @@ -256,20 +263,42 @@ Integer {- ^ Exponent width -} -> Integer {- ^ Precision width -} -> Gen g sym-randomFloat sym e p w g =- ( VFloat <$> fpLit sym e p (nu % de)- , g3- )+randomFloat sym e p w g0 =+ let sz = max 0 (min 100 w)+ ( x, g') = randomR (0, 10*(sz+1)) g0+ in if | x < 2 -> (VFloat <$> fpNaN sym e p, g')+ | x < 4 -> (VFloat <$> fpPosInf sym e p, g')+ | x < 6 -> (VFloat <$> (fpNeg sym =<< fpPosInf sym e p), g')+ | x < 8 -> (VFloat <$> fpLit sym e p 0, g')+ | x < 10 -> (VFloat <$> (fpNeg sym =<< fpLit sym e p 0), g')+ | x <= sz -> genSubnormal g' -- about 10% of the time+ | x <= 4*(sz+1) -> genBinary g' -- about 40%+ | otherwise -> genNormal (toInteger sz) g' -- remaining ~50%+ where- -- XXX: we never generat NaN- -- XXX: Not sure that we need such big integers, we should probably- -- use `e` and `p` as a guide.- (n, g1) = if w < 100 then (fromInteger w, g) else randomSize 8 100 g- (nu, g2) = randomR (- 256^n, 256^n) g1- (de, g3) = randomR (1, 256^n) g2+ emax = bit (fromInteger e) - 1+ smax = bit (fromInteger p) - 1 + -- generates floats uniformly chosen from among all bitpatterns+ genBinary g =+ let (v, g1) = randomR (0, bit (fromInteger (e+p)) - 1) g+ in (VFloat <$> (fpFromBits sym e p =<< wordLit sym (e+p) v), g1) + -- generates floats corresponding to subnormal values. These are+ -- values with 0 biased exponent and nonzero mantissa.+ genSubnormal g =+ let (sgn, g1) = random g+ (v, g2) = randomR (1, bit (fromInteger p) - 1) g1+ in (VFloat <$> ((if sgn then fpNeg sym else pure) =<< fpFromBits sym e p =<< wordLit sym (e+p) v), g2) + -- generates floats where the exponent and mantissa are scaled by the size+ genNormal sz g =+ let (sgn, g1) = random g+ (ex, g2) = randomR ((1-emax)*sz `div` 100, (sz*emax) `div` 100) g1+ (mag, g3) = randomR (1, max 1 ((sz*smax) `div` 100)) g2+ r = fromInteger mag ^^ (ex - widthInteger mag)+ r' = if sgn then negate r else r+ in (VFloat <$> fpLit sym e p r', g3) -- | A test result is either a pass, a failure due to evaluating to@@ -277,7 +306,7 @@ data TestResult = Pass | FailFalse [Value]- | FailError EvalError [Value]+ | FailError EvalErrorEx [Value] isPass :: TestResult -> Bool isPass Pass = True@@ -291,15 +320,16 @@ evalTest v0 vs0 = run `X.catch` handle where run = do- result <- runEval (go v0 vs0)+ result <- runEval mempty (go v0 vs0) if result then return Pass else return (FailFalse vs0) handle e = return (FailError e vs0) go :: Value -> [Value] -> Eval Bool- go (VFun f) (v : vs) = join (go <$> (f (pure v)) <*> return vs)- go (VFun _) [] = panic "Not enough arguments while applying function"+ go f@VFun{} (v : vs) = do f' <- fromVFun Concrete f (pure v)+ go f' vs+ go VFun{} [] = panic "Not enough arguments while applying function" [] go (VBit b) [] = return b go v vs = do vdoc <- ppValue Concrete defaultPPOpts v@@ -348,7 +378,7 @@ TVInteger -> Nothing TVRational -> Nothing TVIntMod n -> Just n- TVFloat{} -> Nothing -- TODO?+ TVFloat e p -> Just (2 ^ (e+p)) TVArray{} -> Nothing TVStream{} -> Nothing TVSeq n el -> (^ n) <$> typeSize el@@ -356,25 +386,26 @@ TVRec fs -> product <$> traverse typeSize fs TVFun{} -> Nothing TVAbstract{} -> Nothing+ TVNewtype _ _ tbody -> typeSize (TVRec tbody) {- | Returns all the values in a type. Returns an empty list of values, for types where 'typeSize' returned 'Nothing'. -} typeValues :: TValue -> [Value] typeValues ty = case ty of- TVBit -> [ VBit False, VBit True ]- TVInteger -> []- TVRational -> []- TVIntMod n -> [ VInteger x | x <- [ 0 .. (n-1) ] ]- TVFloat{} -> [] -- TODO?- TVArray{} -> []- TVStream{} -> []+ TVBit -> [ VBit False, VBit True ]+ TVInteger -> []+ TVRational -> []+ TVIntMod n -> [ VInteger x | x <- [ 0 .. (n-1) ] ]+ TVFloat e p -> [ VFloat (floatFromBits e p v) | v <- [0 .. 2^(e+p) - 1] ]+ TVArray{} -> []+ TVStream{} -> [] TVSeq n TVBit -> [ VWord n (pure (WordVal (BV n x))) | x <- [ 0 .. 2^n - 1 ] ] TVSeq n el ->- [ VSeq n (finiteSeqMap Concrete (map pure xs))+ [ VSeq n (finiteSeqMap (map pure xs)) | xs <- sequence (genericReplicate n (typeValues el)) ] TVTuple ts ->@@ -387,16 +418,10 @@ ] TVFun{} -> [] TVAbstract{} -> []+ TVNewtype _ _ tbody -> typeValues (TVRec tbody) -------------------------------------------------------------------------------- -- Driver function--data TestReport = TestReport {- reportResult :: TestResult- , reportProp :: String -- ^ The property as entered by the user- , reportTestsRun :: Integer- , reportTestsPossible :: Maybe Integer- } exhaustiveTests :: MonadIO m => (Integer -> m ()) {- ^ progress callback -} ->
src/Cryptol/Transform/AddModParams.hs view
@@ -230,6 +230,7 @@ in ESel (EVar paramModRecParam) (RecordSel (nameIdent x) (Just sh)) | otherwise -> EVar x + ELocated r t -> ELocated r (inst ps t) EList es t -> EList (inst ps es) (inst ps t) ETuple es -> ETuple (inst ps es) ERec fs -> ERec (fmap (inst ps) fs)@@ -288,17 +289,13 @@ where ts1 = inst ps ts t1 = inst ps t - TCon tc ts ->- case tc of- TC (TCNewtype (UserTC x k))- | needsInst ps x -> TCon (TC (TCNewtype (UserTC x (k1 k))))- (newTs ++ ts1)- _ -> TCon tc ts1- where- ts1 = inst ps ts- newTs = instTyParams ps- k1 k = foldr (:->) k (map kindOf newTs)+ TNewtype nt ts+ | needsInst ps (ntName nt) -> TNewtype (inst ps nt) (instTyParams ps ++ ts1)+ | otherwise -> TNewtype nt ts1+ where ts1 = inst ps ts + TCon tc ts -> TCon tc (inst ps ts)+ TVar x | Just x' <- isTParam ps x -> TVar (TVBound x') | otherwise -> ty @@ -311,7 +308,7 @@ instance Inst Newtype where inst ps nt = nt { ntConstraints = inst ps (ntConstraints nt)- , ntFields = [ (f, inst ps t) | (f,t) <- ntFields nt ]+ , ntFields = fmap (inst ps) (ntFields nt) }
src/Cryptol/Transform/MonoValues.hs view
@@ -179,6 +179,7 @@ Nothing -> EProofApp <$> go e Just yes -> return yes + ELocated r t -> ELocated r <$> go t EList es t -> EList <$> mapM go es <*> return t ETuple es -> ETuple <$> mapM go es ERec fs -> ERec <$> traverse go fs
src/Cryptol/Transform/Specialize.hs view
@@ -59,17 +59,18 @@ -- type-specialized versions of all functions called (transitively) by -- the body of the expression. specialize :: Expr -> M.ModuleCmd Expr-specialize expr (ev, byteReader, modEnv) = run $ do- let extDgs = allDeclGroups modEnv+specialize expr minp = run $ do+ let extDgs = allDeclGroups (M.minpModuleEnv minp) let (tparams, expr') = destETAbs expr spec' <- specializeEWhere expr' extDgs return (foldr ETAbs spec' tparams) where- run = M.runModuleT (ev, byteReader, modEnv) . fmap fst . runSpecT Map.empty+ run = M.runModuleT minp . fmap fst . runSpecT Map.empty specializeExpr :: Expr -> SpecM Expr specializeExpr expr = case expr of+ ELocated r e -> ELocated r <$> specializeExpr e EList es t -> EList <$> traverse specializeExpr es <*> pure t ETuple es -> ETuple <$> traverse specializeExpr es ERec fs -> ERec <$> traverse specializeExpr fs
src/Cryptol/TypeCheck.hs view
@@ -52,6 +52,8 @@ import Cryptol.Utils.PP import Cryptol.Utils.Panic(panic) ++ tcModule :: P.Module Name -> InferInput -> IO (InferOutput Module) tcModule m inp = runInferM inp (inferModule m) @@ -78,7 +80,9 @@ where go loc expr = case expr of- P.ELocated e loc' -> go loc' e+ P.ELocated e loc' ->+ do (te, sch) <- go loc' e+ pure $! if inpCallStacks inp then (ELocated loc' te, sch) else (te,sch) P.EVar x -> do res <- lookupVar x case res of
src/Cryptol/TypeCheck/AST.hs view
@@ -28,7 +28,7 @@ , module Cryptol.TypeCheck.Type ) where -import Cryptol.Parser.Position(Located)+import Cryptol.Parser.Position(Located,Range,HasLoc(..)) import Cryptol.ModuleSystem.Name import Cryptol.ModuleSystem.Exports(ExportSpec(..) , isExportedBind, isExportedType)@@ -124,6 +124,8 @@ | EAbs Name Type Expr -- ^ Function value + | ELocated Range Expr -- ^ Source location information+ {- | Proof abstraction. Because we don't keep proofs around we don't need to name the assumption, but we still need to record the assumption. The assumption is the 'Type' term,@@ -200,6 +202,8 @@ instance PP (WithNames Expr) where ppPrec prec (WithNames expr nm) = case expr of+ ELocated _ t -> ppWP prec t+ EList [] t -> optParens (prec > 0) $ text "[]" <+> colon <+> ppWP prec t @@ -319,7 +323,9 @@ (ts,e2) = splitWhile splitTApp e1 -+instance HasLoc Expr where+ getLoc (ELocated r _) = Just r+ getLoc _ = Nothing instance PP Expr where ppPrec n t = ppWithNamesPrec IntMap.empty n t
src/Cryptol/TypeCheck/CheckModuleInstance.hs view
@@ -112,7 +112,7 @@ src = CtPartialTypeFun nm mapM_ (newGoal src) (ntConstraints nt) - return (tp, TCon (TC (TCNewtype (UserTC nm k2))) [])+ return (tp, TNewtype nt []) -- Check that a type parameter defined as another type parameter is OK checkTP tp tp1 =
src/Cryptol/TypeCheck/Default.hs view
@@ -3,7 +3,7 @@ import qualified Data.Set as Set import Data.Map (Map) import qualified Data.Map as Map-import Data.Maybe(mapMaybe)+import Data.Maybe(mapMaybe, isJust) import Data.List((\\),nub) import Control.Monad(guard,mzero) @@ -35,14 +35,16 @@ allProps = saturatedPropSet gSet has p a = Set.member (p (TVar a)) allProps + isLiteralGoal a = isJust (Map.lookup a (literalGoals gSet)) ||+ isJust (Map.lookup a (literalLessThanGoals gSet)) tryDefVar a = -- If there is an `FLiteral` constraint we use that for defaulting. case Map.lookup a (flitDefaultCandidates gSet) of Just m -> m -- Otherwise we try to use a `Literal`- Nothing ->- do _gt <- Map.lookup a (literalGoals gSet)+ Nothing+ | isLiteralGoal a -> do defT <- if has pLogic a then mzero else if has pField a && not (has pIntegral a) then pure tRational@@ -56,6 +58,7 @@ -- to depend on return ((a,defT),w) + | otherwise -> mzero flitDefaultCandidates :: Goals -> Map TVar (Maybe ((TVar,Type),Warning)) flitDefaultCandidates gs =
src/Cryptol/TypeCheck/Depends.hs view
@@ -15,9 +15,10 @@ import Cryptol.Parser.Position(Range, Located(..), thing) import Cryptol.Parser.Names (namesB, tnamesT, tnamesC, boundNamesSet, boundNames)-import Cryptol.TypeCheck.Monad( InferM, recordError, getTVars )+import Cryptol.TypeCheck.Monad( InferM, getTVars ) import Cryptol.TypeCheck.Error(Error(..)) import Cryptol.Utils.Panic(panic)+import Cryptol.Utils.RecordMap(recordElements) import Data.List(sortBy, groupBy) import Data.Function(on)@@ -28,6 +29,7 @@ import qualified Data.Map as Map import qualified Data.Set as Set import Data.Text (Text)+import MonadLib (ExceptionT, runExceptionT, raise) data TyDecl = TS (P.TySyn Name) (Maybe Text) -- ^ Type synonym@@ -48,13 +50,13 @@ -- | Check for duplicate and recursive type synonyms. -- Returns the type-synonyms in dependency order.-orderTyDecls :: [TyDecl] -> InferM [TyDecl]+orderTyDecls :: [TyDecl] -> InferM (Either Error [TyDecl]) orderTyDecls ts = do vs <- getTVars ds <- combine $ map (toMap vs) ts let ordered = mkScc [ (t,[x],deps) | (x,(t,deps)) <- Map.toList (Map.map thing ds) ]- concat `fmap` mapM check ordered+ runExceptionT (concat `fmap` mapM check ordered) where toMap vs ty@(PT p _) =@@ -81,7 +83,7 @@ boundNamesSet vs $ boundNames (map P.tpName as) $ Set.unions $- map (tnamesT . P.value) fs+ map (tnamesT . snd) (recordElements fs) ) } )@@ -112,17 +114,12 @@ getN (AT x _) = thing (P.ptName x) getN (PT x _) = thing (P.primTName x) + check :: SCC TyDecl -> ExceptionT Error InferM [TyDecl] check (AcyclicSCC x) = return [x] -- We don't support any recursion, for now. -- We could support recursion between newtypes, or newtypes and tysysn.- check (CyclicSCC xs) =- do recordError (RecursiveTypeDecls (map getN xs))- return [] -- XXX: This is likely to cause fake errors for missing- -- type synonyms. We could avoid this by, for example, checking- -- for recursive synonym errors, when looking up tycons.--+ check (CyclicSCC xs) = raise (RecursiveTypeDecls (map getN xs)) -- | Associate type signatures with bindings and order bindings by dependency. orderBinds :: [P.Bind Name] -> [SCC (P.Bind Name)]
src/Cryptol/TypeCheck/Error.hs view
@@ -117,6 +117,10 @@ -- ^ Too many positional type arguments, in an explicit -- type instantiation + | BadParameterKind TParam Kind+ -- ^ Kind other than `*` or `#` given to parameter of+ -- type synonym, newtype, function signature, etc.+ | CannotMixPositionalAndNamedTypeParams | UndefinedTypeParameter (Located Ident)@@ -128,6 +132,9 @@ -- but we know it must be at least as large as the given type -- (or unconstrained, if Nothing). + | BareTypeApp+ -- ^ Bare expression of the form `{_}+ | UndefinedExistVar Name | TypeShadowing String Name String | MissingModTParam (Located Ident)@@ -139,6 +146,7 @@ errorImportance :: Error -> Int errorImportance err = case err of+ BareTypeApp -> 11 -- basically a parse error KindMismatch {} -> 10 TyVarWithParams {} -> 9 TypeMismatch {} -> 8@@ -151,7 +159,7 @@ MissingModTParam {} -> 10 MissingModVParam {} -> 10 -+ BadParameterKind{} -> 9 CannotMixPositionalAndNamedTypeParams {} -> 8 TooManyTypeParams {} -> 8 TooFewTyParams {} -> 8@@ -180,6 +188,7 @@ + instance TVars Warning where apSubst su warn = case warn of@@ -215,10 +224,12 @@ TooManyPositionalTypeParams -> err CannotMixPositionalAndNamedTypeParams -> err + BadParameterKind{} -> err UndefinedTypeParameter {} -> err RepeatedTypeParameter {} -> err AmbiguousSize x t -> AmbiguousSize x !$ (apSubst su t) + BareTypeApp -> err UndefinedExistVar {} -> err TypeShadowing {} -> err@@ -249,7 +260,10 @@ UndefinedTypeParameter {} -> Set.empty RepeatedTypeParameter {} -> Set.empty AmbiguousSize _ t -> fvs t+ BadParameterKind tp _ -> Set.singleton (TVBound tp) + BareTypeApp -> Set.empty+ UndefinedExistVar {} -> Set.empty TypeShadowing {} -> Set.empty MissingModTParam {} -> Set.empty@@ -378,9 +392,15 @@ , "When checking" <+> pp src ] + BadParameterKind tp k ->+ addTVarsDescsAfter names err $+ vcat [ "Illegal kind assigned to type variable:" <+> ppWithNames names tp+ , "Unexpected:" <+> pp k+ ]+ TooManyPositionalTypeParams -> addTVarsDescsAfter names err $- "Too many positional type-parameters in explicit type application"+ "Too many positional type-parameters in explicit type application." CannotMixPositionalAndNamedTypeParams -> addTVarsDescsAfter names err $@@ -403,6 +423,10 @@ Nothing -> empty in addTVarsDescsAfter names err ("Ambiguous numeric type:" <+> pp (tvarDesc x) $$ sizeMsg) + BareTypeApp ->+ "Unexpected bare type application." $$+ "Perhaps you meant `( ... ) instead."+ UndefinedExistVar x -> "Undefined type" <+> quotes (pp x) TypeShadowing this new that -> "Type" <+> text this <+> quotes (pp new) <+>@@ -475,7 +499,7 @@ PPrime -> useCtr PHas sel ->- custom ("Type" <+> doc1 <+> "does not have field" <+> f + custom ("Type" <+> doc1 <+> "does not have field" <+> f <+> "of type" <+> (tys !! 1)) where f = case sel of P.TupleSel n _ -> int n@@ -513,6 +537,10 @@ let doc2 = tys !! 1 in custom (doc1 <+> "is not a valid literal of type" <+> doc2) + PLiteralLessThan ->+ let doc2 = tys !! 1+ in custom ("Type" <+> doc2 <+> "does not contain all literals below" <+> (doc1 <> "."))+ PFLiteral -> case ts of ~[m,n,_r,_a] ->@@ -544,7 +572,7 @@ {- XXX: Currently we pick the names based on the unique of the variable: smaller uniques get an earlier name (e.g., 100 might get `a` and 200 `b`)- This may still lead to changes in the names if the uniques got reordred+ This may still lead to changes in the names if the uniques got reordered for some reason. A more stable approach might be to order the variables on their location in the error/warning, but that's quite a bit more code so for now we just go with the simple approximation. -}@@ -570,4 +598,3 @@ variant n x = if n == 0 then x else x ++ suff n variants roots = [ variant n r | n <- [ 0 .. ], r <- roots ]-
src/Cryptol/TypeCheck/Infer.hs view
@@ -169,7 +169,9 @@ -- XXX: Is there a scoping issue here? I think not, but check. P.ELocated e r ->- inRange r (appTys e ts tGoal)+ do e' <- inRange r (appTys e ts tGoal)+ cs <- getCallStacks+ if cs then pure (ELocated r e') else pure e' P.ENeg {} -> mono P.EComplement {} -> mono@@ -181,6 +183,7 @@ P.ESel {} -> mono P.EList {} -> mono P.EFromTo {} -> mono+ P.EFromToLessThan {} -> mono P.EInfFrom {} -> mono P.EComp {} -> mono P.EApp {} -> mono@@ -292,6 +295,20 @@ es' <- mapM checkElem es return (EList es' a) + P.EFromToLessThan t1 t2 mety ->+ do l <- curRange+ let fs0 =+ case mety of+ Just ety -> [("a", ety)]+ Nothing -> []+ let fs = [("first", t1), ("bound", t2)] ++ fs0+ prim <- mkPrim "fromToLessThan"+ let e' = P.EAppT prim+ [ P.NamedInst P.Named { name = Located l (packIdent x), value = y }+ | (x,y) <- fs+ ]+ checkE e' tGoal+ P.EFromTo t1 mbt2 t3 mety -> do l <- curRange let fs0 =@@ -366,9 +383,12 @@ P.Named { name = Located l (packIdent "val") , value = t }]) tGoal - P.EFun ps e -> checkFun Nothing ps e tGoal+ P.EFun desc ps e -> checkFun desc ps e tGoal - P.ELocated e r -> inRange r (checkE e tGoal)+ P.ELocated e r ->+ do e' <- inRange r (checkE e tGoal)+ cs <- getCallStacks+ if cs then pure (ELocated r e') else pure e' P.ESplit e -> do prim <- mkPrim "splitAt"@@ -388,7 +408,7 @@ Nothing -> do r <- newParamName (packIdent "r") let p = P.PVar Located { srcRange = nameLoc r, thing = r }- fe = P.EFun [p] (P.EUpd (Just (P.EVar r)) fs)+ fe = P.EFun P.emptyFunDesc [p] (P.EUpd (Just (P.EVar r)) fs) checkE fe tGoal Just e ->@@ -561,11 +581,11 @@ checkFun ::- Maybe Name -> [P.Pattern Name] -> P.Expr Name -> TypeWithSource -> InferM Expr+ P.FunDesc Name -> [P.Pattern Name] -> P.Expr Name -> TypeWithSource -> InferM Expr checkFun _ [] e tGoal = checkE e tGoal-checkFun fun ps e tGoal =+checkFun (P.FunDesc fun offset) ps e tGoal = inNewScope $- do let descs = [ TypeOfArg (ArgDescr fun (Just n)) | n <- [ 1 :: Int .. ] ]+ do let descs = [ TypeOfArg (ArgDescr fun (Just n)) | n <- [ 1 + offset .. ] ] (tys,tRes) <- expectFun fun (length ps) tGoal largs <- sequence (zipWith checkP ps (zipWith WithSource tys descs))@@ -826,8 +846,13 @@ * and vars in the inferred types that do not appear anywhere else. -} let as = sortBy numFst $ as0 ++ Set.toList (Set.difference inSigs asmpVs)- asPs = [ TParam { tpUnique = x, tpKind = k, tpFlav = TPOther Nothing- , tpInfo = i } | TVFree x k _ i <- as ]+ asPs = [ TParam { tpUnique = x+ , tpKind = k+ , tpFlav = TPUnifyVar+ , tpInfo = i+ }+ | TVFree x k _ i <- as+ ] {- Finally, we replace free variables with bound ones, and fix-up the definitions as needed to reflect that we are now working@@ -866,7 +891,7 @@ P.DExpr e -> do let nm = thing (P.bName b) let tGoal = WithSource t (DefinitionOf nm)- e1 <- checkFun (Just nm) (P.bParams b) e tGoal+ e1 <- checkFun (P.FunDesc (Just nm) 0) (P.bParams b) e tGoal let f = thing (P.bName b) return Decl { dName = f , dSignature = Forall [] [] t@@ -898,7 +923,7 @@ do (e1,cs0) <- collectGoals $ do let nm = thing (P.bName b) tGoal = WithSource t0 (DefinitionOf nm)- e1 <- checkFun (Just nm) (P.bParams b) e0 tGoal+ e1 <- checkFun (P.FunDesc (Just nm) 0) (P.bParams b) e0 tGoal addGoals validSchema () <- simplifyAllConstraints -- XXX: using `asmps` also? return e1@@ -941,8 +966,10 @@ } inferDs :: FromDecl d => [d] -> ([DeclGroup] -> InferM a) -> InferM a-inferDs ds continue = checkTyDecls =<< orderTyDecls (mapMaybe toTyDecl ds)+inferDs ds continue = either onErr checkTyDecls =<< orderTyDecls (mapMaybe toTyDecl ds) where+ onErr err = recordError err >> continue []+ isTopLevel = isTopDecl (head ds) checkTyDecls (AT t mbD : ts) =
src/Cryptol/TypeCheck/InferTypes.hs view
@@ -47,6 +47,7 @@ -- ^ Look for the solver prelude in these locations. } deriving (Show, Generic, NFData) + -- | The types of variables in the environment. data VarType = ExtVar Schema -- ^ Known type@@ -66,6 +67,10 @@ , literalGoals :: Map TVar LitGoal -- ^ An entry @(a,t)@ corresponds to @Literal t a@.++ , literalLessThanGoals :: Map TVar LitGoal+ -- ^ An entry @(a,t)@ corresponds to @LiteralLessThan t a@.+ } deriving (Show) -- | This abuses the type 'Goal' a bit. The 'goal' field contains@@ -84,15 +89,35 @@ return (a, g { goal = tn }) +litLessThanGoalToGoal :: (TVar,LitGoal) -> Goal+litLessThanGoalToGoal (a,g) = g { goal = pLiteralLessThan (goal g) (TVar a) } +goalToLitLessThanGoal :: Goal -> Maybe (TVar,LitGoal)+goalToLitLessThanGoal g =+ do (tn,a) <- matchMaybe $ do (tn,b) <- aLiteralLessThan (goal g)+ a <- aTVar b+ return (tn,a)+ return (a, g { goal = tn })++ emptyGoals :: Goals-emptyGoals = Goals { goalSet = Set.empty, saturatedPropSet = Set.empty, literalGoals = Map.empty }+emptyGoals =+ Goals+ { goalSet = Set.empty+ , saturatedPropSet = Set.empty+ , literalGoals = Map.empty+ , literalLessThanGoals = Map.empty+ } nullGoals :: Goals -> Bool-nullGoals gs = Set.null (goalSet gs) && Map.null (literalGoals gs)+nullGoals gs =+ Set.null (goalSet gs) &&+ Map.null (literalGoals gs) &&+ Map.null (literalLessThanGoals gs) fromGoals :: Goals -> [Goal] fromGoals gs = map litGoalToGoal (Map.toList (literalGoals gs)) +++ map litLessThanGoalToGoal (Map.toList (literalLessThanGoals gs)) ++ Set.toList (goalSet gs) goalsFromList :: [Goal] -> Goals@@ -106,6 +131,11 @@ let jn g1 g2 = g1 { goal = tMax (goal g1) (goal g2) } in gls { literalGoals = Map.insertWith jn a newG (literalGoals gls) , saturatedPropSet = Set.insert (pFin (TVar a)) (saturatedPropSet gls)+ }++ | Just (a,newG) <- goalToLitLessThanGoal g =+ let jn g1 g2 = g1 { goal = tMax (goal g1) (goal g2) } in+ gls { literalLessThanGoals = Map.insertWith jn a newG (literalLessThanGoals gls) } -- If the goal is already implied by some other goal, skip it
src/Cryptol/TypeCheck/Instantiate.hs view
@@ -102,9 +102,9 @@ where src = case drop (n-1) {- count from 1 -} as of p:_ ->- case tpFlav p of- TPOther (Just a) -> TypeParamInstNamed nm (nameIdent a)- _ -> TypeParamInstPos nm n+ case tpName p of+ Just a -> TypeParamInstNamed nm (nameIdent a)+ _ -> TypeParamInstPos nm n _ -> panic "instantiateWithPos" [ "Invalid parameter index", show n, show as ]
src/Cryptol/TypeCheck/Kind.hs view
@@ -20,7 +20,6 @@ ) where import qualified Cryptol.Parser.AST as P-import Cryptol.Parser.AST (Named(..)) import Cryptol.Parser.Position import Cryptol.TypeCheck.AST import Cryptol.TypeCheck.Error@@ -37,7 +36,7 @@ import Data.Maybe(fromMaybe) import Data.Function(on) import Data.Text (Text)-import Control.Monad(unless,forM,when)+import Control.Monad(unless,when) @@ -114,11 +113,8 @@ do ((as1,fs1),gs) <- collectGoals $ inRange (srcRange x) $ do r <- withTParams NoWildCards newtypeParam as $- forM fs $ \field ->- let n = name field- in kInRange (srcRange n) $- do t1 <- doCheckType (value field) (Just KType)- return (thing n, t1)+ flip traverseRecordMap fs $ \_n (rng,f) ->+ kInRange rng $ doCheckType f (Just KType) simplifyAllConstraints return r @@ -132,7 +128,7 @@ checkPrimType :: P.PrimType Name -> Maybe Text -> InferM AbstractType checkPrimType p mbD = do let (as,cs) = P.primTCts p- (as',cs') <- withTParams NoWildCards (TPOther . Just) as $+ (as',cs') <- withTParams NoWildCards TPPrimParam as $ mapM checkProp cs pure AbstractType { atName = thing (P.primTName p) , atKind = cvtK (thing (P.primTKind p))@@ -265,10 +261,13 @@ checkKind (TUser x ts1 t1) k k1 checkNewTypeUse nt =- do let tc = newtypeTyCon nt- (ts1,_) <- appTy ts (kindOf tc)- ts2 <- checkParams (ntParams nt) ts1- return (TCon tc ts2)+ do (ts1,k1) <- appTy ts (kindOf nt)+ let as = ntParams nt+ ts2 <- checkParams as ts1+ let su = zip as ts2+ ps1 <- mapM (`kInstantiateT` su) (ntConstraints nt)+ kNewGoals (CtPartialTypeFun (ntName nt)) ps1+ checkKind (TNewtype nt ts2) k k1 checkAbstractTypeUse absT = do let tc = abstractTypeTC absT@@ -388,8 +387,8 @@ P.TInfix t x _ u-> doCheckType (P.TUser (thing x) [t, u]) k - P.TTyApp _fs -> panic "doCheckType"- ["TTyApp found when kind checking, but it should have been eliminated already"]+ P.TTyApp _fs -> do kRecordError BareTypeApp+ kNewType TypeWildCard KNum where checkF _nm (rng,v) = kInRange rng $ doCheckType v (Just KType)
src/Cryptol/TypeCheck/Monad.hs view
@@ -74,6 +74,8 @@ , inpMonoBinds :: Bool -- ^ Should local bindings without -- signatures be monomorphized? + , inpCallStacks :: Bool -- ^ Are we tracking call stacks?+ , inpSolverConfig :: SolverConfig -- ^ Options for the constraint solver , inpSearchPath :: [FilePath] -- ^ Where to look for Cryptol theory file.@@ -83,8 +85,9 @@ -- identifier (e.g., @number@). , inpSupply :: !Supply -- ^ The supply for fresh name generation- } deriving Show + , inpSolver :: SMT.Solver -- ^ Solver connection for typechecking+ } -- | This is used for generating various names. data NameSeeds = NameSeeds@@ -114,7 +117,7 @@ io $ modifyIORef' iSolveCounter (+1) runInferM :: TVars a => InferInput -> InferM a -> IO (InferOutput a)-runInferM info (IM m) = SMT.withSolver (inpSolverConfig info) $ \solver ->+runInferM info (IM m) = do counter <- newIORef 0 rec ro <- return RO { iRange = inpRange info , iVars = Map.map ExtVar (inpVars info)@@ -128,7 +131,8 @@ , iSolvedHasLazy = iSolvedHas finalRW -- RECURSION , iMonoBinds = inpMonoBinds info- , iSolver = solver+ , iCallStacks = inpCallStacks info+ , iSolver = inpSolver info , iPrimNames = inpPrimNames info , iSolveCounter = counter }@@ -232,6 +236,10 @@ -- in where-blocks will never be generalized. Bindings with type -- signatures, and all bindings at top level are unaffected. + , iCallStacks :: Bool+ -- ^ When this flag is true, retain source location information+ -- in typechecked terms+ , iSolver :: SMT.Solver , iPrimNames :: !PrimMap@@ -475,22 +483,54 @@ in (TVFree x k vs msg, s { seedTVar = x + 1 }) +-- | Check that the given "flavor" of parameter is allowed to+-- have the given type, and raise an error if not+checkParamKind :: TParam -> TPFlavor -> Kind -> InferM () +checkParamKind tp flav k =+ case flav of+ TPModParam _ -> return () -- All kinds allowed as module parameters+ TPPropSynParam _ -> starOrHashOrProp+ TPTySynParam _ -> starOrHash+ TPSchemaParam _ -> starOrHash+ TPNewtypeParam _ -> starOrHash+ TPPrimParam _ -> starOrHash+ TPUnifyVar -> starOrHash++ where+ starOrHashOrProp =+ case k of+ KNum -> return ()+ KType -> return ()+ KProp -> return ()+ _ -> recordError (BadParameterKind tp k)++ starOrHash =+ case k of+ KNum -> return ()+ KType -> return ()+ _ -> recordError (BadParameterKind tp k)++ -- | Generate a new free type variable. newTParam :: P.TParam Name -> TPFlavor -> Kind -> InferM TParam-newTParam nm flav k = newName $ \s ->- let x = seedTVar s- in (TParam { tpUnique = x- , tpKind = k- , tpFlav = flav- , tpInfo = desc- }- , s { seedTVar = x + 1 })- where desc = TVarInfo { tvarDesc = TVFromSignature (P.tpName nm)- , tvarSource = fromMaybe emptyRange (P.tpRange nm)+newTParam nm flav k =+ do let desc = TVarInfo { tvarDesc = TVFromSignature (P.tpName nm)+ , tvarSource = fromMaybe emptyRange (P.tpRange nm)+ }+ tp <- newName $ \s ->+ let x = seedTVar s+ in (TParam { tpUnique = x+ , tpKind = k+ , tpFlav = flav+ , tpInfo = desc }+ , s { seedTVar = x + 1 }) + checkParamKind tp flav k+ return tp + -- | Generate an unknown type. The doc is a note about what is this type about. newType :: TypeSource -> Kind -> InferM Type newType src k = TVar `fmap` newTVar src k@@ -692,6 +732,9 @@ getMonoBinds :: InferM Bool getMonoBinds = IM (asks iMonoBinds) +getCallStacks :: InferM Bool+getCallStacks = IM (asks iCallStacks)+ {- | We disallow shadowing between type synonyms and type variables because it is confusing. As a bonus, in the implementation we don't need to worry about where we lookup things (i.e., in the variable or@@ -942,5 +985,3 @@ kInInferM :: InferM a -> KindM a kInInferM m = KM $ lift $ lift m--
src/Cryptol/TypeCheck/Parseable.hs view
@@ -31,6 +31,7 @@ showParseable :: t -> Doc instance ShowParseable Expr where+ showParseable (ELocated _ e) = showParseable e -- TODO? emit range information showParseable (EList es _) = parens (text "EList" <+> showParseable es) showParseable (ETuple es) = parens (text "ETuple" <+> showParseable es) showParseable (ERec ides) = parens (text "ERec" <+> showParseable (canonicalFields ides))
src/Cryptol/TypeCheck/Sanity.hs view
@@ -15,7 +15,7 @@ ) where -import Cryptol.Parser.Position(thing)+import Cryptol.Parser.Position(thing,Range,emptyRange) import Cryptol.TypeCheck.AST import Cryptol.TypeCheck.Subst (apSubst, singleTParamSubst) import Cryptol.TypeCheck.Monad(InferInput(..))@@ -31,15 +31,15 @@ import qualified Data.Map as Map -tcExpr :: InferInput -> Expr -> Either Error (Schema, [ ProofObligation ])+tcExpr :: InferInput -> Expr -> Either (Range, Error) (Schema, [ ProofObligation ]) tcExpr env e = runTcM env (exprSchema e) -tcDecls :: InferInput -> [DeclGroup] -> Either Error [ ProofObligation ]+tcDecls :: InferInput -> [DeclGroup] -> Either (Range, Error) [ ProofObligation ] tcDecls env ds0 = case runTcM env (checkDecls ds0) of Left err -> Left err Right (_,ps) -> Right ps -tcModule :: InferInput -> Module -> Either Error [ ProofObligation ]+tcModule :: InferInput -> Module -> Either (Range, Error) [ ProofObligation ] tcModule env m = case runTcM env check of Left err -> Left err Right (_,ps) -> Right ps@@ -68,6 +68,10 @@ do ks <- mapM checkType ts checkKind (kindOf tc) ks + TNewtype nt ts ->+ do ks <- mapM checkType ts+ checkKind (kindOf nt) ks+ TVar tv -> lookupTVar tv TRec fs ->@@ -143,6 +147,8 @@ exprSchema expr = case expr of + ELocated rng t -> withRange rng (exprSchema t)+ EList es t -> do checkTypeIs KType t forM_ es $ \e ->@@ -367,6 +373,12 @@ | tc1 == tc2 -> goMany ts1 ts2 _ -> err + TNewtype nt1 ts1 ->+ case other of+ TNewtype nt2 ts2+ | nt1 == nt2 -> goMany ts1 ts2+ _ -> err+ TRec fs -> case other of TRec gs ->@@ -444,6 +456,7 @@ data RO = RO { roTVars :: Map Int TParam , roAsmps :: [Prop]+ , roRange :: Range , roVars :: Map Name Schema } @@ -453,7 +466,7 @@ { woProofObligations :: [ProofObligation] } -newtype TcM a = TcM (ReaderT RO (ExceptionT Error (StateT RW Id)) a)+newtype TcM a = TcM (ReaderT RO (ExceptionT (Range, Error) (StateT RW Id)) a) instance Functor TcM where fmap = liftM@@ -468,7 +481,7 @@ let TcM m1 = f a m1) -runTcM :: InferInput -> TcM a -> Either Error (a, [ProofObligation])+runTcM :: InferInput -> TcM a -> Either (Range, Error) (a, [ProofObligation]) runTcM env (TcM m) = case runM m ro rw of (Left err, _) -> Left err@@ -478,6 +491,7 @@ | tp <- Map.elems (inpParamTypes env) , let x = mtpParam tp ] , roAsmps = map thing (inpParamConstraints env)+ , roRange = emptyRange , roVars = Map.union (fmap mvpType (inpParamFuns env)) (inpVars env)@@ -511,12 +525,19 @@ deriving Show reportError :: Error -> TcM a-reportError e = TcM (raise e)+reportError e = TcM $+ do ro <- ask+ raise (roRange ro, e) withTVar :: TParam -> TcM a -> TcM a withTVar a (TcM m) = TcM $ do ro <- ask local ro { roTVars = Map.insert (tpUnique a) a (roTVars ro) } m++withRange :: Range -> TcM a -> TcM a+withRange rng (TcM m) = TcM $+ do ro <- ask+ local ro { roRange = rng } m withAsmp :: Prop -> TcM a -> TcM a withAsmp p (TcM m) = TcM $
src/Cryptol/TypeCheck/SimpType.hs view
@@ -19,6 +19,7 @@ | otherwise -> go t TVar _ -> ty TRec xs -> TRec (fmap go xs)+ TNewtype nt xs -> TNewtype nt (map go xs) TCon tc ts -> tCon tc (map go ts) tRebuild :: Type -> Type
src/Cryptol/TypeCheck/SimpleSolver.hs view
@@ -11,6 +11,7 @@ , solveIntegralInst, solveFieldInst, solveRoundInst , solveEqInst, solveCmpInst, solveSignedCmpInst , solveLiteralInst+ , solveLiteralLessThanInst , solveValidFloat, solveFLiteralInst ) @@ -55,6 +56,7 @@ TCon (PC PCmp) [ty] -> solveCmpInst ty TCon (PC PSignedCmp) [ty] -> solveSignedCmpInst ty TCon (PC PLiteral) [t1,t2] -> solveLiteralInst t1 t2+ TCon (PC PLiteralLessThan) [t1,t2] -> solveLiteralLessThanInst t1 t2 TCon (PC PFLiteral) [t1,t2,t3,t4] -> solveFLiteralInst t1 t2 t3 t4 TCon (PC PValidFloat) [t1,t2] -> solveValidFloat t1 t2
src/Cryptol/TypeCheck/Solver/Class.hs view
@@ -20,14 +20,15 @@ , solveCmpInst , solveSignedCmpInst , solveLiteralInst+ , solveLiteralLessThanInst , solveFLiteralInst , solveValidFloat ) where import qualified LibBF as FP -import Cryptol.TypeCheck.Type-import Cryptol.TypeCheck.SimpType (tAdd,tWidth)+import Cryptol.TypeCheck.Type hiding (tSub)+import Cryptol.TypeCheck.SimpType (tAdd,tSub,tWidth,tMax) import Cryptol.TypeCheck.Solver.Types import Cryptol.Utils.RecordMap @@ -99,6 +100,9 @@ -- (Zero a, Zero b) => Zero { x1 : a, x2 : b } TRec fs -> SolvedIf [ pZero ety | ety <- recordElements fs ] + -- Zero <newtype> -> fails+ TNewtype{} -> Unsolvable+ _ -> Unsolved -- | Solve a Logic constraint by instance, if possible.@@ -135,6 +139,9 @@ -- (Logic a, Logic b) => Logic { x1 : a, x2 : b } TRec fs -> SolvedIf [ pLogic ety | ety <- recordElements fs ] + -- Logic <newtype> -> fails+ TNewtype{} -> Unsolvable+ _ -> Unsolved @@ -172,6 +179,9 @@ -- (Ring a, Ring b) => Ring { x1 : a, x2 : b } TRec fs -> SolvedIf [ pRing ety | ety <- recordElements fs ] + -- Ring <newtype> -> fails+ TNewtype{} -> Unsolvable+ _ -> Unsolved @@ -256,6 +266,9 @@ -- Field {x : a, y : b, ...} fails TRec _ -> Unsolvable + -- Field <newtype> -> fails+ TNewtype{} -> Unsolvable+ _ -> Unsolved @@ -295,6 +308,9 @@ -- Round {x : a, y : b, ...} fails TRec _ -> Unsolvable + -- Round <newtype> -> fails+ TNewtype{} -> Unsolvable+ _ -> Unsolved @@ -333,6 +349,9 @@ -- (Eq a, Eq b) => Eq { x:a, y:b } TRec fs -> SolvedIf [ pEq e | e <- recordElements fs ] + -- Eq <newtype> -> fails+ TNewtype{} -> Unsolvable+ _ -> Unsolved @@ -370,6 +389,9 @@ -- (Cmp a, Cmp b) => Cmp { x:a, y:b } TRec fs -> SolvedIf [ pCmp e | e <- recordElements fs ] + -- Cmp <newtype> -> fails+ TNewtype{} -> Unsolvable+ _ -> Unsolved @@ -422,6 +444,9 @@ -- (SignedCmp a, SignedCmp b) => SignedCmp { x:a, y:b } TRec fs -> SolvedIf [ pSignedCmp e | e <- recordElements fs ] + -- SignedCmp <newtype> -> fails+ TNewtype{} -> Unsolvable+ _ -> Unsolved @@ -459,6 +484,7 @@ _ -> Unsolvable + -- | Solve Literal constraints. solveLiteralInst :: Type -> Type -> Solved solveLiteralInst val ty@@ -490,12 +516,11 @@ | otherwise -> Unsolved - -- (fin val, fin m, m >= val + 1) => Literal val (Z m) TCon (TC TCIntMod) [modulus] -> SolvedIf [ pFin val, pFin modulus, modulus >== tAdd val tOne ] - -- (fin bits, bits => width n) => Literal n [bits]+ -- (fin bits, bits >= width n) => Literal n [bits] TCon (TC TCSeq) [bits, elTy] | TCon (TC TCBit) [] <- ety -> SolvedIf [ pFin val, pFin bits, bits >== tWidth val ]@@ -507,3 +532,50 @@ _ -> Unsolvable +-- | Solve Literal constraints.+solveLiteralLessThanInst :: Type -> Type -> Solved+solveLiteralLessThanInst val ty+ | TCon (TError {}) _ <- tNoUser val = Unsolvable+ | otherwise =+ case tNoUser ty of++ -- Literal n Error -> fails+ TCon (TError {}) _ -> Unsolvable++ -- (2 >= val) => LiteralLessThan val Bit+ TCon (TC TCBit) [] -> SolvedIf [ tTwo >== val ]++ -- LiteralLessThan val Integer+ TCon (TC TCInteger) [] -> SolvedIf [ ]++ -- LiteralLessThan val Rational+ TCon (TC TCRational) [] -> SolvedIf [ ]++ -- ValidFloat e p => LiteralLessThan val (Float e p) if `val-1` is representable+ -- RWD Should we remove this instance for floats?+ TCon (TC TCFloat) [e, p]+ | Just n <- tIsNum val+ , n > 0+ , Just opts <- knownSupportedFloat e p ->+ let bf = FP.bfFromInteger (n-1)+ in case FP.bfRoundFloat opts bf of+ (bf1,FP.Ok) | bf == bf1 -> SolvedIf []+ _ -> Unsolvable++ | otherwise -> Unsolved++ -- (fin val, fin m, m >= val) => LiteralLessThan val (Z m)+ TCon (TC TCIntMod) [modulus] ->+ SolvedIf [ pFin val, pFin modulus, modulus >== val ]++ -- (fin bits, bits >= lg2 n) => LiteralLessThan n [bits]+ TCon (TC TCSeq) [bits, elTy]+ | TCon (TC TCBit) [] <- ety ->+ SolvedIf [ pFin val, pFin bits, bits >== tWidth val' ]+ | TVar _ <- ety -> Unsolved+ where ety = tNoUser elTy+ val' = tSub (tMax val tOne) tOne++ TVar _ -> Unsolved++ _ -> Unsolvable
src/Cryptol/TypeCheck/Solver/Improve.hs view
@@ -45,6 +45,8 @@ improveLit impSkol prop -- XXX: others +-- Whenever we have `Literal n [m]a`,+-- we can learn that `a = Bit` improveLit :: Bool -> Prop -> Match (Subst, [Prop]) improveLit impSkol prop = do (_,t) <- aLiteral prop@@ -53,7 +55,6 @@ unless impSkol $ guard (isFreeTV a) let su = uncheckedSingleSubst a tBit return (su, [])- -- | Improvements from equality constraints.
src/Cryptol/TypeCheck/Solver/SMT.hs view
@@ -16,6 +16,8 @@ ( -- * Setup Solver , withSolver+ , startSolver+ , stopSolver , isNumeric -- * Debugging@@ -65,21 +67,20 @@ -- ^ For debugging } --- | Execute a computation with a fresh solver instance.-withSolver :: SolverConfig -> (Solver -> IO a) -> IO a-withSolver SolverConfig{ .. } =- bracket- (do logger <- if solverVerbose > 0 then SMT.newLogger 0- else return quietLogger- let smtDbg = if solverVerbose > 1 then Just logger else Nothing- solver <- SMT.newSolver solverPath solverArgs smtDbg- _ <- SMT.setOptionMaybe solver ":global-decls" "false"- -- SMT.setLogic solver "QF_LIA"- let sol = Solver { .. }- loadTcPrelude sol solverPreludePath- return sol)- (\s -> void $ SMT.stop (solver s))+-- | Start a fresh solver instance+startSolver :: SolverConfig -> IO Solver+startSolver SolverConfig { .. } =+ do logger <- if solverVerbose > 0 then SMT.newLogger 0 + else return quietLogger+ let smtDbg = if solverVerbose > 1 then Just logger else Nothing+ solver <- SMT.newSolver solverPath solverArgs smtDbg+ _ <- SMT.setOptionMaybe solver ":global-decls" "false"+ -- SMT.setLogic solver "QF_LIA"+ let sol = Solver { .. }+ loadTcPrelude sol solverPreludePath+ return sol+ where quietLogger = SMT.Logger { SMT.logMessage = \_ -> return () , SMT.logLevel = return 0@@ -88,7 +89,14 @@ , SMT.logUntab = return () } +-- | Shut down a solver instance+stopSolver :: Solver -> IO ()+stopSolver s = void $ SMT.stop (solver s) +-- | Execute a computation with a fresh solver instance.+withSolver :: SolverConfig -> (Solver -> IO a) -> IO a+withSolver cfg = bracket (startSolver cfg) stopSolver+ -- | Load the definitions used for type checking. loadTcPrelude :: Solver -> [FilePath] {- ^ Search in this paths -} -> IO () loadTcPrelude s [] = loadString s cryptolTcContents@@ -388,8 +396,3 @@ mk tvs f (x,y,z) = SMT.fun f [ toSMT tvs x, toSMT tvs y, toSMT tvs z ] -------------------------------------------------------------------------------------
src/Cryptol/TypeCheck/Solver/Selector.hs view
@@ -10,7 +10,7 @@ import Cryptol.TypeCheck.AST import Cryptol.TypeCheck.InferTypes-import Cryptol.TypeCheck.Monad( InferM, unify, newGoals, lookupNewtype+import Cryptol.TypeCheck.Monad( InferM, unify, newGoals , newType, applySubst, solveHasGoal , newParamName )@@ -66,21 +66,18 @@ (RecordSel l _, ty) -> case ty of- TRec fs -> return (lookupField l fs)+ TRec fs -> return (lookupField l fs)+ TNewtype nt ts ->+ case lookupField l (ntFields nt) of+ Nothing -> return Nothing+ Just t ->+ do let su = listParamSubst (zip (ntParams nt) ts)+ newGoals (CtPartialTypeFun (ntName nt))+ $ apSubst su $ ntConstraints nt+ return $ Just $ apSubst su t+ TCon (TC TCSeq) [len,el] -> liftSeq len el TCon (TC TCFun) [t1,t2] -> liftFun t1 t2- TCon (TC (TCNewtype (UserTC x _))) ts ->- do mb <- lookupNewtype x- case mb of- Nothing -> return Nothing- Just nt ->- case lookup l (ntFields nt) of- Nothing -> return Nothing- Just t ->- do let su = listParamSubst (zip (ntParams nt) ts)- newGoals (CtPartialTypeFun x)- $ apSubst su $ ntConstraints nt- return $ Just $ apSubst su t _ -> return Nothing (TupleSel n _, ty) ->
src/Cryptol/TypeCheck/Solver/Utils.hs view
@@ -22,6 +22,7 @@ go ty = case ty of TVar x -> return (x, tNum (0::Int)) TRec {} -> []+ TNewtype{} -> [] TUser _ _ t -> go t TCon (TF TCAdd) [t1,t2] -> do (a,yes) <- go t1@@ -45,6 +46,7 @@ case ty of TVar {} -> Nothing TRec {} -> Nothing+ TNewtype{} -> Nothing TUser _ _ t -> splitConstSummand t TCon (TF TCAdd) [t1,t2] -> do (k,t1') <- splitConstSummand t1@@ -63,6 +65,7 @@ case ty of TVar {} -> Nothing TRec {} -> Nothing+ TNewtype{} -> Nothing TUser _ _ t -> splitConstFactor t TCon (TF TCMul) [t1,t2] -> do (k,t1') <- splitConstFactor t1
src/Cryptol/TypeCheck/Subst.hs view
@@ -240,7 +240,8 @@ do (ts1, t1) <- anyJust2 (anyJust (apSubstMaybe su)) (apSubstMaybe su) (ts, t) Just (TUser f ts1 t1) - TRec fs -> TRec `fmap` (anyJust (apSubstMaybe su) fs)+ TRec fs -> TRec `fmap` (anyJust (apSubstMaybe su) fs)+ TNewtype nt ts -> TNewtype nt `fmap` anyJust (apSubstMaybe su) ts TVar x -> applySubstToVar su x lookupSubst :: TVar -> Subst -> Maybe Type@@ -315,6 +316,7 @@ tm' = TM { tvar = Map.fromList vars , tcon = fmap (lgo merge atNode) tcon , trec = fmap (lgo merge atNode) trec+ , tnewtype = fmap (lgo merge atNode) tnewtype } -- partition out variables that have been replaced with more specific types@@ -348,6 +350,7 @@ where go expr = case expr of+ ELocated r e -> ELocated r !$ (go e) EApp e1 e2 -> EApp !$ (go e1) !$ (go e2) EAbs x t e1 -> EAbs x !$ (apSubst su t) !$ (go e1) ETAbs a e -> ETAbs a !$ (go e)
src/Cryptol/TypeCheck/TCon.hs view
@@ -80,6 +80,7 @@ , "Cmp" ~> PC PCmp , "SignedCmp" ~> PC PSignedCmp , "Literal" ~> PC PLiteral+ , "LiteralLessThan" ~> PC PLiteralLessThan , "FLiteral" ~> PC PFLiteral -- Type functions@@ -142,7 +143,6 @@ TCSeq -> KNum :-> KType :-> KType TCFun -> KType :-> KType :-> KType TCTuple n -> foldr (:->) KType (replicate n KType)- TCNewtype x -> kindOf x TCAbstract x -> kindOf x instance HasKind PC where@@ -164,6 +164,7 @@ PCmp -> KType :-> KProp PSignedCmp -> KType :-> KProp PLiteral -> KNum :-> KType :-> KProp+ PLiteralLessThan -> KNum :-> KType :-> KProp PFLiteral -> KNum :-> KNum :-> KNum :-> KType :-> KProp PValidFloat -> KNum :-> KNum :-> KProp PAnd -> KProp :-> KProp :-> KProp@@ -214,6 +215,7 @@ | PCmp -- ^ @Cmp _@ | PSignedCmp -- ^ @SignedCmp _@ | PLiteral -- ^ @Literal _ _@+ | PLiteralLessThan -- ^ @LiteralLessThan _ _@ | PFLiteral -- ^ @FLiteral _ _ _@ | PValidFloat -- ^ @ValidFloat _ _@ constraints on supported@@ -237,7 +239,6 @@ | TCFun -- ^ @_ -> _@ | TCTuple Int -- ^ @(_, _, _)@ | TCAbstract UserTC -- ^ An abstract type- | TCNewtype UserTC -- ^ user-defined, @T@ deriving (Show, Eq, Ord, Generic, NFData) @@ -316,6 +317,7 @@ PCmp -> text "Cmp" PSignedCmp -> text "SignedCmp" PLiteral -> text "Literal"+ PLiteralLessThan -> text "LiteralLessThan" PFLiteral -> text "FLiteral" PValidFloat -> text "ValidFloat" PTrue -> text "True"@@ -337,7 +339,6 @@ TCTuple 0 -> text "()" TCTuple 1 -> text "(one tuple?)" TCTuple n -> parens $ hcat $ replicate (n-1) comma- TCNewtype u -> pp u TCAbstract u -> pp u instance PP UserTC where
src/Cryptol/TypeCheck/Type.hs view
@@ -49,7 +49,12 @@ deriving (Generic, NFData, Show) data TPFlavor = TPModParam Name- | TPOther (Maybe Name)+ | TPUnifyVar+ | TPSchemaParam Name+ | TPTySynParam Name+ | TPPropSynParam Name+ | TPNewtypeParam Name+ | TPPrimParam Name deriving (Generic, NFData, Show) tMono :: Type -> Schema@@ -62,18 +67,17 @@ _ -> Nothing - schemaParam :: Name -> TPFlavor-schemaParam x = TPOther (Just x)+schemaParam = TPSchemaParam tySynParam :: Name -> TPFlavor-tySynParam x = TPOther (Just x)+tySynParam = TPTySynParam propSynParam :: Name -> TPFlavor-propSynParam x = TPOther (Just x)+propSynParam = TPPropSynParam newtypeParam :: Name -> TPFlavor-newtypeParam x = TPOther (Just x)+newtypeParam = TPNewtypeParam modTyParam :: Name -> TPFlavor modTyParam = TPModParam@@ -82,8 +86,13 @@ tpfName :: TPFlavor -> Maybe Name tpfName f = case f of- TPModParam x -> Just x- TPOther x -> x+ TPUnifyVar -> Nothing+ TPModParam x -> Just x+ TPSchemaParam x -> Just x+ TPTySynParam x -> Just x+ TPPropSynParam x -> Just x+ TPNewtypeParam x -> Just x+ TPPrimParam x -> Just x tpName :: TParam -> Maybe Name tpName = tpfName . tpFlav@@ -106,6 +115,9 @@ | TRec !(RecordMap Ident Type) -- ^ Record type + | TNewtype !Newtype ![Type]+ -- ^ A newtype+ deriving (Show, Generic, NFData) @@ -209,11 +221,18 @@ data Newtype = Newtype { ntName :: Name , ntParams :: [TParam] , ntConstraints :: [Prop]- , ntFields :: [(Ident,Type)]+ , ntFields :: RecordMap Ident Type , ntDoc :: Maybe Text } deriving (Show, Generic, NFData) +instance Eq Newtype where+ x == y = ntName x == ntName y++instance Ord Newtype where+ compare x y = compare (ntName x) (ntName y)++ -- | Information about an abstract type. data AbstractType = AbstractType { atName :: Name@@ -240,6 +259,7 @@ TCon c ts -> quickApply (kindOf c) ts TUser _ _ t -> kindOf t TRec {} -> KType+ TNewtype{} -> KType instance HasKind TySyn where kindOf ts = foldr (:->) (kindOf (tsDef ts)) (map kindOf (tsParams ts))@@ -270,6 +290,7 @@ TCon x xs == TCon y ys = x == y && xs == ys TVar x == TVar y = x == y TRec xs == TRec ys = xs == ys+ TNewtype ntx xs == TNewtype nty ys = ntx == nty && xs == ys _ == _ = False @@ -288,7 +309,10 @@ (_,TCon {}) -> GT (TRec xs, TRec ys) -> compare xs ys+ (TRec{}, _) -> LT+ (_, TRec{}) -> GT + (TNewtype x xs, TNewtype y ys) -> compare (x,xs) (y,ys) instance Eq TParam where x == y = tpUnique x == tpUnique y@@ -332,7 +356,7 @@ newtypeConType :: Newtype -> Schema newtypeConType nt = Forall as (ntConstraints nt)- $ TRec (recordFromFields (ntFields nt)) `tFun` TCon (newtypeTyCon nt) (map (TVar . tpVar) as)+ $ TRec (ntFields nt) `tFun` TNewtype nt (map (TVar . tpVar) as) where as = ntParams nt @@ -538,6 +562,12 @@ TCon (PC PLiteral) [t1, t2] -> Just (t1, t2) _ -> Nothing +pIsLiteralLessThan :: Prop -> Maybe (Type, Type)+pIsLiteralLessThan ty =+ case tNoUser ty of+ TCon (PC PLiteralLessThan) [t1, t2] -> Just (t1, t2)+ _ -> Nothing+ pIsFLiteral :: Prop -> Maybe (Type,Type,Type,Type) pIsFLiteral ty = case tNoUser ty of TCon (PC PFLiteral) [t1,t2,t3,t4] -> Just (t1,t2,t3,t4)@@ -584,6 +614,9 @@ tAbstract :: UserTC -> [Type] -> Type tAbstract u ts = TCon (TC (TCAbstract u)) ts +tNewtype :: Newtype -> [Type] -> Type+tNewtype nt ts = TNewtype nt ts+ tBit :: Type tBit = TCon (TC TCBit) [] @@ -620,10 +653,6 @@ tTuple :: [Type] -> Type tTuple ts = TCon (TC (TCTuple (length ts))) ts -newtypeTyCon :: Newtype -> TCon-newtypeTyCon nt = TC $ TCNewtype $ UserTC (ntName nt) (kindOf nt)-- -- | Make a function type. tFun :: Type -> Type -> Type tFun a b = TCon (TC TCFun) [a,b]@@ -725,6 +754,9 @@ pLiteral :: Type -> Type -> Prop pLiteral x y = TCon (PC PLiteral) [x, y] +pLiteralLessThan :: Type -> Type -> Prop+pLiteralLessThan x y = TCon (PC PLiteralLessThan) [x, y]+ -- | Make a greater-than-or-equal-to constraint. (>==) :: Type -> Type -> Prop x >== y = TCon (PC PGeq) [x,y]@@ -801,6 +833,7 @@ TVar x -> Set.singleton x TUser _ _ t -> go t TRec fs -> fvs (recordElements fs)+ TNewtype _nt ts -> fvs ts instance FVS a => FVS (Maybe a) where fvs Nothing = Set.empty@@ -915,6 +948,7 @@ ppPrec prec ty0@(WithNames ty nmMap) = case ty of TVar a -> ppWithNames nmMap a+ TNewtype nt ts -> optParens (prec > 3) $ pp (ntName nt) <+> fsep (map (go 5) ts) TRec fs -> braces $ fsep $ punctuate comma [ pp l <+> text ":" <+> go 0 t | (l,t) <- displayFields fs ] @@ -972,6 +1006,7 @@ (PCmp, [t1]) -> pp pc <+> go 5 t1 (PSignedCmp, [t1]) -> pp pc <+> go 5 t1 (PLiteral, [t1,t2]) -> pp pc <+> go 5 t1 <+> go 5 t2+ (PLiteralLessThan, [t1,t2]) -> pp pc <+> go 5 t1 <+> go 5 t2 (_, _) -> optParens (prec > 3) $ pp pc <+> fsep (map (go 5) ts) @@ -1011,10 +1046,15 @@ | otherwise = case tv of TVBound x ->+ let declNm n = pp n <.> "`" <.> int (tpUnique x) in case tpFlav x of TPModParam n -> ppPrefixName n- TPOther (Just n) -> pp n <.> "`" <.> int (tpUnique x)- _ -> pickTVarName (tpKind x) (tvarDesc (tpInfo x)) (tpUnique x)+ TPUnifyVar -> pickTVarName (tpKind x) (tvarDesc (tpInfo x)) (tpUnique x)+ TPSchemaParam n -> declNm n+ TPTySynParam n -> declNm n+ TPPropSynParam n -> declNm n+ TPNewtypeParam n -> declNm n+ TPPrimParam n -> declNm n TVFree x k _ d -> pickTVarName k (tvarDesc d) x
src/Cryptol/TypeCheck/TypeMap.hs view
@@ -118,14 +118,17 @@ data TypeMap a = TM { tvar :: Map TVar a , tcon :: Map TCon (List TypeMap a) , trec :: Map [Ident] (List TypeMap a)+ , tnewtype :: Map Newtype (List TypeMap a) } deriving (Functor, Foldable, Traversable) instance TrieMap TypeMap Type where- emptyTM = TM { tvar = emptyTM, tcon = emptyTM, trec = emptyTM }+ emptyTM = TM { tvar = emptyTM, tcon = emptyTM, trec = emptyTM, tnewtype = emptyTM } nullTM ty = and [ nullTM (tvar ty) , nullTM (tcon ty)- , nullTM (trec ty) ]+ , nullTM (trec ty)+ , nullTM (tnewtype ty)+ ] lookupTM ty = case ty of@@ -134,6 +137,7 @@ TCon c ts -> lookupTM ts <=< lookupTM c . tcon TRec fs -> let (xs,ts) = unzip $ canonicalFields fs in lookupTM ts <=< lookupTM xs . trec+ TNewtype nt ts -> lookupTM ts <=< lookupTM nt . tnewtype alterTM ty f m = case ty of@@ -142,6 +146,7 @@ TCon c ts -> m { tcon = alterTM c (updSub ts f) (tcon m) } TRec fs -> let (xs,ts) = unzip $ canonicalFields fs in m { trec = alterTM xs (updSub ts f) (trec m) }+ TNewtype nt ts -> m { tnewtype = alterTM nt (updSub ts f) (tnewtype m) } toListTM m = [ (TVar x, v) | (x,v) <- toListTM (tvar m) ] ++@@ -152,11 +157,16 @@ -- It's not clear if we should try to fix this. [ (TRec (recordFromFields (zip fs ts)), v) | (fs,m1) <- toListTM (trec m)- , (ts,v) <- toListTM m1 ]+ , (ts,v) <- toListTM m1 ] ++ + [ (TNewtype nt ts, v) | (nt,m1) <- toListTM (tnewtype m)+ , (ts,v) <- toListTM m1+ ]+ unionTM f m1 m2 = TM { tvar = unionTM f (tvar m1) (tvar m2) , tcon = unionTM (unionTM f) (tcon m1) (tcon m2) , trec = unionTM (unionTM f) (trec m1) (trec m2)+ , tnewtype = unionTM (unionTM f) (tnewtype m1) (tnewtype m2) } mapMaybeWithKeyTM f m =@@ -167,6 +177,8 @@ (\ts a -> f (TRec (recordFromFields (zip fs ts))) a) l) (trec m) -- NB: this step loses 'displayOrder' information. -- It's not clear if we should try to fix this.+ , tnewtype = mapWithKeyTM (\nt l -> mapMaybeWithKeyTM+ (\ts a -> f (TNewtype nt ts) a) l) (tnewtype m) }
src/Cryptol/TypeCheck/TypeOf.hs view
@@ -30,6 +30,7 @@ fastTypeOf tyenv expr = case expr of -- Monomorphic fragment+ ELocated _ t -> fastTypeOf tyenv t EList es t -> tSeq (tNum (length es)) t ETuple es -> tTuple (map (fastTypeOf tyenv) es) ERec fields -> tRec (fmap (fastTypeOf tyenv) fields)@@ -59,6 +60,8 @@ fastSchemaOf :: Map Name Schema -> Expr -> Schema fastSchemaOf tyenv expr = case expr of+ ELocated _ e -> fastSchemaOf tyenv e+ -- Polymorphic fragment EVar x -> case Map.lookup x tyenv of Just ty -> ty@@ -113,10 +116,11 @@ plainSubst :: Subst -> Type -> Type plainSubst s ty = case ty of- TCon tc ts -> TCon tc (map (plainSubst s) ts)- TUser f ts t -> TUser f (map (plainSubst s) ts) (plainSubst s t)- TRec fs -> TRec (fmap (plainSubst s) fs)- TVar x -> apSubst s (TVar x)+ TCon tc ts -> TCon tc (map (plainSubst s) ts)+ TUser f ts t -> TUser f (map (plainSubst s) ts) (plainSubst s t)+ TRec fs -> TRec (fmap (plainSubst s) fs)+ TNewtype nt ts -> TNewtype nt (map (plainSubst s) ts)+ TVar x -> apSubst s (TVar x) -- | Yields the return type of the selector on the given argument type. typeSelect :: Type -> Selector -> Type
src/Cryptol/TypeCheck/TypePat.hs view
@@ -7,7 +7,9 @@ , aCeilDiv, aCeilMod , aLenFromThenTo - , aLiteral, aLogic+ , aLiteral+ , aLiteralLessThan+ , aLogic , aTVar , aFreeTVar@@ -177,6 +179,9 @@ aLiteral :: Pat Prop (Type,Type) aLiteral = tp PLiteral ar2++aLiteralLessThan :: Pat Prop (Type,Type)+aLiteralLessThan = tp PLiteralLessThan ar2 aLogic :: Pat Prop Type aLogic = tp PLogic ar1
src/Cryptol/TypeCheck/Unify.hs view
@@ -74,6 +74,9 @@ mgu (TRec fs1) (TRec fs2) | fieldSet fs1 == fieldSet fs2 = mguMany (recordElements fs1) (recordElements fs2) +mgu (TNewtype ntx xs) (TNewtype nty ys)+ | ntx == nty = mguMany xs ys+ mgu t1 t2 | not (k1 == k2) = uniError $ UniKindMismatch k1 k2 | otherwise = uniError $ UniTypeMismatch t1 t2
src/Cryptol/Utils/PP.hs view
@@ -27,6 +27,38 @@ import Prelude () import Prelude.Compat ++-- | How to pretty print things when evaluating+data PPOpts = PPOpts+ { useAscii :: Bool+ , useBase :: Int+ , useInfLength :: Int+ , useFPBase :: Int+ , useFPFormat :: PPFloatFormat+ }+ deriving Show++asciiMode :: PPOpts -> Integer -> Bool+asciiMode opts width = useAscii opts && (width == 7 || width == 8)++data PPFloatFormat =+ FloatFixed Int PPFloatExp -- ^ Use this many significant digis+ | FloatFrac Int -- ^ Show this many digits after floating point+ | FloatFree PPFloatExp -- ^ Use the correct number of digits+ deriving Show++data PPFloatExp = ForceExponent -- ^ Always show an exponent+ | AutoExponent -- ^ Only show exponent when needed+ deriving Show+++defaultPPOpts :: PPOpts+defaultPPOpts = PPOpts { useAscii = False, useBase = 10, useInfLength = 5+ , useFPBase = 16+ , useFPFormat = FloatFree AutoExponent+ }++ -- Name Displaying ------------------------------------------------------------- {- | How to display names, inspired by the GHC `Outputable` module.
src/GitRev.hs view
@@ -24,4 +24,3 @@ dirty :: Bool dirty = $(gitDirty)--- Last build Fri Sep 11 16:44:33 PDT 2020
utils/CryHtml.hs view
@@ -1,6 +1,7 @@ #!/usr/bin/env runhaskell {-# LANGUAGE OverloadedStrings #-}+{-# LANGUAGE ViewPatterns #-} -- | -- Module : Main@@ -11,13 +12,14 @@ -- Portability : portable import Cryptol.Parser.Lexer+import Cryptol.Parser.Position import Cryptol.Utils.PP import qualified Data.Text.IO as Text-import Text.Blaze.Html (Html, AttributeValue, toValue, toHtml, (!))+import Text.Blaze.Html (Html, AttributeValue, toHtml, (!), toValue) import qualified Text.Blaze.Html as H import qualified Text.Blaze.Html5 as H import qualified Text.Blaze.Html5.Attributes as A-import Text.Blaze.Html.Renderer.Pretty (renderHtml)+import Text.Blaze.Html.Renderer.String (renderHtml) main :: IO ()@@ -41,8 +43,9 @@ toBlaze :: Located Token -> Html+toBlaze (Located _ (tokenType -> EOF)) = mempty toBlaze tok = H.span ! (A.class_ $ cl $ tokenType $ thing tok)- ! (A.title $ toValue $ show $ pp $ srcRange tok)+ ! (A.id $ toValue $ show $ pp $ from $ srcRange tok) $ H.toHtml $ tokenText $ thing tok@@ -70,7 +73,7 @@ sty :: String sty = unlines- [ "body { font-family: monospace }"+ [ "body { font-family: monospace; white-space: pre; }" , ".number { color: #cc00cc }" , ".identifier { }" , ".selector { color: #33033 }"