g2-0.2.0.0: src/G2/Translation/HaskellCheck.hs
module G2.Translation.HaskellCheck ( validateStates
, runHPC) where
import GHC hiding (Name, entry)
import GHC.Paths
import Data.Either
import Data.List
import qualified Data.Text as T
import Text.Regex
import Unsafe.Coerce
import G2.Initialization.MkCurrExpr
import G2.Interface.OutputTypes
import G2.Language
import G2.Translation.Haskell
import G2.Translation.TransTypes
import G2.Lib.Printers
import Control.Exception
import System.Process
import Control.Monad.IO.Class
validateStates :: [FilePath] -> [FilePath] -> String -> String -> [String] -> [GeneralFlag] -> [ExecRes t] -> IO Bool
validateStates proj src modN entry chAll gflags in_out = do
return . all id =<< runGhc (Just libdir) (do
loadToCheck proj src modN gflags
mapM (runCheck modN entry chAll) in_out)
-- Compile with GHC, and check that the output we got is correct for the input
runCheck :: String -> String -> [String] -> ExecRes t -> Ghc Bool
runCheck modN entry chAll (ExecRes {final_state = s, conc_args = ars, conc_out = out}) = do
(v, chAllR) <- runCheck' modN entry chAll s ars out
v' <- liftIO $ (unsafeCoerce v :: IO (Either SomeException Bool))
let outStr = T.unpack $ printHaskell s out
let v'' = case v' of
Left _ -> outStr == "error"
Right b -> b && outStr /= "error"
chAllR' <- liftIO $ (unsafeCoerce chAllR :: IO [Either SomeException Bool])
let chAllR'' = rights chAllR'
return $ v'' && and chAllR''
runCheck' :: String -> String -> [String] -> State t -> [Expr] -> Expr -> Ghc (HValue, [HValue])
runCheck' modN entry chAll s ars out = do
let Left (v, _) = findFunc (T.pack entry) (Just $ T.pack modN) (expr_env s)
let e = mkApp $ Var v:ars
let pg = updatePrettyGuide (exprNames e)
. updatePrettyGuide (exprNames out)
$ mkPrettyGuide $ varIds v
let arsStr = T.unpack $ printHaskellPG pg s e
let outStr = T.unpack $ printHaskellPG pg s out
let arsType = T.unpack $ mkTypeHaskell (typeOf e)
outType = T.unpack $ mkTypeHaskell (typeOf out)
let chck = case outStr == "error" of
False -> "try (evaluate (" ++ arsStr ++ " == " ++ "("
++ outStr ++ " :: " ++ outType ++ ")" ++ ")) :: IO (Either SomeException Bool)"
True -> "try (evaluate ( (" ++ arsStr ++ " :: " ++ arsType ++
") == " ++ arsStr ++ ")) :: IO (Either SomeException Bool)"
v' <- compileExpr chck
let chArgs = ars ++ [out]
let chAllStr = map (\f -> T.unpack $ printHaskellPG pg s $ mkApp ((simpVar $ T.pack f):chArgs)) chAll
let chAllStr' = map (\str -> "try (evaluate (" ++ str ++ ")) :: IO (Either SomeException Bool)") chAllStr
chAllR <- mapM compileExpr chAllStr'
return $ (v', chAllR)
loadToCheck :: [FilePath] -> [FilePath] -> String -> [GeneralFlag] -> Ghc ()
loadToCheck proj src modN gflags = do
_ <- loadProj Nothing proj src gflags simplTranslationConfig
let prN = mkModuleName "Prelude"
let prImD = simpleImportDecl prN
let exN = mkModuleName "Control.Exception"
let exImD = simpleImportDecl exN
let coerceN = mkModuleName "Data.Coerce"
let coerceImD = simpleImportDecl coerceN
let charN = mkModuleName "Data.Char"
let charD = simpleImportDecl charN
let mdN = mkModuleName modN
let imD = simpleImportDecl mdN
setContext [IIDecl prImD, IIDecl exImD, IIDecl coerceImD, IIDecl imD, IIDecl charD]
simpVar :: T.Text -> Expr
simpVar s = Var (Id (Name s Nothing 0 Nothing) TyBottom)
runHPC :: FilePath -> String -> String -> [(State t, Bindings, [Expr], Expr, Maybe FuncCall)] -> IO ()
runHPC src modN entry in_out = do
let calls = map (\(s, _, i, o, _) -> toCall entry s i o) in_out
runHPC' src modN calls
-- Compile with GHC, and check that the output we got is correct for the input
runHPC' :: FilePath -> String -> [String] -> IO ()
runHPC' src modN ars = do
srcCode <- readFile src
let srcCode' = removeModule modN srcCode
let spces = " "
let chck = intercalate ("\n" ++ spces) $ map (\s -> "print (" ++ s ++ ")") ars
let mainFunc = "\n\nmain :: IO ()\nmain =do\n" ++ spces ++ chck ++ "\n" ++ spces
let mainN = "Main_" ++ modN
writeFile (mainN ++ ".hs") (srcCode' ++ mainFunc)
callProcess "ghc" ["-fhpc", mainN ++ ".hs"]
callProcess ("./" ++ mainN) []
callProcess "hpc" ["report", mainN]
-- putStrLn mainFunc
toCall :: String -> State t -> [Expr] -> Expr -> String
toCall entry s ars _ = T.unpack . printHaskell s $ mkApp ((simpVar $ T.pack entry):ars)
removeModule :: String -> String -> String
removeModule modN s =
let
r = mkRegex $ "module " ++ modN ++ " where"
in
subRegex r s ""