module SMT.Unsafe.Z3 where
open import Agda.Primitive using (Set)
open import Agda.Builtin.Bool using (Bool; true; false)
open import Agda.Builtin.List using (List; []; _∷_)
open import Agda.Builtin.Nat using (Nat; zero; suc)
import Agda.Builtin.Reflection as R
open import Agda.Builtin.Sigma using (Σ; _,_)
open import Agda.Builtin.String
using (String; primShowNat; primStringAppend; primStringEquality)
open import Agda.Builtin.Unit using (⊤)
open import SMT.Core using (Problem; Statement; counterexampleCheckSMT; counterexampleQuerySMT)
infixr 5 _++_
infixl 1 _>>=_
postulate
execTC : String → List String → String →
R.TC (Σ Nat (λ _ → Σ String (λ _ → String)))
{-# BUILTIN AGDATCMEXEC execTC #-}
_++_ : String → String → String
_++_ = primStringAppend
_>>=_ : ∀ {A B : Set} → R.TC A → (A → R.TC B) → R.TC B
_>>=_ = R.bindTC
return : ∀ {A : Set} → A → R.TC A
return = R.returnTC
vinfo : R.ArgInfo
vinfo = R.arg-info R.visible (R.modality R.relevant R.quantity-ω)
varg : ∀ {A : Set} → A → R.Arg A
varg = R.arg vinfo
z3Executable : String
z3Executable = "z3"
z3Args : List String
z3Args = "-in" ∷ "-smt2" ∷ []
failString : String → R.TC String
failString message = R.typeError (R.strErr message ∷ [])
showExit : Nat → String
showExit zero = "0"
showExit (suc n) = primShowNat (suc n)
runExecutable : String → List String → String → R.TC String
runExecutable exe args stdin =
execTC exe args stdin >>= λ where
(zero , (stdout , stderr)) → return stdout
(suc n , (stdout , stderr)) →
failString
( "external command failed with exit code " ++ showExit (suc n) ++
"\nstdout:\n" ++ stdout ++ "\nstderr:\n" ++ stderr
)
runZ3TC : String → R.TC String
runZ3TC script = runExecutable z3Executable z3Args script
z3VersionTC : R.TC String
z3VersionTC = runExecutable z3Executable ("--version" ∷ []) ""
fillStringTC : String → R.Term → R.TC ⊤
fillStringTC s hole = R.unify hole (R.lit (R.string s))
statementTypeTerm : R.Term → R.Term
statementTypeTerm p = R.def (quote Statement) (varg p ∷ [])
fillStatementTypeTC : ∀ {Γ} → Problem Γ → R.Term → R.TC ⊤
fillStatementTypeTC p hole =
R.quoteTC p >>= λ pTerm →
R.unify hole (statementTypeTerm pTerm)
checkedStatementResultTC : ∀ {Γ} → Problem Γ → R.Term → String → R.TC ⊤
checkedStatementResultTC p hole out with primStringEquality out "unsat\n"
... | true = fillStatementTypeTC p hole
... | false with primStringEquality out "sat\n"
... | true =
runZ3TC (counterexampleQuerySMT p) >>= λ model →
R.typeError
( R.strErr
( "Z3 found a counterexample; refusing to produce an assumption type.\n" ++
"Counterexample query output:\n" ++ model
)
∷ []
)
... | false =
R.typeError
( R.strErr
( "Z3 did not return a supported check-sat result; refusing to produce an assumption type.\n" ++
"Raw output:\n" ++ out
)
∷ []
)
checkedStatementTC : ∀ {Γ} → Problem Γ → R.Term → R.TC ⊤
checkedStatementTC p hole =
runZ3TC (counterexampleCheckSMT p) >>= checkedStatementResultTC p hole
macro
z3Version : R.Term → R.TC ⊤
z3Version hole =
z3VersionTC >>= λ out →
fillStringTC out hole
z3Run : String → R.Term → R.TC ⊤
z3Run script hole =
runZ3TC script >>= λ out →
fillStringTC out hole
z3CounterexampleQuery : ∀ {Γ} → Problem Γ → R.Term → R.TC ⊤
z3CounterexampleQuery p hole =
runZ3TC (counterexampleQuerySMT p) >>= λ out →
fillStringTC out hole
z3CounterexampleCheck : ∀ {Γ} → Problem Γ → R.Term → R.TC ⊤
z3CounterexampleCheck p hole =
runZ3TC (counterexampleCheckSMT p) >>= λ out →
fillStringTC out hole
z3CheckedStatement : ∀ {Γ} → Problem Γ → R.Term → R.TC ⊤
z3CheckedStatement = checkedStatementTC