{-# LANGUAGE NamedFieldPuns #-}
module Data.SBV.SMT.Utils (
SMTLibConverter
, SMTLibIncConverter
, annotateWithName
, showTimeoutValue
, alignDiagnostic
, alignPlain
, debug
, mergeSExpr
, SMTException(..)
)
where
import qualified Control.Exception as C
import Data.SBV.Core.Data
import Data.SBV.Utils.Lib (joinArgs)
import Data.List (intercalate)
import qualified Data.Set as Set (Set)
import System.Exit (ExitCode(..))
type SMTLibConverter a = Set.Set Kind
-> Bool
-> [String]
-> ([(Quantifier, NamedSymVar)], [NamedSymVar])
-> [Either SW (SW, [SW])]
-> [(SW, CW)]
-> [((Int, Kind, Kind), [SW])]
-> [(Int, ArrayInfo)]
-> [(String, SBVType)]
-> [(String, [String])]
-> SBVPgm
-> [(Maybe String, SW)]
-> SW
-> SMTConfig
-> a
type SMTLibIncConverter a = [NamedSymVar]
-> Set.Set Kind
-> [(SW, CW)]
-> [(Int, ArrayInfo)]
-> [((Int, Kind, Kind), [SW])]
-> SBVPgm
-> SMTConfig
-> a
annotateWithName :: String -> String -> String
annotateWithName nm x = "(! " ++ x ++ " :named |" ++ concatMap sanitize nm ++ "|)"
where sanitize '|' = "_bar_"
sanitize '\\' = "_backslash_"
sanitize c = [c]
showTimeoutValue :: Int -> String
showTimeoutValue i = case (i `quotRem` 1000000, i `quotRem` 500000) of
((s, 0), _) -> shows s "s"
(_, (hs, 0)) -> shows (fromIntegral hs / (2::Float)) "s"
_ -> shows i "ms"
alignDiagnostic :: String -> String -> String
alignDiagnostic = alignWithPrefix "*** "
alignPlain :: String -> String -> String
alignPlain = alignWithPrefix ""
alignWithPrefix :: String -> String -> String -> String
alignWithPrefix pre tag multi = intercalate "\n" $ zipWith (++) (tag : repeat (pre ++ replicate (length tag - length pre) ' ')) (filter (not . null) (lines multi))
debug :: SMTConfig -> [String] -> IO ()
debug cfg
| not (verbose cfg) = const (return ())
| Just f <- redirectVerbose cfg = mapM_ (appendFile f . (++ "\n"))
| True = mapM_ putStrLn
mergeSExpr :: [String] -> [String]
mergeSExpr [] = []
mergeSExpr (x:xs)
| d == 0 = x : mergeSExpr xs
| True = let (f, r) = grab d xs in unlines (x:f) : mergeSExpr r
where d = parenDiff x
parenDiff :: String -> Int
parenDiff = go 0
where go i "" = i
go i ('(':cs) = let i'= i+1 in i' `seq` go i' cs
go i (')':cs) = let i'= i-1 in i' `seq` go i' cs
go i ('"':cs) = go i (skipString cs)
go i ('|':cs) = go i (skipBar cs)
go i (_ :cs) = go i cs
grab i ls
| i <= 0 = ([], ls)
grab _ [] = ([], [])
grab i (l:ls) = let (a, b) = grab (i+parenDiff l) ls in (l:a, b)
skipString ('"':'"':cs) = skipString cs
skipString ('"':cs) = cs
skipString (_:cs) = skipString cs
skipString [] = []
skipBar ('|':cs) = cs
skipBar (_:cs) = skipBar cs
skipBar [] = []
data SMTException = SMTException {
smtExceptionDescription :: String
, smtExceptionSent :: String
, smtExceptionExpected :: String
, smtExceptionReceived :: String
, smtExceptionStdOut :: String
, smtExceptionStdErr :: Maybe String
, smtExceptionExitCode :: Maybe ExitCode
, smtExceptionConfig :: SMTConfig
, smtExceptionReason :: Maybe [String]
, smtExceptionHint :: Maybe [String]
}
instance C.Exception SMTException
instance Show SMTException where
show SMTException { smtExceptionDescription
, smtExceptionSent
, smtExceptionExpected
, smtExceptionReceived
, smtExceptionStdOut
, smtExceptionStdErr
, smtExceptionExitCode
, smtExceptionConfig
, smtExceptionReason
, smtExceptionHint
}
= let grp1 = [ ""
, "*** " ++ smtExceptionDescription ++ ":"
, "***"
, "*** Sent : " `alignDiagnostic` smtExceptionSent
, "*** Expected : " `alignDiagnostic` smtExceptionExpected
, "*** Received : " `alignDiagnostic` smtExceptionReceived
]
grp2 = ["*** Stdout : " `alignDiagnostic` smtExceptionStdOut | not $ null smtExceptionStdOut ]
++ ["*** Stderr : " `alignDiagnostic` err | Just err <- [smtExceptionStdErr], not $ null err]
++ ["*** Exit code : " `alignDiagnostic` show ec | Just ec <- [smtExceptionExitCode] ]
++ ["*** Executable: " `alignDiagnostic` executable (solver smtExceptionConfig) ]
++ ["*** Options : " `alignDiagnostic` joinArgs (options (solver smtExceptionConfig) smtExceptionConfig) ]
grp3 = ["*** Reason : " `alignDiagnostic` unlines rsn | Just rsn <- [smtExceptionReason]]
++ ["*** Hint : " `alignDiagnostic` unlines hnt | Just hnt <- [smtExceptionHint ]]
sep1
| null grp2 = []
| True = ["***"]
sep2
| null grp3 = []
| True = ["***"]
in unlines $ grp1 ++ sep1 ++ grp2 ++ sep2 ++ grp3