/ compiler / ast / src / expressions / binary.rs
binary.rs
  1  // Copyright (C) 2019-2025 ADnet Contributors
  2  // This file is part of the ADL library.
  3  
  4  // The ADL 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 ADL 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 ADL library. If not, see <https://www.gnu.org/licenses/>.
 16  
 17  use super::*;
 18  use adl_span::{Symbol, sym};
 19  
 20  use std::cmp::Ordering;
 21  
 22  /// A binary operator.
 23  ///
 24  /// Precedence is defined in the parser.
 25  #[derive(Debug, Copy, Clone, PartialEq, Eq, Hash, Ord, PartialOrd, Serialize, Deserialize)]
 26  pub 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  
 89  impl 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  
126  impl 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)]
167  pub 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  
180  impl 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  
222  impl 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  
257  impl From<BinaryExpression> for Expression {
258      fn from(value: BinaryExpression) -> Self {
259          Expression::Binary(Box::new(value))
260      }
261  }
262  
263  crate::simple_node_impl!(BinaryExpression);