Skip to main content

gruel_util/
ops.rs

1//! Shared binary and unary operator enums used across all IRs.
2//!
3//! Centralizing these means each IR's `InstData` enum has a single `Bin`
4//! or `Unary` variant, and ~20 parallel match arms across passes collapse
5//! into one. See ADR notes in the gruel-util README for background.
6
7use std::fmt;
8
9/// Binary operator. Used in expressions of the form `lhs <op> rhs`.
10///
11/// `And`/`Or` are short-circuiting and are lowered to control flow in the
12/// CFG builder; they should never appear in CFG instructions.
13#[derive(Debug, Clone, Copy, PartialEq, Eq, Hash, serde::Serialize, serde::Deserialize)]
14pub enum BinOp {
15    Add,
16    Sub,
17    Mul,
18    Div,
19    Mod,
20    Eq,
21    Ne,
22    Lt,
23    Gt,
24    Le,
25    Ge,
26    And,
27    Or,
28    BitAnd,
29    BitOr,
30    BitXor,
31    Shl,
32    Shr,
33}
34
35impl BinOp {
36    /// Mnemonic used by all IR pretty-printers.
37    pub const fn as_str(self) -> &'static str {
38        match self {
39            BinOp::Add => "add",
40            BinOp::Sub => "sub",
41            BinOp::Mul => "mul",
42            BinOp::Div => "div",
43            BinOp::Mod => "mod",
44            BinOp::Eq => "eq",
45            BinOp::Ne => "ne",
46            BinOp::Lt => "lt",
47            BinOp::Gt => "gt",
48            BinOp::Le => "le",
49            BinOp::Ge => "ge",
50            BinOp::And => "and",
51            BinOp::Or => "or",
52            BinOp::BitAnd => "bit_and",
53            BinOp::BitOr => "bit_or",
54            BinOp::BitXor => "bit_xor",
55            BinOp::Shl => "shl",
56            BinOp::Shr => "shr",
57        }
58    }
59
60    /// Surface-syntax spelling (e.g. `+`, `==`). Used in diagnostic messages.
61    pub const fn symbol(self) -> &'static str {
62        match self {
63            BinOp::Add => "+",
64            BinOp::Sub => "-",
65            BinOp::Mul => "*",
66            BinOp::Div => "/",
67            BinOp::Mod => "%",
68            BinOp::Eq => "==",
69            BinOp::Ne => "!=",
70            BinOp::Lt => "<",
71            BinOp::Gt => ">",
72            BinOp::Le => "<=",
73            BinOp::Ge => ">=",
74            BinOp::And => "&&",
75            BinOp::Or => "||",
76            BinOp::BitAnd => "&",
77            BinOp::BitOr => "|",
78            BinOp::BitXor => "^",
79            BinOp::Shl => "<<",
80            BinOp::Shr => ">>",
81        }
82    }
83
84    pub const fn is_arithmetic(self) -> bool {
85        matches!(
86            self,
87            BinOp::Add | BinOp::Sub | BinOp::Mul | BinOp::Div | BinOp::Mod
88        )
89    }
90
91    pub const fn is_comparison(self) -> bool {
92        matches!(
93            self,
94            BinOp::Eq | BinOp::Ne | BinOp::Lt | BinOp::Gt | BinOp::Le | BinOp::Ge
95        )
96    }
97
98    pub const fn is_short_circuit(self) -> bool {
99        matches!(self, BinOp::And | BinOp::Or)
100    }
101
102    pub const fn is_bitwise(self) -> bool {
103        matches!(
104            self,
105            BinOp::BitAnd | BinOp::BitOr | BinOp::BitXor | BinOp::Shl | BinOp::Shr
106        )
107    }
108}
109
110impl fmt::Display for BinOp {
111    fn fmt(&self, f: &mut fmt::Formatter<'_>) -> fmt::Result {
112        f.write_str(self.as_str())
113    }
114}
115
116/// Unary operator. Used in expressions of the form `<op>operand`.
117#[derive(Debug, Clone, Copy, PartialEq, Eq, Hash, serde::Serialize, serde::Deserialize)]
118pub enum UnaryOp {
119    /// Arithmetic negation: `-x`
120    Neg,
121    /// Logical NOT: `!x` (boolean)
122    Not,
123    /// Bitwise NOT: `~x`
124    BitNot,
125}
126
127impl UnaryOp {
128    pub const fn as_str(self) -> &'static str {
129        match self {
130            UnaryOp::Neg => "neg",
131            UnaryOp::Not => "not",
132            UnaryOp::BitNot => "bit_not",
133        }
134    }
135
136    pub const fn symbol(self) -> &'static str {
137        match self {
138            UnaryOp::Neg => "-",
139            UnaryOp::Not => "!",
140            UnaryOp::BitNot => "~",
141        }
142    }
143}
144
145impl fmt::Display for UnaryOp {
146    fn fmt(&self, f: &mut fmt::Formatter<'_>) -> fmt::Result {
147        f.write_str(self.as_str())
148    }
149}