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