1use regex::Regex;
4use std::future::Future;
5use std::time::Instant;
6
7use derive_more::Display;
8use genawaiter::{sync::Gen, sync::gen, yield_};
9use indexmap::{IndexMap, IndexSet};
10use rusqlite::{Connection, Result};
11use z3_sys::*;
12
13use crate::ast::*;
14use crate::error::{format_error, SolverError};
15use crate::grammar::parse;
16use crate::private::a_sort::{declare_datatype, declare_datatypes, declare_sort, define_sort, PolymorphicObject, SortObject};
17use crate::private::b_fun::{declare_fun, define_fun, define_funs_rec, FunctionObject};
18use crate::private::c_assert::assert_;
19use crate::private::d_interpret::{interpret_pred, interpret_fun};
20use crate::private::e_ground::{ground, Grounding};
21use crate::private::e2_ground_query::TableName;
22use crate::private::e3_ground_sql::Predefined;
23use crate::private::y_db::init_db;
24use crate::ast::L;
25
26
27#[derive(PartialEq)]
28pub(crate) enum Backend {
29 NoDriver,
30 Z3(Z3_context)
31}
32
33impl Backend {
34 pub(crate) fn exec(&mut self, cmd: &str) -> Result<String, SolverError> {
36 match self {
37 Backend::NoDriver => {
38 return Ok(cmd.to_string())
39 },
40 Backend::Z3(ctx) => {
41 unsafe {
42 let c_cmd = std::ffi::CString::new(cmd).unwrap();
43 let response = Z3_eval_smtlib2_string(*ctx, c_cmd.as_ptr());
44 let c_str: &std::ffi::CStr = std::ffi::CStr::from_ptr(response);
45 let str_slice: &str = c_str.to_str().unwrap();
46 let result: String = str_slice.to_owned();
47 return Ok(result)
48 }
49 }
50 }
51 }
52}
53
54pub(crate) type TermId = usize;
55
56#[derive(Debug, Display, Clone, PartialEq, Eq, Hash)]
58pub(crate) struct CanonicalSort(pub(crate) Sort);
59
60
61pub struct Solver {
63 pub(crate) conn: Connection,
66 pub(crate) backend: Backend,
67 pub (crate) started: bool,
69
70 pub(crate) polymorphic_sorts: IndexMap<Symbol, PolymorphicObject>,
72
73 pub(crate) canonical_sorts: IndexMap<Sort, CanonicalSort>,
75 pub(crate) sort_objects: IndexMap<CanonicalSort, SortObject>,
76
77 pub(crate) interpretable_functions: IndexMap<L<Identifier>, (Vec<CanonicalSort>, CanonicalSort)>,
79 pub(crate) function_objects: IndexMap<(L<Identifier>, Vec<CanonicalSort>),
80 IndexMap<CanonicalSort, FunctionObject>>,
81
82 pub(crate) assertions_to_ground: Vec<L<Term>>,
86 pub(crate) groundings: IndexMap<(L<Term>, bool), (Grounding, CanonicalSort)>,
88
89 pub(crate) grounded: IndexSet<Identifier>,
93
94 pub(crate) converted: IndexSet<L<Identifier>>,
97
98 pub(crate) db_names: IndexSet<String>,
100}
101
102
103#[derive(Debug, strum_macros::Display, Clone, PartialEq, Eq, Hash)]
104pub(crate) enum TableType {
105 #[strum(to_string = "sort")] Sort,
106 #[strum(to_string = "selector")] Selector,
107 #[strum(to_string = "tester")] Tester,
108 #[strum(to_string = "interp" )] Interpretation,
109 #[strum(to_string = "view" )] Dynamic,
110}
111
112impl Solver {
115 pub fn new(conn: Option<Connection>) -> Solver {
119
120 let mut conn =
121 if let Some(conn) = conn {
122 conn
123 } else {
124 Connection::open_in_memory().unwrap()
125 };
126
127 conn.execute(
129 "CREATE TABLE Bool (
130 G TEXT PRIMARY KEY
131 )",
132 (), ).unwrap();
134 conn.execute("INSERT INTO Bool (G) VALUES (\"true\")" , ()).unwrap();
135 conn.execute("INSERT INTO Bool (G) VALUES (\"false\")", ()).unwrap();
136
137 init_db(&mut conn).unwrap();
138
139 let mut polymorphic_sorts = IndexMap::new();
143 polymorphic_sorts.insert(Symbol("Array".to_string()), PolymorphicObject::Unknown);
144
145 let mut sort_objects = IndexMap::new();
151 let sort = |s: &str|
152 Sort::new(&Symbol(s.to_string()));
153 let canonical_sort = |s: &str|
154 CanonicalSort(Sort::new(&Symbol(s.to_string())));
155
156 let bool_decl = SortObject::Normal{
157 datatype_dec: DatatypeDec::DatatypeDec(
158 vec![
159 ConstructorDec (Symbol("true" .to_string()),vec![]),
160 ConstructorDec (Symbol("false".to_string()),vec![]),
161 ],
162 ),
163 table: TableName("Bool".to_string()),
164 row_count: 2};
165 sort_objects.insert(CanonicalSort(sort("Bool")), bool_decl);
166 sort_objects.insert(canonical_sort("Int"), SortObject::Infinite);
168 sort_objects.insert(canonical_sort("Real"), SortObject::Infinite);
169 sort_objects.insert(canonical_sort("RoundingMode"), SortObject::Infinite); sort_objects.insert(canonical_sort("String"), SortObject::Infinite); sort_objects.insert(canonical_sort("RegLan"), SortObject::Infinite); let mut canonical_sorts = IndexMap::new();
175 canonical_sorts.insert(sort("Bool"), canonical_sort("Bool"));
176 canonical_sorts.insert(sort("Int"), canonical_sort("Int"));
177 canonical_sorts.insert(sort("Real"), canonical_sort("Real"));
178 canonical_sorts.insert(sort("RoundingMode"), canonical_sort("RoundingMode")); canonical_sorts.insert(sort("String"), canonical_sort("String")); canonical_sorts.insert(sort("RegLan"), canonical_sort("RegLan")); let id = |s: &str|
184 Identifier::new(&Symbol(s.to_string()));
185
186 let mut function_objects = IndexMap::new();
187
188
189 {let co_domain = CanonicalSort(sort("Bool"));
191 for s in ["true", "false"] {
193 let func = FunctionObject::Constructor;
194 function_objects.insert((id(s), vec![]), IndexMap::from([(co_domain.clone(), func.clone())]));
195 }
196
197 for (s, function) in [
199 ("not", Predefined::Not),
200 ("=>", Predefined::_Implies),
201 ("and", Predefined::And),
202 ("or", Predefined::Or),
203 ("xor", Predefined::_Xor),
204 ("=", Predefined::Eq),
205 ("distinct", Predefined::Distinct),
206 ("<=", Predefined::LE),
207 ("<", Predefined::Less),
208 (">=", Predefined::GE),
209 (">", Predefined::Greater)
210 ] {
211 let func = FunctionObject::Predefined{ function, boolean: Some(true) };
212 function_objects.insert((id(s), vec![]), IndexMap::from([(co_domain.clone(), func.clone())]));
213 }
214
215 let func = FunctionObject::Predefined { function: Predefined::Ite, boolean: None };
217 function_objects.insert((id("ite"), vec![]), IndexMap::from([(co_domain.clone(), func.clone())]));
218
219 let func = FunctionObject::Predefined { function: Predefined::_Let, boolean: None };
220 function_objects.insert((id("let"), vec![]), IndexMap::from([(co_domain.clone(), func.clone())]));
221 }
222 { let co_domain = CanonicalSort(sort("Real"));
224 for (s, function) in [
225 ("+", Predefined::Plus),
226 ("-", Predefined::Minus),
227 ("*", Predefined::Times),
228 ("div", Predefined::Div),
229 ("mod", Predefined::Mod),
230 ("abs", Predefined::Abs),
231 ] {
232 let func = FunctionObject::Predefined{ function, boolean: Some(false) };
233 function_objects.insert((id(s), vec![]), IndexMap::from([(co_domain.clone(), func.clone())]));
234 };
235 }
236 unsafe {
237 let cfg = Z3_mk_config();
238 let ctx = Z3_mk_context(cfg);
239 let backend = Backend::Z3(ctx);
240
241 Solver {
242 backend,
243 started: false,
244 conn,
245 polymorphic_sorts,
246 sort_objects,
247 canonical_sorts,
248 interpretable_functions: IndexMap::new(),
249 function_objects,
250 assertions_to_ground: vec![],
251 groundings: IndexMap::new(),
252 grounded: IndexSet::new(),
253 db_names: IndexSet::new(),
254 converted: IndexSet::new()
255 }
256 }
257
258 }
259}
260
261
262impl Solver {
263
264 pub fn parse_and_execute<'a> (
266 &'a mut self,
267 source: &'a str
268 ) -> Gen<String, (), impl Future<Output = ()> + 'a> {
269 gen!({
270 match parse(&source) {
271 Ok(commands) => {
272 for result in self.execute(commands) {
273 match result {
274 Ok(s) => yield_!(s),
275 Err(e) => {
276 yield_!(format_error(&source, e));
277 break
278 }
279 }
280 }
281 },
282 Err(err) => {
283 yield_!(format_error(&source, SolverError::ParseError(err)))
285 }
286 }
287 })
288 }
289
290 pub(crate) fn execute (
292 &mut self,
293 commands: Vec<Command>
294 ) -> Gen<Result<String, SolverError>, (), impl Future<Output = ()> + '_> {
295
296 gen!({
297 let mut start = Instant::now();
298 for command in commands {
299 for result in self.execute1(command, &mut start) {
300 if result.is_err() {
301 yield_!(result);
302 break
303 } else {
304 yield_!(result);
305 }
306 }
307 }
308 })
309 }
310
311 pub(crate) fn execute1<'a> (
313 &'a mut self,
314 c: Command,
315 start: &'a mut Instant
316 ) -> Gen<Result<String, SolverError>, (), impl Future<Output = ()> + 'a>
317 {
318 gen!({
319 let command = c.to_string();
320 match c {
321
322 Command::Assert(term) => {
323 if self.backend != Backend::NoDriver {
324 yield_!(self.exec("(push)"));
327 yield_!(self.exec(&command));
328 yield_!(self.exec("(pop)"));
329 }
330
331 yield_!(assert_(&term, self))
332 }
333 Command::CheckSat => {
334 for res in ground(false, false, false, self) {
335 yield_!(res)
336 }
337 match self.exec(&command) {
338 Ok(res) => yield_!(Ok(res)),
339 Err(err) => {
340 yield_!(Err(err));
341 }
342 };
343 }
344
345 Command::DeclareConst(symb, sort) =>
346 yield_!(declare_fun(symb, vec![], sort, command, self)),
347
348 Command::DeclareDatatype(symb, decl) =>
349 yield_!(declare_datatype(symb, decl, command, self)),
350
351 Command::DeclareDatatypes(sort_decls, decls) =>
352 yield_!(declare_datatypes(sort_decls, decls, command, self)),
353
354 Command::DeclareFun(symb, domain, co_domain) =>
355 yield_!(declare_fun(symb, domain, co_domain, command, self)),
356
357 Command::DeclareSort(symb, numeral) =>
358 yield_!(declare_sort(symb, numeral, command, self)),
359
360 Command::DefineFun(def, rec) => yield_!(define_fun(def, rec, command, self)),
361
362 Command::DefineFunsRec(decs, terms) =>
363 yield_!(define_funs_rec(decs, terms, command, self)),
364
365 Command::DefineSort(symb, variables, sort) =>
366 yield_!(define_sort(symb, variables, sort, command, self)),
367
368 Command::Echo(string) => yield_!(self.exec(&command)),
369 Command::GetInfo(keyword) => yield_!(self.exec(&command)),
370 Command::XInterpretPred(identifier, tuples) =>
371 yield_!(interpret_pred(identifier, tuples, self)),
372
373 Command::XInterpretFun(identifier, tuples, else_) =>
374 yield_!(interpret_fun(identifier, tuples, else_, command, self)),
375
376 Command::SetOption(option) =>
377 yield_!(self.set_option(option, command)),
378
379 Command::XDebug(typ, obj) => {
380 match typ.to_string().as_str() {
381 "solver" => {
382 match obj.to_string().as_str() {
383 "sorts" => {
384 yield_!(Ok("Sorts:\n".to_string()));
385 for (sort, canonical) in &self.canonical_sorts {
386 let decl = self.sort_objects.get(canonical).unwrap();
387 let canonical = if canonical.0 == sort.clone() { "".to_string() }
388 else { format!(" (= {canonical})") };
389 match decl {
390 SortObject::Normal{datatype_dec, table, row_count} =>
391 yield_!(Ok(format!(" - ({table}: {row_count}) {sort}{canonical}: {datatype_dec}\n"))),
392 SortObject::Recursive =>
393 yield_!(Ok(format!(" - (recursive) {sort}{canonical}\n"))),
394 SortObject::Infinite =>
395 yield_!(Ok(format!(" - (infinite) {sort}{canonical}\n"))),
396 SortObject::Unknown =>
397 yield_!(Ok(format!(" - (unknown) {sort}{canonical}\n"))),
398 }
399 }
400 },
401 "polymorphic_sorts" => {
402 yield_!(Ok("Polymorphic datatypes:\n".to_string()));
403 for (sort, decl) in &self.polymorphic_sorts {
404 match decl {
405 PolymorphicObject::Datatype(decl) =>
406 yield_!(Ok(format!(" - {sort}: {decl}\n"))),
407 PolymorphicObject::SortDefinition{variables, definiendum} => {
408 let vars = variables.iter()
409 .map(|v| v.0.clone())
410 .collect::<Vec<String>>().join(",");
411 yield_!(Ok(format!(" - {sort}: ({vars}) -> {definiendum}\n")))
412 },
413 PolymorphicObject::RecursiveDT(decl) =>
414 yield_!(Ok(format!(" - (recursive) {sort}: {decl}\n"))),
415 PolymorphicObject::Unknown =>
416 yield_!(Ok(format!(" - (unknown): {sort}\n"))),
417 }
418 }
419 },
420 "functions" => {
421 yield_!(Ok("Functions2:\n".to_string()));
422 for ((symbol, domain), map) in &self.function_objects {
423 let domain = domain.iter()
424 .map(|s| s.to_string())
425 .collect::<Vec<_>>().join(", ");
426 for (co_domain, func) in map {
427 yield_!(Ok(format!(" - {symbol} ({domain})->{co_domain} : {func}\n")))
428 }
429 }
430 },
431 "groundings" => {
432 yield_!(Ok("Groundings:\n".to_string()));
433 for ((term, top), (grounding, _)) in &self.groundings {
434 let top = if *top { "(top)" } else { "" };
435 yield_!(Ok(format!("=== {top} {term} ======================================\n{grounding}\n")))
436 }
437 yield_!(Ok("===========================================\n".to_string()))
438 },
439 _ => yield_!(Err(SolverError::IdentifierError("Unknown 'x-debug solver' parameter\n", obj)))
440 }
441 },
442 "db" => {
443 if obj.to_string() == "tables" {
444 let query = "SELECT name, type FROM sqlite_master WHERE type IN ('table', 'view')";
446 let mut stmt = self.conn.prepare(query).unwrap();
447 let rows = stmt.query_map([], |row| {
448 let name: String = row.get(0)?;
449 let typ: String = row.get(1)?;
450 Ok((name, typ))
451 }).unwrap();
452
453 yield_!(Ok("Tables and Views:\n".to_string()));
454 for row in rows {
455 if let Ok((name, typ)) = row {
456 yield_!(Ok(format!(" - {name} ({typ})\n")));
457 }
458 }
459 } else if let Ok(content) = pretty_sqlite::pretty_table(&self.conn, obj.to_string().to_lowercase().as_str()) {
460 yield_!(Ok(format!("{content}\n")))
461 } else {
462 yield_!(Err(SolverError::IdentifierError("Unknown table\n", typ)))
463 }
464 },
465 _ => yield_!(Err(SolverError::IdentifierError("Unknown 'x-debug' parameter\n", typ)))
466 }
467 },
468
469 Command::XDuration(string) => {
470 let duration = start.elapsed().as_secs_f32();
471 *start = Instant::now();
472 yield_!(Ok(format!("{}{:.3} sec\n", string.0, duration)))
473 },
474
475 Command::XGround{no, debug, sql} => {
476 for res in ground(no, debug, sql, self) {
477 yield_!(res)
478 }
479 }
480
481 Command::Verbatim(_) => yield_!(self.exec(&command)),
482 }
483 })
484 }
485
486 pub(crate) fn exec(&mut self, cmd: &str) -> Result<String, SolverError> {
488 if cmd.to_string().len() != 0 {
489 self.started = true;
490 }
491 self.backend.exec(cmd)
492 }
493
494 pub(crate) fn set_option(&mut self, option: Option_, cmd: String) -> Result<String, SolverError> {
495 match option {
496 Option_::Attribute(Attribute::Keyword(_)) => {
497 self.exec(&cmd)
498 },
499 Option_::Attribute(Attribute::WithValue(keyword, value)) => {
500 match (keyword.0.as_str(), value) {
501 (":backend", AttributeValue::Symbol(Symbol(value))) => {
502 let new =
503 match value.as_str() {
504 "none" => Backend::NoDriver,
505 "Z3" => {
506 unsafe {
507 let cfg = Z3_mk_config();
508 let ctx = Z3_mk_context(cfg);
509 Backend::Z3(ctx)
510 }
511 },
512 _ => return Err(SolverError::ExprError(format!("Unknown backend: {value}")))
513 };
514 if self.backend != new {
515 if self.started {
516 return Err(SolverError::ExprError("Can't change backend anymore".to_string()))
517 };
518 self.backend = new;
519 }
520 Ok("".to_string())
521 },
522 _ => self.exec(&cmd)
523 }
524
525 },
526 }
527 }
528
529
530 pub(crate) fn create_table_name(self: &mut Solver, name: String, type_: TableType) -> TableName {
532 let re = Regex::new(r"[\+\-/\*=\%\?\!\.\$\&\^<>@\|]").unwrap();
533 let db_name = re.replace_all(&name, "").to_string().to_lowercase();
534 let index = self.db_names.len();
535 let db_name =
536 if db_name.len() == 0 {
537 format!("_xmt_{type_}_{index}")
538 } else {
539 let temp =
540 if db_name.starts_with("_xmt_") { strip_prefix(&db_name) }
541 else { db_name };
542 let temp = format!("_xmt_{type_}_{temp}");
543 if self.db_names.contains(&temp) {
544 format!("{temp}_{index}")
545 } else {
546 temp
547 }
548 };
549 self.db_names.insert(db_name.clone());
550 TableName(db_name)
551 }
552}
553
554fn strip_prefix(s: &str) -> String {
555 let re = Regex::new(r"^_xmt_[^_]+_").unwrap();
557 re.replace(&s, "").to_string()
558}