Skip to main content

leo_parser_rowan/parser/
expressions.rs

1// Copyright (C) 2019-2026 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
17//! Expression parsing for the Leo language.
18//!
19//! This module implements a Pratt parser (precedence climbing) for Leo expressions.
20//! It handles operator precedence, associativity, and all expression forms.
21
22use super::{CompletedMarker, EXPR_RECOVERY, Parser};
23use crate::syntax_kind::{SyntaxKind, SyntaxKind::*};
24
25// =============================================================================
26// Operator Precedence
27// =============================================================================
28
29/// Binding power for operators (higher = tighter binding).
30/// Returns (left_bp, right_bp) for the operator.
31/// Left-associative: left_bp < right_bp
32/// Right-associative: left_bp > right_bp
33/// Non-associative: left_bp == right_bp (with special handling)
34fn infix_binding_power(op: SyntaxKind) -> Option<(u8, u8)> {
35    let bp = match op {
36        // Ternary is handled specially at the lowest level
37        // Level 14: ||
38        PIPE2 => (28, 29),
39        // Level 13: &&
40        AMP2 => (26, 27),
41        // Level 12: == != (non-associative, but we parse left-to-right)
42        EQ2 | BANG_EQ => (24, 25),
43        // Level 11: < <= > >= (non-associative)
44        LT | LT_EQ | GT | GT_EQ => (22, 23),
45        // Level 10: |
46        PIPE => (20, 21),
47        // Level 9: ^
48        CARET => (18, 19),
49        // Level 8: &
50        AMP => (16, 17),
51        // Level 7: << >>
52        SHL | SHR => (14, 15),
53        // Level 6: + -
54        PLUS | MINUS => (12, 13),
55        // Level 5: * / %
56        STAR | SLASH | PERCENT => (10, 11),
57        // Level 4: ** (right-associative)
58        STAR2 => (9, 8),
59        // Level 3: as (cast)
60        KW_AS => (6, 7),
61        _ => return None,
62    };
63    Some(bp)
64}
65
66/// Prefix binding power for unary operators.
67fn prefix_binding_power(op: SyntaxKind) -> Option<u8> {
68    match op {
69        // Level 2: ! - (unary)
70        BANG | MINUS => Some(30),
71        _ => None,
72    }
73}
74
75/// Postfix binding power for postfix operators.
76fn postfix_binding_power(op: SyntaxKind) -> Option<u8> {
77    match op {
78        // Level 1: . [] () (postfix) - highest precedence
79        DOT | L_BRACKET | L_PAREN => Some(32),
80        _ => None,
81    }
82}
83
84// =============================================================================
85// Expression Options
86// =============================================================================
87
88/// Options for expression parsing to handle context-sensitive cases.
89#[derive(Default, Clone, Copy)]
90pub struct ExprOpts {
91    /// Disallow struct literals `Foo { ... }` in this context.
92    /// Used in conditional expressions to avoid ambiguity.
93    pub no_struct: bool,
94}
95
96impl ExprOpts {
97    /// Create options that disallow struct literals.
98    pub fn no_struct() -> Self {
99        Self { no_struct: true }
100    }
101}
102
103// =============================================================================
104// Expression Parsing
105// =============================================================================
106
107impl Parser<'_, '_> {
108    /// Parse an expression.
109    pub fn parse_expr(&mut self) -> Option<CompletedMarker> {
110        self.parse_expr_with_opts(ExprOpts::default())
111    }
112
113    /// Parse an expression with options.
114    pub fn parse_expr_with_opts(&mut self, opts: ExprOpts) -> Option<CompletedMarker> {
115        self.parse_expr_bp(0, opts)
116    }
117
118    /// Parse an expression with minimum binding power.
119    fn parse_expr_bp(&mut self, min_bp: u8, opts: ExprOpts) -> Option<CompletedMarker> {
120        // Parse prefix expression or primary
121        let mut lhs = self.parse_prefix_expr(opts)?;
122
123        loop {
124            // Try postfix operators (highest precedence)
125            if let Some(bp) = self.current_postfix_bp() {
126                if bp < min_bp {
127                    break;
128                }
129                lhs = self.parse_postfix_expr(lhs, opts)?;
130                continue;
131            }
132
133            // Handle ternary operator specially (lowest precedence)
134            if self.at(QUESTION) && min_bp <= 2 {
135                lhs = self.parse_ternary_expr(lhs)?;
136                continue;
137            }
138
139            // Try infix operators
140            let op = self.current();
141            if let Some((l_bp, r_bp)) = infix_binding_power(op) {
142                if l_bp < min_bp {
143                    break;
144                }
145                lhs = self.parse_infix_expr(lhs, op, r_bp, opts)?;
146                continue;
147            }
148
149            break;
150        }
151
152        Some(lhs)
153    }
154
155    /// Get the postfix binding power of the current token.
156    fn current_postfix_bp(&self) -> Option<u8> {
157        postfix_binding_power(self.current())
158    }
159
160    /// Parse a prefix expression (unary operators or primary).
161    fn parse_prefix_expr(&mut self, opts: ExprOpts) -> Option<CompletedMarker> {
162        self.skip_trivia();
163
164        // Check for prefix operators
165        if let Some(bp) = prefix_binding_power(self.current()) {
166            let m = self.start();
167            self.bump_any(); // operator
168
169            // Parse operand with prefix binding power
170            // If the operand fails, we still complete the unary expression
171            if self.parse_expr_bp(bp, opts).is_none() {
172                self.error("expected expression after unary operator".to_string());
173            }
174
175            return Some(m.complete(self, UNARY_EXPR));
176        }
177
178        // Parse primary expression
179        self.parse_primary_expr(opts)
180    }
181
182    /// Parse a postfix expression (member access, indexing, calls).
183    fn parse_postfix_expr(&mut self, lhs: CompletedMarker, opts: ExprOpts) -> Option<CompletedMarker> {
184        match self.current() {
185            DOT => self.parse_member_access(lhs),
186            L_BRACKET => self.parse_index_expr(lhs),
187            L_PAREN => self.parse_call_expr(lhs, opts),
188            _ => Some(lhs),
189        }
190    }
191
192    /// Parse an infix (binary) expression.
193    fn parse_infix_expr(
194        &mut self,
195        lhs: CompletedMarker,
196        op: SyntaxKind,
197        r_bp: u8,
198        opts: ExprOpts,
199    ) -> Option<CompletedMarker> {
200        let m = lhs.precede(self);
201        self.bump_any(); // operator
202
203        // Handle cast specially - parse type instead of expression
204        if op == KW_AS {
205            if self.parse_type().is_none() {
206                self.error("expected type after 'as'".to_string());
207            }
208            return Some(m.complete(self, CAST_EXPR));
209        }
210
211        // Parse right-hand side
212        // If RHS fails, we still complete the binary expression with an error
213        if self.parse_expr_bp(r_bp, opts).is_none() {
214            self.error("expected expression after operator".to_string());
215        }
216
217        Some(m.complete(self, BINARY_EXPR))
218    }
219
220    /// Parse a ternary expression: `condition ? then : else`.
221    fn parse_ternary_expr(&mut self, condition: CompletedMarker) -> Option<CompletedMarker> {
222        let m = condition.precede(self);
223        self.bump_any(); // ?
224
225        // Parse then branch
226        if self.parse_expr().is_none() {
227            self.error("expected expression after '?'".to_string());
228        }
229
230        self.expect(COLON);
231
232        // Parse else branch (right-associative)
233        if self.parse_expr_bp(2, ExprOpts::default()).is_none() {
234            self.error("expected expression after ':'".to_string());
235        }
236
237        Some(m.complete(self, TERNARY_EXPR))
238    }
239
240    /// Parse member access: `expr.field` or `expr.0` (tuple index).
241    fn parse_member_access(&mut self, lhs: CompletedMarker) -> Option<CompletedMarker> {
242        let m = lhs.precede(self);
243        self.bump_any(); // .
244
245        self.skip_trivia();
246
247        // Parse field name or tuple index.
248        // Keywords are valid as field names (e.g. `.field`, `.owner`).
249        if self.at(IDENT) || self.at(INTEGER) || self.current().is_keyword() {
250            self.bump_any();
251        } else {
252            self.error("expected field name or tuple index".to_string());
253        }
254
255        Some(m.complete(self, FIELD_EXPR))
256    }
257
258    /// Parse index expression: `expr[index]`.
259    fn parse_index_expr(&mut self, lhs: CompletedMarker) -> Option<CompletedMarker> {
260        let m = lhs.precede(self);
261        self.bump_any(); // [
262
263        if self.parse_expr().is_none() {
264            self.error("expected index expression".to_string());
265        }
266
267        self.expect(R_BRACKET);
268
269        Some(m.complete(self, INDEX_EXPR))
270    }
271
272    /// Parse call expression: `expr(args)`.
273    fn parse_call_expr(&mut self, lhs: CompletedMarker, _opts: ExprOpts) -> Option<CompletedMarker> {
274        let m = lhs.precede(self);
275        self.bump_any(); // (
276
277        // Parse arguments
278        if !self.at(R_PAREN) {
279            if self.parse_expr().is_none() && !self.at(R_PAREN) && !self.at(COMMA) {
280                // Skip invalid tokens until we find a recovery point
281                self.error_recover("expected argument expression", EXPR_RECOVERY);
282            }
283            while self.eat(COMMA) {
284                if self.at(R_PAREN) {
285                    break;
286                }
287                if self.parse_expr().is_none() && !self.at(R_PAREN) && !self.at(COMMA) {
288                    self.error_recover("expected argument expression", EXPR_RECOVERY);
289                }
290            }
291        }
292
293        self.expect(R_PAREN);
294
295        Some(m.complete(self, CALL_EXPR))
296    }
297
298    // =========================================================================
299    // Primary Expressions
300    // =========================================================================
301
302    /// Parse a primary expression (atoms and grouped expressions).
303    fn parse_primary_expr(&mut self, opts: ExprOpts) -> Option<CompletedMarker> {
304        self.skip_trivia();
305
306        match self.current() {
307            // Literals
308            INTEGER => self.parse_integer_literal(),
309            STRING => self.parse_string_literal(),
310            ADDRESS_LIT => self.parse_address_literal(),
311            KW_TRUE | KW_FALSE => self.parse_bool_literal(),
312            KW_NONE => self.parse_none_literal(),
313
314            // Parenthesized or tuple expression
315            L_PAREN => self.parse_paren_or_tuple_expr(),
316
317            // Array expression
318            L_BRACKET => self.parse_array_expr(),
319
320            // Identifier, path, or struct literal
321            IDENT => self.parse_ident_expr(opts),
322
323            // Self access
324            KW_SELF => self.parse_self_expr(),
325
326            // Block expressions (block, network)
327            KW_BLOCK => self.parse_block_access(),
328            KW_NETWORK => self.parse_network_access(),
329
330            // Async block expression: `async { ... }`
331            KW_ASYNC => self.parse_async_block_expr(),
332
333            _ => {
334                self.error(format!("expected expression, found {:?}", self.current()));
335                None
336            }
337        }
338    }
339
340    /// Parse an integer literal.
341    fn parse_integer_literal(&mut self) -> Option<CompletedMarker> {
342        let m = self.start();
343        self.bump_any();
344        Some(m.complete(self, LITERAL))
345    }
346
347    /// Parse a string literal.
348    fn parse_string_literal(&mut self) -> Option<CompletedMarker> {
349        let m = self.start();
350        self.bump_any();
351        Some(m.complete(self, LITERAL))
352    }
353
354    /// Parse an address literal.
355    fn parse_address_literal(&mut self) -> Option<CompletedMarker> {
356        let m = self.start();
357        self.bump_any();
358        Some(m.complete(self, LITERAL))
359    }
360
361    /// Parse a boolean literal (true/false).
362    fn parse_bool_literal(&mut self) -> Option<CompletedMarker> {
363        let m = self.start();
364        self.bump_any();
365        Some(m.complete(self, LITERAL))
366    }
367
368    /// Parse the `none` literal.
369    fn parse_none_literal(&mut self) -> Option<CompletedMarker> {
370        let m = self.start();
371        self.bump_any();
372        Some(m.complete(self, LITERAL))
373    }
374
375    /// Parse a parenthesized expression or tuple.
376    fn parse_paren_or_tuple_expr(&mut self) -> Option<CompletedMarker> {
377        let m = self.start();
378        self.bump_any(); // (
379
380        // Empty tuple: ()
381        if self.eat(R_PAREN) {
382            return Some(m.complete(self, TUPLE_EXPR));
383        }
384
385        // Parse first expression
386        if self.parse_expr().is_none() && !self.at(R_PAREN) && !self.at(COMMA) {
387            self.error_recover("expected expression", EXPR_RECOVERY);
388        }
389
390        // Check if this is a tuple
391        if self.eat(COMMA) {
392            // It's a tuple - parse remaining elements
393            if !self.at(R_PAREN) {
394                if self.parse_expr().is_none() && !self.at(R_PAREN) && !self.at(COMMA) {
395                    self.error_recover("expected tuple element", EXPR_RECOVERY);
396                }
397                while self.eat(COMMA) {
398                    if self.at(R_PAREN) {
399                        break;
400                    }
401                    if self.parse_expr().is_none() && !self.at(R_PAREN) && !self.at(COMMA) {
402                        self.error_recover("expected tuple element", EXPR_RECOVERY);
403                    }
404                }
405            }
406            self.expect(R_PAREN);
407            return Some(m.complete(self, TUPLE_EXPR));
408        }
409
410        // Single expression - parenthesized
411        self.expect(R_PAREN);
412        Some(m.complete(self, PAREN_EXPR))
413    }
414
415    /// Parse an array expression: `[a, b, c]` or `[x; n]`.
416    fn parse_array_expr(&mut self) -> Option<CompletedMarker> {
417        let m = self.start();
418        self.bump_any(); // [
419
420        // Empty array
421        if self.eat(R_BRACKET) {
422            return Some(m.complete(self, ARRAY_EXPR));
423        }
424
425        // Parse first element
426        if self.parse_expr().is_none() && !self.at(R_BRACKET) && !self.at(COMMA) && !self.at(SEMICOLON) {
427            self.error_recover("expected array element", EXPR_RECOVERY);
428        }
429
430        // Check for repeat syntax: [x; n]
431        if self.eat(SEMICOLON) {
432            if self.parse_expr().is_none() && !self.at(R_BRACKET) {
433                self.error("expected repeat count".to_string());
434            }
435            self.expect(R_BRACKET);
436            return Some(m.complete(self, ARRAY_EXPR));
437        }
438
439        // List syntax: [a, b, c]
440        while self.eat(COMMA) {
441            if self.at(R_BRACKET) {
442                break;
443            }
444            if self.parse_expr().is_none() && !self.at(R_BRACKET) && !self.at(COMMA) {
445                self.error_recover("expected array element", EXPR_RECOVERY);
446            }
447        }
448
449        self.expect(R_BRACKET);
450        Some(m.complete(self, ARRAY_EXPR))
451    }
452
453    /// Parse an identifier expression, path, or struct literal.
454    fn parse_ident_expr(&mut self, opts: ExprOpts) -> Option<CompletedMarker> {
455        let m = self.start();
456        self.bump_any(); // first identifier
457
458        // Check for locator: name.aleo/path
459        if self.at(DOT) && self.nth(1) == KW_ALEO {
460            self.bump_any(); // .
461            self.bump_any(); // aleo
462
463            if self.eat(SLASH) {
464                // Locator path
465                if self.at(IDENT) {
466                    self.bump_any();
467                }
468            }
469
470            // Optional const generic args after locator: child.aleo/foo::[3]
471            if self.at(COLON_COLON) && self.nth(1) == L_BRACKET {
472                self.bump_any(); // ::
473                self.parse_const_generic_args_bracket();
474            }
475
476            // Check for struct literal: `child.aleo/Foo::[N] { ... }`
477            if !opts.no_struct && self.at(L_BRACE) {
478                self.bump_any(); // {
479                if !self.at(R_BRACE) {
480                    self.parse_struct_field();
481                    while self.eat(COMMA) {
482                        if self.at(R_BRACE) {
483                            break;
484                        }
485                        self.parse_struct_field();
486                    }
487                }
488                self.expect(R_BRACE);
489                return Some(m.complete(self, STRUCT_EXPR));
490            }
491
492            // Check for call
493            if self.at(L_PAREN) {
494                let cm = m.complete(self, PATH_EXPR);
495                return self.parse_call_expr(cm, opts);
496            }
497
498            return Some(m.complete(self, PATH_EXPR));
499        }
500
501        // Check for path or const generics: Foo::Bar or Foo::[N]
502        while self.eat(COLON_COLON) {
503            if self.at(L_BRACKET) {
504                // Const generics with brackets: Foo::[N]
505                self.parse_const_generic_args_bracket();
506                break;
507            } else if self.at(LT) {
508                // This could be const generics or just less-than
509                // Try to parse as const generics
510                self.parse_const_generic_args_angle();
511                break;
512            } else if self.at(IDENT) {
513                self.bump_any();
514            } else {
515                self.error("expected identifier after ::".to_string());
516                break;
517            }
518        }
519
520        // Check for struct literal: `Foo { field: value }`
521        if !opts.no_struct && self.at(L_BRACE) {
522            self.bump_any(); // {
523
524            // Parse fields
525            if !self.at(R_BRACE) {
526                self.parse_struct_field();
527                while self.eat(COMMA) {
528                    if self.at(R_BRACE) {
529                        break;
530                    }
531                    self.parse_struct_field();
532                }
533            }
534
535            self.expect(R_BRACE);
536            return Some(m.complete(self, STRUCT_EXPR));
537        }
538
539        // Check for function call
540        if self.at(L_PAREN) {
541            let cm = m.complete(self, PATH_EXPR);
542            return self.parse_call_expr(cm, opts);
543        }
544
545        Some(m.complete(self, PATH_EXPR))
546    }
547
548    /// Parse a struct field: `name: value` or `name` (shorthand).
549    fn parse_struct_field(&mut self) {
550        let m = self.start();
551        self.skip_trivia();
552
553        if self.at(IDENT) {
554            self.bump_any(); // field name
555
556            if self.eat(COLON) {
557                // Field with value
558                if self.parse_expr().is_none() && !self.at(R_BRACE) && !self.at(COMMA) {
559                    self.error("expected field value".to_string());
560                }
561            }
562            // Otherwise it's shorthand: `{ x }` means `{ x: x }`
563        } else {
564            self.error("expected field name".to_string());
565        }
566
567        m.complete(self, STRUCT_FIELD_INIT);
568    }
569
570    /// Parse `self` expression.
571    fn parse_self_expr(&mut self) -> Option<CompletedMarker> {
572        let m = self.start();
573        self.bump_any(); // self
574        Some(m.complete(self, PATH_EXPR))
575    }
576
577    /// Parse `block.height` access.
578    fn parse_block_access(&mut self) -> Option<CompletedMarker> {
579        let m = self.start();
580        self.bump_any(); // block
581        Some(m.complete(self, PATH_EXPR))
582    }
583
584    /// Parse `network.id` access.
585    fn parse_network_access(&mut self) -> Option<CompletedMarker> {
586        let m = self.start();
587        self.bump_any(); // network
588        Some(m.complete(self, PATH_EXPR))
589    }
590
591    /// Parse an async block expression: `async { stmts }`.
592    fn parse_async_block_expr(&mut self) -> Option<CompletedMarker> {
593        let m = self.start();
594        self.bump_any(); // async
595        self.skip_trivia();
596        if self.parse_block().is_none() {
597            self.error("expected block after 'async'".to_string());
598        }
599        Some(m.complete(self, ASYNC_EXPR))
600    }
601}
602
603#[cfg(test)]
604mod tests {
605    use super::*;
606    use crate::{lexer::lex, parser::Parse};
607    use expect_test::{Expect, expect};
608
609    fn check_expr(input: &str, expect: Expect) {
610        let (tokens, _) = lex(input);
611        let mut parser = Parser::new(input, &tokens);
612        let root = parser.start();
613        parser.parse_expr();
614        parser.skip_trivia();
615        root.complete(&mut parser, ROOT);
616        let parse: Parse = parser.finish();
617        let output = format!("{:#?}", parse.syntax());
618        expect.assert_eq(&output);
619    }
620
621    // =========================================================================
622    // Literals
623    // =========================================================================
624
625    #[test]
626    fn parse_expr_integer() {
627        check_expr("42", expect![[r#"
628                ROOT@0..2
629                  LITERAL@0..2
630                    INTEGER@0..2 "42"
631            "#]]);
632    }
633
634    #[test]
635    fn parse_expr_bool_true() {
636        check_expr("true", expect![[r#"
637                ROOT@0..4
638                  LITERAL@0..4
639                    KW_TRUE@0..4 "true"
640            "#]]);
641    }
642
643    #[test]
644    fn parse_expr_bool_false() {
645        check_expr("false", expect![[r#"
646                ROOT@0..5
647                  LITERAL@0..5
648                    KW_FALSE@0..5 "false"
649            "#]]);
650    }
651
652    #[test]
653    fn parse_expr_none() {
654        check_expr("none", expect![[r#"
655                ROOT@0..4
656                  LITERAL@0..4
657                    KW_NONE@0..4 "none"
658            "#]]);
659    }
660
661    // =========================================================================
662    // Identifiers and Paths
663    // =========================================================================
664
665    #[test]
666    fn parse_expr_ident() {
667        check_expr("foo", expect![[r#"
668                ROOT@0..3
669                  PATH_EXPR@0..3
670                    IDENT@0..3 "foo"
671            "#]]);
672    }
673
674    #[test]
675    fn parse_expr_path() {
676        check_expr("Foo::bar", expect![[r#"
677                ROOT@0..8
678                  PATH_EXPR@0..8
679                    IDENT@0..3 "Foo"
680                    COLON_COLON@3..5 "::"
681                    IDENT@5..8 "bar"
682            "#]]);
683    }
684
685    #[test]
686    fn parse_expr_self() {
687        check_expr("self", expect![[r#"
688                ROOT@0..4
689                  PATH_EXPR@0..4
690                    KW_SELF@0..4 "self"
691            "#]]);
692    }
693
694    // =========================================================================
695    // Arithmetic
696    // =========================================================================
697
698    #[test]
699    fn parse_expr_add() {
700        check_expr("1 + 2", expect![[r#"
701                ROOT@0..5
702                  BINARY_EXPR@0..5
703                    LITERAL@0..1
704                      INTEGER@0..1 "1"
705                    WHITESPACE@1..2 " "
706                    PLUS@2..3 "+"
707                    WHITESPACE@3..4 " "
708                    LITERAL@4..5
709                      INTEGER@4..5 "2"
710            "#]]);
711    }
712
713    #[test]
714    fn parse_expr_mul() {
715        check_expr("a * b", expect![[r#"
716                ROOT@0..5
717                  BINARY_EXPR@0..5
718                    PATH_EXPR@0..2
719                      IDENT@0..1 "a"
720                      WHITESPACE@1..2 " "
721                    STAR@2..3 "*"
722                    WHITESPACE@3..4 " "
723                    PATH_EXPR@4..5
724                      IDENT@4..5 "b"
725            "#]]);
726    }
727
728    #[test]
729    fn parse_expr_precedence() {
730        // 1 + 2 * 3 should parse as 1 + (2 * 3)
731        check_expr("1 + 2 * 3", expect![[r#"
732                ROOT@0..9
733                  BINARY_EXPR@0..9
734                    BINARY_EXPR@0..5
735                      LITERAL@0..1
736                        INTEGER@0..1 "1"
737                      WHITESPACE@1..2 " "
738                      PLUS@2..3 "+"
739                      WHITESPACE@3..4 " "
740                      LITERAL@4..5
741                        INTEGER@4..5 "2"
742                    WHITESPACE@5..6 " "
743                    STAR@6..7 "*"
744                    WHITESPACE@7..8 " "
745                    LITERAL@8..9
746                      INTEGER@8..9 "3"
747            "#]]);
748    }
749
750    #[test]
751    fn parse_expr_power_right_assoc() {
752        // a ** b ** c should parse as a ** (b ** c)
753        check_expr("a ** b ** c", expect![[r#"
754                ROOT@0..11
755                  BINARY_EXPR@0..11
756                    PATH_EXPR@0..2
757                      IDENT@0..1 "a"
758                      WHITESPACE@1..2 " "
759                    STAR2@2..4 "**"
760                    WHITESPACE@4..5 " "
761                    BINARY_EXPR@5..11
762                      PATH_EXPR@5..7
763                        IDENT@5..6 "b"
764                        WHITESPACE@6..7 " "
765                      STAR2@7..9 "**"
766                      WHITESPACE@9..10 " "
767                      PATH_EXPR@10..11
768                        IDENT@10..11 "c"
769            "#]]);
770    }
771
772    // =========================================================================
773    // Unary Operators
774    // =========================================================================
775
776    #[test]
777    fn parse_expr_unary_neg() {
778        check_expr("-x", expect![[r#"
779                ROOT@0..2
780                  UNARY_EXPR@0..2
781                    MINUS@0..1 "-"
782                    PATH_EXPR@1..2
783                      IDENT@1..2 "x"
784            "#]]);
785    }
786
787    #[test]
788    fn parse_expr_unary_not() {
789        check_expr("!flag", expect![[r#"
790                ROOT@0..5
791                  UNARY_EXPR@0..5
792                    BANG@0..1 "!"
793                    PATH_EXPR@1..5
794                      IDENT@1..5 "flag"
795            "#]]);
796    }
797
798    // =========================================================================
799    // Comparison and Logical
800    // =========================================================================
801
802    #[test]
803    fn parse_expr_comparison() {
804        check_expr("a < b", expect![[r#"
805                ROOT@0..5
806                  BINARY_EXPR@0..5
807                    PATH_EXPR@0..2
808                      IDENT@0..1 "a"
809                      WHITESPACE@1..2 " "
810                    LT@2..3 "<"
811                    WHITESPACE@3..4 " "
812                    PATH_EXPR@4..5
813                      IDENT@4..5 "b"
814            "#]]);
815    }
816
817    #[test]
818    fn parse_expr_logical_and() {
819        check_expr("a && b", expect![[r#"
820                ROOT@0..6
821                  BINARY_EXPR@0..6
822                    PATH_EXPR@0..2
823                      IDENT@0..1 "a"
824                      WHITESPACE@1..2 " "
825                    AMP2@2..4 "&&"
826                    WHITESPACE@4..5 " "
827                    PATH_EXPR@5..6
828                      IDENT@5..6 "b"
829            "#]]);
830    }
831
832    #[test]
833    fn parse_expr_logical_or() {
834        check_expr("a || b", expect![[r#"
835                ROOT@0..6
836                  BINARY_EXPR@0..6
837                    PATH_EXPR@0..2
838                      IDENT@0..1 "a"
839                      WHITESPACE@1..2 " "
840                    PIPE2@2..4 "||"
841                    WHITESPACE@4..5 " "
842                    PATH_EXPR@5..6
843                      IDENT@5..6 "b"
844            "#]]);
845    }
846
847    // =========================================================================
848    // Ternary
849    // =========================================================================
850
851    #[test]
852    fn parse_expr_ternary() {
853        check_expr("a ? b : c", expect![[r#"
854                ROOT@0..9
855                  TERNARY_EXPR@0..9
856                    PATH_EXPR@0..2
857                      IDENT@0..1 "a"
858                      WHITESPACE@1..2 " "
859                    QUESTION@2..3 "?"
860                    WHITESPACE@3..4 " "
861                    PATH_EXPR@4..6
862                      IDENT@4..5 "b"
863                      WHITESPACE@5..6 " "
864                    COLON@6..7 ":"
865                    WHITESPACE@7..8 " "
866                    PATH_EXPR@8..9
867                      IDENT@8..9 "c"
868            "#]]);
869    }
870
871    // =========================================================================
872    // Postfix: Member Access, Indexing, Calls
873    // =========================================================================
874
875    #[test]
876    fn parse_expr_member_access() {
877        check_expr("foo.bar", expect![[r#"
878                ROOT@0..7
879                  FIELD_EXPR@0..7
880                    PATH_EXPR@0..3
881                      IDENT@0..3 "foo"
882                    DOT@3..4 "."
883                    IDENT@4..7 "bar"
884            "#]]);
885    }
886
887    #[test]
888    fn parse_expr_tuple_access() {
889        check_expr("tuple.0", expect![[r#"
890                ROOT@0..7
891                  FIELD_EXPR@0..7
892                    PATH_EXPR@0..5
893                      IDENT@0..5 "tuple"
894                    DOT@5..6 "."
895                    INTEGER@6..7 "0"
896            "#]]);
897    }
898
899    #[test]
900    fn parse_expr_index() {
901        check_expr("arr[0]", expect![[r#"
902                ROOT@0..6
903                  INDEX_EXPR@0..6
904                    PATH_EXPR@0..3
905                      IDENT@0..3 "arr"
906                    L_BRACKET@3..4 "["
907                    LITERAL@4..5
908                      INTEGER@4..5 "0"
909                    R_BRACKET@5..6 "]"
910            "#]]);
911    }
912
913    #[test]
914    fn parse_expr_call() {
915        check_expr("foo(a, b)", expect![[r#"
916                ROOT@0..9
917                  CALL_EXPR@0..9
918                    PATH_EXPR@0..3
919                      IDENT@0..3 "foo"
920                    L_PAREN@3..4 "("
921                    PATH_EXPR@4..5
922                      IDENT@4..5 "a"
923                    COMMA@5..6 ","
924                    WHITESPACE@6..7 " "
925                    PATH_EXPR@7..8
926                      IDENT@7..8 "b"
927                    R_PAREN@8..9 ")"
928            "#]]);
929    }
930
931    #[test]
932    fn parse_expr_method_call() {
933        check_expr("x.foo()", expect![[r#"
934                ROOT@0..7
935                  CALL_EXPR@0..7
936                    FIELD_EXPR@0..5
937                      PATH_EXPR@0..1
938                        IDENT@0..1 "x"
939                      DOT@1..2 "."
940                      IDENT@2..5 "foo"
941                    L_PAREN@5..6 "("
942                    R_PAREN@6..7 ")"
943            "#]]);
944    }
945
946    // =========================================================================
947    // Cast
948    // =========================================================================
949
950    #[test]
951    fn parse_expr_cast() {
952        check_expr("x as u64", expect![[r#"
953                ROOT@0..8
954                  CAST_EXPR@0..8
955                    PATH_EXPR@0..2
956                      IDENT@0..1 "x"
957                      WHITESPACE@1..2 " "
958                    KW_AS@2..4 "as"
959                    WHITESPACE@4..5 " "
960                    TYPE_PATH@5..8
961                      KW_U64@5..8 "u64"
962            "#]]);
963    }
964
965    // =========================================================================
966    // Parentheses and Tuples
967    // =========================================================================
968
969    #[test]
970    fn parse_expr_paren() {
971        check_expr("(a + b)", expect![[r#"
972                ROOT@0..7
973                  PAREN_EXPR@0..7
974                    L_PAREN@0..1 "("
975                    BINARY_EXPR@1..6
976                      PATH_EXPR@1..3
977                        IDENT@1..2 "a"
978                        WHITESPACE@2..3 " "
979                      PLUS@3..4 "+"
980                      WHITESPACE@4..5 " "
981                      PATH_EXPR@5..6
982                        IDENT@5..6 "b"
983                    R_PAREN@6..7 ")"
984            "#]]);
985    }
986
987    #[test]
988    fn parse_expr_tuple() {
989        check_expr("(a, b)", expect![[r#"
990                ROOT@0..6
991                  TUPLE_EXPR@0..6
992                    L_PAREN@0..1 "("
993                    PATH_EXPR@1..2
994                      IDENT@1..2 "a"
995                    COMMA@2..3 ","
996                    WHITESPACE@3..4 " "
997                    PATH_EXPR@4..5
998                      IDENT@4..5 "b"
999                    R_PAREN@5..6 ")"
1000            "#]]);
1001    }
1002
1003    #[test]
1004    fn parse_expr_unit() {
1005        check_expr("()", expect![[r#"
1006                ROOT@0..2
1007                  TUPLE_EXPR@0..2
1008                    L_PAREN@0..1 "("
1009                    R_PAREN@1..2 ")"
1010            "#]]);
1011    }
1012
1013    // =========================================================================
1014    // Arrays
1015    // =========================================================================
1016
1017    #[test]
1018    fn parse_expr_array() {
1019        check_expr("[1, 2, 3]", expect![[r#"
1020                ROOT@0..9
1021                  ARRAY_EXPR@0..9
1022                    L_BRACKET@0..1 "["
1023                    LITERAL@1..2
1024                      INTEGER@1..2 "1"
1025                    COMMA@2..3 ","
1026                    WHITESPACE@3..4 " "
1027                    LITERAL@4..5
1028                      INTEGER@4..5 "2"
1029                    COMMA@5..6 ","
1030                    WHITESPACE@6..7 " "
1031                    LITERAL@7..8
1032                      INTEGER@7..8 "3"
1033                    R_BRACKET@8..9 "]"
1034            "#]]);
1035    }
1036
1037    #[test]
1038    fn parse_expr_array_repeat() {
1039        check_expr("[0; 10]", expect![[r#"
1040                ROOT@0..7
1041                  ARRAY_EXPR@0..7
1042                    L_BRACKET@0..1 "["
1043                    LITERAL@1..2
1044                      INTEGER@1..2 "0"
1045                    SEMICOLON@2..3 ";"
1046                    WHITESPACE@3..4 " "
1047                    LITERAL@4..6
1048                      INTEGER@4..6 "10"
1049                    R_BRACKET@6..7 "]"
1050            "#]]);
1051    }
1052
1053    // =========================================================================
1054    // Struct Literals
1055    // =========================================================================
1056
1057    #[test]
1058    fn parse_expr_struct_init() {
1059        check_expr("Point { x: 1, y: 2 }", expect![[r#"
1060                ROOT@0..20
1061                  STRUCT_EXPR@0..20
1062                    IDENT@0..5 "Point"
1063                    WHITESPACE@5..6 " "
1064                    L_BRACE@6..7 "{"
1065                    STRUCT_FIELD_INIT@7..12
1066                      WHITESPACE@7..8 " "
1067                      IDENT@8..9 "x"
1068                      COLON@9..10 ":"
1069                      WHITESPACE@10..11 " "
1070                      LITERAL@11..12
1071                        INTEGER@11..12 "1"
1072                    COMMA@12..13 ","
1073                    STRUCT_FIELD_INIT@13..18
1074                      WHITESPACE@13..14 " "
1075                      IDENT@14..15 "y"
1076                      COLON@15..16 ":"
1077                      WHITESPACE@16..17 " "
1078                      LITERAL@17..18
1079                        INTEGER@17..18 "2"
1080                    WHITESPACE@18..19 " "
1081                    R_BRACE@19..20 "}"
1082            "#]]);
1083    }
1084
1085    #[test]
1086    fn parse_expr_struct_shorthand() {
1087        check_expr("Point { x, y }", expect![[r#"
1088                ROOT@0..14
1089                  STRUCT_EXPR@0..14
1090                    IDENT@0..5 "Point"
1091                    WHITESPACE@5..6 " "
1092                    L_BRACE@6..7 "{"
1093                    STRUCT_FIELD_INIT@7..9
1094                      WHITESPACE@7..8 " "
1095                      IDENT@8..9 "x"
1096                    COMMA@9..10 ","
1097                    STRUCT_FIELD_INIT@10..13
1098                      WHITESPACE@10..11 " "
1099                      IDENT@11..12 "y"
1100                      WHITESPACE@12..13 " "
1101                    R_BRACE@13..14 "}"
1102            "#]]);
1103    }
1104
1105    // =========================================================================
1106    // Complex Expressions
1107    // =========================================================================
1108
1109    // =========================================================================
1110    // Const Generic Arguments (Use Sites) in Expressions
1111    // =========================================================================
1112
1113    fn check_expr_no_errors(input: &str) {
1114        let (tokens, _) = lex(input);
1115        let mut parser = Parser::new(input, &tokens);
1116        let root = parser.start();
1117        parser.parse_expr();
1118        parser.skip_trivia();
1119        root.complete(&mut parser, ROOT);
1120        let parse: Parse = parser.finish();
1121        if !parse.errors().is_empty() {
1122            for err in parse.errors() {
1123                eprintln!("error at {:?}: {}", err.range, err.message);
1124            }
1125            eprintln!("tree:\n{:#?}", parse.syntax());
1126            panic!("expression parse had {} error(s)", parse.errors().len());
1127        }
1128    }
1129
1130    #[test]
1131    fn parse_expr_call_const_generic_simple() {
1132        // Function call with const generic integer arg
1133        check_expr_no_errors("foo::[5]()");
1134    }
1135
1136    #[test]
1137    fn parse_expr_call_const_generic_expr() {
1138        // Function call with expression const generic arg
1139        check_expr_no_errors("foo::[N + 1]()");
1140    }
1141
1142    #[test]
1143    fn parse_expr_call_const_generic_multi() {
1144        // Multi-arg const generic call
1145        check_expr_no_errors("bar::[M, K, N]()");
1146    }
1147
1148    #[test]
1149    fn parse_expr_struct_lit_const_generic() {
1150        // Struct literal with const generic arg
1151        check_expr_no_errors("Foo::[8u32] { arr: x }");
1152    }
1153
1154    #[test]
1155    fn parse_expr_locator_call_const_generic() {
1156        // Locator + const generic call
1157        check_expr_no_errors("child.aleo/foo::[3]()");
1158    }
1159
1160    #[test]
1161    fn parse_expr_assoc_fn_const_generic() {
1162        // Associated function with const generic: Path::method::[N]()
1163        check_expr_no_errors("Foo::bar::[N]()");
1164    }
1165
1166    // =========================================================================
1167    // Complex Expressions
1168    // =========================================================================
1169
1170    #[test]
1171    fn parse_expr_complex() {
1172        check_expr("a.b[c](d) + e", expect![[r#"
1173                ROOT@0..13
1174                  BINARY_EXPR@0..13
1175                    CALL_EXPR@0..9
1176                      INDEX_EXPR@0..6
1177                        FIELD_EXPR@0..3
1178                          PATH_EXPR@0..1
1179                            IDENT@0..1 "a"
1180                          DOT@1..2 "."
1181                          IDENT@2..3 "b"
1182                        L_BRACKET@3..4 "["
1183                        PATH_EXPR@4..5
1184                          IDENT@4..5 "c"
1185                        R_BRACKET@5..6 "]"
1186                      L_PAREN@6..7 "("
1187                      PATH_EXPR@7..8
1188                        IDENT@7..8 "d"
1189                      R_PAREN@8..9 ")"
1190                    WHITESPACE@9..10 " "
1191                    PLUS@10..11 "+"
1192                    WHITESPACE@11..12 " "
1193                    PATH_EXPR@12..13
1194                      IDENT@12..13 "e"
1195            "#]]);
1196    }
1197}