leo_ast/expressions/unary.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
20/// A unary operator for a unary expression.
21#[derive(Debug, Copy, Clone, PartialEq, Eq, Serialize, Deserialize)]
22pub enum UnaryOperation {
23 /// Absolute value checking for overflow, i.e. `.abs()`.
24 Abs,
25 /// Absolute value wrapping around at the boundary of the type, i.e. `.abs_wrapped()`.
26 AbsWrapped,
27 /// Double operation, i.e. `.double()`.
28 Double,
29 /// Multiplicative inverse, i.e. `.inv()`.
30 Inverse,
31 /// Negate operation, i.e. `.neg()`.
32 Negate,
33 /// Bitwise NOT, i.e. `!`, `.not()`.
34 Not,
35 /// Square operation, i.e. `.square()`.
36 Square,
37 /// Square root operation, i.e. `.sqrt()`.
38 SquareRoot,
39 /// Converts a group element to its x-coordinate, i.e. `.to_x_coordinate()`.
40 ToXCoordinate,
41 /// Converts a group element to its y-coordinate, i.e. `.to_y_coordinate()`.
42 ToYCoordinate,
43}
44
45impl UnaryOperation {
46 /// Returns a `UnaryOperation` from the given `Symbol`.
47 pub fn from_symbol(symbol: Symbol) -> Option<Self> {
48 Some(match symbol {
49 sym::abs => Self::Abs,
50 sym::abs_wrapped => Self::AbsWrapped,
51 sym::double => Self::Double,
52 sym::inv => Self::Inverse,
53 sym::neg => Self::Negate,
54 sym::not => Self::Not,
55 sym::square => Self::Square,
56 sym::square_root => Self::SquareRoot,
57 sym::to_x_coordinate => Self::ToXCoordinate,
58 sym::to_y_coordinate => Self::ToYCoordinate,
59 _ => return None,
60 })
61 }
62
63 /// Represents the operator as a string.
64 fn as_str(self) -> &'static str {
65 match self {
66 Self::Abs => "abs",
67 Self::AbsWrapped => "abs_wrapped",
68 Self::Double => "double",
69 Self::Inverse => "inv",
70 Self::Negate => "neg",
71 Self::Not => "not",
72 Self::Square => "square",
73 Self::SquareRoot => "square_root",
74 Self::ToXCoordinate => "to_x_coordinate",
75 Self::ToYCoordinate => "to_y_coordinate",
76 }
77 }
78}
79
80impl fmt::Display for UnaryOperation {
81 fn fmt(&self, f: &mut fmt::Formatter) -> fmt::Result {
82 write!(f, "{}", self.as_str())
83 }
84}
85
86/// An unary expression applying an operator to an inner expression.
87#[derive(Debug, Clone, PartialEq, Eq, Serialize, Deserialize)]
88pub struct UnaryExpression {
89 /// The inner expression `op` is applied to.
90 pub receiver: Expression,
91 /// The unary operator to apply to `inner`.
92 pub op: UnaryOperation,
93 /// The span covering `op inner`.
94 pub span: Span,
95 /// The ID of the node.
96 pub id: NodeID,
97}
98
99impl fmt::Display for UnaryExpression {
100 fn fmt(&self, f: &mut fmt::Formatter) -> fmt::Result {
101 if self.receiver.precedence() < 20 {
102 write!(f, "({})", self.receiver)?;
103 } else {
104 write!(f, "{}", self.receiver)?;
105 }
106 write!(f, ".{}()", self.op)
107 }
108}
109
110impl From<UnaryExpression> for Expression {
111 fn from(value: UnaryExpression) -> Self {
112 Expression::Unary(Box::new(value))
113 }
114}
115
116crate::simple_node_impl!(UnaryExpression);