packages feed

language-smtlib-0.2.0.0: src/Language/SMTLIB/Parser/Response.hs

-- | Parsers for solver command responses.
--
-- Many responses share the @( ... )@ shape, so they cannot be told apart
-- without knowing which command they answer.  This module therefore exposes a
-- per-response parser for each command, plus 'pCommandResponse' for the
-- context-free responses (@success@, @unsupported@, @sat@\/@unsat@\/@unknown@
-- and @(error ...)@).
module Language.SMTLIB.Parser.Response
  ( -- * Combinators
    pCommandResponse
  , pGeneralResponse
  , pCheckSatResponse
  , pGetValueResponse
  , pGetModelResponse
  , pGetAssignmentResponse
  , pGetUnsatCoreResponse
  , pGetUnsatAssumptionsResponse
  , pGetAssertionsResponse
  , pGetInfoResponse
  , pGetProofResponse
  , pGetOptionResponse
  , pInfoResponse
  , pValuationPair
  , pModelResponse
  ) where

import Data.Functor (($>))
import Text.Megaparsec

import Language.SMTLIB.Parser.Internal
import Language.SMTLIB.Parser.Term (pFunctionDec, pFunctionDef, pTerm)
import Language.SMTLIB.Syntax.Annotation (SrcSpan)
import Language.SMTLIB.Syntax.Attribute (AttributeValue, SExpr)
import Language.SMTLIB.Syntax.Constant (Symbol)
import Language.SMTLIB.Syntax.Response
import Language.SMTLIB.Syntax.Term (Term)

-- | The context-free responses (@success@, @unsupported@, the @check-sat@
-- answers, and @(error ...)@).  Use the specific parsers below for
-- list-shaped responses.
--
-- Any other syntactically well-formed s-expression — a solver's non-standard or
-- extension output — is kept as
-- 'Language.SMTLIB.Syntax.Response.ROther' rather than rejected, leaving the
-- application to decide what to do with it.
pCommandResponse :: P (CommandResponse SrcSpan)
pCommandResponse = choice
  [ tok "success"     $> RSuccess
  , tok "unsupported" $> RUnsupported
  , tok "sat"         $> RCheckSat Sat
  , tok "unsat"       $> RCheckSat Unsat
  , tok "unknown"     $> RCheckSat Unknown
  , try (parens (tok "error" *> (RError <$> pStringLit)))
  , ROther <$> pSExpr
  ]

-- | @success | unsupported | (error string)@.
pGeneralResponse :: P (CommandResponse SrcSpan)
pGeneralResponse = choice
  [ tok "success"     $> RSuccess
  , tok "unsupported" $> RUnsupported
  , parens (tok "error" *> (RError <$> pStringLit))
  ]

-- | @sat | unsat | unknown@.
pCheckSatResponse :: P CheckSatResponse
pCheckSatResponse = choice
  [ tok "sat"     $> Sat
  , tok "unsat"   $> Unsat
  , tok "unknown" $> Unknown
  ]

-- | @( (term value)+ )@.
pGetValueResponse :: P [ValuationPair SrcSpan]
pGetValueResponse = parens (some pValuationPair)

-- | A @(term value)@ pair.
pValuationPair :: P (ValuationPair SrcSpan)
pValuationPair = parens (ValuationPair <$> pTerm <*> pTerm)

-- | @( model_response* )@, tolerating a legacy leading @model@ keyword.
pGetModelResponse :: P [ModelResponse SrcSpan]
pGetModelResponse = parens (optional (tok "model") *> many pModelResponse)

-- | A single @model_response@ definition (@define-fun@\/@-rec@\/@-funs-rec@).
pModelResponse :: P (ModelResponse SrcSpan)
pModelResponse = parens $ choice
  [ tok "define-fun-rec"  *> (MRDefineFunRec <$> pFunctionDef)
  , tok "define-funs-rec" *> (MRDefineFunsRec <$> parens (some pFunctionDec)
                                              <*> parens (some pTerm))
  , tok "define-fun"      *> (MRDefineFun <$> pFunctionDef)
  ]

-- | @( (symbol b_value)* )@.
pGetAssignmentResponse :: P [(Symbol, Bool)]
pGetAssignmentResponse = parens (many (parens ((,) <$> pSymbolRaw <*> pBool)))

-- | @( symbol* )@.
pGetUnsatCoreResponse :: P [Symbol]
pGetUnsatCoreResponse = parens (many pSymbolRaw)

-- | @( term* )@ (SMT-LIB 2.7 generalised assumptions: arbitrary Bool terms).
pGetUnsatAssumptionsResponse :: P [Term SrcSpan]
pGetUnsatAssumptionsResponse = parens (many pTerm)

-- | @( term* )@.
pGetAssertionsResponse :: P [Term SrcSpan]
pGetAssertionsResponse = parens (many pTerm)

-- | @( info_response+ )@.
pGetInfoResponse :: P [InfoResponse SrcSpan]
pGetInfoResponse = parens (some pInfoResponse)

-- | A single @info_response@ entry.
pInfoResponse :: P (InfoResponse SrcSpan)
pInfoResponse = choice
  [ tok ":assertion-stack-levels" *> (IRAssertionStackLevels <$> numeral)
  , tok ":authors"        *> (IRAuthors <$> pStringLit)
  , tok ":error-behavior" *> (IRErrorBehavior <$> pErrorBehavior)
  , tok ":name"           *> (IRName <$> pStringLit)
  , tok ":reason-unknown" *> (IRReasonUnknown <$> pReasonUnknown)
  , tok ":version"        *> (IRVersion <$> pStringLit)
  , IRAttribute <$> pAttribute
  ]

pErrorBehavior :: P ErrorBehavior
pErrorBehavior = choice
  [ tok "immediate-exit"      $> ImmediateExit
  , tok "continued-execution" $> ContinuedExecution
  ]

pReasonUnknown :: P (ReasonUnknown SrcSpan)
pReasonUnknown = choice
  [ tok "memout"     $> RUMemout
  , tok "incomplete" $> RUIncomplete
  , RUOther <$> pSExpr
  ]

-- | A single @s_expr@.
pGetProofResponse :: P (SExpr SrcSpan)
pGetProofResponse = pSExpr

-- | An @attribute_value@.
pGetOptionResponse :: P (AttributeValue SrcSpan)
pGetOptionResponse = pAttributeValue