1use crate::{Identifier, IntegerType, Intrinsic, Node, NodeBuilder, NodeID, Path, Type};
18use leo_span::{Span, Symbol};
19
20use serde::{Deserialize, Serialize};
21use std::fmt;
22
23mod array_access;
24pub use array_access::*;
25
26mod async_;
27pub use async_::*;
28
29mod array;
30pub use array::*;
31
32mod binary;
33pub use binary::*;
34
35mod call;
36pub use call::*;
37
38mod cast;
39pub use cast::*;
40
41mod err;
42pub use err::*;
43
44mod member_access;
45pub use member_access::*;
46
47mod intrinsic;
48pub use intrinsic::*;
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#[derive(Debug, Clone, PartialEq, Eq, Serialize, Deserialize)]
79pub enum Expression {
80 ArrayAccess(Box<ArrayAccess>),
82 Async(AsyncExpression),
84 Array(ArrayExpression),
86 Binary(Box<BinaryExpression>),
88 Intrinsic(Box<IntrinsicExpression>),
90 Call(Box<CallExpression>),
92 Cast(Box<CastExpression>),
94 Err(ErrExpression),
97 Path(Path),
99 Literal(Literal),
101 Locator(LocatorExpression),
103 MemberAccess(Box<MemberAccess>),
105 Repeat(Box<RepeatExpression>),
107 Struct(StructExpression),
109 Ternary(Box<TernaryExpression>),
111 Tuple(TupleExpression),
113 TupleAccess(Box<TupleAccess>),
115 Unary(Box<UnaryExpression>),
117 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 Async(n) => n.span(),
134 Binary(n) => n.span(),
135 Call(n) => n.span(),
136 Cast(n) => n.span(),
137 Err(n) => n.span(),
138 Intrinsic(n) => n.span(),
139 Path(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 Async(n) => n.set_span(span),
159 Binary(n) => n.set_span(span),
160 Call(n) => n.set_span(span),
161 Cast(n) => n.set_span(span),
162 Err(n) => n.set_span(span),
163 Intrinsic(n) => n.set_span(span),
164 Path(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 Async(n) => n.id(),
184 Binary(n) => n.id(),
185 Call(n) => n.id(),
186 Cast(n) => n.id(),
187 Path(n) => n.id(),
188 Literal(n) => n.id(),
189 Locator(n) => n.id(),
190 MemberAccess(n) => n.id(),
191 Repeat(n) => n.id(),
192 Err(n) => n.id(),
193 Intrinsic(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 Async(n) => n.set_id(id),
209 Binary(n) => n.set_id(id),
210 Call(n) => n.set_id(id),
211 Cast(n) => n.set_id(id),
212 Path(n) => n.set_id(id),
213 Literal(n) => n.set_id(id),
214 Locator(n) => n.set_id(id),
215 MemberAccess(n) => n.set_id(id),
216 Repeat(n) => n.set_id(id),
217 Err(n) => n.set_id(id),
218 Intrinsic(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 Async(n) => n.fmt(f),
236 Binary(n) => n.fmt(f),
237 Call(n) => n.fmt(f),
238 Cast(n) => n.fmt(f),
239 Err(n) => n.fmt(f),
240 Intrinsic(n) => n.fmt(f),
241 Path(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(_) => 0,
270 Array(_) | ArrayAccess(_) | Async(_) | Call(_) | Err(_) | Intrinsic(_) | Path(_) | Literal(_)
271 | Locator(_) | MemberAccess(_) | Repeat(_) | Struct(_) | Tuple(_) | TupleAccess(_) | Unary(_) | Unit(_) => {
272 20
273 }
274 }
275 }
276
277 pub(crate) fn associativity(&self) -> Associativity {
278 if let Expression::Binary(bin) = self { bin.associativity() } else { Associativity::None }
279 }
280
281 pub fn as_u32(&self) -> Option<u32> {
284 if let Expression::Literal(literal) = &self {
285 if let LiteralVariant::Integer(int_type, s, ..) = &literal.variant {
286 use crate::IntegerType::*;
287 let s = s.replace("_", "");
288
289 return match int_type {
290 U8 => u8::from_str_by_radix(&s).map(|v| v as u32).ok(),
291 U16 => u16::from_str_by_radix(&s).map(|v| v as u32).ok(),
292 U32 => u32::from_str_by_radix(&s).ok(),
293 U64 => u64::from_str_by_radix(&s).ok().and_then(|v| u32::try_from(v).ok()),
294 U128 => u128::from_str_by_radix(&s).ok().and_then(|v| u32::try_from(v).ok()),
295 I8 => i8::from_str_by_radix(&s).ok().and_then(|v| u32::try_from(v).ok()),
296 I16 => i16::from_str_by_radix(&s).ok().and_then(|v| u32::try_from(v).ok()),
297 I32 => i32::from_str_by_radix(&s).ok().and_then(|v| u32::try_from(v).ok()),
298 I64 => i64::from_str_by_radix(&s).ok().and_then(|v| u32::try_from(v).ok()),
299 I128 => i128::from_str_by_radix(&s).ok().and_then(|v| u32::try_from(v).ok()),
300 };
301 } else if let LiteralVariant::Unsuffixed(s) = &literal.variant {
302 let s = s.replace("_", "");
304 return u32::from_str_by_radix(&s).ok();
305 }
306 }
307 None
308 }
309
310 pub fn is_none_expr(&self) -> bool {
311 matches!(self, Expression::Literal(Literal { variant: LiteralVariant::None, .. }))
312 }
313
314 pub fn is_pure(&self, get_type: &impl Fn(NodeID) -> Type) -> bool {
316 match self {
317 Expression::Intrinsic(intr) => {
319 if let Some(intrinsic) = Intrinsic::from_symbol(intr.name, &intr.type_parameters) {
320 intrinsic.is_pure()
321 } else {
322 false
323 }
324 }
325
326 Expression::Call(..) | Expression::Err(..) | Expression::Async(..) | Expression::Cast(..) => false,
329
330 Expression::Binary(expr) => {
331 use BinaryOperation::*;
332 match expr.op {
333 Div | Mod | Rem | Shl | Shr => false,
335 Add | Mul | Pow => !matches!(get_type(expr.id()), Type::Integer(..)),
337 _ => expr.left.is_pure(get_type) && expr.right.is_pure(get_type),
338 }
339 }
340 Expression::Unary(expr) => {
341 use UnaryOperation::*;
342 match expr.op {
343 Abs | Inverse | SquareRoot => false,
345 Negate => !matches!(get_type(expr.id()), Type::Integer(..)),
347 _ => expr.receiver.is_pure(get_type),
348 }
349 }
350
351 Expression::Locator(..) | Expression::Literal(..) | Expression::Path(..) | Expression::Unit(..) => true,
353
354 Expression::ArrayAccess(expr) => expr.array.is_pure(get_type) && expr.index.is_pure(get_type),
356 Expression::MemberAccess(expr) => expr.inner.is_pure(get_type),
357 Expression::Repeat(expr) => expr.expr.is_pure(get_type) && expr.count.is_pure(get_type),
358 Expression::TupleAccess(expr) => expr.tuple.is_pure(get_type),
359 Expression::Array(expr) => expr.elements.iter().all(|e| e.is_pure(get_type)),
360 Expression::Struct(expr) => {
361 expr.const_arguments.iter().all(|e| e.is_pure(get_type))
362 && expr.members.iter().all(|init| init.expression.as_ref().is_none_or(|e| e.is_pure(get_type)))
363 }
364 Expression::Ternary(expr) => {
365 expr.condition.is_pure(get_type) && expr.if_true.is_pure(get_type) && expr.if_false.is_pure(get_type)
366 }
367 Expression::Tuple(expr) => expr.elements.iter().all(|e| e.is_pure(get_type)),
368 }
369 }
370
371 #[allow(clippy::type_complexity)]
388 pub fn zero(
389 ty: &Type,
390 span: Span,
391 node_builder: &NodeBuilder,
392 struct_lookup: &dyn Fn(&[Symbol]) -> Vec<(Symbol, Type)>,
393 ) -> Option<Self> {
394 let id = node_builder.next_id();
395
396 match ty {
397 Type::Integer(IntegerType::I8) => Some(Literal::integer(IntegerType::I8, "0".to_string(), span, id).into()),
399 Type::Integer(IntegerType::I16) => {
400 Some(Literal::integer(IntegerType::I16, "0".to_string(), span, id).into())
401 }
402 Type::Integer(IntegerType::I32) => {
403 Some(Literal::integer(IntegerType::I32, "0".to_string(), span, id).into())
404 }
405 Type::Integer(IntegerType::I64) => {
406 Some(Literal::integer(IntegerType::I64, "0".to_string(), span, id).into())
407 }
408 Type::Integer(IntegerType::I128) => {
409 Some(Literal::integer(IntegerType::I128, "0".to_string(), span, id).into())
410 }
411 Type::Integer(IntegerType::U8) => Some(Literal::integer(IntegerType::U8, "0".to_string(), span, id).into()),
412 Type::Integer(IntegerType::U16) => {
413 Some(Literal::integer(IntegerType::U16, "0".to_string(), span, id).into())
414 }
415 Type::Integer(IntegerType::U32) => {
416 Some(Literal::integer(IntegerType::U32, "0".to_string(), span, id).into())
417 }
418 Type::Integer(IntegerType::U64) => {
419 Some(Literal::integer(IntegerType::U64, "0".to_string(), span, id).into())
420 }
421 Type::Integer(IntegerType::U128) => {
422 Some(Literal::integer(IntegerType::U128, "0".to_string(), span, id).into())
423 }
424
425 Type::Boolean => Some(Literal::boolean(false, span, id).into()),
427
428 Type::Address => Some(
432 Literal::address(
433 "aleo1qqqqqqqqqqqqqqqqqqqqqqqqqqqqqqqqqqqqqqqqqqqqqqqqqqqq3ljyzc".to_string(),
434 span,
435 id,
436 )
437 .into(),
438 ),
439
440 Type::Field => Some(Literal::field("0".to_string(), span, id).into()),
442 Type::Group => Some(Literal::group("0".to_string(), span, id).into()),
443 Type::Scalar => Some(Literal::scalar("0".to_string(), span, id).into()),
444
445 Type::Composite(composite_type) => {
447 let path = &composite_type.path;
448 let members = struct_lookup(&path.absolute_path());
449
450 let struct_members = members
451 .into_iter()
452 .map(|(symbol, member_type)| {
453 let member_id = node_builder.next_id();
454 let zero_expr = Self::zero(&member_type, span, node_builder, struct_lookup)?;
455
456 Some(StructVariableInitializer {
457 span,
458 id: member_id,
459 identifier: Identifier::new(symbol, node_builder.next_id()),
460 expression: Some(zero_expr),
461 })
462 })
463 .collect::<Option<Vec<_>>>()?;
464
465 Some(Expression::Struct(StructExpression {
466 span,
467 id,
468 path: path.clone(),
469 const_arguments: composite_type.const_arguments.clone(),
470 members: struct_members,
471 }))
472 }
473
474 Type::Array(array_type) => {
476 let element_ty = &array_type.element_type;
477
478 let element_expr = Self::zero(element_ty, span, node_builder, struct_lookup)?;
479
480 Some(Expression::Repeat(
481 RepeatExpression { span, id, expr: element_expr, count: *array_type.length.clone() }.into(),
482 ))
483 }
484
485 _ => None,
487 }
488 }
489}