use crate::{
fold::{Fold, Folder, SuperFold},
quantifier::Quantifier,
uf::UninterpretedFunction,
visit::SuperVisit,
Arguments, IOp, IQuantifier, Internable, Operation, Sorted, Term, IUF,
};
use std::{
fmt::{Debug, Display},
hash::Hash,
};
pub trait Logic: Clone + Debug + Default + Hash + PartialEq + Eq + 'static {
type Var: Internable + Sorted<Self> + Clone + Debug + Display;
type Op: Internable
+ Operation<Self>
+ Sorted<Self>
+ for<'a> Arguments<'a, Self>
+ Into<Term<Self>>
+ Into<IOp<Self>>
+ SuperFold<Self, Term<Self>, Output = Self::Op>
+ SuperVisit<Self>
+ Clone
+ Debug
+ Display;
type Quantifier: Internable
+ Quantifier<Self>
+ Sorted<Self>
+ Into<Term<Self>>
+ Into<IQuantifier<Self>>
+ SuperFold<Self, Term<Self>, Output = Self::Quantifier>
+ SuperVisit<Self>
+ Clone
+ Debug
+ Display;
type UninterpretedFunc: Internable
+ UninterpretedFunction<Self>
+ for<'a> Arguments<'a, Self>
+ Into<Term<Self>>
+ Into<IUF<Self>>
+ SuperFold<Self, Term<Self>, Output = Self::UninterpretedFunc>
+ SuperVisit<Self>
+ Clone
+ Debug
+ Display;
fn fold<F: Folder<Self, M>, Output, M>(
x: impl Fold<Self, F::Output, Output = Output>,
folder: &mut F,
) -> Result<Output, F::Error> {
x.fold_with(folder)
}
}
macro_rules! combine_ops {
(pub enum $name:ident<Term> { $($variant:ident($inner:ident<Term>),)+ }) => {
use crate::{args::Iterate, fold::{Folder, SuperFold}, visit::*, *};
use std::fmt;
#[derive(Clone, PartialEq, Eq, Hash)]
pub enum $name<Term> {
$($variant($inner<Term>)),*
}
impl<Term> fmt::Debug for $name<Term>
where
$($inner<Term>: fmt::Debug),*
{
fn fmt(&self, f: &mut fmt::Formatter<'_>) -> fmt::Result {
match self {
$(Self::$variant(x) => x.fmt(f),)*
}
}
}
impl<Term> fmt::Display for $name<Term>
where
$($inner<Term>: fmt::Display),*
{
fn fmt(&self, f: &mut fmt::Formatter<'_>) -> fmt::Result {
match self {
$(Self::$variant(x) => x.fmt(f),)*
}
}
}
impl<L: Logic, Term> Operation<L> for $name<Term>
where
$($inner<Term>: Operation<L>),*
{
fn parse(func: QualIdentifier, args: Vec<$crate::Term<L>>) -> Result<Self, InvalidOp<L>> {
Err(InvalidOp { func, args })
$(.or_else(|InvalidOp { func, args }| Operation::parse(func, args).map(Self::$variant)))*
}
fn func(&self) -> ISymbol {
match self {
$(Self::$variant(x) => x.func(),)*
}
}
}
impl<L: Logic, Term> SuperVisit<L> for $name<Term>
where
$($inner<Term>: SuperVisit<L>),*
{
fn super_visit_with<V: Visitor<L>>(&self, visitor: &mut V) -> ControlFlow<V::BreakTy> {
match self {
$(Self::$variant(x) => x.super_visit_with(visitor),)*
}
}
}
impl<L: Logic, Term, Out> SuperFold<L, Out> for $name<Term>
where
$($inner<Term>: SuperFold<L, Out, Output = $inner<Out>>),*
{
type Output = $name<Out>;
fn super_fold_with<F, M>(self, folder: &mut F) -> Result<Self::Output, F::Error>
where
F: Folder<L, M, Output = Out>,
{
match self {
$(Self::$variant(x) => Ok($name::$variant(x.super_fold_with(folder)?)),)*
}
}
}
impl<L: Logic, Term> Sorted<L> for $name<Term>
where
$($inner<Term>: Sorted<L>),*
{
fn sort(&self, ctx: &mut Ctx) -> Result<ISort, UnknownSort<$crate::Term<L>>> {
match self {
$(Self::$variant(x) => x.sort(ctx),)*
}
}
}
impl<'a, L: Logic, Term> Iterate<'a, L> for $name<Term>
where
$($inner<Term>: Iterate<'a, L>),*
{
type Terms = Box<dyn Iterator<Item = &'a $crate::Term<L>> + 'a>;
type IntoTerms = Box<dyn Iterator<Item = $crate::Term<L>> + 'a>;
fn terms(&'a self) -> Self::Terms {
match self {
$(Self::$variant(x) => Box::new(x.terms()),)*
}
}
fn into_terms(self) -> Self::IntoTerms {
match self {
$(Self::$variant(x) => Box::new(x.into_terms()),)*
}
}
}
impl<'a, L: Logic> Arguments<'a, L> for $name<Term<L>> {}
impl<L: Logic<Op = $name<Term>>, Term> From<$name<Term>> for IOp<L> {
fn from(op: $name<Term>) -> Self {
IOp::new(op)
}
}
impl<L: Logic<Op = $name<Term>>, Term> From<$name<Term>> for $crate::Term<L> {
fn from(op: $name<Term>) -> Self {
Self::from(IOp::from(op))
}
}
$(
impl<Term> From<$inner<Term>> for $name<Term> {
fn from(op: $inner<Term>) -> Self {
Self::$variant(op)
}
}
)*
};
}
pub mod all;
pub use all::ALL;
pub mod arrays;
pub use arrays::*;
pub mod bitvecs;
pub use bitvecs::*;
pub mod arith;
pub use arith::*;
pub mod strings;
pub use strings::*;