sexpr-parser-0.2.2.0: z3-demo/Main.hs
{-|
Module : Main
Description : Z3 demo
Copyright : (C) Richard Cook, 2019
Licence : MIT
Maintainer : rcook@rcook.org
Stability : stable
Portability : portable
-}
{-# OPTIONS_GHC -Wall -Werror -Wno-incomplete-uni-patterns #-}
module Main (main) where
import Control.Applicative ((<|>))
import Control.Exception (evaluate)
import Control.Monad (void)
import Data.Foldable (for_)
import Data.List (sort)
import Data.Maybe (catMaybes)
import System.IO (BufferMode(..), hGetContents, hPutStrLn, hSetBuffering)
import System.Process
import Text.Megaparsec (parse)
import Text.Megaparsec.Char (char, string)
import Text.Printf (printf)
import Text.SExpression (Parser, SExpr(..), parseSExpr, def)
data Z3SATResult = Satisfied | Unsatisfied deriving Show
data Z3Output = Z3Output Z3SATResult SExpr deriving Show
main :: IO ()
main = do
result <- checkSATWithZ3 "input.smt2" $
"(push)\n\
\(declare-const x bool)\n\
\(declare-const y bool)\n\
\(assert (and (not x) y))\n\
\(check-sat)\n\
\(get-model)\n\
\(pop)\n\
\(exit)\n"
case result of
Left e -> putStrLn $ "Error: " ++ e
Right (satResult, funs) -> do
for_ funs $ \(name, value) ->
putStrLn $ printf "%s = %s" name (if value then "1" else "0")
putStrLn $ printf "result=%s" (show satResult)
parseZ3SATResult :: Parser Z3SATResult
parseZ3SATResult = do
s <- string "sat" <|> string "unsat"
void $ char '\n'
case s of
"sat" -> pure Satisfied
"unsat" -> pure Unsatisfied
_ -> error "Unreachable"
parseZ3Output :: Parser Z3Output
parseZ3Output = Z3Output <$> parseZ3SATResult <*> parseSExpr def
checkSATWithZ3 :: String -> String -> IO (Either String (Z3SATResult, [(String, Bool)]))
checkSATWithZ3 ctx input = do
output <- withCreateProcess (proc "z3" ["-in"])
{ std_in = CreatePipe
, std_out = CreatePipe
, std_err = Inherit
} $ \(Just hIn) (Just hOut) _ _ -> do
hSetBuffering hIn NoBuffering
hPutStrLn hIn input
s <- hGetContents hOut
void $ evaluate (length s)
pure s
case parse parseZ3Output ctx output of
Left e -> pure $ Left (show e)
Right (Z3Output satResult f) -> pure $ Right (satResult, sort (boolFuns f))
boolFuns :: SExpr -> [(String, Bool)]
boolFuns (List (Atom "model" : fs)) = catMaybes $ map p fs
where
p :: SExpr -> Maybe (String, Bool)
p (List [Atom "define-fun", Atom name, List [], Atom "bool", Atom "false"]) = Just (name, False)
p (List [Atom "define-fun", Atom name, List [], Atom "bool", Atom "true"]) = Just (name, True)
p _ = Nothing
boolFuns _ = []