analyssa 0.1.0

Target-agnostic SSA IR, analyses, and optimization pipeline
Documentation
//! Symbolic operation types for expression trees.
//!
//! This module defines [`SymbolicOp`], the set of operations supported in
//! [`SymbolicExpr`](super::SymbolicExpr) trees. These operations map directly
//! to CIL arithmetic and logical operations using 32-bit wrapping semantics
//! (ECMA-335).
//!
//! # Operation Categories
//!
//! | Category | Operations | Properties |
//! |----------|------------|------------|
//! | Arithmetic | Add, Sub, Mul, DivS, DivU, RemS, RemU, Neg | Wrapping 32-bit |
//! | Bitwise | And, Or, Xor, Not, Shl, ShrS, ShrU | Standard bitwise |
//! | Comparison | Eq, Ne, LtS, LtU, GtS, GtU, LeS, LeU, GeS, GeU | Return 0 or 1 |
//!
//! Commutative operations: Add, Mul, And, Or, Xor, Eq, Ne.
//! Unary operations: Neg, Not.

use std::fmt;

/// A symbolic operation in an expression tree.
#[derive(Debug, Clone, Copy, PartialEq, Eq, Hash)]
pub enum SymbolicOp {
    // Arithmetic operations
    /// Addition.
    Add,
    /// Subtraction.
    Sub,
    /// Multiplication.
    Mul,
    /// Signed division.
    DivS,
    /// Unsigned division.
    DivU,
    /// Signed remainder (modulo).
    RemS,
    /// Unsigned remainder (modulo).
    RemU,
    /// Negation.
    Neg,

    // Rotate operations
    /// Rotate left.
    Rol,
    /// Rotate right.
    Ror,
    /// Rotate through carry left.
    Rcl,
    /// Rotate through carry right.
    Rcr,

    // Bit manipulation operations
    /// Byte swap.
    BSwap,
    /// Bit reverse.
    BRev,
    /// Bit scan forward (index of least significant set bit).
    BitScanForward,
    /// Bit scan reverse (index of most significant set bit).
    BitScanReverse,
    /// Population count (number of set bits).
    Popcount,
    /// Parity (1 if odd number of set bits, 0 if even).
    Parity,

    // Bitwise operations
    /// Bitwise AND.
    And,
    /// Bitwise OR.
    Or,
    /// Bitwise XOR.
    Xor,
    /// Bitwise NOT.
    Not,
    /// Shift left.
    Shl,
    /// Arithmetic shift right (preserves sign).
    ShrS,
    /// Logical shift right (zero-fill).
    ShrU,

    // Comparison operations (return 0 or 1)
    /// Equal.
    Eq,
    /// Not equal.
    Ne,
    /// Signed less than.
    LtS,
    /// Unsigned less than.
    LtU,
    /// Signed greater than.
    GtS,
    /// Unsigned greater than.
    GtU,
    /// Signed less than or equal.
    LeS,
    /// Unsigned less than or equal.
    LeU,
    /// Signed greater than or equal.
    GeS,
    /// Unsigned greater than or equal.
    GeU,
}

impl SymbolicOp {
    /// Checks if this operation is commutative.
    ///
    /// Commutative operations produce the same result regardless of operand order:
    /// `a op b == b op a`. This property is useful for expression canonicalization.
    ///
    /// # Returns
    ///
    /// `true` if the operation is commutative (Add, Mul, And, Or, Xor, Eq, Ne).
    #[must_use]
    pub const fn is_commutative(self) -> bool {
        matches!(
            self,
            Self::Add | Self::Mul | Self::And | Self::Or | Self::Xor | Self::Eq | Self::Ne
        )
    }

    /// Checks if this operation is a comparison.
    ///
    /// Comparison operations return 0 or 1 based on the relationship between operands.
    ///
    /// # Returns
    ///
    /// `true` if this is a comparison operation (Eq, Ne, Lt*, Gt*, Le*, Ge*).
    #[must_use]
    pub const fn is_comparison(self) -> bool {
        matches!(
            self,
            Self::Eq
                | Self::Ne
                | Self::LtS
                | Self::LtU
                | Self::GtS
                | Self::GtU
                | Self::LeS
                | Self::LeU
                | Self::GeS
                | Self::GeU
        )
    }

    /// Checks if this is a unary operation.
    ///
    /// Unary operations take a single operand, unlike binary operations which take two.
    ///
    /// # Returns
    ///
    /// `true` if this is a unary operation (Neg, Not, BSwap, BRev,
    /// BitScanForward, BitScanReverse, Popcount, Parity).
    #[must_use]
    pub const fn is_unary(self) -> bool {
        matches!(
            self,
            Self::Neg
                | Self::Not
                | Self::BSwap
                | Self::BRev
                | Self::BitScanForward
                | Self::BitScanReverse
                | Self::Popcount
                | Self::Parity
        )
    }
}

impl fmt::Display for SymbolicOp {
    #[allow(clippy::match_same_arms)] // Sub and Neg are semantically different (binary vs unary)
    fn fmt(&self, f: &mut fmt::Formatter<'_>) -> fmt::Result {
        match self {
            Self::Add => write!(f, "+"),
            Self::Sub => write!(f, "-"),
            Self::Mul => write!(f, "*"),
            Self::DivS => write!(f, "/"),
            Self::DivU => write!(f, "/u"),
            Self::RemS => write!(f, "%"),
            Self::RemU => write!(f, "%u"),
            Self::Neg => write!(f, "-"),
            Self::Rol => write!(f, "rol"),
            Self::Ror => write!(f, "ror"),
            Self::Rcl => write!(f, "rcl"),
            Self::Rcr => write!(f, "rcr"),
            Self::BSwap => write!(f, "bswap"),
            Self::BRev => write!(f, "brev"),
            Self::BitScanForward => write!(f, "bsf"),
            Self::BitScanReverse => write!(f, "bsr"),
            Self::Popcount => write!(f, "popcnt"),
            Self::Parity => write!(f, "parity"),
            Self::And => write!(f, "&"),
            Self::Or => write!(f, "|"),
            Self::Xor => write!(f, "^"),
            Self::Not => write!(f, "~"),
            Self::Shl => write!(f, "<<"),
            Self::ShrS => write!(f, ">>"),
            Self::ShrU => write!(f, ">>>"),
            Self::Eq => write!(f, "=="),
            Self::Ne => write!(f, "!="),
            Self::LtS => write!(f, "<"),
            Self::LtU => write!(f, "<u"),
            Self::GtS => write!(f, ">"),
            Self::GtU => write!(f, ">u"),
            Self::LeS => write!(f, "<="),
            Self::LeU => write!(f, "<=u"),
            Self::GeS => write!(f, ">="),
            Self::GeU => write!(f, ">=u"),
        }
    }
}