use std::fs::File;
use std::io::{BufReader, BufWriter, Read, Write};
use std::process::{Child, ChildStdin, ChildStdout, Command, Stdio};
use crate::{actlit::Actlit, parse::*, prelude::*, print::*};
pub struct FutureCheckSat {
_nothing: (),
}
fn future_check_sat() -> FutureCheckSat {
FutureCheckSat { _nothing: () }
}
pub struct Solver<Parser> {
conf: SmtConf,
kid: Child,
stdin: BufWriter<ChildStdin>,
tee: Option<BufWriter<File>>,
smt_parser: RSmtParser,
parser: Parser,
actlit: usize,
check_success: bool,
}
impl<Parser> Write for Solver<Parser> {
fn write(&mut self, buf: &[u8]) -> std::io::Result<usize> {
if let Some(tee) = self.tee.as_mut() {
let _ = tee.write(buf);
}
self.stdin.write(buf)
}
fn flush(&mut self) -> ::std::io::Result<()> {
if let Some(tee) = self.tee.as_mut() {
let _ = tee.flush();
}
self.stdin.flush()
}
}
impl<Parser> Read for Solver<Parser> {
fn read(&mut self, buf: &mut [u8]) -> std::io::Result<usize> {
self.smt_parser.read(buf)
}
}
macro_rules! tee_write {
($slf:expr, no_check |$w:ident| $($tail:tt)*) => ({
if let Some(ref mut $w) = $slf.tee {
$($tail)*;
writeln!($w)?;
$w.flush() ?
}
let $w = & mut $slf.stdin;
$($tail)*;
$w.flush()?;
});
($slf:expr, |$w:ident| $($tail:tt)*) => ({
tee_write! { $slf, no_check |$w| $($tail)* }
if $slf.check_success {
$slf.check_success()?
}
});
}
impl<Parser> ::std::ops::Drop for Solver<Parser> {
fn drop(&mut self) {
let _ = self.kill();
()
}
}
impl<Parser> Solver<Parser> {
fn spawn(conf: &SmtConf) -> SmtRes<(Child, BufWriter<ChildStdin>, BufReader<ChildStdout>)> {
let mut kid = Command::new(
conf.get_cmd(),
)
.args(
conf.get_options(),
)
.stdin(Stdio::piped())
.stdout(Stdio::piped())
.stderr(Stdio::piped())
.spawn()
.chain_err::<_, ErrorKind>(|| {
format!(
"While spawning child process with {}",
conf.get_cmd().to_string()
)
.into()
})?;
let mut stdin_opt = None;
::std::mem::swap(&mut stdin_opt, &mut kid.stdin);
let stdin = if let Some(inner) = stdin_opt {
BufWriter::new(inner)
} else {
bail!("could not retrieve solver's stdin")
};
let mut stdout_opt = None;
::std::mem::swap(&mut stdout_opt, &mut kid.stdout);
let stdout = if let Some(inner) = stdout_opt {
BufReader::new(inner)
} else {
bail!("could not retrieve solver's stdout")
};
Ok((kid, stdin, stdout))
}
pub fn new(conf: SmtConf, parser: Parser) -> SmtRes<Self> {
let (kid, stdin, stdout) = Self::spawn(&conf)?;
let smt_parser = RSmtParser::new(stdout);
let tee = None;
let actlit = 0;
let mut slf = Solver {
kid,
stdin,
tee,
conf,
smt_parser,
parser,
actlit,
check_success: false,
};
if slf.conf.get_check_success() {
slf.print_success()?;
}
if slf.conf.get_models() {
slf.produce_models()?;
}
if slf.conf.get_unsat_cores() {
slf.produce_unsat_cores()?;
}
Ok(slf)
}
pub fn z3(parser: Parser, cmd: impl Into<String>) -> SmtRes<Self> {
Self::new(SmtConf::z3(cmd), parser)
}
pub fn cvc4(parser: Parser, cmd: impl Into<String>) -> SmtRes<Self> {
Self::new(SmtConf::cvc4(cmd), parser)
}
pub fn yices_2(parser: Parser, cmd: impl Into<String>) -> SmtRes<Self> {
Self::new(SmtConf::yices_2(cmd), parser)
}
pub fn default_z3(parser: Parser) -> SmtRes<Self> {
Self::new(SmtConf::default_z3(), parser)
}
pub fn default_cvc4(parser: Parser) -> SmtRes<Self> {
Self::new(SmtConf::default_cvc4(), parser)
}
pub fn default_yices_2(parser: Parser) -> SmtRes<Self> {
Self::new(SmtConf::default_yices_2(), parser)
}
pub fn conf(&self) -> &SmtConf {
&self.conf
}
pub fn tee(&mut self, file: File) -> SmtRes<()> {
if self.tee.is_some() {
bail!("Trying to tee a solver that's already tee-ed")
}
let mut tee = BufWriter::with_capacity(1000, file);
write!(tee, "; Command:\n; > {}", self.conf.get_cmd())?;
for option in self.conf.get_options() {
write!(tee, " {}", option)?
}
writeln!(tee, "\n")?;
self.tee = Some(tee);
Ok(())
}
pub fn path_tee<P>(&mut self, path: P) -> SmtRes<()>
where
P: AsRef<::std::path::Path>,
{
use std::fs::OpenOptions;
let path: &::std::path::Path = path.as_ref();
let file = OpenOptions::new()
.create(true)
.write(true)
.truncate(true)
.open(path)
.chain_err(|| format!("while opening tee file `{}`", path.to_string_lossy()))?;
self.tee(file)
}
pub fn is_teed(&self) -> bool {
self.tee.is_some()
}
#[cfg(windows)]
pub fn kill(&mut self) -> SmtRes<()> {
let _ = writeln!(self.stdin, "(exit)");
let _ = self.stdin.flush();
let _ = self.kid.kill();
Ok(())
}
#[cfg(not(windows))]
pub fn kill(&mut self) -> SmtRes<()> {
let _ = writeln!(self.stdin, "(exit)");
let _ = self.stdin.flush();
let _ = self.kid.kill();
let wait_time = std::time::Duration::from_millis(10);
for _ in 0..100 {
let join = self
.kid
.try_wait()
.chain_err(|| "waiting for child process to exit")?;
if join.is_some() {
return Ok(());
}
std::thread::sleep(wait_time);
}
bail!("failed to wait for child process to properly terminate")
}
#[inline]
fn cmt(file: &mut BufWriter<File>, blah: &str) -> SmtRes<()> {
for line in blah.lines() {
writeln!(file, "; {}", line)?
}
file.flush()?;
Ok(())
}
#[inline]
pub fn comment_args(&mut self, args: std::fmt::Arguments) -> SmtRes<()> {
if let Some(ref mut file) = self.tee {
Self::cmt(file, &format!("{}", args))?
}
Ok(())
}
#[inline]
pub fn comment(&mut self, blah: &str) -> SmtRes<()> {
if let Some(ref mut file) = self.tee {
Self::cmt(file, blah)?
}
Ok(())
}
}
impl<Parser> Solver<Parser> {
#[inline]
pub fn print_success(&mut self) -> SmtRes<()> {
self.check_success = true;
self.set_option(":print-success", "true")
}
#[inline]
pub fn check_success(&mut self) -> SmtRes<()> {
self.smt_parser.success()
}
#[inline]
pub fn produce_unsat_cores(&mut self) -> SmtRes<()> {
self.set_option(":produce-unsat-cores", "true")
}
#[inline]
pub fn produce_models(&mut self) -> SmtRes<()> {
self.set_option(":produce-models", "true")
}
#[inline]
pub fn assert(&mut self, expr: impl Expr2Smt) -> SmtRes<()> {
self.assert_with(expr, ())
}
pub fn check_sat(&mut self) -> SmtRes<bool> {
let future = self.print_check_sat()?;
self.parse_check_sat(future)
}
pub fn check_sat_or_unk(&mut self) -> SmtRes<Option<bool>> {
let future = self.print_check_sat()?;
self.parse_check_sat_or_unk(future)
}
#[inline]
pub fn reset(&mut self) -> SmtRes<()> {
self.actlit = 0;
tee_write! {
self, |w| write_str(w, "(reset)\n") ?
}
Ok(())
}
#[inline]
pub fn declare_const(&mut self, symbol: impl Sym2Smt, out_sort: impl Sort2Smt) -> SmtRes<()> {
self.declare_const_with(symbol, out_sort, ())
}
#[inline]
pub fn declare_fun<FunSym, Args, OutSort>(
&mut self,
symbol: FunSym,
args: Args,
out: OutSort,
) -> SmtRes<()>
where
FunSym: Sym2Smt<()>,
OutSort: Sort2Smt,
Args: IntoIterator,
Args::Item: Sort2Smt,
{
self.declare_fun_with(symbol, args, out, ())
}
#[inline]
pub fn define_const(
&mut self,
symbol: impl Sym2Smt,
out: impl Sort2Smt,
body: impl Expr2Smt,
) -> SmtRes<()> {
self.define_const_with(symbol, out, body, ())
}
#[inline]
pub fn define_fun<Args>(
&mut self,
symbol: impl Sym2Smt,
args: Args,
out: impl Sort2Smt,
body: impl Expr2Smt,
) -> SmtRes<()>
where
Args: IntoIterator,
Args::Item: SymAndSort,
{
self.define_fun_with(symbol, args, out, body, ())
}
#[inline]
pub fn push(&mut self, n: u8) -> SmtRes<()> {
tee_write! {
self, |w| writeln!(w, "(push {})", n) ?
}
Ok(())
}
#[inline]
pub fn pop(&mut self, n: u8) -> SmtRes<()> {
tee_write! {
self, |w| writeln!(w, "(pop {})", n) ?
}
Ok(())
}
pub fn check_sat_assuming<Idents>(&mut self, idents: Idents) -> SmtRes<bool>
where
Idents: IntoIterator,
Idents::Item: Sym2Smt,
{
self.check_sat_assuming_with(idents, ())
}
pub fn check_sat_assuming_or_unk<Ident, Idents>(
&mut self,
idents: Idents,
) -> SmtRes<Option<bool>>
where
Idents: IntoIterator,
Idents::Item: Sym2Smt,
{
self.check_sat_assuming_or_unk_with(idents, ())
}
#[inline]
pub fn set_logic(&mut self, logic: Logic) -> SmtRes<()> {
tee_write! {
self, |w| {
write_str(w, "(set-logic ")?;
logic.to_smt2(w, ())?;
write_str(w, ")\n") ?
}
}
Ok(())
}
#[inline]
pub fn set_custom_logic(&mut self, logic: impl AsRef<str>) -> SmtRes<()> {
tee_write! {
self, |w| {
write_str(w, "(set-logic ")?;
write_str(w, logic.as_ref())?;
write_str(w, ")\n") ?
}
}
Ok(())
}
#[inline]
pub fn define_fun_rec<Args>(
&mut self,
symbol: impl Sym2Smt,
args: Args,
out: impl Sort2Smt,
body: impl Expr2Smt,
) -> SmtRes<()>
where
Args: IntoIterator,
Args::Item: SymAndSort,
{
self.define_fun_rec_with(symbol, args, out, body, ())
}
#[inline]
pub fn define_funs_rec<Defs>(&mut self, funs: Defs) -> SmtRes<()>
where
Defs: IntoIterator + Clone,
Defs::Item: FunDef,
{
self.define_funs_rec_with(funs, ())
}
pub fn declare_datatypes<Defs>(&mut self, defs: Defs) -> SmtRes<()>
where
Defs: IntoIterator + Clone,
Defs::Item: AdtDecl,
{
tee_write! {
self, no_check |w| write!(w, "(declare-datatypes (") ?
}
for def in defs.clone() {
let sort_sym = def.adt_sym();
let arity = def.arity();
tee_write! {
self, no_check |w| {
write!(w, " (")?;
sort_sym.sym_to_smt2(w, ())?;
write!(w, " {})", arity) ?
}
}
}
tee_write! {
self, no_check |w| write!(w, " ) (") ?
}
for def in defs {
let arity = def.arity();
let args = def.adt_sort_args();
let variants = def.adt_variants();
tee_write! { self, |w| write!(w, " (")? };
if arity > 0 {
tee_write! { self, no_check |w| write!(w, "par (")? };
for param in args {
tee_write! { self, no_check |w| {
write!(w, " ")?;
param.sym_to_smt2(w, ())?;
}}
}
tee_write! { self, no_check |w| write!(w, " ) (")? };
}
for variant in variants {
let sym = variant.sym();
let mut fields = variant.fields();
let first_field = fields.next();
tee_write! { self, no_check |w| write!(w, " ")? };
if first_field.is_some() {
tee_write! { self, no_check |w| write!(w, "(")? };
}
tee_write! { self, no_check |w| sym.sym_to_smt2(w, ())? };
if let Some(first) = first_field {
for field in Some(first).into_iter().chain(fields) {
let sym = field.field_sym();
let sort = field.field_sort();
tee_write! {
self, no_check |w| {
write!(w, " (")?;
sym.sym_to_smt2(w, ())?;
write!(w, " ")?;
sort.sort_to_smt2(w)?;
write!(w, ")")?;
}
}
}
tee_write! { self, no_check |w| write!(w, ")")? };
}
}
tee_write! {
self, no_check |w| {
write!(w, " )")?;
if arity > 0 {
write!(w, " )") ?
}
}
}
}
tee_write! {
self, |w| writeln!(w, " ) )") ?
}
Ok(())
}
}
impl<Parser> Solver<Parser> {
pub fn get_model<Ident, Type, Value>(&mut self) -> SmtRes<Model<Ident, Type, Value>>
where
Parser: for<'p> IdentParser<Ident, Type, &'p mut RSmtParser>
+ for<'p> ModelParser<Ident, Type, Value, &'p mut RSmtParser>,
{
self.print_get_model()?;
self.parse_get_model()
}
pub fn get_model_const<Ident, Type, Value>(&mut self) -> SmtRes<Vec<(Ident, Type, Value)>>
where
Parser: for<'p> IdentParser<Ident, Type, &'p mut RSmtParser>
+ for<'p> ModelParser<Ident, Type, Value, &'p mut RSmtParser>,
{
self.print_get_model()?;
self.parse_get_model_const()
}
pub fn get_values<Exprs, PExpr, PValue>(&mut self, exprs: Exprs) -> SmtRes<Vec<(PExpr, PValue)>>
where
Parser: for<'p> ExprParser<PExpr, (), &'p mut RSmtParser>
+ for<'p> ValueParser<PValue, &'p mut RSmtParser>,
Exprs: IntoIterator,
Exprs::Item: Expr2Smt,
{
self.get_values_with(exprs, ())
.map_err(|e| self.conf.enrich_get_values_error(e))
}
pub fn get_values_with<Exprs, PExpr, PValue, Info>(
&mut self,
exprs: Exprs,
info: Info,
) -> SmtRes<Vec<(PExpr, PValue)>>
where
Info: Copy,
Parser: for<'p> ExprParser<PExpr, Info, &'p mut RSmtParser>
+ for<'p> ValueParser<PValue, &'p mut RSmtParser>,
Exprs: IntoIterator,
Exprs::Item: Expr2Smt<Info>,
{
self.print_get_values_with(exprs, info)?;
self.parse_get_values_with(info)
}
pub fn get_unsat_core<Sym>(&mut self) -> SmtRes<Vec<Sym>>
where
Parser: for<'p> SymParser<Sym, &'p mut RSmtParser>,
{
self.print_get_unsat_core()?;
self.parse_get_unsat_core()
}
pub fn get_interpolant<Expr>(
&mut self,
sym_1: impl Sym2Smt,
sym_2: impl Sym2Smt,
) -> SmtRes<Expr>
where
Parser: for<'p> ExprParser<Expr, (), &'p mut RSmtParser>,
{
self.get_interpolant_with(sym_1, sym_2, ())
}
pub fn get_interpolant_with<Info, Expr>(
&mut self,
sym_1: impl Sym2Smt,
sym_2: impl Sym2Smt,
info: Info,
) -> SmtRes<Expr>
where
Parser: for<'p> ExprParser<Expr, Info, &'p mut RSmtParser>,
{
self.print_get_interpolant(sym_1, sym_2)?;
let res = self.parse_get_interpolant(info);
if res.is_err() && self.conf.style().is_z3() {
res.chain_err(|| {
format!(
"`get-interpolant` is not legal for {} solvers",
self.conf.style()
)
})
.chain_err(|| format!("only Z3 supports `get-interpolant`"))
} else {
res
}
}
}
impl<Parser> Solver<Parser> {
#[inline]
fn has_actlits(&self) -> bool {
self.actlit > 0
}
#[inline]
pub fn get_actlit(&mut self) -> SmtRes<crate::actlit::Actlit> {
let id = self.actlit;
self.actlit += 1;
let next_actlit = crate::actlit::Actlit::new(id);
tee_write! {
self, |w|
write!(w, "(declare-fun ")?;
next_actlit.write(w)?;
writeln!(w, " () Bool)")?
}
Ok(next_actlit)
}
#[inline]
pub fn de_actlit(&mut self, actlit: Actlit) -> SmtRes<()> {
self.set_actlit(actlit, false)
}
#[inline]
pub fn set_actlit(&mut self, actlit: Actlit, b: bool) -> SmtRes<()> {
tee_write! {
self, |w| {
if b {
write!(w, "(assert ") ?
} else {
write!(w, "(assert (not ") ?
}
actlit.write(w)?;
if b {
writeln!(w, ")") ?
} else {
writeln!(w, ") )") ?
}
}
}
::std::mem::drop(actlit);
Ok(())
}
#[inline]
pub fn assert_act(&mut self, actlit: &Actlit, expr: impl Expr2Smt) -> SmtRes<()> {
self.assert_act_with(actlit, expr, ())
}
pub fn check_sat_act<Actlits>(&mut self, actlits: Actlits) -> SmtRes<bool>
where
Actlits: IntoIterator,
Actlits::Item: Sym2Smt,
{
let future = self.print_check_sat_act(actlits)?;
self.parse_check_sat(future)
}
pub fn check_sat_act_or_unk<Actlits>(&mut self, actlits: Actlits) -> SmtRes<Option<bool>>
where
Actlits: IntoIterator,
Actlits::Item: Sym2Smt,
{
let future = self.print_check_sat_act(actlits)?;
self.parse_check_sat_or_unk(future)
}
}
impl<Parser> Solver<Parser> {
#[inline]
pub fn print_check_sat(&mut self) -> SmtRes<FutureCheckSat> {
tee_write! {
self, no_check |w| write_str(w, "(check-sat)\n") ?
}
Ok(future_check_sat())
}
#[inline]
pub fn print_check_sat_act<Actlits>(&mut self, actlits: Actlits) -> SmtRes<FutureCheckSat>
where
Actlits: IntoIterator,
Actlits::Item: Sym2Smt,
{
match self.conf.get_check_sat_assuming() {
Some(ref cmd) => {
tee_write! {
self, no_check |w| write!(w, "({} (", cmd) ?
}
for actlit in actlits {
tee_write! {
self, no_check |w| {
write!(w, " ")?;
actlit.sym_to_smt2(w, ()) ?
}
}
}
tee_write! {
self, |w| write_str(w, ") )\n") ?
}
Ok(future_check_sat())
}
None => {
let msg = format!("{} does not support check-sat-assuming", self.conf.desc());
Err(msg.into())
}
}
}
#[inline]
pub fn parse_check_sat(&mut self, _: FutureCheckSat) -> SmtRes<bool> {
if let Some(res) = self.smt_parser.check_sat()? {
Ok(res)
} else {
Err(ErrorKind::Unknown.into())
}
}
#[inline]
pub fn parse_check_sat_or_unk(&mut self, _: FutureCheckSat) -> SmtRes<Option<bool>> {
self.smt_parser.check_sat()
}
#[inline]
pub fn print_get_interpolant(
&mut self,
sym_1: impl Sym2Smt<()>,
sym_2: impl Sym2Smt<()>,
) -> SmtRes<()> {
tee_write! {
self, no_check |w|
write_str(w, "(get-interpolant ")?;
sym_1.sym_to_smt2(w, ())?;
write_str(w, " ")?;
sym_2.sym_to_smt2(w, ())?;
write_str(w, ")\n")?
}
Ok(())
}
#[inline]
fn print_get_model(&mut self) -> SmtRes<()> {
tee_write! {
self, no_check |w| write_str(w, "(get-model)\n") ?
}
Ok(())
}
#[allow(dead_code)]
fn print_get_assertions(&mut self) -> SmtRes<()> {
tee_write! {
self, no_check |w| write_str(w, "(get-assertions)\n") ?
}
Ok(())
}
#[allow(dead_code)]
fn print_get_assignment(&mut self) -> SmtRes<()> {
tee_write! {
self, no_check |w| write_str(w, "(get-assignment)\n") ?
}
Ok(())
}
#[allow(dead_code)]
fn print_get_unsat_assumptions(&mut self) -> SmtRes<()> {
tee_write! {
self, no_check |w| write_str(w, "(get-unsat-assumptions)\n") ?
}
Ok(())
}
#[allow(dead_code)]
fn print_get_proof(&mut self) -> SmtRes<()> {
tee_write! {
self, no_check |w| write_str(w, "(get-proof)\n") ?
}
Ok(())
}
#[allow(dead_code)]
fn print_get_unsat_core(&mut self) -> SmtRes<()> {
tee_write! {
self, no_check |w| write_str(w, "(get-unsat-core)\n") ?
}
Ok(())
}
fn print_get_values_with<Exprs, Info>(&mut self, exprs: Exprs, info: Info) -> SmtRes<()>
where
Info: Copy,
Exprs: IntoIterator,
Exprs::Item: Expr2Smt<Info>,
{
tee_write! {
self, no_check |w| write!(w, "(get-value (") ?
}
for e in exprs {
tee_write! {
self, no_check |w| {
write_str(w, "\n ")?;
e.expr_to_smt2(w, info) ?
}
}
}
tee_write! {
self, no_check |w| write_str(w, "\n) )\n") ?
}
Ok(())
}
pub fn print_check_sat_assuming<Idents>(&mut self, bool_vars: Idents) -> SmtRes<FutureCheckSat>
where
Idents: IntoIterator,
Idents::Item: Sym2Smt,
{
self.print_check_sat_assuming_with(bool_vars, ())
}
pub fn print_check_sat_assuming_with<Idents, Info>(
&mut self,
bool_vars: Idents,
info: Info,
) -> SmtRes<FutureCheckSat>
where
Info: Copy,
Idents: IntoIterator,
Idents::Item: Sym2Smt<Info>,
{
match self.conf.get_check_sat_assuming() {
Some(ref cmd) => {
tee_write! {
self, no_check |w| write!(w, "({} (\n ", cmd) ?
}
for sym in bool_vars {
tee_write! {
self, no_check |w| {
write_str(w, " ")?;
sym.sym_to_smt2(w, info) ?
}
}
}
tee_write! {
self, no_check |w| write_str(w, "\n))\n") ?
}
Ok(future_check_sat())
}
None => {
let msg = format!("{} does not support check-sat-assuming", self.conf.desc());
Err(msg.into())
}
}
}
fn parse_get_model<Ident, Type, Value>(&mut self) -> SmtRes<Model<Ident, Type, Value>>
where
Parser: for<'p> IdentParser<Ident, Type, &'p mut RSmtParser>
+ for<'p> ModelParser<Ident, Type, Value, &'p mut RSmtParser>,
{
let has_actlits = self.has_actlits();
let res = self.smt_parser.get_model(has_actlits, self.parser);
if res.is_err() && !self.conf.get_models() {
res.chain_err(|| {
"\
Note: model production is not active \
for this SmtConf, see [`SmtConf::models`]\
"
})
} else {
res
}
}
fn parse_get_unsat_core<Sym>(&mut self) -> SmtRes<Vec<Sym>>
where
Parser: for<'p> SymParser<Sym, &'p mut RSmtParser>,
{
self.smt_parser.get_unsat_core(self.parser)
}
fn parse_get_model_const<Ident, Type, Value>(&mut self) -> SmtRes<Vec<(Ident, Type, Value)>>
where
Parser: for<'p> IdentParser<Ident, Type, &'p mut RSmtParser>
+ for<'p> ModelParser<Ident, Type, Value, &'p mut RSmtParser>,
{
let has_actlits = self.has_actlits();
let res = self.smt_parser.get_model_const(has_actlits, self.parser);
if res.is_err() && !self.conf.get_models() {
res.chain_err(|| {
"\
Note: model production is not active \
for this SmtConf (`conf.models()`)\
"
})
} else {
res
}
}
fn parse_get_values_with<Info, Expr, Val>(&mut self, info: Info) -> SmtRes<Vec<(Expr, Val)>>
where
Info: Copy,
Parser: for<'p> ExprParser<Expr, Info, &'p mut RSmtParser>
+ for<'p> ValueParser<Val, &'p mut RSmtParser>,
{
let res = self.smt_parser.get_values(self.parser, info);
if res.is_err() && !self.conf.get_models() {
res.chain_err(|| {
"Note: model production is not active \
for this SmtConf (`conf.models()`)"
})
} else {
res
}
}
fn parse_get_interpolant<Expr, Info>(&mut self, info: Info) -> SmtRes<Expr>
where
Parser: for<'p> ExprParser<Expr, Info, &'p mut RSmtParser>,
{
let mut res = self.smt_parser.get_interpolant(self.parser, info);
if res.is_err() {
if !self.conf.style().is_z3() {
res = res.chain_err(|| {
format!(
"`{}` does not support interpolant production, only Z3 does",
self.conf.style()
)
})
} else if !self.conf.get_interpolants() {
res = res.chain_err(|| format!("interpolant production is not active"))
}
}
res
}
}
impl<Parser: Send + 'static> Solver<Parser> {
pub unsafe fn async_check_sat_or_unk(&mut self) -> crate::asynch::CheckSatFuture<Parser> {
crate::asynch::CheckSatFuture::new(self)
}
}
impl<Parser> Solver<Parser> {
#[inline]
pub fn declare_sort(&mut self, sort: impl Sort2Smt, arity: u8) -> SmtRes<()> {
tee_write! {
self, |w| {
write_str(w, "(declare-sort ")?;
sort.sort_to_smt2(w)?;
writeln!(w, " {})", arity) ?
}
}
Ok(())
}
#[inline]
pub fn define_sort<Args>(
&mut self,
sort_sym: impl Sym2Smt,
args: Args,
body: impl Sort2Smt,
) -> SmtRes<()>
where
Args: IntoIterator,
Args::Item: Sort2Smt,
{
tee_write! {
self, no_check |w| {
write_str(w, "( define-sort ")?;
sort_sym.sym_to_smt2(w, ())?;
write_str(w, "\n ( ")?;
}
}
for arg in args {
tee_write! {
self, no_check |w| {
arg.sort_to_smt2(w)?;
write_str(w, " ") ?
}
}
}
tee_write! {
self, |w| {
write_str(w, ")\n ")?;
body.sort_to_smt2(w)?;
write_str(w, "\n)\n") ?
}
}
Ok(())
}
#[inline]
pub fn define_null_sort(&mut self, sym: impl Sym2Smt, body: impl Sort2Smt) -> SmtRes<()> {
self.define_sort(sym, None as Option<&str>, body)
}
}
impl<Parser> Solver<Parser> {
#[inline]
pub fn declare_const_with<Info>(
&mut self,
symbol: impl Sym2Smt<Info>,
out_sort: impl Sort2Smt,
info: Info,
) -> SmtRes<()>
where
Info: Copy,
{
tee_write! {
self, |w| {
write_str(w, "(declare-const ")?;
symbol.sym_to_smt2(w, info)?;
write_str(w, " ")?;
out_sort.sort_to_smt2(w)?;
write_str(w, ")\n") ?
}
}
Ok(())
}
#[inline]
pub fn declare_fun_with<Args, Info>(
&mut self,
symbol: impl Sym2Smt<Info>,
args: Args,
out: impl Sort2Smt,
info: Info,
) -> SmtRes<()>
where
Info: Copy,
Args: IntoIterator,
Args::Item: Sort2Smt,
{
tee_write! {
self, no_check |w| {
write_str(w, "(declare-fun ")?;
symbol.sym_to_smt2(w, info)?;
write_str(w, " ( ") ?
}
}
for arg in args {
tee_write! {
self, no_check |w| {
arg.sort_to_smt2(w)?;
write_str(w, " ") ?
}
}
}
tee_write! {
self, |w| {
write_str(w, ") ")?;
out.sort_to_smt2(w)?;
write_str(w, ")\n") ?
}
}
Ok(())
}
#[inline]
pub fn define_const_with<Info>(
&mut self,
symbol: impl Sym2Smt<Info>,
out_sort: impl Sort2Smt,
body: impl Expr2Smt<Info>,
info: Info,
) -> SmtRes<()>
where
Info: Copy,
{
tee_write! {
self, |w| {
write_str(w, "(define-const ")?;
symbol.sym_to_smt2(w, info)?;
write_str(w, " ")?;
out_sort.sort_to_smt2(w)?;
write_str(w, " ")?;
body.expr_to_smt2(w, info)?;
write_str(w, ")\n") ?
}
}
Ok(())
}
#[inline]
pub fn define_fun_with<Args, Info>(
&mut self,
symbol: impl Sym2Smt<Info>,
args: Args,
out: impl Sort2Smt,
body: impl Expr2Smt<Info>,
info: Info,
) -> SmtRes<()>
where
Info: Copy,
Args: IntoIterator,
Args::Item: SymAndSort<Info>,
{
tee_write! {
self, no_check |w| {
write_str(w, "(define-fun ")?;
symbol.sym_to_smt2(w, info)?;
write_str(w, " ( ") ?
}
}
for arg in args {
let sym = arg.sym();
let sort = arg.sort();
tee_write! {
self, no_check |w| {
write_str(w, "(")?;
sym.sym_to_smt2(w, info)?;
write_str(w, " ")?;
sort.sort_to_smt2(w)?;
write_str(w, ") ") ?
}
}
}
tee_write! {
self, |w| {
write_str(w, ") ")?;
out.sort_to_smt2(w)?;
write_str(w, "\n ")?;
body.expr_to_smt2(w, info)?;
write_str(w, "\n)\n") ?
}
}
Ok(())
}
pub fn define_funs_rec_with<Defs, Info>(&mut self, funs: Defs, info: Info) -> SmtRes<()>
where
Info: Copy,
Defs: IntoIterator + Clone,
Defs::Item: FunDef<Info>,
{
tee_write! {
self, no_check |w| write_str(w, "(define-funs-rec (\n") ?
}
for fun in funs.clone() {
let sym = fun.fun_sym();
let args = fun.args();
let out = fun.out_sort();
tee_write! {
self, no_check |w| {
write_str(w, " (")?;
sym.sym_to_smt2(w, info)?;
write_str(w, " ( ") ?
}
}
for arg in args {
tee_write! {
self, no_check |w| {
let sym = arg.sym();
let sort = arg.sort();
write_str(w, "(")?;
sym.sym_to_smt2(w, info)?;
write_str(w, " ")?;
sort.sort_to_smt2(w)?;
write_str(w, ") ") ?
}
}
}
tee_write! {
self, no_check |w| {
write_str(w, ") ")?;
out.sort_to_smt2(w)?;
write_str(w, ")\n") ?
}
}
}
tee_write! {
self, no_check |w| write_str(w, " ) (") ?
}
for fun in funs {
let body = fun.body();
tee_write! {
self, no_check |w| {
write_str(w, "\n ")?;
body.expr_to_smt2(w, info) ?
}
}
}
tee_write! {
self, |w| write_str(w, "\n )\n)\n") ?
}
Ok(())
}
#[inline]
pub fn define_fun_rec_with<Args, Info>(
&mut self,
symbol: impl Sym2Smt<Info>,
args: Args,
out: impl Sort2Smt,
body: impl Expr2Smt<Info>,
info: Info,
) -> SmtRes<()>
where
Info: Copy,
Args: IntoIterator,
Args::Item: SymAndSort<Info>,
{
tee_write! {
self, no_check |w| write_str(w, "(define-fun-rec (\n") ?
}
tee_write! {
self, no_check |w| {
write_str(w, " (")?;
symbol.sym_to_smt2(w, info)?;
write_str(w, " ( ") ?
}
}
for arg in args {
let sym = arg.sym();
let sort = arg.sort();
tee_write! {
self, no_check |w| {
write_str(w, "(")?;
sym.sym_to_smt2(w, info)?;
write_str(w, " ")?;
sort.sort_to_smt2(w)?;
write_str(w, ") ") ?
}
}
}
tee_write! {
self, |w| {
write_str(w, ") ")?;
out.sort_to_smt2(w)?;
write_str(w, ")\n")?;
write_str(w, " ) (")?;
write_str(w, "\n ")?;
body.expr_to_smt2(w, info)?;
write_str(w, "\n )\n)\n") ?
}
}
Ok(())
}
#[inline]
pub fn full_assert<Act, Name, Info>(
&mut self,
actlit: Option<Act>,
name: Option<Name>,
expr: impl Expr2Smt<Info>,
info: Info,
) -> SmtRes<()>
where
Info: Copy,
Name: Sym2Smt,
Act: Sym2Smt,
{
tee_write! {
self, |w| {
write_str(w, "(assert")?;
if name.is_some() {
write_str(w, " (!")?;
}
if let Some(actlit) = actlit.as_ref() {
write_str(w, " (=> ")?;
actlit.sym_to_smt2(w, ())?;
}
write_str(w, "\n ")?;
expr.expr_to_smt2(w, info)?;
write_str(w, "\n")?;
if actlit.is_some() {
write_str(w, ")")?;
}
if let Some(name) = name.as_ref() {
write_str(w, " :named ")?;
name.sym_to_smt2(w, ())?;
write_str(w, ")")?;
}
write_str(w, ")\n")?;
}
}
Ok(())
}
#[inline]
pub fn named_assert_act_with<Info>(
&mut self,
actlit: &Actlit,
name: impl Sym2Smt,
expr: impl Expr2Smt<Info>,
info: Info,
) -> SmtRes<()>
where
Info: Copy,
{
self.full_assert(Some(actlit), Some(name), expr, info)
}
#[inline]
pub fn assert_act_with<Info>(
&mut self,
actlit: &Actlit,
expr: impl Expr2Smt<Info>,
info: Info,
) -> SmtRes<()>
where
Info: Copy,
{
let name: Option<&str> = None;
self.full_assert(Some(actlit.as_ref()), name, expr, info)
}
#[inline]
pub fn assert_with<Info, Expr>(&mut self, expr: Expr, info: Info) -> SmtRes<()>
where
Info: Copy,
Expr: Expr2Smt<Info>,
{
let name: Option<&str> = None;
let act: Option<Actlit> = None;
self.full_assert(act, name, expr, info)
}
#[inline]
pub fn named_assert<Expr, Name>(&mut self, name: Name, expr: Expr) -> SmtRes<()>
where
Name: Sym2Smt,
Expr: Expr2Smt,
{
let act: Option<Actlit> = None;
self.full_assert(act, Some(name), expr, ())
}
#[inline]
pub fn named_assert_with<Name, Info, Expr>(
&mut self,
name: Name,
expr: Expr,
info: Info,
) -> SmtRes<()>
where
Info: Copy,
Expr: Expr2Smt<Info>,
Name: Sym2Smt,
{
let act: Option<Actlit> = None;
self.full_assert(act, Some(name), expr, info)
}
pub fn check_sat_assuming_with<Info, Syms>(&mut self, idents: Syms, info: Info) -> SmtRes<bool>
where
Info: Copy,
Syms: IntoIterator,
Syms::Item: Sym2Smt<Info>,
{
let future = self.print_check_sat_assuming_with(idents, info)?;
self.parse_check_sat(future)
}
pub fn check_sat_assuming_or_unk_with<Idents, Info>(
&mut self,
idents: Idents,
info: Info,
) -> SmtRes<Option<bool>>
where
Info: Copy,
Idents: IntoIterator,
Idents::Item: Sym2Smt<Info>,
{
let future = self.print_check_sat_assuming_with(idents, info)?;
self.parse_check_sat_or_unk(future)
}
}
impl<Parser> Solver<Parser> {
#[inline]
pub fn set_option<Value: ::std::fmt::Display>(
&mut self,
option: &str,
value: Value,
) -> SmtRes<()> {
match option {
":interactive_mode" => return Err("illegal set-option on interactive mode".into()),
_ => (),
};
tee_write! {
self, |w| writeln!(
w, "(set-option {} {})", option, value
) ?
}
Ok(())
}
#[inline]
pub fn reset_assertions(&mut self) -> SmtRes<()> {
tee_write! {
self, |w| write_str(w, "(reset-assertions)\n") ?
}
Ok(())
}
#[inline]
pub fn get_info(&mut self, flag: &str) -> SmtRes<()> {
tee_write! {
self, no_check |w| writeln!(w, "(get-info {})", flag) ?
}
Ok(())
}
#[inline]
pub fn get_option(&mut self, option: &str) -> SmtRes<()> {
tee_write! {
self, no_check |w| writeln!(w, "(get-option {})", option) ?
}
Ok(())
}
#[inline]
pub fn set_info(&mut self, attribute: &str) -> SmtRes<()> {
tee_write! {
self, |w| writeln!(w, "(set-info {})", attribute) ?
}
Ok(())
}
#[inline]
pub fn echo(&mut self, text: &str) -> SmtRes<()> {
tee_write! {
self, no_check |w| writeln!(w, "(echo \"{}\")", text) ?
}
Ok(())
}
}