leo_ast/expressions/
mod.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 crate::{Identifier, Node, NodeID};
18use leo_span::Span;
19
20use serde::{Deserialize, Serialize};
21use std::fmt;
22
23mod array_access;
24pub use array_access::*;
25
26mod associated_constant;
27pub use associated_constant::*;
28
29mod associated_function;
30pub use associated_function::*;
31
32mod array;
33pub use array::*;
34
35mod binary;
36pub use binary::*;
37
38mod call;
39pub use call::*;
40
41mod cast;
42pub use cast::*;
43
44mod err;
45pub use err::*;
46
47mod member_access;
48pub use member_access::*;
49
50mod repeat;
51pub use repeat::*;
52
53mod struct_init;
54pub use struct_init::*;
55
56mod ternary;
57pub use ternary::*;
58
59mod tuple;
60pub use tuple::*;
61
62mod tuple_access;
63pub use tuple_access::*;
64
65mod unary;
66pub use unary::*;
67
68mod unit;
69pub use unit::*;
70
71mod literal;
72pub use literal::*;
73
74pub mod locator;
75pub use locator::*;
76
77/// Expression that evaluates to a value.
78#[derive(Debug, Clone, PartialEq, Eq, Serialize, Deserialize)]
79pub enum Expression {
80    /// An array access, e.g. `arr[i]`.
81    ArrayAccess(Box<ArrayAccess>),
82    /// An associated constant; e.g., `group::GEN`.
83    AssociatedConstant(AssociatedConstantExpression),
84    /// An associated function; e.g., `BHP256::hash_to_field`.
85    AssociatedFunction(AssociatedFunctionExpression),
86    /// An array expression, e.g., `[true, false, true, false]`.
87    Array(ArrayExpression),
88    /// A binary expression, e.g., `42 + 24`.
89    Binary(Box<BinaryExpression>),
90    /// A call expression, e.g., `my_fun(args)`.
91    Call(Box<CallExpression>),
92    /// A cast expression, e.g., `42u32 as u8`.
93    Cast(Box<CastExpression>),
94    /// An expression of type "error".
95    /// Will result in a compile error eventually.
96    Err(ErrExpression),
97    /// An identifier.
98    Identifier(Identifier),
99    /// A literal expression.
100    Literal(Literal),
101    /// A locator expression, e.g., `hello.aleo/foo`.
102    Locator(LocatorExpression),
103    /// An access of a struct member, e.g. `struc.member`.
104    MemberAccess(Box<MemberAccess>),
105    /// An array expression constructed from one repeated element, e.g., `[1u32; 5]`.
106    Repeat(Box<RepeatExpression>),
107    /// An expression constructing a struct like `Foo { bar: 42, baz }`.
108    Struct(StructExpression),
109    /// A ternary conditional expression `cond ? if_expr : else_expr`.
110    Ternary(Box<TernaryExpression>),
111    /// A tuple expression e.g., `(foo, 42, true)`.
112    Tuple(TupleExpression),
113    /// A tuple access expression e.g., `foo.2`.
114    TupleAccess(Box<TupleAccess>),
115    /// An unary expression.
116    Unary(Box<UnaryExpression>),
117    /// A unit expression e.g. `()`
118    Unit(UnitExpression),
119}
120
121impl Default for Expression {
122    fn default() -> Self {
123        Expression::Err(Default::default())
124    }
125}
126
127impl Node for Expression {
128    fn span(&self) -> Span {
129        use Expression::*;
130        match self {
131            ArrayAccess(n) => n.span(),
132            Array(n) => n.span(),
133            AssociatedConstant(n) => n.span(),
134            AssociatedFunction(n) => n.span(),
135            Binary(n) => n.span(),
136            Call(n) => n.span(),
137            Cast(n) => n.span(),
138            Err(n) => n.span(),
139            Identifier(n) => n.span(),
140            Literal(n) => n.span(),
141            Locator(n) => n.span(),
142            MemberAccess(n) => n.span(),
143            Repeat(n) => n.span(),
144            Struct(n) => n.span(),
145            Ternary(n) => n.span(),
146            Tuple(n) => n.span(),
147            TupleAccess(n) => n.span(),
148            Unary(n) => n.span(),
149            Unit(n) => n.span(),
150        }
151    }
152
153    fn set_span(&mut self, span: Span) {
154        use Expression::*;
155        match self {
156            ArrayAccess(n) => n.set_span(span),
157            Array(n) => n.set_span(span),
158            AssociatedConstant(n) => n.set_span(span),
159            AssociatedFunction(n) => n.set_span(span),
160            Binary(n) => n.set_span(span),
161            Call(n) => n.set_span(span),
162            Cast(n) => n.set_span(span),
163            Err(n) => n.set_span(span),
164            Identifier(n) => n.set_span(span),
165            Literal(n) => n.set_span(span),
166            Locator(n) => n.set_span(span),
167            MemberAccess(n) => n.set_span(span),
168            Repeat(n) => n.set_span(span),
169            Struct(n) => n.set_span(span),
170            Ternary(n) => n.set_span(span),
171            Tuple(n) => n.set_span(span),
172            TupleAccess(n) => n.set_span(span),
173            Unary(n) => n.set_span(span),
174            Unit(n) => n.set_span(span),
175        }
176    }
177
178    fn id(&self) -> NodeID {
179        use Expression::*;
180        match self {
181            Array(n) => n.id(),
182            ArrayAccess(n) => n.id(),
183            AssociatedConstant(n) => n.id(),
184            AssociatedFunction(n) => n.id(),
185            Binary(n) => n.id(),
186            Call(n) => n.id(),
187            Cast(n) => n.id(),
188            Identifier(n) => n.id(),
189            Literal(n) => n.id(),
190            Locator(n) => n.id(),
191            MemberAccess(n) => n.id(),
192            Repeat(n) => n.id(),
193            Err(n) => n.id(),
194            Struct(n) => n.id(),
195            Ternary(n) => n.id(),
196            Tuple(n) => n.id(),
197            TupleAccess(n) => n.id(),
198            Unary(n) => n.id(),
199            Unit(n) => n.id(),
200        }
201    }
202
203    fn set_id(&mut self, id: NodeID) {
204        use Expression::*;
205        match self {
206            Array(n) => n.set_id(id),
207            ArrayAccess(n) => n.set_id(id),
208            AssociatedConstant(n) => n.set_id(id),
209            AssociatedFunction(n) => n.set_id(id),
210            Binary(n) => n.set_id(id),
211            Call(n) => n.set_id(id),
212            Cast(n) => n.set_id(id),
213            Identifier(n) => n.set_id(id),
214            Literal(n) => n.set_id(id),
215            Locator(n) => n.set_id(id),
216            MemberAccess(n) => n.set_id(id),
217            Repeat(n) => n.set_id(id),
218            Err(n) => n.set_id(id),
219            Struct(n) => n.set_id(id),
220            Ternary(n) => n.set_id(id),
221            Tuple(n) => n.set_id(id),
222            TupleAccess(n) => n.set_id(id),
223            Unary(n) => n.set_id(id),
224            Unit(n) => n.set_id(id),
225        }
226    }
227}
228
229impl fmt::Display for Expression {
230    fn fmt(&self, f: &mut fmt::Formatter) -> fmt::Result {
231        use Expression::*;
232        match &self {
233            Array(n) => n.fmt(f),
234            ArrayAccess(n) => n.fmt(f),
235            AssociatedConstant(n) => n.fmt(f),
236            AssociatedFunction(n) => n.fmt(f),
237            Binary(n) => n.fmt(f),
238            Call(n) => n.fmt(f),
239            Cast(n) => n.fmt(f),
240            Err(n) => n.fmt(f),
241            Identifier(n) => n.fmt(f),
242            Literal(n) => n.fmt(f),
243            Locator(n) => n.fmt(f),
244            MemberAccess(n) => n.fmt(f),
245            Repeat(n) => n.fmt(f),
246            Struct(n) => n.fmt(f),
247            Ternary(n) => n.fmt(f),
248            Tuple(n) => n.fmt(f),
249            TupleAccess(n) => n.fmt(f),
250            Unary(n) => n.fmt(f),
251            Unit(n) => n.fmt(f),
252        }
253    }
254}
255
256#[derive(Clone, Copy, Eq, PartialEq)]
257pub(crate) enum Associativity {
258    Left,
259    Right,
260    None,
261}
262
263impl Expression {
264    pub(crate) fn precedence(&self) -> u32 {
265        use Expression::*;
266        match self {
267            Binary(e) => e.precedence(),
268            Cast(_) => 12,
269            Ternary(_) => 14,
270            Array(_)
271            | ArrayAccess(_)
272            | AssociatedConstant(_)
273            | AssociatedFunction(_)
274            | Call(_)
275            | Err(_)
276            | Identifier(_)
277            | Literal(_)
278            | Locator(_)
279            | MemberAccess(_)
280            | Repeat(_)
281            | Struct(_)
282            | Tuple(_)
283            | TupleAccess(_)
284            | Unary(_)
285            | Unit(_) => 20,
286        }
287    }
288
289    pub(crate) fn associativity(&self) -> Associativity {
290        if let Expression::Binary(bin) = self { bin.associativity() } else { Associativity::None }
291    }
292
293    /// Returns `self` as a known `u32` if possible. Otherwise, returns a `None`. This allows for large and/or signed
294    /// types but only if they can be safely cast to a `u32`.
295    pub fn as_u32(&self) -> Option<u32> {
296        if let Expression::Literal(literal) = &self {
297            if let LiteralVariant::Integer(int_type, s, ..) = &literal.variant {
298                use crate::IntegerType::*;
299                let s = s.replace("_", "");
300
301                return match int_type {
302                    U8 => u8::from_str_by_radix(&s).map(|v| v as u32).ok(),
303                    U16 => u16::from_str_by_radix(&s).map(|v| v as u32).ok(),
304                    U32 => u32::from_str_by_radix(&s).ok(),
305                    U64 => u64::from_str_by_radix(&s).ok().and_then(|v| u32::try_from(v).ok()),
306                    U128 => u128::from_str_by_radix(&s).ok().and_then(|v| u32::try_from(v).ok()),
307                    I8 => i8::from_str_by_radix(&s).ok().and_then(|v| u32::try_from(v).ok()),
308                    I16 => i16::from_str_by_radix(&s).ok().and_then(|v| u32::try_from(v).ok()),
309                    I32 => i32::from_str_by_radix(&s).ok().and_then(|v| u32::try_from(v).ok()),
310                    I64 => i64::from_str_by_radix(&s).ok().and_then(|v| u32::try_from(v).ok()),
311                    I128 => i128::from_str_by_radix(&s).ok().and_then(|v| u32::try_from(v).ok()),
312                };
313            } else if let LiteralVariant::Unsuffixed(s) = &literal.variant {
314                // Assume unsuffixed literals are `u32`. The type checker should enforce that as the default type.
315                let s = s.replace("_", "");
316                return u32::from_str_by_radix(&s).ok();
317            }
318        }
319        None
320    }
321}