use crate::*;
use formally::support::*;
use derive_more::{Deref, From};
use transitive::Transitive;
use std::{fmt::Debug, sync::Arc};
#[derive(Copy, Clone, Debug)]
pub enum Associativity {
LeftAssoc,
RightAssoc,
Chainable,
Pairwise,
}
#[derive(Clone, Debug, Hash, PartialEq, Eq, Located)]
pub struct Variable<S: ToSort = Sort>(Nominal<Arc<VariableData<S>>>);
#[derive(Clone, Debug, Located, Locatable)]
struct VariableData<S: ToSort> {
pub name: Identifier<'static>,
pub sort: S,
pub span: Option<Span>,
}
impl<S: ToSort> Variable<S> {
pub fn new<'a>(name: impl Into<Identifier<'a>>, sort: S) -> Variable<S> {
Variable(Nominal(Arc::new(VariableData {
name: name.into().into_owned(),
sort,
span: None,
})))
}
pub fn name(&self) -> &Identifier<'static> {
&self.0.name
}
pub fn sort(&self) -> &S {
&self.0.sort
}
}
impl<S: Clone + ToSort> Locatable for Variable<S> {
type Located = Variable<S>;
fn over(self, span: impl Into<Option<Span>>) -> Self::Located {
Variable(Nominal(Arc::new((**self.0).clone().over(span.into()))))
}
}
#[derive(Clone, Debug, Hash, PartialEq, Eq)]
pub struct Primitive(pub(crate) Nominal<SArc<PrimitiveData>>);
#[derive(Clone, Debug)]
pub(crate) struct PrimitiveData {
pub name: Identifier<'static>,
pub parameters: Vec<Variable>,
pub domain: Vec<Sort>,
pub range: Sort,
pub associativity: Option<Associativity>,
}
impl Located for Primitive {
fn span(&self) -> Option<Span> {
None
}
}
impl Primitive {
pub fn new<'a>(
name: impl Into<Identifier<'a>>,
parameters: Vec<Variable>,
domain: Vec<Sort>,
range: Sort,
associativity: Option<Associativity>,
) -> Primitive {
Primitive(Nominal(SArc::Arc(Arc::new(PrimitiveData {
name: name.into().into_owned(),
parameters,
domain,
range,
associativity,
}))))
}
pub fn name(&self) -> &Identifier<'static> {
&self.0.name
}
pub fn parameters(&self) -> &[Variable] {
&self.0.parameters
}
pub fn domain(&self) -> &[Sort] {
&self.0.domain
}
pub fn range(&self) -> &Sort {
&self.0.range
}
pub fn associativity(&self) -> Option<Associativity> {
self.0.associativity
}
}
#[derive(Clone, Debug, Hash, PartialEq, Eq, Located, Locatable)]
pub struct Declaration<D: ToSort, R: ToSort> {
pub name: Identifier<'static>,
pub domain: Vec<D>,
pub range: R,
pub span: Option<Span>,
}
impl<D: ToSort, R: ToSort> Declaration<D, R> {
pub fn function<'a>(
name: impl Into<Identifier<'a>>,
domain: impl IntoIterator<Item = D>,
range: R,
) -> Declaration<D, R> {
Declaration {
name: name.into().into_owned(),
domain: domain.into_iter().collect(),
range,
span: None,
}
}
}
impl<D: ToSort> Declaration<D, Sort> {
pub fn predicate<'a>(
name: impl Into<Identifier<'a>>,
domain: impl IntoIterator<Item = D>,
) -> Declaration<D, Sort> {
Declaration::function(name, domain, theories::Core::Bool())
}
}
impl<R: ToSort> Declaration<Sort, R> {
pub fn constant<'a>(name: impl Into<Identifier<'a>>, sort: R) -> Declaration<Sort, R> {
Declaration::function(name, Vec::<Sort>::new(), sort)
}
}
impl Declaration<Sort, Sort> {
pub fn sort<'a>(name: impl Into<Identifier<'a>>) -> Declaration<Sort, Sort> {
Declaration::constant(name, Sort::sort())
}
pub fn boolean<'a>(name: impl Into<Identifier<'a>>) -> Declaration<Sort, Sort> {
Declaration::constant(name, theories::Core::Bool())
}
pub fn integer<'a>(name: impl Into<Identifier<'a>>) -> Declaration<Sort, Sort> {
Declaration::constant(name, theories::Ints::Int())
}
pub fn real<'a>(name: impl Into<Identifier<'a>>) -> Declaration<Sort, Sort> {
Declaration::constant(name, theories::Reals::Real())
}
}
#[derive(Clone, Debug, Hash, PartialEq, Eq, Located, Deref)]
pub struct Declared(pub(crate) Nominal<Arc<Declaration<Sort, Sort>>>);
#[derive(Clone, Debug, Hash, PartialEq, Eq, Located, Locatable)]
pub struct Definition<V: ToSort, R: ToSort, B: ToTerm> {
pub name: Identifier<'static>,
pub domain: Vec<Variable<V>>,
pub range: R,
pub body: B,
pub span: Option<Span>,
}
impl<V: ToSort, R: ToSort, B: ToTerm> Definition<V, R, B> {
pub fn function<'a>(
name: impl Into<Identifier<'a>>,
domain: impl IntoIterator<Item = Variable<V>>,
range: R,
body: B,
) -> Definition<V, R, B> {
Definition {
name: name.into().into_owned(),
domain: domain.into_iter().collect(),
range,
body,
span: None,
}
}
}
impl<V: ToSort, B: ToTerm> Definition<V, Sort, B> {
pub fn predicate<'a>(
name: impl Into<Identifier<'a>>,
domain: impl IntoIterator<Item = Variable<V>>,
body: B,
) -> Definition<V, Sort, B> {
Definition::function(name, domain, theories::Core::Bool(), body)
}
pub fn sort<'a>(
name: impl Into<Identifier<'a>>,
domain: impl IntoIterator<Item = Variable<V>>,
body: B,
) -> Definition<V, Sort, B> {
Definition::function(name, domain, Sort::sort(), body)
}
}
impl<R: ToSort, B: ToTerm> Definition<Sort, R, B> {
pub fn constant<'a>(
name: impl Into<Identifier<'a>>,
sort: R,
body: B,
) -> Definition<Sort, R, B> {
Definition::function(name, [], sort, body)
}
}
impl<B: ToTerm> Definition<Sort, Sort, B> {
pub fn boolean<'a>(name: impl Into<Identifier<'a>>, value: B) -> Definition<Sort, Sort, B> {
Definition::constant(name, theories::Core::Bool(), value)
}
pub fn integer<'a>(name: impl Into<Identifier<'a>>, value: B) -> Definition<Sort, Sort, B> {
Definition::constant(name, theories::Ints::Int(), value)
}
pub fn real<'a>(name: impl Into<Identifier<'a>>, value: B) -> Definition<Sort, Sort, B> {
Definition::constant(name, theories::Reals::Real(), value)
}
}
#[derive(Clone, Debug, Hash, PartialEq, Eq, Located, Deref)]
pub struct Defined(pub(crate) Nominal<Arc<Definition<Sort, Sort, Term>>>);
#[derive(Clone, Debug, Hash, PartialEq, Eq, Located, From, Transitive)]
#[allow(clippy::duplicated_attributes)]
#[transitive(from(Declared, UserFunction))]
#[transitive(from(Defined, UserFunction))]
pub enum Function {
Variable(Variable),
Primitive(Primitive),
User(UserFunction),
}
impl Function {
pub fn name(&self) -> &Identifier<'static> {
match self {
Function::Variable(var) => var.name(),
Function::Primitive(prim) => prim.name(),
Function::User(user) => user.name(),
}
}
pub fn parameters(&self) -> Vec<Sort> {
match self {
Function::Variable(_) => Vec::new(),
Function::Primitive(prim) => {
prim.parameters().iter().map(|p| p.sort().clone()).collect()
}
Function::User(_) => Vec::new(),
}
}
pub fn domain(&self) -> Vec<Sort> {
match self {
Function::Variable(_) => Vec::new(),
Function::Primitive(prim) => prim.domain().to_vec(),
Function::User(user) => user.domain(),
}
}
pub fn range(&self) -> &Sort {
match self {
Function::Variable(var) => var.sort(),
Function::Primitive(prim) => prim.range(),
Function::User(user) => user.range(),
}
}
}
#[derive(Clone, Debug, Hash, PartialEq, Eq, Located, From)]
pub enum UserFunction {
Declared(Declared),
Defined(Defined),
}
impl UserFunction {
pub fn name(&self) -> &Identifier<'static> {
match self {
UserFunction::Declared(decl) => &decl.name,
UserFunction::Defined(def) => &def.name,
}
}
pub fn domain(&self) -> Vec<Sort> {
match self {
UserFunction::Declared(decl) => decl.domain.clone(),
UserFunction::Defined(def) => def.domain.iter().map(|p| p.sort().clone()).collect(),
}
}
pub fn range(&self) -> &Sort {
match self {
UserFunction::Declared(decl) => &decl.range,
UserFunction::Defined(def) => &def.range,
}
}
}