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_name("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_name("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_name("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_name() {
225            self.eat_name();
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_name("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_name("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_name("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) && (self.nth_is_name(1) || self.nth(1) == 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_name("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_name("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_name("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_name() {
487            self.error("expected a type name");
488            return;
489        }
490        self.eat_name();
491        while self.at(Dot) {
492            self.bump();
493            self.expect_name("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_name("expected a loop variable name");
677        if self.at(Colon) && (self.nth_is_name(1) || self.nth(1) == 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                    // `String.match()` is on the engine's API, so the couple
889                    // of keywords Godot still treats as names are accepted
890                    // here. See `SyntaxKind::is_name`.
891                    if self.at_name() {
892                        self.eat_name();
893                    } else {
894                        self.error("expected a member name after `.`");
895                    }
896                    self.builder.finish_node();
897                }
898                _ => break,
899            }
900        }
901    }
902
903    #[allow(clippy::too_many_lines)]
904    fn parse_atom(&mut self) {
905        match self.current() {
906            Int | Float | Str | StringName | NodePath | GetNode | UniqueNode | TrueKw | FalseKw
907            | NullKw => {
908                self.builder.start_node(Literal);
909                self.bump();
910                self.builder.finish_node();
911            }
912
913            Ident | SelfKw | SuperKw | MatchKw | WhenKw => {
914                self.builder.start_node(NameRef);
915                // `self` and `super` are themselves, not names.
916                if !self.eat_name() {
917                    self.bump();
918                }
919                self.builder.finish_node();
920            }
921
922            PreloadKw => {
923                self.builder.start_node(PreloadExpr);
924                self.bump();
925                if self.at(LParen) {
926                    self.parse_arg_list();
927                } else {
928                    self.error("expected `(` after `preload`");
929                }
930                self.builder.finish_node();
931            }
932
933            LParen => {
934                self.builder.start_node(ParenExpr);
935                self.bump();
936                self.enter_brackets();
937                if !self.at(RParen) {
938                    self.parse_expr();
939                }
940                self.expect(RParen, "expected `)` to close the group");
941                self.leave_brackets();
942                self.builder.finish_node();
943            }
944
945            LBracket => {
946                self.builder.start_node(ArrayExpr);
947                self.bump();
948                self.enter_brackets();
949                while !self.at(RBracket) && !self.at(Eof) {
950                    let before = self.pos;
951                    self.parse_expr();
952                    if !self.eat(Comma) {
953                        break;
954                    }
955                    self.ensure_progress(before, &[RBracket]);
956                }
957                self.expect(RBracket, "expected `]` to close the array");
958                self.leave_brackets();
959                self.builder.finish_node();
960            }
961
962            LBrace => self.parse_dict(),
963
964            // `var name` binds a capture inside a match pattern.
965            VarKw if self.in_pattern => {
966                self.builder.start_node(NameRef);
967                self.bump();
968                self.expect_name("expected a name after `var` in a pattern");
969                self.builder.finish_node();
970            }
971
972            // `..` matches whatever is left of an array or dictionary pattern.
973            DotDot if self.in_pattern => {
974                self.builder.start_node(Literal);
975                self.bump();
976                self.builder.finish_node();
977            }
978
979            // A lambda: `func(a): ...` or `func named(a): ...`
980            FuncKw => {
981                self.builder.start_node(LambdaExpr);
982                self.bump();
983                if self.at_name() {
984                    self.eat_name();
985                }
986                if self.at(LParen) {
987                    self.parse_param_list();
988                } else {
989                    self.error("expected `(` to open the lambda parameters");
990                }
991                if self.at(Arrow) {
992                    self.builder.start_node(ReturnType);
993                    self.bump();
994                    self.parse_type();
995                    self.builder.finish_node();
996                }
997                if self.eat(Colon) {
998                    self.parse_block();
999                } else {
1000                    self.error("expected `:` to open the lambda body");
1001                }
1002                self.builder.finish_node();
1003            }
1004
1005            _ => self.error_and_recover("expected an expression", STATEMENT_START),
1006        }
1007    }
1008
1009    /// `{"key": value}` and the Lua-style `{key = value}`.
1010    fn parse_dict(&mut self) {
1011        self.builder.start_node(DictExpr);
1012        self.bump(); // {
1013        self.enter_brackets();
1014        while !self.at(RBrace) && !self.at(Eof) {
1015            let before = self.pos;
1016            self.builder.start_node(DictEntry);
1017            if self.in_pattern && self.at(DotDot) {
1018                // A rest marker stands alone; it has no `key: value` shape.
1019                self.bump();
1020            } else if self.at_name() && self.nth(1) == Eq {
1021                self.bump(); // key
1022                self.bump(); // =
1023                self.parse_expr();
1024            } else {
1025                self.parse_expr();
1026                if self.eat(Colon) {
1027                    self.parse_expr();
1028                } else if !self.in_pattern {
1029                    // A dictionary pattern may test for a key alone, as in
1030                    // `{"name", "age"}`.
1031                    self.error("expected `:` between the key and value");
1032                }
1033            }
1034            self.builder.finish_node();
1035            if !self.eat(Comma) {
1036                break;
1037            }
1038            self.ensure_progress(before, &[RBrace]);
1039        }
1040        self.expect(RBrace, "expected `}` to close the dictionary");
1041        self.leave_brackets();
1042        self.builder.finish_node();
1043    }
1044
1045    // -- Token plumbing -----------------------------------------------------
1046
1047    /// The next real token, without consuming anything.
1048    ///
1049    /// Lookahead deliberately does not emit the trivia it skips over. Trivia is
1050    /// emitted by [`Self::bump`], which means it lands inside whichever node
1051    /// owns the token that *follows* it — so a comment on its own line attaches
1052    /// to the declaration it documents rather than to the one above it.
1053    fn current(&self) -> SyntaxKind {
1054        self.nth(0)
1055    }
1056
1057    /// The `n`th upcoming non-trivia token, without emitting anything.
1058    fn nth(&self, n: usize) -> SyntaxKind {
1059        self.tokens[self.pos..]
1060            .iter()
1061            .filter(|token| !token.kind.is_trivia())
1062            .nth(n)
1063            .map_or(Eof, |token| token.kind)
1064    }
1065
1066    /// Source text of the next non-trivia token, for contextual keywords.
1067    fn current_text(&self) -> &str {
1068        self.nth_text(0)
1069    }
1070
1071    /// Source text of the `n`th upcoming non-trivia token.
1072    fn nth_text(&self, n: usize) -> &str {
1073        self.tokens[self.pos..]
1074            .iter()
1075            .filter(|token| !token.kind.is_trivia())
1076            .nth(n)
1077            .map_or("", |token| token.text(self.source))
1078    }
1079
1080    fn at(&self, kind: SyntaxKind) -> bool {
1081        self.current() == kind
1082    }
1083
1084    fn eat(&mut self, kind: SyntaxKind) -> bool {
1085        if self.at(kind) {
1086            self.bump();
1087            true
1088        } else {
1089            false
1090        }
1091    }
1092
1093    fn expect(&mut self, kind: SyntaxKind, message: &str) {
1094        if !self.eat(kind) {
1095            self.error(message);
1096        }
1097    }
1098
1099    /// Whether the current token can serve as a name.
1100    ///
1101    /// See [`SyntaxKind::is_name`]: a couple of keywords can, because Godot
1102    /// accepts them there and real code relies on it.
1103    fn at_name(&self) -> bool {
1104        self.current().is_name()
1105    }
1106
1107    /// Like [`Self::at_name`], for a token further along.
1108    fn nth_is_name(&self, n: usize) -> bool {
1109        self.nth(n).is_name()
1110    }
1111
1112    /// Consume a name, recording a contextual keyword as the identifier it is
1113    /// being used as.
1114    fn eat_name(&mut self) -> bool {
1115        if !self.at_name() {
1116            return false;
1117        }
1118        self.skip_trivia();
1119        let mut token = self.tokens[self.pos];
1120        token.kind = Ident;
1121        self.builder.token(token);
1122        if self.tokens[self.pos].kind != Eof {
1123            self.pos += 1;
1124        }
1125        true
1126    }
1127
1128    fn expect_name(&mut self, message: &str) {
1129        if !self.eat_name() {
1130            self.error(message);
1131        }
1132    }
1133
1134    /// Consume the current token into the tree.
1135    fn bump(&mut self) {
1136        self.skip_trivia();
1137        self.bump_raw();
1138    }
1139
1140    fn bump_raw(&mut self) {
1141        let token = self.tokens[self.pos];
1142        self.builder.token(token);
1143        if token.kind != Eof {
1144            self.pos += 1;
1145        }
1146    }
1147
1148    fn skip_trivia(&mut self) {
1149        while self.tokens[self.pos].kind.is_trivia() {
1150            self.bump_raw();
1151        }
1152    }
1153
1154    /// Whether a newline separates the cursor from the next real token.
1155    ///
1156    /// A line continuation is a distinct token kind, so `a \` followed by a
1157    /// newline correctly reports `false` here.
1158    fn newline_ahead(&self) -> bool {
1159        self.tokens[self.pos..]
1160            .iter()
1161            .take_while(|token| token.kind.is_trivia())
1162            .any(|token| token.kind == Newline)
1163    }
1164
1165    /// Whether the current position ends a logical line.
1166    ///
1167    /// Inside brackets a newline carries no meaning, which is what lets an
1168    /// array literal or a parenthesised expression span several lines.
1169    fn at_line_break(&self) -> bool {
1170        self.bracket_depth == 0 && self.newline_ahead()
1171    }
1172
1173    fn enter_brackets(&mut self) {
1174        self.bracket_depth += 1;
1175    }
1176
1177    fn leave_brackets(&mut self) {
1178        self.bracket_depth = self.bracket_depth.saturating_sub(1);
1179    }
1180
1181    fn at_statement_end(&self) -> bool {
1182        self.newline_ahead() || matches!(self.current(), Semicolon | Dedent | Eof)
1183    }
1184
1185    // -- Errors -------------------------------------------------------------
1186
1187    fn error(&mut self, message: &str) {
1188        // Point at the offending token, not at the trivia in front of it.
1189        let range = self.tokens[self.pos..]
1190            .iter()
1191            .find(|token| !token.kind.is_trivia())
1192            .map_or_else(|| self.tokens[self.pos].range, |token| token.range);
1193        // Collapse runs of errors at the same spot; they are almost always
1194        // cascades from the first one and only add noise.
1195        if self
1196            .errors
1197            .last()
1198            .is_some_and(|last| last.range().start() == range.start())
1199        {
1200            return;
1201        }
1202        self.errors
1203            .push(SyntaxError::new(TextRange::empty(range.start()), message));
1204    }
1205
1206    /// Record an error and skip tokens until something in `recovery` shows up.
1207    fn error_and_recover(&mut self, message: &str, recovery: &[SyntaxKind]) {
1208        self.error(message);
1209        self.builder.start_node(Error);
1210        // Always consume at least one token so the caller cannot spin.
1211        if !self.at(Eof) {
1212            self.bump();
1213        }
1214        while !self.at(Eof) && !recovery.contains(&self.current()) && !self.at(Dedent) {
1215            if self.newline_ahead() {
1216                break;
1217            }
1218            self.bump();
1219        }
1220        self.builder.finish_node();
1221    }
1222
1223    /// Backstop against a rule that returned without consuming anything.
1224    ///
1225    /// Every loop in the parser routes through here, so a grammar bug shows up
1226    /// as one stray Error node rather than a hang.
1227    fn ensure_progress(&mut self, before: usize, recovery: &[SyntaxKind]) {
1228        if self.pos != before {
1229            self.fuel = 0;
1230            return;
1231        }
1232        self.fuel += 1;
1233        if self.fuel > 1 {
1234            self.fuel = 0;
1235            self.error_and_recover("unexpected token", recovery);
1236        }
1237    }
1238}
1239
1240// -- Precedence -------------------------------------------------------------
1241
1242/// Binding power of the ternary `x if c else y`, the loosest operator.
1243const TERNARY_BP: u8 = 1;
1244/// Binding power of `as`, which sits just above the boolean operators.
1245const CAST_BP: u8 = 9;
1246/// Right binding power of the `not` / `!` prefix operator.
1247const NOT_BP: u8 = 7;
1248/// Right binding power of the arithmetic prefix operators.
1249const UNARY_BP: u8 = 27;
1250/// Binding powers of `not in`, matching plain `in`.
1251const NOT_IN_BP: (u8, u8) = (11, 12);
1252
1253/// Left and right binding powers for infix operators.
1254///
1255/// Ordering follows the GDScript reference: comparisons bind tighter than
1256/// `in`, which binds tighter than `is`, which binds tighter than `not`.
1257/// Right-associative operators get a right power below their left power.
1258fn infix_binding_power(kind: SyntaxKind) -> Option<(u8, u8)> {
1259    Some(match kind {
1260        OrKw | PipePipe => (3, 4),
1261        AndKw | AmpAmp => (5, 6),
1262        IsKw => (9, 10),
1263        InKw => (11, 12),
1264        Lt | LtEq | Gt | GtEq | EqEq | BangEq => (13, 14),
1265        Pipe => (15, 16),
1266        Caret => (17, 18),
1267        Amp => (19, 20),
1268        Shl | Shr => (21, 22),
1269        Plus | Minus => (23, 24),
1270        Star | Slash | Percent => (25, 26),
1271        // Right-associative and tighter than unary minus, so `-2 ** 2` is
1272        // `-(2 ** 2)`, matching Godot.
1273        StarStar => (30, 29),
1274        _ => return None,
1275    })
1276}
1277
1278fn is_assign_op(kind: SyntaxKind) -> bool {
1279    matches!(
1280        kind,
1281        Eq | PlusEq
1282            | MinusEq
1283            | StarEq
1284            | StarStarEq
1285            | SlashEq
1286            | PercentEq
1287            | AmpEq
1288            | PipeEq
1289            | CaretEq
1290            | ShlEq
1291            | ShrEq
1292    )
1293}