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