Skip to content

Commit cd66c0d

Browse files
authored
Use separate methods for configuring the solver program and its args (#44)
Note: this is a breaking change. Fixes #43
1 parent 9d9b902 commit cd66c0d

File tree

5 files changed

+46
-57
lines changed

5 files changed

+46
-57
lines changed

README.md

Lines changed: 4 additions & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -33,7 +33,8 @@ use easy_smt::{ContextBuilder, Response};
3333
fn main() -> std::io::Result<()> {
3434
// Create a new context, backed by a Z3 subprocess.
3535
let mut ctx = ContextBuilder::new()
36-
.solver("z3", ["-smt2", "-in"])
36+
.solver("z3")
37+
.solver_args(["-smt2", "-in"])
3738
.build()?;
3839

3940
// Declare `x` and `y` variables that are bitvectors of width 32.
@@ -147,7 +148,8 @@ fn main() -> std::io::Result<()> {
147148
// Everything needed to replay the solver session will be written
148149
// to `replay.smt2`.
149150
.replay_file(Some(std::fs::File::create("replay.smt2")?))
150-
.solver("z3", ["-smt2", "-in"])
151+
.solver("z3")
152+
.solver_args(["-smt2", "-in"])
151153
.build()?;
152154

153155
// ...

examples/quantifiers.rs

Lines changed: 13 additions & 42 deletions
Original file line numberDiff line numberDiff line change
@@ -4,7 +4,8 @@
44
fn main() -> std::io::Result<()> {
55
env_logger::init();
66
let mut ctx = easy_smt::ContextBuilder::new()
7-
.solver("z3", ["-smt2", "-in"])
7+
.solver("z3")
8+
.solver_args(["-smt2", "-in"])
89
.build()?;
910

1011
// Declare an uninterpreted representation for sets.
@@ -14,11 +15,7 @@ fn main() -> std::io::Result<()> {
1415

1516
// Our sets have a simple interface of predicates: empty(s),
1617
// member(x,s), and subset(s1,s2).
17-
ctx.declare_fun(
18-
"empty",
19-
vec![ctx.atom("MySet")],
20-
ctx.bool_sort(),
21-
)?;
18+
ctx.declare_fun("empty", vec![ctx.atom("MySet")], ctx.bool_sort())?;
2219
ctx.declare_fun(
2320
"member",
2421
vec![ctx.atom("MyElement"), ctx.atom("MySet")],
@@ -41,30 +38,18 @@ fn main() -> std::io::Result<()> {
4138
// One of the following is true:
4239
ctx.or(
4340
// (1) s1 is a subset of s2, or
44-
ctx.list(vec![
45-
ctx.atom("subset"),
46-
ctx.atom("s1"),
47-
ctx.atom("s2"),
48-
]),
41+
ctx.list(vec![ctx.atom("subset"), ctx.atom("s1"), ctx.atom("s2")]),
4942
// (2) an element exists which is a member of s1, and
5043
// not a member of s2.
5144
ctx.exists(
5245
[("x", ctx.atom("MyElement"))],
5346
ctx.and(
54-
ctx.list(vec![
55-
ctx.atom("member"),
56-
ctx.atom("x"),
57-
ctx.atom("s1"),
58-
]),
59-
ctx.not(ctx.list(vec![
60-
ctx.atom("member"),
61-
ctx.atom("x"),
62-
ctx.atom("s2"),
63-
])),
47+
ctx.list(vec![ctx.atom("member"), ctx.atom("x"), ctx.atom("s1")]),
48+
ctx.not(ctx.list(vec![ctx.atom("member"), ctx.atom("x"), ctx.atom("s2")])),
6449
),
6550
),
6651
),
67-
)
52+
),
6853
)?;
6954

7055
// Second, a set is empty iff no member exists.
@@ -79,11 +64,7 @@ fn main() -> std::io::Result<()> {
7964
// (2) an element exists that is a member of the set.
8065
ctx.exists(
8166
[("x", ctx.atom("MyElement"))],
82-
ctx.list(vec![
83-
ctx.atom("member"),
84-
ctx.atom("x"),
85-
ctx.atom("s1"),
86-
]),
67+
ctx.list(vec![ctx.atom("member"), ctx.atom("x"), ctx.atom("s1")]),
8768
),
8869
),
8970
),
@@ -95,31 +76,21 @@ fn main() -> std::io::Result<()> {
9576
ctx.declare_const("s2", ctx.atom("MySet"))?;
9677

9778
// Is it possible for s1 to be empty,
98-
ctx.assert(
99-
ctx.list(vec![ctx.atom("empty"), ctx.atom("s1")])
100-
)?;
79+
ctx.assert(ctx.list(vec![ctx.atom("empty"), ctx.atom("s1")]))?;
10180
// while also s1 is not a subset of s2?
102-
ctx.assert(
103-
ctx.not(
104-
ctx.list(vec![
105-
ctx.atom("subset"),
106-
ctx.atom("s1"),
107-
ctx.atom("s2"),
108-
])
109-
)
110-
)?;
81+
ctx.assert(ctx.not(ctx.list(vec![ctx.atom("subset"), ctx.atom("s1"), ctx.atom("s2")])))?;
11182

11283
// We expect the answer to be no (UNSAT).
11384
match ctx.check()? {
11485
easy_smt::Response::Sat => {
11586
println!("Solver returned SAT. This is unexpected!");
116-
},
87+
}
11788
easy_smt::Response::Unsat => {
11889
println!("Solver returned UNSAT. This is expected.");
119-
},
90+
}
12091
easy_smt::Response::Unknown => {
12192
println!("Solver returned UNKNOWN. This is unexpected!");
122-
},
93+
}
12394
}
12495
Ok(())
12596
}

examples/sudoku.rs

Lines changed: 2 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -6,7 +6,8 @@ fn main() -> std::io::Result<()> {
66
env_logger::init();
77

88
let mut ctx = easy_smt::ContextBuilder::new()
9-
.solver("z3", ["-smt2", "-in"])
9+
.solver("z3")
10+
.solver_args(["-smt2", "-in"])
1011
.build()?;
1112

1213
// for helping diagnose unsolvable problems

src/context.rs

Lines changed: 22 additions & 8 deletions
Original file line numberDiff line numberDiff line change
@@ -3,7 +3,7 @@ use crate::{
33
sexpr::{Arena, DisplayExpr, SExpr, SExprData},
44
solver::Solver,
55
};
6-
use std::{ffi, io};
6+
use std::{ffi, io, mem};
77

88
macro_rules! variadic {
99
($name:ident, $op:ident) => {
@@ -70,7 +70,8 @@ macro_rules! pairwise {
7070

7171
#[derive(Default)]
7272
pub struct ContextBuilder {
73-
solver_program_and_args: Option<(ffi::OsString, Vec<ffi::OsString>)>,
73+
solver: Option<ffi::OsString>,
74+
solver_args: Vec<ffi::OsString>,
7475
replay_file: Option<Box<dyn io::Write + Send>>,
7576
}
7677

@@ -82,17 +83,29 @@ impl ContextBuilder {
8283

8384
/// Configure the solver that will be used.
8485
///
86+
/// You can pass arguments to the underlying solver via the
87+
/// [`solver_args`][Self::solver_args] method.
88+
///
8589
/// By default, no solver is configured, and any `Context` created will only
8690
/// be able to build and display expressions, not assert them or query for
8791
/// their satisfiability.
88-
pub fn solver<P, A>(&mut self, program: P, args: A) -> &mut Self
92+
pub fn solver<P>(&mut self, program: P) -> &mut Self
8993
where
9094
P: Into<ffi::OsString>,
95+
{
96+
self.solver = Some(program.into());
97+
self
98+
}
99+
100+
/// Configure the arguments that will be passed to the solver.
101+
///
102+
/// By default, no arguments are passed to the solver.
103+
pub fn solver_args<A>(&mut self, args: A) -> &mut Self
104+
where
91105
A: IntoIterator,
92106
A::Item: Into<ffi::OsString>,
93107
{
94-
self.solver_program_and_args =
95-
Some((program.into(), args.into_iter().map(|a| a.into()).collect()));
108+
self.solver_args = args.into_iter().map(|a| a.into()).collect();
96109
self
97110
}
98111

@@ -102,7 +115,8 @@ impl ContextBuilder {
102115
/// `Context` created will only be able to build and display expressions,
103116
/// not assert them or query for their satisfiability.
104117
pub fn without_solver(&mut self) -> &mut Self {
105-
self.solver_program_and_args = None;
118+
self.solver = None;
119+
self.solver_args.clear();
106120
self
107121
}
108122

@@ -128,10 +142,10 @@ impl ContextBuilder {
128142
let arena = Arena::new();
129143
let atoms = KnownAtoms::new(&arena);
130144

131-
let solver = if let Some((program, args)) = self.solver_program_and_args.take() {
145+
let solver = if let Some(program) = self.solver.take() {
132146
Some(Solver::new(
133147
program,
134-
args,
148+
mem::take(&mut self.solver_args),
135149
self.replay_file
136150
.take()
137151
.unwrap_or_else(|| Box::new(io::sink())),

tests/error.rs

Lines changed: 5 additions & 4 deletions
Original file line numberDiff line numberDiff line change
@@ -1,18 +1,19 @@
1-
21
// This test ensures that we can handle `(error "...")` responses from z3.
32
#[test]
43
fn handles_errors_gracefully() -> std::io::Result<()> {
54
let mut context = easy_smt::ContextBuilder::new()
6-
.solver("z3", ["-smt2", "-in"])
5+
.solver("z3")
6+
.solver_args(["-smt2", "-in"])
77
.build()?;
88

99
let width = context.numeral(1);
1010
let sort = context.bit_vec_sort(width);
1111

1212
// The name `foo:a` will cause a parse error, as z3 will parse it as the two atoms, `foo`
1313
// and `:a`, and then reject the invalid declaration.
14-
context.declare_fun("foo:a", vec![], sort).expect_err("z3 should reject this declaration");
14+
context
15+
.declare_fun("foo:a", vec![], sort)
16+
.expect_err("z3 should reject this declaration");
1517

1618
Ok(())
1719
}
18-

0 commit comments

Comments
 (0)