use std::fmt;
use miden_diagnostics::{SourceSpan, Spanned};
use super::*;
#[derive(Debug, Clone, PartialEq, Eq, Spanned)]
pub enum Statement {
Let(Let),
Expr(Expr),
Enforce(ScalarExpr),
EnforceIf(#[span] ScalarExpr, ScalarExpr),
EnforceAll(ListComprehension),
BusEnforce(ListComprehension),
}
impl Statement {
pub fn has_constraints(&self) -> bool {
match self {
Self::Enforce(_)
| Self::EnforceIf(_, _)
| Self::EnforceAll(_)
| Self::BusEnforce(_) => true,
Self::Let(Let { body, .. }) => body.iter().any(|s| s.has_constraints()),
Self::Expr(_) => false,
}
}
pub fn display(&self, indent: usize) -> DisplayStatement<'_> {
DisplayStatement {
statement: self,
indent,
}
}
}
impl From<Expr> for Statement {
fn from(expr: Expr) -> Self {
match expr {
Expr::Let(let_expr) => Self::Let(*let_expr),
expr => Self::Expr(expr),
}
}
}
impl TryFrom<ScalarExpr> for Statement {
type Error = ();
fn try_from(expr: ScalarExpr) -> Result<Self, Self::Error> {
match expr {
ScalarExpr::Let(let_expr) => Ok(Self::Let(*let_expr)),
expr => Expr::try_from(expr).map_err(|_| ()).map(Self::Expr),
}
}
}
#[derive(Clone, Spanned)]
pub struct Let {
#[span]
pub span: SourceSpan,
pub name: Identifier,
pub value: Expr,
pub body: Vec<Statement>,
}
impl Let {
pub fn new(span: SourceSpan, name: Identifier, value: Expr, body: Vec<Statement>) -> Self {
Self {
span,
name,
value,
body,
}
}
pub fn ty(&self) -> Option<Type> {
let mut last = self.body.last();
while let Some(stmt) = last.take() {
match stmt {
Statement::Let(let_expr) => {
last = let_expr.body.last();
}
Statement::Expr(expr) => return expr.ty(),
Statement::Enforce(_)
| Statement::EnforceIf(_, _)
| Statement::EnforceAll(_)
| Statement::BusEnforce(_) => break,
}
}
None
}
}
impl Eq for Let {}
impl PartialEq for Let {
fn eq(&self, other: &Self) -> bool {
self.name == other.name && self.value == other.value && self.body == other.body
}
}
impl fmt::Debug for Let {
fn fmt(&self, f: &mut fmt::Formatter) -> fmt::Result {
f.debug_struct("Let")
.field("name", &self.name)
.field("value", &self.value)
.field("body", &self.body)
.finish()
}
}