packages feed

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