--------------------------------------------------------------------------------
-- Schmitty the Solver
--
-- Defines the `cvc4` tactic, which runs an SMT-LIB script using CVC4, as well
-- as the `solveCVC4` tactic, which translates the goal term to an SMT-LIB
-- script and solves it using CVC4.
--------------------------------------------------------------------------------

{-# OPTIONS --allow-exec #-}

open import SMT.Theory

module SMT.Backend.CVC4 {theory : Theory} (reflectable : Reflectable theory) where

open import Data.List as List using (List; _∷_; [])
open import Data.Maybe as Maybe using (Maybe; just; nothing)
open import Data.Product using (_×_; _,_; proj₁; proj₂)
open import Data.String as String using (String; _++_)
open import Data.Sum as Sum using (_⊎_; inj₁; inj₂; [_,_])
open import Data.Unit as Unit using ()
open import Function using (case_of_; const; _$_; _∘_)
open import Reflection as Rfl using (return; _>>=_; _>>_)
open import Reflection.External
open import SMT.Script reflectable public
open import Text.Parser.String using (runParser)
open import SMT.Backend.Base
open Theory theory

private
  variable
    Γ : Ctxt
    ξ : OutputType
    Ξ : OutputCtxt

cvc4TC : Script [] Γ (ξ  Ξ)  Rfl.TC (Outputs (ξ  Ξ))
cvc4TC {Γ} {ξ} {Ξ} scr = do

  -- Print the SMT-LIB script and build the output parser.
  let (scr , parseOutputs) = showScript scr

  -- Construct the command specification.
  --
  -- TODO: Inspect the output type to see if any models should be produced,
  --       and set the --produce-models flag accordingly.
  --
  let cvc4Cmd = record
                { name  = "cvc4"
                ; args  = "--lang=smt2"  "--output-lang=smt2"  "--produce-models"  "-q"  "-"  []
                ; input = scr
                }

  -- Run the CVC4 command and parse the output.
  result exitCode stdout stderr  unsafeRunCmdTC cvc4Cmd
  case runParser parseOutputs stdout of λ where
    (inj₁ parserr)  parseError stdout parserr (showCmdSpec cvc4Cmd) scr
    (inj₂ outputs)  return outputs

macro
  cvc4 : Script [] Γ (ξ  Ξ)  Rfl.Term  Rfl.TC 
  cvc4 scr hole = cvc4TC scr >>= Rfl.unify hole  quoteOutputs

macro
  solveCVC4 : Rfl.Term  Rfl.TC 
  solveCVC4 = solve "cvc4" cvc4TC
    where
      open Solver reflectable using (solve)