g2-0.1.0.0: src/G2/Language/Support.hs
{-# LANGUAGE BangPatterns #-}
{-# LANGUAGE DeriveDataTypeable #-}
{-# LANGUAGE MultiParamTypeClasses #-}
{-# LANGUAGE FlexibleInstances #-}
{-# LANGUAGE FlexibleContexts #-}
module G2.Language.Support
( module G2.Language.AST
, module G2.Language.Support
, module G2.Language.TypeEnv
, E.ExprEnv
, PathConds
, KnownValues
, PathCond (..)
, Constraint
, Assertion
) where
import G2.Language.AST
import qualified G2.Language.ExprEnv as E
import G2.Language.KnownValues
import G2.Language.Naming
import G2.Language.Stack
import G2.Language.Syntax
import G2.Language.TypeClasses
import G2.Language.TypeEnv
import G2.Language.Typing
import G2.Language.PathConds hiding (map, filter)
import G2.Execution.RuleTypes
import Data.Data (Data, Typeable)
import qualified Data.Map as M
import qualified Data.HashMap.Lazy as HM
import qualified Data.HashSet as S
import qualified Data.Text as T
-- | The State is passed around in G2. It can be utilized to
-- perform defunctionalization, execution, and SMT solving.
-- The t parameter can be used to track extra information during the execution.
data State t = State { expr_env :: E.ExprEnv
, type_env :: TypeEnv
, curr_expr :: CurrExpr
, path_conds :: PathConds -- ^ Path conditions, in SWHNF
, non_red_path_conds :: [Expr] -- ^ Path conditions that still need further reduction
, true_assert :: Bool -- ^ Have we violated an assertion?
, assert_ids :: Maybe FuncCall
, type_classes :: TypeClasses
, symbolic_ids :: SymbolicIds
, exec_stack :: Stack Frame
, model :: Model
, known_values :: KnownValues
, rules :: ![Rule]
, num_steps :: !Int -- Invariant: The length of the rules list
, tags :: S.HashSet Name -- ^ Allows attaching tags to a State, to identify it later
, track :: t
} deriving (Show, Eq, Read, Typeable, Data)
data Bindings = Bindings { deepseq_walkers :: Walkers
, fixed_inputs :: [Expr]
, arb_value_gen :: ArbValueGen
, cleaned_names :: CleanedNames
, higher_order_inst :: [Name] -- ^ Functions to try instantiating higher order functions with
, input_names :: [Name]
, rewrite_rules :: ![RewriteRule]
, name_gen :: NameGen
} deriving (Show, Eq, Read, Typeable, Data)
-- | The `InputIds` are a list of the variable names passed as input to the
-- function being symbolically executed
type InputIds = [Id]
inputIds :: State t -> Bindings -> InputIds
inputIds (State { expr_env = eenv }) (Bindings { input_names = ns }) =
map (\n -> case E.lookup n eenv of
Just e -> Id n (typeOf e)
Nothing -> error "inputIds: Name not found in ExprEnv") ns
-- | The `SymbolicIds` are a list of the variable names that we should ensure are
-- inserted in the model, after we solve the path constraints
type SymbolicIds = [Id]
-- | `CurrExpr` is the current expression we have.
data CurrExpr = CurrExpr EvalOrReturn Expr
deriving (Show, Eq, Read, Typeable, Data)
-- | Tracks whether the `CurrExpr` is being evaluated, or if
-- it is in some terminal form that is simply returned. Technically we do not
-- need to make this distinction, and could simply call a `isTerm` function
-- to check, but this makes clearer distinctions for writing the
-- evaluation code.
data EvalOrReturn = Evaluate
| Return
deriving (Show, Eq, Read, Typeable, Data)
-- Used to map names (typically of ADTs) to corresponding autogenerated function names
type Walkers = M.Map Name Id
-- Map new names to old ones
type CleanedNames = HM.HashMap Name Name
data ArbValueGen = ArbValueGen { intGen :: Integer
, floatGen :: Rational
, doubleGen :: Rational
, charGen :: [Char]
, boolGen :: Bool
} deriving (Show, Eq, Read, Typeable, Data)
-- | Naive expression lookup by only the occurrence name string.
naiveLookup :: T.Text -> E.ExprEnv -> [(Name, Expr)]
naiveLookup key = filter (\(Name occ _ _ _, _) -> occ == key) . E.toExprList
-- | These are stack frames. They are used to guide evaluation.
data Frame = CaseFrame Id [Alt]
| ApplyFrame Expr
| UpdateFrame Name
| CastFrame Coercion
| CurrExprFrame CurrExpr
| AssumeFrame Expr
| AssertFrame (Maybe FuncCall) Expr
deriving (Show, Eq, Read, Typeable, Data)
-- | A model is a mapping of symbolic variable names to `Expr`@s@,
-- typically produced by a solver.
type Model = M.Map Name Expr
-- | Replaces all of the names old in state with a name seeded by new_seed
renameState :: Named t => Name -> Name -> State t -> Bindings -> (State t, Bindings)
renameState old new_seed s b =
let (new, ng') = freshSeededName new_seed (name_gen b)
in (State { expr_env = rename old new (expr_env s)
, type_env =
M.mapKeys (\k -> if k == old then new else k)
$ rename old new (type_env s)
, curr_expr = rename old new (curr_expr s)
, path_conds = rename old new (path_conds s)
, non_red_path_conds = rename old new (non_red_path_conds s)
, true_assert = true_assert s
, assert_ids = rename old new (assert_ids s)
, type_classes = rename old new (type_classes s)
, symbolic_ids = rename old new (symbolic_ids s)
, exec_stack = exec_stack s
, model = model s
, known_values = rename old new (known_values s)
, rules = rules s
, num_steps = num_steps s
, track = rename old new (track s)
, tags = tags s }
, b { name_gen = ng'})
instance Named t => Named (State t) where
names s = names (expr_env s)
++ names (type_env s)
++ names (curr_expr s)
++ names (path_conds s)
++ names (assert_ids s)
++ names (type_classes s)
++ names (symbolic_ids s)
++ names (exec_stack s)
++ names (model s)
++ names (known_values s)
++ names (track s)
rename old new s =
State { expr_env = rename old new (expr_env s)
, type_env =
M.mapKeys (\k -> if k == old then new else k)
$ rename old new (type_env s)
, curr_expr = rename old new (curr_expr s)
, path_conds = rename old new (path_conds s)
, non_red_path_conds = rename old new (non_red_path_conds s)
, true_assert = true_assert s
, assert_ids = rename old new (assert_ids s)
, type_classes = rename old new (type_classes s)
, symbolic_ids = rename old new (symbolic_ids s)
, exec_stack = rename old new (exec_stack s)
, model = rename old new (model s)
, known_values = rename old new (known_values s)
, rules = rules s
, num_steps = num_steps s
, track = rename old new (track s)
, tags = tags s }
renames hm s =
State { expr_env = renames hm (expr_env s)
, type_env =
M.mapKeys (renames hm)
$ renames hm (type_env s)
, curr_expr = renames hm (curr_expr s)
, path_conds = renames hm (path_conds s)
, non_red_path_conds = renames hm (non_red_path_conds s)
, true_assert = true_assert s
, assert_ids = renames hm (assert_ids s)
, type_classes = renames hm (type_classes s)
, symbolic_ids = renames hm (symbolic_ids s)
, exec_stack = renames hm (exec_stack s)
, model = renames hm (model s)
, known_values = renames hm (known_values s)
, rules = rules s
, num_steps = num_steps s
, track = renames hm (track s)
, tags = tags s }
instance ASTContainer t Expr => ASTContainer (State t) Expr where
containedASTs s = (containedASTs $ type_env s) ++
(containedASTs $ expr_env s) ++
(containedASTs $ curr_expr s) ++
(containedASTs $ path_conds s) ++
(containedASTs $ assert_ids s) ++
(containedASTs $ symbolic_ids s) ++
(containedASTs $ exec_stack s) ++
(containedASTs $ track s)
modifyContainedASTs f s = s { type_env = modifyContainedASTs f $ type_env s
, expr_env = modifyContainedASTs f $ expr_env s
, curr_expr = modifyContainedASTs f $ curr_expr s
, path_conds = modifyContainedASTs f $ path_conds s
, assert_ids = modifyContainedASTs f $ assert_ids s
, symbolic_ids = modifyContainedASTs f $ symbolic_ids s
, exec_stack = modifyContainedASTs f $ exec_stack s
, track = modifyContainedASTs f $ track s }
instance ASTContainer t Type => ASTContainer (State t) Type where
containedASTs s = ((containedASTs . expr_env) s) ++
((containedASTs . type_env) s) ++
((containedASTs . curr_expr) s) ++
((containedASTs . path_conds) s) ++
((containedASTs . assert_ids) s) ++
((containedASTs . type_classes) s) ++
((containedASTs . symbolic_ids) s) ++
((containedASTs . exec_stack) s) ++
(containedASTs $ track s)
modifyContainedASTs f s = s { type_env = (modifyContainedASTs f . type_env) s
, expr_env = (modifyContainedASTs f . expr_env) s
, curr_expr = (modifyContainedASTs f . curr_expr) s
, path_conds = (modifyContainedASTs f . path_conds) s
, assert_ids = (modifyContainedASTs f . assert_ids) s
, type_classes = (modifyContainedASTs f . type_classes) s
, symbolic_ids = (modifyContainedASTs f . symbolic_ids) s
, exec_stack = (modifyContainedASTs f . exec_stack) s
, track = modifyContainedASTs f $ track s }
instance Named Bindings where
names b = names (fixed_inputs b)
++ names (deepseq_walkers b)
++ names (cleaned_names b)
++ names (higher_order_inst b)
++ names (input_names b)
rename old new b =
Bindings { fixed_inputs = rename old new (fixed_inputs b)
, deepseq_walkers = rename old new (deepseq_walkers b)
, arb_value_gen = arb_value_gen b
, cleaned_names = HM.insert new old (cleaned_names b)
, higher_order_inst = rename old new (higher_order_inst b)
, input_names = rename old new (input_names b)
, rewrite_rules = rename old new (rewrite_rules b)
, name_gen = name_gen b
}
renames hm b =
Bindings { fixed_inputs = renames hm (fixed_inputs b)
, deepseq_walkers = renames hm (deepseq_walkers b)
, arb_value_gen = arb_value_gen b
, cleaned_names = foldr (\(old, new) -> HM.insert new old) (cleaned_names b) (HM.toList hm)
, higher_order_inst = renames hm (higher_order_inst b)
, input_names = renames hm (input_names b)
, rewrite_rules = renames hm (rewrite_rules b)
, name_gen = name_gen b
}
instance ASTContainer Bindings Expr where
containedASTs b = (containedASTs $ fixed_inputs b) ++ (containedASTs $ input_names b)
modifyContainedASTs f b = b { fixed_inputs = modifyContainedASTs f $ fixed_inputs b
, input_names = modifyContainedASTs f $ input_names b }
instance ASTContainer Bindings Type where
containedASTs b = ((containedASTs . fixed_inputs) b) ++ ((containedASTs . input_names) b)
modifyContainedASTs f b = b { fixed_inputs = (modifyContainedASTs f . fixed_inputs) b
, input_names = (modifyContainedASTs f . input_names) b }
instance ASTContainer CurrExpr Expr where
containedASTs (CurrExpr _ e) = [e]
modifyContainedASTs f (CurrExpr er e) = CurrExpr er (f e)
instance ASTContainer CurrExpr Type where
containedASTs (CurrExpr _ e) = containedASTs e
modifyContainedASTs f (CurrExpr er e) = CurrExpr er (modifyContainedASTs f e)
instance ASTContainer Frame Expr where
containedASTs (CaseFrame _ a) = containedASTs a
containedASTs (ApplyFrame e) = [e]
containedASTs (CurrExprFrame e) = containedASTs e
containedASTs (AssumeFrame e) = [e]
containedASTs (AssertFrame _ e) = [e]
containedASTs _ = []
modifyContainedASTs f (CaseFrame i a) = CaseFrame i (modifyContainedASTs f a)
modifyContainedASTs f (ApplyFrame e) = ApplyFrame (f e)
modifyContainedASTs f (CurrExprFrame e) = CurrExprFrame (modifyContainedASTs f e)
modifyContainedASTs f (AssumeFrame e) = AssumeFrame (f e)
modifyContainedASTs f (AssertFrame is e) = AssertFrame is (f e)
modifyContainedASTs _ fr = fr
instance ASTContainer Frame Type where
containedASTs (CaseFrame i a) = containedASTs i ++ containedASTs a
containedASTs (ApplyFrame e) = containedASTs e
containedASTs (CurrExprFrame e) = containedASTs e
containedASTs (AssumeFrame e) = containedASTs e
containedASTs (AssertFrame _ e) = containedASTs e
containedASTs _ = []
modifyContainedASTs f (CaseFrame i a) =
CaseFrame (modifyContainedASTs f i) (modifyContainedASTs f a)
modifyContainedASTs f (ApplyFrame e) = ApplyFrame (modifyContainedASTs f e)
modifyContainedASTs f (CurrExprFrame e) = CurrExprFrame (modifyContainedASTs f e)
modifyContainedASTs f (AssumeFrame e) = AssumeFrame (modifyContainedASTs f e)
modifyContainedASTs f (AssertFrame is e) = AssertFrame (modifyContainedASTs f is) (modifyContainedASTs f e)
modifyContainedASTs _ fr = fr
instance Named CurrExpr where
names (CurrExpr _ e) = names e
rename old new (CurrExpr er e) = CurrExpr er $ rename old new e
renames hm (CurrExpr er e) = CurrExpr er $ renames hm e
instance Named Frame where
names (CaseFrame i a) = names i ++ names a
names (ApplyFrame e) = names e
names (UpdateFrame n) = [n]
names (CastFrame c) = names c
names (CurrExprFrame e) = names e
names (AssumeFrame e) = names e
names (AssertFrame is e) = names is ++ names e
rename old new (CaseFrame i a) = CaseFrame (rename old new i) (rename old new a)
rename old new (ApplyFrame e) = ApplyFrame (rename old new e)
rename old new (UpdateFrame n) = UpdateFrame (rename old new n)
rename old new (CastFrame c) = CastFrame (rename old new c)
rename old new (CurrExprFrame e) = CurrExprFrame (rename old new e)
rename old new (AssumeFrame e) = AssumeFrame (rename old new e)
rename old new (AssertFrame is e) = AssertFrame (rename old new is) (rename old new e)
renames hm (CaseFrame i a) = CaseFrame (renames hm i) (renames hm a)
renames hm (ApplyFrame e) = ApplyFrame (renames hm e)
renames hm (UpdateFrame n) = UpdateFrame (renames hm n)
renames hm (CastFrame c) = CastFrame (renames hm c)
renames hm (CurrExprFrame e) = CurrExprFrame (renames hm e)
renames hm (AssumeFrame e) = AssumeFrame (renames hm e)
renames hm (AssertFrame is e) = AssertFrame (renames hm is) (renames hm e)