1#![cfg_attr(feature = "nightly", feature(rustc_private))]
5
6#[cfg(feature = "nightly")]
7extern crate rustc_data_structures;
8#[cfg(all(test, feature = "nightly"))]
10#[allow(unused_extern_crates)]
11extern crate rustc_driver;
12#[cfg(feature = "nightly")]
13extern crate rustc_macros;
14#[cfg(feature = "nightly")]
15extern crate rustc_serialize;
16#[cfg(feature = "nightly")]
17extern crate rustc_span;
18
19mod constraint;
20#[cfg(feature = "rust-fixpoint")]
21mod constraint_fragments;
22#[cfg(feature = "rust-fixpoint")]
23mod constraint_solving;
24mod constraint_with_env;
25#[cfg(feature = "rust-fixpoint")]
26mod cstr2smt2;
27mod format;
28mod graph;
29pub mod parser;
30pub mod sexp;
31mod smt_fmt;
32pub mod smt_horn;
33mod suggestion_solver;
34mod z3_subprocess;
35
36use std::{
37 collections::{HashMap, hash_map::DefaultHasher},
38 fmt::{self, Debug},
39 hash::{Hash, Hasher},
40 io,
41 str::FromStr,
42 time::Duration,
43};
44#[cfg(not(feature = "rust-fixpoint"))]
45use std::{
46 io::{BufWriter, Write as IOWrite},
47 process::{Command, Stdio},
48};
49
50pub use constraint::{
51 Axiom, BinOp, BinRel, Bind, Constant, Constraint, DataCtor, DataDecl, DataField, Expr,
52 FlatConstraint, FunSort, Pred, QualParam, Qualifier, Quantifier, Sort, SortCtor, SortDecl,
53 WKVar,
54};
55use derive_where::derive_where;
56#[cfg(feature = "nightly")]
57use rustc_macros::{Decodable, Encodable};
58use serde::{Deserialize, Serialize, de};
59
60pub type Assignments<'a, T> = HashMap<<T as Types>::KVar, Vec<(&'a Qualifier<T>, Vec<usize>)>>;
62
63#[cfg(not(feature = "rust-fixpoint"))]
64use process_control::{ChildExt, Control};
65
66#[cfg(feature = "rust-fixpoint")]
67use crate::constraint_with_env::ConstraintWithEnv;
68pub use crate::suggestion_solver::{SuggestionSolver, SuggestionSolverError};
69
70pub trait Types {
71 type Sort: Identifier + Hash + Clone + Debug + Eq;
72 type KVar: Identifier + Hash + Clone + Debug + Eq;
73 type Var: Identifier + Hash + Clone + Debug + Eq;
74 type String: FixpointFmt + Hash + Clone + Debug + Eq;
75 type Real: FixpointFmt + Hash + Clone + Debug + Eq;
76 type Tag: fmt::Display + FromStr + Hash + Clone + Debug;
77}
78
79pub trait FixpointFmt: Sized {
80 fn fmt(&self, f: &mut fmt::Formatter<'_>) -> fmt::Result;
81
82 fn display(&self) -> impl fmt::Display {
84 struct DisplayAdapter<T>(T);
85 impl<T: FixpointFmt> std::fmt::Display for DisplayAdapter<&T> {
86 fn fmt(&self, f: &mut fmt::Formatter<'_>) -> fmt::Result {
87 FixpointFmt::fmt(self.0, f)
88 }
89 }
90 DisplayAdapter(self)
91 }
92}
93
94pub trait Identifier: Sized {
95 fn fmt(&self, f: &mut fmt::Formatter<'_>) -> fmt::Result;
96
97 fn display(&self) -> impl fmt::Display {
99 struct DisplayAdapter<T>(T);
100 impl<T: Identifier> fmt::Display for DisplayAdapter<&T> {
101 fn fmt(&self, f: &mut fmt::Formatter<'_>) -> fmt::Result {
102 Identifier::fmt(self.0, f)
103 }
104 }
105 DisplayAdapter(self)
106 }
107}
108
109impl Identifier for &str {
110 fn fmt(&self, f: &mut fmt::Formatter<'_>) -> fmt::Result {
111 write!(f, "{self}")
112 }
113}
114
115impl FixpointFmt for u32 {
116 fn fmt(&self, f: &mut fmt::Formatter<'_>) -> fmt::Result {
117 write!(f, "{self}")
118 }
119}
120
121impl FixpointFmt for String {
122 fn fmt(&self, f: &mut fmt::Formatter<'_>) -> fmt::Result {
123 write!(f, "\"{self}\"")
124 }
125}
126
127#[macro_export]
128macro_rules! declare_types {
129 ( type Sort = $sort:ty;
130 type KVar = $kvar:ty;
131 type Var = $var:ty;
132 type String = $str:ty;
133 type Real = $real:ty;
134 type Tag = $tag:ty;
135 ) => {
136 pub mod fixpoint_generated {
137 pub struct FixpointTypes;
138 pub type Expr = $crate::Expr<FixpointTypes>;
139 pub type Constraint = $crate::Constraint<FixpointTypes>;
140 pub type FlatConstraint = $crate::FlatConstraint<FixpointTypes>;
141 pub type KVarDecl = $crate::KVarDecl<FixpointTypes>;
142 pub type ConstDecl = $crate::ConstDecl<FixpointTypes>;
143 pub type FunDef = $crate::FunDef<FixpointTypes>;
144 pub type FunSort = $crate::FunSort<FixpointTypes>;
145 pub type FunBody = $crate::FunBody<FixpointTypes>;
146 pub type Task = $crate::Task<FixpointTypes>;
147 pub type Qualifier = $crate::Qualifier<FixpointTypes>;
148 pub type Axiom = $crate::Axiom<FixpointTypes>;
149 pub type QualParam = $crate::QualParam<FixpointTypes>;
150 pub type Sort = $crate::Sort<FixpointTypes>;
151 pub type SortCtor = $crate::SortCtor<FixpointTypes>;
152 pub type SortDecl = $crate::SortDecl<FixpointTypes>;
153 pub type DataDecl = $crate::DataDecl<FixpointTypes>;
154 pub type DataCtor = $crate::DataCtor<FixpointTypes>;
155 pub type DataField = $crate::DataField<FixpointTypes>;
156 pub type Bind = $crate::Bind<FixpointTypes>;
157 pub type Constant = $crate::Constant<FixpointTypes>;
158 pub type Pred = $crate::Pred<FixpointTypes>;
159 pub use $crate::{BinOp, BinRel, Quantifier, ThyFunc, WKVar};
160 }
161
162 impl $crate::Types for fixpoint_generated::FixpointTypes {
163 type Sort = $sort;
164 type KVar = $kvar;
165 type Var = $var;
166 type String = $str;
167 type Real = $real;
168 type Tag = $tag;
169 }
170 };
171}
172
173pub fn qe_and_simplify<T: Types>(
174 solver: &mut SuggestionSolver<T>,
175 constraint: &FlatConstraint<T>,
176 binder_consts: &[ConstDecl<T>],
177) -> Result<Expr<T>, SuggestionSolverError> {
178 solver.qe_and_simplify(constraint, binder_consts)
179}
180
181pub fn check_validity<T: Types>(
182 solver: &mut SuggestionSolver<T>,
183 constraint: &FlatConstraint<T>,
184) -> Result<bool, SuggestionSolverError> {
185 solver.check_validity(constraint)
186}
187
188#[derive_where(Hash, Clone, Debug)]
189pub struct ConstDecl<T: Types> {
190 pub name: T::Var,
191 pub sort: Sort<T>,
192 #[derive_where(skip)]
193 pub comment: Option<String>,
194}
195
196#[derive_where(Hash, Clone, Debug)]
197pub struct FunDef<T: Types> {
198 pub name: T::Var,
199 pub sort: FunSort<T>,
200 pub body: Option<FunBody<T>>,
201 #[derive_where(skip)]
202 pub comment: Option<String>,
203}
204
205#[derive_where(Hash, Clone, Debug)]
206pub struct FunBody<T: Types> {
207 pub args: Vec<T::Var>,
208 pub expr: Expr<T>,
209}
210
211#[derive_where(Hash)]
212pub struct Task<T: Types> {
213 #[derive_where(skip)]
214 pub comments: Vec<String>,
215 pub constants: Vec<ConstDecl<T>>,
216 pub data_decls: Vec<DataDecl<T>>,
217 pub define_funs: Vec<FunDef<T>>,
218 pub kvars: Vec<KVarDecl<T>>,
219 pub constraint: Constraint<T>,
220 pub qualifiers: Vec<Qualifier<T>>,
221 pub axioms: Vec<Axiom<T>>,
222 pub scrape_quals: bool,
223 pub solver: SmtSolver,
224}
225
226#[derive(Clone, Copy, Hash)]
227pub enum SmtSolver {
228 Z3,
229 CVC5,
230}
231
232impl fmt::Display for SmtSolver {
233 fn fmt(&self, f: &mut fmt::Formatter<'_>) -> fmt::Result {
234 match self {
235 SmtSolver::Z3 => write!(f, "z3"),
236 SmtSolver::CVC5 => write!(f, "cvc5"),
237 }
238 }
239}
240
241#[derive(Serialize, Deserialize, Debug, Clone)]
242#[serde(
243 tag = "tag",
244 content = "contents",
245 bound(deserialize = "Tag: FromStr", serialize = "Tag: ToString")
246)]
247pub enum FixpointStatus<Tag> {
248 Safe(Stats),
249 Unsafe(Stats, Vec<Error<Tag>>),
250 Crash(CrashInfo),
251}
252
253#[derive(Debug)]
255pub enum FixpointError {
256 Timeout,
258 Io(io::Error),
259}
260
261impl From<io::Error> for FixpointError {
262 fn from(err: io::Error) -> Self {
263 FixpointError::Io(err)
264 }
265}
266
267#[derive(Serialize, Deserialize, Debug, Clone, Default)]
268#[serde(tag = "tag", content = "contents")]
269pub enum LeanStatus {
270 #[default]
271 Invalid,
272 Valid(u64),
274}
275
276#[derive(Serialize, Deserialize, Debug, Clone)]
277#[serde(bound(deserialize = "Tag: FromStr", serialize = "Tag: ToString"))]
278pub struct VerificationResult<Tag> {
279 pub status: FixpointStatus<Tag>,
280 pub solution: Vec<KVarBind>,
281 #[serde(rename = "nonCutsSolution")]
282 pub non_cuts_solution: Vec<KVarBind>,
283 #[serde(default)]
284 pub lean_status: LeanStatus,
285}
286
287#[derive(Serialize, Deserialize, Debug, Clone)]
288pub struct KVarBind {
289 pub kvar: String,
290 pub val: String,
291}
292
293impl KVarBind {
294 pub fn dump(&self) -> String {
295 format!("{} := {}", self.kvar, self.val)
296 }
297}
298
299impl<Tag> FixpointStatus<Tag> {
300 pub fn is_safe(&self) -> bool {
301 matches!(self, FixpointStatus::Safe(_))
302 }
303
304 pub fn merge(self, other: FixpointStatus<Tag>) -> Self {
305 use FixpointStatus as FR;
306 match (self, other) {
307 (FR::Safe(stats1), FR::Safe(stats2)) => FR::Safe(stats1.merge(&stats2)),
308 (FR::Safe(stats1), FR::Unsafe(stats2, errors)) => {
309 FR::Unsafe(stats1.merge(&stats2), errors)
310 }
311 (FR::Unsafe(stats1, mut errors1), FR::Unsafe(stats2, errors2)) => {
312 errors1.extend(errors2);
313 FR::Unsafe(stats1.merge(&stats2), errors1)
314 }
315 (FR::Unsafe(stats1, errors), FR::Safe(stats2)) => {
316 FR::Unsafe(stats1.merge(&stats2), errors)
317 }
318 (FR::Crash(info1), FR::Crash(info2)) => FR::Crash(info1.merge(info2)),
319 (FR::Crash(info), _) => FR::Crash(info),
320 (_, FR::Crash(info)) => FR::Crash(info),
321 }
322 }
323}
324
325#[derive(Debug, Clone)]
326pub struct Error<Tag> {
327 pub id: i32,
328 pub tag: Tag,
329}
330
331#[derive(Debug, Serialize, Deserialize, Default, Clone)]
332#[serde(rename_all = "camelCase")]
333pub struct Stats {
334 pub num_cstr: i32,
335 pub num_iter: i32,
336 pub num_chck: i32,
337 pub num_vald: i32,
338}
339
340impl Stats {
341 pub fn merge(&self, other: &Stats) -> Self {
342 Stats {
343 num_cstr: self.num_cstr + other.num_cstr,
344 num_iter: self.num_iter + other.num_iter,
345 num_chck: self.num_chck + other.num_chck,
346 num_vald: self.num_vald + other.num_vald,
347 }
348 }
349}
350
351#[derive(Serialize, Deserialize, Debug, Clone)]
352pub struct CrashInfo(Vec<serde_json::Value>);
353
354impl CrashInfo {
355 pub fn merge(self, other: CrashInfo) -> Self {
356 let mut v = self.0;
357 v.extend(other.0);
358 CrashInfo(v)
359 }
360}
361
362#[derive_where(Debug, Clone, Hash)]
363pub struct KVarDecl<T: Types> {
364 pub kvid: T::KVar,
365 pub sorts: Vec<Sort<T>>,
366 pub self_args: usize,
370}
371
372impl<T: Types> Task<T> {
373 pub fn hash_with_default(&self) -> u64 {
374 let mut hasher = DefaultHasher::new();
375 self.hash(&mut hasher);
376 hasher.finish()
377 }
378
379 #[cfg(feature = "rust-fixpoint")]
381 pub fn run(
382 &self,
383 _timeout: Option<Duration>,
384 ) -> Result<VerificationResult<T::Tag>, FixpointError> {
385 let mut cstr_with_env = ConstraintWithEnv::new(
386 self.data_decls.clone(),
387 self.kvars.clone(),
388 self.qualifiers.clone(),
389 self.constants.clone(),
390 self.constraint.clone(),
391 );
392 Ok(VerificationResult {
393 status: cstr_with_env.is_satisfiable(),
394 solution: vec![],
395 non_cuts_solution: vec![],
396 lean_status: LeanStatus::default(),
397 })
398 }
399
400 #[cfg(not(feature = "rust-fixpoint"))]
403 pub fn run(
404 &self,
405 timeout: Option<Duration>,
406 ) -> Result<VerificationResult<T::Tag>, FixpointError> {
407 let mut child = Command::new("fixpoint")
408 .arg("-q")
409 .arg("--stdin")
410 .arg("--sorted-solution")
411 .arg("--json")
412 .arg("--allowho")
413 .arg("--allowhoqs")
414 .arg(format!("--solver={}", self.solver))
415 .stdin(Stdio::piped())
416 .stdout(Stdio::piped())
417 .stderr(Stdio::piped())
418 .spawn()?;
419 let mut stdin = None;
420 std::mem::swap(&mut stdin, &mut child.stdin);
421 {
422 let mut w = BufWriter::new(stdin.unwrap());
423 writeln!(w, "{}", format::CompactTask(self))?;
425 }
426
427 let mut control = child.controlled_with_output();
428 if let Some(timeout) = timeout {
429 control = control.time_limit(timeout).terminate_for_timeout();
430 }
431 let out = control.wait()?.ok_or(FixpointError::Timeout)?;
432
433 serde_json::from_slice(&out.stdout).map_err(|err| {
434 if !out.stderr.is_empty() {
437 let stderr = std::str::from_utf8(&out.stderr)
438 .unwrap_or("fixpoint exited with a non-zero return code");
439 FixpointError::Io(io::Error::other(stderr))
440 } else {
441 FixpointError::Io(err.into())
442 }
443 })
444 }
445}
446
447impl<T: Types> KVarDecl<T> {
448 pub fn new(kvid: T::KVar, sorts: Vec<Sort<T>>, self_args: usize) -> Self {
449 Self { kvid, sorts, self_args }
450 }
451}
452
453#[derive(Serialize, Deserialize)]
454struct ErrorInner(i32, String);
455
456impl<Tag: ToString> Serialize for Error<Tag> {
457 fn serialize<S>(&self, serializer: S) -> Result<S::Ok, S::Error>
458 where
459 S: serde::Serializer,
460 {
461 ErrorInner(self.id, self.tag.to_string()).serialize(serializer)
462 }
463}
464
465impl<'de, Tag: FromStr> Deserialize<'de> for Error<Tag> {
466 fn deserialize<D>(deserializer: D) -> Result<Self, D::Error>
467 where
468 D: serde::Deserializer<'de>,
469 {
470 let ErrorInner(id, tag) = Deserialize::deserialize(deserializer)?;
471 let tag = tag
472 .parse()
473 .map_err(|_| de::Error::invalid_value(de::Unexpected::Str(&tag), &"valid tag"))?;
474 Ok(Error { id, tag })
475 }
476}
477
478#[derive(Clone, Copy, PartialEq, Eq, Hash, Debug)]
479#[cfg_attr(feature = "nightly", derive(Encodable, Decodable))]
480pub enum ThyFunc {
481 StrLen,
483 StrConcat,
484 StrPrefixOf,
485 StrSuffixOf,
486 StrContains,
487
488 BvZeroExtend(u8),
490 BvSignExtend(u8),
491 IntToBv8,
492 Bv8ToInt,
493 IntToBv32,
494 Bv32ToInt,
495 IntToBv64,
496 Bv64ToInt,
497 IntToBv128,
498 Bv128ToInt,
499 BvUle,
500 BvSle,
501 BvUge,
502 BvSge,
503 BvUdiv,
504 BvSdiv,
505 BvSrem,
506 BvUrem,
507 BvLshr,
508 BvAshr,
509 BvAnd,
510 BvOr,
511 BvXor,
512 BvNot,
513 BvAdd,
514 BvNeg,
515 BvSub,
516 BvMul,
517 BvShl,
518 BvUgt,
519 BvSgt,
520 BvUlt,
521 BvSlt,
522
523 SetEmpty,
526 SetSng,
528 SetCup,
530 SetCap,
532 SetDif,
534 SetSub,
536 SetMem,
538
539 MapDefault,
542 MapSelect,
544 MapStore,
546}
547
548impl ThyFunc {
549 pub const ALL: [ThyFunc; 46] = [
550 ThyFunc::StrLen,
551 ThyFunc::StrConcat,
552 ThyFunc::StrPrefixOf,
553 ThyFunc::StrSuffixOf,
554 ThyFunc::StrContains,
555 ThyFunc::IntToBv8,
556 ThyFunc::Bv8ToInt,
557 ThyFunc::IntToBv32,
558 ThyFunc::Bv32ToInt,
559 ThyFunc::IntToBv64,
560 ThyFunc::Bv64ToInt,
561 ThyFunc::IntToBv128,
562 ThyFunc::Bv128ToInt,
563 ThyFunc::BvAdd,
564 ThyFunc::BvNeg,
565 ThyFunc::BvSub,
566 ThyFunc::BvShl,
567 ThyFunc::BvLshr,
568 ThyFunc::BvAshr,
569 ThyFunc::BvMul,
570 ThyFunc::BvUdiv,
571 ThyFunc::BvSdiv,
572 ThyFunc::BvUrem,
573 ThyFunc::BvSrem,
574 ThyFunc::BvAnd,
575 ThyFunc::BvOr,
576 ThyFunc::BvXor,
577 ThyFunc::BvNot,
578 ThyFunc::BvUle,
579 ThyFunc::BvSle,
580 ThyFunc::BvUge,
581 ThyFunc::BvSge,
582 ThyFunc::BvUgt,
583 ThyFunc::BvSgt,
584 ThyFunc::BvUlt,
585 ThyFunc::BvSlt,
586 ThyFunc::SetEmpty,
587 ThyFunc::SetSng,
588 ThyFunc::SetCup,
589 ThyFunc::SetMem,
590 ThyFunc::SetCap,
591 ThyFunc::SetDif,
592 ThyFunc::SetSub,
593 ThyFunc::MapDefault,
594 ThyFunc::MapSelect,
595 ThyFunc::MapStore,
596 ];
597}
598
599impl fmt::Display for ThyFunc {
600 fn fmt(&self, f: &mut fmt::Formatter<'_>) -> fmt::Result {
601 match self {
602 ThyFunc::StrLen => write!(f, "strLen"),
603 ThyFunc::StrConcat => write!(f, "strConcat"),
604 ThyFunc::StrPrefixOf => write!(f, "strPrefixOf"),
605 ThyFunc::StrSuffixOf => write!(f, "strSuffixOf"),
606 ThyFunc::StrContains => write!(f, "strContains"),
607 ThyFunc::BvZeroExtend(size) => {
608 write!(f, "app (_ zero_extend {size})")
610 }
611 ThyFunc::BvSignExtend(size) => write!(f, "app (_ sign_extend {size})"),
612 ThyFunc::IntToBv32 => write!(f, "int_to_bv32"),
613 ThyFunc::Bv32ToInt => write!(f, "bv32_to_int"),
614 ThyFunc::IntToBv8 => write!(f, "int_to_bv8"),
615 ThyFunc::Bv8ToInt => write!(f, "bv8_to_int"),
616 ThyFunc::IntToBv64 => write!(f, "int_to_bv64"),
617 ThyFunc::Bv64ToInt => write!(f, "bv64_to_int"),
618 ThyFunc::IntToBv128 => write!(f, "int_to_bv128"),
619 ThyFunc::Bv128ToInt => write!(f, "bv128_to_int"),
620 ThyFunc::BvUle => write!(f, "bvule"),
621 ThyFunc::BvSle => write!(f, "bvsle"),
622 ThyFunc::BvUge => write!(f, "bvuge"),
623 ThyFunc::BvSge => write!(f, "bvsge"),
624 ThyFunc::BvUdiv => write!(f, "bvudiv"),
625 ThyFunc::BvSdiv => write!(f, "bvsdiv"),
626 ThyFunc::BvUrem => write!(f, "bvurem"),
627 ThyFunc::BvSrem => write!(f, "bvsrem"),
628 ThyFunc::BvLshr => write!(f, "bvlshr"),
629 ThyFunc::BvAshr => write!(f, "bvashr"),
630 ThyFunc::BvAnd => write!(f, "bvand"),
631 ThyFunc::BvOr => write!(f, "bvor"),
632 ThyFunc::BvXor => write!(f, "bvxor"),
633 ThyFunc::BvNot => write!(f, "bvnot"),
634 ThyFunc::BvAdd => write!(f, "bvadd"),
635 ThyFunc::BvNeg => write!(f, "bvneg"),
636 ThyFunc::BvSub => write!(f, "bvsub"),
637 ThyFunc::BvMul => write!(f, "bvmul"),
638 ThyFunc::BvShl => write!(f, "bvshl"),
639 ThyFunc::BvUgt => write!(f, "bvugt"),
640 ThyFunc::BvSgt => write!(f, "bvsgt"),
641 ThyFunc::BvUlt => write!(f, "bvult"),
642 ThyFunc::BvSlt => write!(f, "bvslt"),
643 ThyFunc::SetEmpty => write!(f, "Set_empty"),
644 ThyFunc::SetSng => write!(f, "Set_sng"),
645 ThyFunc::SetCup => write!(f, "Set_cup"),
646 ThyFunc::SetCap => write!(f, "Set_cap"),
647 ThyFunc::SetDif => write!(f, "Set_dif"),
648 ThyFunc::SetMem => write!(f, "Set_mem"),
649 ThyFunc::SetSub => write!(f, "Set_sub"),
650 ThyFunc::MapDefault => write!(f, "Map_default"),
651 ThyFunc::MapSelect => write!(f, "Map_select"),
652 ThyFunc::MapStore => write!(f, "Map_store"),
653 }
654 }
655}
656
657impl FromStr for ThyFunc {
658 type Err = String;
659 fn from_str(s: &str) -> Result<Self, Self::Err> {
660 match s {
661 "strLen" => Ok(ThyFunc::StrLen),
662 "int_to_bv32" => Ok(ThyFunc::IntToBv32),
663 "bv32_to_int" => Ok(ThyFunc::Bv32ToInt),
664 "int_to_bv8" => Ok(ThyFunc::IntToBv8),
665 "bv8_to_int" => Ok(ThyFunc::Bv8ToInt),
666 "int_to_bv64" => Ok(ThyFunc::IntToBv64),
667 "bv64_to_int" => Ok(ThyFunc::Bv64ToInt),
668 "int_to_bv128" => Ok(ThyFunc::IntToBv128),
669 "bv128_to_int" => Ok(ThyFunc::Bv128ToInt),
670 "bvule" => Ok(ThyFunc::BvUle),
671 "bvsle" => Ok(ThyFunc::BvSle),
672 "bvuge" => Ok(ThyFunc::BvUge),
673 "bvsge" => Ok(ThyFunc::BvSge),
674 "bvudiv" => Ok(ThyFunc::BvUdiv),
675 "bvsdiv" => Ok(ThyFunc::BvSdiv),
676 "bvurem" => Ok(ThyFunc::BvUrem),
677 "bvsrem" => Ok(ThyFunc::BvSrem),
678 "bvlshr" => Ok(ThyFunc::BvLshr),
679 "bvashr" => Ok(ThyFunc::BvAshr),
680 "bvand" => Ok(ThyFunc::BvAnd),
681 "bvor" => Ok(ThyFunc::BvOr),
682 "bvxor" => Ok(ThyFunc::BvXor),
683 "bvnot" => Ok(ThyFunc::BvNot),
684 "bvadd" => Ok(ThyFunc::BvAdd),
685 "bvneg" => Ok(ThyFunc::BvNeg),
686 "bvsub" => Ok(ThyFunc::BvSub),
687 "bvmul" => Ok(ThyFunc::BvMul),
688 "bvshl" => Ok(ThyFunc::BvShl),
689 "bvugt" => Ok(ThyFunc::BvUgt),
690 "bvsgt" => Ok(ThyFunc::BvSgt),
691 "bvult" => Ok(ThyFunc::BvUlt),
692 "bvslt" => Ok(ThyFunc::BvSlt),
693 "Set_empty" => Ok(ThyFunc::SetEmpty),
694 "Set_sng" => Ok(ThyFunc::SetSng),
695 "Set_cup" => Ok(ThyFunc::SetCup),
696 "Set_mem" => Ok(ThyFunc::SetMem),
697 "Map_default" => Ok(ThyFunc::MapDefault),
698 "Map_select" => Ok(ThyFunc::MapSelect),
699 "Map_store" => Ok(ThyFunc::MapStore),
700 _ => Err(format!("Unexpected ThyFunc {}", s)),
705 }
706 }
707}