sexpr-parser-0.2.0.0: lib/Text/SExpression.hs
{-|
Module : Text.SExpression
Description : S-expression parser
Copyright : (C) Richard Cook, 2019
Licence : MIT
Maintainer : rcook@rcook.org
Stability : stable
Portability : portable
This module provides a 'parseSExpr' function which parses simple
s-expressions represented using the 'SExpr' type from 'String' input.
Here's a full example which uses <https://github.com/Z3Prover/z3 Z3> to
determine the satisfiability of a simple Boolean expression. It feeds
<http://smtlib.cs.uiowa.edu/language.shtml SMT-LIB v2>-format input to
Z3 and then parses the output (which uses a subset of Lisp-style
s-expressions) to display the satisfying assignment for the expression.
> 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 _ = []
This demonstrates how to run the parser with 'Text.Megaparsec.parse' and
'parseSExpr' as well as how to compose the s-expression parser with
other parsers to handle a composite format. It also shows how to
pattern-match on 'SExpr' to extract data from s-expressions.
-}
{-# OPTIONS_GHC -Wall -Werror #-}
module Text.SExpression
( -- * Parser context
Parser
, -- * S-expression values
SExpr(..)
, -- * S-expression parser
parseSExpr
, -- * Polymorphic default value
def
) where
import Data.Default (def)
import Text.SExpression.Internal (parseSExpr)
import Text.SExpression.Types (Parser, SExpr(..))