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