g2-0.2.0.0: src/G2/Nebula.hs
{-# LANGUAGE CPP, FlexibleContexts #-}
module G2.Nebula (plugin) where
#if MIN_VERSION_GLASGOW_HASKELL(9,0,2,0)
import GHC.Plugins
#else
import GhcPlugins
#endif
import G2.Config
import G2.Equiv.Config
import G2.Equiv.Verifier
import qualified G2.Initialization.Types as IT
import G2.Interface
import G2.Language as L
import qualified G2.Language.ExprEnv as E
import qualified G2.Solver as S
import G2.Translation
import Data.IORef
import System.IO.Unsafe
import Data.List
import qualified Data.Text as T
import Options.Applicative
-- | During symbolic execution, we need to know definitions, types, etc.
-- from previously compiled modules. We also need to avoid reusing the same
-- names. We use `compiledModules` to store both previously compiled modules
-- and existing Expression/Type Name maps.
compiledModules :: IORef (Maybe (ExtractedG2, NameMap, TypeNameMap))
compiledModules = unsafePerformIO $ newIORef Nothing
{-# NOINLINE compiledModules #-}
plugin :: Plugin
plugin = defaultPlugin { installCoreToDos = install }
install :: [CommandLineOption] -> [CoreToDo] -> CoreM [CoreToDo]
install cmd_lne todo = do
env <- getHscEnv
let pr_nebula_config = getNebulaConfigPlugin cmd_lne
(entry, nebula_config) <- liftIO $ handleParseResult pr_nebula_config
return $ CoreDoPluginPass "Nebula" (nebulaPluginPass entry nebula_config env):todo
nebulaPluginPass :: Maybe String -> NebulaConfig -> HscEnv -> ModGuts -> CoreM ModGuts
nebulaPluginPass m_entry nebula_config env modguts = do
_ <- liftIO $ nebulaPluginPass' m_entry nebula_config env modguts
return modguts
nebulaPluginPass' :: Maybe String -> NebulaConfig -> HscEnv -> ModGuts -> IO ()
nebulaPluginPass' m_entry nebula_config env modguts = do
config <- getConfigDirect
-- We want simpl to be False so the simplifier does not run, because
-- this plugin get's inserted into the simplifier. Thus, running the implifier
-- results in an infinite loop.
let tconfig = (simplTranslationConfig {simpl = False, load_rewrite_rules = True, hpc_ticks = False})
ems = EnvModSumModGuts env [] [modguts]
prev_comp <- readIORef compiledModules
(prev_exg2, prev_nm, prev_tnm) <- case prev_comp of
Just prev -> return prev
Nothing -> translateBase tconfig config [] Nothing
(new_nm, new_tm, exg2) <- hskToG2ViaEMS tconfig ems prev_nm prev_tnm
let merged_exg2 = mergeExtractedG2s [exg2, prev_exg2]
injected_exg2 = specialInject merged_exg2
writeIORef compiledModules $ Just (merged_exg2, new_nm, new_tm)
let simp_state = initSimpleState injected_exg2
(init_state, bindings) = initStateFromSimpleState simp_state Nothing False
(\_ ng _ _ _ _ _ -> (Prim Undefined TyBottom, [], [], ng))
(E.higherOrderExprs . IT.expr_env)
config
let total = []
case m_entry of
Just entry -> do
let tentry = T.pack entry
let rule = find (\r -> tentry == L.ru_name r) (rewrite_rules bindings)
rule' = case rule of
Just r -> r
Nothing -> error "not found"
_ <- checkRulePrinting config nebula_config init_state bindings total rule'
return ()
Nothing -> do
let mod_name = T.pack . moduleNameString . moduleName . mg_module $ modguts
mapM_ (checkRulePrinting config nebula_config init_state bindings total)
$ filter (\r -> L.ru_module r == mod_name) (rewrite_rules bindings)
checkRulePrinting :: (ASTContainer t L.Type, ASTContainer t L.Expr) => Config
-> NebulaConfig
-> State t
-> Bindings
-> [T.Text] -- ^ names of forall'd variables required to be total
-> RewriteRule
-> IO (S.Result () () ())
checkRulePrinting config nebula_config init_state bindings total rule = do
let rule_name = T.unpack $ L.ru_name rule
nebula_config' = case log_rule nebula_config of
Just n -> if n == rule_name then nebula_config
else nebula_config {log_states = NoLog}
Nothing -> nebula_config
putStrLn $ "Log-rule nebula config = " ++ show (log_rule nebula_config)
putStrLn $ "Checking " ++ rule_name
res <- checkRule config nebula_config' init_state bindings total rule
case res of
S.SAT _ -> putStrLn $ rule_name ++ " - counterexample found"
S.UNSAT _ -> putStrLn $ rule_name ++ " - verified"
S.Unknown _ _ -> putStrLn $ rule_name ++ " - unknown result"
return res