mod constructor;
use std::convert::TryInto;
use z3_sys::*;
use crate::datatype_builder::constructor::{Constructor, ConstructorList};
use crate::{Context, DatatypeBuilder, DatatypeSort, DatatypeVariant, FuncDecl, Sort, Symbol};
impl DatatypeBuilder {
pub fn new<S: Into<Symbol>>(name: S) -> Self {
let ctx = &Context::thread_local();
Self {
ctx: ctx.clone(),
name: name.into(),
constructors: Vec::new(),
}
}
pub fn variant(mut self, name: &str, fields: Vec<(&str, DatatypeAccessor)>) -> Self {
let mut accessor_vec: Vec<(String, DatatypeAccessor)> = Vec::new();
for (accessor_name, accessor) in fields {
accessor_vec.push((accessor_name.to_string(), accessor));
}
self.constructors.push((name.to_string(), accessor_vec));
self
}
pub fn finish(self) -> DatatypeSort {
let mut dtypes = create_datatypes(vec![self]);
dtypes.remove(0)
}
}
fn build_datatype_sort(
ctx: &Context,
sort: Sort,
datatype_builder: &DatatypeBuilder,
) -> DatatypeSort {
let num_cs = datatype_builder.constructors.len();
let mut variants: Vec<DatatypeVariant> = Vec::with_capacity(num_cs);
for (j, (_cname, fs)) in datatype_builder.constructors.iter().enumerate() {
let num_fs = fs.len();
let raw_constructor = unsafe {
Z3_get_datatype_sort_constructor(
ctx.z3_ctx.0,
sort.get_z3_sort(),
j.try_into().unwrap(),
)
.unwrap()
};
let constructor: FuncDecl = unsafe { FuncDecl::wrap(ctx, raw_constructor) };
let tester_func = unsafe {
Z3_get_datatype_sort_recognizer(ctx.z3_ctx.0, sort.get_z3_sort(), j.try_into().unwrap())
.unwrap()
};
let tester = unsafe { FuncDecl::wrap(ctx, tester_func) };
let mut accessors: Vec<FuncDecl> = Vec::new();
for k in 0..num_fs {
let accessor_func = unsafe {
Z3_get_datatype_sort_constructor_accessor(
ctx.z3_ctx.0,
sort.get_z3_sort(),
j.try_into().unwrap(),
k.try_into().unwrap(),
)
.unwrap()
};
accessors.push(unsafe { FuncDecl::wrap(ctx, accessor_func) });
}
variants.push(DatatypeVariant {
constructor,
tester,
accessors,
});
}
DatatypeSort { sort, variants }
}
pub fn create_datatypes(datatype_builders: Vec<DatatypeBuilder>) -> Vec<DatatypeSort> {
let num = datatype_builders.len();
assert!(num > 0, "At least one DatatypeBuilder must be specified");
let ctx: Context = datatype_builders[0].ctx.clone();
assert!(datatype_builders.iter().all(|d| d.ctx == ctx));
let mut names: Vec<Z3_symbol> = Vec::with_capacity(num);
let mut raw_sorts: Vec<Z3_sort> = Vec::with_capacity(num);
let mut ctor_wrapped: Vec<Constructor> = Vec::with_capacity(num * 2);
let mut clist_wrapped: Vec<ConstructorList> = Vec::with_capacity(num);
for d in datatype_builders.iter() {
names.push(d.name.as_z3_symbol());
let num_cs = d.constructors.len();
let cs_start_idx = ctor_wrapped.len();
for (cname, fs) in &d.constructors {
let mut rname: String = "is-".to_string();
rname.push_str(cname);
let cname_symbol = Symbol::String(cname.clone());
let rname_symbol = Symbol::String(rname);
let ctor_wrapper = Constructor::new(
&ctx,
cname_symbol,
rname_symbol,
fs.as_slice(),
&datatype_builders,
);
ctor_wrapped.push(ctor_wrapper);
}
assert!(ctor_wrapped.len() >= cs_start_idx + num_cs);
let ctors_slice = &ctor_wrapped[cs_start_idx..cs_start_idx + num_cs];
let clist_wrapper = ConstructorList::new(&ctx, ctors_slice);
clist_wrapped.push(clist_wrapper);
}
assert_eq!(num, names.len());
assert_eq!(num, clist_wrapped.len());
let mut clist_handles: Vec<Z3_constructor_list> = clist_wrapped
.iter()
.map(|c| c.z3_constructor_list())
.collect();
unsafe {
Z3_mk_datatypes(
ctx.z3_ctx.0,
num.try_into().unwrap(),
names.as_ptr(),
raw_sorts.as_mut_ptr(),
clist_handles.as_mut_ptr(),
);
raw_sorts.set_len(num);
};
let sorts = raw_sorts
.into_iter()
.map(|s| unsafe { Sort::wrap(&ctx, s) })
.collect::<Vec<_>>();
let mut datatype_sorts: Vec<DatatypeSort> = Vec::with_capacity(sorts.len());
for (sort, datatype_builder) in sorts.into_iter().zip(&datatype_builders) {
datatype_sorts.push(build_datatype_sort(&ctx, sort, datatype_builder));
}
datatype_sorts
}
#[derive(Debug)]
pub enum DatatypeAccessor {
Sort(Sort),
Datatype(Symbol),
}
impl DatatypeAccessor {
pub fn sort<S: Into<Sort>>(s: S) -> Self {
Self::Sort(s.into())
}
pub fn datatype<S: Into<Symbol>>(s: S) -> Self {
Self::Datatype(s.into())
}
}