crate::prelude!();
use rsmt2::print::{Expr2Smt, Sort2Smt, Sym2Smt};
pub use crate::{build_expr as build, build_typ};
#[derive(Debug, Clone, Copy, PartialEq, Eq, PartialOrd, Ord)]
pub enum Typ {
Bool,
Int,
Rat,
}
impl Typ {
pub fn bool() -> Self {
Self::Bool
}
pub fn int() -> Self {
Self::Int
}
pub fn rat() -> Self {
Self::Rat
}
}
impl Sort2Smt for Typ {
fn sort_to_smt2<W: Write>(&self, w: &mut W) -> SmtRes<()> {
write!(
w,
"{}",
match self {
Self::Bool => "Bool",
Self::Int => "Int",
Self::Rat => "Real",
}
)?;
Ok(())
}
}
#[derive(Debug, Clone, PartialEq, Eq, PartialOrd, Ord)]
pub enum Cst {
B(bool),
I(Int),
R(Rat),
}
impl Cst {
pub fn bool(b: bool) -> Self {
Cst::B(b)
}
pub fn int<I: Into<Int>>(i: I) -> Self {
Cst::I(i.into())
}
pub fn rat<R: Into<Rat>>(r: R) -> Self {
Cst::R(r.into())
}
}
impl Expr2Smt<()> for Cst {
fn expr_to_smt2<W: Write>(&self, w: &mut W, _: ()) -> SmtRes<()> {
match self {
Self::B(b) => write!(w, "{}", b)?,
Self::I(i) => write!(w, "{}", i)?,
Self::R(r) => write!(w, "(/ {} {})", r.numer(), r.denom())?,
}
Ok(())
}
}
#[derive(Debug, Clone, Copy, PartialEq, Eq, PartialOrd, Ord)]
pub enum Op {
Ite,
Implies,
Add,
Sub,
Mul,
Div,
Mod,
Ge,
Le,
Gt,
Lt,
Eq,
Not,
And,
Or,
}
impl Op {
pub fn of_str<Str: AsRef<str>>(s: Str) -> Option<Self> {
use Op::*;
let res = match s.as_ref() {
"ite" => Ite,
"=>" | "implies" | "⇒" => Implies,
"+" => Add,
"-" => Sub,
"*" => Mul,
"/" => Div,
"mod" => Mod,
">=" | "≥" => Ge,
"<=" | "≤" => Le,
">" => Gt,
"<" => Lt,
"=" => Eq,
"not" | "!" | "¬" => Not,
"and" | "&&" | "⋀" => And,
"or" | "||" | "⋁" => Or,
_ => return None,
};
Some(res)
}
}
impl Expr2Smt<()> for Op {
fn expr_to_smt2<W: Write>(&self, w: &mut W, _: ()) -> SmtRes<()> {
write!(
w,
"{}",
match self {
Self::Ite => "ite",
Self::Implies => "=>",
Self::Add => "+",
Self::Sub => "-",
Self::Mul => "*",
Self::Div => "/",
Self::Mod => "mod",
Self::Ge => ">=",
Self::Le => "<=",
Self::Gt => ">",
Self::Lt => "<",
Self::Eq => "=",
Self::Not => "not",
Self::And => "and",
Self::Or => "or",
}
)?;
Ok(())
}
}
#[derive(Debug, Clone, PartialEq, Eq, PartialOrd, Ord)]
pub struct Var {
id: String,
typ: Typ,
}
impl Var {
pub fn new<S: Into<String>>(id: S, typ: Typ) -> Self {
Self { id: id.into(), typ }
}
pub fn id(&self) -> &str {
&self.id
}
pub fn typ(&self) -> Typ {
self.typ
}
}
impl Sym2Smt<Unroll> for Var {
fn sym_to_smt2<W: Write>(&self, w: &mut W, step: Unroll) -> SmtRes<()> {
write!(w, "{}@{}", self.id, step)?;
Ok(())
}
}
#[derive(Debug, Clone, PartialEq, Eq, PartialOrd, Ord)]
pub struct SVar {
var: Var,
nxt: bool,
}
impl SVar {
pub fn new_next(var: Var) -> Self {
Self { var, nxt: true }
}
pub fn new_curr(var: Var) -> Self {
Self { var, nxt: false }
}
pub fn is_next(&self) -> bool {
self.nxt
}
}
impl Sym2Smt<Unroll> for SVar {
fn sym_to_smt2<W: Write>(&self, w: &mut W, step: Unroll) -> SmtRes<()> {
write!(w, "{}@{}", self.id, if self.nxt { step + 1 } else { step })?;
Ok(())
}
}
#[derive(Debug, Clone, PartialEq, Eq, PartialOrd, Ord)]
pub enum PExpr<V> {
Cst(Cst),
Var(V),
App {
op: Op,
args: Vec<PExpr<V>>,
},
}
impl<V> PExpr<V> {
pub fn new_var(var: V) -> Self {
Self::Var(var)
}
pub fn new_op(op: Op, args: Vec<Self>) -> Self {
PExpr::App { op, args }
}
pub fn negated(&self) -> NotPExpr<V> {
self.into()
}
}
impl<Info: Copy, V: Sym2Smt<Info>> Expr2Smt<Info> for PExpr<V> {
fn expr_to_smt2<W: Write>(&self, w: &mut W, i: Info) -> SmtRes<()> {
match self {
Self::Cst(cst) => cst.expr_to_smt2(w, ()),
Self::Var(var) => var.sym_to_smt2(w, i),
Self::App { op, args } => {
write!(w, "(")?;
op.expr_to_smt2(w, ())?;
for arg in args {
write!(w, " ")?;
arg.expr_to_smt2(w, i)?
}
write!(w, ")")?;
Ok(())
}
}
}
}
pub type Expr = PExpr<Var>;
pub type SExpr = PExpr<SVar>;
pub struct NotPExpr<'a, V> {
expr: &'a PExpr<V>,
}
impl<'a, V> From<&'a PExpr<V>> for NotPExpr<'a, V> {
fn from(expr: &'a PExpr<V>) -> Self {
Self { expr }
}
}
impl<'a, Info: Copy, V: Sym2Smt<Info>> Expr2Smt<Info> for NotPExpr<'a, V> {
fn expr_to_smt2<W: Write>(&self, w: &mut W, i: Info) -> SmtRes<()> {
write!(w, "(not ")?;
self.expr.expr_to_smt2(w, i)?;
write!(w, ")")?;
Ok(())
}
}
mod trait_impls {
use super::*;
impl fmt::Display for Typ {
fn fmt(&self, fmt: &mut fmt::Formatter) -> fmt::Result {
match self {
Self::Bool => write!(fmt, "bool"),
Self::Int => write!(fmt, "int"),
Self::Rat => write!(fmt, "rat"),
}
}
}
impl fmt::Display for Op {
fn fmt(&self, fmt: &mut fmt::Formatter) -> fmt::Result {
match self {
Self::Ite => write!(fmt, "ite"),
Self::Implies => write!(fmt, "=>"),
Self::Add => write!(fmt, "+"),
Self::Sub => write!(fmt, "-"),
Self::Mul => write!(fmt, "*"),
Self::Div => write!(fmt, "/"),
Self::Mod => write!(fmt, "%"),
Self::Ge => write!(fmt, ">="),
Self::Le => write!(fmt, "<="),
Self::Gt => write!(fmt, ">"),
Self::Lt => write!(fmt, "<"),
Self::Eq => write!(fmt, "="),
Self::Not => write!(fmt, "not"),
Self::And => write!(fmt, "and"),
Self::Or => write!(fmt, "or"),
}
}
}
impl fmt::Display for Cst {
fn fmt(&self, fmt: &mut fmt::Formatter) -> fmt::Result {
match self {
Self::B(b) => b.fmt(fmt),
Self::I(i) => {
if i.sign() == Sign::Minus {
write!(fmt, "(- {})", -i)
} else {
i.fmt(fmt)
}
}
Self::R(r) => {
let (num, den) = (r.numer(), r.denom());
match (num.sign(), den.sign()) {
(Sign::Minus, Sign::Minus) => write!(fmt, "(/ {} {})", -num, -den),
(Sign::Minus, _) => write!(fmt, "(- (/ {} {}))", -num, den),
(_, Sign::Minus) => write!(fmt, "(- (/ {} {}))", num, -den),
_ => write!(fmt, "(/ {} {})", num, den),
}
}
}
}
}
impl From<bool> for Cst {
fn from(b: bool) -> Self {
Self::B(b)
}
}
impl From<Int> for Cst {
fn from(i: Int) -> Self {
Self::I(i)
}
}
impl From<usize> for Cst {
fn from(n: usize) -> Self {
Int::from_bytes_be(Sign::Plus, &n.to_be_bytes()).into()
}
}
impl From<(usize, usize)> for Cst {
fn from((num, den): (usize, usize)) -> Self {
let (num, den): (Int, Int) = (num.into(), den.into());
Rat::new(num, den).into()
}
}
impl From<Rat> for Cst {
fn from(r: Rat) -> Self {
Self::R(r)
}
}
impl fmt::Display for Var {
fn fmt(&self, fmt: &mut fmt::Formatter) -> fmt::Result {
write!(fmt, "{}", self.id)
}
}
impl Deref for SVar {
type Target = Var;
fn deref(&self) -> &Var {
&self.var
}
}
impl fmt::Display for SVar {
fn fmt(&self, fmt: &mut fmt::Formatter) -> fmt::Result {
write!(fmt, "{}@{}", self.id, if self.nxt { 1 } else { 0 })
}
}
impl<V: fmt::Display> fmt::Display for PExpr<V> {
fn fmt(&self, fmt: &mut fmt::Formatter) -> fmt::Result {
match self {
Self::Cst(cst) => cst.fmt(fmt),
Self::Var(var) => var.fmt(fmt),
Self::App { op, args } => {
write!(fmt, "({}", op)?;
for arg in args {
write!(fmt, " {}", arg)?
}
write!(fmt, ")")
}
}
}
}
impl<C, V> From<C> for PExpr<V>
where
C: Into<Cst>,
{
fn from(cst: C) -> Self {
Self::Cst(cst.into())
}
}
impl<V> From<(Op, Vec<PExpr<V>>)> for PExpr<V> {
fn from((op, args): (Op, Vec<PExpr<V>>)) -> Self {
Self::App { op, args }
}
}
}