leo_parser/parser/
expression.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_errors::{ParserError, Result};
19
20use leo_span::sym;
21use snarkvm::{
22    console::account::Address,
23    prelude::{CanaryV0, MainnetV0, TestnetV0},
24};
25
26const INT_TYPES: &[Token] = &[
27    Token::I8,
28    Token::I16,
29    Token::I32,
30    Token::I64,
31    Token::I128,
32    Token::U8,
33    Token::U16,
34    Token::U32,
35    Token::U64,
36    Token::U128,
37    Token::Field,
38    Token::Group,
39    Token::Scalar,
40];
41
42impl ParserContext<'_> {
43    /// Returns an [`Expression`] AST node if the next token is an expression.
44    /// Includes struct init expressions.
45    pub(crate) fn parse_expression(&mut self) -> Result<Expression> {
46        // Store current parser state.
47        let prior_fuzzy_state = self.disallow_struct_construction;
48
49        // Allow struct init expressions.
50        self.disallow_struct_construction = false;
51
52        // Parse expression.
53        let result = self.parse_conditional_expression();
54
55        // Restore prior parser state.
56        self.disallow_struct_construction = prior_fuzzy_state;
57
58        result
59    }
60
61    /// Returns an [`Expression`] AST node if the next tokens represent
62    /// a ternary expression. May or may not include struct init expressions.
63    ///
64    /// Otherwise, tries to parse the next token using [`parse_boolean_or_expression`].
65    pub(super) fn parse_conditional_expression(&mut self) -> Result<Expression> {
66        // Try to parse the next expression. Try BinaryOperation::Or.
67        let mut expr = self.parse_boolean_or_expression()?;
68
69        // Parse the rest of the ternary expression.
70        if self.eat(&Token::Question) {
71            let if_true = self.parse_expression()?;
72            self.expect(&Token::Colon)?;
73            let if_false = self.parse_expression()?;
74            expr = TernaryExpression {
75                span: expr.span() + if_false.span(),
76                condition: expr,
77                if_true,
78                if_false,
79                id: self.node_builder.next_id(),
80            }
81            .into();
82        }
83        Ok(expr)
84    }
85
86    /// Constructs a binary expression `left op right`.
87    fn bin_expr(node_builder: &NodeBuilder, left: Expression, right: Expression, op: BinaryOperation) -> Expression {
88        BinaryExpression { span: left.span() + right.span(), op, left, right, id: node_builder.next_id() }.into()
89    }
90
91    /// Parses a left-associative binary expression `<left> token <right>` using `f` for left/right.
92    /// The `token` is translated to `op` in the AST.
93    fn parse_bin_expr(
94        &mut self,
95        tokens: &[Token],
96        mut f: impl FnMut(&mut Self) -> Result<Expression>,
97    ) -> Result<Expression> {
98        let mut expr = f(self)?;
99        while let Some(op) = self.eat_bin_op(tokens) {
100            expr = Self::bin_expr(self.node_builder, expr, f(self)?, op);
101        }
102        Ok(expr)
103    }
104
105    /// Returns an [`Expression`] AST node if the next tokens represent
106    /// a binary OR expression.
107    ///
108    /// Otherwise, tries to parse the next token using [`parse_boolean_and_expression`].
109    fn parse_boolean_or_expression(&mut self) -> Result<Expression> {
110        self.parse_bin_expr(&[Token::Or], Self::parse_boolean_and_expression)
111    }
112
113    /// Returns an [`Expression`] AST node if the next tokens represent a
114    /// binary AND expression.
115    ///
116    /// Otherwise, tries to parse the next token using [`parse_equality_expression`].
117    fn parse_boolean_and_expression(&mut self) -> Result<Expression> {
118        self.parse_bin_expr(&[Token::And], Self::parse_equality_expression)
119    }
120
121    fn eat_unary_op(&mut self) -> Option<UnaryOperation> {
122        self.eat_any(&[Token::Not, Token::Sub]).then(|| match &self.prev_token.token {
123            Token::Not => UnaryOperation::Not,
124            Token::Sub => UnaryOperation::Negate,
125            _ => panic!("Can't happen."),
126        })
127    }
128
129    /// Eats one of binary operators matching any in `tokens`.
130    fn eat_bin_op(&mut self, tokens: &[Token]) -> Option<BinaryOperation> {
131        self.eat_any(tokens).then(|| match &self.prev_token.token {
132            Token::Eq => BinaryOperation::Eq,
133            Token::NotEq => BinaryOperation::Neq,
134            Token::Lt => BinaryOperation::Lt,
135            Token::LtEq => BinaryOperation::Lte,
136            Token::Gt => BinaryOperation::Gt,
137            Token::GtEq => BinaryOperation::Gte,
138            Token::Add => BinaryOperation::Add,
139            Token::Sub => BinaryOperation::Sub,
140            Token::Mul => BinaryOperation::Mul,
141            Token::Div => BinaryOperation::Div,
142            Token::Rem => BinaryOperation::Rem,
143            Token::Or => BinaryOperation::Or,
144            Token::And => BinaryOperation::And,
145            Token::BitOr => BinaryOperation::BitwiseOr,
146            Token::BitAnd => BinaryOperation::BitwiseAnd,
147            Token::Pow => BinaryOperation::Pow,
148            Token::Shl => BinaryOperation::Shl,
149            Token::Shr => BinaryOperation::Shr,
150            Token::BitXor => BinaryOperation::Xor,
151            _ => unreachable!("`eat_bin_op` shouldn't produce this"),
152        })
153    }
154
155    /// Returns an [`Expression`] AST node if the next tokens represent a
156    /// binary relational expression: less than, less than or equals, greater than, greater than or equals.
157    ///
158    /// Otherwise, tries to parse the next token using [`parse_additive_expression`].
159    fn parse_ordering_expression(&mut self) -> Result<Expression> {
160        let mut expr = self.parse_bitwise_exclusive_or_expression()?;
161        if let Some(op) = self.eat_bin_op(&[Token::Lt, Token::LtEq, Token::Gt, Token::GtEq]) {
162            let right = self.parse_bitwise_exclusive_or_expression()?;
163            expr = Self::bin_expr(self.node_builder, expr, right, op);
164        }
165        Ok(expr)
166    }
167
168    /// Returns an [`Expression`] AST node if the next tokens represent a
169    /// binary equals or not equals expression.
170    ///
171    /// Otherwise, tries to parse the next token using [`parse_ordering_expression`].
172    fn parse_equality_expression(&mut self) -> Result<Expression> {
173        let mut expr = self.parse_ordering_expression()?;
174        if let Some(op) = self.eat_bin_op(&[Token::Eq, Token::NotEq]) {
175            let right = self.parse_ordering_expression()?;
176            expr = Self::bin_expr(self.node_builder, expr, right, op);
177        }
178        Ok(expr)
179    }
180
181    /// Returns an [`Expression`] AST node if the next tokens represent a
182    /// bitwise exclusive or expression.
183    ///
184    /// Otherwise, tries to parse the next token using [`parse_bitwise_inclusive_or_expression`].
185    fn parse_bitwise_exclusive_or_expression(&mut self) -> Result<Expression> {
186        self.parse_bin_expr(&[Token::BitXor], Self::parse_bitwise_inclusive_or_expression)
187    }
188
189    /// Returns an [`Expression`] AST node if the next tokens represent a
190    /// bitwise inclusive or expression.
191    ///
192    /// Otherwise, tries to parse the next token using [`parse_bitwise_and_expression`].
193    fn parse_bitwise_inclusive_or_expression(&mut self) -> Result<Expression> {
194        self.parse_bin_expr(&[Token::BitOr], Self::parse_bitwise_and_expression)
195    }
196
197    /// Returns an [`Expression`] AST node if the next tokens represent a
198    /// bitwise and expression.
199    ///
200    /// Otherwise, tries to parse the next token using [`parse_shift_expression`].
201    fn parse_bitwise_and_expression(&mut self) -> Result<Expression> {
202        self.parse_bin_expr(&[Token::BitAnd], Self::parse_shift_expression)
203    }
204
205    /// Returns an [`Expression`] AST node if the next tokens represent a
206    /// shift left or a shift right expression.
207    ///
208    /// Otherwise, tries to parse the next token using [`parse_additive_expression`].
209    fn parse_shift_expression(&mut self) -> Result<Expression> {
210        self.parse_bin_expr(&[Token::Shl, Token::Shr], Self::parse_additive_expression)
211    }
212
213    /// Returns an [`Expression`] AST node if the next tokens represent a
214    /// binary addition or subtraction expression.
215    ///
216    /// Otherwise, tries to parse the next token using [`parse_mul_div_pow_expression`].
217    fn parse_additive_expression(&mut self) -> Result<Expression> {
218        self.parse_bin_expr(&[Token::Add, Token::Sub], Self::parse_multiplicative_expression)
219    }
220
221    /// Returns an [`Expression`] AST node if the next tokens represent a
222    /// binary multiplication, division, or a remainder expression.
223    ///
224    /// Otherwise, tries to parse the next token using [`parse_exponential_expression`].
225    fn parse_multiplicative_expression(&mut self) -> Result<Expression> {
226        self.parse_bin_expr(&[Token::Mul, Token::Div, Token::Rem], Self::parse_exponential_expression)
227    }
228
229    /// Returns an [`Expression`] AST node if the next tokens represent a
230    /// binary exponentiation expression.
231    ///
232    /// Otherwise, tries to parse the next token using [`parse_cast_expression`].
233    fn parse_exponential_expression(&mut self) -> Result<Expression> {
234        self.parse_bin_expr(&[Token::Pow], Self::parse_cast_expression)
235    }
236
237    /// Returns an [`Expression`] AST node if the next tokens represent a
238    /// cast expression.
239    ///
240    /// Otherwise, tries to parse the next token using [`parse_unary_expression`].
241    fn parse_cast_expression(&mut self) -> Result<Expression> {
242        let mut expr = self.parse_unary_expression()?;
243        if self.eat(&Token::As) {
244            let (type_, end_span) = self.parse_primitive_type()?;
245            let span = expr.span() + end_span;
246            expr = CastExpression { expression: expr, type_, span, id: self.node_builder.next_id() }.into();
247        }
248
249        Ok(expr)
250    }
251
252    /// Returns an [`Expression`] AST node if the next tokens represent a
253    /// unary not, negate, or bitwise not expression.
254    ///
255    /// Otherwise, tries to parse the next token using [`parse_postfix_expression`].
256    pub(super) fn parse_unary_expression(&mut self) -> Result<Expression> {
257        let token_span = self.token.span;
258
259        let Some(op) = self.eat_unary_op() else {
260            return self.parse_postfix_expression();
261        };
262
263        let mut inner = self.parse_unary_expression()?;
264
265        // Try to construct a negative literal.
266        if let UnaryOperation::Negate = op {
267            use LiteralVariant::*;
268            if let Expression::Literal(Literal {
269                variant: Integer(_, string) | Field(string) | Group(string) | Scalar(string),
270                span,
271                ..
272            }) = &mut inner
273            {
274                if !string.starts_with('-') {
275                    // The operation was a negation and the literal was not already negative, so fold it in.
276                    string.insert(0, '-');
277                    *span = token_span + *span;
278                    return Ok(inner);
279                }
280            }
281        }
282
283        Ok(UnaryExpression { span: token_span + inner.span(), op, receiver: inner, id: self.node_builder.next_id() }
284            .into())
285    }
286
287    // TODO: Parse method call expressions directly and later put them into a canonical form.
288    /// Returns an [`Expression`] AST node if the next tokens represent a
289    /// method call expression.
290    fn parse_method_call_expression(&mut self, receiver: Expression, method: Identifier) -> Result<Expression> {
291        // Parse the argument list.
292        let (mut args, _, span) = self.parse_expr_tuple()?;
293        let span = receiver.span() + span;
294
295        if let (true, Some(op)) = (args.is_empty(), UnaryOperation::from_symbol(method.name)) {
296            // Found an unary operator and the argument list is empty.
297            Ok(UnaryExpression { span, op, receiver, id: self.node_builder.next_id() }.into())
298        } else if let (1, Some(op)) = (args.len(), BinaryOperation::from_symbol(method.name)) {
299            // Found a binary operator and the argument list contains a single argument.
300            Ok(BinaryExpression {
301                span,
302                op,
303                left: receiver,
304                right: args.swap_remove(0),
305                id: self.node_builder.next_id(),
306            }
307            .into())
308        } else if let (2, Some(CoreFunction::SignatureVerify)) =
309            (args.len(), CoreFunction::from_symbols(sym::signature, method.name))
310        {
311            Ok(AssociatedFunctionExpression {
312                variant: Identifier::new(sym::signature, self.node_builder.next_id()),
313                name: method,
314                arguments: std::iter::once(receiver).chain(args).collect(),
315                span,
316                id: self.node_builder.next_id(),
317            }
318            .into())
319        } else if let (0, Some(CoreFunction::FutureAwait)) =
320            (args.len(), CoreFunction::from_symbols(sym::Future, method.name))
321        {
322            Ok(AssociatedFunctionExpression {
323                variant: Identifier::new(sym::Future, self.node_builder.next_id()),
324                name: method,
325                arguments: vec![receiver],
326                span,
327                id: self.node_builder.next_id(),
328            }
329            .into())
330        } else {
331            // Attempt to parse the method call as a mapping operation.
332            match (args.len(), CoreFunction::from_symbols(sym::Mapping, method.name)) {
333                (1, Some(CoreFunction::MappingGet))
334                | (2, Some(CoreFunction::MappingGetOrUse))
335                | (2, Some(CoreFunction::MappingSet))
336                | (1, Some(CoreFunction::MappingRemove))
337                | (1, Some(CoreFunction::MappingContains)) => {
338                    // Found an instance of `<mapping>.get`, `<mapping>.get_or_use`, `<mapping>.set`, `<mapping>.remove`, or `<mapping>.contains`.
339                    Ok(AssociatedFunctionExpression {
340                        variant: Identifier::new(sym::Mapping, self.node_builder.next_id()),
341                        name: method,
342                        arguments: std::iter::once(receiver).chain(args).collect(),
343                        span,
344                        id: self.node_builder.next_id(),
345                    }
346                    .into())
347                }
348                _ => {
349                    // Either an invalid unary/binary operator, or more arguments given.
350                    self.emit_err(ParserError::invalid_method_call(receiver, method, args.len(), span));
351                    Ok(ErrExpression { span, id: self.node_builder.next_id() }.into())
352                }
353            }
354        }
355    }
356
357    /// Returns an [`Expression`] AST node if the next tokens represent a
358    /// static access expression.
359    fn parse_associated_access_expression(&mut self, module_name: Expression) -> Result<Expression> {
360        // Ensure that the preceding expression is an identifier (a named type).
361        let Expression::Path(ref path) = module_name else {
362            return Err(ParserError::invalid_associated_access(&module_name, module_name.span()).into());
363        };
364
365        let variant = path.identifier();
366        if !path.qualifier().is_empty() {
367            return Err(ParserError::invalid_associated_access(&module_name, module_name.span()).into());
368        };
369
370        // Parse the constant or function name.
371        let member_name = self.expect_identifier()?;
372
373        // Check if there are arguments.
374        let expression = if self.check(&Token::LeftParen) {
375            // Parse the arguments
376            let (args, _, end) = self.parse_expr_tuple()?;
377
378            // Return the associated function.
379            AssociatedFunctionExpression {
380                span: module_name.span() + end,
381                variant,
382                name: member_name,
383                arguments: args,
384                id: self.node_builder.next_id(),
385            }
386            .into()
387        } else if CoreConstant::from_symbols(variant.name, member_name.name).is_some() {
388            // Return the associated constant.
389            AssociatedConstantExpression {
390                span: module_name.span() + member_name.span(),
391                ty: Type::Identifier(variant),
392                name: member_name,
393                id: self.node_builder.next_id(),
394            }
395            .into()
396        } else {
397            Path::new(vec![variant], member_name, None, variant.span + member_name.span, self.node_builder.next_id())
398                .into()
399        };
400
401        Ok(expression)
402    }
403
404    /// Parses a tuple of `Expression` AST nodes.
405    pub(crate) fn parse_expr_tuple(&mut self) -> Result<(Vec<Expression>, bool, Span)> {
406        self.parse_paren_comma_list(|p| p.parse_expression().map(Some))
407    }
408
409    /// Parses an external function call `credits.aleo/transfer()` or locator `token.aleo/accounts`.
410    ///
411    /// In the ABNF grammar,
412    /// an external function call is one of the two kinds of free function calls,
413    /// namely the one that uses a locator to designate the function;
414    /// a locator is a kind of primary expression.
415    fn parse_external_resource(&mut self, expr: Expression, network_span: Span) -> Result<Expression> {
416        // Parse `/`.
417        self.expect(&Token::Div)?;
418
419        // Parse name.
420        let name = self.expect_identifier()?;
421
422        // Ensure the preceding expression is a (program) identifier.
423        let Expression::Path(ref path) = expr else {
424            unreachable!("Function must be preceded by a program identifier.");
425        };
426
427        if !path.qualifier().is_empty() {
428            unreachable!("Function must be preceded by a single-segment path.");
429        };
430
431        let program = path.identifier();
432
433        // Parsing a '{' means that user is trying to illegally define an external record.
434        if self.token.token == Token::LeftCurly {
435            return Err(ParserError::cannot_define_external_record(expr.span() + name.span()).into());
436        }
437
438        // If there is no parenthesis, then it is a locator.
439        if self.token.token != Token::LeftParen {
440            // Parse an external resource locator.
441            return Ok(LocatorExpression {
442                program: ProgramId {
443                    name: program,
444                    network: Identifier { name: sym::aleo, span: network_span, id: self.node_builder.next_id() },
445                },
446                name: name.name,
447                span: expr.span() + name.span(),
448                id: self.node_builder.next_id(),
449            }
450            .into());
451        }
452
453        // Parse the function call.
454        let (arguments, _, span) = self.parse_paren_comma_list(|p| p.parse_expression().map(Some))?;
455
456        Ok(CallExpression {
457            span: expr.span() + span,
458            function: name.into(),
459            program: Some(program.name),
460            const_arguments: vec![], // we do not expect const arguments for external calls at this time
461            arguments,
462            id: self.node_builder.next_id(),
463        }
464        .into())
465    }
466
467    /// Returns an [`Expression`] AST node if the next tokens represent an
468    /// array access, struct member access, tuple access, or method call expression.
469    ///
470    /// Otherwise, tries to parse the next token using [`parse_primary_expression`].
471    /// Note that, as mentioned in [`parse_primary_expression`],
472    /// this function also completes the parsing of some primary expressions
473    /// (as defined in the ABNF grammar),
474    /// which [`parse_primary_expression`] only starts to parse.
475    fn parse_postfix_expression(&mut self) -> Result<Expression> {
476        // We don't directly parse named types and identifiers in associated constants and functions
477        // here as the ABNF states. Rather, those named types and identifiers are parsed
478        // as primary expressions, and combined to form associated constants and functions here.
479        let mut expr = self.parse_primary_expression()?;
480        loop {
481            if self.eat(&Token::Dot) {
482                if self.check_int() {
483                    // Eat a tuple member access.
484                    let (index, span) = self.eat_whole_number()?;
485                    expr = TupleAccess { tuple: expr, index, span, id: self.node_builder.next_id() }.into();
486                } else if self.eat(&Token::Leo) {
487                    return Err(ParserError::only_aleo_external_calls(expr.span()).into());
488                } else if self.eat(&Token::Aleo) {
489                    if self.token.token == Token::Div {
490                        expr = self.parse_external_resource(expr, self.prev_token.span)?;
491                    } else {
492                        // Parse as address literal, e.g. `hello.aleo`.
493                        if !matches!(expr, Expression::Path(ref path) if path.qualifier().is_empty()) {
494                            self.emit_err(ParserError::unexpected(expr.to_string(), "an identifier", expr.span()));
495                        }
496
497                        expr =
498                            Literal::address(format!("{expr}.aleo"), expr.span(), self.node_builder.next_id()).into();
499                    }
500                } else {
501                    // Parse instances of `self.address`.
502                    // This needs to be handled as a special case because `address` is a keyword in Leo,
503                    if matches!(expr, Expression::Path(ref path) if path.identifier().name == sym::SelfLower && path.qualifier().is_empty())
504                        && self.token.token == Token::Address
505                    {
506                        // Eat the address token.
507                        let span = self.expect(&Token::Address)?;
508                        // Return a member access expression.
509                        expr = MemberAccess {
510                            span: expr.span() + span,
511                            inner: expr,
512                            name: Identifier { name: sym::address, span, id: self.node_builder.next_id() },
513                            id: self.node_builder.next_id(),
514                        }
515                        .into();
516                        continue;
517                    }
518
519                    // Parse identifier name.
520                    let name = self.expect_identifier()?;
521
522                    if self.check(&Token::LeftParen) {
523                        // Eat a method call on a type
524                        expr = self.parse_method_call_expression(expr, name)?
525                    } else {
526                        // Eat a struct member access.
527                        let expr_span = expr.span();
528                        expr = MemberAccess {
529                            inner: expr,
530                            name,
531                            span: expr_span + name.span(),
532                            id: self.node_builder.next_id(),
533                        }
534                        .into();
535                    }
536                }
537            } else if self.eat(&Token::DoubleColon) {
538                // If we see a `::`, then we either expect a core associated expression or a list of const arguments in
539                // square brackets.
540                if self.check(&Token::LeftSquare) {
541                    // Check that the expression is a path.
542                    let Expression::Path(path) = &expr else {
543                        return Err(leo_errors::LeoError::ParserError(ParserError::unexpected(
544                            expr.to_string(),
545                            "a path",
546                            expr.span(),
547                        )));
548                    };
549
550                    // Parse a list of const arguments in between `[..]`
551                    let const_arguments = self.parse_bracket_comma_list(|p| p.parse_expression().map(Some))?.0;
552
553                    // If the next token is a `(` then we parse a call expression.
554                    // If the next token is a `{`, then we parse a struct init expression.
555                    if self.check(&Token::LeftParen) {
556                        // Parse a list of input arguments in between `(..)`
557                        let (arguments, _, span) = self.parse_paren_comma_list(|p| p.parse_expression().map(Some))?;
558
559                        // Now form a `CallExpression`
560                        expr = CallExpression {
561                            span: expr.span() + span,
562                            function: path.clone(),
563                            program: self.program_name,
564                            const_arguments,
565                            arguments,
566                            id: self.node_builder.next_id(),
567                        }
568                        .into();
569                    } else if !self.disallow_struct_construction && self.check(&Token::LeftCurly) {
570                        // Parse struct and records inits as struct expressions with const arguments.
571                        // Enforce struct or record type later at type checking.
572                        expr = self.parse_struct_init_expression(path.clone(), const_arguments)?;
573                    } else {
574                        self.emit_err(ParserError::unexpected(expr.to_string(), "( or {{", expr.span()))
575                    }
576                } else {
577                    // Eat a core associated constant or core associated function call.
578                    expr = self.parse_associated_access_expression(expr)?;
579                }
580            } else if self.eat(&Token::LeftSquare) {
581                // Eat an array access.
582                let index = self.parse_expression()?;
583                // Eat the closing bracket.
584                let span = self.expect(&Token::RightSquare)?;
585                let expr_span = expr.span();
586                expr =
587                    ArrayAccess { array: expr, index, span: expr_span + span, id: self.node_builder.next_id() }.into();
588            } else if self.check(&Token::LeftParen) {
589                // Check that the expression is a path.
590                let Expression::Path(path) = &expr else {
591                    return Err(leo_errors::LeoError::ParserError(ParserError::unexpected(
592                        expr.to_string(),
593                        "a path",
594                        expr.span(),
595                    )));
596                };
597
598                // Parse a function call that's by itself.
599                let (arguments, _, span) = self.parse_paren_comma_list(|p| p.parse_expression().map(Some))?;
600
601                // Check for a core function otherwise treat as regular call.
602                expr = if path.qualifier().len() == 1
603                    && CoreFunction::from_symbols(path.qualifier()[0].name, path.identifier().name).is_some()
604                {
605                    AssociatedFunctionExpression {
606                        variant: path.qualifier()[0],
607                        name: path.identifier(),
608                        arguments,
609                        span: expr.span() + span,
610                        id: self.node_builder.next_id(),
611                    }
612                    .into()
613                } else {
614                    CallExpression {
615                        span: expr.span() + span,
616                        function: path.clone(),
617                        program: self.program_name,
618                        const_arguments: vec![],
619                        arguments,
620                        id: self.node_builder.next_id(),
621                    }
622                    .into()
623                };
624            }
625            // Stop parsing the postfix expression unless a dot or square bracket follows.
626            if !(self.check(&Token::Dot) || self.check(&Token::LeftSquare)) {
627                break;
628            }
629        }
630        Ok(expr)
631    }
632
633    /// Returns an [`Expression`] AST node if the next tokens represent
634    /// a parenthesized expression or a unit expression
635    /// or a tuple initialization expression or an affine group literal.
636    fn parse_tuple_expression(&mut self) -> Result<Expression> {
637        let (mut elements, trailing, span) = self.parse_expr_tuple()?;
638
639        match (elements.len(), trailing) {
640            (0, _) | (1, true) => {
641                // A tuple with 0 or 1 elements - emit an error since tuples must have at least two elements.
642                Err(ParserError::tuple_must_have_at_least_two_elements("expression", span).into())
643            }
644            (1, false) => {
645                // If there is one element in the tuple but no trailing comma, e.g `(foo)`, return the element.
646                Ok(elements.remove(0))
647            }
648            _ => {
649                // Otherwise, return a tuple expression.
650                // Note: This is the only place where `TupleExpression` is constructed in the parser.
651                Ok(TupleExpression { elements, span, id: self.node_builder.next_id() }.into())
652            }
653        }
654    }
655
656    /// Attempts to parse an array initialization expression and returns an [`Expression`] AST node if successful.
657    fn parse_array_or_repeat_expression(&mut self) -> Result<Expression> {
658        let (open, close) = Delimiter::Bracket.open_close_pair();
659        let open_span = self.expect(&open)?;
660
661        // Attempt to parse the first expression in the array.
662        let Ok(first_expr) = self.parse_expression() else {
663            // If we're unable to parse an expression, just expect a `]` and error out on empty array.
664            let close_span = self.expect(&close)?;
665            return Err(ParserError::array_must_have_at_least_one_element("expression", open_span + close_span).into());
666        };
667
668        // Handle array repetition syntax: [expr; count]
669        if self.eat(&Token::Semicolon) {
670            let count = self.parse_expression()?;
671            let span = open_span + self.expect(&close)?;
672            return Ok(RepeatExpression { expr: first_expr, count, span, id: self.node_builder.next_id() }.into());
673        }
674
675        // Handle array with multiple elements: [expr1, expr2, ...] or single element with or without trailing comma:
676        // [expr,]
677        let mut elements = vec![first_expr];
678        while self.eat(&Token::Comma) && !self.check(&close) {
679            elements.push(self.parse_expression()?);
680        }
681        let span = open_span + self.expect(&close)?;
682        Ok(ArrayExpression { elements, span, id: self.node_builder.next_id() }.into())
683    }
684
685    fn parse_struct_member(&mut self) -> Result<StructVariableInitializer> {
686        let identifier = self.expect_identifier()?;
687
688        let (expression, span) = if self.eat(&Token::Colon) {
689            // Parse individual struct variable declarations.
690            let expression = self.parse_expression()?;
691            let span = identifier.span + expression.span();
692            (Some(expression), span)
693        } else {
694            (None, identifier.span)
695        };
696
697        Ok(StructVariableInitializer { identifier, expression, id: self.node_builder.next_id(), span })
698    }
699
700    /// Returns an [`Expression`] AST node if the next tokens represent a
701    /// struct initialization expression.
702    /// let foo = Foo { x: 1u8 };
703    pub fn parse_struct_init_expression(&mut self, path: Path, const_arguments: Vec<Expression>) -> Result<Expression> {
704        let (members, _, end) =
705            self.parse_list(Delimiter::Brace, Some(Token::Comma), |p| p.parse_struct_member().map(Some))?;
706
707        Ok(StructExpression { span: path.span + end, path, const_arguments, members, id: self.node_builder.next_id() }
708            .into())
709    }
710
711    /// Returns an [`Expression`] AST node if the next token is a primary expression:
712    /// - Literals: field, group, unsigned integer, signed integer, boolean, address, string
713    /// - Aggregate type constructors: array, tuple, structs
714    /// - Identifiers: variables, keywords
715    ///
716    /// This function only parses some of the primary expressions defined in the ABNF grammar;
717    /// for the others, it parses their initial parts,
718    /// leaving it to the [self.parse_postfix_expression] function to complete the parsing.
719    /// For example, of the primary expression `u8::c`, this function only parses the `u8` part,
720    /// leaving it to [self.parse_postfix_expression] to parse the `::c` part.
721    /// So technically the expression returned by this function may not quite be
722    /// an expression as defined in the ABNF grammar,
723    /// but it is only a temporary expression that is combined into a larger one
724    /// by [self.parse_postfix_expression], yielding an actual expression according to the grammar.
725    ///
726    /// Returns an expression error if the token cannot be matched.
727    fn parse_primary_expression(&mut self) -> Result<Expression> {
728        if let Token::LeftParen = self.token.token {
729            return self.parse_tuple_expression();
730        } else if let Token::LeftSquare = self.token.token {
731            return self.parse_array_or_repeat_expression();
732        } else if let Token::Async = self.token.token {
733            let async_keyword_span = self.expect(&Token::Async)?;
734            let block = self.parse_block()?;
735            let span = async_keyword_span + block.span;
736            return Ok(AsyncExpression { block, span, id: self.node_builder.next_id() }.into());
737        }
738
739        let SpannedToken { token, span } = self.token.clone();
740        self.bump();
741
742        Ok(match token {
743            Token::Integer(value) => {
744                let suffix_span = self.token.span;
745                let full_span = span + suffix_span;
746                let assert_no_whitespace = |x| assert_no_whitespace(span, suffix_span, &value, x);
747
748                match self.eat_any(INT_TYPES).then_some(&self.prev_token.token) {
749                    // Hex, octal, binary literal on a noninteger is an error.
750                    Some(Token::Field) | Some(Token::Group) | Some(Token::Scalar)
751                        if value.starts_with("0x")
752                            || value.starts_with("0o")
753                            || value.starts_with("0b")
754                            || value.starts_with("-0x")
755                            || value.starts_with("-0o")
756                            || value.starts_with("-0b") =>
757                    {
758                        return Err(ParserError::hexbin_literal_nonintegers(span).into());
759                    }
760                    // Literal followed by `field`, e.g., `42field`.
761                    Some(Token::Field) => {
762                        assert_no_whitespace("field")?;
763                        Literal::field(value, full_span, self.node_builder.next_id()).into()
764                    }
765                    // Literal followed by `group`, e.g., `42group`.
766                    Some(Token::Group) => {
767                        assert_no_whitespace("group")?;
768                        Literal::group(value, full_span, self.node_builder.next_id()).into()
769                    }
770                    // Literal followed by `scalar` e.g., `42scalar`.
771                    Some(Token::Scalar) => {
772                        assert_no_whitespace("scalar")?;
773                        Literal::scalar(value, full_span, self.node_builder.next_id()).into()
774                    }
775                    // Literal followed by other type suffix, e.g., `42u8`.
776                    Some(suffix) => {
777                        assert_no_whitespace(&suffix.to_string())?;
778                        let int_ty = Self::token_to_int_type(suffix).expect("unknown int type token");
779                        Literal::integer(int_ty, value, full_span, self.node_builder.next_id()).into()
780                    }
781                    None => {
782                        // `Integer` tokens with no suffix are `unsuffixed`. We try to infer their
783                        // type in the type inference phase of the type checker.
784                        Literal::unsuffixed(value, span, self.node_builder.next_id()).into()
785                    }
786                }
787            }
788            Token::True => Literal::boolean(true, span, self.node_builder.next_id()).into(),
789            Token::False => Literal::boolean(false, span, self.node_builder.next_id()).into(),
790            Token::AddressLit(address_string) => {
791                if match self.network {
792                    NetworkName::MainnetV0 => address_string.parse::<Address<MainnetV0>>().is_err(),
793                    NetworkName::TestnetV0 => address_string.parse::<Address<TestnetV0>>().is_err(),
794                    NetworkName::CanaryV0 => address_string.parse::<Address<CanaryV0>>().is_err(),
795                } {
796                    self.emit_err(ParserError::invalid_address_lit(&address_string, span));
797                }
798                Literal::address(address_string, span, self.node_builder.next_id()).into()
799            }
800            Token::StaticString(value) => {
801                Literal { span, id: self.node_builder.next_id(), variant: LiteralVariant::String(value) }.into()
802            }
803            Token::Identifier(first_ident) => {
804                let mut path_span = span;
805                let identifier = Identifier { name: first_ident, span, id: self.node_builder.next_id() };
806                let mut segments = vec![identifier];
807
808                // Parse `::`-separated path segments
809                while self.check(&Token::DoubleColon) {
810                    // Look ahead to see if the next token after `::` is a `[` — if so, stop for const generics
811                    if self.look_ahead(1, |next| matches!(next.token, Token::LeftSquare)) {
812                        break;
813                    }
814
815                    self.bump(); // consume `::`
816
817                    let next_ident = self.expect_identifier()?;
818                    path_span = path_span + next_ident.span;
819                    segments.push(next_ident);
820                }
821
822                let (identifier, qualifier) = segments.split_last().expect("guaranateed to have at least one segment");
823
824                let path = Path::new(qualifier.to_vec(), *identifier, None, path_span, self.node_builder.next_id());
825
826                // Check for struct initializer
827                if !self.disallow_struct_construction && self.check(&Token::LeftCurly) {
828                    // Parse struct and records inits as struct expressions without const arguments.
829                    // Enforce struct or record type later at type checking.
830                    self.parse_struct_init_expression(path.clone(), Vec::new())?
831                } else {
832                    path.into()
833                }
834            }
835            Token::SelfLower => Identifier { name: sym::SelfLower, span, id: self.node_builder.next_id() }.into(),
836            Token::Block => Identifier { name: sym::block, span, id: self.node_builder.next_id() }.into(),
837            Token::Future => Identifier { name: sym::Future, span, id: self.node_builder.next_id() }.into(),
838            Token::Network => Identifier { name: sym::network, span, id: self.node_builder.next_id() }.into(),
839            t if crate::type_::TYPE_TOKENS.contains(&t) => {
840                Identifier { name: t.keyword_to_symbol().unwrap(), span, id: self.node_builder.next_id() }.into()
841            }
842            token => {
843                return Err(ParserError::unexpected_str(token, "expression", span).into());
844            }
845        })
846    }
847}
848
849fn assert_no_whitespace(left_span: Span, right_span: Span, left: &str, right: &str) -> Result<()> {
850    if left_span.hi != right_span.lo {
851        let error_span = Span::new(left_span.hi, right_span.lo); // The span between them.
852        return Err(ParserError::unexpected_whitespace(left, right, error_span).into());
853    }
854
855    Ok(())
856}