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