1use std::io::Write;
8
9use crate::{common::*, parse::*};
10
11#[cfg(test)]
12use crate::example::get_solver;
13
14use self::Var::*;
15
16#[derive(Debug, Clone, Copy, PartialEq)]
18enum Type {
19 Int,
21 Bool,
23 Real,
25}
26impl Type {
27 pub fn to_str(self) -> &'static str {
29 match self {
30 Type::Int => "Int",
31 Type::Bool => "Bool",
32 Type::Real => "Real",
33 }
34 }
35}
36impl Sort2Smt for Type {
37 fn sort_to_smt2<Writer: Write>(&self, writer: &mut Writer) -> SmtRes<()> {
38 writer.write_all(self.to_str().as_bytes())?;
39 Ok(())
40 }
41}
42
43#[derive(Debug, Clone, PartialEq)]
45pub struct Symbol<'a, 'b>(&'a Var, &'b Offset);
46
47#[derive(Debug, Clone, Copy, PartialEq)]
49pub struct Offset(usize, usize);
50impl Offset {
51 #[inline(always)]
53 pub fn curr(&self) -> usize {
54 self.0
55 }
56 #[inline(always)]
58 pub fn next(&self) -> usize {
59 self.1
60 }
61}
62
63#[derive(Debug, Clone, PartialEq)]
65pub struct Unrolled<'a, T>(T, &'a Offset);
66
67pub type Sym = String;
69
70#[derive(Debug, Clone, PartialEq)]
72pub enum Var {
73 NSVar(Sym),
75 SVar0(Sym),
77 SVar1(Sym),
79}
80impl Var {
81 pub fn sym(&self) -> &str {
83 match *self {
84 NSVar(ref s) => s,
85 SVar0(ref s) => s,
86 SVar1(ref s) => s,
87 }
88 }
89 pub fn nsvar(s: &str) -> Self {
91 NSVar(s.to_string())
92 }
93 pub fn svar0(s: &str) -> Self {
95 SVar0(s.to_string())
96 }
97 pub fn svar1(s: &str) -> Self {
99 SVar1(s.to_string())
100 }
101
102 pub fn unroll<'a, 'b>(&'a self, off: &'b Offset) -> Unrolled<'b, &'a Var> {
104 Unrolled(self, off)
105 }
106}
107
108impl<'a, V: AsRef<Var>> Expr2Smt<()> for Unrolled<'a, V> {
109 fn expr_to_smt2<Writer: Write>(&self, writer: &mut Writer, _: ()) -> SmtRes<()> {
110 self.0.as_ref().expr_to_smt2(writer, &self.1)
111 }
112}
113impl<'a> Expr2Smt<&'a Offset> for Var {
114 fn expr_to_smt2<Writer: Write>(&self, writer: &mut Writer, off: &'a Offset) -> SmtRes<()> {
115 match *self {
116 NSVar(ref sym) => write!(writer, "|{}|", sym)?,
117 SVar0(ref sym) => write!(writer, "|{}@{}|", sym, off.0)?,
119 SVar1(ref sym) => write!(writer, "|{}@{}|", sym, off.1)?,
121 }
122 Ok(())
123 }
124}
125
126impl<'a> Sym2Smt<&'a Offset> for Var {
127 fn sym_to_smt2<Writer: Write>(&self, writer: &mut Writer, off: &'a Offset) -> SmtRes<()> {
128 self.expr_to_smt2(writer, off)
129 }
130}
131impl<'a, 'b> Sym2Smt<()> for Unrolled<'a, &'b Var> {
132 fn sym_to_smt2<Writer: Write>(&self, writer: &mut Writer, _: ()) -> SmtRes<()> {
133 self.0.expr_to_smt2(writer, &self.1)
134 }
135}
136
137#[derive(Debug, Clone, PartialEq)]
139pub enum Const {
140 BConst(bool),
142 IConst(isize),
144 RConst(isize, usize),
146}
147
148impl Expr2Smt<()> for Const {
149 fn expr_to_smt2<Writer: Write>(&self, writer: &mut Writer, _: ()) -> SmtRes<()> {
150 match *self {
151 Const::BConst(b) => write!(writer, "{}", b)?,
152 Const::IConst(i) => {
153 let neg = i < 0;
154 if neg {
155 write!(writer, "(- ")?
156 }
157 write!(writer, "{}", i.abs())?;
158 if neg {
159 write!(writer, ")")?
160 }
161 }
162 Const::RConst(num, den) => {
163 let neg = num < 0;
164 if neg {
165 write!(writer, "(- ")?
166 }
167 write!(writer, "(/ {} {})", num, den)?;
168 if neg {
169 write!(writer, ")")?
170 }
171 }
172 }
173 Ok(())
174 }
175}
176
177#[derive(Debug, Clone, PartialEq)]
179pub enum SExpr {
180 Id(Var),
182 Val(Const),
184 App(Sym, Vec<SExpr>),
186}
187
188impl SExpr {
189 pub fn app(sym: &str, args: Vec<SExpr>) -> Self {
191 SExpr::App(sym.to_string(), args)
192 }
193 pub fn unroll<'a, 'b>(&'a self, off: &'b Offset) -> Unrolled<'b, &'a SExpr> {
195 Unrolled(self, off)
196 }
197}
198
199impl<'a> Expr2Smt<&'a Offset> for SExpr {
200 fn expr_to_smt2<Writer: Write>(&self, writer: &mut Writer, off: &'a Offset) -> SmtRes<()> {
201 match *self {
202 SExpr::Id(ref var) => var.expr_to_smt2(writer, off),
203 SExpr::Val(ref cst) => cst.expr_to_smt2(writer, ()),
204 SExpr::App(ref sym, ref args) => {
205 write!(writer, "({}", sym)?;
206 for arg in args {
207 write!(writer, " ")?;
208 arg.expr_to_smt2(writer, off)?
209 }
210 write!(writer, ")")?;
211 Ok(())
212 }
213 }
214 }
215}
216
217impl<'a, 'b> Expr2Smt<()> for Unrolled<'a, &'b SExpr> {
218 fn expr_to_smt2<Writer: Write>(&self, writer: &mut Writer, _: ()) -> SmtRes<()> {
219 self.0.expr_to_smt2(writer, &self.1)
220 }
221}
222
223#[derive(Clone, Copy)]
225pub struct Parser;
226
227impl<'a> IdentParser<(Var, Option<usize>), Type, &'a str> for Parser {
228 fn parse_ident(self, s: &'a str) -> SmtRes<(Var, Option<usize>)> {
229 if s.len() <= 2 {
230 bail!("not one of my idents...")
231 }
232 let s = &s[1..(s.len() - 1)]; let mut parts = s.split('@');
234 let id = if let Some(id) = parts.next() {
235 id.to_string()
236 } else {
237 bail!("nothing between my pipes!")
238 };
239 if let Some(index) = parts.next() {
240 use std::str::FromStr;
241 Ok((
242 Var::SVar0(id),
243 match usize::from_str(index) {
244 Ok(index) => Some(index),
245 Err(e) => bail!("while parsing the offset in `{}`: {}", s, e),
246 },
247 ))
248 } else {
249 Ok((Var::NSVar(id), None))
250 }
251 }
252 fn parse_type(self, s: &'a str) -> SmtRes<Type> {
253 match s {
254 "Int" => Ok(Type::Int),
255 "Bool" => Ok(Type::Bool),
256 "Real" => Ok(Type::Real),
257 _ => bail!(format!("unknown type `{}`", s)),
258 }
259 }
260}
261
262impl<'a, Br> ModelParser<(Var, Option<usize>), Type, Const, &'a mut SmtParser<Br>> for Parser
263where
264 Br: ::std::io::BufRead,
265{
266 fn parse_value(
267 self,
268 input: &'a mut SmtParser<Br>,
269 _: &(Var, Option<usize>),
270 _: &[((Var, Option<usize>), Type)],
271 _: &Type,
272 ) -> SmtRes<Const> {
273 use std::str::FromStr;
274 if let Some(b) = input.try_bool()? {
275 Ok(Const::BConst(b))
276 } else if let Some(int) = input.try_int(|int, pos| match isize::from_str(int) {
277 Ok(int) => {
278 if pos {
279 Ok(int)
280 } else {
281 Ok(-int)
282 }
283 }
284 Err(e) => Err(e),
285 })? {
286 Ok(Const::IConst(int))
287 } else if let Some((num, den)) =
288 input.try_rat(
289 |num, den, pos| match (isize::from_str(num), usize::from_str(den)) {
290 (Ok(num), Ok(den)) => {
291 if pos {
292 Ok((num, den))
293 } else {
294 Ok((-num, den))
295 }
296 }
297 (Err(e), _) | (_, Err(e)) => Err(format!("{}", e)),
298 },
299 )?
300 {
301 Ok(Const::RConst(num, den))
302 } else {
303 input.fail_with("unexpected value")
304 }
305 }
306}
307
308#[test]
309fn declare_non_nullary_fun() {
310 let mut solver = get_solver(Parser);
311
312 smtry!(
313 solver.declare_fun(
314 "my_fun", & [ "Int", "Real", "Bool" ], "Real"
315 ), failwith "during function declaration: {:?}"
316 );
317
318 solver.kill().expect("kill")
319}
320
321#[test]
322fn test_native() {
323 use self::SExpr::*;
324
325 let mut solver = get_solver(Parser);
326
327 let nsv_0 = Var::nsvar("non-stateful var");
328 let s_nsv_0 = Id(nsv_0.clone());
329 let nsv_1 = Var::nsvar("also non-stateful");
330 let s_nsv_1 = Id(nsv_1.clone());
331 let sv_0 = Var::svar0("stateful var");
332 let s_sv_0 = Id(sv_0.clone());
333 let sv_1 = Var::svar1("also stateful");
334 let s_sv_1 = Id(sv_1.clone());
335 let app1 = SExpr::app("not", vec![s_sv_0.clone()]);
336 let app2 = SExpr::app(">", vec![s_sv_1.clone(), Val(Const::IConst(7))]);
337 let app3 = SExpr::app(
338 "=",
339 vec![
340 Val(Const::RConst(-7, 3)),
341 SExpr::app("+", vec![s_nsv_1.clone(), Val(Const::RConst(2, 1))]),
342 ],
343 );
344 let app = SExpr::app("and", vec![s_nsv_0.clone(), app1, app2, app3]);
345 let offset1 = Offset(0, 1);
346
347 smtry!(
348 solver.declare_const_with(& nsv_0, & "Bool", & offset1),
349 failwith "declaration failed: {:?}"
350 );
351
352 smtry!(
353 solver.declare_const_with(& nsv_1, & "Real", & offset1),
354 failwith "declaration failed: {:?}"
355 );
356
357 smtry!(
358 solver.declare_const_with(& sv_0, & "Bool", & offset1),
359 failwith "declaration failed: {:?}"
360 );
361
362 smtry!(
363 solver.declare_const_with(& sv_1, & "Int", & offset1),
364 failwith "declaration failed: {:?}"
365 );
366
367 smtry!(
368 solver.assert_with(& app, & offset1),
369 failwith "assert failed: {:?}"
370 );
371
372 assert!(smtry!(
373 solver.check_sat(),
374 failwith "error in checksat: {:?}"
375 ));
376
377 let model = smtry!(
378 solver.get_model(),
379 failwith "while getting model: {:?}"
380 );
381
382 for ((var, off), _, typ, val) in model {
383 if var.sym() == "stateful var" {
384 assert_eq!(off, Some(0));
385 assert_eq!(typ, Type::Bool);
386 assert_eq!(val, Const::BConst(false))
387 } else if var.sym() == "also stateful" {
388 assert_eq!(off, Some(1));
389 assert_eq!(typ, Type::Int);
390 if let Const::IConst(val) = val {
391 assert!(val > 7)
392 } else {
393 panic!("expected variable, got {:?}", val)
394 }
395 } else if var.sym() == "non-stateful var" {
396 assert_eq!(off, None);
397 assert_eq!(typ, Type::Bool);
398 assert_eq!(val, Const::BConst(true))
399 } else if var.sym() == "also non-stateful" {
400 assert_eq!(off, None);
401 assert_eq!(typ, Type::Real);
402 if let Const::RConst(num, den) = val {
403 assert_eq!(num * 3 + (2 * 3 * den as isize), (7 * den as isize))
404 } else {
405 panic!("expected variable, got {:?}", val)
406 }
407 }
408 }
409
410 solver.kill().expect("kill")
411}
412
413#[test]
414fn test_unroll() {
415 use self::SExpr::*;
416
417 let mut solver = get_solver(Parser);
418
419 let nsv_0 = Var::nsvar("non-stateful var");
420 let s_nsv_0 = Id(nsv_0.clone());
421 let nsv_1 = Var::nsvar("also non-stateful");
422 let s_nsv_1 = Id(nsv_1.clone());
423 let sv_0 = Var::svar0("stateful var");
424 let s_sv_0 = Id(sv_0.clone());
425 let sv_1 = Var::svar1("also stateful");
426 let s_sv_1 = Id(sv_1.clone());
427 let app1 = SExpr::app("not", vec![s_sv_0.clone()]);
428 let app2 = SExpr::app(">", vec![s_sv_1.clone(), Val(Const::IConst(7))]);
429 let app3 = SExpr::app(
430 "=",
431 vec![
432 Val(Const::RConst(-7, 3)),
433 SExpr::app("+", vec![s_nsv_1.clone(), Val(Const::RConst(2, 1))]),
434 ],
435 );
436 let app = SExpr::app("and", vec![s_nsv_0.clone(), app1, app2, app3]);
437 let offset1 = Offset(0, 1);
438
439 let sym = nsv_0.unroll(&offset1);
440 smtry!(
441 solver.declare_const(& sym, & "Bool"),
442 failwith "declaration failed: {:?}"
443 );
444
445 let sym = nsv_1.unroll(&offset1);
446 smtry!(
447 solver.declare_const(& sym, & "Real"),
448 failwith "declaration failed: {:?}"
449 );
450
451 let sym = sv_0.unroll(&offset1);
452 smtry!(
453 solver.declare_const(& sym, & "Bool"),
454 failwith "declaration failed: {:?}"
455 );
456
457 let sym = sv_1.unroll(&offset1);
458 smtry!(
459 solver.declare_const(& sym, & "Int"),
460 failwith "declaration failed: {:?}"
461 );
462
463 let expr = app.unroll(&offset1);
464 smtry!(
465 solver.assert(& expr),
466 failwith "assert failed: {:?}"
467 );
468
469 assert!(smtry!(
470 solver.check_sat(),
471 failwith "error in checksat: {:?}"
472 ));
473
474 let model = smtry!(
475 solver.get_model(),
476 failwith "while getting model: {:?}"
477 );
478
479 for ((var, off), _, typ, val) in model {
480 if var.sym() == "stateful var" {
481 assert_eq!(off, Some(0));
482 assert_eq!(typ, Type::Bool);
483 assert_eq!(val, Const::BConst(false))
484 } else if var.sym() == "also stateful" {
485 assert_eq!(off, Some(1));
486 assert_eq!(typ, Type::Int);
487 if let Const::IConst(val) = val {
488 assert!(val > 7)
489 } else {
490 panic!("expected variable, got {:?}", val)
491 }
492 } else if var.sym() == "non-stateful var" {
493 assert_eq!(off, None);
494 assert_eq!(typ, Type::Bool);
495 assert_eq!(val, Const::BConst(true))
496 } else if var.sym() == "also non-stateful" {
497 assert_eq!(off, None);
498 assert_eq!(typ, Type::Real);
499 if let Const::RConst(num, den) = val {
500 assert_eq!(num * 3 + (2 * 3 * den as isize), (7 * den as isize))
501 } else {
502 panic!("expected variable, got {:?}", val)
503 }
504 }
505 }
506
507 solver.kill().expect("kill")
508}