1use crate::{Identifier, IntegerType, Intrinsic, Location, Mode, 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 composite_init;
42pub use composite_init::*;
43
44mod dynamic_op;
45pub use dynamic_op::*;
46
47mod err;
48pub use err::*;
49
50mod member_access;
51pub use member_access::*;
52
53mod intrinsic;
54pub use intrinsic::*;
55
56mod repeat;
57pub use repeat::*;
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
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 DynamicOp(Box<DynamicOpExpression>),
95 Cast(Box<CastExpression>),
97 Composite(CompositeExpression),
101 Err(ErrExpression),
102 Path(Path),
104 Literal(Literal),
106 MemberAccess(Box<MemberAccess>),
108 Repeat(Box<RepeatExpression>),
110 Ternary(Box<TernaryExpression>),
112 Tuple(TupleExpression),
114 TupleAccess(Box<TupleAccess>),
116 Unary(Box<UnaryExpression>),
118 Unit(UnitExpression),
120}
121
122impl Default for Expression {
123 fn default() -> Self {
124 Expression::Err(Default::default())
125 }
126}
127
128impl Node for Expression {
129 fn span(&self) -> Span {
130 use Expression::*;
131 match self {
132 ArrayAccess(n) => n.span(),
133 Array(n) => n.span(),
134 Async(n) => n.span(),
135 Binary(n) => n.span(),
136 Call(n) => n.span(),
137 DynamicOp(n) => n.span(),
138 Cast(n) => n.span(),
139 Composite(n) => n.span(),
140 Err(n) => n.span(),
141 Intrinsic(n) => n.span(),
142 Path(n) => n.span(),
143 Literal(n) => n.span(),
144 MemberAccess(n) => n.span(),
145 Repeat(n) => n.span(),
146 Ternary(n) => n.span(),
147 Tuple(n) => n.span(),
148 TupleAccess(n) => n.span(),
149 Unary(n) => n.span(),
150 Unit(n) => n.span(),
151 }
152 }
153
154 fn set_span(&mut self, span: Span) {
155 use Expression::*;
156 match self {
157 ArrayAccess(n) => n.set_span(span),
158 Array(n) => n.set_span(span),
159 Async(n) => n.set_span(span),
160 Binary(n) => n.set_span(span),
161 Call(n) => n.set_span(span),
162 DynamicOp(n) => n.set_span(span),
163 Cast(n) => n.set_span(span),
164 Composite(n) => n.set_span(span),
165 Err(n) => n.set_span(span),
166 Intrinsic(n) => n.set_span(span),
167 Path(n) => n.set_span(span),
168 Literal(n) => n.set_span(span),
169 MemberAccess(n) => n.set_span(span),
170 Repeat(n) => n.set_span(span),
171 Ternary(n) => n.set_span(span),
172 Tuple(n) => n.set_span(span),
173 TupleAccess(n) => n.set_span(span),
174 Unary(n) => n.set_span(span),
175 Unit(n) => n.set_span(span),
176 }
177 }
178
179 fn id(&self) -> NodeID {
180 use Expression::*;
181 match self {
182 Array(n) => n.id(),
183 ArrayAccess(n) => n.id(),
184 Async(n) => n.id(),
185 Binary(n) => n.id(),
186 Call(n) => n.id(),
187 DynamicOp(n) => n.id(),
188 Cast(n) => n.id(),
189 Composite(n) => n.id(),
190 Path(n) => n.id(),
191 Literal(n) => n.id(),
192 MemberAccess(n) => n.id(),
193 Repeat(n) => n.id(),
194 Err(n) => n.id(),
195 Intrinsic(n) => n.id(),
196 Ternary(n) => n.id(),
197 Tuple(n) => n.id(),
198 TupleAccess(n) => n.id(),
199 Unary(n) => n.id(),
200 Unit(n) => n.id(),
201 }
202 }
203
204 fn set_id(&mut self, id: NodeID) {
205 use Expression::*;
206 match self {
207 Array(n) => n.set_id(id),
208 ArrayAccess(n) => n.set_id(id),
209 Async(n) => n.set_id(id),
210 Binary(n) => n.set_id(id),
211 Call(n) => n.set_id(id),
212 DynamicOp(n) => n.set_id(id),
213 Cast(n) => n.set_id(id),
214 Composite(n) => n.set_id(id),
215 Path(n) => n.set_id(id),
216 Literal(n) => n.set_id(id),
217 MemberAccess(n) => n.set_id(id),
218 Repeat(n) => n.set_id(id),
219 Err(n) => n.set_id(id),
220 Intrinsic(n) => n.set_id(id),
221 Ternary(n) => n.set_id(id),
222 Tuple(n) => n.set_id(id),
223 TupleAccess(n) => n.set_id(id),
224 Unary(n) => n.set_id(id),
225 Unit(n) => n.set_id(id),
226 }
227 }
228}
229
230impl fmt::Display for Expression {
231 fn fmt(&self, f: &mut fmt::Formatter) -> fmt::Result {
232 use Expression::*;
233 match &self {
234 Array(n) => n.fmt(f),
235 ArrayAccess(n) => n.fmt(f),
236 Async(n) => n.fmt(f),
237 Binary(n) => n.fmt(f),
238 Call(n) => n.fmt(f),
239 DynamicOp(n) => n.fmt(f),
240 Cast(n) => n.fmt(f),
241 Composite(n) => n.fmt(f),
242 Err(n) => n.fmt(f),
243 Intrinsic(n) => n.fmt(f),
244 Path(n) => n.fmt(f),
245 Literal(n) => n.fmt(f),
246 MemberAccess(n) => n.fmt(f),
247 Repeat(n) => n.fmt(f),
248 Ternary(n) => n.fmt(f),
249 Tuple(n) => n.fmt(f),
250 TupleAccess(n) => n.fmt(f),
251 Unary(n) => n.fmt(f),
252 Unit(n) => n.fmt(f),
253 }
254 }
255}
256
257#[derive(Clone, Copy, Eq, PartialEq)]
258pub(crate) enum Associativity {
259 Left,
260 Right,
261 None,
262}
263
264impl Expression {
265 pub(crate) fn precedence(&self) -> u32 {
266 use Expression::*;
267 match self {
268 Binary(e) => e.precedence(),
269 Cast(_) => 12,
270 Ternary(_) => 0,
271 Array(_) | ArrayAccess(_) | Async(_) | Call(_) | DynamicOp(_) | Composite(_) | Err(_) | Intrinsic(_)
272 | Path(_) | Literal(_) | MemberAccess(_) | Repeat(_) | Tuple(_) | TupleAccess(_) | Unary(_) | Unit(_) => 20,
273 }
274 }
275
276 pub(crate) fn associativity(&self) -> Associativity {
277 if let Expression::Binary(bin) = self { bin.associativity() } else { Associativity::None }
278 }
279
280 pub fn as_u32(&self) -> Option<u32> {
283 if let Expression::Literal(literal) = &self {
284 if let LiteralVariant::Integer(int_type, s, ..) = &literal.variant {
285 use crate::IntegerType::*;
286 let s = s.replace("_", "");
287
288 return match int_type {
289 U8 => u8::from_str_by_radix(&s).map(|v| v as u32).ok(),
290 U16 => u16::from_str_by_radix(&s).map(|v| v as u32).ok(),
291 U32 => u32::from_str_by_radix(&s).ok(),
292 U64 => u64::from_str_by_radix(&s).ok().and_then(|v| u32::try_from(v).ok()),
293 U128 => u128::from_str_by_radix(&s).ok().and_then(|v| u32::try_from(v).ok()),
294 I8 => i8::from_str_by_radix(&s).ok().and_then(|v| u32::try_from(v).ok()),
295 I16 => i16::from_str_by_radix(&s).ok().and_then(|v| u32::try_from(v).ok()),
296 I32 => i32::from_str_by_radix(&s).ok().and_then(|v| u32::try_from(v).ok()),
297 I64 => i64::from_str_by_radix(&s).ok().and_then(|v| u32::try_from(v).ok()),
298 I128 => i128::from_str_by_radix(&s).ok().and_then(|v| u32::try_from(v).ok()),
299 };
300 } else if let LiteralVariant::Unsuffixed(s) = &literal.variant {
301 let s = s.replace("_", "");
303 return u32::from_str_by_radix(&s).ok();
304 }
305 }
306 None
307 }
308
309 pub fn is_none_expr(&self) -> bool {
310 matches!(self, Expression::Literal(Literal { variant: LiteralVariant::None, .. }))
311 }
312
313 pub fn is_pure(&self, get_type: &impl Fn(NodeID) -> Type) -> bool {
315 match self {
316 Expression::Intrinsic(intr) => {
318 if let Some(intrinsic) = Intrinsic::from_symbol(intr.name, &intr.type_parameters) {
319 intrinsic.is_pure()
320 } else {
321 false
322 }
323 }
324
325 Expression::Call(..)
328 | Expression::DynamicOp(..)
329 | Expression::Err(..)
330 | Expression::Async(..)
331 | Expression::Cast(..) => false,
332
333 Expression::Binary(expr) => {
334 use BinaryOperation::*;
335 match expr.op {
336 Div | Mod | Rem | Shl | Shr => false,
338 Add | Mul | Pow => !matches!(get_type(expr.id()), Type::Integer(..)),
340 _ => expr.left.is_pure(get_type) && expr.right.is_pure(get_type),
341 }
342 }
343 Expression::Unary(expr) => {
344 use UnaryOperation::*;
345 match expr.op {
346 Abs | Inverse | SquareRoot => false,
348 Negate => !matches!(get_type(expr.id()), Type::Integer(..)),
350 _ => expr.receiver.is_pure(get_type),
351 }
352 }
353
354 Expression::Literal(..) | Expression::Path(..) | Expression::Unit(..) => true,
356
357 Expression::ArrayAccess(expr) => expr.array.is_pure(get_type) && expr.index.is_pure(get_type),
359 Expression::MemberAccess(expr) => expr.inner.is_pure(get_type),
360 Expression::Repeat(expr) => expr.expr.is_pure(get_type) && expr.count.is_pure(get_type),
361 Expression::TupleAccess(expr) => expr.tuple.is_pure(get_type),
362 Expression::Array(expr) => expr.elements.iter().all(|e| e.is_pure(get_type)),
363 Expression::Composite(expr) => {
364 expr.const_arguments.iter().all(|e| e.is_pure(get_type))
365 && expr.members.iter().all(|init| init.expression.as_ref().is_none_or(|e| e.is_pure(get_type)))
366 }
367 Expression::Ternary(expr) => {
368 expr.condition.is_pure(get_type) && expr.if_true.is_pure(get_type) && expr.if_false.is_pure(get_type)
369 }
370 Expression::Tuple(expr) => expr.elements.iter().all(|e| e.is_pure(get_type)),
371 }
372 }
373
374 #[allow(clippy::type_complexity)]
391 pub fn zero(
392 ty: &Type,
393 span: Span,
394 node_builder: &NodeBuilder,
395 composite_lookup: &dyn Fn(&Location) -> Vec<(Symbol, Type)>,
396 ) -> Option<Self> {
397 let id = node_builder.next_id();
398
399 match ty {
400 Type::Integer(IntegerType::I8) => Some(Literal::integer(IntegerType::I8, "0".to_string(), span, id).into()),
402 Type::Integer(IntegerType::I16) => {
403 Some(Literal::integer(IntegerType::I16, "0".to_string(), span, id).into())
404 }
405 Type::Integer(IntegerType::I32) => {
406 Some(Literal::integer(IntegerType::I32, "0".to_string(), span, id).into())
407 }
408 Type::Integer(IntegerType::I64) => {
409 Some(Literal::integer(IntegerType::I64, "0".to_string(), span, id).into())
410 }
411 Type::Integer(IntegerType::I128) => {
412 Some(Literal::integer(IntegerType::I128, "0".to_string(), span, id).into())
413 }
414 Type::Integer(IntegerType::U8) => Some(Literal::integer(IntegerType::U8, "0".to_string(), span, id).into()),
415 Type::Integer(IntegerType::U16) => {
416 Some(Literal::integer(IntegerType::U16, "0".to_string(), span, id).into())
417 }
418 Type::Integer(IntegerType::U32) => {
419 Some(Literal::integer(IntegerType::U32, "0".to_string(), span, id).into())
420 }
421 Type::Integer(IntegerType::U64) => {
422 Some(Literal::integer(IntegerType::U64, "0".to_string(), span, id).into())
423 }
424 Type::Integer(IntegerType::U128) => {
425 Some(Literal::integer(IntegerType::U128, "0".to_string(), span, id).into())
426 }
427
428 Type::Boolean => Some(Literal::boolean(false, span, id).into()),
430
431 Type::Address => Some(
435 Literal::address(
436 "aleo1qqqqqqqqqqqqqqqqqqqqqqqqqqqqqqqqqqqqqqqqqqqqqqqqqqqq3ljyzc".to_string(),
437 span,
438 id,
439 )
440 .into(),
441 ),
442
443 Type::Field => Some(Literal::field("0".to_string(), span, id).into()),
445 Type::Group => Some(Literal::group("0".to_string(), span, id).into()),
446 Type::Scalar => Some(Literal::scalar("0".to_string(), span, id).into()),
447
448 Type::Signature => Some(
452 Literal::signature(
453 "sign195m229jvzr0wmnshj6f8gwplhkrkhjumgjmad553r997u7pjfgpfz4j2w0c9lp53mcqqdsmut2g3a2zuvgst85w38hv273mwjec3sqjsv9w6uglcy58gjh7x3l55z68zsf24kx7a73ctp8x8klhuw7l2p4s3aq8um5jp304js7qcnwdqj56q5r5088tyvxsgektun0rnmvtsuxpe6sj".to_string(),
454 span,
455 id,
456 )
457 .into(),
458 ),
459
460 Type::Composite(composite_type) => {
462 let path = &composite_type.path;
463 let members = composite_lookup(path.expect_global_location());
464
465 let composite_members = members
466 .into_iter()
467 .map(|(symbol, member_type)| {
468 let member_id = node_builder.next_id();
469 let zero_expr = Self::zero(&member_type, span, node_builder, composite_lookup)?;
470
471 Some(CompositeFieldInitializer {
472 span,
473 id: member_id,
474 identifier: Identifier::new(symbol, node_builder.next_id()),
475 expression: Some(zero_expr),
476 })
477 })
478 .collect::<Option<Vec<_>>>()?;
479
480 Some(Expression::Composite(CompositeExpression {
481 span,
482 id,
483 path: path.clone(),
484 const_arguments: composite_type.const_arguments.clone(),
485 members: composite_members,
486 }))
487 }
488
489 Type::Array(array_type) => {
491 let element_ty = &array_type.element_type;
492
493 let element_expr = Self::zero(element_ty, span, node_builder, composite_lookup)?;
494
495 Some(Expression::Repeat(
496 RepeatExpression { span, id, expr: element_expr, count: *array_type.length.clone() }.into(),
497 ))
498 }
499
500 _ => None,
502 }
503 }
504}