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