Skip to main content

gdck_syntax/
parser.rs

1//! A recursive-descent parser with a Pratt loop for expressions.
2//!
3//! The parser never fails. Input it cannot fit into the grammar is wrapped in
4//! [`SyntaxKind::Error`] nodes and recorded as a diagnostic, so the resulting
5//! tree always covers the whole file. That matters for editor use, where most
6//! keystrokes leave the buffer temporarily unparseable, and it is what lets
7//! `gdck` report several problems in one pass instead of stopping at the first.
8//!
9//! Trivia is emitted into whichever node is open when the parser looks ahead,
10//! so a comment before a declaration becomes a sibling preceding it rather than
11//! disappearing.
12
13use crate::error::SyntaxError;
14// The grammar rules below read far better as `self.at(FuncKw)` than as
15// `self.at(SyntaxKind::FuncKw)`, and this module does nothing but grammar.
16#[allow(clippy::enum_glob_use)]
17use crate::kind::SyntaxKind::{self, *};
18use crate::lexer::{Token, tokenize};
19use crate::text::TextRange;
20use crate::tree::{Checkpoint, SyntaxTree, TreeBuilder};
21
22/// Parse GDScript source into a lossless tree.
23///
24/// Always returns a tree. Check [`SyntaxTree::errors`] for problems.
25#[must_use]
26pub fn parse(source: &str) -> SyntaxTree {
27    let lexed = tokenize(source);
28    Parser {
29        source,
30        tokens: lexed.tokens,
31        pos: 0,
32        builder: TreeBuilder::new(),
33        errors: lexed.errors,
34        bracket_depth: 0,
35        in_pattern: false,
36        fuel: 0,
37    }
38    .run()
39}
40
41struct Parser<'a> {
42    source: &'a str,
43    tokens: Vec<Token>,
44    pos: usize,
45    builder: TreeBuilder,
46    errors: Vec<SyntaxError>,
47    /// Nesting depth of `()`, `[]` and `{}`.
48    ///
49    /// Outside brackets a newline ends the statement, so the expression parser
50    /// must stop at one; inside them a newline is just formatting and an
51    /// expression may span as many lines as it likes.
52    bracket_depth: u32,
53    /// Set while parsing a `match` pattern, where `var name` bindings and `..`
54    /// rest markers are legal in places an ordinary expression forbids them.
55    in_pattern: bool,
56    /// Guards against a rule that loops without consuming input.
57    fuel: u32,
58}
59
60/// Tokens that can begin a class-level declaration; used to resynchronise.
61const CLASS_MEMBER_START: &[SyntaxKind] = &[
62    At,
63    VarKw,
64    ConstKw,
65    FuncKw,
66    ClassKw,
67    ClassNameKw,
68    ExtendsKw,
69    SignalKw,
70    EnumKw,
71    StaticKw,
72];
73
74/// Tokens that can begin a statement; used to resynchronise inside a block.
75const STATEMENT_START: &[SyntaxKind] = &[
76    VarKw,
77    ConstKw,
78    IfKw,
79    ElifKw,
80    ElseKw,
81    ForKw,
82    WhileKw,
83    MatchKw,
84    ReturnKw,
85    PassKw,
86    BreakKw,
87    ContinueKw,
88    BreakpointKw,
89    AssertKw,
90    AwaitKw,
91    FuncKw,
92    ClassKw,
93    SignalKw,
94    EnumKw,
95    StaticKw,
96];
97
98impl Parser<'_> {
99    fn run(mut self) -> SyntaxTree {
100        self.builder.start_node(SourceFile);
101        while !self.at(Eof) {
102            let before = self.pos;
103            self.parse_class_member();
104            while self.eat(Semicolon) {}
105            self.ensure_progress(before, CLASS_MEMBER_START);
106        }
107        // Trailing trivia and the Eof marker still belong in the tree.
108        self.skip_trivia();
109        self.bump_raw();
110        self.builder.finish_node();
111        self.builder.finish(self.source.to_string(), self.errors)
112    }
113
114    // -- Class level --------------------------------------------------------
115
116    fn parse_class_member(&mut self) {
117        let checkpoint = self.builder.checkpoint();
118
119        // Annotations bind to the declaration that follows, so parse them
120        // first and let the declaration retroactively adopt them.
121        let mut is_abstract = false;
122        while self.at(At) {
123            is_abstract |= self.parse_annotation();
124        }
125
126        match self.current() {
127            // File-level annotations such as `@tool` and `@icon` precede these
128            // but do not modify them, so they stay as siblings.
129            ClassNameKw => self.parse_class_name(),
130            ExtendsKw => self.parse_extends(),
131
132            VarKw => self.parse_var_decl(checkpoint),
133            ConstKw => self.parse_const_decl(checkpoint),
134            SignalKw => self.parse_signal_decl(checkpoint),
135            EnumKw => self.parse_enum_decl(checkpoint),
136            FuncKw => self.parse_func_decl(checkpoint, is_abstract),
137            ClassKw => self.parse_inner_class(checkpoint),
138
139            StaticKw => match self.nth(1) {
140                VarKw => self.parse_var_decl(checkpoint),
141                FuncKw => self.parse_func_decl(checkpoint, is_abstract),
142                _ => self.error_and_recover(
143                    "expected `var` or `func` after `static`",
144                    CLASS_MEMBER_START,
145                ),
146            },
147
148            // A bare `pass` is a legal class body, standing in for members that
149            // are not there yet.
150            PassKw => self.simple_statement(PassStmt),
151
152            // A bare string at class level is a docstring.
153            Str => self.parse_expr_statement(),
154
155            // Annotations with nothing to modify are legal on their own, as
156            // `@tool` and `@icon` are.
157            At | Eof | Dedent => {}
158
159            _ => self.error_and_recover("expected a declaration", CLASS_MEMBER_START),
160        }
161    }
162
163    /// `@name` or `@name(arg, ...)`. Returns whether this was `@abstract`.
164    fn parse_annotation(&mut self) -> bool {
165        self.builder.start_node(Annotation);
166        self.bump(); // @
167        let mut is_abstract = false;
168        if self.current().is_ident_like() {
169            is_abstract = self.current_text() == "abstract";
170            self.bump();
171        } else {
172            self.error("expected an annotation name after `@`");
173        }
174        if self.at(LParen) {
175            self.parse_arg_list();
176        }
177        self.builder.finish_node();
178        is_abstract
179    }
180
181    /// `class_name Name [extends Base]`
182    fn parse_class_name(&mut self) {
183        self.builder.start_node(ClassNameDecl);
184        self.bump(); // class_name
185        self.expect(Ident, "expected a class name");
186        if self.at(ExtendsKw) {
187            self.parse_extends();
188        }
189        self.builder.finish_node();
190    }
191
192    /// `extends Base` or `extends "res://base.gd"`
193    fn parse_extends(&mut self) {
194        self.builder.start_node(ExtendsDecl);
195        self.bump(); // extends
196        if self.at(Str) {
197            self.bump();
198            // `extends "path.gd".Inner`
199            while self.at(Dot) {
200                self.bump();
201                self.expect(Ident, "expected a name after `.`");
202            }
203        } else {
204            self.parse_type();
205        }
206        self.builder.finish_node();
207    }
208
209    /// `signal name` or `signal name(a, b: int)`
210    fn parse_signal_decl(&mut self, checkpoint: Checkpoint) {
211        self.builder.start_node_at(checkpoint, SignalDecl);
212        self.bump(); // signal
213        self.expect(Ident, "expected a signal name");
214        if self.at(LParen) {
215            self.parse_param_list();
216        }
217        self.builder.finish_node();
218    }
219
220    /// `enum [Name] { A, B = 2, }`
221    fn parse_enum_decl(&mut self, checkpoint: Checkpoint) {
222        self.builder.start_node_at(checkpoint, EnumDecl);
223        self.bump(); // enum
224        if self.at(Ident) {
225            self.bump();
226        }
227        if self.at(LBrace) {
228            self.builder.start_node(EnumBody);
229            self.bump(); // {
230            self.enter_brackets();
231            while !self.at(RBrace) && !self.at(Eof) {
232                let before = self.pos;
233                self.builder.start_node(EnumVariant);
234                self.expect(Ident, "expected an enum member name");
235                if self.eat(Eq) {
236                    self.parse_expr();
237                }
238                self.builder.finish_node();
239                if !self.eat(Comma) {
240                    break;
241                }
242                self.ensure_progress(before, &[RBrace]);
243            }
244            self.expect(RBrace, "expected `}` to close the enum");
245            self.leave_brackets();
246            self.builder.finish_node();
247        } else {
248            self.error("expected `{` to open the enum body");
249        }
250        self.builder.finish_node();
251    }
252
253    /// `const NAME [: Type] = value`
254    fn parse_const_decl(&mut self, checkpoint: Checkpoint) {
255        self.builder.start_node_at(checkpoint, ConstDecl);
256        self.bump(); // const
257        self.expect(Ident, "expected a constant name");
258        if !self.parse_type_and_initializer() {
259            self.error("a constant must be initialised");
260        }
261        self.builder.finish_node();
262    }
263
264    /// `[static] var name [: Type] [= value] [: set/get]`
265    fn parse_var_decl(&mut self, checkpoint: Checkpoint) {
266        self.builder.start_node_at(checkpoint, VarDecl);
267        self.eat(StaticKw);
268        self.bump(); // var
269        self.expect(Ident, "expected a variable name");
270        self.parse_type_and_initializer();
271        // Property accessors: `var x: set = f, get = g` or an indented block.
272        if self.at(Colon) {
273            self.parse_accessors();
274        }
275        self.builder.finish_node();
276    }
277
278    /// Parse `: Type`, `:= value`, `: Type = value`, `= value`, or nothing.
279    ///
280    /// Returns whether an initializer was present. The `:=` form is recorded as
281    /// an [`Initializer`] holding the `:=` token, which is what lets the
282    /// static-typing lint rules tell inferred from explicit declarations.
283    fn parse_type_and_initializer(&mut self) -> bool {
284        // `:=` and the equivalent `: =` written with a space.
285        if self.at(ColonEq) || (self.at(Colon) && self.nth(1) == Eq) {
286            self.builder.start_node(Initializer);
287            self.bump(); // `:=` or `:`
288            self.eat(Eq); // the `=` of a spaced `: =`
289            self.parse_expr();
290            self.builder.finish_node();
291            return true;
292        }
293
294        // A bare `:` is a type hint only when a type name follows; otherwise it
295        // opens an accessor clause, which is the caller's business. `set` and
296        // `get` are identifiers, so `var p: set = f` needs telling apart from a
297        // genuine type annotation by name.
298        let names_accessor = matches!(self.nth_text(1), "set" | "get");
299        if self.at(Colon) && matches!(self.nth(1), Ident | VoidKw) && !names_accessor {
300            self.builder.start_node(TypeHint);
301            self.bump(); // :
302            self.parse_type();
303            self.builder.finish_node();
304        }
305
306        if self.at(Eq) {
307            self.parse_initializer();
308            return true;
309        }
310        false
311    }
312
313    fn parse_initializer(&mut self) {
314        self.builder.start_node(Initializer);
315        self.bump(); // =
316        self.parse_expr();
317        self.builder.finish_node();
318    }
319
320    /// The `set`/`get` clauses attached to a `var`.
321    fn parse_accessors(&mut self) {
322        self.builder.start_node(Accessors);
323        self.bump(); // :
324        if self.at(Indent) {
325            self.bump();
326            while !self.at(Dedent) && !self.at(Eof) {
327                let before = self.pos;
328                self.parse_one_accessor();
329                // `get = __get,` and `set = __set` may be comma-separated even
330                // when written across several lines.
331                self.eat(Comma);
332                self.ensure_progress(before, &[Dedent]);
333            }
334            self.eat(Dedent);
335        } else {
336            loop {
337                self.parse_one_accessor();
338                if !self.eat(Comma) {
339                    break;
340                }
341            }
342        }
343        self.builder.finish_node();
344    }
345
346    fn parse_one_accessor(&mut self) {
347        // `set` and `get` are contextual keywords: everywhere else they are
348        // ordinary identifiers, so they are matched by text rather than kind.
349        if !self.at(Ident) {
350            self.error_and_recover("expected `set` or `get`", &[Dedent, Comma]);
351            return;
352        }
353        let node = match self.current_text() {
354            "set" => Setter,
355            "get" => Getter,
356            _ => {
357                self.error_and_recover("expected `set` or `get`", &[Dedent, Comma]);
358                return;
359            }
360        };
361
362        self.builder.start_node(node);
363        self.bump(); // set / get
364
365        if self.at(LParen) {
366            // `set(value):` — an inline accessor body.
367            self.parse_param_list();
368        }
369        if self.eat(Eq) {
370            // `set = method_name`
371            self.parse_expr();
372        } else if self.eat(Colon) {
373            self.parse_block();
374        } else {
375            self.error("expected `=` or `:` after the accessor");
376        }
377        self.builder.finish_node();
378    }
379
380    /// `[static] func name(params) [-> Type]: block`
381    ///
382    /// `allow_no_body` is set when an `@abstract` annotation preceded the
383    /// declaration, since an abstract function is written without one.
384    fn parse_func_decl(&mut self, checkpoint: Checkpoint, allow_no_body: bool) {
385        self.builder.start_node_at(checkpoint, FuncDecl);
386        self.eat(StaticKw);
387        self.bump(); // func
388        self.expect(Ident, "expected a function name");
389        if self.at(LParen) {
390            self.parse_param_list();
391        } else {
392            self.error("expected `(` to open the parameter list");
393        }
394        if self.at(Arrow) {
395            self.builder.start_node(ReturnType);
396            self.bump();
397            self.parse_type();
398            self.builder.finish_node();
399        }
400        if self.eat(Colon) {
401            self.parse_block();
402        } else if !allow_no_body {
403            self.error("expected `:` to open the function body");
404        }
405        self.builder.finish_node();
406    }
407
408    /// `class Name [extends Base]: block`
409    fn parse_inner_class(&mut self, checkpoint: Checkpoint) {
410        self.builder.start_node_at(checkpoint, ClassDecl);
411        self.bump(); // class
412        self.expect(Ident, "expected a class name");
413        if self.at(ExtendsKw) {
414            self.parse_extends();
415        }
416        if self.eat(Colon) {
417            self.parse_class_block();
418        } else {
419            self.error("expected `:` to open the class body");
420        }
421        self.builder.finish_node();
422    }
423
424    fn parse_class_block(&mut self) {
425        self.builder.start_node(Block);
426        if self.at(Indent) {
427            self.bump();
428            while !self.at(Dedent) && !self.at(Eof) {
429                let before = self.pos;
430                self.parse_class_member();
431                while self.eat(Semicolon) {}
432                self.ensure_progress(before, CLASS_MEMBER_START);
433            }
434            self.eat(Dedent);
435        } else {
436            self.parse_class_member();
437        }
438        self.builder.finish_node();
439    }
440
441    fn parse_param_list(&mut self) {
442        self.builder.start_node(ParamList);
443        self.bump(); // (
444        self.enter_brackets();
445        while !self.at(RParen) && !self.at(Eof) {
446            let before = self.pos;
447            self.builder.start_node(Param);
448            // `...rest` collects the remaining arguments.
449            self.eat(Ellipsis);
450            self.expect(Ident, "expected a parameter name");
451            self.parse_type_and_initializer();
452            self.builder.finish_node();
453            if !self.eat(Comma) {
454                break;
455            }
456            self.ensure_progress(before, &[RParen]);
457        }
458        self.expect(RParen, "expected `)` to close the parameter list");
459        self.leave_brackets();
460        self.builder.finish_node();
461    }
462
463    fn parse_arg_list(&mut self) {
464        self.builder.start_node(ArgList);
465        self.bump(); // (
466        self.enter_brackets();
467        while !self.at(RParen) && !self.at(Eof) {
468            let before = self.pos;
469            self.parse_expr();
470            if !self.eat(Comma) {
471                break;
472            }
473            self.ensure_progress(before, &[RParen]);
474        }
475        self.expect(RParen, "expected `)` to close the argument list");
476        self.leave_brackets();
477        self.builder.finish_node();
478    }
479
480    /// `int`, `Vector2`, `A.B`, `Array[int]`, `void`
481    fn parse_type(&mut self) {
482        if self.at(VoidKw) {
483            self.bump();
484            return;
485        }
486        if !self.at(Ident) {
487            self.error("expected a type name");
488            return;
489        }
490        self.bump();
491        while self.at(Dot) {
492            self.bump();
493            self.expect(Ident, "expected a name after `.`");
494        }
495        if self.at(LBracket) {
496            self.bump();
497            self.enter_brackets();
498            while !self.at(RBracket) && !self.at(Eof) {
499                let before = self.pos;
500                self.parse_type();
501                if !self.eat(Comma) {
502                    break;
503                }
504                self.ensure_progress(before, &[RBracket]);
505            }
506            self.expect(RBracket, "expected `]` to close the type parameters");
507            self.leave_brackets();
508        }
509    }
510
511    // -- Statements ---------------------------------------------------------
512
513    /// Parse a block body, either indented or inline after a `:`.
514    fn parse_block(&mut self) {
515        self.builder.start_node(Block);
516        if self.at(Indent) {
517            // An indented block is its own line-oriented world even when it
518            // sits inside brackets, which is the case for a multi-line lambda
519            // passed as an argument. Without this reset, statements in the body
520            // would be glued together into one expression.
521            let enclosing_brackets = std::mem::take(&mut self.bracket_depth);
522            self.bump();
523            while !self.at(Dedent) && !self.at(Eof) {
524                let before = self.pos;
525                self.parse_statement();
526                // `a = 1; b = 2` on one line inside an indented block.
527                while self.eat(Semicolon) {}
528                self.ensure_progress(before, STATEMENT_START);
529            }
530            self.eat(Dedent);
531            self.bracket_depth = enclosing_brackets;
532        } else {
533            // `if x: pass` — one or more statements on the same line.
534            loop {
535                self.parse_statement();
536                if !self.eat(Semicolon) || self.newline_ahead() {
537                    break;
538                }
539                if self.at(Eof) || self.at(Dedent) {
540                    break;
541                }
542            }
543        }
544        self.builder.finish_node();
545    }
546
547    #[allow(clippy::too_many_lines)]
548    fn parse_statement(&mut self) {
549        match self.current() {
550            PassKw => self.simple_statement(PassStmt),
551            BreakKw => self.simple_statement(BreakStmt),
552            ContinueKw => self.simple_statement(ContinueStmt),
553            BreakpointKw => self.simple_statement(BreakpointStmt),
554
555            ReturnKw => {
556                self.builder.start_node(ReturnStmt);
557                self.bump();
558                if !self.at_statement_end() {
559                    self.parse_expr();
560                }
561                self.builder.finish_node();
562            }
563
564            AssertKw => {
565                self.builder.start_node(AssertStmt);
566                self.bump();
567                if self.at(LParen) {
568                    self.parse_arg_list();
569                } else {
570                    self.error("expected `(` after `assert`");
571                }
572                self.builder.finish_node();
573            }
574
575            VarKw => {
576                let checkpoint = self.builder.checkpoint();
577                self.parse_var_decl(checkpoint);
578            }
579            ConstKw => {
580                let checkpoint = self.builder.checkpoint();
581                self.parse_const_decl(checkpoint);
582            }
583            StaticKw if self.nth(1) == VarKw => {
584                let checkpoint = self.builder.checkpoint();
585                self.parse_var_decl(checkpoint);
586            }
587
588            IfKw => self.parse_if_statement(),
589            WhileKw => {
590                self.builder.start_node(WhileStmt);
591                self.bump();
592                self.parse_expr();
593                if self.eat(Colon) {
594                    self.parse_block();
595                } else {
596                    self.error("expected `:` to open the loop body");
597                }
598                self.builder.finish_node();
599            }
600            ForKw => self.parse_for_statement(),
601            MatchKw => self.parse_match_statement(),
602
603            // Annotations such as `@warning_ignore` are legal inside a body.
604            At => {
605                let checkpoint = self.builder.checkpoint();
606                while self.at(At) {
607                    self.parse_annotation();
608                }
609                match self.current() {
610                    VarKw => self.parse_var_decl(checkpoint),
611                    ConstKw => self.parse_const_decl(checkpoint),
612                    // A trailing annotation at the end of a block modifies
613                    // nothing, but is not an error.
614                    Dedent | Eof => {}
615                    _ => self.parse_statement(),
616                }
617            }
618
619            // A nested `func` is a lambda used as a statement; `class` and
620            // `signal` can appear inside a class body reached from here.
621            ClassKw | SignalKw | EnumKw => self.parse_class_member(),
622
623            Eof | Dedent => {
624                self.error("unexpected end of block");
625            }
626
627            _ => self.parse_expr_statement(),
628        }
629    }
630
631    fn simple_statement(&mut self, kind: SyntaxKind) {
632        self.builder.start_node(kind);
633        self.bump();
634        self.builder.finish_node();
635    }
636
637    fn parse_if_statement(&mut self) {
638        self.builder.start_node(IfStmt);
639        self.bump(); // if
640        self.parse_expr();
641        if self.eat(Colon) {
642            self.parse_block();
643        } else {
644            self.error("expected `:` to open the branch body");
645        }
646
647        while self.at(ElifKw) {
648            self.builder.start_node(ElifClause);
649            self.bump();
650            self.parse_expr();
651            if self.eat(Colon) {
652                self.parse_block();
653            } else {
654                self.error("expected `:` to open the branch body");
655            }
656            self.builder.finish_node();
657        }
658
659        if self.at(ElseKw) {
660            self.builder.start_node(ElseClause);
661            self.bump();
662            if self.eat(Colon) {
663                self.parse_block();
664            } else {
665                self.error("expected `:` to open the branch body");
666            }
667            self.builder.finish_node();
668        }
669
670        self.builder.finish_node();
671    }
672
673    fn parse_for_statement(&mut self) {
674        self.builder.start_node(ForStmt);
675        self.bump(); // for
676        self.expect(Ident, "expected a loop variable name");
677        if self.at(Colon) && matches!(self.nth(1), Ident | VoidKw) {
678            self.builder.start_node(TypeHint);
679            self.bump();
680            self.parse_type();
681            self.builder.finish_node();
682        }
683        // The `in` here is part of the loop, not the containment operator, so
684        // the iterable is parsed separately rather than as one expression.
685        if !self.eat(InKw) {
686            self.error("expected `in` after the loop variable");
687        }
688        self.parse_expr();
689        if self.eat(Colon) {
690            self.parse_block();
691        } else {
692            self.error("expected `:` to open the loop body");
693        }
694        self.builder.finish_node();
695    }
696
697    fn parse_match_statement(&mut self) {
698        self.builder.start_node(MatchStmt);
699        self.bump(); // match
700        self.parse_expr();
701        if !self.eat(Colon) {
702            self.error("expected `:` after the match subject");
703        }
704        if self.at(Indent) {
705            self.bump();
706            while !self.at(Dedent) && !self.at(Eof) {
707                let before = self.pos;
708                self.parse_match_arm();
709                self.ensure_progress(before, &[Dedent]);
710            }
711            self.eat(Dedent);
712        } else {
713            self.error("expected an indented block of match arms");
714        }
715        self.builder.finish_node();
716    }
717
718    fn parse_match_arm(&mut self) {
719        self.builder.start_node(MatchArm);
720        // Patterns are comma-separated alternatives. Inside one, `var x` binds
721        // a capture and `..` matches the rest, at any nesting depth — so the
722        // flag stays set through nested array and dictionary patterns.
723        self.in_pattern = true;
724        loop {
725            self.parse_expr();
726            if !self.eat(Comma) {
727                break;
728            }
729            if self.at(Colon) || self.at(WhenKw) || self.at(Eof) {
730                break;
731            }
732        }
733        self.in_pattern = false;
734        if self.at(WhenKw) {
735            self.builder.start_node(MatchGuard);
736            self.bump();
737            self.parse_expr();
738            self.builder.finish_node();
739        }
740        if self.eat(Colon) {
741            self.parse_block();
742        } else {
743            self.error("expected `:` after the match pattern");
744        }
745        self.builder.finish_node();
746    }
747
748    /// An expression, optionally followed by an assignment operator.
749    fn parse_expr_statement(&mut self) {
750        let checkpoint = self.builder.checkpoint();
751        self.builder.start_node(ExprStmt);
752        self.parse_expr();
753
754        if is_assign_op(self.current()) {
755            // Retroactively reclassify: this was an assignment all along.
756            self.builder.finish_node();
757            self.builder.start_node_at(checkpoint, AssignStmt);
758            self.bump();
759            self.parse_expr();
760        }
761        self.builder.finish_node();
762    }
763
764    // -- Expressions --------------------------------------------------------
765
766    fn parse_expr(&mut self) {
767        self.parse_expr_bp(0);
768    }
769
770    /// Pratt loop. `min_bp` is the binding power the caller has already claimed.
771    fn parse_expr_bp(&mut self, min_bp: u8) {
772        let checkpoint = self.builder.checkpoint();
773        self.parse_prefix();
774
775        loop {
776            // A newline outside brackets ends the statement. Without this the
777            // `if` opening the *next* line would be read as a ternary belonging
778            // to this expression.
779            if self.at_line_break() {
780                break;
781            }
782            let kind = self.current();
783
784            // Ternary `value if cond else other` binds loosest of all.
785            if kind == IfKw && min_bp <= TERNARY_BP {
786                self.builder.start_node_at(checkpoint, TernaryExpr);
787                self.bump(); // if
788                self.parse_expr_bp(TERNARY_BP + 1);
789                if !self.eat(ElseKw) {
790                    self.error("expected `else` to complete the conditional expression");
791                }
792                self.parse_expr_bp(TERNARY_BP);
793                self.builder.finish_node();
794                continue;
795            }
796
797            // `not in` is a single infix operator spelled as two words. It has
798            // to be matched before `not` is considered as anything else.
799            if kind == NotKw && self.nth(1) == InKw {
800                let (left_bp, right_bp) = NOT_IN_BP;
801                if left_bp < min_bp {
802                    break;
803                }
804                self.builder.start_node_at(checkpoint, BinaryExpr);
805                self.bump(); // not
806                self.bump(); // in
807                self.parse_expr_bp(right_bp);
808                self.builder.finish_node();
809                continue;
810            }
811
812            // `as` is a cast, not a plain binary operator, so it gets its own
813            // node kind for the benefit of the static-typing lint rules.
814            if kind == AsKw && CAST_BP >= min_bp {
815                self.builder.start_node_at(checkpoint, CastExpr);
816                self.bump();
817                self.parse_type();
818                self.builder.finish_node();
819                continue;
820            }
821
822            let Some((left_bp, right_bp)) = infix_binding_power(kind) else {
823                break;
824            };
825            if left_bp < min_bp {
826                break;
827            }
828
829            self.builder.start_node_at(checkpoint, BinaryExpr);
830            self.bump();
831            self.parse_expr_bp(right_bp);
832            self.builder.finish_node();
833        }
834    }
835
836    fn parse_prefix(&mut self) {
837        match self.current() {
838            NotKw | Bang => {
839                self.builder.start_node(UnaryExpr);
840                self.bump();
841                self.parse_expr_bp(NOT_BP);
842                self.builder.finish_node();
843            }
844            Minus | Plus | Tilde => {
845                self.builder.start_node(UnaryExpr);
846                self.bump();
847                self.parse_expr_bp(UNARY_BP);
848                self.builder.finish_node();
849            }
850            AwaitKw => {
851                self.builder.start_node(AwaitExpr);
852                self.bump();
853                self.parse_expr_bp(UNARY_BP);
854                self.builder.finish_node();
855            }
856            _ => self.parse_postfix(),
857        }
858    }
859
860    fn parse_postfix(&mut self) {
861        let checkpoint = self.builder.checkpoint();
862        self.parse_atom();
863
864        loop {
865            // Postfix operators cannot start a new line either, so `foo()`
866            // followed by a line beginning `(x)` stays two statements.
867            if self.at_line_break() {
868                break;
869            }
870            match self.current() {
871                LParen => {
872                    self.builder.start_node_at(checkpoint, CallExpr);
873                    self.parse_arg_list();
874                    self.builder.finish_node();
875                }
876                LBracket => {
877                    self.builder.start_node_at(checkpoint, SubscriptExpr);
878                    self.bump();
879                    self.enter_brackets();
880                    self.parse_expr();
881                    self.expect(RBracket, "expected `]` to close the subscript");
882                    self.leave_brackets();
883                    self.builder.finish_node();
884                }
885                Dot => {
886                    self.builder.start_node_at(checkpoint, AttributeExpr);
887                    self.bump();
888                    // Keywords are legal member names in a few places, so accept
889                    // any identifier-shaped token here.
890                    if self.at(Ident) {
891                        self.bump();
892                    } else {
893                        self.error("expected a member name after `.`");
894                    }
895                    self.builder.finish_node();
896                }
897                _ => break,
898            }
899        }
900    }
901
902    #[allow(clippy::too_many_lines)]
903    fn parse_atom(&mut self) {
904        match self.current() {
905            Int | Float | Str | StringName | NodePath | GetNode | UniqueNode | TrueKw | FalseKw
906            | NullKw => {
907                self.builder.start_node(Literal);
908                self.bump();
909                self.builder.finish_node();
910            }
911
912            Ident | SelfKw | SuperKw => {
913                self.builder.start_node(NameRef);
914                self.bump();
915                self.builder.finish_node();
916            }
917
918            PreloadKw => {
919                self.builder.start_node(PreloadExpr);
920                self.bump();
921                if self.at(LParen) {
922                    self.parse_arg_list();
923                } else {
924                    self.error("expected `(` after `preload`");
925                }
926                self.builder.finish_node();
927            }
928
929            LParen => {
930                self.builder.start_node(ParenExpr);
931                self.bump();
932                self.enter_brackets();
933                if !self.at(RParen) {
934                    self.parse_expr();
935                }
936                self.expect(RParen, "expected `)` to close the group");
937                self.leave_brackets();
938                self.builder.finish_node();
939            }
940
941            LBracket => {
942                self.builder.start_node(ArrayExpr);
943                self.bump();
944                self.enter_brackets();
945                while !self.at(RBracket) && !self.at(Eof) {
946                    let before = self.pos;
947                    self.parse_expr();
948                    if !self.eat(Comma) {
949                        break;
950                    }
951                    self.ensure_progress(before, &[RBracket]);
952                }
953                self.expect(RBracket, "expected `]` to close the array");
954                self.leave_brackets();
955                self.builder.finish_node();
956            }
957
958            LBrace => self.parse_dict(),
959
960            // `var name` binds a capture inside a match pattern.
961            VarKw if self.in_pattern => {
962                self.builder.start_node(NameRef);
963                self.bump();
964                self.expect(Ident, "expected a name after `var` in a pattern");
965                self.builder.finish_node();
966            }
967
968            // `..` matches whatever is left of an array or dictionary pattern.
969            DotDot if self.in_pattern => {
970                self.builder.start_node(Literal);
971                self.bump();
972                self.builder.finish_node();
973            }
974
975            // A lambda: `func(a): ...` or `func named(a): ...`
976            FuncKw => {
977                self.builder.start_node(LambdaExpr);
978                self.bump();
979                if self.at(Ident) {
980                    self.bump();
981                }
982                if self.at(LParen) {
983                    self.parse_param_list();
984                } else {
985                    self.error("expected `(` to open the lambda parameters");
986                }
987                if self.at(Arrow) {
988                    self.builder.start_node(ReturnType);
989                    self.bump();
990                    self.parse_type();
991                    self.builder.finish_node();
992                }
993                if self.eat(Colon) {
994                    self.parse_block();
995                } else {
996                    self.error("expected `:` to open the lambda body");
997                }
998                self.builder.finish_node();
999            }
1000
1001            _ => self.error_and_recover("expected an expression", STATEMENT_START),
1002        }
1003    }
1004
1005    /// `{"key": value}` and the Lua-style `{key = value}`.
1006    fn parse_dict(&mut self) {
1007        self.builder.start_node(DictExpr);
1008        self.bump(); // {
1009        self.enter_brackets();
1010        while !self.at(RBrace) && !self.at(Eof) {
1011            let before = self.pos;
1012            self.builder.start_node(DictEntry);
1013            if self.in_pattern && self.at(DotDot) {
1014                // A rest marker stands alone; it has no `key: value` shape.
1015                self.bump();
1016            } else if self.at(Ident) && self.nth(1) == Eq {
1017                self.bump(); // key
1018                self.bump(); // =
1019                self.parse_expr();
1020            } else {
1021                self.parse_expr();
1022                if self.eat(Colon) {
1023                    self.parse_expr();
1024                } else if !self.in_pattern {
1025                    // A dictionary pattern may test for a key alone, as in
1026                    // `{"name", "age"}`.
1027                    self.error("expected `:` between the key and value");
1028                }
1029            }
1030            self.builder.finish_node();
1031            if !self.eat(Comma) {
1032                break;
1033            }
1034            self.ensure_progress(before, &[RBrace]);
1035        }
1036        self.expect(RBrace, "expected `}` to close the dictionary");
1037        self.leave_brackets();
1038        self.builder.finish_node();
1039    }
1040
1041    // -- Token plumbing -----------------------------------------------------
1042
1043    /// The next real token, without consuming anything.
1044    ///
1045    /// Lookahead deliberately does not emit the trivia it skips over. Trivia is
1046    /// emitted by [`Self::bump`], which means it lands inside whichever node
1047    /// owns the token that *follows* it — so a comment on its own line attaches
1048    /// to the declaration it documents rather than to the one above it.
1049    fn current(&self) -> SyntaxKind {
1050        self.nth(0)
1051    }
1052
1053    /// The `n`th upcoming non-trivia token, without emitting anything.
1054    fn nth(&self, n: usize) -> SyntaxKind {
1055        self.tokens[self.pos..]
1056            .iter()
1057            .filter(|token| !token.kind.is_trivia())
1058            .nth(n)
1059            .map_or(Eof, |token| token.kind)
1060    }
1061
1062    /// Source text of the next non-trivia token, for contextual keywords.
1063    fn current_text(&self) -> &str {
1064        self.nth_text(0)
1065    }
1066
1067    /// Source text of the `n`th upcoming non-trivia token.
1068    fn nth_text(&self, n: usize) -> &str {
1069        self.tokens[self.pos..]
1070            .iter()
1071            .filter(|token| !token.kind.is_trivia())
1072            .nth(n)
1073            .map_or("", |token| token.text(self.source))
1074    }
1075
1076    fn at(&self, kind: SyntaxKind) -> bool {
1077        self.current() == kind
1078    }
1079
1080    fn eat(&mut self, kind: SyntaxKind) -> bool {
1081        if self.at(kind) {
1082            self.bump();
1083            true
1084        } else {
1085            false
1086        }
1087    }
1088
1089    fn expect(&mut self, kind: SyntaxKind, message: &str) {
1090        if !self.eat(kind) {
1091            self.error(message);
1092        }
1093    }
1094
1095    /// Consume the current token into the tree.
1096    fn bump(&mut self) {
1097        self.skip_trivia();
1098        self.bump_raw();
1099    }
1100
1101    fn bump_raw(&mut self) {
1102        let token = self.tokens[self.pos];
1103        self.builder.token(token);
1104        if token.kind != Eof {
1105            self.pos += 1;
1106        }
1107    }
1108
1109    fn skip_trivia(&mut self) {
1110        while self.tokens[self.pos].kind.is_trivia() {
1111            self.bump_raw();
1112        }
1113    }
1114
1115    /// Whether a newline separates the cursor from the next real token.
1116    ///
1117    /// A line continuation is a distinct token kind, so `a \` followed by a
1118    /// newline correctly reports `false` here.
1119    fn newline_ahead(&self) -> bool {
1120        self.tokens[self.pos..]
1121            .iter()
1122            .take_while(|token| token.kind.is_trivia())
1123            .any(|token| token.kind == Newline)
1124    }
1125
1126    /// Whether the current position ends a logical line.
1127    ///
1128    /// Inside brackets a newline carries no meaning, which is what lets an
1129    /// array literal or a parenthesised expression span several lines.
1130    fn at_line_break(&self) -> bool {
1131        self.bracket_depth == 0 && self.newline_ahead()
1132    }
1133
1134    fn enter_brackets(&mut self) {
1135        self.bracket_depth += 1;
1136    }
1137
1138    fn leave_brackets(&mut self) {
1139        self.bracket_depth = self.bracket_depth.saturating_sub(1);
1140    }
1141
1142    fn at_statement_end(&self) -> bool {
1143        self.newline_ahead() || matches!(self.current(), Semicolon | Dedent | Eof)
1144    }
1145
1146    // -- Errors -------------------------------------------------------------
1147
1148    fn error(&mut self, message: &str) {
1149        // Point at the offending token, not at the trivia in front of it.
1150        let range = self.tokens[self.pos..]
1151            .iter()
1152            .find(|token| !token.kind.is_trivia())
1153            .map_or_else(|| self.tokens[self.pos].range, |token| token.range);
1154        // Collapse runs of errors at the same spot; they are almost always
1155        // cascades from the first one and only add noise.
1156        if self
1157            .errors
1158            .last()
1159            .is_some_and(|last| last.range().start() == range.start())
1160        {
1161            return;
1162        }
1163        self.errors
1164            .push(SyntaxError::new(TextRange::empty(range.start()), message));
1165    }
1166
1167    /// Record an error and skip tokens until something in `recovery` shows up.
1168    fn error_and_recover(&mut self, message: &str, recovery: &[SyntaxKind]) {
1169        self.error(message);
1170        self.builder.start_node(Error);
1171        // Always consume at least one token so the caller cannot spin.
1172        if !self.at(Eof) {
1173            self.bump();
1174        }
1175        while !self.at(Eof) && !recovery.contains(&self.current()) && !self.at(Dedent) {
1176            if self.newline_ahead() {
1177                break;
1178            }
1179            self.bump();
1180        }
1181        self.builder.finish_node();
1182    }
1183
1184    /// Backstop against a rule that returned without consuming anything.
1185    ///
1186    /// Every loop in the parser routes through here, so a grammar bug shows up
1187    /// as one stray Error node rather than a hang.
1188    fn ensure_progress(&mut self, before: usize, recovery: &[SyntaxKind]) {
1189        if self.pos != before {
1190            self.fuel = 0;
1191            return;
1192        }
1193        self.fuel += 1;
1194        if self.fuel > 1 {
1195            self.fuel = 0;
1196            self.error_and_recover("unexpected token", recovery);
1197        }
1198    }
1199}
1200
1201// -- Precedence -------------------------------------------------------------
1202
1203/// Binding power of the ternary `x if c else y`, the loosest operator.
1204const TERNARY_BP: u8 = 1;
1205/// Binding power of `as`, which sits just above the boolean operators.
1206const CAST_BP: u8 = 9;
1207/// Right binding power of the `not` / `!` prefix operator.
1208const NOT_BP: u8 = 7;
1209/// Right binding power of the arithmetic prefix operators.
1210const UNARY_BP: u8 = 27;
1211/// Binding powers of `not in`, matching plain `in`.
1212const NOT_IN_BP: (u8, u8) = (11, 12);
1213
1214/// Left and right binding powers for infix operators.
1215///
1216/// Ordering follows the GDScript reference: comparisons bind tighter than
1217/// `in`, which binds tighter than `is`, which binds tighter than `not`.
1218/// Right-associative operators get a right power below their left power.
1219fn infix_binding_power(kind: SyntaxKind) -> Option<(u8, u8)> {
1220    Some(match kind {
1221        OrKw | PipePipe => (3, 4),
1222        AndKw | AmpAmp => (5, 6),
1223        IsKw => (9, 10),
1224        InKw => (11, 12),
1225        Lt | LtEq | Gt | GtEq | EqEq | BangEq => (13, 14),
1226        Pipe => (15, 16),
1227        Caret => (17, 18),
1228        Amp => (19, 20),
1229        Shl | Shr => (21, 22),
1230        Plus | Minus => (23, 24),
1231        Star | Slash | Percent => (25, 26),
1232        // Right-associative and tighter than unary minus, so `-2 ** 2` is
1233        // `-(2 ** 2)`, matching Godot.
1234        StarStar => (30, 29),
1235        _ => return None,
1236    })
1237}
1238
1239fn is_assign_op(kind: SyntaxKind) -> bool {
1240    matches!(
1241        kind,
1242        Eq | PlusEq
1243            | MinusEq
1244            | StarEq
1245            | StarStarEq
1246            | SlashEq
1247            | PercentEq
1248            | AmpEq
1249            | PipeEq
1250            | CaretEq
1251            | ShlEq
1252            | ShrEq
1253    )
1254}