leo_ast/expressions/
binary.rs

1// Copyright (C) 2019-2025 Provable Inc.
2// This file is part of the Leo library.
3
4// The Leo library is free software: you can redistribute it and/or modify
5// it under the terms of the GNU General Public License as published by
6// the Free Software Foundation, either version 3 of the License, or
7// (at your option) any later version.
8
9// The Leo library is distributed in the hope that it will be useful,
10// but WITHOUT ANY WARRANTY; without even the implied warranty of
11// MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
12// GNU General Public License for more details.
13
14// You should have received a copy of the GNU General Public License
15// along with the Leo library. If not, see <https://www.gnu.org/licenses/>.
16
17use super::*;
18use leo_span::{Symbol, sym};
19
20use std::cmp::Ordering;
21
22/// A binary operator.
23///
24/// Precedence is defined in the parser.
25#[derive(Debug, Copy, Clone, PartialEq, Eq, Serialize, Deserialize)]
26pub enum BinaryOperation {
27    /// Addition, i.e. `+`, `.add()`.
28    Add,
29    /// Wrapping addition, i.e. `.add_wrapped()`.
30    AddWrapped,
31    /// Logical AND, i.e. `&&`.
32    And,
33    /// Bitwise AND, i.e. `&`, `.and()`.
34    BitwiseAnd,
35    /// Division, i.e. `/`, `.div()`.
36    Div,
37    /// Wrapping division, i.e. `.div_wrapped()`.
38    DivWrapped,
39    /// Equality relation, i.e. `==`, `.eq()`.
40    Eq,
41    /// Greater-or-equal relation, i.e. `>=`, `.gte()`.
42    Gte,
43    /// Greater-than relation, i.e. `>`, `.gt()`.
44    Gt,
45    /// Lesser-or-equal relation, i.e. `<=`, `.lte()`.
46    Lte,
47    /// Lesser-than relation, i.e. `<`, `.lt()`.
48    Lt,
49    /// Arithmetic modulo, i.e. `.mod()`
50    Mod,
51    /// Multiplication, i.e. `*`, `.mul()`.
52    Mul,
53    /// Wrapping multiplication, i.e. `.mul_wrapped()`.
54    MulWrapped,
55    /// Boolean NAND, i.e. `.nand()`.
56    Nand,
57    /// In-equality relation, i.e. `!=`, `.neq()`.
58    Neq,
59    /// Boolean NOR, i.e. `.nor()`.
60    Nor,
61    /// Logical OR, i.e. `||`.
62    Or,
63    /// Bitwise OR, i.e. `|`, `.or()`.
64    BitwiseOr,
65    /// Exponentiation, i.e. `**` in `a ** b`, `.pow()`.
66    Pow,
67    /// Wrapping exponentiation, i.e. `.pow_wrapped()`.
68    PowWrapped,
69    /// Remainder, i.e. `%`, `.rem()`.
70    Rem,
71    /// Wrapping remainder, i.e. `.rem_wrapped()`.
72    RemWrapped,
73    /// Shift left operation, i.e. `<<`, `.shl()`.
74    Shl,
75    /// Wrapping shift left operation, i.e. `.shl_wrapped()`.
76    ShlWrapped,
77    /// Shift right operation, i.e. >>, `.shr()`.
78    Shr,
79    /// Wrapping shift right operation, i.e. `.shr_wrapped()`.
80    ShrWrapped,
81    /// Subtraction, i.e. `-`, `.sub()`.
82    Sub,
83    /// Wrapped subtraction, i.e. `.sub_wrapped()`.
84    SubWrapped,
85    /// Bitwise XOR, i.e. `.xor()`.
86    Xor,
87}
88
89impl fmt::Display for BinaryOperation {
90    fn fmt(&self, f: &mut fmt::Formatter) -> fmt::Result {
91        write!(f, "{}", match self {
92            Self::Add => "+",
93            Self::AddWrapped => "add_wrapped",
94            Self::And => "&&",
95            Self::BitwiseAnd => "&",
96            Self::Div => "/",
97            Self::DivWrapped => "div_wrapped",
98            Self::Eq => "==",
99            Self::Gte => ">=",
100            Self::Gt => ">",
101            Self::Lte => "<=",
102            Self::Lt => "<",
103            Self::Mod => "mod",
104            Self::Mul => "*",
105            Self::MulWrapped => "mul_wrapped",
106            Self::Nand => "NAND",
107            Self::Neq => "!=",
108            Self::Nor => "NOR",
109            Self::Or => "||",
110            Self::BitwiseOr => "|",
111            Self::Pow => "**",
112            Self::PowWrapped => "pow_wrapped",
113            Self::Rem => "%",
114            Self::RemWrapped => "rem_wrapped",
115            Self::Shl => "<<",
116            Self::ShlWrapped => "shl_wrapped",
117            Self::Shr => ">>",
118            Self::ShrWrapped => "shr_wrapped",
119            Self::Sub => "-",
120            Self::SubWrapped => "sub_wrapped",
121            Self::Xor => "^",
122        })
123    }
124}
125
126impl BinaryOperation {
127    /// Returns a `BinaryOperation` from the given `Symbol`.
128    /// This is used to resolve native operators invoked as method calls, e.g. `a.add_wrapped(b)`.
129    pub fn from_symbol(symbol: Symbol) -> Option<Self> {
130        Some(match symbol {
131            sym::add => Self::Add,
132            sym::add_wrapped => Self::AddWrapped,
133            sym::and => Self::BitwiseAnd,
134            sym::div => Self::Div,
135            sym::div_wrapped => Self::DivWrapped,
136            sym::eq => Self::Eq,
137            sym::gte => Self::Gte,
138            sym::gt => Self::Gt,
139            sym::lte => Self::Lte,
140            sym::lt => Self::Lt,
141            sym::Mod => Self::Mod,
142            sym::mul => Self::Mul,
143            sym::mul_wrapped => Self::MulWrapped,
144            sym::nand => Self::Nand,
145            sym::neq => Self::Neq,
146            sym::nor => Self::Nor,
147            sym::or => Self::BitwiseOr,
148            sym::pow => Self::Pow,
149            sym::pow_wrapped => Self::PowWrapped,
150            sym::rem => Self::Rem,
151            sym::rem_wrapped => Self::RemWrapped,
152            sym::shl => Self::Shl,
153            sym::shl_wrapped => Self::ShlWrapped,
154            sym::shr => Self::Shr,
155            sym::shr_wrapped => Self::ShrWrapped,
156            sym::sub => Self::Sub,
157            sym::sub_wrapped => Self::SubWrapped,
158            sym::xor => Self::Xor,
159            _ => return None,
160        })
161    }
162}
163
164/// A binary expression `left op right` of two operands separated by some operator.
165/// For example, `foo + bar`.
166#[derive(Debug, Clone, PartialEq, Eq, Serialize, Deserialize)]
167pub struct BinaryExpression {
168    /// The left operand of the expression.
169    pub left: Expression,
170    /// The right operand of the expression.
171    pub right: Expression,
172    /// The operand defining the meaning of the resulting binary expression.
173    pub op: BinaryOperation,
174    /// The span from `left` to `right`.
175    pub span: Span,
176    /// The ID of the expression.
177    pub id: NodeID,
178}
179
180impl fmt::Display for BinaryExpression {
181    fn fmt(&self, f: &mut fmt::Formatter) -> fmt::Result {
182        use Associativity::*;
183        use BinaryOperation::*;
184
185        if matches!(
186            self.op,
187            AddWrapped
188                | DivWrapped
189                | Mod
190                | MulWrapped
191                | Nand
192                | Nor
193                | PowWrapped
194                | RemWrapped
195                | ShlWrapped
196                | ShrWrapped
197                | SubWrapped
198        ) {
199            if self.left.precedence() < 20 {
200                write!(f, "({})", self.left)?;
201            } else {
202                write!(f, "{}", self.left)?;
203            }
204            write!(f, ".{}({})", self.op, self.right)
205        } else {
206            let my_precedence = self.precedence();
207            let my_associativity = self.associativity();
208            match (self.left.precedence().cmp(&my_precedence), my_associativity, self.left.associativity()) {
209                (Ordering::Greater, _, _) | (Ordering::Equal, Left, Left) => write!(f, "{}", self.left)?,
210                _ => write!(f, "({})", self.left)?,
211            }
212            write!(f, " {} ", self.op)?;
213            match (self.right.precedence().cmp(&my_precedence), my_associativity, self.right.associativity()) {
214                (Ordering::Greater, _, _) | (Ordering::Equal, Right, Right) => write!(f, "{}", self.right)?,
215                _ => write!(f, "({})", self.right)?,
216            }
217            Ok(())
218        }
219    }
220}
221
222impl BinaryExpression {
223    pub(crate) fn precedence(&self) -> u32 {
224        use BinaryOperation::*;
225
226        match self.op {
227            BitwiseOr => 1,
228            BitwiseAnd => 2,
229            Eq | Neq | Lt | Gt | Lte | Gte => 3,
230            Or => 4,
231            Xor => 5,
232            And => 6,
233            Shl => 7,
234            Shr => 8,
235            Add | Sub => 9,
236            Mul | Div | Rem => 10,
237            Pow => 11,
238            AddWrapped | DivWrapped | Mod | MulWrapped | Nand | Nor | PowWrapped | RemWrapped | ShlWrapped
239            | ShrWrapped | SubWrapped => 20,
240        }
241    }
242
243    pub(crate) fn associativity(&self) -> Associativity {
244        use Associativity::*;
245        use BinaryOperation::*;
246
247        match self.op {
248            Pow => Right,
249            BitwiseOr | BitwiseAnd | Eq | Neq | Lt | Gt | Lte | Gte | Or | Xor | And | Shl | Shr | Add | Sub | Mul
250            | Div | Rem => Left,
251            AddWrapped | DivWrapped | Mod | MulWrapped | Nand | Nor | PowWrapped | RemWrapped | ShlWrapped
252            | ShrWrapped | SubWrapped => None,
253        }
254    }
255}
256
257impl From<BinaryExpression> for Expression {
258    fn from(value: BinaryExpression) -> Self {
259        Expression::Binary(Box::new(value))
260    }
261}
262
263crate::simple_node_impl!(BinaryExpression);