g2-0.1.0.0: src/G2/Interface/Interface.hs
{-# LANGUAGE FlexibleContexts #-}
{-# LANGUAGE OverloadedStrings #-}
module G2.Interface.Interface ( doTimeout
, maybeDoTimeout
, initState
, initState'
, initStateFromSimpleState
, initStateFromSimpleState'
, initSimpleState
, initRedHaltOrd
, initSolver
, initSolverInfinite
, initialStateFromFileSimple
, initialStateFromFile
, runG2FromFile
, runG2WithConfig
, runG2WithSomes
, runG2Pre
, runG2Post
, runG2ThroughExecution
, runExecution
, runG2Solving
, runG2
, Config) where
import G2.Config.Config
import G2.Language
import G2.Initialization.Interface
import G2.Initialization.KnownValues
import G2.Initialization.MkCurrExpr
import qualified G2.Initialization.Types as IT
import G2.Preprocessing.Interface
import G2.Execution.Interface
import G2.Execution.Reducer
import G2.Execution.PrimitiveEval
import G2.Execution.Memory
import G2.Interface.OutputTypes
import G2.Translation
import G2.Solver
import G2.Postprocessing.Interface
import qualified G2.Language.ExprEnv as E
import qualified G2.Language.PathConds as PC
import qualified G2.Language.Stack as Stack
import qualified Data.HashMap.Lazy as HM
import qualified Data.HashSet as S
import qualified Data.Map as M
import Data.Maybe
import qualified Data.Text as T
import System.Timeout
type AssumeFunc = T.Text
type AssertFunc = T.Text
type ReachFunc = T.Text
type StartFunc = T.Text
type ModuleName = Maybe T.Text
type MkCurrExpr = Id -> TypeClasses -> NameGen -> ExprEnv -> Walkers
-> KnownValues -> Config -> (Expr, [Id], [Expr], NameGen)
doTimeout :: Int -> IO a -> IO (Maybe a)
doTimeout secs action = do
res <- timeout (secs * 1000 * 1000) action -- timeout takes micros.
case res of
Just _ -> return res
Nothing -> do
putStrLn "Timeout!"
return Nothing
maybeDoTimeout :: Maybe Int -> IO a -> IO (Maybe a)
maybeDoTimeout (Just secs) = doTimeout secs
maybeDoTimeout Nothing = fmap Just
initState :: ExtractedG2 -> Bool -> StartFunc -> ModuleName
-> MkCurrExpr
-> Config -> (State (), Id, Bindings)
initState exg2 useAssert f m_mod mkCurr config =
let
s = initSimpleState exg2
in
initStateFromSimpleState s useAssert f m_mod mkCurr config
initState' :: ExtractedG2
-> StartFunc
-> ModuleName
-> MkCurrExpr
-> Config
-> (State (), Id, Bindings)
initState' exg2 sf m_mod mkCurr =
initState exg2 False sf m_mod mkCurr
initStateFromSimpleState :: IT.SimpleState
-> Bool
-> StartFunc
-> ModuleName
-> MkCurrExpr
-> Config
-> (State (), Id, Bindings)
initStateFromSimpleState s useAssert f m_mod mkCurr config =
let
(ie, fe) = case findFunc f m_mod (IT.expr_env s) of
Left ie' -> ie'
Right errs -> error errs
(_, ts) = instantiateArgTypes (IT.type_classes s) (IT.known_values s) fe
(s', ds_walkers) = runInitialization s ts
eenv' = IT.expr_env s'
tenv' = IT.type_env s'
ng' = IT.name_gen s'
kv' = IT.known_values s'
tc' = IT.type_classes s'
(ce, is, f_i, ng'') = mkCurr ie tc' ng' eenv' ds_walkers kv' config
in
(State {
expr_env = foldr (\i@(Id n _) -> E.insertSymbolic n i) eenv' is
, type_env = tenv'
, curr_expr = CurrExpr Evaluate ce
, path_conds = PC.fromList kv' $ map PCExists is
, non_red_path_conds = []
, true_assert = if useAssert then False else True
, assert_ids = Nothing
, type_classes = tc'
, symbolic_ids = is
, exec_stack = Stack.empty
, model = M.empty
, known_values = kv'
, rules = []
, num_steps = 0
, track = ()
, tags = S.empty
}
, ie
, Bindings {
deepseq_walkers = ds_walkers
, fixed_inputs = f_i
, arb_value_gen = arbValueInit
, cleaned_names = HM.empty
, input_names = map idName is
, higher_order_inst = IT.exports s
, rewrite_rules = IT.rewrite_rules s
, name_gen = ng''})
initStateFromSimpleState' :: IT.SimpleState
-> StartFunc
-> ModuleName
-> Config
-> (State (), Id, Bindings)
initStateFromSimpleState' s sf m_mod =
initStateFromSimpleState s False sf m_mod (mkCurrExpr Nothing Nothing)
initSimpleState :: ExtractedG2
-> IT.SimpleState
initSimpleState (ExtractedG2 { exg2_binds = prog
, exg2_tycons = prog_typ
, exg2_classes = cls
, exg2_exports = es
, exg2_rules = rs }) =
let
eenv = mkExprEnv prog
tenv = mkTypeEnv prog_typ
tc = initTypeClasses cls
kv = initKnownValues eenv tenv
ng = mkNameGen (prog, prog_typ)
in
IT.SimpleState { IT.expr_env = eenv
, IT.type_env = tenv
, IT.name_gen = ng
, IT.known_values = kv
, IT.type_classes = tc
, IT.rewrite_rules = rs
, IT.exports = es }
initCheckReaches :: State t -> ModuleName -> Maybe ReachFunc -> State t
initCheckReaches s@(State { expr_env = eenv
, known_values = kv }) m_mod reaches =
s {expr_env = checkReaches eenv kv reaches m_mod }
initRedHaltOrd :: Solver conv => conv -> Config -> (SomeReducer (), SomeHalter (), SomeOrderer ())
initRedHaltOrd conv config =
let
tr_ng = mkNameGen ()
state_name = Name "state" Nothing 0 Nothing
in
if higherOrderSolver config == AllFuncs
then (SomeReducer (NonRedPCRed)
<~| (case logStates config of
Just fp -> SomeReducer (StdRed conv :<~ Logger fp)
Nothing -> SomeReducer (StdRed conv))
, SomeHalter
(SwitchEveryNHalter 20
:<~> MaxOutputsHalter (maxOutputs config)
:<~> ZeroHalter (steps config)
:<~> AcceptHalter)
, SomeOrderer $ PickLeastUsedOrderer)
else ( SomeReducer (NonRedPCRed :<~| TaggerRed state_name tr_ng)
<~| (case logStates config of
Just fp -> SomeReducer (StdRed conv :<~ Logger fp)
Nothing -> SomeReducer (StdRed conv))
, SomeHalter
(DiscardIfAcceptedTag state_name
:<~> SwitchEveryNHalter 20
:<~> MaxOutputsHalter (maxOutputs config)
:<~> ZeroHalter (steps config)
:<~> AcceptHalter)
, SomeOrderer $ PickLeastUsedOrderer)
initSolver :: Config -> IO SomeSolver
initSolver = initSolver' arbValue
initSolverInfinite :: Config -> IO SomeSolver
initSolverInfinite con = initSolver' arbValueInfinite con
initSolver' :: ArbValueFunc -> Config -> IO SomeSolver
initSolver' avf config = do
SomeSMTSolver con <- getSMTAV avf config
let con' = GroupRelated avf (UndefinedHigherOrder :?> ADTSolver avf :?> con)
return (SomeSolver con')
mkExprEnv :: [(Id, Expr)] -> E.ExprEnv
mkExprEnv = E.fromExprList . map (\(i, e) -> (idName i, e))
mkTypeEnv :: [ProgramType] -> TypeEnv
mkTypeEnv = M.fromList . map (\(n, dcs) -> (n, dcs))
initialStateFromFileSimple :: [FilePath]
-> [FilePath]
-> [FilePath]
-> StartFunc
-> MkCurrExpr
-> Config
-> IO (State (), Id, Bindings)
initialStateFromFileSimple proj src libs f mkCurr config =
initialStateFromFile proj src libs Nothing False f mkCurr config
initialStateFromFile :: [FilePath]
-> [FilePath]
-> [FilePath]
-> Maybe ReachFunc
-> Bool
-> StartFunc
-> MkCurrExpr
-> Config
-> IO (State (), Id, Bindings)
initialStateFromFile proj src libs m_reach def_assert f mkCurr config = do
(mb_modname, exg2) <- translateLoaded proj src libs simplTranslationConfig config
let (init_s, ent_f, bindings) = initState exg2 def_assert
f mb_modname mkCurr config
reaches_state = initCheckReaches init_s mb_modname m_reach
return (reaches_state, ent_f, bindings)
runG2FromFile :: [FilePath]
-> [FilePath]
-> [FilePath]
-> Maybe AssumeFunc
-> Maybe AssertFunc
-> Maybe ReachFunc
-> Bool
-> StartFunc
-> Config
-> IO (([ExecRes ()], Bindings), Id)
runG2FromFile proj src libs m_assume m_assert m_reach def_assert f config = do
(init_state, entry_f, bindings) <- initialStateFromFile proj src libs
m_reach def_assert f (mkCurrExpr m_assume m_assert) config
r <- runG2WithConfig init_state config bindings
return (r, entry_f)
runG2WithConfig :: State () -> Config -> Bindings -> IO ([ExecRes ()], Bindings)
runG2WithConfig state config bindings = do
SomeSolver con <- initSolver config
(in_out, bindings') <- case initRedHaltOrd con config of
(red, hal, ord) ->
runG2WithSomes red hal ord con [] state bindings
close con
return (in_out, bindings')
runG2WithSomes :: ( Named t
, ASTContainer t Expr
, ASTContainer t Type
, Solver solver)
=> (SomeReducer t)
-> (SomeHalter t)
-> (SomeOrderer t)
-> solver
-> [Name]
-> State t
-> Bindings
-> IO ([ExecRes t], Bindings)
runG2WithSomes red hal ord con pns state bindings =
case (red, hal, ord) of
(SomeReducer red', SomeHalter hal', SomeOrderer ord') ->
runG2 red' hal' ord' con pns state bindings
runG2Pre :: ( Named t
, ASTContainer t Expr
, ASTContainer t Type) => [Name] -> State t -> Bindings -> (State t, Bindings)
runG2Pre pns s@(State { known_values = kv, type_classes = tc }) bindings =
let
(swept, bindings') = markAndSweepPreserving (pns ++ names (lookupStructEqDicts kv tc)) s bindings
in
runPreprocessing swept bindings'
runG2Post :: ( Named t
, ASTContainer t Expr
, ASTContainer t Type
, Reducer r rv t
, Halter h hv t
, Orderer or sov b t
, Solver solver) => r -> h -> or ->
solver -> State t -> Bindings -> IO ([ExecRes t], Bindings)
runG2Post red hal ord con is bindings = do
(exec_states, bindings') <- runExecution red hal ord is bindings
sol_states <- mapM (runG2Solving con bindings') exec_states
return (catMaybes sol_states, bindings')
runG2ThroughExecution ::
( Named t
, ASTContainer t Expr
, ASTContainer t Type
, Reducer r rv t
, Halter h hv t
, Orderer or sov b t) => r -> h -> or ->
[Name] -> State t -> Bindings -> IO ([State t], Bindings)
runG2ThroughExecution red hal ord pns is bindings = do
let (is', bindings') = runG2Pre pns is bindings
runExecution red hal ord is' bindings'
runG2Solving :: ( Named t
, ASTContainer t Expr
, ASTContainer t Type
, Solver solver) =>
solver -> Bindings -> State t -> IO (Maybe (ExecRes t))
runG2Solving con bindings s@(State { known_values = kv })
| true_assert s = do
(_, m) <- solve con s bindings (symbolic_ids s) (path_conds s)
case m of
Just m' -> do
let s' = s { model = m' }
let (es, e, ais) = subModel s' bindings
sm = ExecRes { final_state = s'
, conc_args = es
, conc_out = e
, violated = ais}
let sm' = runPostprocessing bindings sm
let sm'' = ExecRes { final_state = final_state sm'
, conc_args = fixed_inputs bindings ++ conc_args sm'
, conc_out = evalPrims kv (conc_out sm')
, violated = evalPrims kv (violated sm')}
return (Just sm'')
Nothing -> do
return Nothing
| otherwise = return Nothing
-- | Runs G2, returning both fully executed states,
-- and states that have only been partially executed.
runG2 :: ( Named t
, ASTContainer t Expr
, ASTContainer t Type
, Reducer r rv t
, Halter h hv t
, Orderer or sov b t
, Solver solver) => r -> h -> or ->
solver -> [Name] -> State t -> Bindings -> IO ([ExecRes t], Bindings)
runG2 red hal ord con pns is bindings = do
(exec_states, bindings') <- runG2ThroughExecution red hal ord pns is bindings
sol_states <- mapM (runG2Solving con bindings') exec_states
return (catMaybes sol_states, bindings')