Skip to main content

tsz_parser/parser/
state_statements.rs

1//! Parser state - statement and declaration parsing methods
2use super::state::{
3    CONTEXT_FLAG_ASYNC, CONTEXT_FLAG_GENERATOR, CONTEXT_FLAG_IN_BLOCK,
4    CONTEXT_FLAG_PARAMETER_DEFAULT, IncrementalParseResult, ParserState,
5};
6use crate::parser::{
7    NodeIndex, NodeList,
8    node::{
9        BlockData, FunctionData, ImportDeclData, LabeledData, QualifiedNameData, SourceFileData,
10        VariableData, VariableDeclarationData,
11    },
12    parse_rules::{
13        is_identifier_or_keyword, look_ahead_is, look_ahead_is_abstract_declaration,
14        look_ahead_is_async_declaration, look_ahead_is_const_enum, look_ahead_is_import_call,
15        look_ahead_is_import_equals, look_ahead_is_module_declaration,
16        look_ahead_is_type_alias_declaration,
17    },
18    syntax_kind_ext,
19};
20use tsz_common::diagnostics::diagnostic_codes;
21use tsz_scanner::SyntaxKind;
22
23impl ParserState {
24    // =========================================================================
25    // Parse Methods - Core Expressions
26    // =========================================================================
27
28    /// Parse a source file
29    pub fn parse_source_file(&mut self) -> NodeIndex {
30        let start_pos = 0u32;
31
32        // Skip shebang (#!) if present at start of file
33        self.scanner.scan_shebang_trivia();
34
35        // Initialize scanner
36        self.next_token();
37
38        // Parse statements (using source file version that handles stray braces)
39        let statements = self.parse_source_file_statements();
40
41        // Cache comment ranges once during parsing (O(N) scan, done only once)
42        // This avoids rescanning on every hover/documentation request
43        // Use scanner's source text (no duplicate allocation)
44        let comments = tsz_common::comments::get_comment_ranges(self.scanner.source_text());
45
46        // Collect scanner-level diagnostics (e.g., conflict markers TS1185) into
47        // parse diagnostics so they appear in the final diagnostic output.
48        for diag in self.scanner.get_scanner_diagnostics() {
49            self.parse_diagnostics.push(super::state::ParseDiagnostic {
50                start: self.u32_from_usize(diag.pos),
51                length: self.u32_from_usize(diag.length),
52                message: diag.message.to_string(),
53                code: diag.code,
54            });
55        }
56        // Sort diagnostics by position to maintain correct order after merging
57        self.parse_diagnostics.sort_by_key(|d| d.start);
58
59        // Create source file node
60        let end_pos = self.token_end();
61        let eof_token = self
62            .arena
63            .add_token(SyntaxKind::EndOfFileToken as u16, end_pos, end_pos);
64
65        // Transfer the scanner's string interner to the arena so that atom-based
66        // identifier text resolution works via get_arena() (not just into_arena()).
67        // This is essential for LSP features that resolve identifier references.
68        self.arena.set_interner(self.scanner.interner().clone());
69
70        self.arena.add_source_file(
71            start_pos,
72            end_pos,
73            SourceFileData {
74                statements,
75                end_of_file_token: eof_token,
76                file_name: self.file_name.clone(),
77                text: self.scanner.source_text_arc(),
78                language_version: 99,
79                language_variant: 0,
80                script_kind: 3,
81                is_declaration_file: false,
82                has_no_default_lib: false,
83                comments, // Cached comment ranges
84                parent: NodeIndex::NONE,
85                id: 0,
86                modifier_flags: 0,
87                transform_flags: 0,
88            },
89        )
90    }
91
92    pub fn parse_source_file_statements_from_offset(
93        &mut self,
94        file_name: String,
95        source_text: String,
96        start: u32,
97    ) -> IncrementalParseResult {
98        let start = usize::min(start as usize, source_text.len());
99        let reparse_start = self.u32_from_usize(start);
100
101        self.file_name = file_name;
102        self.scanner.set_text(source_text, Some(start), None);
103        self.context_flags = 0;
104        self.current_token = SyntaxKind::Unknown;
105        self.parse_diagnostics.clear();
106        self.recursion_depth = 0;
107
108        self.next_token();
109        let statements = self.parse_source_file_statements();
110        let end_pos = self.token_end();
111        let eof_token = self
112            .arena
113            .add_token(SyntaxKind::EndOfFileToken as u16, end_pos, end_pos);
114
115        IncrementalParseResult {
116            statements,
117            end_pos,
118            end_of_file_token: eof_token,
119            reparse_start,
120        }
121    }
122
123    /// Parse list of statements for a source file (top-level).
124    /// Reports error 1128 for unexpected closing braces.
125    /// Uses resynchronization to recover from errors and continue parsing.
126    pub(crate) fn parse_source_file_statements(&mut self) -> NodeList {
127        let mut statements = Vec::new();
128        let mut skip_after_binary_payload = false;
129
130        while !self.is_token(SyntaxKind::EndOfFileToken) {
131            let pos_before = self.token_pos();
132            if skip_after_binary_payload {
133                break;
134            }
135
136            // Handle Unknown tokens (invalid characters) - must be checked FIRST
137            if self.is_token(SyntaxKind::Unknown) {
138                use tsz_common::diagnostics::diagnostic_codes;
139                self.parse_error_at_current_token(
140                    "Invalid character.",
141                    diagnostic_codes::INVALID_CHARACTER,
142                );
143                self.resync_after_error_with_statement_starts(false);
144                continue;
145            }
146
147            // If we see a closing brace at the top level, report error 1128
148            if self.is_token(SyntaxKind::CloseBraceToken) {
149                // Only emit error if we haven't already emitted one at this position
150                if self.token_pos() != self.last_error_pos {
151                    use tsz_common::diagnostics::diagnostic_codes;
152                    self.parse_error_at_current_token(
153                        "Declaration or statement expected.",
154                        diagnostic_codes::DECLARATION_OR_STATEMENT_EXPECTED,
155                    );
156                }
157                self.next_token();
158                // Resync to next statement boundary
159                self.resync_after_error();
160                continue;
161            }
162
163            if self.is_token(SyntaxKind::AtToken) {
164                let snapshot = self.scanner.save_state();
165                let at_token = self.current_token;
166                self.next_token();
167                if self.is_token(SyntaxKind::Unknown) {
168                    self.current_token = at_token;
169                    self.next_token();
170                    self.parse_error_at_current_token(
171                        "Invalid character.",
172                        tsz_common::diagnostics::diagnostic_codes::INVALID_CHARACTER,
173                    );
174
175                    self.next_token();
176                    if !self.is_token(SyntaxKind::EndOfFileToken) {
177                        self.parse_error_at_current_token(
178                            "Declaration or statement expected.",
179                            tsz_common::diagnostics::diagnostic_codes::DECLARATION_OR_STATEMENT_EXPECTED,
180                        );
181                    }
182
183                    skip_after_binary_payload = true;
184                    continue;
185                }
186                self.scanner.restore_state(snapshot);
187                self.current_token = at_token;
188            }
189
190            let statement_start_token = self.token();
191            let stmt = self.parse_statement();
192            if stmt.is_none() {
193                // Statement parsing failed, resync to recover
194                // Suppress cascading errors when a recent error was within 3 chars
195                let current = self.token_pos();
196                if (self.last_error_pos == 0 || current.abs_diff(self.last_error_pos) > 3)
197                    && !self.is_token(SyntaxKind::EndOfFileToken)
198                {
199                    use tsz_common::diagnostics::diagnostic_codes;
200                    self.parse_error_at_current_token(
201                        "Declaration or statement expected.",
202                        diagnostic_codes::DECLARATION_OR_STATEMENT_EXPECTED,
203                    );
204                }
205                // Resync to next statement boundary to continue parsing
206                let allow_statement_starts = if statement_start_token == SyntaxKind::AtToken {
207                    false
208                } else {
209                    !self.is_statement_start()
210                };
211                self.resync_after_error_with_statement_starts(allow_statement_starts);
212            } else {
213                statements.push(stmt);
214            }
215
216            // Safety: if position didn't advance, force-skip the current token
217            // to prevent infinite loop when resync returns at a sync point
218            // that parse_statement can't handle
219            if self.token_pos() == pos_before && !self.is_token(SyntaxKind::EndOfFileToken) {
220                self.next_token();
221            }
222        }
223
224        self.make_node_list(statements)
225    }
226
227    /// Parse list of statements (for blocks, function bodies, etc.).
228    /// Stops at closing brace without error (closing brace is expected).
229    /// Uses resynchronization to recover from errors and continue parsing.
230    pub(crate) fn parse_statements(&mut self) -> NodeList {
231        let mut statements = Vec::new();
232
233        while !self.is_token(SyntaxKind::EndOfFileToken)
234            && !self.is_token(SyntaxKind::CloseBraceToken)
235        {
236            let pos_before = self.token_pos();
237
238            // Error recovery: when inside a nested block within a class body (e.g.,
239            // a method body with an unclosed `{`), terminate the block if we encounter
240            // a class member modifier followed by an identifier on the same line. This
241            // matches TSC's "abort parsing list" behavior: tokens that could start a
242            // class member in an outer context cause the inner block list to terminate
243            // rather than consuming tokens that belong to the class body.
244            if self.in_block_context()
245                && self.in_class_body()
246                && matches!(
247                    self.token(),
248                    SyntaxKind::PublicKeyword
249                        | SyntaxKind::PrivateKeyword
250                        | SyntaxKind::ProtectedKeyword
251                        | SyntaxKind::StaticKeyword
252                        | SyntaxKind::AbstractKeyword
253                        | SyntaxKind::ReadonlyKeyword
254                        | SyntaxKind::OverrideKeyword
255                        | SyntaxKind::AccessorKeyword
256                )
257                && self.look_ahead_next_is_identifier_or_keyword_on_same_line()
258            {
259                use tsz_common::diagnostics::diagnostic_codes;
260                self.parse_error_at_current_token(
261                    "Declaration or statement expected.",
262                    diagnostic_codes::DECLARATION_OR_STATEMENT_EXPECTED,
263                );
264                break;
265            }
266
267            // Handle Unknown tokens (invalid characters)
268            if self.is_token(SyntaxKind::Unknown) {
269                use tsz_common::diagnostics::diagnostic_codes;
270                self.parse_error_at_current_token(
271                    "Invalid character.",
272                    diagnostic_codes::INVALID_CHARACTER,
273                );
274                self.resync_after_error_with_statement_starts(false);
275                continue;
276            }
277
278            let statement_start_token = self.token();
279            let stmt = self.parse_statement();
280            if stmt.is_none() {
281                // Statement parsing failed, resync to recover
282                // Emit error if we haven't already at the exact same position
283                // Suppress cascading errors when a recent error was within 3 chars
284                let current = self.token_pos();
285                if (self.last_error_pos == 0 || current.abs_diff(self.last_error_pos) > 3)
286                    && !self.is_token(SyntaxKind::EndOfFileToken)
287                {
288                    use tsz_common::diagnostics::diagnostic_codes;
289                    self.parse_error_at_current_token(
290                        "Declaration or statement expected.",
291                        diagnostic_codes::DECLARATION_OR_STATEMENT_EXPECTED,
292                    );
293                }
294                // Resync to next statement boundary to continue parsing
295                let allow_statement_starts = if statement_start_token == SyntaxKind::AtToken {
296                    false
297                } else {
298                    !self.is_statement_start()
299                };
300                self.resync_after_error_with_statement_starts(allow_statement_starts);
301            } else {
302                statements.push(stmt);
303            }
304
305            // Safety: if position didn't advance, force-skip the current token
306            // to prevent infinite loop when resync returns at a sync point
307            // that parse_statement can't handle
308            if self.token_pos() == pos_before
309                && !self.is_token(SyntaxKind::EndOfFileToken)
310                && !self.is_token(SyntaxKind::CloseBraceToken)
311            {
312                self.next_token();
313            }
314        }
315
316        self.make_node_list(statements)
317    }
318
319    /// Parse a statement
320    pub fn parse_statement(&mut self) -> NodeIndex {
321        match self.token() {
322            SyntaxKind::OpenBraceToken => self.parse_block(),
323            SyntaxKind::VarKeyword | SyntaxKind::UsingKeyword => self.parse_variable_statement(),
324            SyntaxKind::LetKeyword => {
325                // In strict mode (modules, classes, etc.), `let` is a reserved word and
326                // cannot be used as an identifier. But `let;` or `let` followed by a
327                // non-declaration-start token should NOT be parsed as a variable declaration.
328                // tsc checks `isLetDeclaration()`: next token must be identifier, `{`, or `[`.
329                if self.look_ahead_is_let_declaration() {
330                    self.parse_variable_statement()
331                } else {
332                    self.parse_expression_statement()
333                }
334            }
335            SyntaxKind::ConstKeyword => {
336                // const enum or const variable
337                if self.look_ahead_is_const_enum() {
338                    let start_pos = self.token_pos();
339                    self.parse_const_enum_declaration(start_pos, Vec::new())
340                } else {
341                    self.parse_variable_statement()
342                }
343            }
344            SyntaxKind::FunctionKeyword => self.parse_function_declaration(),
345            SyntaxKind::AsyncKeyword => self.parse_statement_async_declaration_or_expression(),
346            SyntaxKind::AwaitKeyword => {
347                // await using declaration (ES2022)
348                // Look ahead to see if it's "await using"
349                if self.look_ahead_is_await_using() {
350                    self.parse_variable_statement()
351                } else {
352                    self.parse_expression_statement()
353                }
354            }
355            SyntaxKind::AtToken => {
356                // Decorator: @decorator class/function
357                self.parse_decorated_declaration()
358            }
359            SyntaxKind::ClassKeyword => self.parse_class_declaration(),
360            SyntaxKind::AbstractKeyword => self.parse_statement_abstract_keyword(),
361            SyntaxKind::AccessorKeyword => self.parse_statement_accessor_keyword(),
362            // Modifier keywords used before declarations at top level
363            // e.g., `public interface I {}`, `protected class C {}`, `static class C {}`
364            // These should emit TS1044 and then parse the declaration
365            SyntaxKind::StaticKeyword
366            | SyntaxKind::PublicKeyword
367            | SyntaxKind::ProtectedKeyword
368            | SyntaxKind::PrivateKeyword
369            | SyntaxKind::OverrideKeyword
370            | SyntaxKind::ReadonlyKeyword => self.parse_statement_top_level_modifier(),
371            SyntaxKind::DefaultKeyword => {
372                // 'default' is only valid after 'export': emit TS1005 "'export' expected"
373                self.parse_error_at_current_token("'export' expected.", diagnostic_codes::EXPECTED);
374                self.next_token();
375                self.parse_statement()
376            }
377            SyntaxKind::InterfaceKeyword => {
378                // ASI: `interface\nI {}` should be parsed as expression statement
379                // 'interface' followed by identifier 'I', not InterfaceDeclaration.
380                if self.look_ahead_next_is_identifier_or_keyword_on_same_line() {
381                    self.parse_interface_declaration()
382                } else {
383                    self.parse_expression_statement()
384                }
385            }
386            SyntaxKind::TypeKeyword => self.parse_statement_type_keyword(),
387            SyntaxKind::EnumKeyword => self.parse_enum_declaration(),
388            SyntaxKind::DeclareKeyword => {
389                if self.in_block_context() && self.look_ahead_is_declare_before_declaration() {
390                    self.parse_error_at_current_token(
391                        "Modifiers cannot appear here.",
392                        diagnostic_codes::MODIFIERS_CANNOT_APPEAR_HERE,
393                    );
394                }
395                self.parse_statement_declare_or_expression()
396            }
397            SyntaxKind::NamespaceKeyword
398            | SyntaxKind::ModuleKeyword
399            | SyntaxKind::GlobalKeyword => self.parse_statement_namespace_or_expression(),
400            SyntaxKind::IfKeyword => self.parse_if_statement(),
401            SyntaxKind::ReturnKeyword => self.parse_return_statement(),
402            SyntaxKind::WhileKeyword => self.parse_while_statement(),
403            SyntaxKind::ForKeyword => self.parse_for_statement(),
404            SyntaxKind::SemicolonToken => self.parse_empty_statement(),
405            SyntaxKind::ExportKeyword => {
406                // Keep parity with tsc recovery for malformed `export =` in blocks:
407                // prefer the parse error from export assignment over generic TS1184.
408                if self.in_block_context() && !self.look_ahead_is_export_assignment() {
409                    self.parse_error_at_current_token(
410                        "Modifiers cannot appear here.",
411                        diagnostic_codes::MODIFIERS_CANNOT_APPEAR_HERE,
412                    );
413                }
414                self.parse_export_declaration()
415            }
416            SyntaxKind::ImportKeyword => self.parse_statement_import_keyword(),
417            SyntaxKind::BreakKeyword => self.parse_break_statement(),
418            SyntaxKind::ContinueKeyword => self.parse_continue_statement(),
419            SyntaxKind::ThrowKeyword => self.parse_throw_statement(),
420            SyntaxKind::DoKeyword => self.parse_do_statement(),
421            SyntaxKind::SwitchKeyword => self.parse_switch_statement(),
422            SyntaxKind::TryKeyword | SyntaxKind::CatchKeyword | SyntaxKind::FinallyKeyword => {
423                self.parse_try_statement()
424            }
425            SyntaxKind::WithKeyword => self.parse_with_statement(),
426            SyntaxKind::DebuggerKeyword => self.parse_debugger_statement(),
427            SyntaxKind::Identifier => {
428                // Check for labeled statement: label: statement
429                if self.look_ahead_is_labeled_statement() {
430                    self.parse_labeled_statement()
431                } else {
432                    self.parse_expression_statement()
433                }
434            }
435            _ => {
436                // Check for labeled statement with keyword as label (e.g., await: if (...))
437                // TypeScript/JavaScript allow reserved keywords as labels
438                // This enables: await: ..., arguments: ..., eval: ..., etc.
439                if self.is_identifier_or_keyword() && self.look_ahead_is_labeled_statement() {
440                    self.parse_labeled_statement()
441                } else {
442                    self.parse_expression_statement()
443                }
444            }
445        }
446    }
447
448    fn parse_statement_async_declaration_or_expression(&mut self) -> NodeIndex {
449        if self.look_ahead_is_async_function() {
450            self.parse_async_function_declaration()
451        } else if self.look_ahead_is_async_declaration() {
452            let start_pos = self.token_pos();
453            let async_start = self.token_pos();
454            self.parse_expected(SyntaxKind::AsyncKeyword);
455            let async_end = self.token_end();
456            let async_modifier =
457                self.arena
458                    .add_token(SyntaxKind::AsyncKeyword as u16, async_start, async_end);
459            let modifiers = Some(self.make_node_list(vec![async_modifier]));
460            match self.token() {
461                SyntaxKind::ClassKeyword => {
462                    self.parse_class_declaration_with_modifiers(start_pos, modifiers)
463                }
464                SyntaxKind::EnumKeyword => {
465                    self.parse_enum_declaration_with_modifiers(start_pos, modifiers)
466                }
467                SyntaxKind::InterfaceKeyword => {
468                    self.parse_interface_declaration_with_modifiers(start_pos, modifiers)
469                }
470                SyntaxKind::NamespaceKeyword
471                | SyntaxKind::ModuleKeyword
472                | SyntaxKind::GlobalKeyword => {
473                    if self.look_ahead_is_module_declaration() {
474                        self.parse_module_declaration_with_modifiers(start_pos, modifiers)
475                    } else {
476                        self.parse_expression_statement()
477                    }
478                }
479                _ => self.parse_expression_statement(),
480            }
481        } else {
482            self.parse_expression_statement()
483        }
484    }
485
486    fn parse_statement_abstract_keyword(&mut self) -> NodeIndex {
487        if self.next_token_is_on_new_line() {
488            self.parse_expression_statement()
489        } else if self.look_ahead_is_abstract_class() {
490            self.parse_abstract_class_declaration()
491        } else if self.look_ahead_is_abstract_declaration() {
492            use tsz_common::diagnostics::diagnostic_codes;
493            self.parse_error_at_current_token(
494                "Modifiers cannot appear here.",
495                diagnostic_codes::MODIFIERS_CANNOT_APPEAR_HERE,
496            );
497            self.next_token();
498            match self.token() {
499                SyntaxKind::InterfaceKeyword => self.parse_interface_declaration(),
500                SyntaxKind::EnumKeyword => self.parse_enum_declaration(),
501                SyntaxKind::NamespaceKeyword
502                | SyntaxKind::ModuleKeyword
503                | SyntaxKind::GlobalKeyword => {
504                    if self.look_ahead_is_module_declaration() {
505                        self.parse_module_declaration()
506                    } else {
507                        self.parse_expression_statement()
508                    }
509                }
510                _ => self.parse_expression_statement(),
511            }
512        } else {
513            self.parse_expression_statement()
514        }
515    }
516
517    fn parse_statement_accessor_keyword(&mut self) -> NodeIndex {
518        if self.look_ahead_is_accessor_declaration() {
519            use tsz_common::diagnostics::diagnostic_codes;
520            self.parse_error_at_current_token(
521                "Modifiers cannot appear here.",
522                diagnostic_codes::MODIFIERS_CANNOT_APPEAR_HERE,
523            );
524            self.next_token();
525            self.parse_statement()
526        } else {
527            self.parse_expression_statement()
528        }
529    }
530
531    fn parse_statement_top_level_modifier(&mut self) -> NodeIndex {
532        use tsz_common::diagnostics::diagnostic_codes;
533
534        if self.next_token_is_on_new_line() {
535            self.parse_expression_statement()
536        } else if self.look_ahead_is_modifier_before_declaration() {
537            // TS1044: '{0}' modifier cannot appear on a module or namespace element.
538            let modifier_text = self.scanner.get_token_text();
539            self.parse_error_at_current_token(
540                &format!(
541                    "'{modifier_text}' modifier cannot appear on a module or namespace element."
542                ),
543                diagnostic_codes::MODIFIER_CANNOT_APPEAR_ON_A_MODULE_OR_NAMESPACE_ELEMENT,
544            );
545            self.next_token();
546            self.parse_statement()
547        } else if self.look_ahead_next_is_identifier_or_keyword_on_same_line() {
548            self.parse_error_at_current_token(
549                "Declaration or statement expected.",
550                diagnostic_codes::DECLARATION_OR_STATEMENT_EXPECTED,
551            );
552            self.next_token();
553            let diag_count = self.parse_diagnostics.len();
554            let result = self.parse_statement();
555            let mut i = diag_count;
556            while i < self.parse_diagnostics.len() {
557                if self.parse_diagnostics[i].code == diagnostic_codes::EXPECTED {
558                    self.parse_diagnostics.remove(i);
559                } else {
560                    i += 1;
561                }
562            }
563            result
564        } else {
565            self.parse_expression_statement()
566        }
567    }
568
569    fn parse_statement_type_keyword(&mut self) -> NodeIndex {
570        if self.look_ahead_is_type_alias_declaration() {
571            self.parse_type_alias_declaration()
572        } else {
573            self.parse_expression_statement()
574        }
575    }
576
577    fn parse_statement_declare_or_expression(&mut self) -> NodeIndex {
578        // `declare` is a contextual keyword — it can be used as an identifier.
579        // Only parse as ambient declaration if the next token is a valid declaration keyword.
580        if self.look_ahead_is_declare_before_declaration() {
581            self.parse_ambient_declaration()
582        } else {
583            self.parse_expression_statement()
584        }
585    }
586
587    fn parse_statement_namespace_or_expression(&mut self) -> NodeIndex {
588        if self.look_ahead_is_module_declaration() {
589            self.parse_module_declaration()
590        } else {
591            self.parse_expression_statement()
592        }
593    }
594
595    fn parse_statement_import_keyword(&mut self) -> NodeIndex {
596        if self.look_ahead_is_import_call() {
597            self.parse_expression_statement()
598        } else if self.look_ahead_is_import_equals() {
599            self.parse_import_equals_declaration()
600        } else {
601            self.parse_import_declaration()
602        }
603    }
604
605    /// Look ahead to see if a modifier keyword (public, protected, private, static, etc.)
606    /// is followed by a declaration keyword like class, interface, function, etc.
607    /// Used to detect `public interface I {}` or `static class C {}` patterns at module level.
608    pub(crate) fn look_ahead_is_modifier_before_declaration(&mut self) -> bool {
609        let snapshot = self.scanner.save_state();
610        let current = self.current_token;
611
612        self.next_token(); // skip the modifier keyword
613        let is_decl = matches!(
614            self.token(),
615            SyntaxKind::ClassKeyword
616                | SyntaxKind::InterfaceKeyword
617                | SyntaxKind::EnumKeyword
618                | SyntaxKind::NamespaceKeyword
619                | SyntaxKind::ModuleKeyword
620                | SyntaxKind::FunctionKeyword
621                | SyntaxKind::AbstractKeyword
622                | SyntaxKind::ConstKeyword
623                | SyntaxKind::VarKeyword
624                | SyntaxKind::LetKeyword
625                | SyntaxKind::TypeKeyword
626        );
627
628        self.scanner.restore_state(snapshot);
629        self.current_token = current;
630        is_decl
631    }
632
633    /// Check if `declare` is followed by a valid declaration keyword on the same line.
634    /// Used to distinguish `declare class ...` (ambient declaration) from
635    /// `declare instanceof C` (expression using `declare` as identifier).
636    /// ASI prevents treating `declare\nclass ...` as an ambient declaration.
637    fn look_ahead_is_declare_before_declaration(&mut self) -> bool {
638        let snapshot = self.scanner.save_state();
639        let current = self.current_token;
640        self.next_token(); // skip `declare`
641        let is_decl = !self.scanner.has_preceding_line_break()
642            && matches!(
643                self.token(),
644                SyntaxKind::ClassKeyword
645                    | SyntaxKind::InterfaceKeyword
646                    | SyntaxKind::EnumKeyword
647                    | SyntaxKind::NamespaceKeyword
648                    | SyntaxKind::ModuleKeyword
649                    | SyntaxKind::FunctionKeyword
650                    | SyntaxKind::AbstractKeyword
651                    | SyntaxKind::ConstKeyword
652                    | SyntaxKind::VarKeyword
653                    | SyntaxKind::LetKeyword
654                    | SyntaxKind::TypeKeyword
655                    | SyntaxKind::GlobalKeyword
656                    | SyntaxKind::AsyncKeyword
657            );
658        self.scanner.restore_state(snapshot);
659        self.current_token = current;
660        is_decl
661    }
662
663    /// Check if the next token is an identifier or keyword on the same line.
664    /// Matches tsc's `nextTokenIsIdentifierOrKeywordOnSameLine`.
665    /// Used by `isStartOfStatement()` for modifier keywords (static, public, etc.)
666    /// to distinguish class-member-like context from standalone expressions.
667    pub(super) fn look_ahead_next_is_identifier_or_keyword_on_same_line(&mut self) -> bool {
668        let snapshot = self.scanner.save_state();
669        let current = self.current_token;
670        self.next_token(); // skip the modifier keyword
671        let result = !self.scanner.has_preceding_line_break() && self.is_identifier_or_keyword();
672        self.scanner.restore_state(snapshot);
673        self.current_token = current;
674        result
675    }
676
677    /// Check if the next token is on a new line (ASI applies).
678    /// Used to detect cases like:
679    ///   abstract
680    ///   class C {}
681    /// where ASI should terminate `abstract` as an expression statement.
682    fn next_token_is_on_new_line(&mut self) -> bool {
683        let snapshot = self.scanner.save_state();
684        self.scanner.scan();
685        let has_line_break = self.scanner.has_preceding_line_break();
686        self.scanner.restore_state(snapshot);
687        has_line_break
688    }
689
690    /// Look ahead to see if we have "async function"
691    pub(crate) fn look_ahead_is_async_function(&mut self) -> bool {
692        look_ahead_is(&mut self.scanner, self.current_token, |token| {
693            token == SyntaxKind::FunctionKeyword
694        })
695    }
696
697    /// Look ahead to see if "async" is followed by a declaration keyword.
698    pub(crate) fn look_ahead_is_async_declaration(&mut self) -> bool {
699        look_ahead_is_async_declaration(&mut self.scanner, self.current_token)
700    }
701
702    /// Look ahead to see if we have "abstract class"
703    pub(crate) fn look_ahead_is_abstract_class(&mut self) -> bool {
704        look_ahead_is(&mut self.scanner, self.current_token, |token| {
705            token == SyntaxKind::ClassKeyword
706        })
707    }
708
709    /// Look ahead to see if "abstract" is followed by another declaration keyword.
710    pub(crate) fn look_ahead_is_abstract_declaration(&mut self) -> bool {
711        look_ahead_is_abstract_declaration(&mut self.scanner, self.current_token)
712    }
713
714    /// Look ahead to see if "accessor" is followed by a declaration keyword.
715    pub(crate) fn look_ahead_is_accessor_declaration(&mut self) -> bool {
716        let snapshot = self.scanner.save_state();
717        let current = self.current_token;
718
719        self.next_token(); // skip 'accessor'
720        let is_decl = matches!(
721            self.token(),
722            SyntaxKind::ClassKeyword
723                | SyntaxKind::InterfaceKeyword
724                | SyntaxKind::EnumKeyword
725                | SyntaxKind::NamespaceKeyword
726                | SyntaxKind::ModuleKeyword
727                | SyntaxKind::DeclareKeyword
728                | SyntaxKind::VarKeyword
729                | SyntaxKind::LetKeyword
730                | SyntaxKind::ConstKeyword
731                | SyntaxKind::TypeKeyword
732                | SyntaxKind::FunctionKeyword
733                | SyntaxKind::ImportKeyword
734                | SyntaxKind::ExportKeyword
735        );
736
737        self.scanner.restore_state(snapshot);
738        self.current_token = current;
739        is_decl
740    }
741
742    /// Look ahead to see if `let` starts a variable declaration.
743    /// In tsc, `let` is only treated as a declaration keyword when followed by
744    /// an identifier, `{` (object destructuring), or `[` (array destructuring).
745    /// Otherwise (e.g. `let;`), `let` is treated as an identifier expression.
746    pub(crate) fn look_ahead_is_let_declaration(&mut self) -> bool {
747        look_ahead_is(&mut self.scanner, self.current_token, |token| {
748            is_identifier_or_keyword(token)
749                || token == SyntaxKind::OpenBraceToken
750                || token == SyntaxKind::OpenBracketToken
751        })
752    }
753
754    /// Look ahead to see if we have "await using"
755    pub(crate) fn look_ahead_is_await_using(&mut self) -> bool {
756        look_ahead_is(&mut self.scanner, self.current_token, |token| {
757            token == SyntaxKind::UsingKeyword
758        })
759    }
760
761    /// Look ahead to see if we have "import identifier ="
762    pub(crate) fn look_ahead_is_import_equals(&mut self) -> bool {
763        look_ahead_is_import_equals(
764            &mut self.scanner,
765            self.current_token,
766            is_identifier_or_keyword,
767        )
768    }
769
770    /// Look ahead to check if the current identifier is directly followed by `=`.
771    /// Used to disambiguate `import type X =` (where `type` is import name)
772    /// from `import type X = require(...)` (where `type` is modifier).
773    fn look_ahead_is_equals_after_identifier(&mut self) -> bool {
774        let snapshot = self.scanner.save_state();
775        let current = self.current_token;
776        // Skip current token (the identifier)
777        self.next_token();
778        let result = self.is_token(SyntaxKind::EqualsToken);
779        self.scanner.restore_state(snapshot);
780        self.current_token = current;
781        result
782    }
783
784    /// Look ahead to see if we have "import (" (dynamic import call)
785    pub(crate) fn look_ahead_is_import_call(&mut self) -> bool {
786        look_ahead_is_import_call(&mut self.scanner, self.current_token)
787    }
788
789    /// Look ahead to see if we have `export =`.
790    fn look_ahead_is_export_assignment(&mut self) -> bool {
791        let snapshot = self.scanner.save_state();
792        let current = self.current_token;
793        self.next_token(); // skip `export`
794        let result = self.is_token(SyntaxKind::EqualsToken);
795        self.scanner.restore_state(snapshot);
796        self.current_token = current;
797        result
798    }
799
800    /// Look ahead to see if "namespace"/"module" starts a declaration.
801    /// Updated to recognize anonymous modules: module { ... }
802    pub(crate) fn look_ahead_is_module_declaration(&mut self) -> bool {
803        look_ahead_is_module_declaration(&mut self.scanner, self.current_token)
804    }
805
806    /// Look ahead to see if "type" starts a type alias declaration.
807    pub(crate) fn look_ahead_is_type_alias_declaration(&mut self) -> bool {
808        look_ahead_is_type_alias_declaration(&mut self.scanner, self.current_token)
809    }
810
811    /// Look ahead to see if we have "identifier :" (labeled statement)
812    pub(crate) fn look_ahead_is_labeled_statement(&mut self) -> bool {
813        let snapshot = self.scanner.save_state();
814        let current = self.current_token;
815
816        // Skip identifier
817        self.next_token();
818        // Check for ':'
819        let is_colon = self.is_token(SyntaxKind::ColonToken);
820
821        self.scanner.restore_state(snapshot);
822        self.current_token = current;
823        is_colon
824    }
825
826    /// Look ahead to see if we have "const enum"
827    pub(crate) fn look_ahead_is_const_enum(&mut self) -> bool {
828        look_ahead_is_const_enum(&mut self.scanner, self.current_token)
829    }
830
831    /// Parse const enum declaration
832    pub(crate) fn parse_const_enum_declaration(
833        &mut self,
834        start_pos: u32,
835        mut modifiers: Vec<NodeIndex>,
836    ) -> NodeIndex {
837        let const_start = self.token_pos();
838        self.parse_expected(SyntaxKind::ConstKeyword);
839        let const_end = self.token_end();
840        let const_modifier =
841            self.arena
842                .add_token(SyntaxKind::ConstKeyword as u16, const_start, const_end);
843        modifiers.push(const_modifier);
844
845        let modifiers = Some(self.make_node_list(modifiers));
846        self.parse_enum_declaration_with_modifiers(start_pos, modifiers)
847    }
848
849    /// Parse labeled statement: label: statement
850    pub(crate) fn parse_labeled_statement(&mut self) -> NodeIndex {
851        let start_pos = self.token_pos();
852
853        // Parse the label (identifier)
854        let label = self.parse_identifier_name();
855
856        // Check for duplicate labels (TS1114) and record this label
857        let label_name = if let Some(label_node) = self.arena.get(label) {
858            if let Some(ident) = self.arena.get_identifier_at(label) {
859                let escaped_text = ident.escaped_text.clone();
860                let pos = label_node.pos;
861                self.check_duplicate_label(&escaped_text, pos);
862                Some(escaped_text)
863            } else {
864                None
865            }
866        } else {
867            None
868        };
869
870        // Consume the colon
871        self.parse_expected(SyntaxKind::ColonToken);
872
873        // Parse the statement
874        let statement = self.parse_statement();
875
876        // Remove the label from the current scope (labels are statement-scoped)
877        // This allows sequential labels with the same name: target: stmt1; target: stmt2;
878        if let Some(label_name) = label_name
879            && let Some(current_scope) = self.label_scopes.last_mut()
880        {
881            current_scope.remove(&label_name);
882        }
883
884        let end_pos = self.token_end();
885
886        self.arena.add_labeled(
887            syntax_kind_ext::LABELED_STATEMENT,
888            start_pos,
889            end_pos,
890            LabeledData { label, statement },
891        )
892    }
893
894    /// Parse import equals declaration: import X = require("...") or import X = Y.Z
895    pub(crate) fn parse_import_equals_declaration(&mut self) -> NodeIndex {
896        let start_pos = self.token_pos();
897        self.parse_expected(SyntaxKind::ImportKeyword);
898
899        // Check for type modifier: `import type X = require(...)`
900        let is_type_only = if self.is_token(SyntaxKind::TypeKeyword)
901            && !self.look_ahead_is_equals_after_identifier()
902        {
903            self.next_token();
904            true
905        } else {
906            false
907        };
908        let _ = is_type_only; // stored for future use in type checking
909
910        // Parse the name - allows keywords like 'require' and 'exports' as valid names
911        let name = self.parse_identifier_name();
912
913        self.parse_expected(SyntaxKind::EqualsToken);
914
915        // Parse module reference: require("...") or qualified name
916        let module_reference = if self.is_token(SyntaxKind::RequireKeyword) {
917            self.parse_external_module_reference()
918        } else {
919            self.parse_entity_name()
920        };
921
922        self.parse_semicolon();
923        let end_pos = self.token_end();
924
925        // Use ImportDeclData with import_clause as the name and module_specifier as reference
926        // This is a simplified representation
927        self.arena.add_import_decl(
928            syntax_kind_ext::IMPORT_EQUALS_DECLARATION,
929            start_pos,
930            end_pos,
931            ImportDeclData {
932                modifiers: None,
933                import_clause: name,
934                module_specifier: module_reference,
935                attributes: NodeIndex::NONE,
936            },
937        )
938    }
939
940    /// Parse external module reference: require("...")
941    pub(crate) fn parse_external_module_reference(&mut self) -> NodeIndex {
942        self.parse_expected(SyntaxKind::RequireKeyword);
943        self.parse_expected(SyntaxKind::OpenParenToken);
944        let expression = self.parse_string_literal();
945        self.parse_expected(SyntaxKind::CloseParenToken);
946
947        // Return the string literal as the module reference
948        expression
949    }
950
951    /// Parse entity name: A or A.B.C or this or this.x
952    pub(crate) fn parse_entity_name(&mut self) -> NodeIndex {
953        // Handle 'this' keyword as a valid start for typeof expressions
954        let mut left = if self.is_token(SyntaxKind::ThisKeyword) {
955            let start_pos = self.token_pos();
956            let end_pos = self.token_end();
957            self.next_token();
958            self.arena
959                .add_token(SyntaxKind::ThisKeyword as u16, start_pos, end_pos)
960        } else {
961            self.parse_identifier()
962        };
963
964        while self.is_token(SyntaxKind::DotToken) {
965            self.next_token();
966            let right = self.parse_identifier_name(); // Use identifier_name to allow keywords as property names
967            let start_pos = if let Some(node) = self.arena.get(left) {
968                node.pos
969            } else {
970                0
971            };
972            let end_pos = self.token_end();
973
974            left = self.arena.add_qualified_name(
975                syntax_kind_ext::QUALIFIED_NAME,
976                start_pos,
977                end_pos,
978                QualifiedNameData { left, right },
979            );
980        }
981
982        left
983    }
984
985    /// Parse async function declaration
986    pub(crate) fn parse_async_function_declaration(&mut self) -> NodeIndex {
987        // TS1040: 'async' modifier cannot be used in an ambient context
988        if (self.context_flags & crate::parser::state::CONTEXT_FLAG_AMBIENT) != 0 {
989            use tsz_common::diagnostics::diagnostic_codes;
990            self.parse_error_at_current_token(
991                "'async' modifier cannot be used in an ambient context.",
992                diagnostic_codes::MODIFIER_CANNOT_BE_USED_IN_AN_AMBIENT_CONTEXT,
993            );
994        }
995        self.parse_expected(SyntaxKind::AsyncKeyword);
996        self.parse_function_declaration_with_async(true, None)
997    }
998
999    /// Parse a block statement
1000    pub(crate) fn parse_block(&mut self) -> NodeIndex {
1001        // Check recursion limit to prevent stack overflow on deeply nested code
1002        if !self.enter_recursion() {
1003            return NodeIndex::NONE;
1004        }
1005
1006        let start_pos = self.token_pos();
1007        let statements = if self.parse_expected(SyntaxKind::OpenBraceToken) {
1008            // Set IN_BLOCK flag so that modifiers like export/declare emit TS1184
1009            let saved_flags = self.context_flags;
1010            self.context_flags |= CONTEXT_FLAG_IN_BLOCK;
1011
1012            let stmts = self.parse_statements();
1013
1014            self.context_flags = saved_flags;
1015            self.parse_expected(SyntaxKind::CloseBraceToken);
1016            stmts
1017        } else {
1018            self.make_node_list(Vec::new())
1019        };
1020        let end_pos = self.token_end();
1021
1022        self.exit_recursion();
1023
1024        self.arena.add_block(
1025            syntax_kind_ext::BLOCK,
1026            start_pos,
1027            end_pos,
1028            BlockData {
1029                statements,
1030                multi_line: true,
1031            },
1032        )
1033    }
1034
1035    /// Parse empty statement
1036    pub(crate) fn parse_empty_statement(&mut self) -> NodeIndex {
1037        let start_pos = self.token_pos();
1038
1039        self.parse_expected(SyntaxKind::SemicolonToken);
1040        let end_pos = self.token_end();
1041
1042        self.arena
1043            .add_token(syntax_kind_ext::EMPTY_STATEMENT, start_pos, end_pos)
1044    }
1045
1046    /// Parse variable statement (var/let/const)
1047    pub(crate) fn parse_variable_statement(&mut self) -> NodeIndex {
1048        self.parse_variable_statement_with_modifiers(None, None)
1049    }
1050
1051    /// Parse variable statement with optional start position and modifiers (for declare statements)
1052    pub(crate) fn parse_variable_statement_with_modifiers(
1053        &mut self,
1054        override_start_pos: Option<u32>,
1055        modifiers: Option<NodeList>,
1056    ) -> NodeIndex {
1057        let start_pos = override_start_pos.unwrap_or_else(|| self.token_pos());
1058        let declaration_list = self.parse_variable_declaration_list();
1059        self.parse_semicolon();
1060        let end_pos = self.token_end();
1061
1062        self.arena.add_variable(
1063            syntax_kind_ext::VARIABLE_STATEMENT,
1064            start_pos,
1065            end_pos,
1066            VariableData {
1067                modifiers,
1068                declarations: self.make_node_list(vec![declaration_list]),
1069            },
1070        )
1071    }
1072
1073    /// Parse variable declaration list
1074    pub(crate) fn parse_variable_declaration_list(&mut self) -> NodeIndex {
1075        use crate::parser::node_flags;
1076
1077        let start_pos = self.token_pos();
1078
1079        // Consume var/let/const/using/await using and get flags
1080        // Use consume_keyword() for TS1260 check (keywords cannot contain escape characters)
1081        let flags: u16 = match self.token() {
1082            SyntaxKind::LetKeyword => {
1083                self.consume_keyword();
1084                self.u16_from_node_flags(node_flags::LET)
1085            }
1086            SyntaxKind::ConstKeyword => {
1087                self.consume_keyword();
1088                self.u16_from_node_flags(node_flags::CONST)
1089            }
1090            SyntaxKind::UsingKeyword => {
1091                self.consume_keyword();
1092                self.u16_from_node_flags(node_flags::USING)
1093            }
1094            SyntaxKind::AwaitKeyword => {
1095                // await using declaration
1096                self.consume_keyword(); // consume 'await'
1097                self.parse_expected(SyntaxKind::UsingKeyword); // consume 'using'
1098                self.u16_from_node_flags(node_flags::AWAIT_USING)
1099            }
1100            _ => {
1101                self.consume_keyword(); // var
1102                0
1103            }
1104        };
1105
1106        // Parse declarations with enhanced error recovery
1107        let mut declarations = Vec::new();
1108        loop {
1109            // Check if we can start a variable declaration
1110            // Can be: identifier, keyword as identifier, or binding pattern (object/array)
1111            let can_start_decl = self.is_identifier_or_keyword()
1112                || self.is_token(SyntaxKind::OpenBraceToken)
1113                || self.is_token(SyntaxKind::OpenBracketToken);
1114
1115            if !can_start_decl {
1116                // Invalid token for variable declaration - emit error and recover
1117                if !self.is_token(SyntaxKind::SemicolonToken)
1118                    && !self.is_token(SyntaxKind::CloseBraceToken)
1119                    && !self.is_token(SyntaxKind::EndOfFileToken)
1120                    && !self.is_token(SyntaxKind::Unknown)
1121                {
1122                    use tsz_common::diagnostics::diagnostic_codes;
1123                    self.parse_error_at_current_token(
1124                        "Variable declaration expected.",
1125                        diagnostic_codes::VARIABLE_DECLARATION_EXPECTED,
1126                    );
1127                }
1128                break;
1129            }
1130
1131            let decl = self.parse_variable_declaration_with_flags(flags);
1132            declarations.push(decl);
1133
1134            if !self.parse_optional(SyntaxKind::CommaToken) {
1135                // If ASI applies (line break, closing brace, EOF, or semicolon),
1136                // just break - parse_semicolon() in the caller will handle it
1137                if self.can_parse_semicolon() {
1138                    break;
1139                }
1140
1141                // No ASI - check if next token looks like another declaration
1142                // on the same line. If so, emit comma error for better diagnostics.
1143                let can_start_next = self.is_identifier_or_keyword()
1144                    || self.is_token(SyntaxKind::OpenBraceToken)
1145                    || self.is_token(SyntaxKind::OpenBracketToken);
1146
1147                if can_start_next {
1148                    self.error_comma_expected();
1149                }
1150                break;
1151            }
1152
1153            // After comma, check if next token can start another declaration.
1154            // Handle cases like: let x, , y (missing declaration between commas).
1155            // Reserved words (return, if, while, etc.) cannot be binding identifiers,
1156            // so `var a, return;` should be a trailing comma error, not a new declaration.
1157            let can_start_next = (self.is_identifier_or_keyword() && !self.is_reserved_word())
1158                || self.is_token(SyntaxKind::OpenBraceToken)
1159                || self.is_token(SyntaxKind::OpenBracketToken);
1160
1161            if !can_start_next {
1162                // Trailing comma in variable declaration list — emit TS1009.
1163                // This covers `var a,;`, `var a,}`, `var a,` (EOF), and
1164                // `var a,\nreturn;` (reserved word after comma = trailing comma).
1165                use tsz_common::diagnostics::{diagnostic_codes, diagnostic_messages};
1166                if self.is_token(SyntaxKind::SemicolonToken)
1167                    || self.is_token(SyntaxKind::CloseBraceToken)
1168                    || self.is_token(SyntaxKind::EndOfFileToken)
1169                    || self.is_reserved_word()
1170                {
1171                    // Report at the comma position (one token back).
1172                    // The comma was already consumed by parse_optional above.
1173                    let end = self.token_pos();
1174                    let start = end.saturating_sub(1);
1175                    self.parse_error_at(
1176                        start,
1177                        1,
1178                        diagnostic_messages::TRAILING_COMMA_NOT_ALLOWED,
1179                        diagnostic_codes::TRAILING_COMMA_NOT_ALLOWED,
1180                    );
1181                } else {
1182                    self.parse_error_at_current_token(
1183                        "Variable declaration expected.",
1184                        diagnostic_codes::VARIABLE_DECLARATION_EXPECTED,
1185                    );
1186                }
1187                break;
1188            }
1189        }
1190
1191        // Check for empty declaration list: var ;
1192        // TSC emits TS1123 "Variable declaration list cannot be empty"
1193        if declarations.is_empty() && !self.is_token(SyntaxKind::Unknown) {
1194            use tsz_common::diagnostics::diagnostic_codes;
1195            self.parse_error_at_current_token(
1196                "Variable declaration list cannot be empty.",
1197                diagnostic_codes::VARIABLE_DECLARATION_LIST_CANNOT_BE_EMPTY,
1198            );
1199        }
1200
1201        let end_pos = self.token_end();
1202        self.arena.add_variable_with_flags(
1203            syntax_kind_ext::VARIABLE_DECLARATION_LIST,
1204            start_pos,
1205            end_pos,
1206            VariableData {
1207                modifiers: None,
1208                declarations: self.make_node_list(declarations),
1209            },
1210            flags,
1211        )
1212    }
1213
1214    /// Parse variable declaration with declaration flags (for using/await using checks)
1215    /// Flags: bits 0-2 used for LET/CONST/USING, bit 3 for catch-clause binding (suppresses TS1182)
1216    pub(crate) fn parse_variable_declaration_with_flags(&mut self, flags: u16) -> NodeIndex {
1217        let start_pos = self.token_pos();
1218        self.parse_variable_declaration_with_flags_pre_checks(flags);
1219
1220        let name = self.parse_variable_declaration_name();
1221        let exclamation_token = self.parse_optional(SyntaxKind::ExclamationToken);
1222        let type_annotation = if self.parse_optional(SyntaxKind::ColonToken) {
1223            self.parse_type()
1224        } else {
1225            NodeIndex::NONE
1226        };
1227        let initializer = self.parse_variable_declaration_initializer();
1228        self.parse_variable_declaration_after_parse_checks(flags, start_pos, name, initializer);
1229
1230        let end_pos =
1231            self.parse_variable_declaration_end_pos(start_pos, type_annotation, name, initializer);
1232
1233        self.arena.add_variable_declaration(
1234            syntax_kind_ext::VARIABLE_DECLARATION,
1235            start_pos,
1236            end_pos,
1237            VariableDeclarationData {
1238                name,
1239                exclamation_token,
1240                type_annotation,
1241                initializer,
1242            },
1243        )
1244    }
1245
1246    fn parse_variable_declaration_with_flags_pre_checks(&mut self, flags: u16) {
1247        use crate::parser::node_flags;
1248        use tsz_common::diagnostics::{diagnostic_codes, diagnostic_messages};
1249
1250        // Check if this is a 'using' or 'await using' declaration.
1251        // Only check the USING bit (bit 2). AWAIT_USING = CONST | USING = 6,
1252        // so checking USING bit matches both USING (4) and AWAIT_USING (6)
1253        // but NOT CONST (2) which only has bit 1 set.
1254        let is_using = (flags & self.u16_from_node_flags(node_flags::USING)) != 0;
1255
1256        // TS1492: 'using'/'await using' declarations may not have binding patterns
1257        if is_using
1258            && (self.is_token(SyntaxKind::OpenBraceToken)
1259                || self.is_token(SyntaxKind::OpenBracketToken))
1260        {
1261            let is_await_using = (flags & self.u16_from_node_flags(node_flags::AWAIT_USING))
1262                == self.u16_from_node_flags(node_flags::AWAIT_USING);
1263            let decl_kind = if is_await_using {
1264                "await using"
1265            } else {
1266                "using"
1267            };
1268            let msg = diagnostic_messages::DECLARATIONS_MAY_NOT_HAVE_BINDING_PATTERNS
1269                .replace("{0}", decl_kind);
1270            self.parse_error_at_current_token(
1271                &msg,
1272                diagnostic_codes::DECLARATIONS_MAY_NOT_HAVE_BINDING_PATTERNS,
1273            );
1274        }
1275
1276        // Parse name - can be identifier, keyword as identifier, or binding pattern
1277        // Check for illegal binding identifiers (e.g., 'await' in static blocks)
1278        self.check_illegal_binding_identifier();
1279        // TS18029: Check for private identifiers in variable declarations (check before parsing)
1280        if self.is_token(SyntaxKind::PrivateIdentifier) {
1281            let start = self.token_pos();
1282            let length = self.token_end() - start;
1283            self.parse_error_at(
1284                start,
1285                length,
1286                "Private identifiers are not allowed in variable declarations.",
1287                diagnostic_codes::PRIVATE_IDENTIFIERS_ARE_NOT_ALLOWED_IN_VARIABLE_DECLARATIONS,
1288            );
1289        }
1290    }
1291
1292    fn parse_variable_declaration_name(&mut self) -> NodeIndex {
1293        if self.is_token(SyntaxKind::OpenBraceToken) {
1294            self.parse_object_binding_pattern()
1295        } else if self.is_token(SyntaxKind::OpenBracketToken) {
1296            self.parse_array_binding_pattern()
1297        } else {
1298            self.parse_identifier()
1299        }
1300    }
1301
1302    fn parse_variable_declaration_initializer(&mut self) -> NodeIndex {
1303        if !self.parse_optional(SyntaxKind::EqualsToken) {
1304            return NodeIndex::NONE;
1305        }
1306
1307        if self.is_token(SyntaxKind::ConstKeyword)
1308            || self.is_token(SyntaxKind::LetKeyword)
1309            || self.is_token(SyntaxKind::VarKeyword)
1310        {
1311            self.error_expression_expected();
1312            return NodeIndex::NONE;
1313        }
1314
1315        let expr = self.parse_assignment_expression();
1316        if expr.is_none() {
1317            self.error_expression_expected();
1318        }
1319        expr
1320    }
1321
1322    fn parse_variable_declaration_after_parse_checks(
1323        &mut self,
1324        flags: u16,
1325        start_pos: u32,
1326        name: NodeIndex,
1327        initializer: NodeIndex,
1328    ) {
1329        use tsz_common::diagnostics::diagnostic_codes;
1330
1331        // TS1182: A destructuring declaration must have an initializer
1332        // Skip for catch clause bindings (flags bit 3 = CATCH_CLAUSE_BINDING)
1333        // and for-in/for-of loop variables, which are destructuring without initializers.
1334        let is_catch_clause = (flags & 0x8) != 0;
1335        if is_catch_clause && initializer.is_some() {
1336            let (pos, len) = self
1337                .arena
1338                .get(initializer)
1339                .map_or((start_pos, 0), |n| (n.pos, n.end - n.pos));
1340            self.parse_error_at(
1341                pos,
1342                len,
1343                "Catch clause variable cannot have an initializer.",
1344                diagnostic_codes::CATCH_CLAUSE_VARIABLE_CANNOT_HAVE_AN_INITIALIZER,
1345            );
1346        }
1347        if !is_catch_clause
1348            && initializer.is_none()
1349            && (self.context_flags & crate::parser::state::CONTEXT_FLAG_AMBIENT) == 0
1350            && let Some(name_node) = self.arena.get(name)
1351        {
1352            use crate::parser::syntax_kind_ext::{ARRAY_BINDING_PATTERN, OBJECT_BINDING_PATTERN};
1353            if name_node.kind == OBJECT_BINDING_PATTERN || name_node.kind == ARRAY_BINDING_PATTERN {
1354                self.parse_error_at(
1355                    name_node.pos,
1356                    name_node.end - name_node.pos,
1357                    "A destructuring declaration must have an initializer.",
1358                    diagnostic_codes::A_DESTRUCTURING_DECLARATION_MUST_HAVE_AN_INITIALIZER,
1359                );
1360            }
1361        }
1362        if name == NodeIndex::NONE {
1363            self.parse_error_at_current_token(
1364                "Identifier expected.",
1365                diagnostic_codes::IDENTIFIER_EXPECTED,
1366            );
1367        }
1368    }
1369
1370    fn parse_variable_declaration_end_pos(
1371        &mut self,
1372        start_pos: u32,
1373        type_annotation: NodeIndex,
1374        name: NodeIndex,
1375        initializer: NodeIndex,
1376    ) -> u32 {
1377        let mut end_pos = self.token_end();
1378        // Calculate end position from the last component present (child node, not token)
1379        if initializer.is_some() {
1380            self.arena
1381                .get(initializer)
1382                .map_or_else(|| self.token_pos(), |n| n.end)
1383        } else if type_annotation.is_some() {
1384            self.arena
1385                .get(type_annotation)
1386                .map_or_else(|| self.token_pos(), |n| n.end)
1387        } else {
1388            self.arena
1389                .get(name)
1390                .map_or_else(|| self.token_pos(), |n| n.end)
1391        };
1392        end_pos = end_pos.max(self.token_end()).max(start_pos);
1393        end_pos
1394    }
1395
1396    /// Parse function declaration (optionally async)
1397    pub(crate) fn parse_function_declaration(&mut self) -> NodeIndex {
1398        tracing::trace!(pos = self.token_pos(), "parse_function_declaration");
1399        self.parse_function_declaration_with_async(false, None)
1400    }
1401
1402    /// Parse function declaration with async modifier already consumed
1403    pub(crate) fn parse_function_declaration_with_async(
1404        &mut self,
1405        is_async: bool,
1406        modifiers: Option<NodeList>,
1407    ) -> NodeIndex {
1408        let start_pos = self.token_pos();
1409
1410        // Check for async modifier if not already parsed
1411        // TS1040: 'async' modifier cannot be used in an ambient context
1412        let _async_token_pos = self.token_pos();
1413        let is_async = if !is_async && self.is_token(SyntaxKind::AsyncKeyword) {
1414            if (self.context_flags & crate::parser::state::CONTEXT_FLAG_AMBIENT) != 0 {
1415                use tsz_common::diagnostics::diagnostic_codes;
1416                self.parse_error_at_current_token(
1417                    "'async' modifier cannot be used in an ambient context.",
1418                    diagnostic_codes::MODIFIER_CANNOT_BE_USED_IN_AN_AMBIENT_CONTEXT,
1419                );
1420            }
1421            self.next_token(); // consume async
1422            true
1423        } else {
1424            is_async
1425        };
1426
1427        self.parse_expected(SyntaxKind::FunctionKeyword);
1428
1429        // Check for generator asterisk
1430        let asterisk_token = self.parse_optional(SyntaxKind::AsteriskToken);
1431
1432        // Set context flags BEFORE parsing name and parameters so that
1433        // reserved keywords (await/yield) are properly detected in function declarations
1434        // For async function * await() {}, the function name 'await' should error
1435        // For async function * (await) {}, the parameter name 'await' should error
1436        let is_async_generator_declaration = is_async && asterisk_token;
1437        let saved_flags = self.context_flags;
1438        if is_async {
1439            self.context_flags |= CONTEXT_FLAG_ASYNC;
1440        }
1441        if asterisk_token {
1442            self.context_flags |= CONTEXT_FLAG_GENERATOR;
1443        }
1444
1445        // Parse name - keywords like 'abstract' can be used as function names
1446        // Note: function names are NOT subject to async/generator context restrictions
1447        // because the name is a declaration in the outer scope, not a binding in the
1448        // function body. `async function * await() {}` and `function * yield() {}` are valid.
1449        // Only check for static block context (where await is always illegal as an identifier)
1450        if self.in_static_block_context() && self.is_token(SyntaxKind::AwaitKeyword) {
1451            self.parse_error_at_current_token(
1452                "Identifier expected. 'await' is a reserved word that cannot be used here.",
1453                diagnostic_codes::IDENTIFIER_EXPECTED_IS_A_RESERVED_WORD_THAT_CANNOT_BE_USED_HERE,
1454            );
1455        }
1456
1457        // Async and generator function declarations are valid with `await`/`yield` in their
1458        // own names, but nested function declarations in those contexts are not.
1459        if !is_async_generator_declaration && self.in_generator_context()
1460            || (self.in_async_context() && self.is_token(SyntaxKind::AwaitKeyword)) && !is_async
1461        {
1462            use tsz_common::diagnostics::diagnostic_codes;
1463            if self.is_token(SyntaxKind::AwaitKeyword) {
1464                self.parse_error_at_current_token(
1465                    "Identifier expected. 'await' is a reserved word that cannot be used here.",
1466                    diagnostic_codes::IDENTIFIER_EXPECTED_IS_A_RESERVED_WORD_THAT_CANNOT_BE_USED_HERE,
1467                );
1468            } else if self.is_token(SyntaxKind::YieldKeyword) {
1469                let is_class_context = self.in_class_body() || self.in_class_member_name();
1470                if is_class_context {
1471                    self.parse_error_at_current_token(
1472                        "Identifier expected. 'yield' is a reserved word in strict mode. Class definitions are automatically in strict mode.",
1473                        diagnostic_codes::IDENTIFIER_EXPECTED_IS_A_RESERVED_WORD_IN_STRICT_MODE_CLASS_DEFINITIONS_ARE_AUTO,
1474                    );
1475                } else {
1476                    self.parse_error_at_current_token(
1477                        "Identifier expected. 'yield' is a reserved word in strict mode.",
1478                        diagnostic_codes::IDENTIFIER_EXPECTED_IS_A_RESERVED_WORD_IN_STRICT_MODE,
1479                    );
1480                }
1481            }
1482        }
1483
1484        let name = if self.is_identifier_or_keyword() {
1485            self.parse_identifier_name()
1486        } else {
1487            self.parse_identifier()
1488        };
1489
1490        // Parse optional type parameters: <T, U extends V>
1491        let type_parameters = self
1492            .is_token(SyntaxKind::LessThanToken)
1493            .then(|| self.parse_type_parameters());
1494
1495        // Parse parameters
1496        self.parse_expected(SyntaxKind::OpenParenToken);
1497        let parameters = self.parse_parameter_list();
1498        self.parse_expected(SyntaxKind::CloseParenToken);
1499
1500        // Parse optional return type (may be a type predicate: param is T)
1501        // Note: Type annotations are not in async/generator context
1502        let type_annotation = if self.parse_optional(SyntaxKind::ColonToken) {
1503            self.parse_return_type()
1504        } else {
1505            NodeIndex::NONE
1506        };
1507
1508        // Parse body - may be missing for overload signatures (just a semicolon)
1509        // Context flags remain set for await/yield expressions in body
1510        // Push a new label scope for the function body
1511        self.push_label_scope();
1512        let body = if self.is_token(SyntaxKind::OpenBraceToken) {
1513            self.parse_block()
1514        } else if self.is_token(SyntaxKind::EqualsGreaterThanToken) {
1515            // TS1144: '{' or ';' expected — user wrote arrow syntax on a function declaration
1516            self.parse_error_at_current_token(
1517                "'{' or ';' expected.",
1518                diagnostic_codes::OR_EXPECTED,
1519            );
1520            // Skip past => and the expression for error recovery
1521            self.next_token();
1522            let _expr = self.parse_expression();
1523            self.parse_optional(SyntaxKind::SemicolonToken);
1524            NodeIndex::NONE
1525        } else {
1526            // Consume the semicolon if present (overload signature)
1527            self.parse_optional(SyntaxKind::SemicolonToken);
1528            NodeIndex::NONE
1529        };
1530        self.pop_label_scope();
1531
1532        // Restore context flags
1533        self.context_flags = saved_flags;
1534
1535        let end_pos = self.token_end();
1536        self.arena.add_function(
1537            syntax_kind_ext::FUNCTION_DECLARATION,
1538            start_pos,
1539            end_pos,
1540            FunctionData {
1541                modifiers,
1542                is_async,
1543                asterisk_token,
1544                name,
1545                type_parameters,
1546                parameters,
1547                type_annotation,
1548                body,
1549                equals_greater_than_token: false,
1550            },
1551        )
1552    }
1553
1554    /// Parse function declaration for export default context (name is optional).
1555    /// Unlike regular function declarations, `export default function() {}` allows anonymous functions.
1556    /// Unlike function expressions, this creates a `FUNCTION_DECLARATION` node and supports
1557    /// overload signatures (missing body).
1558    pub(crate) fn parse_function_declaration_with_async_optional_name(
1559        &mut self,
1560        is_async: bool,
1561        modifiers: Option<NodeList>,
1562    ) -> NodeIndex {
1563        let start_pos = self.token_pos();
1564        tracing::trace!(
1565            start_pos,
1566            "parse_function_declaration_with_async_optional_name"
1567        );
1568
1569        let is_async = is_async || self.parse_optional(SyntaxKind::AsyncKeyword);
1570        self.parse_expected(SyntaxKind::FunctionKeyword);
1571        let asterisk_token = self.parse_optional(SyntaxKind::AsteriskToken);
1572
1573        // Name is optional for export default function declarations
1574        let name = if self.is_identifier_or_keyword() {
1575            self.parse_identifier_name()
1576        } else {
1577            NodeIndex::NONE
1578        };
1579
1580        let type_parameters = self
1581            .is_token(SyntaxKind::LessThanToken)
1582            .then(|| self.parse_type_parameters());
1583
1584        self.parse_expected(SyntaxKind::OpenParenToken);
1585        let parameters = self.parse_parameter_list();
1586        self.parse_expected(SyntaxKind::CloseParenToken);
1587
1588        let type_annotation = if self.parse_optional(SyntaxKind::ColonToken) {
1589            self.parse_return_type()
1590        } else {
1591            NodeIndex::NONE
1592        };
1593
1594        let saved_flags = self.context_flags;
1595        if is_async {
1596            self.context_flags |= CONTEXT_FLAG_ASYNC;
1597        }
1598        if asterisk_token {
1599            self.context_flags |= CONTEXT_FLAG_GENERATOR;
1600        }
1601
1602        // Push a new label scope for the function body
1603        // Labels are function-scoped, so each function gets its own label namespace
1604        self.push_label_scope();
1605
1606        let body = if self.is_token(SyntaxKind::OpenBraceToken) {
1607            self.parse_block()
1608        } else {
1609            self.parse_optional(SyntaxKind::SemicolonToken);
1610            NodeIndex::NONE
1611        };
1612
1613        // Pop the label scope when exiting the function
1614        self.pop_label_scope();
1615
1616        self.context_flags = saved_flags;
1617
1618        let end_pos = self.token_end();
1619        self.arena.add_function(
1620            syntax_kind_ext::FUNCTION_DECLARATION,
1621            start_pos,
1622            end_pos,
1623            FunctionData {
1624                modifiers,
1625                is_async,
1626                asterisk_token,
1627                name,
1628                type_parameters,
1629                parameters,
1630                type_annotation,
1631                body,
1632                equals_greater_than_token: false,
1633            },
1634        )
1635    }
1636
1637    /// Parse function expression: `function()` {} or function `name()` {}
1638    ///
1639    /// Unlike function declarations, function expressions can be anonymous.
1640    pub(crate) fn parse_function_expression(&mut self) -> NodeIndex {
1641        self.parse_function_expression_with_async(false)
1642    }
1643
1644    /// Parse async function expression: async `function()` {} or async function `name()` {}
1645    pub(crate) fn parse_async_function_expression(&mut self) -> NodeIndex {
1646        self.parse_function_expression_with_async(true)
1647    }
1648
1649    /// Parse function expression with optional async modifier
1650    pub(crate) fn parse_function_expression_with_async(&mut self, is_async: bool) -> NodeIndex {
1651        let start_pos = self.token_pos();
1652
1653        // Consume async if present - only if we haven't already determined it's async
1654        // (When called from parse_async_function_expression, async hasn't been consumed yet)
1655        let is_async = if is_async {
1656            self.parse_expected(SyntaxKind::AsyncKeyword);
1657            true
1658        } else {
1659            self.parse_optional(SyntaxKind::AsyncKeyword)
1660        };
1661
1662        self.parse_expected(SyntaxKind::FunctionKeyword);
1663
1664        // Check for generator asterisk
1665        let asterisk_token = self.parse_optional(SyntaxKind::AsteriskToken);
1666
1667        // Set context flags BEFORE parsing name and parameters so that
1668        // reserved keywords (await/yield) are properly detected in function expressions
1669        // For async function * await() {}, the function name 'await' should error
1670        // For async function * (await) {}, the parameter name 'await' should error
1671        let saved_flags = self.context_flags;
1672        // Parameter-default context is for the containing parameter initializer only.
1673        // Nested function expressions create a new parsing context where this flag
1674        // must not leak into function body parsing.
1675        self.context_flags &= !CONTEXT_FLAG_PARAMETER_DEFAULT;
1676        if is_async {
1677            self.context_flags |= CONTEXT_FLAG_ASYNC;
1678        }
1679        if asterisk_token {
1680            self.context_flags |= CONTEXT_FLAG_GENERATOR;
1681        }
1682
1683        // Check for reserved words used as function expression names:
1684        // - `await` cannot be used as name in async function expressions
1685        // - `yield` cannot be used as name in generator function expressions
1686        // - `await` in static blocks is always illegal
1687        // Note: function DECLARATIONS are different - they bind in outer scope, so
1688        // `async function await() {}` as a declaration is valid.
1689        {
1690            use tsz_common::diagnostics::diagnostic_codes;
1691            if self.is_token(SyntaxKind::AwaitKeyword)
1692                && (self.in_static_block_context() || is_async || self.in_async_context())
1693            {
1694                self.parse_error_at_current_token(
1695                    "Identifier expected. 'await' is a reserved word that cannot be used here.",
1696                    diagnostic_codes::IDENTIFIER_EXPECTED_IS_A_RESERVED_WORD_THAT_CANNOT_BE_USED_HERE,
1697                );
1698            } else if self.is_token(SyntaxKind::YieldKeyword) && self.in_generator_context() {
1699                let is_class_context = self.in_class_body() || self.in_class_member_name();
1700                if is_class_context {
1701                    self.parse_error_at_current_token(
1702                        "Identifier expected. 'yield' is a reserved word in strict mode. Class definitions are automatically in strict mode.",
1703                        diagnostic_codes::IDENTIFIER_EXPECTED_IS_A_RESERVED_WORD_IN_STRICT_MODE_CLASS_DEFINITIONS_ARE_AUTO,
1704                    );
1705                } else {
1706                    self.parse_error_at_current_token(
1707                        "Identifier expected. 'yield' is a reserved word in strict mode.",
1708                        diagnostic_codes::IDENTIFIER_EXPECTED_IS_A_RESERVED_WORD_IN_STRICT_MODE,
1709                    );
1710                }
1711            }
1712        }
1713
1714        // Parse optional name (function expressions can be anonymous)
1715        let name = if self.is_identifier_or_keyword() {
1716            self.parse_identifier_name()
1717        } else {
1718            NodeIndex::NONE
1719        };
1720
1721        // Parse optional type parameters: <T, U extends V>
1722        let type_parameters = self
1723            .is_token(SyntaxKind::LessThanToken)
1724            .then(|| self.parse_type_parameters());
1725
1726        // Parse parameters
1727        self.parse_expected(SyntaxKind::OpenParenToken);
1728        let parameters = self.parse_parameter_list();
1729        self.parse_expected(SyntaxKind::CloseParenToken);
1730
1731        // Parse optional return type (may be a type predicate: param is T)
1732        // Note: Type annotations are not in async/generator context
1733        let type_annotation = if self.parse_optional(SyntaxKind::ColonToken) {
1734            self.parse_return_type()
1735        } else {
1736            NodeIndex::NONE
1737        };
1738
1739        // Parse body (context flags remain set for await/yield expressions in body)
1740        // Push a new label scope for the function body
1741        self.push_label_scope();
1742        let body = self.parse_block();
1743        self.pop_label_scope();
1744
1745        // Restore context flags
1746        self.context_flags = saved_flags;
1747
1748        let end_pos = self.token_end();
1749        self.arena.add_function(
1750            syntax_kind_ext::FUNCTION_EXPRESSION,
1751            start_pos,
1752            end_pos,
1753            FunctionData {
1754                modifiers: None,
1755                is_async,
1756                asterisk_token,
1757                name,
1758                type_parameters,
1759                parameters,
1760                type_annotation,
1761                body,
1762                equals_greater_than_token: false,
1763            },
1764        )
1765    }
1766
1767    // Class expressions, declarations, and decorators → state_statements_class.rs
1768    // Class member modifiers, members, and static blocks → state_statements_class_members.rs
1769}