use std::cmp::{Eq, PartialEq};
use std::convert::{TryFrom, TryInto};
use std::ffi::{CStr, CString};
use std::fmt;
use std::hash::{Hash, Hasher};
use z3_sys::*;
use Context;
use FuncDecl;
use IsNotApp;
use Pattern;
use Sort;
use SortDiffers;
use Symbol;
pub use z3_sys::AstKind;
#[cfg(feature = "arbitrary-size-numeral")]
use num::bigint::BigInt;
#[cfg(feature = "arbitrary-size-numeral")]
use num::rational::BigRational;
pub struct Bool<'ctx> {
pub(crate) ctx: &'ctx Context,
pub(crate) z3_ast: Z3_ast,
}
pub struct Int<'ctx> {
pub(crate) ctx: &'ctx Context,
pub(crate) z3_ast: Z3_ast,
}
pub struct Real<'ctx> {
pub(crate) ctx: &'ctx Context,
pub(crate) z3_ast: Z3_ast,
}
pub struct Float<'ctx> {
pub(crate) ctx: &'ctx Context,
pub(crate) z3_ast: Z3_ast,
}
pub struct String<'ctx> {
pub(crate) ctx: &'ctx Context,
pub(crate) z3_ast: Z3_ast,
}
pub struct BV<'ctx> {
pub(crate) ctx: &'ctx Context,
pub(crate) z3_ast: Z3_ast,
}
pub struct Array<'ctx> {
pub(crate) ctx: &'ctx Context,
pub(crate) z3_ast: Z3_ast,
}
pub struct Set<'ctx> {
pub(crate) ctx: &'ctx Context,
pub(crate) z3_ast: Z3_ast,
}
pub struct Datatype<'ctx> {
pub(crate) ctx: &'ctx Context,
pub(crate) z3_ast: Z3_ast,
}
pub struct Dynamic<'ctx> {
pub(crate) ctx: &'ctx Context,
pub(crate) z3_ast: Z3_ast,
}
pub struct Regexp<'ctx> {
pub(crate) ctx: &'ctx Context,
pub(crate) z3_ast: Z3_ast,
}
macro_rules! unop {
(
$(
$( #[ $attr:meta ] )* $f:ident ( $z3fn:ident, $retty:ty ) ;
)*
) => {
$(
$( #[ $attr ] )*
pub fn $f(&self) -> $retty {
unsafe {
<$retty>::wrap(self.ctx, {
$z3fn(self.ctx.z3_ctx, self.z3_ast)
})
}
}
)*
};
}
macro_rules! binop {
(
$(
$( #[ $attr:meta ] )* $f:ident ( $z3fn:ident, $retty:ty ) ;
)*
) => {
$(
$( #[ $attr ] )*
pub fn $f(&self, other: &Self) -> $retty {
assert!(self.ctx == other.ctx);
unsafe {
<$retty>::wrap(self.ctx, {
$z3fn(self.ctx.z3_ctx, self.z3_ast, other.z3_ast)
})
}
}
)*
};
}
macro_rules! trinop {
(
$(
$( #[ $attr:meta ] )* $f:ident ( $z3fn:ident, $retty:ty ) ;
)*
) => {
$(
$( #[ $attr ] )*
pub fn $f(&self, a: &Self, b: &Self) -> $retty {
assert!((self.ctx == a.ctx) && (a.ctx == b.ctx));
unsafe {
<$retty>::wrap(self.ctx, {
$z3fn(self.ctx.z3_ctx, self.z3_ast, a.z3_ast, b.z3_ast)
})
}
}
)*
};
}
macro_rules! varop {
(
$(
$( #[ $attr:meta ] )* $f:ident ( $z3fn:ident, $retty:ty ) ;
)*
) => {
$(
$( #[ $attr ] )*
pub fn $f(ctx: &'ctx Context, values: &[&Self]) -> $retty {
assert!(values.iter().all(|v| v.get_ctx().z3_ctx == ctx.z3_ctx));
unsafe {
<$retty>::wrap(ctx, {
let tmp: Vec<_> = values.iter().map(|x| x.z3_ast).collect();
assert!(tmp.len() <= 0xffff_ffff);
$z3fn(ctx.z3_ctx, tmp.len() as u32, tmp.as_ptr())
})
}
}
)*
};
}
pub trait Ast<'ctx>: fmt::Debug {
fn get_ctx(&self) -> &'ctx Context;
fn get_z3_ast(&self) -> Z3_ast;
unsafe fn wrap(ctx: &'ctx Context, ast: Z3_ast) -> Self
where
Self: Sized;
fn _eq(&self, other: &Self) -> Bool<'ctx>
where
Self: Sized,
{
self._safe_eq(other).unwrap()
}
fn _safe_eq(&self, other: &Self) -> Result<Bool<'ctx>, SortDiffers<'ctx>>
where
Self: Sized,
{
assert_eq!(self.get_ctx(), other.get_ctx());
let left_sort = self.get_sort();
let right_sort = other.get_sort();
match left_sort == right_sort {
true => Ok(unsafe {
Bool::wrap(self.get_ctx(), {
Z3_mk_eq(self.get_ctx().z3_ctx, self.get_z3_ast(), other.get_z3_ast())
})
}),
false => Err(SortDiffers::new(left_sort, right_sort)),
}
}
fn distinct(ctx: &'ctx Context, values: &[&Self]) -> Bool<'ctx>
where
Self: Sized,
{
unsafe {
Bool::wrap(ctx, {
assert!(values.len() <= 0xffffffff);
let values: Vec<Z3_ast> = values.iter().map(|nodes| nodes.get_z3_ast()).collect();
Z3_mk_distinct(ctx.z3_ctx, values.len() as u32, values.as_ptr())
})
}
}
fn get_sort(&self) -> Sort<'ctx> {
unsafe {
Sort::wrap(
self.get_ctx(),
Z3_get_sort(self.get_ctx().z3_ctx, self.get_z3_ast()),
)
}
}
fn simplify(&self) -> Self
where
Self: Sized,
{
unsafe {
Self::wrap(self.get_ctx(), {
Z3_simplify(self.get_ctx().z3_ctx, self.get_z3_ast())
})
}
}
fn substitute<T: Ast<'ctx>>(&self, substitutions: &[(&T, &T)]) -> Self
where
Self: Sized,
{
unsafe {
Self::wrap(self.get_ctx(), {
let this_ast = self.get_z3_ast();
let num_exprs = substitutions.len() as ::std::os::raw::c_uint;
let mut froms: Vec<_> = vec![];
let mut tos: Vec<_> = vec![];
for (from_ast, to_ast) in substitutions {
froms.push(from_ast.get_z3_ast());
tos.push(to_ast.get_z3_ast());
}
Z3_substitute(
self.get_ctx().z3_ctx,
this_ast,
num_exprs,
froms.as_ptr(),
tos.as_ptr(),
)
})
}
}
fn num_children(&self) -> usize {
let this_ctx = self.get_ctx().z3_ctx;
unsafe {
let this_app = Z3_to_app(this_ctx, self.get_z3_ast());
Z3_get_app_num_args(this_ctx, this_app) as usize
}
}
fn nth_child(&self, idx: usize) -> Option<Dynamic<'ctx>> {
if idx >= self.num_children() {
None
} else {
let idx = u32::try_from(idx).unwrap();
let this_ctx = self.get_ctx().z3_ctx;
let child_ast = unsafe {
let this_app = Z3_to_app(this_ctx, self.get_z3_ast());
Z3_get_app_arg(this_ctx, this_app, idx)
};
Some(unsafe { Dynamic::wrap(self.get_ctx(), child_ast) })
}
}
fn children(&self) -> Vec<Dynamic<'ctx>> {
let n = self.num_children();
(0..n).map(|i| self.nth_child(i).unwrap()).collect()
}
fn kind(&self) -> AstKind {
unsafe {
let z3_ctx = self.get_ctx().z3_ctx;
Z3_get_ast_kind(z3_ctx, self.get_z3_ast())
}
}
fn is_app(&self) -> bool {
let kind = self.kind();
kind == AstKind::Numeral || kind == AstKind::App
}
fn is_const(&self) -> bool {
self.is_app() && self.num_children() == 0
}
fn decl(&self) -> FuncDecl<'ctx> {
self.safe_decl().expect("Ast is not an app")
}
fn safe_decl(&self) -> Result<FuncDecl<'ctx>, IsNotApp> {
if !self.is_app() {
Err(IsNotApp::new(self.kind()))
} else {
let ctx = self.get_ctx();
let func_decl = unsafe {
let app = Z3_to_app(ctx.z3_ctx, self.get_z3_ast());
Z3_get_app_decl(ctx.z3_ctx, app)
};
Ok(unsafe { FuncDecl::wrap(ctx, func_decl) })
}
}
fn translate<'src_ctx>(&'src_ctx self, dest: &'ctx Context) -> Self
where
Self: Sized,
{
unsafe {
Self::wrap(dest, {
Z3_translate(self.get_ctx().z3_ctx, self.get_z3_ast(), dest.z3_ctx)
})
}
}
}
macro_rules! impl_ast {
($ast:ident) => {
impl<'ctx> Ast<'ctx> for $ast<'ctx> {
unsafe fn wrap(ctx: &'ctx Context, ast: Z3_ast) -> Self {
assert!(!ast.is_null());
Self {
ctx,
z3_ast: {
debug!(
"new ast: id = {}, pointer = {:p}",
Z3_get_ast_id(ctx.z3_ctx, ast),
ast
);
Z3_inc_ref(ctx.z3_ctx, ast);
ast
},
}
}
fn get_ctx(&self) -> &'ctx Context {
self.ctx
}
fn get_z3_ast(&self) -> Z3_ast {
self.z3_ast
}
}
impl<'ctx> From<$ast<'ctx>> for Z3_ast {
fn from(ast: $ast<'ctx>) -> Self {
ast.z3_ast
}
}
impl<'ctx> PartialEq for $ast<'ctx> {
fn eq(&self, other: &$ast<'ctx>) -> bool {
assert_eq!(self.ctx, other.ctx);
unsafe { Z3_is_eq_ast(self.ctx.z3_ctx, self.z3_ast, other.z3_ast) }
}
}
impl<'ctx> Eq for $ast<'ctx> {}
impl<'ctx> Clone for $ast<'ctx> {
fn clone(&self) -> Self {
debug!(
"clone ast: id = {}, pointer = {:p}",
unsafe { Z3_get_ast_id(self.ctx.z3_ctx, self.z3_ast) },
self.z3_ast
);
unsafe { Self::wrap(self.ctx, self.z3_ast) }
}
}
impl<'ctx> Drop for $ast<'ctx> {
fn drop(&mut self) {
debug!(
"drop ast: id = {}, pointer = {:p}",
unsafe { Z3_get_ast_id(self.ctx.z3_ctx, self.z3_ast) },
self.z3_ast
);
unsafe {
Z3_dec_ref(self.ctx.z3_ctx, self.z3_ast);
}
}
}
impl<'ctx> Hash for $ast<'ctx> {
fn hash<H: Hasher>(&self, state: &mut H) {
unsafe {
let u = Z3_get_ast_hash(self.ctx.z3_ctx, self.z3_ast);
u.hash(state);
}
}
}
impl<'ctx> fmt::Debug for $ast<'ctx> {
fn fmt(&self, f: &mut fmt::Formatter) -> Result<(), fmt::Error> {
let p = unsafe { Z3_ast_to_string(self.ctx.z3_ctx, self.z3_ast) };
if p.is_null() {
return Result::Err(fmt::Error);
}
match unsafe { CStr::from_ptr(p) }.to_str() {
Ok(s) => write!(f, "{}", s),
Err(_) => Result::Err(fmt::Error),
}
}
}
impl<'ctx> fmt::Display for $ast<'ctx> {
fn fmt(&self, f: &mut fmt::Formatter) -> Result<(), fmt::Error> {
<Self as fmt::Debug>::fmt(self, f)
}
}
};
}
macro_rules! impl_from_try_into_dynamic {
($ast:ident, $as_ast:ident) => {
impl<'ctx> From<$ast<'ctx>> for Dynamic<'ctx> {
fn from(ast: $ast<'ctx>) -> Self {
unsafe { Dynamic::wrap(ast.ctx, ast.z3_ast) }
}
}
impl<'ctx> From<&$ast<'ctx>> for Dynamic<'ctx> {
fn from(ast: &$ast<'ctx>) -> Self {
unsafe { Dynamic::wrap(ast.ctx, ast.z3_ast) }
}
}
impl<'ctx> TryFrom<Dynamic<'ctx>> for $ast<'ctx> {
type Error = std::string::String;
fn try_from(ast: Dynamic<'ctx>) -> Result<Self, std::string::String> {
ast.$as_ast()
.ok_or_else(|| format!("Dynamic is not of requested type: {:?}", ast))
}
}
};
}
impl_ast!(Bool);
impl_from_try_into_dynamic!(Bool, as_bool);
impl_ast!(Int);
impl_from_try_into_dynamic!(Int, as_int);
impl_ast!(Real);
impl_from_try_into_dynamic!(Real, as_real);
impl_ast!(Float);
impl_from_try_into_dynamic!(Float, as_float);
impl_ast!(String);
impl_from_try_into_dynamic!(String, as_string);
impl_ast!(BV);
impl_from_try_into_dynamic!(BV, as_bv);
impl_ast!(Array);
impl_from_try_into_dynamic!(Array, as_array);
impl_ast!(Set);
impl_from_try_into_dynamic!(Set, as_set);
impl_ast!(Regexp);
impl<'ctx> Int<'ctx> {
#[cfg(feature = "arbitrary-size-numeral")]
pub fn from_big_int(ctx: &'ctx Context, value: &BigInt) -> Int<'ctx> {
Int::from_str(ctx, &value.to_str_radix(10)).unwrap()
}
pub fn from_str(ctx: &'ctx Context, value: &str) -> Option<Int<'ctx>> {
let sort = Sort::int(ctx);
let ast = unsafe {
let int_cstring = CString::new(value).unwrap();
let numeral_ptr = Z3_mk_numeral(ctx.z3_ctx, int_cstring.as_ptr(), sort.z3_sort);
if numeral_ptr.is_null() {
return None;
}
numeral_ptr
};
Some(unsafe { Int::wrap(ctx, ast) })
}
}
impl<'ctx> Real<'ctx> {
#[cfg(feature = "arbitrary-size-numeral")]
pub fn from_big_rational(ctx: &'ctx Context, value: &BigRational) -> Real<'ctx> {
let num = value.numer();
let den = value.denom();
Real::from_real_str(ctx, &num.to_str_radix(10), &den.to_str_radix(10)).unwrap()
}
pub fn from_real_str(ctx: &'ctx Context, num: &str, den: &str) -> Option<Real<'ctx>> {
let sort = Sort::real(ctx);
let ast = unsafe {
let fraction_cstring = CString::new(format!("{:} / {:}", num, den)).unwrap();
let numeral_ptr = Z3_mk_numeral(ctx.z3_ctx, fraction_cstring.as_ptr(), sort.z3_sort);
if numeral_ptr.is_null() {
return None;
}
numeral_ptr
};
Some(unsafe { Real::wrap(ctx, ast) })
}
}
impl<'ctx> Float<'ctx> {
pub fn from_f32(ctx: &'ctx Context, value: f32) -> Float<'ctx> {
let sort = Sort::float32(ctx);
unsafe {
Self::wrap(ctx, {
Z3_mk_fpa_numeral_float(ctx.z3_ctx, value, sort.z3_sort)
})
}
}
pub fn from_f64(ctx: &'ctx Context, value: f64) -> Float<'ctx> {
let sort = Sort::double(ctx);
unsafe {
Self::wrap(ctx, {
Z3_mk_fpa_numeral_double(ctx.z3_ctx, value, sort.z3_sort)
})
}
}
}
impl_ast!(Datatype);
impl_from_try_into_dynamic!(Datatype, as_datatype);
impl_ast!(Dynamic);
impl<'ctx> Bool<'ctx> {
pub fn new_const<S: Into<Symbol>>(ctx: &'ctx Context, name: S) -> Bool<'ctx> {
let sort = Sort::bool(ctx);
unsafe {
Self::wrap(ctx, {
Z3_mk_const(ctx.z3_ctx, name.into().as_z3_symbol(ctx), sort.z3_sort)
})
}
}
pub fn fresh_const(ctx: &'ctx Context, prefix: &str) -> Bool<'ctx> {
let sort = Sort::bool(ctx);
unsafe {
Self::wrap(ctx, {
let pp = CString::new(prefix).unwrap();
let p = pp.as_ptr();
Z3_mk_fresh_const(ctx.z3_ctx, p, sort.z3_sort)
})
}
}
pub fn from_bool(ctx: &'ctx Context, b: bool) -> Bool<'ctx> {
unsafe {
Self::wrap(ctx, {
if b {
Z3_mk_true(ctx.z3_ctx)
} else {
Z3_mk_false(ctx.z3_ctx)
}
})
}
}
pub fn as_bool(&self) -> Option<bool> {
unsafe {
match Z3_get_bool_value(self.ctx.z3_ctx, self.z3_ast) {
Z3_L_TRUE => Some(true),
Z3_L_FALSE => Some(false),
_ => None,
}
}
}
pub fn ite<T>(&self, a: &T, b: &T) -> T
where
T: Ast<'ctx>,
{
unsafe {
T::wrap(self.ctx, {
Z3_mk_ite(self.ctx.z3_ctx, self.z3_ast, a.get_z3_ast(), b.get_z3_ast())
})
}
}
varop! {
and(Z3_mk_and, Self);
or(Z3_mk_or, Self);
}
binop! {
xor(Z3_mk_xor, Self);
iff(Z3_mk_iff, Self);
implies(Z3_mk_implies, Self);
}
unop! {
not(Z3_mk_not, Self);
}
pub fn pb_le(ctx: &'ctx Context, values: &[(&Bool<'ctx>, i32)], k: i32) -> Bool<'ctx> {
unsafe {
Bool::wrap(ctx, {
assert!(values.len() <= 0xffffffff);
let (values, coefficients): (Vec<Z3_ast>, Vec<i32>) = values
.iter()
.map(|(boolean, coefficient)| (boolean.z3_ast, coefficient))
.unzip();
Z3_mk_pble(
ctx.z3_ctx,
values.len() as u32,
values.as_ptr(),
coefficients.as_ptr(),
k,
)
})
}
}
pub fn pb_ge(ctx: &'ctx Context, values: &[(&Bool<'ctx>, i32)], k: i32) -> Bool<'ctx> {
unsafe {
Bool::wrap(ctx, {
assert!(values.len() <= 0xffffffff);
let (values, coefficients): (Vec<Z3_ast>, Vec<i32>) = values
.iter()
.map(|(boolean, coefficient)| (boolean.z3_ast, coefficient))
.unzip();
Z3_mk_pbge(
ctx.z3_ctx,
values.len() as u32,
values.as_ptr(),
coefficients.as_ptr(),
k,
)
})
}
}
pub fn pb_eq(ctx: &'ctx Context, values: &[(&Bool<'ctx>, i32)], k: i32) -> Bool<'ctx> {
unsafe {
Bool::wrap(ctx, {
assert!(values.len() <= 0xffffffff);
let (values, coefficients): (Vec<Z3_ast>, Vec<i32>) = values
.iter()
.map(|(boolean, coefficient)| (boolean.z3_ast, coefficient))
.unzip();
Z3_mk_pbeq(
ctx.z3_ctx,
values.len() as u32,
values.as_ptr(),
coefficients.as_ptr(),
k,
)
})
}
}
}
impl<'ctx> Int<'ctx> {
pub fn new_const<S: Into<Symbol>>(ctx: &'ctx Context, name: S) -> Int<'ctx> {
let sort = Sort::int(ctx);
unsafe {
Self::wrap(ctx, {
Z3_mk_const(ctx.z3_ctx, name.into().as_z3_symbol(ctx), sort.z3_sort)
})
}
}
pub fn fresh_const(ctx: &'ctx Context, prefix: &str) -> Int<'ctx> {
let sort = Sort::int(ctx);
unsafe {
Self::wrap(ctx, {
let pp = CString::new(prefix).unwrap();
let p = pp.as_ptr();
Z3_mk_fresh_const(ctx.z3_ctx, p, sort.z3_sort)
})
}
}
pub fn from_i64(ctx: &'ctx Context, i: i64) -> Int<'ctx> {
let sort = Sort::int(ctx);
unsafe { Self::wrap(ctx, Z3_mk_int64(ctx.z3_ctx, i, sort.z3_sort)) }
}
pub fn from_u64(ctx: &'ctx Context, u: u64) -> Int<'ctx> {
let sort = Sort::int(ctx);
unsafe { Self::wrap(ctx, Z3_mk_unsigned_int64(ctx.z3_ctx, u, sort.z3_sort)) }
}
pub fn as_i64(&self) -> Option<i64> {
unsafe {
let mut tmp: ::std::os::raw::c_longlong = 0;
if Z3_get_numeral_int64(self.ctx.z3_ctx, self.z3_ast, &mut tmp) {
Some(tmp)
} else {
None
}
}
}
pub fn as_u64(&self) -> Option<u64> {
unsafe {
let mut tmp: ::std::os::raw::c_ulonglong = 0;
if Z3_get_numeral_uint64(self.ctx.z3_ctx, self.z3_ast, &mut tmp) {
Some(tmp)
} else {
None
}
}
}
pub fn from_real(ast: &Real<'ctx>) -> Int<'ctx> {
unsafe { Self::wrap(ast.ctx, Z3_mk_real2int(ast.ctx.z3_ctx, ast.z3_ast)) }
}
pub fn to_real(&self) -> Real<'ctx> {
Real::from_int(self)
}
pub fn from_bv(ast: &BV<'ctx>, signed: bool) -> Int<'ctx> {
unsafe {
Self::wrap(ast.ctx, {
Z3_mk_bv2int(ast.ctx.z3_ctx, ast.z3_ast, signed)
})
}
}
pub fn to_ast(&self, sz: u32) -> BV<'ctx> {
BV::from_int(self, sz)
}
varop! {
add(Z3_mk_add, Self);
sub(Z3_mk_sub, Self);
mul(Z3_mk_mul, Self);
}
unop! {
unary_minus(Z3_mk_unary_minus, Self);
}
binop! {
div(Z3_mk_div, Self);
rem(Z3_mk_rem, Self);
modulo(Z3_mk_mod, Self);
power(Z3_mk_power, Real<'ctx>);
lt(Z3_mk_lt, Bool<'ctx>);
le(Z3_mk_le, Bool<'ctx>);
gt(Z3_mk_gt, Bool<'ctx>);
ge(Z3_mk_ge, Bool<'ctx>);
}
}
impl<'ctx> Real<'ctx> {
pub fn new_const<S: Into<Symbol>>(ctx: &'ctx Context, name: S) -> Real<'ctx> {
let sort = Sort::real(ctx);
unsafe {
Self::wrap(ctx, {
Z3_mk_const(ctx.z3_ctx, name.into().as_z3_symbol(ctx), sort.z3_sort)
})
}
}
pub fn fresh_const(ctx: &'ctx Context, prefix: &str) -> Real<'ctx> {
let sort = Sort::real(ctx);
unsafe {
Self::wrap(ctx, {
let pp = CString::new(prefix).unwrap();
let p = pp.as_ptr();
Z3_mk_fresh_const(ctx.z3_ctx, p, sort.z3_sort)
})
}
}
pub fn from_real(ctx: &'ctx Context, num: i32, den: i32) -> Real<'ctx> {
unsafe {
Self::wrap(ctx, {
Z3_mk_real(
ctx.z3_ctx,
num as ::std::os::raw::c_int,
den as ::std::os::raw::c_int,
)
})
}
}
pub fn as_real(&self) -> Option<(i64, i64)> {
unsafe {
let mut num: i64 = 0;
let mut den: i64 = 0;
if Z3_get_numeral_small(self.ctx.z3_ctx, self.z3_ast, &mut num, &mut den) {
Some((num, den))
} else {
None
}
}
}
pub fn from_int(ast: &Int<'ctx>) -> Real<'ctx> {
unsafe { Self::wrap(ast.ctx, Z3_mk_int2real(ast.ctx.z3_ctx, ast.z3_ast)) }
}
pub fn to_int(&self) -> Int<'ctx> {
Int::from_real(self)
}
unop! {
is_int(Z3_mk_is_int, Bool<'ctx>);
}
varop! {
add(Z3_mk_add, Self);
sub(Z3_mk_sub, Self);
mul(Z3_mk_mul, Self);
}
unop! {
unary_minus(Z3_mk_unary_minus, Self);
}
binop! {
div(Z3_mk_div, Self);
power(Z3_mk_power, Self);
lt(Z3_mk_lt, Bool<'ctx>);
le(Z3_mk_le, Bool<'ctx>);
gt(Z3_mk_gt, Bool<'ctx>);
ge(Z3_mk_ge, Bool<'ctx>);
}
}
impl<'ctx> Float<'ctx> {
pub fn new_const<S: Into<Symbol>>(
ctx: &'ctx Context,
name: S,
ebits: u32,
sbits: u32,
) -> Float<'ctx> {
let sort = Sort::float(ctx, ebits, sbits);
unsafe {
Self::wrap(ctx, {
Z3_mk_const(ctx.z3_ctx, name.into().as_z3_symbol(ctx), sort.z3_sort)
})
}
}
pub fn new_const_float32<S: Into<Symbol>>(ctx: &'ctx Context, name: S) -> Float<'ctx> {
let sort = Sort::float32(ctx);
unsafe {
Self::wrap(ctx, {
Z3_mk_const(ctx.z3_ctx, name.into().as_z3_symbol(ctx), sort.z3_sort)
})
}
}
pub fn new_const_double<S: Into<Symbol>>(ctx: &'ctx Context, name: S) -> Float<'ctx> {
let sort = Sort::double(ctx);
unsafe {
Self::wrap(ctx, {
Z3_mk_const(ctx.z3_ctx, name.into().as_z3_symbol(ctx), sort.z3_sort)
})
}
}
pub fn fresh_const(ctx: &'ctx Context, prefix: &str, ebits: u32, sbits: u32) -> Float<'ctx> {
let sort = Sort::float(ctx, ebits, sbits);
unsafe {
Self::wrap(ctx, {
let pp = CString::new(prefix).unwrap();
let p = pp.as_ptr();
Z3_mk_fresh_const(ctx.z3_ctx, p, sort.z3_sort)
})
}
}
pub fn fresh_const_float32(ctx: &'ctx Context, prefix: &str) -> Float<'ctx> {
let sort = Sort::float32(ctx);
unsafe {
Self::wrap(ctx, {
let pp = CString::new(prefix).unwrap();
let p = pp.as_ptr();
Z3_mk_fresh_const(ctx.z3_ctx, p, sort.z3_sort)
})
}
}
pub fn fresh_const_double(ctx: &'ctx Context, prefix: &str) -> Float<'ctx> {
let sort = Sort::double(ctx);
unsafe {
Self::wrap(ctx, {
let pp = CString::new(prefix).unwrap();
let p = pp.as_ptr();
Z3_mk_fresh_const(ctx.z3_ctx, p, sort.z3_sort)
})
}
}
pub fn round_towards_zero(ctx: &'ctx Context) -> Float<'ctx> {
unsafe { Self::wrap(ctx, Z3_mk_fpa_round_toward_zero(ctx.z3_ctx)) }
}
pub fn round_towards_negative(ctx: &'ctx Context) -> Float<'ctx> {
unsafe { Self::wrap(ctx, Z3_mk_fpa_round_toward_negative(ctx.z3_ctx)) }
}
pub fn round_towards_positive(ctx: &'ctx Context) -> Float<'ctx> {
unsafe { Self::wrap(ctx, Z3_mk_fpa_round_toward_positive(ctx.z3_ctx)) }
}
pub fn add_towards_zero(&self, other: &Self) -> Float<'ctx> {
Self::round_towards_zero(self.ctx).add(self, other)
}
pub fn sub_towards_zero(&self, other: &Self) -> Float<'ctx> {
Self::round_towards_zero(self.ctx).sub(self, other)
}
pub fn mul_towards_zero(&self, other: &Self) -> Float<'ctx> {
Self::round_towards_zero(self.ctx).mul(self, other)
}
pub fn div_towards_zero(&self, other: &Self) -> Float<'ctx> {
Self::round_towards_zero(self.ctx).div(self, other)
}
unop! {
unary_abs(Z3_mk_fpa_abs, Self);
unary_neg(Z3_mk_fpa_neg, Self);
}
binop! {
lt(Z3_mk_fpa_lt, Bool<'ctx>);
le(Z3_mk_fpa_leq, Bool<'ctx>);
gt(Z3_mk_fpa_gt, Bool<'ctx>);
ge(Z3_mk_fpa_geq, Bool<'ctx>);
}
trinop! {
add(Z3_mk_fpa_add, Self);
sub(Z3_mk_fpa_sub, Self);
mul(Z3_mk_fpa_mul, Self);
div(Z3_mk_fpa_div, Self);
}
}
impl<'ctx> String<'ctx> {
pub fn new_const<S: Into<Symbol>>(ctx: &'ctx Context, name: S) -> String<'ctx> {
let sort = Sort::string(ctx);
unsafe {
Self::wrap(ctx, {
Z3_mk_const(ctx.z3_ctx, name.into().as_z3_symbol(ctx), sort.z3_sort)
})
}
}
pub fn fresh_const(ctx: &'ctx Context, prefix: &str) -> String<'ctx> {
let sort = Sort::string(ctx);
unsafe {
Self::wrap(ctx, {
let pp = CString::new(prefix).unwrap();
let p = pp.as_ptr();
Z3_mk_fresh_const(ctx.z3_ctx, p, sort.z3_sort)
})
}
}
pub fn from_str(ctx: &'ctx Context, string: &str) -> Result<String<'ctx>, std::ffi::NulError> {
let string = CString::new(string)?;
Ok(unsafe {
Self::wrap(ctx, {
Z3_mk_string(ctx.z3_ctx, string.as_c_str().as_ptr())
})
})
}
pub fn as_string(&self) -> Option<std::string::String> {
let z3_ctx = self.get_ctx().z3_ctx;
unsafe {
let bytes = Z3_get_string(z3_ctx, self.get_z3_ast());
if bytes.is_null() {
None
} else {
Some(CStr::from_ptr(bytes).to_string_lossy().into_owned())
}
}
}
pub fn regex_matches(&self, regex: &Regexp) -> Bool<'ctx> {
assert!(self.ctx == regex.ctx);
unsafe {
Bool::wrap(
self.ctx,
Z3_mk_seq_in_re(self.ctx.z3_ctx, self.get_z3_ast(), regex.get_z3_ast()),
)
}
}
varop! {
concat(Z3_mk_seq_concat, String<'ctx>);
}
binop! {
contains(Z3_mk_seq_contains, Bool<'ctx>);
prefix(Z3_mk_seq_prefix, Bool<'ctx>);
suffix(Z3_mk_seq_suffix, Bool<'ctx>);
}
}
macro_rules! bv_overflow_check_signed {
(
$(
$( #[ $attr:meta ] )* $f:ident ( $z3fn:ident ) ;
)*
) => {
$(
$( #[ $attr ] )*
pub fn $f(&self, other: &BV<'ctx>, b: bool) -> Bool<'ctx> {
unsafe {
Ast::wrap(self.ctx, {
$z3fn(self.ctx.z3_ctx, self.z3_ast, other.z3_ast, b)
})
}
}
)*
};
}
impl<'ctx> BV<'ctx> {
pub fn from_str(ctx: &'ctx Context, sz: u32, value: &str) -> Option<BV<'ctx>> {
let sort = Sort::bitvector(ctx, sz);
let ast = unsafe {
let bv_cstring = CString::new(value).unwrap();
let numeral_ptr = Z3_mk_numeral(ctx.z3_ctx, bv_cstring.as_ptr(), sort.z3_sort);
if numeral_ptr.is_null() {
return None;
}
numeral_ptr
};
Some(unsafe { Self::wrap(ctx, ast) })
}
pub fn new_const<S: Into<Symbol>>(ctx: &'ctx Context, name: S, sz: u32) -> BV<'ctx> {
let sort = Sort::bitvector(ctx, sz);
unsafe {
Self::wrap(ctx, {
Z3_mk_const(ctx.z3_ctx, name.into().as_z3_symbol(ctx), sort.z3_sort)
})
}
}
pub fn fresh_const(ctx: &'ctx Context, prefix: &str, sz: u32) -> BV<'ctx> {
let sort = Sort::bitvector(ctx, sz);
unsafe {
Self::wrap(ctx, {
let pp = CString::new(prefix).unwrap();
let p = pp.as_ptr();
Z3_mk_fresh_const(ctx.z3_ctx, p, sort.z3_sort)
})
}
}
pub fn from_i64(ctx: &'ctx Context, i: i64, sz: u32) -> BV<'ctx> {
let sort = Sort::bitvector(ctx, sz);
unsafe { Self::wrap(ctx, Z3_mk_int64(ctx.z3_ctx, i, sort.z3_sort)) }
}
pub fn from_u64(ctx: &'ctx Context, u: u64, sz: u32) -> BV<'ctx> {
let sort = Sort::bitvector(ctx, sz);
unsafe { Self::wrap(ctx, Z3_mk_unsigned_int64(ctx.z3_ctx, u, sort.z3_sort)) }
}
pub fn as_i64(&self) -> Option<i64> {
unsafe {
let mut tmp: ::std::os::raw::c_longlong = 0;
if Z3_get_numeral_int64(self.ctx.z3_ctx, self.z3_ast, &mut tmp) {
Some(tmp)
} else {
None
}
}
}
pub fn as_u64(&self) -> Option<u64> {
unsafe {
let mut tmp: ::std::os::raw::c_ulonglong = 0;
if Z3_get_numeral_uint64(self.ctx.z3_ctx, self.z3_ast, &mut tmp) {
Some(tmp)
} else {
None
}
}
}
pub fn from_int(ast: &Int<'ctx>, sz: u32) -> BV<'ctx> {
unsafe { Self::wrap(ast.ctx, Z3_mk_int2bv(ast.ctx.z3_ctx, sz, ast.z3_ast)) }
}
pub fn to_int(&self, signed: bool) -> Int<'ctx> {
Int::from_bv(self, signed)
}
pub fn get_size(&self) -> u32 {
let sort = self.get_sort();
unsafe { Z3_get_bv_sort_size(self.ctx.z3_ctx, sort.z3_sort) }
}
unop! {
bvnot(Z3_mk_bvnot, Self);
bvneg(Z3_mk_bvneg, Self);
bvredand(Z3_mk_bvredand, Self);
bvredor(Z3_mk_bvredor, Self);
}
binop! {
bvand(Z3_mk_bvand, Self);
bvor(Z3_mk_bvor, Self);
bvxor(Z3_mk_bvxor, Self);
bvnand(Z3_mk_bvnand, Self);
bvnor(Z3_mk_bvnor, Self);
bvxnor(Z3_mk_bvxnor, Self);
}
binop! {
bvadd(Z3_mk_bvadd, Self);
bvsub(Z3_mk_bvsub, Self);
bvmul(Z3_mk_bvmul, Self);
bvudiv(Z3_mk_bvudiv, Self);
bvsdiv(Z3_mk_bvsdiv, Self);
bvurem(Z3_mk_bvurem, Self);
bvsrem(Z3_mk_bvsrem, Self);
bvsmod(Z3_mk_bvsmod, Self);
}
binop! {
bvult(Z3_mk_bvult, Bool<'ctx>);
bvslt(Z3_mk_bvslt, Bool<'ctx>);
bvule(Z3_mk_bvule, Bool<'ctx>);
bvsle(Z3_mk_bvsle, Bool<'ctx>);
bvuge(Z3_mk_bvuge, Bool<'ctx>);
bvsge(Z3_mk_bvsge, Bool<'ctx>);
bvugt(Z3_mk_bvugt, Bool<'ctx>);
bvsgt(Z3_mk_bvsgt, Bool<'ctx>);
}
binop! {
bvshl(Z3_mk_bvshl, Self);
bvlshr(Z3_mk_bvlshr, Self);
bvashr(Z3_mk_bvashr, Self);
bvrotl(Z3_mk_ext_rotate_left, Self);
bvrotr(Z3_mk_ext_rotate_right, Self);
}
binop! {
concat(Z3_mk_concat, Self);
}
unop! {
bvneg_no_overflow(Z3_mk_bvneg_no_overflow, Bool<'ctx>);
}
bv_overflow_check_signed! {
bvadd_no_overflow(Z3_mk_bvadd_no_overflow);
bvsub_no_underflow(Z3_mk_bvsub_no_underflow);
bvmul_no_overflow(Z3_mk_bvmul_no_overflow);
}
binop! {
bvadd_no_underflow(Z3_mk_bvadd_no_underflow, Bool<'ctx>);
bvsub_no_overflow(Z3_mk_bvsub_no_overflow, Bool<'ctx>);
bvsdiv_no_overflow(Z3_mk_bvsdiv_no_overflow, Bool<'ctx>);
bvmul_no_underflow(Z3_mk_bvmul_no_underflow, Bool<'ctx>);
}
pub fn extract(&self, high: u32, low: u32) -> Self {
unsafe {
Self::wrap(self.ctx, {
Z3_mk_extract(self.ctx.z3_ctx, high, low, self.z3_ast)
})
}
}
pub fn sign_ext(&self, i: u32) -> Self {
unsafe {
Self::wrap(self.ctx, {
Z3_mk_sign_ext(self.ctx.z3_ctx, i, self.z3_ast)
})
}
}
pub fn zero_ext(&self, i: u32) -> Self {
unsafe {
Self::wrap(self.ctx, {
Z3_mk_zero_ext(self.ctx.z3_ctx, i, self.z3_ast)
})
}
}
}
impl<'ctx> Array<'ctx> {
pub fn new_const<S: Into<Symbol>>(
ctx: &'ctx Context,
name: S,
domain: &Sort<'ctx>,
range: &Sort<'ctx>,
) -> Array<'ctx> {
let sort = Sort::array(ctx, domain, range);
unsafe {
Self::wrap(ctx, {
Z3_mk_const(ctx.z3_ctx, name.into().as_z3_symbol(ctx), sort.z3_sort)
})
}
}
pub fn fresh_const(
ctx: &'ctx Context,
prefix: &str,
domain: &Sort<'ctx>,
range: &Sort<'ctx>,
) -> Array<'ctx> {
let sort = Sort::array(ctx, domain, range);
unsafe {
Self::wrap(ctx, {
let pp = CString::new(prefix).unwrap();
let p = pp.as_ptr();
Z3_mk_fresh_const(ctx.z3_ctx, p, sort.z3_sort)
})
}
}
pub fn const_array<A>(ctx: &'ctx Context, domain: &Sort<'ctx>, val: &A) -> Array<'ctx>
where
A: Ast<'ctx>,
{
unsafe {
Self::wrap(ctx, {
Z3_mk_const_array(ctx.z3_ctx, domain.z3_sort, val.get_z3_ast())
})
}
}
pub fn select<A>(&self, index: &A) -> Dynamic<'ctx>
where
A: Ast<'ctx>,
{
unsafe {
Dynamic::wrap(self.ctx, {
Z3_mk_select(self.ctx.z3_ctx, self.z3_ast, index.get_z3_ast())
})
}
}
pub fn store<A1, A2>(&self, index: &A1, value: &A2) -> Self
where
A1: Ast<'ctx>,
A2: Ast<'ctx>,
{
unsafe {
Self::wrap(self.ctx, {
Z3_mk_store(
self.ctx.z3_ctx,
self.z3_ast,
index.get_z3_ast(),
value.get_z3_ast(),
)
})
}
}
}
impl<'ctx> Set<'ctx> {
pub fn new_const<S: Into<Symbol>>(
ctx: &'ctx Context,
name: S,
eltype: &Sort<'ctx>,
) -> Set<'ctx> {
let sort = Sort::set(ctx, eltype);
unsafe {
Self::wrap(ctx, {
Z3_mk_const(ctx.z3_ctx, name.into().as_z3_symbol(ctx), sort.z3_sort)
})
}
}
pub fn fresh_const(ctx: &'ctx Context, prefix: &str, eltype: &Sort<'ctx>) -> Set<'ctx> {
let sort = Sort::set(ctx, eltype);
unsafe {
Self::wrap(ctx, {
let pp = CString::new(prefix).unwrap();
let p = pp.as_ptr();
Z3_mk_fresh_const(ctx.z3_ctx, p, sort.z3_sort)
})
}
}
pub fn empty(ctx: &'ctx Context, domain: &Sort<'ctx>) -> Set<'ctx> {
unsafe { Self::wrap(ctx, Z3_mk_empty_set(ctx.z3_ctx, domain.z3_sort)) }
}
pub fn add<A>(&self, element: &A) -> Set<'ctx>
where
A: Ast<'ctx>,
{
unsafe {
Self::wrap(self.ctx, {
Z3_mk_set_add(self.ctx.z3_ctx, self.z3_ast, element.get_z3_ast())
})
}
}
pub fn del<A>(&self, element: &A) -> Set<'ctx>
where
A: Ast<'ctx>,
{
unsafe {
Self::wrap(self.ctx, {
Z3_mk_set_del(self.ctx.z3_ctx, self.z3_ast, element.get_z3_ast())
})
}
}
pub fn member<A>(&self, element: &A) -> Bool<'ctx>
where
A: Ast<'ctx>,
{
unsafe {
Bool::wrap(self.ctx, {
Z3_mk_set_member(self.ctx.z3_ctx, element.get_z3_ast(), self.z3_ast)
})
}
}
varop! {
intersect(Z3_mk_set_intersect, Self);
set_union(Z3_mk_set_union, Self);
}
unop! {
complement(Z3_mk_set_complement, Self);
}
binop! {
set_subset(Z3_mk_set_subset, Bool<'ctx>);
difference(Z3_mk_set_difference, Self);
}
}
impl<'ctx> Dynamic<'ctx> {
pub fn from_ast(ast: &dyn Ast<'ctx>) -> Self {
unsafe { Self::wrap(ast.get_ctx(), ast.get_z3_ast()) }
}
pub fn sort_kind(&self) -> SortKind {
unsafe { Z3_get_sort_kind(self.ctx.z3_ctx, Z3_get_sort(self.ctx.z3_ctx, self.z3_ast)) }
}
pub fn as_bool(&self) -> Option<Bool<'ctx>> {
match self.sort_kind() {
SortKind::Bool => Some(unsafe { Bool::wrap(self.ctx, self.z3_ast) }),
_ => None,
}
}
pub fn as_int(&self) -> Option<Int<'ctx>> {
match self.sort_kind() {
SortKind::Int => Some(unsafe { Int::wrap(self.ctx, self.z3_ast) }),
_ => None,
}
}
pub fn as_real(&self) -> Option<Real<'ctx>> {
match self.sort_kind() {
SortKind::Real => Some(unsafe { Real::wrap(self.ctx, self.z3_ast) }),
_ => None,
}
}
pub fn as_float(&self) -> Option<Float<'ctx>> {
match self.sort_kind() {
SortKind::FloatingPoint => Some(unsafe { Float::wrap(self.ctx, self.z3_ast) }),
_ => None,
}
}
pub fn as_string(&self) -> Option<String<'ctx>> {
unsafe {
if Z3_is_string_sort(self.ctx.z3_ctx, Z3_get_sort(self.ctx.z3_ctx, self.z3_ast)) {
Some(String::wrap(self.ctx, self.z3_ast))
} else {
None
}
}
}
pub fn as_bv(&self) -> Option<BV<'ctx>> {
match self.sort_kind() {
SortKind::BV => Some(unsafe { BV::wrap(self.ctx, self.z3_ast) }),
_ => None,
}
}
pub fn as_array(&self) -> Option<Array<'ctx>> {
match self.sort_kind() {
SortKind::Array => Some(unsafe { Array::wrap(self.ctx, self.z3_ast) }),
_ => None,
}
}
pub fn as_set(&self) -> Option<Set<'ctx>> {
unsafe {
match self.sort_kind() {
SortKind::Array => {
match Z3_get_sort_kind(
self.ctx.z3_ctx,
Z3_get_array_sort_range(
self.ctx.z3_ctx,
Z3_get_sort(self.ctx.z3_ctx, self.z3_ast),
),
) {
SortKind::Bool => Some(Set::wrap(self.ctx, self.z3_ast)),
_ => None,
}
}
_ => None,
}
}
}
pub fn as_datatype(&self) -> Option<Datatype<'ctx>> {
match self.sort_kind() {
SortKind::Datatype => Some(unsafe { Datatype::wrap(self.ctx, self.z3_ast) }),
_ => None,
}
}
}
impl<'ctx> Datatype<'ctx> {
pub fn new_const<S: Into<Symbol>>(ctx: &'ctx Context, name: S, sort: &Sort<'ctx>) -> Self {
assert_eq!(ctx, sort.ctx);
assert_eq!(sort.kind(), SortKind::Datatype);
unsafe {
Self::wrap(ctx, {
Z3_mk_const(ctx.z3_ctx, name.into().as_z3_symbol(ctx), sort.z3_sort)
})
}
}
pub fn fresh_const(ctx: &'ctx Context, prefix: &str, sort: &Sort<'ctx>) -> Self {
assert_eq!(ctx, sort.ctx);
assert_eq!(sort.kind(), SortKind::Datatype);
unsafe {
Self::wrap(ctx, {
let pp = CString::new(prefix).unwrap();
let p = pp.as_ptr();
Z3_mk_fresh_const(ctx.z3_ctx, p, sort.z3_sort)
})
}
}
}
impl<'ctx> Regexp<'ctx> {
pub fn literal(ctx: &'ctx Context, s: &str) -> Self {
unsafe {
Self::wrap(ctx, {
let c_str = CString::new(s).unwrap();
Z3_mk_seq_to_re(ctx.z3_ctx, Z3_mk_string(ctx.z3_ctx, c_str.as_ptr()))
})
}
}
pub fn range(ctx: &'ctx Context, lo: &char, hi: &char) -> Self {
unsafe {
Self::wrap(ctx, {
let lo_cs = CString::new(lo.to_string()).unwrap();
let hi_cs = CString::new(hi.to_string()).unwrap();
let lo_z3s = Z3_mk_string(ctx.z3_ctx, lo_cs.as_ptr());
Z3_inc_ref(ctx.z3_ctx, lo_z3s);
let hi_z3s = Z3_mk_string(ctx.z3_ctx, hi_cs.as_ptr());
Z3_inc_ref(ctx.z3_ctx, hi_z3s);
let ret = Z3_mk_re_range(ctx.z3_ctx, lo_z3s, hi_z3s);
Z3_dec_ref(ctx.z3_ctx, lo_z3s);
Z3_dec_ref(ctx.z3_ctx, hi_z3s);
ret
})
}
}
pub fn r#loop(&self, lo: u32, hi: u32) -> Self {
unsafe {
Self::wrap(self.ctx, {
Z3_mk_re_loop(self.ctx.z3_ctx, self.z3_ast, lo, hi)
})
}
}
pub fn full(ctx: &'ctx Context) -> Self {
unsafe {
Self::wrap(ctx, {
Z3_mk_re_full(
ctx.z3_ctx,
Z3_mk_re_sort(ctx.z3_ctx, Z3_mk_string_sort(ctx.z3_ctx)),
)
})
}
}
pub fn empty(ctx: &'ctx Context) -> Self {
unsafe {
Self::wrap(ctx, {
Z3_mk_re_empty(
ctx.z3_ctx,
Z3_mk_re_sort(ctx.z3_ctx, Z3_mk_string_sort(ctx.z3_ctx)),
)
})
}
}
unop! {
plus(Z3_mk_re_plus, Self);
star(Z3_mk_re_star, Self);
complement(Z3_mk_re_complement, Self);
}
varop! {
concat(Z3_mk_re_concat, Self);
union(Z3_mk_re_union, Self);
intersect(Z3_mk_re_intersect, Self);
}
}
pub fn forall_const<'ctx>(
ctx: &'ctx Context,
bounds: &[&dyn Ast<'ctx>],
patterns: &[&Pattern<'ctx>],
body: &Bool<'ctx>,
) -> Bool<'ctx> {
assert!(bounds.iter().all(|a| a.get_ctx() == ctx));
assert!(patterns.iter().all(|p| p.ctx == ctx));
assert_eq!(ctx, body.get_ctx());
if bounds.is_empty() {
return body.clone();
}
let bounds: Vec<_> = bounds.iter().map(|a| a.get_z3_ast()).collect();
let patterns: Vec<_> = patterns.iter().map(|p| p.z3_pattern).collect();
unsafe {
Ast::wrap(ctx, {
Z3_mk_forall_const(
ctx.z3_ctx,
0,
bounds.len().try_into().unwrap(),
bounds.as_ptr() as *const Z3_app,
patterns.len().try_into().unwrap(),
patterns.as_ptr() as *const Z3_pattern,
body.get_z3_ast(),
)
})
}
}
pub fn exists_const<'ctx>(
ctx: &'ctx Context,
bounds: &[&dyn Ast<'ctx>],
patterns: &[&Pattern<'ctx>],
body: &Bool<'ctx>,
) -> Bool<'ctx> {
assert!(bounds.iter().all(|a| a.get_ctx() == ctx));
assert!(patterns.iter().all(|p| p.ctx == ctx));
assert_eq!(ctx, body.get_ctx());
if bounds.is_empty() {
return body.clone();
}
let bounds: Vec<_> = bounds.iter().map(|a| a.get_z3_ast()).collect();
let patterns: Vec<_> = patterns.iter().map(|p| p.z3_pattern).collect();
unsafe {
Ast::wrap(ctx, {
Z3_mk_exists_const(
ctx.z3_ctx,
0,
bounds.len().try_into().unwrap(),
bounds.as_ptr() as *const Z3_app,
patterns.len().try_into().unwrap(),
patterns.as_ptr() as *const Z3_pattern,
body.get_z3_ast(),
)
})
}
}
impl IsNotApp {
pub fn new(kind: AstKind) -> Self {
Self { kind }
}
pub fn kind(&self) -> AstKind {
self.kind
}
}
impl fmt::Display for IsNotApp {
fn fmt(&self, f: &mut fmt::Formatter) -> Result<(), fmt::Error> {
write!(
f,
"ast node is not a function application, has kind {:?}",
self.kind()
)
}
}