packages feed

simple-smt 0.9.7 → 0.9.8

raw patch · 2 files changed

+153/−39 lines, 2 filesPVP: major bump suggested

API removals or changes: PVP suggests a major version bump

API changes (from Hackage documentation)

+ SimpleSMT: Config :: String -> [String] -> Maybe (ExitCode -> IO ()) -> SolverLogger -> Config
+ SimpleSMT: SolverLogger :: (SExpr -> IO ()) -> (SExpr -> IO ()) -> (IOException -> IO ()) -> (String -> IO ()) -> SolverLogger
+ SimpleSMT: [forceStop] :: Solver -> IO ExitCode
+ SimpleSMT: [solverArguments] :: Config -> [String]
+ SimpleSMT: [solverExecutable] :: Config -> String
+ SimpleSMT: [solverLogExcn] :: SolverLogger -> IOException -> IO ()
+ SimpleSMT: [solverLogRecv] :: SolverLogger -> SExpr -> IO ()
+ SimpleSMT: [solverLogSend] :: SolverLogger -> SExpr -> IO ()
+ SimpleSMT: [solverLogStdErr] :: SolverLogger -> String -> IO ()
+ SimpleSMT: [solverLogger] :: Config -> SolverLogger
+ SimpleSMT: [solverOnExit] :: Config -> Maybe (ExitCode -> IO ())
+ SimpleSMT: data Config
+ SimpleSMT: data SolverLogger
+ SimpleSMT: defaultConfig :: String -> [String] -> Config
+ SimpleSMT: heraldSolverLogger :: Logger -> SolverLogger
+ SimpleSMT: newLoggerWithHandle :: Handle -> Int -> IO Logger
+ SimpleSMT: newSolverWithConfig :: Config -> IO Solver
+ SimpleSMT: noSolverLogger :: SolverLogger
+ SimpleSMT: smtSolverLogger :: Logger -> SolverLogger
- SimpleSMT: Solver :: (SExpr -> IO SExpr) -> IO ExitCode -> Solver
+ SimpleSMT: Solver :: (SExpr -> IO SExpr) -> IO ExitCode -> IO ExitCode -> Solver

Files

SimpleSMT.hs view
@@ -8,6 +8,13 @@     Solver(..)   , newSolver   , newSolverNotify+  , newSolverWithConfig+  , Config(..)+  , SolverLogger(..)+  , defaultConfig+  , noSolverLogger+  , heraldSolverLogger+  , smtSolverLogger   , ackCommand   , simpleCommand   , simpleCommandMaybe@@ -21,6 +28,7 @@     -- ** Logging and Debugging   , Logger(..)   , newLogger+  , newLoggerWithHandle   , withLogLevel   , logMessageAt   , logIndented@@ -39,7 +47,7 @@   , define   , defineFun   , defineFunRec-  , defineFunsRec  +  , defineFunsRec   , assert   , check   , Result(..)@@ -59,8 +67,8 @@   , quoteSymbol   , symbol   , keyword-  , as -  +  , as+     -- ** Types   , tInt   , tBool@@ -147,8 +155,9 @@ import Data.Bits(testBit) import Data.IORef(newIORef, atomicModifyIORef, modifyIORef', readIORef,                   writeIORef)-import System.Process(runInteractiveProcess, waitForProcess)-import System.IO (hFlush, hGetLine, hGetContents, hPutStrLn, stdout, hClose)+import System.Process(runInteractiveProcess, waitForProcess, terminateProcess)+import System.IO (Handle, hFlush, hGetLine, hGetContents, hPutStr, hPutStrLn,+                  stdout, hClose) import System.Exit(ExitCode) import qualified Control.Exception as X import Control.Concurrent(forkIO)@@ -178,16 +187,35 @@               deriving (Eq, Ord, Show)  -- | Show an s-expression.+--+-- >>> let Just (e, _) = readSExpr "(assert (= ((_ map (- (Int Int) Int)) a1Cl a1Cm) a1Cv))"+-- >>> putStrLn $ showsSExpr e ""+-- (assert (= ((_ map (- (Int Int) Int)) a1Cl a1Cm) a1Cv)) showsSExpr :: SExpr -> ShowS showsSExpr ex =   case ex of     Atom x  -> showString x-    List es -> showChar '(' .-                foldr (\e m -> showsSExpr e . showChar ' ' . m)-                (showChar ')') es+    List [] -> showString "()"+    List (e0 : es) -> showChar '(' . showsSExpr e0 .+                       foldr (\e m -> showChar ' ' . showsSExpr e . m)+                       (showChar ')') es  --- | Show an S-expression in a somewhat readbale fashion.+-- | Show an s-expression in a somewhat readable fashion.+--+-- >>> let Just (e, _) = readSExpr "(assert (= ((_ map (- (Int Int) Int)) a1Cl a1Cm) a1Cv))"+-- >>> putStrLn $ ppSExpr e ""+-- (assert+--    (=+--       (+--         (_+--            map+--            (-+--               (Int Int)+--               Int))+--         a1Cl+--         a1Cm)+--       a1Cv)) ppSExpr :: SExpr -> ShowS ppSExpr = go 0   where@@ -219,11 +247,14 @@       List es -> showString "(" . many (map (new (n+2)) es) . showString ")"  -- | Parse an s-expression.+--+-- >>> readSExpr "(_ map (- (Int Int) Int)) a1Cl a1Cm)"+-- Just (List [Atom "_",Atom "map",List [Atom "-",List [Atom "Int",Atom "Int"],Atom "Int"]]," a1Cl a1Cm)") readSExpr :: String -> Maybe (SExpr, String) readSExpr (c : more) | isSpace c = readSExpr more readSExpr (';' : more) = readSExpr $ drop 1 $ dropWhile (/= '\n') more readSExpr ('|' : more) = do (sym, '|' : rest) <- pure (span ((/=) '|') more)-                            Just (Atom ('|' : sym ++ ['|']), rest)                            +                            Just (Atom ('|' : sym ++ ['|']), rest) readSExpr ('(' : more) = do (xs,more1) <- list more                             return (List xs, more1)   where@@ -246,7 +277,10 @@     -- ^ Send a command to the solver.    , stop :: IO ExitCode-    -- ^ Terminate the solver.+    -- ^ Wait for the solver to finish and exit gracefully.++  , forceStop :: IO ExitCode+    -- ^ Terminate the solver without waiting for it to finish.   }  @@ -255,7 +289,10 @@              [String]     {- ^ Arguments -}             ->              Maybe Logger {- ^ Optional logging here -} ->              IO Solver-newSolver n xs l = newSolverNotify n xs l Nothing+newSolver exe opts mbLog = newSolverWithConfig $+  (defaultConfig exe opts)+    { solverLogger = maybe noSolverLogger heraldSolverLogger mbLog+    }  newSolverNotify ::   String        {- ^ Executable -}            ->@@ -263,15 +300,24 @@   Maybe Logger  {- ^ Optional logging here -} ->   Maybe (ExitCode -> IO ()) {- ^ Do this when the solver exits -} ->   IO Solver-newSolverNotify exe opts mbLog mbOnExit =-  do (hIn, hOut, hErr, h) <- runInteractiveProcess exe opts Nothing Nothing+newSolverNotify exe opts mbLog mbOnExit = newSolverWithConfig $+  (defaultConfig exe opts)+    { solverOnExit = mbOnExit+    , solverLogger = maybe noSolverLogger heraldSolverLogger mbLog+    } -     let info a = case mbLog of-                    Nothing -> return ()-                    Just l  -> logMessage l a+-- | Start a new solver process using the provided 'Config' options.+newSolverWithConfig :: Config -> IO Solver+newSolverWithConfig+  (Config { solverExecutable = exe+          , solverArguments = opts+          , solverOnExit = mbOnExit+          , solverLogger = log+          }) =+  do (hIn, hOut, hErr, h) <- runInteractiveProcess exe opts Nothing Nothing       _ <- forkIO $ forever (do errs <- hGetLine hErr-                               info ("[stderr] " ++ errs))+                               solverLogStdErr log errs)                     `X.catch` \X.SomeException {} -> return ()       case mbOnExit of@@ -287,7 +333,7 @@                         y : ys -> (ys, Just y)       let cmd c = do let txt = showsSExpr c ""-                    info ("[send->] " ++ txt)+                    solverLogSend log c                     hPutStrLn hIn txt                     hFlush hIn @@ -295,20 +341,25 @@            do cmd c               mb <- getResponse               case mb of-                Just res -> do info ("[<-recv] " ++ showsSExpr res "")+                Just res -> do solverLogRecv log res                                return res                 Nothing  -> fail "Missing response from solver" -         stop =-           do cmd (List [Atom "exit"])-                `X.catch` (\X.SomeException{} -> pure ())-              ec <- waitForProcess h+         waitAndCleanup =+           do ec <- waitForProcess h               X.catch (do hClose hIn                           hClose hOut                           hClose hErr)-                      (\ex -> info (show (ex::X.IOException)))+                      (solverLogExcn log)               return ec +         forceStop = terminateProcess h *> waitAndCleanup++         stop =+           do cmd (List [Atom "exit"])+                `X.catch` (\X.SomeException{} -> pure ())+              waitAndCleanup+          solver = Solver { .. }       setOption solver ":print-success" "true"@@ -316,7 +367,73 @@       return solver +-- | Options for configuring how to start, stop, and interact with an SMT+-- solver process.+data Config = Config+  { solverExecutable :: String+    -- ^ The SMT solver executable.+  , solverArguments :: [String]+    -- ^ The command-line arguments to pass to the SMT solver.+  , solverOnExit :: Maybe (ExitCode -> IO ())+    -- ^ Do this when the SMT solver exits.+  , solverLogger :: SolverLogger+    -- ^ How to log solver-related messages.+  } +-- | Options for logging SMT solver–related messages.+data SolverLogger = SolverLogger+  { solverLogSend :: SExpr -> IO ()+    -- ^ Log an SMT query ('SExpr') being sent to the SMT solver.+  , solverLogRecv :: SExpr -> IO ()+    -- ^ Log a response ('SExpr') being received from the SMT solver.+  , solverLogExcn :: X.IOException -> IO ()+    -- ^ Log the SMT solver throwing an 'X.IOException'.+  , solverLogStdErr :: String -> IO ()+    -- ^ Log the SMT solver displaying an error to @stderr@.+  }++-- | A reasonable default 'Config' value.+defaultConfig ::+  String   {- ^ Solver executable -} ->+  [String] {- ^ Solver arguments -}  ->+  Config+defaultConfig exe opts = Config+  { solverExecutable = exe+  , solverArguments = opts+  , solverOnExit = Nothing+  , solverLogger = noSolverLogger+  }++-- | A trivial 'SolverLogger' that does not perform any logging.+noSolverLogger :: SolverLogger+noSolverLogger = SolverLogger+  { solverLogSend = \_ -> pure ()+  , solverLogRecv = \_ -> pure ()+  , solverLogExcn = \_ -> pure ()+  , solverLogStdErr = \_ -> pure ()+  }++-- | A basic 'SolverLogger' that prints out heralds in front of sent and+-- received SMT queries, as well as messages to @stderr@. This is the approach+-- that 'newSolver' and 'newSolverNotify' use for logging.+heraldSolverLogger :: Logger -> SolverLogger+heraldSolverLogger l = SolverLogger+  { solverLogSend = \c -> logMessage l ("[send->] " ++ showsSExpr c "")+  , solverLogRecv = \c -> logMessage l ("[<-recv] " ++ showsSExpr c "")+  , solverLogExcn = \exc -> logMessage l (show exc)+  , solverLogStdErr = \errs -> logMessage l ("[stderr] " ++ errs)+  }++-- | A 'SolverLogger' that formats log messages into the SMT-LIB file format so+-- that the resulting log can be parsed as input by an SMT solver.+smtSolverLogger :: Logger -> SolverLogger+smtSolverLogger l = SolverLogger+  { solverLogSend = \c -> logMessage l (showsSExpr c "")+  , solverLogRecv = \c -> logMessage l ("; " ++ showsSExpr c "")+  , solverLogExcn = \exc -> logMessage l (show exc)+  , solverLogStdErr = \errs -> logMessage l errs+  }+ -- | Load the contents of a file. loadFile :: Solver -> FilePath -> IO () loadFile s file = loadString s =<< readFile file@@ -504,7 +621,7 @@     decls  = List (map oneArg ds)     bodies = List (map (\(_, _, _, body) -> body) ds) -     + -- | Assume a fact. assert :: Solver -> SExpr -> IO () assert proc e = ackCommand proc $ fun "assert" [e]@@ -643,7 +760,7 @@ isSimpleSymbol _         = False  quoteSymbol :: String -> String-quoteSymbol s +quoteSymbol s   | isSimpleSymbol s = s   | otherwise        = '|' : s ++ "|" @@ -1008,7 +1125,12 @@ -- | A simple stdout logger.  Shows only messages logged at a level that is -- greater than or equal to the passed level. newLogger :: Int -> IO Logger-newLogger l =+newLogger = newLoggerWithHandle stdout++-- | A simple logger that writes to a 'Handle'. Shows only messages logged at a+-- level that is greater than or equal to the passed level.+newLoggerWithHandle :: Handle -> Int -> IO Logger+newLoggerWithHandle h l =   do tab <- newIORef 0      lev <- newIORef 0      let logLevel    = readIORef lev@@ -1021,17 +1143,9 @@          logMessage x = shouldLog $            do let ls = lines x               t <- readIORef tab-              putStr $ unlines [ replicate t ' ' ++ l | l <- ls ]-              hFlush stdout+              hPutStr h $ unlines [ replicate t ' ' ++ l | l <- ls ]+              hFlush h           logTab   = shouldLog (modifyIORef' tab (+ 2))          logUntab = shouldLog (modifyIORef' tab (subtract 2))      return Logger { .. }--------
simple-smt.cabal view
@@ -1,5 +1,5 @@ name:                simple-smt-version:             0.9.7+version:             0.9.8 synopsis:            A simple way to interact with an SMT solver process. description:         A simple way to interact with an SMT solver process. license:             BSD3