use crate::formally;
use formally::{smt::backends::*, support::*};
use itertools::Itertools;
use linkme::distributed_slice;
use thiserror::Error;
#[doc(hidden)]
#[distributed_slice]
pub static BACKENDS: [&'static dyn Backend];
pub struct Register;
#[derive(Debug, Error, Located)]
#[error("SMT backend `{0}` not found")]
pub struct BackendNotFound<'s>(pub Identifier<'s>);
impl Diagnosable for BackendNotFound<'_> {
fn notes(&self) -> DiagnosticEmitted {
let mut backends = Vec::new();
for backend in Register::backends() {
if let Ok(backend) = backend.name() {
backends.push(backend)
}
}
note!(
self.0.span(),
"available backends: {}",
backends.into_iter().join(", ")
);
DiagnosticEmitted
}
}
pub struct Default;
impl Backend for Default {
fn name(&self) -> Result<&str, Error> {
Register::default_backend()?.name()
}
fn manager(&self) -> Result<Box<dyn Manager>, Error> {
Register::default_backend()?.manager()
}
fn solver(&self, config: &Config, manager: Rc<dyn Manager>) -> Result<Box<dyn Solver>, Error> {
Register::default_backend()?.solver(config, manager)
}
}
impl Register {
pub fn default_backend() -> Result<&'static dyn Backend, BackendNotFound<'static>> {
if cfg!(feature = "cvc5") {
Self::backend("cvc5")
} else if cfg!(feature = "z3") {
Self::backend("z3")
} else {
Err(BackendNotFound(Identifier::from("default")))
}
}
pub fn backend<'a>(
name: impl Into<Identifier<'a>>,
) -> Result<&'static dyn Backend, BackendNotFound<'a>> {
let name = name.into();
for b in BACKENDS {
if let Ok(bname) = b.name() && bname == name.name() {
return Ok(*b);
}
}
Err(BackendNotFound(name))
}
pub fn backends() -> &'static [&'static dyn Backend] {
&BACKENDS
}
}