use super::*;
use leo_span::{Symbol, sym};
use std::cmp::Ordering;
#[derive(Debug, Copy, Clone, PartialEq, Eq, Hash, Ord, PartialOrd, Serialize, Deserialize)]
pub enum BinaryOperation {
Add,
AddWrapped,
And,
BitwiseAnd,
Div,
DivWrapped,
Eq,
Gte,
Gt,
Lte,
Lt,
Mod,
Mul,
MulWrapped,
Nand,
Neq,
Nor,
Or,
BitwiseOr,
Pow,
PowWrapped,
Rem,
RemWrapped,
Shl,
ShlWrapped,
Shr,
ShrWrapped,
Sub,
SubWrapped,
Xor,
}
impl fmt::Display for BinaryOperation {
fn fmt(&self, f: &mut fmt::Formatter) -> fmt::Result {
write!(f, "{}", match self {
Self::Add => "+",
Self::AddWrapped => "add_wrapped",
Self::And => "&&",
Self::BitwiseAnd => "&",
Self::Div => "/",
Self::DivWrapped => "div_wrapped",
Self::Eq => "==",
Self::Gte => ">=",
Self::Gt => ">",
Self::Lte => "<=",
Self::Lt => "<",
Self::Mod => "mod",
Self::Mul => "*",
Self::MulWrapped => "mul_wrapped",
Self::Nand => "NAND",
Self::Neq => "!=",
Self::Nor => "NOR",
Self::Or => "||",
Self::BitwiseOr => "|",
Self::Pow => "**",
Self::PowWrapped => "pow_wrapped",
Self::Rem => "%",
Self::RemWrapped => "rem_wrapped",
Self::Shl => "<<",
Self::ShlWrapped => "shl_wrapped",
Self::Shr => ">>",
Self::ShrWrapped => "shr_wrapped",
Self::Sub => "-",
Self::SubWrapped => "sub_wrapped",
Self::Xor => "^",
})
}
}
impl BinaryOperation {
pub fn from_symbol(symbol: Symbol) -> Option<Self> {
Some(match symbol {
sym::add => Self::Add,
sym::add_wrapped => Self::AddWrapped,
sym::and => Self::BitwiseAnd,
sym::div => Self::Div,
sym::div_wrapped => Self::DivWrapped,
sym::eq => Self::Eq,
sym::gte => Self::Gte,
sym::gt => Self::Gt,
sym::lte => Self::Lte,
sym::lt => Self::Lt,
sym::Mod => Self::Mod,
sym::mul => Self::Mul,
sym::mul_wrapped => Self::MulWrapped,
sym::nand => Self::Nand,
sym::neq => Self::Neq,
sym::nor => Self::Nor,
sym::or => Self::BitwiseOr,
sym::pow => Self::Pow,
sym::pow_wrapped => Self::PowWrapped,
sym::rem => Self::Rem,
sym::rem_wrapped => Self::RemWrapped,
sym::shl => Self::Shl,
sym::shl_wrapped => Self::ShlWrapped,
sym::shr => Self::Shr,
sym::shr_wrapped => Self::ShrWrapped,
sym::sub => Self::Sub,
sym::sub_wrapped => Self::SubWrapped,
sym::xor => Self::Xor,
_ => return None,
})
}
}
#[derive(Debug, Clone, PartialEq, Eq, Serialize, Deserialize)]
pub struct BinaryExpression {
pub left: Expression,
pub right: Expression,
pub op: BinaryOperation,
pub span: Span,
pub id: NodeID,
}
impl fmt::Display for BinaryExpression {
fn fmt(&self, f: &mut fmt::Formatter) -> fmt::Result {
use Associativity::*;
use BinaryOperation::*;
if matches!(
self.op,
AddWrapped
| DivWrapped
| Mod
| MulWrapped
| Nand
| Nor
| PowWrapped
| RemWrapped
| ShlWrapped
| ShrWrapped
| SubWrapped
) {
if self.left.precedence() < 20 {
write!(f, "({})", self.left)?;
} else {
write!(f, "{}", self.left)?;
}
write!(f, ".{}({})", self.op, self.right)
} else {
let my_precedence = self.precedence();
let my_associativity = self.associativity();
match (self.left.precedence().cmp(&my_precedence), my_associativity, self.left.associativity()) {
(Ordering::Greater, _, _) | (Ordering::Equal, Left, Left) => write!(f, "{}", self.left)?,
_ => write!(f, "({})", self.left)?,
}
write!(f, " {} ", self.op)?;
match (self.right.precedence().cmp(&my_precedence), my_associativity, self.right.associativity()) {
(Ordering::Greater, _, _) | (Ordering::Equal, Right, Right) => write!(f, "{}", self.right)?,
_ => write!(f, "({})", self.right)?,
}
Ok(())
}
}
}
impl BinaryExpression {
pub(crate) fn precedence(&self) -> u32 {
use BinaryOperation::*;
match self.op {
BitwiseOr => 1,
BitwiseAnd => 2,
Eq | Neq | Lt | Gt | Lte | Gte => 3,
Or => 4,
Xor => 5,
And => 6,
Shl => 7,
Shr => 8,
Add | Sub => 9,
Mul | Div | Rem => 10,
Pow => 11,
AddWrapped | DivWrapped | Mod | MulWrapped | Nand | Nor | PowWrapped | RemWrapped | ShlWrapped
| ShrWrapped | SubWrapped => 20,
}
}
pub(crate) fn associativity(&self) -> Associativity {
use Associativity::*;
use BinaryOperation::*;
match self.op {
Pow => Right,
BitwiseOr | BitwiseAnd | Eq | Neq | Lt | Gt | Lte | Gte | Or | Xor | And | Shl | Shr | Add | Sub | Mul
| Div | Rem => Left,
AddWrapped | DivWrapped | Mod | MulWrapped | Nand | Nor | PowWrapped | RemWrapped | ShlWrapped
| ShrWrapped | SubWrapped => None,
}
}
}
impl From<BinaryExpression> for Expression {
fn from(value: BinaryExpression) -> Self {
Expression::Binary(Box::new(value))
}
}
crate::simple_node_impl!(BinaryExpression);