use itertools::Itertools;
use crate::ir::{
expressions::{Constant, Expr, ExprKind, Function, Operator},
StreamReference, Type, WindowReference,
};
pub trait ExprFormatter {
type Return;
fn constant(&self, c: Constant) -> Self::Return;
fn unary(&self, op: Operator, operand: Expr) -> Self::Return;
fn binary(&self, op: Operator, lhs: Expr, rhs: Expr) -> Self::Return;
fn if_then_else(&self, condition: Expr, consequence: Expr, alternative: Expr) -> Self::Return;
fn sync_access(&self, sr: StreamReference, parameters: Vec<Expr>) -> Self::Return;
fn offset_access(
&self,
sr: StreamReference,
offset: u32,
default: Expr,
parameters: Vec<Expr>,
) -> Self::Return;
fn hold_access(
&self,
sr: StreamReference,
default: Expr,
parameters: Vec<Expr>,
) -> Self::Return;
fn get_access(&self, sr: StreamReference, default: Expr, parameters: Vec<Expr>)
-> Self::Return;
fn is_fresh(&self, sr: StreamReference, parameters: Vec<Expr>) -> Self::Return;
fn sliding_window_access(&self, wref: usize, default: Option<Expr>) -> Self::Return;
fn discrete_window_access(&self, wref: usize, default: Option<Expr>) -> Self::Return;
fn instance_aggregation(&self, wref: usize, default: Option<Expr>) -> Self::Return;
fn parameter_access(&self, sr: StreamReference, p: usize) -> Self::Return;
fn lambda_parameter_access(&self, wref: WindowReference, idx: usize) -> Self::Return;
fn cast(&self, ty: Type, expr: Expr) -> Self::Return;
fn tuple(&self, inner_exprs: Vec<Expr>) -> Self::Return;
fn tuple_access(&self, expr: Expr, idx: usize) -> Self::Return;
fn function_call(&self, function: Function, args: Vec<Expr>) -> Self::Return;
fn expr(&self, expr: Expr) -> Self::Return {
match expr.kind {
ExprKind::Constant(c) => self.constant(c),
ExprKind::BinaryOperation(op, lhs, rhs) => self.binary(op, *lhs, *rhs),
ExprKind::UnaryOperation(op, operand) => self.unary(op, *operand),
ExprKind::Ite(condition, consequence, alternative) => {
self.if_then_else(*condition, *consequence, *alternative)
}
ExprKind::SyncStreamAccess { target, parameters } => {
self.sync_access(target, parameters)
}
ExprKind::OffsetStreamAccess {
target,
offset,
default,
parameters,
} => self.offset_access(target, offset, *default, parameters),
ExprKind::HoldStreamAccess {
target,
default,
parameters,
} => self.hold_access(target, *default, parameters),
ExprKind::IsFresh { target, parameters } => self.is_fresh(target, parameters),
ExprKind::GetAccess {
target,
default,
parameters,
} => self.get_access(target, *default, parameters),
ExprKind::WindowAccess {
target: _,
window,
parameters: _,
default,
} => match window {
WindowReference::Sliding(w) => self.sliding_window_access(w, default.map(|b| *b)),
WindowReference::Discrete(w) => self.discrete_window_access(w, default.map(|b| *b)),
WindowReference::Instance(w) => self.instance_aggregation(w, default.map(|b| *b)),
},
ExprKind::Cast(ty, inner) => self.cast(ty, *inner),
ExprKind::ParameterAccess(sr, p) => self.parameter_access(sr, p),
ExprKind::FunctionCall(f, args) => self.function_call(f, args),
ExprKind::Tuple(inner) => self.tuple(inner),
ExprKind::TupleAccess(tuple, idx) => self.tuple_access(*tuple, idx),
ExprKind::LambdaParameterAccess(window_reference, idx) => {
self.lambda_parameter_access(window_reference, idx)
}
}
}
}
pub trait DefaultExprFormatter
where
Self: ExprFormatter<Return = String>
+ OperatorFormatter<Return = String>
+ FunctionFormatter<Return = String>
+ ConstantFormatter<Return = String>,
{
fn constant(&self, c: Constant) -> String {
<Self as ConstantFormatter>::constant(self, c)
}
fn unary(&self, op: Operator, operand: Expr) -> String {
format!("({}{})", self.op(op), self.expr(operand))
}
fn binary(&self, op: Operator, lhs: Expr, rhs: Expr) -> String {
format!("({}{}{})", self.expr(lhs), self.op(op), self.expr(rhs))
}
fn if_then_else(&self, condition: Expr, consequence: Expr, alternative: Expr) -> String {
format!(
"({}?{}:{})",
self.expr(condition),
self.expr(consequence),
self.expr(alternative)
)
}
fn sync_access(&self, sr: StreamReference, parameters: Vec<Expr>) -> String;
fn offset_access(
&self,
sr: StreamReference,
offset: u32,
default: Expr,
parameters: Vec<Expr>,
) -> String;
fn hold_access(&self, sr: StreamReference, default: Expr, parameters: Vec<Expr>) -> String;
fn get_access(&self, sr: StreamReference, default: Expr, parameters: Vec<Expr>) -> String;
fn is_fresh(&self, sr: StreamReference, parameters: Vec<Expr>) -> String;
fn sliding_window_access(&self, wref: usize, default: Option<Expr>) -> String;
fn discrete_window_access(&self, wref: usize, default: Option<Expr>) -> String;
fn instance_aggregation(&self, wref: usize, default: Option<Expr>) -> String;
fn parameter_access(&self, sr: StreamReference, p: usize) -> String;
fn lambda_parameter_access(&self, wref: WindowReference, idx: usize) -> String;
fn cast(&self, ty: Type, expr: Expr) -> String;
fn tuple(&self, inner: Vec<Expr>) -> String {
format!("({})", inner.into_iter().map(|e| self.expr(e)).join(", "))
}
fn tuple_access(&self, expr: Expr, i: usize) -> String {
format!("{}.{}", self.expr(expr), i)
}
fn function_call(&self, function: Function, args: Vec<Expr>) -> String {
let args = args.into_iter().map(|e| self.expr(e)).join(", ");
format!("{}({})", self.function(function), args)
}
}
impl<X> ExprFormatter for X
where
X: DefaultExprFormatter,
{
type Return = String;
fn constant(&self, c: Constant) -> Self::Return {
<Self as DefaultExprFormatter>::constant(self, c)
}
fn unary(&self, op: Operator, operand: Expr) -> Self::Return {
<Self as DefaultExprFormatter>::unary(self, op, operand)
}
fn binary(&self, op: Operator, lhs: Expr, rhs: Expr) -> Self::Return {
<Self as DefaultExprFormatter>::binary(self, op, lhs, rhs)
}
fn if_then_else(&self, condition: Expr, consequence: Expr, alternative: Expr) -> Self::Return {
<Self as DefaultExprFormatter>::if_then_else(self, condition, consequence, alternative)
}
fn sync_access(&self, stream: StreamReference, parameters: Vec<Expr>) -> Self::Return {
<Self as DefaultExprFormatter>::sync_access(self, stream, parameters)
}
fn offset_access(
&self,
stream: StreamReference,
offset: u32,
default: Expr,
parameters: Vec<Expr>,
) -> Self::Return {
<Self as DefaultExprFormatter>::offset_access(self, stream, offset, default, parameters)
}
fn hold_access(
&self,
stream: StreamReference,
default: Expr,
parameters: Vec<Expr>,
) -> Self::Return {
<Self as DefaultExprFormatter>::hold_access(self, stream, default, parameters)
}
fn get_access(
&self,
stream: StreamReference,
default: Expr,
parameters: Vec<Expr>,
) -> Self::Return {
<Self as DefaultExprFormatter>::get_access(self, stream, default, parameters)
}
fn is_fresh(&self, stream: StreamReference, parameters: Vec<Expr>) -> Self::Return {
<Self as DefaultExprFormatter>::is_fresh(self, stream, parameters)
}
fn sliding_window_access(&self, window_idx: usize, default: Option<Expr>) -> Self::Return {
<Self as DefaultExprFormatter>::sliding_window_access(self, window_idx, default)
}
fn discrete_window_access(&self, window_idx: usize, default: Option<Expr>) -> Self::Return {
<Self as DefaultExprFormatter>::discrete_window_access(self, window_idx, default)
}
fn instance_aggregation(&self, window_idx: usize, default: Option<Expr>) -> Self::Return {
<Self as DefaultExprFormatter>::instance_aggregation(self, window_idx, default)
}
fn parameter_access(&self, sr: StreamReference, p: usize) -> Self::Return {
<Self as DefaultExprFormatter>::parameter_access(self, sr, p)
}
fn lambda_parameter_access(&self, wref: WindowReference, idx: usize) -> Self::Return {
<Self as DefaultExprFormatter>::lambda_parameter_access(self, wref, idx)
}
fn cast(&self, ty: Type, expr: Expr) -> Self::Return {
<Self as DefaultExprFormatter>::cast(self, ty, expr)
}
fn tuple(&self, inner_exprs: Vec<Expr>) -> Self::Return {
<Self as DefaultExprFormatter>::tuple(self, inner_exprs)
}
fn tuple_access(&self, expr: Expr, i: usize) -> Self::Return {
<Self as DefaultExprFormatter>::tuple_access(self, expr, i)
}
fn function_call(&self, function: Function, args: Vec<Expr>) -> Self::Return {
<Self as DefaultExprFormatter>::function_call(self, function, args)
}
}
pub trait OperatorFormatter {
type Return;
fn op_not(&self) -> Self::Return;
fn op_neg(&self) -> Self::Return;
fn op_add(&self) -> Self::Return;
fn op_sub(&self) -> Self::Return;
fn op_mul(&self) -> Self::Return;
fn op_div(&self) -> Self::Return;
fn op_rem(&self) -> Self::Return;
fn op_pow(&self) -> Self::Return;
fn op_and(&self) -> Self::Return;
fn op_or(&self) -> Self::Return;
fn op_bitxor(&self) -> Self::Return;
fn op_bitand(&self) -> Self::Return;
fn op_bitor(&self) -> Self::Return;
fn op_bitnot(&self) -> Self::Return;
fn op_shr(&self) -> Self::Return;
fn op_shl(&self) -> Self::Return;
fn op_eq(&self) -> Self::Return;
fn op_lt(&self) -> Self::Return;
fn op_le(&self) -> Self::Return;
fn op_ne(&self) -> Self::Return;
fn op_ge(&self) -> Self::Return;
fn op_gt(&self) -> Self::Return;
fn op(&self, op: Operator) -> Self::Return {
match op {
Operator::Not => self.op_not(),
Operator::Neg => self.op_neg(),
Operator::Add => self.op_add(),
Operator::Sub => self.op_sub(),
Operator::Mul => self.op_mul(),
Operator::Div => self.op_div(),
Operator::Rem => self.op_rem(),
Operator::Pow => self.op_pow(),
Operator::And => self.op_and(),
Operator::Or => self.op_or(),
Operator::BitXor => self.op_bitxor(),
Operator::BitAnd => self.op_bitand(),
Operator::BitOr => self.op_bitor(),
Operator::BitNot => self.op_bitnot(),
Operator::Shl => self.op_shl(),
Operator::Shr => self.op_shr(),
Operator::Eq => self.op_eq(),
Operator::Lt => self.op_lt(),
Operator::Le => self.op_le(),
Operator::Ne => self.op_ne(),
Operator::Ge => self.op_ge(),
Operator::Gt => self.op_gt(),
}
}
}
pub trait DefaultOperatorFormatter {
fn op_not(&self) -> String {
"!".into()
}
fn op_neg(&self) -> String {
"-".into()
}
fn op_add(&self) -> String {
"+".into()
}
fn op_sub(&self) -> String {
"-".into()
}
fn op_mul(&self) -> String {
"*".into()
}
fn op_div(&self) -> String {
"/".into()
}
fn op_rem(&self) -> String {
"%".into()
}
fn op_pow(&self) -> String {
"**".into()
}
fn op_and(&self) -> String {
"&&".into()
}
fn op_or(&self) -> String {
"||".into()
}
fn op_bitxor(&self) -> String {
"^".into()
}
fn op_bitand(&self) -> String {
"&".into()
}
fn op_bitor(&self) -> String {
"|".into()
}
fn op_bitnot(&self) -> String {
"~".into()
}
fn op_shr(&self) -> String {
">>".into()
}
fn op_shl(&self) -> String {
"<<".into()
}
fn op_eq(&self) -> String {
"==".into()
}
fn op_lt(&self) -> String {
"<".into()
}
fn op_le(&self) -> String {
"<=".into()
}
fn op_ne(&self) -> String {
"!=".into()
}
fn op_ge(&self) -> String {
">=".into()
}
fn op_gt(&self) -> String {
">".into()
}
}
impl<X> OperatorFormatter for X
where
X: DefaultOperatorFormatter,
{
type Return = String;
fn op_not(&self) -> Self::Return {
<Self as DefaultOperatorFormatter>::op_not(self)
}
fn op_neg(&self) -> Self::Return {
<Self as DefaultOperatorFormatter>::op_neg(self)
}
fn op_add(&self) -> Self::Return {
<Self as DefaultOperatorFormatter>::op_add(self)
}
fn op_sub(&self) -> Self::Return {
<Self as DefaultOperatorFormatter>::op_sub(self)
}
fn op_mul(&self) -> Self::Return {
<Self as DefaultOperatorFormatter>::op_mul(self)
}
fn op_div(&self) -> Self::Return {
<Self as DefaultOperatorFormatter>::op_div(self)
}
fn op_rem(&self) -> Self::Return {
<Self as DefaultOperatorFormatter>::op_rem(self)
}
fn op_pow(&self) -> Self::Return {
<Self as DefaultOperatorFormatter>::op_pow(self)
}
fn op_and(&self) -> Self::Return {
<Self as DefaultOperatorFormatter>::op_and(self)
}
fn op_or(&self) -> Self::Return {
<Self as DefaultOperatorFormatter>::op_or(self)
}
fn op_bitxor(&self) -> Self::Return {
<Self as DefaultOperatorFormatter>::op_bitxor(self)
}
fn op_bitand(&self) -> Self::Return {
<Self as DefaultOperatorFormatter>::op_bitand(self)
}
fn op_bitor(&self) -> Self::Return {
<Self as DefaultOperatorFormatter>::op_bitor(self)
}
fn op_bitnot(&self) -> Self::Return {
<Self as DefaultOperatorFormatter>::op_bitnot(self)
}
fn op_shr(&self) -> Self::Return {
<Self as DefaultOperatorFormatter>::op_shr(self)
}
fn op_shl(&self) -> Self::Return {
<Self as DefaultOperatorFormatter>::op_shl(self)
}
fn op_eq(&self) -> Self::Return {
<Self as DefaultOperatorFormatter>::op_eq(self)
}
fn op_lt(&self) -> Self::Return {
<Self as DefaultOperatorFormatter>::op_lt(self)
}
fn op_le(&self) -> Self::Return {
<Self as DefaultOperatorFormatter>::op_le(self)
}
fn op_ne(&self) -> Self::Return {
<Self as DefaultOperatorFormatter>::op_ne(self)
}
fn op_ge(&self) -> Self::Return {
<Self as DefaultOperatorFormatter>::op_ge(self)
}
fn op_gt(&self) -> Self::Return {
<Self as DefaultOperatorFormatter>::op_gt(self)
}
}
pub trait FunctionFormatter {
type Return;
fn function_sqrt(&self) -> Self::Return;
fn function_abs(&self) -> Self::Return;
fn function_sin(&self) -> Self::Return;
fn function_arcsin(&self) -> Self::Return;
fn function_cos(&self) -> Self::Return;
fn function_arccos(&self) -> Self::Return;
fn function_tan(&self) -> Self::Return;
fn function_arctan(&self) -> Self::Return;
fn function_min(&self) -> Self::Return;
fn function_max(&self) -> Self::Return;
fn function(&self, f: Function) -> Self::Return {
match f {
Function::Sqrt => self.function_sqrt(),
Function::Abs => self.function_abs(),
Function::Sin => self.function_sin(),
Function::Arcsin => self.function_arcsin(),
Function::Cos => self.function_cos(),
Function::Arccos => self.function_arccos(),
Function::Tan => self.function_tan(),
Function::Arctan => self.function_arctan(),
Function::Min => self.function_min(),
Function::Max => self.function_max(),
}
}
}
pub trait DefaultFunctionFormatter {
fn function_sqrt(&self) -> String {
"sqrt".into()
}
fn function_abs(&self) -> String {
"abs".into()
}
fn function_sin(&self) -> String {
"sin".into()
}
fn function_arcsin(&self) -> String {
"arcsin".into()
}
fn function_cos(&self) -> String {
"cos".into()
}
fn function_arccos(&self) -> String {
"arccos".into()
}
fn function_tan(&self) -> String {
"tan".into()
}
fn function_arctan(&self) -> String {
"arctan".into()
}
fn function_min(&self) -> String {
"min".into()
}
fn function_max(&self) -> String {
"max".into()
}
}
impl<X> FunctionFormatter for X
where
X: DefaultFunctionFormatter,
{
type Return = String;
fn function_sqrt(&self) -> Self::Return {
<Self as DefaultFunctionFormatter>::function_sqrt(self)
}
fn function_abs(&self) -> Self::Return {
<Self as DefaultFunctionFormatter>::function_abs(self)
}
fn function_sin(&self) -> Self::Return {
<Self as DefaultFunctionFormatter>::function_sin(self)
}
fn function_arcsin(&self) -> Self::Return {
<Self as DefaultFunctionFormatter>::function_arcsin(self)
}
fn function_cos(&self) -> Self::Return {
<Self as DefaultFunctionFormatter>::function_cos(self)
}
fn function_arccos(&self) -> Self::Return {
<Self as DefaultFunctionFormatter>::function_arccos(self)
}
fn function_tan(&self) -> Self::Return {
<Self as DefaultFunctionFormatter>::function_tan(self)
}
fn function_arctan(&self) -> Self::Return {
<Self as DefaultFunctionFormatter>::function_arctan(self)
}
fn function_min(&self) -> Self::Return {
<Self as DefaultFunctionFormatter>::function_min(self)
}
fn function_max(&self) -> Self::Return {
<Self as DefaultFunctionFormatter>::function_max(self)
}
}
pub trait ConstantFormatter {
type Return;
fn constant_bool(&self, b: bool) -> Self::Return;
fn constant_string(&self, s: String) -> Self::Return;
fn constant_uint(&self, i: u64, _bits: u16) -> Self::Return;
fn constant_int(&self, i: i64, _bits: u16) -> Self::Return;
fn constant_float32(&self, f: f64) -> Self::Return;
fn constant_float64(&self, f: f64) -> Self::Return;
fn constant_tuple(&self, f: Vec<Constant>) -> Self::Return;
fn constant(&self, c: Constant) -> Self::Return {
match c {
Constant::Str(s) => self.constant_string(s),
Constant::Bool(b) => self.constant_bool(b),
Constant::UInt(u, b) => self.constant_uint(u, b),
Constant::Int(u, b) => self.constant_int(u, b),
Constant::Float32(f) => self.constant_float32(f),
Constant::Float64(f) => self.constant_float64(f),
Constant::Tuple(constants) => self.constant_tuple(constants),
}
}
}
pub trait DefaultConstantFormatter
where
Self: ConstantFormatter<Return = String>,
{
fn constant_bool(&self, b: bool) -> String {
match b {
true => "true",
false => "false",
}
.into()
}
fn constant_string(&self, s: String) -> String {
format!("\"{s}\"")
}
fn constant_uint(&self, i: u64, _bits: u16) -> String {
i.to_string()
}
fn constant_int(&self, i: i64, _bits: u16) -> String {
i.to_string()
}
fn constant_float32(&self, f: f64) -> String {
f.to_string()
}
fn constant_float64(&self, f: f64) -> String {
f.to_string()
}
fn constant_tuple(&self, f: Vec<Constant>) -> String {
let fields = f.into_iter().map(|v| self.constant(v)).join(", ");
format!("({})", fields)
}
}
impl<X> ConstantFormatter for X
where
X: DefaultConstantFormatter,
{
type Return = String;
fn constant_bool(&self, b: bool) -> Self::Return {
<Self as DefaultConstantFormatter>::constant_bool(self, b)
}
fn constant_string(&self, s: String) -> Self::Return {
<Self as DefaultConstantFormatter>::constant_string(self, s)
}
fn constant_uint(&self, i: u64, _bits: u16) -> Self::Return {
<Self as DefaultConstantFormatter>::constant_uint(self, i, _bits)
}
fn constant_int(&self, i: i64, _bits: u16) -> Self::Return {
<Self as DefaultConstantFormatter>::constant_int(self, i, _bits)
}
fn constant_float32(&self, f: f64) -> Self::Return {
<Self as DefaultConstantFormatter>::constant_float32(self, f)
}
fn constant_float64(&self, f: f64) -> Self::Return {
<Self as DefaultConstantFormatter>::constant_float64(self, f)
}
fn constant_tuple(&self, f: Vec<Constant>) -> Self::Return {
<Self as DefaultConstantFormatter>::constant_tuple(self, f)
}
}