{-# Language DeriveGeneric, DeriveAnyClass #-}
module Cryptol.Prims.Syntax where
import GHC.Generics (Generic)
import Control.DeepSeq
import qualified Data.Map as Map
import Cryptol.Parser.Name
import Cryptol.Parser.Selector
import Cryptol.Parser.Fixity
import qualified Cryptol.ModuleSystem.Name as M
import Cryptol.Utils.Ident
import Cryptol.Utils.PP
data PrimTy = PrimTy
{ primTyCon :: !TCon
, primTyIdent :: !Ident
, primTyDoc :: !String
, primTyFixity :: !(Maybe Fixity)
}
instance Eq PrimTy where
x == y = primTyCon x == primTyCon y
instance Ord PrimTy where
compare x y = compare (primTyCon x) (primTyCon y)
primTyList :: [ PrimTy ]
primTyList =
[
tPrefix "inf" TC TCInf
"A numeric type representing infinity."
, tPrefix "Bit" TC TCBit
"The type of boolean values."
, tPrefix "Integer" TC TCInteger
"The type of unbounded integers."
, tPrefix "Z" TC TCIntMod
"'Z n' is the type of integers, modulo 'n'."
, tInfix "==" PC PEqual (n 20)
"Assert that two numeric types are equal."
, tInfix "!=" PC PNeq (n 20)
"Assert that two numeric types are different."
, tInfix ">=" PC PGeq (n 30)
"Assert that the first numeric type is larger than, or equal to the second."
, tPrefix "fin" PC PFin
"Assert that a numeric type is a proper natural number (not 'inf')."
, tPrefix "Zero" PC PZero
"Value types that have a notion of 'zero'."
, tPrefix "Logic" PC PLogic
"Value types that support logical operations."
, tPrefix "Arith" PC PArith
"Value types that support arithmetic."
, tPrefix "Cmp" PC PCmp
"Value types that support unsigned comparisons."
, tPrefix "SignedCmp" PC PSignedCmp
"Value types that support signed comparisons."
, tPrefix "Literal" PC PLiteral
"'Literal n a' asserts that type 'a' contains the number 'n'."
, tInfix "+" TF TCAdd (l 80)
"Add numeric types."
, tInfix "-" TF TCSub (l 80)
"Subtract numeric types."
, tInfix "*" TF TCMul (l 90)
"Multiply numeric types."
, tInfix "/" TF TCDiv (l 90)
"Divide numeric types, rounding down."
, tInfix "%" TF TCMod (l 90)
"Remainder of numeric type division."
, tInfix "^^" TF TCExp (r 95)
"Exponentiate numeric types."
, tPrefix "width" TF TCWidth
"The number of bits required to represent the value of a numeric type."
, tPrefix "min" TF TCMin
"The smaller of two numeric types."
, tPrefix "max" TF TCMax
"The larger of two numeric types."
, tInfix "/^" TF TCCeilDiv (l 90)
"Divide numeric types, rounding up."
, tInfix "%^" TF TCCeilMod (l 90)
"How much we need to add to make a proper multiple of the second argument."
, tPrefix "lengthFromThenTo" TF TCLenFromThenTo
"The length of an enumeration."
]
where
r x = Fixity { fAssoc = RightAssoc, fLevel = x }
l x = Fixity { fAssoc = LeftAssoc, fLevel = x }
n x = Fixity { fAssoc = NonAssoc, fLevel = x }
tPrefix x mk tc d =
PrimTy { primTyCon = mk tc
, primTyIdent = packIdent x
, primTyDoc = d
, primTyFixity = Nothing
}
tInfix x mk tc f d =
PrimTy { primTyCon = mk tc
, primTyIdent = packInfix x
, primTyDoc = d
, primTyFixity = Just f
}
primTyIx :: Ord a => (PrimTy -> Maybe a) -> a -> Maybe PrimTy
primTyIx toKey = \x -> Map.lookup x mp
where mp = Map.fromList [ (k,x) | x <- primTyList, Just k <- [ toKey x ] ]
{-# Inline primTyIx #-}
primTyFromPName :: PName -> Maybe PrimTy
primTyFromPName = primTyIx $ \t -> Just (mkUnqual (primTyIdent t))
primTyFromTC :: TCon -> Maybe PrimTy
primTyFromTC = primTyIx $ \t -> Just (primTyCon t)
primTyFromTF :: TFun -> Maybe PrimTy
primTyFromTF = primTyIx $ \t ->
case primTyCon t of
TF tf -> Just tf
_ -> Nothing
primTyFromPC :: PC -> Maybe PrimTy
primTyFromPC = primTyIx $ \t ->
case primTyCon t of
PC tf -> Just tf
_ -> Nothing
infixr 5 :->
data Kind = KType
| KNum
| KProp
| Kind :-> Kind
deriving (Eq, Ord, Show, Generic, NFData)
class HasKind t where
kindOf :: t -> Kind
instance HasKind TCon where
kindOf (TC tc) = kindOf tc
kindOf (PC pc) = kindOf pc
kindOf (TF tf) = kindOf tf
kindOf (TError k _) = k
instance HasKind UserTC where
kindOf (UserTC _ k) = k
instance HasKind TC where
kindOf tcon =
case tcon of
TCNum _ -> KNum
TCInf -> KNum
TCBit -> KType
TCInteger -> KType
TCIntMod -> KNum :-> KType
TCSeq -> KNum :-> KType :-> KType
TCFun -> KType :-> KType :-> KType
TCTuple n -> foldr (:->) KType (replicate n KType)
TCNewtype x -> kindOf x
instance HasKind PC where
kindOf pc =
case pc of
PEqual -> KNum :-> KNum :-> KProp
PNeq -> KNum :-> KNum :-> KProp
PGeq -> KNum :-> KNum :-> KProp
PFin -> KNum :-> KProp
PHas _ -> KType :-> KType :-> KProp
PZero -> KType :-> KProp
PLogic -> KType :-> KProp
PArith -> KType :-> KProp
PCmp -> KType :-> KProp
PSignedCmp -> KType :-> KProp
PLiteral -> KNum :-> KType :-> KProp
PAnd -> KProp :-> KProp :-> KProp
PTrue -> KProp
instance HasKind TFun where
kindOf tfun =
case tfun of
TCWidth -> KNum :-> KNum
TCAdd -> KNum :-> KNum :-> KNum
TCSub -> KNum :-> KNum :-> KNum
TCMul -> KNum :-> KNum :-> KNum
TCDiv -> KNum :-> KNum :-> KNum
TCMod -> KNum :-> KNum :-> KNum
TCExp -> KNum :-> KNum :-> KNum
TCMin -> KNum :-> KNum :-> KNum
TCMax -> KNum :-> KNum :-> KNum
TCCeilDiv -> KNum :-> KNum :-> KNum
TCCeilMod -> KNum :-> KNum :-> KNum
TCLenFromThenTo -> KNum :-> KNum :-> KNum :-> KNum
data TCon = TC TC | PC PC | TF TFun | TError Kind TCErrorMessage
deriving (Show, Eq, Ord, Generic, NFData)
data PC = PEqual
| PNeq
| PGeq
| PFin
| PHas Selector
| PZero
| PLogic
| PArith
| PCmp
| PSignedCmp
| PLiteral
| PAnd
| PTrue
deriving (Show, Eq, Ord, Generic, NFData)
data TC = TCNum Integer
| TCInf
| TCBit
| TCInteger
| TCIntMod
| TCSeq
| TCFun
| TCTuple Int
| TCNewtype UserTC
deriving (Show, Eq, Ord, Generic, NFData)
data UserTC = UserTC M.Name Kind
deriving (Show, Generic, NFData)
instance Eq UserTC where
UserTC x _ == UserTC y _ = x == y
instance Ord UserTC where
compare (UserTC x _) (UserTC y _) = compare x y
data TCErrorMessage = TCErrorMessage
{ tcErrorMessage :: !String
} deriving (Show, Eq, Ord, Generic, NFData)
data TFun
= TCAdd
| TCSub
| TCMul
| TCDiv
| TCMod
| TCExp
| TCWidth
| TCMin
| TCMax
| TCCeilDiv
| TCCeilMod
| TCLenFromThenTo
deriving (Show, Eq, Ord, Bounded, Enum, Generic, NFData)
instance PP Kind where
ppPrec p k = case k of
KType -> char '*'
KNum -> char '#'
KProp -> text "Prop"
l :-> r -> optParens (p >= 1) (sep [ppPrec 1 l, text "->", ppPrec 0 r])
instance PP TCon where
ppPrec _ (TC tc) = pp tc
ppPrec _ (PC tc) = pp tc
ppPrec _ (TF tc) = pp tc
ppPrec _ (TError _ msg) = pp msg
instance PPName TCon where
ppNameFixity (TC _) = Nothing
ppNameFixity (PC _) = Nothing
ppNameFixity (TF tf) = ppNameFixity tf
ppNameFixity (TError _ _) = Nothing
ppPrefixName (TC tc) = pp tc
ppPrefixName (PC pc) = pp pc
ppPrefixName (TF tf) = ppPrefixName tf
ppPrefixName (TError _ msg) = pp msg
ppInfixName (TC tc) = pp tc
ppInfixName (PC pc) = pp pc
ppInfixName (TF tf) = ppInfixName tf
ppInfixName (TError _ msg) = pp msg
instance PP TCErrorMessage where
ppPrec _ tc = parens (text "error:" <+> text (tcErrorMessage tc))
instance PP PC where
ppPrec _ x =
case x of
PEqual -> text "(==)"
PNeq -> text "(/=)"
PGeq -> text "(>=)"
PFin -> text "fin"
PHas sel -> parens (ppSelector sel)
PZero -> text "Zero"
PLogic -> text "Logic"
PArith -> text "Arith"
PCmp -> text "Cmp"
PSignedCmp -> text "SignedCmp"
PLiteral -> text "Literal"
PTrue -> text "True"
PAnd -> text "(&&)"
instance PP TC where
ppPrec _ x =
case x of
TCNum n -> integer n
TCInf -> text "inf"
TCBit -> text "Bit"
TCInteger -> text "Integer"
TCIntMod -> text "Z"
TCSeq -> text "[]"
TCFun -> text "(->)"
TCTuple 0 -> text "()"
TCTuple 1 -> text "(one tuple?)"
TCTuple n -> parens $ hcat $ replicate (n-1) comma
TCNewtype u -> pp u
instance PP UserTC where
ppPrec p (UserTC x _) = ppPrec p x
instance PPName TFun where
ppNameFixity f =
do pt <- primTyFromTF f
fi <- primTyFixity pt
return (fAssoc fi, fLevel fi)
ppPrefixName TCAdd = text "(+)"
ppPrefixName TCSub = text "(-)"
ppPrefixName TCMul = text "(*)"
ppPrefixName TCDiv = text "(/)"
ppPrefixName TCMod = text "(%)"
ppPrefixName TCExp = text "(^^)"
ppPrefixName TCCeilDiv = text "(/^)"
ppPrefixName TCCeilMod = text "(%^)"
ppPrefixName f = pp f
ppInfixName TCAdd = text "+"
ppInfixName TCSub = text "-"
ppInfixName TCMul = text "*"
ppInfixName TCDiv = text "/"
ppInfixName TCMod = text "%"
ppInfixName TCExp = text "^^"
ppInfixName TCCeilDiv = text "/^"
ppInfixName TCCeilMod = text "%^"
ppInfixName f = error $ "Not a prefix type function: " ++ show (pp f)
instance PP TFun where
ppPrec _ tcon =
case tcon of
TCAdd -> text "+"
TCSub -> text "-"
TCMul -> text "*"
TCDiv -> text "/"
TCMod -> text "%"
TCExp -> text "^^"
TCWidth -> text "width"
TCMin -> text "min"
TCMax -> text "max"
TCCeilDiv -> text "/^"
TCCeilMod -> text "%^"
TCLenFromThenTo -> text "lengthFromThenTo"