haloumi-picus 0.5.5

Haloumi backend to the Picus Constraint Language.
Documentation
use std::{any::Any, collections::HashSet};

use super::Stmt;
use crate::pcl::{
    display::TextRepresentable,
    errors::ExprArgsError,
    expr::{Expr, traits::ConstraintExpr},
    vars::VarStr,
};
use anyhow::Result;
use haloumi_ir::Prime;

pub trait ExprArgs {
    fn args(&self) -> Vec<Expr>;

    fn replace_arg(&mut self, idx: usize, expr: Expr) -> Result<(), ExprArgsError>;
}

pub trait FreeVars {
    fn free_vars(&self) -> HashSet<&VarStr>;
}

pub trait ConstraintLike {
    fn is_constraint(&self) -> bool;

    fn constraint_expr(&self) -> Option<&dyn ConstraintExpr>;
}

pub trait CallLike: std::fmt::Debug {
    fn callee(&self) -> &str;

    fn with_new_callee(&self, new_name: String) -> Stmt;

    fn outputs(&self) -> &[VarStr];
}

pub trait StmtConstantFolding {
    fn fold(&self, prime: Prime) -> Option<Stmt>;
}

#[allow(dead_code)]
pub trait CallLikeMut: CallLike {
    fn set_callee(&mut self, new_name: String);
}

#[derive(Debug)]
pub struct CallLikeAdaptor<'a>(&'a dyn CallLike);

impl<'a> CallLikeAdaptor<'a> {
    pub fn new(c: &'a dyn CallLike) -> Self {
        Self(c)
    }
}

impl CallLike for CallLikeAdaptor<'_> {
    fn callee(&self) -> &str {
        self.0.callee()
    }

    fn with_new_callee(&self, new_name: String) -> Stmt {
        self.0.with_new_callee(new_name)
    }

    fn outputs(&self) -> &[VarStr] {
        self.0.outputs()
    }
}

pub trait MaybeCallLike {
    fn as_call<'a>(&'a self) -> Option<CallLikeAdaptor<'a>>;
}

pub trait AsStmtEq: Any {
    fn as_any(&self) -> &dyn Any;
    fn as_stmt_eq(&self) -> &dyn StmtEq;
}

pub trait StmtEq {
    fn stmt_eq(&self, other: &dyn StmtLike) -> bool;
}

impl<T: Any + StmtEq> AsStmtEq for T {
    fn as_any(&self) -> &dyn Any {
        self
    }

    fn as_stmt_eq(&self) -> &dyn StmtEq {
        self
    }
}

impl<T: Any + PartialEq> StmtEq for T {
    fn stmt_eq(&self, other: &dyn StmtLike) -> bool {
        if let Some(other) = other.as_any().downcast_ref::<Self>() {
            self == other
        } else {
            false
        }
    }
}

impl PartialEq<dyn StmtLike> for dyn StmtLike {
    fn eq(&self, other: &dyn StmtLike) -> bool {
        self.stmt_eq(other)
    }
}

pub trait StmtLike:
    ExprArgs
    + ConstraintLike
    + MaybeCallLike
    + StmtConstantFolding
    + TextRepresentable
    + std::fmt::Debug
    + StmtEq
    + AsStmtEq
    + FreeVars
{
}