g2-0.2.0.0: src/G2/Language/Syntax.hs
{-# LANGUAGE DeriveDataTypeable #-}
{-# LANGUAGE DeriveGeneric #-}
-- | Defines most of the central language in G2. This language closely resembles Core Haskell.
-- The central datatypes are `Expr` and t`Type`.
module G2.Language.Syntax
( module G2.Language.Syntax
) where
import GHC.Generics (Generic)
import Data.Data
import Data.Hashable
import qualified Data.Text as T
import qualified GHC.Generics as GHC
-- | Binds `Id`s to `Expr`s, primarily in @let@ `Expr`s
type Binds = [(Id, Expr)]
-- | Records a location in the source code
data Loc = Loc { line :: Int
, col :: Int
, file :: String } deriving (Show, Eq, Read, Ord, Generic, Typeable, Data)
instance Hashable Loc
-- | Records a span in the source code.
--
-- Invariant:
--
-- > file start == file end
data Span = Span { start :: Loc
, end :: Loc } deriving (Show, Eq, Read, Ord, Generic, Typeable, Data)
instance Hashable Span
-- | A name has three pieces: an occurence name, Maybe a module name, and a Unique Id.
data Name = Name T.Text (Maybe T.Text) Int (Maybe Span)
deriving (Show, Read, Generic, Typeable, Data)
-- | Disregards the Span
instance Eq Name where
Name n m i _ == Name n' m' i' _ = n == n' && m == m' && i == i'
-- | Disregards the Span
instance Ord Name where
Name n m i _ `compare` Name n' m' i' _ = (n, m, i) `compare` (n', m', i')
-- | Disregards the Span
instance Hashable Name where
hashWithSalt s (Name n m i _) =
s `hashWithSalt`
n `hashWithSalt`
m `hashWithSalt` i
-- | Pairing of a `Name` with a t`Type`
data Id = Id Name Type deriving (Show, Eq, Read, Generic, Typeable, Data, Ord)
instance Hashable Id
-- | Indicates the purpose of the a Lambda binding
data LamUse = TermL -- ^ Binds at the term level
| TypeL -- ^ Binds at the type level
deriving (Show, Eq, Read, Generic, Typeable, Data)
instance Hashable LamUse
-- | Extract the `Name` from an `Id`.
idName :: Id -> Name
idName (Id name _) = name
-- | The `sym_gens` field of a `State` is used to record the values generated by certain `SymGen`s.
-- This allows us to track, and eventually print to display to the user, values generated by (certain) `SymGen`s.
-- `SymGen`s tagged with `SLog` are logged, i.e. will be recorded in the `sym_gens` field. Those tagged by `SNoLog` are not logged.
data SymLog = SLog | SNoLog
deriving (Show, Eq, Read, Generic, Typeable, Data)
instance Hashable SymLog
-- | Expressions, representing G2's intermediate language.
data Expr =
-- | @`Var` `Id`@ is a variable. Variables may be bound by a `Lam`, `Let`
-- or `Case` `Expr`, or be bound in the `G2.Language.ExprEnv.ExprEnv`. A variable may also be
-- free (unbound), in which case it is symbolic
Var Id
-- | @v`Lit` t`Lit`@ denotes a literal.
| Lit Lit
-- | Primitive functions. Should be wrapped in `App`s.
| Prim Primitive Type
-- | @v`Data` `DataCon`@ denotes a Data Constructor
| Data DataCon
{-| @`App` `Expr` `Expr`@ denotes function application.
For example, the function call:
@ f x y @
would be represented as
@ `App`
(`App`
(`Var` (`Id` (`Name` "f" Nothing 0 Nothing) (`TyFun` t (`TyFun` t t))))
(`Var` (`Id` (`Name` "x" Nothing 0 Nothing) t))
)
(`Var` (`Id` (`Name` "y" Nothing 0 Nothing) t)) @
-}
| App Expr Expr
-- | @`Lam` `LamUse` `Id` `Expr`@ denotes a lambda function.
-- The `Id` is bound in the `Expr`.
-- This binding may be on the type or term level, depending on the `LamUse`.
| Lam LamUse Id Expr
-- | @`Let` b e@ gives a mapping of `Name`s to `Expr`s in `b`, allowing those names
-- to be used in `e`.
| Let Binds Expr
-- | @`Case` e i as@ splits into multiple `Alt`s (Alternatives),
-- Depending on the value of @e@. In each Alt, the `Id` @i@ is bound to @e@.
-- The `Alt`s must always be exhaustive- there should never be a case where no `Alt`
-- can match a given `Expr`.
| Case Expr -- ^ Scrutinee
Id -- ^ Bindee
Type -- ^ Type of the case expression
[Alt] -- ^ Alternatives
-- | @v`Type` t`Type`@ gives a `Expr` level representation of a t`Type`.
-- These only ever appear as the arguments to polymorphic functions,
-- to determine the t`Type` bound to type level variables.
| Type Type
-- | @`Cast` e (t1 `:~` t2)@ casts @e@ from the t`Type` @t1@ to @t2@
-- This requires that @t1@ and @t2@ have the same representation.
| Cast Expr Coercion
-- | @v`Coercion` t`Coercion`@ allows runtime passing of t`Coercion`s to `Cast`s.
| Coercion Coercion
-- | @`Tick` `Tickish` `Expr`@ records some extra information into an `Expr`.
| Tick Tickish Expr
-- | @`NonDet` [`Expr`]@ gives a nondeterministic choice between multiple options
-- to continue execution with.
| NonDet [Expr]
-- | @`SymGen` t`Type`@ evaluates to a fresh symbolic variable of the given type.
-- The `SymLog` determines whether the SymGen logs its generated value in the `State`s `sym_gens` field.
| SymGen SymLog Type
-- | @`Assume` b e@ takes a boolean typed expression @b@, and an expression of
-- arbitrary type @e@. During exectuion, @b@ is reduced to SWHNF, and assumed.
-- Then, execution continues with @b@.
| Assume (Maybe FuncCall) Expr Expr
-- | @`Assert` fc b e@ is similar to `Assume`, but asserts the @b@ holds.
-- The `Maybe` `FuncCall` allows us to optionally indicate that the
-- assertion is related to a specific function.
| Assert (Maybe FuncCall) Expr Expr
deriving (Show, Eq, Read, Generic, Typeable, Data)
instance Hashable Expr
-- | These are known, and G2-augmented operations, over unwrapped
-- data types such as Int#, Char#, Double#, etc.
-- Generally, calls to these should actually be created using the functions in:
--
-- "G2.Language.Primitives"
--
-- And evaluation over literals can be peformed with the functions in:
--
-- "G2.Execution.PrimitiveEval"
data Primitive = -- Mathematical and logical operators
Ge
| Gt
| Eq
| Neq
| Lt
| Le
| And
| Or
| Not
| Implies
| Iff
| Plus
| Minus
| Mult
| Div
| DivInt
| Quot
| Mod
| Rem
| Negate
| Abs
| SqRt
-- GHC conversions from data constructors to Int#, and vice versa
| DataToTag
| TagToEnum
-- Numeric conversion
| IntToFloat
| IntToDouble
| RationalToDouble
| FromInteger
| ToInteger
| ToInt
-- String Handling
| StrLen
| StrAppend
| Chr
| OrdChar
| WGenCat
-- Convert a positive Int to a String. (This matches the SMT Str.from_int function, which supports only positive Ints.)
| IntToString
-- Errors
| Error
| Undefined
deriving (Show, Eq, Read, Generic, Typeable, Data)
instance Hashable Primitive
-- | Literals for denoting unwrapped types such as Int#, Double#.
data Lit = LitInt Integer
| LitFloat Rational
| LitDouble Rational
| LitChar Char
| LitString String
| LitInteger Integer
deriving (Show, Eq, Read, Generic, Typeable, Data)
instance Hashable Lit
-- | Data constructor.
data DataCon = DataCon Name Type deriving (Show, Eq, Read, Generic, Typeable, Data, Ord)
instance Hashable DataCon
-- | Extract the `Name` of a `DataCon`.
dcName :: DataCon -> Name
dcName (DataCon n _) = n
-- | Describe the conditions to match on a particular `Alt`.
data AltMatch = DataAlt DataCon [Id] -- ^ Match a datacon. The number of `Id`s
-- must match the number of term arguments
-- for the datacon.
| LitAlt Lit
| Default
deriving (Show, Eq, Read, Generic, Typeable, Data)
instance Hashable AltMatch
-- | `Alt`s consist of the `AltMatch` that is used to match
-- them, and the `Expr` that is evaluated provided that the `AltMatch`
-- successfully matches.
data Alt = Alt { altMatch :: AltMatch, altExpr :: Expr } deriving (Show, Eq, Read, Generic, Typeable, Data)
instance Hashable Alt
-- | Concrete evidence of the equality or compatibility of two types.
data Coercion = Type :~ Type deriving (Eq, Show, Read, Generic, Typeable, Data)
instance Hashable Coercion
-- | Types information.
data Type = TyVar Id -- ^ Polymorphic type variable.
| TyLitInt -- ^ Unwrapped primitive Int type.
| TyLitFloat -- ^ Unwrapped primitive Float type.
| TyLitDouble -- ^ Unwrapped primitive Int type.
| TyLitChar -- ^ Unwrapped primitive Int type.
| TyLitString -- ^ Unwrapped primitive String type.
| TyFun Type Type -- ^ Function type. For instance (assume Int): \x -> x + 1 :: TyFun TyInt TyInt
| TyApp Type Type -- ^ Application of a type.
| TyCon Name Kind -- ^ Type constructor for a concrete type
| TyForAll Id Type -- ^ Introduces a type variable.
| TyBottom -- ^ Type for erroring/non-terminating expressions.
| TYPE
| TyUnknown
deriving (Show, Eq, Read, Generic, Typeable, Data, Ord)
-- | A `Kind` is a t`Type` of a t`Type`.
type Kind = Type
instance Hashable Type
-- | A `Tickish` allows storing extra information in a `Tick`.
data Tickish = Breakpoint Span -- ^ A breakpoint for the GHC Debugger
| HpcTick !Int T.Text -- ^ A tick used by HPC to track each subexpression in the original source code.
--
-- Together, the `Int` identifier and the Module Name indicate a unique location.
| NamedLoc Name -- ^ A G2 specific tick, intended to allow,
-- in concert with a @`G2.Execution.Reducer.Reducer`@, for domain
-- specific modifications to a
-- @`G2.Language.Support.State`@'s tracking field.
deriving (Show, Eq, Read, Generic, Typeable, Data)
instance Hashable Tickish
-- | Represents a rewrite rule
data RewriteRule = RewriteRule { ru_name :: T.Text
, ru_module :: T.Text
, ru_head :: Name
, ru_rough :: [Maybe Name]
, ru_bndrs :: [Id]
, ru_args :: [Expr]
, ru_rhs :: Expr } deriving (Show, Eq, Read, Generic, Typeable, Data)
instance Hashable RewriteRule
-- | Represents a function call, with it's arguments and return value as Expr
data FuncCall = FuncCall { funcName :: Name
, arguments :: [Expr]
, returns :: Expr } deriving (Show, Eq, Read, Generic, Typeable, Data)
instance Hashable FuncCall