// rottlib/src/parser/grammar/class.rs

#![allow(clippy::all, clippy::pedantic, clippy::nursery)]

use crate::ast::{
    BlockBody, ClassConstDecl, ClassConstDeclRef, ClassDeclaration, ClassDefinition, ClassMember,
    ClassModifier, ClassModifierRef, ClassVarDecl, ClassVarDeclRef, DeclarationLiteral,
    DeclarationLiteralRef, ExecDirective, ExecDirectiveRef, ExpressionRef, IdentifierToken,
    Reliability, ReplicationBlock, ReplicationBlockRef, ReplicationRule, ReplicationRuleRef,
    StateDecl, StateDeclRef, StateModifier, VariableDeclarator, VariableDeclaratorRef,
};
use crate::lexer::{Keyword, Token, TokenPosition, TokenSpan};
use crate::parser::{ParseErrorKind, ParseResult, ResultRecoveryExt, SyncLevel};

use std::collections::{HashMap, HashSet};

impl<'src, 'arena> crate::parser::Parser<'src, 'arena> {
    #[inline]
    pub fn ensure_progress_or_break(&mut self, before: TokenPosition) -> bool {
        match self.peek_position() {
            Some(position) if position > before => true,
            _ => self.advance().is_some(),
        }
    }

    fn parse_exec_directive(&mut self) -> ParseResult<'src, 'arena, ExecDirectiveRef<'arena>> {
        let (token, lexeme, start_position) =
            self.require_token_lexeme_and_position(ParseErrorKind::UnexpectedEndOfFile)?;
        debug_assert!(matches!(token, Token::ExecDirective));

        let trimmed = lexeme.trim_end_matches(['\r', '\n']);
        self.advance();

        let span = TokenSpan::range(start_position, self.last_consumed_position_or_start());
        Ok(self.arena.alloc_node(
            ExecDirective {
                text: self.arena.string(trimmed),
                span,
            },
            span,
        ))
    }

    fn parse_parenthesised_identifier(&mut self) -> ParseResult<'src, 'arena, IdentifierToken> {
        let has_opening_parenthesis = self.eat(Token::LeftParenthesis);
        let identifier =
            self.parse_identifier(ParseErrorKind::ParenthesisedIdentifierNameNotIdentifier)?;
        if has_opening_parenthesis {
            self.expect(
                Token::RightParenthesis,
                ParseErrorKind::ParenthesisedIdentifierMissingClosingParenthesis,
            )
            .sync_error_at(self, SyncLevel::CloseParenthesis)
            .report_error(self);
        }
        Ok(identifier)
    }

    #[inline]
    fn lookahead_state_after_mods(&mut self) -> bool {
        let mut lookahead = 0;
        loop {
            match self.peek_keyword_at(lookahead) {
                Some(Keyword::Auto | Keyword::Simulated) => {
                    lookahead += 1;
                }
                Some(Keyword::State) => return true,
                _ => return false,
            }
        }
    }

    pub fn parse_array_len_expr(
        &mut self,
    ) -> ParseResult<'src, 'arena, Option<ExpressionRef<'src, 'arena>>> {
        if !self.eat(Token::LeftBracket) {
            return Ok(None);
        }

        let expression = self.parse_expression();

        self.expect(
            Token::RightBracket,
            ParseErrorKind::ParenthesizedExpressionMissingClosingParenthesis,
        )
        .sync_error_at(self, SyncLevel::CloseBracket)?;

        Ok(Some(expression))
    }

    pub fn parse_class_declaration_modifier(
        &mut self,
    ) -> ParseResult<'src, 'arena, Option<ClassModifierRef<'arena>>> {
        use ClassModifier::{
            Abstract, CacheExempt, CollapseCategories, Config, Const, DependsOn, Deprecated,
            DontCollapseCategories, DynamicRecompile, EditConst, EditInline, EditInlineNew, Export,
            ExportStructs, Final, GlobalConfig, HideCategories, HideDropdown, Instanced, Localized,
            Native, NativeReplication, NoExport, NotEditInlineNew, NotPlaceable, ParseConfig,
            PerObjectConfig, Placeable, Private, Protected, Public, SafeReplace, ShowCategories,
            Static, Transient, Within,
        };

        let Some((token, modifier_position)) = self.peek_token_and_position() else {
            return Err(self.make_error_at_last_consumed(ParseErrorKind::UnexpectedEndOfFile));
        };

        let mut consumed_inside_match = false;
        let mut span = TokenSpan::new(modifier_position);

        let modifier = match token {
            Token::Keyword(Keyword::Final) => Final,
            Token::Keyword(Keyword::Native) => Native,
            Token::Keyword(Keyword::Abstract) => Abstract,
            Token::Keyword(Keyword::Transient) => Transient,
            Token::Keyword(Keyword::Public) => Public,
            Token::Keyword(Keyword::Protected) => Protected,
            Token::Keyword(Keyword::Private) => Private,
            Token::Keyword(Keyword::Static) => Static,
            Token::Keyword(Keyword::Const) => Const,
            Token::Keyword(Keyword::Deprecated) => Deprecated,
            Token::Keyword(Keyword::NoExport) => NoExport,
            Token::Keyword(Keyword::Export) => Export,

            Token::Keyword(Keyword::Config) => {
                self.advance();
                consumed_inside_match = true;
                let value = if self.peek_token() == Some(Token::LeftParenthesis) {
                    Some(self.parse_parenthesised_identifier()?)
                } else {
                    None
                };
                Config(value)
            }

            Token::Keyword(Keyword::Localized) => Localized,
            Token::Keyword(Keyword::Placeable) => Placeable,
            Token::Keyword(Keyword::NotPlaceable) => NotPlaceable,
            Token::Keyword(Keyword::Instanced) => Instanced,
            Token::Keyword(Keyword::EditConst) => EditConst,
            Token::Keyword(Keyword::EditInline) => EditInline,
            Token::Keyword(Keyword::EditInlineNew) => EditInlineNew,
            Token::Keyword(Keyword::NotEditInlineNew) => NotEditInlineNew,
            Token::Keyword(Keyword::CollapseCategories) => CollapseCategories,
            Token::Keyword(Keyword::DontCollapseCategories) => DontCollapseCategories,
            Token::Keyword(Keyword::GlobalConfig) => GlobalConfig,
            Token::Keyword(Keyword::PerObjectConfig) => PerObjectConfig,
            Token::Keyword(Keyword::DynamicRecompile) => DynamicRecompile,
            Token::Keyword(Keyword::CacheExempt) => CacheExempt,
            Token::Keyword(Keyword::HideDropdown) => HideDropdown,
            Token::Keyword(Keyword::ParseConfig) => ParseConfig,
            Token::Keyword(Keyword::NativeReplication) => NativeReplication,
            Token::Keyword(Keyword::ExportStructs) => ExportStructs,
            Token::Keyword(Keyword::SafeReplace) => SafeReplace,

            Token::Keyword(Keyword::HideCategories) => {
                self.advance();
                consumed_inside_match = true;
                self.expect(
                    Token::LeftParenthesis,
                    ParseErrorKind::HideCategoriesMissingOpeningParenthesis,
                )?;
                let categories = self.parse_identifier_list();
                self.expect(
                    Token::RightParenthesis,
                    ParseErrorKind::HideCategoriesMissingClosingParenthesis,
                )
                .sync_error_at(self, SyncLevel::CloseParenthesis)?;
                HideCategories(categories)
            }
            Token::Keyword(Keyword::ShowCategories) => {
                self.advance();
                consumed_inside_match = true;
                self.expect(
                    Token::LeftParenthesis,
                    ParseErrorKind::ShowCategoriesMissingOpeningParenthesis,
                )?;
                let categories = self.parse_identifier_list();
                self.expect(
                    Token::RightParenthesis,
                    ParseErrorKind::ShowCategoriesMissingClosingParenthesis,
                )
                .sync_error_at(self, SyncLevel::CloseParenthesis)?;
                ShowCategories(categories)
            }
            Token::Keyword(Keyword::Within) => {
                self.advance();
                consumed_inside_match = true;
                Within(self.parse_identifier(ParseErrorKind::WithinNameNotIdentifier)?)
            }
            Token::Keyword(Keyword::DependsOn) => {
                self.advance();
                consumed_inside_match = true;
                DependsOn(self.parse_parenthesised_identifier()?)
            }

            _ => return Ok(None),
        };

        if !consumed_inside_match {
            self.advance();
        }
        span.extend_to(self.last_consumed_position_or_start());
        Ok(Some(self.arena.alloc_node(modifier, span)))
    }

    pub(crate) fn parse_class_header_cont(
        &mut self,
    ) -> ParseResult<'src, 'arena, ClassDeclaration<'arena>>
    where
        'src: 'arena,
    {
        let class_name = self.parse_identifier(ParseErrorKind::ClassNameNotIdentifier)?;

        let parent_class_name = if self.eat_keyword(Keyword::Extends) {
            let qualified_parent =
                self.parse_qualified_identifier(ParseErrorKind::ClassParentNameNotIdentifier)?;
            Some(qualified_parent)
        } else {
            None
        };

        let mut modifiers = Vec::new();
        loop {
            match self.parse_class_declaration_modifier() {
                Ok(Some(next_modifier)) => modifiers.push(next_modifier),
                Ok(None) => break,
                Err(error) => {
                    self.report_error(error);
                    break;
                }
            }
        }

        self.expect(Token::Semicolon, ParseErrorKind::ClassMissingSemicolon)?;
        Ok(ClassDeclaration {
            name: class_name,
            parent: parent_class_name.map(|identifier| identifier.head()),
            modifiers,
        })
    }

    fn parse_class_var_decl(&mut self) -> ParseResult<'src, 'arena, ClassVarDeclRef<'src, 'arena>> {
        let start_position = self.expect(
            Token::Keyword(Keyword::Var),
            ParseErrorKind::VarMissingKeyword,
        )?;

        let paren_specs = self.parse_var_editor_specifier_list();
        let modifiers = self.parse_var_declaration_modifiers();
        let type_spec = self.parse_type_specifier()?;
        let declarators = self.parse_class_var_declarators();

        self.expect(Token::Semicolon, ParseErrorKind::DeclMissingSemicolon)?;

        let span = TokenSpan::range(start_position, self.last_consumed_position_or_start());
        Ok(self.arena.alloc_node(
            ClassVarDecl {
                paren_specs,
                modifiers,
                type_spec,
                declarators,
                span,
            },
            span,
        ))
    }

    fn parse_replication_rule(
        &mut self,
    ) -> ParseResult<'src, 'arena, ReplicationRuleRef<'src, 'arena>> {
        let start_position = self.require_position(ParseErrorKind::UnexpectedEndOfFile)?;

        let reliability = match self.peek_token() {
            Some(Token::Keyword(Keyword::Reliable)) => {
                self.advance();
                Reliability::Reliable
            }
            Some(Token::Keyword(Keyword::Unreliable)) => {
                self.advance();
                Reliability::Unreliable
            }
            _ => return Err(self.make_error_at_last_consumed(ParseErrorKind::ReplicationMissingReliability)),
        };

        let condition = if self.eat_keyword(Keyword::If) {
            self.expect(
                Token::LeftParenthesis,
                ParseErrorKind::ReplicationIfMissingOpeningParenthesis,
            )?;
            let expression = self.parse_expression();
            self.expect(
                Token::RightParenthesis,
                ParseErrorKind::ReplicationIfMissingClosingParenthesis,
            )
            .sync_error_at(self, SyncLevel::CloseParenthesis)?;
            Some(expression)
        } else {
            None
        };

        let mut members = self.arena.vec();
        loop {
            let identifier =
                self.parse_identifier(ParseErrorKind::ReplicationMemberNotIdentifier)?;
            members.push(identifier);

            if self.eat(Token::LeftParenthesis) {
                self.expect(
                    Token::RightParenthesis,
                    ParseErrorKind::ReplicationMemberMissingClosingParenthesis,
                )
                .sync_error_at(self, SyncLevel::CloseParenthesis)
                .report_error(self);
            }

            if !self.eat(Token::Comma) {
                break;
            }
        }

        self.expect(
            Token::Semicolon,
            ParseErrorKind::ReplicationRuleMissingSemicolon,
        )?;
        let span = TokenSpan::range(start_position, self.last_consumed_position_or_start());
        Ok(self.arena.alloc_node(
            ReplicationRule {
                reliability,
                condition,
                members,
                span,
            },
            span,
        ))
    }

    fn parse_replication_block(
        &mut self,
    ) -> ParseResult<'src, 'arena, ReplicationBlockRef<'src, 'arena>> {
        let start_position = self.expect(
            Token::Keyword(Keyword::Replication),
            ParseErrorKind::ReplicationMissingKeyword,
        )?;
        self.expect(Token::LeftBrace, ParseErrorKind::ReplicationMissingLBrace)?;

        let mut rules = self.arena.vec();
        while !matches!(self.peek_token(), Some(Token::RightBrace)) {
            let loop_start = self
                .peek_position()
                .unwrap_or_else(|| self.last_consumed_position_or_start());

            if self.peek_token().is_none() {
                return Err(self.make_error_at_last_consumed(ParseErrorKind::UnexpectedEndOfFile));
            }

            match self.parse_replication_rule() {
                Ok(rule) => rules.push(rule),
                Err(error) => {
                    self.report_error(error);
                    self.recover_until(SyncLevel::StatementStart);
                    let _ = self.eat(Token::Semicolon);
                    if !self.ensure_progress_or_break(loop_start) {
                        break;
                    }
                    continue;
                }
            }

            if !self.ensure_progress_or_break(loop_start) {
                break;
            }
        }

        self.expect(Token::RightBrace, ParseErrorKind::ReplicationMissingRBrace)?;
        let span = TokenSpan::range(start_position, self.last_consumed_position_or_start());
        Ok(self
            .arena
            .alloc_node(ReplicationBlock { rules, span }, span))
    }

    fn parse_ignores_clause(
        &mut self,
    ) -> ParseResult<'src, 'arena, Option<crate::arena::ArenaVec<'arena, IdentifierToken>>> {
        if !self.eat_keyword(Keyword::Ignores) {
            return Ok(None);
        }

        let mut identifiers = self.arena.vec();
        loop {
            let identifier = self.parse_identifier(ParseErrorKind::IgnoresItemNotIdentifier)?;
            identifiers.push(identifier);
            if !self.eat(Token::Comma) {
                break;
            }
        }

        self.expect(Token::Semicolon, ParseErrorKind::IgnoresMissingSemicolon)?;
        Ok(Some(identifiers))
    }

    fn parse_state_decl(&mut self) -> ParseResult<'src, 'arena, StateDeclRef<'src, 'arena>> {
        let start_position = self.require_position(ParseErrorKind::UnexpectedEndOfFile)?;

        let mut modifiers = self.arena.vec();
        loop {
            match self.peek_keyword() {
                Some(Keyword::Auto) => {
                    self.advance();
                    modifiers.push(StateModifier::Auto);
                }
                Some(Keyword::Simulated) => {
                    self.advance();
                    modifiers.push(StateModifier::Simulated);
                }
                _ => break,
            }
        }

        self.expect(
            Token::Keyword(Keyword::State),
            ParseErrorKind::StateMissingKeyword,
        )?;

        loop {
            match self.peek_keyword() {
                Some(Keyword::Auto) => {
                    self.advance();
                    modifiers.push(StateModifier::Auto);
                }
                Some(Keyword::Simulated) => {
                    self.advance();
                    modifiers.push(StateModifier::Simulated);
                }
                _ => break,
            }
        }

        if self.eat(Token::LeftParenthesis) {
            self.expect(
                Token::RightParenthesis,
                ParseErrorKind::StateParensMissingRParen,
            )
            .sync_error_at(self, SyncLevel::CloseParenthesis)
            .report_error(self);
        }

        let name = self.parse_identifier(ParseErrorKind::StateNameNotIdentifier)?;
        let parent = if self.eat_keyword(Keyword::Extends) {
            Some(self.parse_identifier(ParseErrorKind::StateParentNameNotIdentifier)?)
        } else {
            None
        };

        let opening_brace_position =
            self.expect(Token::LeftBrace, ParseErrorKind::StateMissingLBrace)?;
        let ignores = self.parse_ignores_clause()?;
        let BlockBody {
            statements: body,
            span: inner_span,
        } = self.parse_braced_block_statements_tail(opening_brace_position);

        let span = TokenSpan::range(start_position, inner_span.end);
        Ok(self.arena.alloc_node(
            StateDecl {
                name,
                parent,
                modifiers,
                ignores,
                body,
                span,
            },
            span,
        ))
    }

    pub(crate) fn parse_class_definition_cont(
        &mut self,
    ) -> ParseResult<'src, 'arena, ClassDefinition<'src, 'arena>> {
        let header = self.parse_class_header_cont()?;
        let mut members = self.arena.vec();

        loop {
            let Some((token, member_start)) = self.peek_token_and_position() else {
                break;
            };

            match token {
                Token::Keyword(Keyword::DefaultProperties) => break,

                _ if self.lookahead_state_after_mods() => {
                    let state = self
                        .parse_state_decl()
                        .widen_error_span_from(member_start)
                        .unwrap_or_fallback(self);
                    let span = *state.span();
                    members.push(self.arena.alloc_node(ClassMember::State(state), span));
                }

                _ if self.is_callable_header_ahead() => {
                    let callable = self.parse_callable_definition();
                    let span = *callable.span();
                    members.push(self.arena.alloc_node(ClassMember::Function(callable), span));
                }

                Token::Keyword(Keyword::Const) => {
                    let constant = self
                        .parse_class_const_decl()
                        .widen_error_span_from(member_start)
                        .unwrap_or_fallback(self);
                    let span = *constant.span();
                    members.push(self.arena.alloc_node(ClassMember::Const(constant), span));
                }

                Token::Keyword(Keyword::Enum)
                    if !matches!(self.peek_token_at(1), Some(Token::LeftBrace)) =>
                {
                    self.advance();
                    let enum_definition = self.parse_enum_definition_tail(member_start);
                    let span = *enum_definition.span();
                    members.push(
                        self.arena
                            .alloc_node(ClassMember::TypeDefEnum(enum_definition), span),
                    );
                    let _ = self.eat(Token::Semicolon);
                }

                Token::Keyword(Keyword::Struct) => {
                    self.advance();
                    let struct_definition = self.parse_struct_definition_tail(member_start);
                    let span = *struct_definition.span();
                    members.push(
                        self.arena
                            .alloc_node(ClassMember::TypeDefStruct(struct_definition), span),
                    );
                    let _ = self.eat(Token::Semicolon);
                }

                Token::Keyword(Keyword::Var) => {
                    let variable_declaration = self
                        .parse_class_var_decl()
                        .widen_error_span_from(member_start)
                        .unwrap_or_fallback(self);
                    let span = *variable_declaration.span();
                    members.push(
                        self.arena
                            .alloc_node(ClassMember::Var(variable_declaration), span),
                    );
                }

                Token::Keyword(Keyword::Replication) => {
                    let replication = self
                        .parse_replication_block()
                        .widen_error_span_from(member_start)
                        .unwrap_or_fallback(self);
                    let span = *replication.span();
                    members.push(
                        self.arena
                            .alloc_node(ClassMember::Replication(replication), span),
                    );
                }

                Token::ExecDirective => {
                    let directive = self
                        .parse_exec_directive()
                        .widen_error_span_from(member_start)
                        .unwrap_or_fallback(self);
                    let span = *directive.span();
                    members.push(self.arena.alloc_node(ClassMember::Exec(directive), span));
                }

                Token::Keyword(Keyword::CppText | Keyword::CppStruct) => {
                    self.advance();
                    if !self.eat(Token::CppBlock) {
                        self.report_error_here(ParseErrorKind::CppDirectiveMissingCppBlock);
                    }
                }

                Token::Keyword(Keyword::Class) => break,

                Token::Semicolon => {
                    self.advance();
                }

                _ => {
                    self.report_error_here(ParseErrorKind::ClassUnexpectedItem);
                    while let Some(next_token) = self.peek_token() {
                        match next_token {
                            Token::Keyword(
                                Keyword::Function
                                | Keyword::Event
                                | Keyword::Enum
                                | Keyword::Struct
                                | Keyword::Var
                                | Keyword::Replication
                                | Keyword::State
                                | Keyword::Class
                                | Keyword::DefaultProperties,
                            ) => break,
                            _ => {
                                self.advance();
                            }
                        }
                    }
                }
            }

            if !self.ensure_progress_or_break(member_start) {
                break;
            }
        }

        Ok(ClassDefinition { header, members })
    }

    pub fn parse_source_file(
        &mut self,
    ) -> ParseResult<'src, 'arena, ClassDefinition<'src, 'arena>> {
        loop {
            match self.peek_token() {
                Some(Token::Semicolon) => {
                    self.advance();
                }
                Some(Token::ExecDirective) => {
                    if let Err(error) = self.parse_exec_directive() {
                        self.report_error(error);
                    }
                }
                //Some(Token::Keyword(Keyword::Class)) | None => break,
                _ => break,
            }
        }

        self.expect(
            Token::Keyword(Keyword::Class),
            ParseErrorKind::ClassMissingKeyword,
        )?;
        let class_definition = self.parse_class_definition_cont()?;

        if matches!(
            self.peek_token(),
            Some(Token::Keyword(Keyword::DefaultProperties))
        ) {
            return Ok(class_definition);
        }

        loop {
            match self.peek_token() {
                Some(Token::Semicolon) => {
                    self.advance();
                }
                Some(_) => {
                    self.report_error_here(ParseErrorKind::ClassUnexpectedItem);
                    while self.peek_token().is_some() {
                        self.advance();
                    }
                    break;
                }
                None => break,
            }
        }

        Ok(class_definition)
    }

    fn decode_signed_integer_literal(&self, s: &str) -> ParseResult<'src, 'arena, i128> {
        let (negative, body) = if let Some(rest) = s.strip_prefix('-') {
            (true, rest)
        } else if let Some(rest) = s.strip_prefix('+') {
            (false, rest)
        } else {
            (false, s)
        };

        let magnitude: u128 = self.decode_unsigned_integer_magnitude(body)?;

        if negative {
            const MIN_MAGNITUDE: u128 = 1u128 << 127;
            if magnitude == MIN_MAGNITUDE {
                Ok(i128::MIN)
            } else {
                let magnitude_as_i128 = i128::try_from(magnitude)
                    .map_err(|_| self.make_error_at_last_consumed(ParseErrorKind::InvalidNumericLiteral))?;
                Ok(-magnitude_as_i128)
            }
        } else {
            i128::try_from(magnitude)
                .map_err(|_| self.make_error_at_last_consumed(ParseErrorKind::InvalidNumericLiteral))
        }
    }

    fn decode_unsigned_integer_magnitude(&self, body: &str) -> ParseResult<'src, 'arena, u128> {
        use ParseErrorKind::InvalidNumericLiteral;

        if body.is_empty() {
            return Err(self.make_error_at_last_consumed(InvalidNumericLiteral));
        }

        let (base, digits) =
            if let Some(rest) = body.strip_prefix("0x").or_else(|| body.strip_prefix("0X")) {
                (16u128, rest)
            } else if let Some(rest) = body.strip_prefix("0b").or_else(|| body.strip_prefix("0B")) {
                (2u128, rest)
            } else if let Some(rest) = body.strip_prefix("0o").or_else(|| body.strip_prefix("0O")) {
                (8u128, rest)
            } else {
                (10u128, body)
            };

        if digits.is_empty() {
            return Err(self.make_error_at_last_consumed(InvalidNumericLiteral));
        }

        let mut accumulator: u128 = 0;
        for character in digits.chars() {
            if character == '_' {
                continue;
            }
            let digit_value = match character {
                '0'..='9' => u128::from(character as u32 - '0' as u32),
                'a'..='f' => u128::from(10 + (character as u32 - 'a' as u32)),
                'A'..='F' => u128::from(10 + (character as u32 - 'A' as u32)),
                _ => return Err(self.make_error_at_last_consumed(InvalidNumericLiteral)),
            };
            if digit_value >= base {
                return Err(self.make_error_at_last_consumed(InvalidNumericLiteral));
            }
            accumulator = accumulator
                .checked_mul(base)
                .and_then(|value| value.checked_add(digit_value))
                .ok_or_else(|| self.make_error_at_last_consumed(InvalidNumericLiteral))?;
        }

        Ok(accumulator)
    }

    fn parse_declaration_literal_class(
        &mut self,
    ) -> ParseResult<'src, 'arena, DeclarationLiteralRef<'src, 'arena>> {
        let (token, lexeme, token_position) =
            self.require_token_lexeme_and_position(ParseErrorKind::UnexpectedEndOfFile)?;

        let literal = match token {
            Token::Plus | Token::Minus => {
                let is_negative = matches!(token, Token::Minus);
                self.advance();

                let (next_token, next_lexeme, token_position) =
                    self.require_token_lexeme_and_position(ParseErrorKind::InvalidNumericLiteral)?;

                match next_token {
                    Token::IntegerLiteral => {
                        let value = if is_negative {
                            self.decode_signed_integer_literal(&format!("-{next_lexeme}"))?
                        } else {
                            self.decode_signed_integer_literal(next_lexeme)?
                        };
                        self.advance();
                        DeclarationLiteral::Integer(value)
                    }
                    Token::FloatLiteral => {
                        let mut signed_lexeme = String::with_capacity(1 + next_lexeme.len());
                        signed_lexeme.push(if is_negative { '-' } else { '+' });
                        signed_lexeme.push_str(next_lexeme);
                        let value = self.decode_float_literal(&signed_lexeme, token_position)?;
                        self.advance();
                        DeclarationLiteral::Float(value)
                    }
                    _ => {
                        return Err(
                            self.make_error_at_last_consumed(ParseErrorKind::DeclarationLiteralUnexpectedToken)
                        );
                    }
                }
            }
            Token::IntegerLiteral => {
                let value = self.decode_signed_integer_literal(lexeme)?;
                self.advance();
                DeclarationLiteral::Integer(value)
            }
            Token::FloatLiteral => {
                let value = self.decode_float_literal(lexeme, token_position)?;
                self.advance();
                DeclarationLiteral::Float(value)
            }
            Token::StringLiteral => {
                let value = self.unescape_string_literal(lexeme);
                self.advance();
                DeclarationLiteral::String(value)
            }
            Token::Keyword(Keyword::True) => {
                self.advance();
                DeclarationLiteral::Bool(true)
            }
            Token::Keyword(Keyword::False) => {
                self.advance();
                DeclarationLiteral::Bool(false)
            }
            Token::Keyword(Keyword::None) => {
                self.advance();
                DeclarationLiteral::None
            }
            Token::NameLiteral => {
                let inner = &lexeme[1..lexeme.len() - 1];
                let value = self.arena.string(inner);
                self.advance();
                DeclarationLiteral::String(value)
            }
            Token::Keyword(Keyword::Class) => {
                self.advance();
                let (next_token, next_lexeme, _) = self.require_token_lexeme_and_position(
                    ParseErrorKind::DeclarationLiteralUnexpectedToken,
                )?;
                if !matches!(next_token, Token::NameLiteral) {
                    return Err(
                        self.make_error_at_last_consumed(ParseErrorKind::DeclarationLiteralUnexpectedToken)
                    );
                }
                let inner = &next_lexeme[1..next_lexeme.len() - 1];
                let quoted_name = self.arena.string(inner);
                self.advance();
                DeclarationLiteral::TaggedName {
                    tag: IdentifierToken(token_position),
                    quoted: quoted_name,
                }
            }
            _ if token.is_valid_identifier_name() => {
                self.advance();
                DeclarationLiteral::Identifier(lexeme)
            }
            _ => return Err(self.make_error_at_last_consumed(ParseErrorKind::ExpressionUnexpectedToken)),
        };

        Ok(DeclarationLiteralRef {
            literal,
            position: token_position,
        })
    }

    fn parse_class_const_decl(
        &mut self,
    ) -> ParseResult<'src, 'arena, ClassConstDeclRef<'src, 'arena>> {
        let start_position = self.expect(
            Token::Keyword(Keyword::Const),
            ParseErrorKind::ClassUnexpectedItem,
        )?;

        let name = self.parse_identifier(ParseErrorKind::VariableDeclaratorBadIdentifier)?;
        self.expect(Token::Assign, ParseErrorKind::NamedTypeInvalidName)?;
        let value = self.parse_declaration_literal_class()?;

        self.expect(Token::Semicolon, ParseErrorKind::DeclMissingSemicolon)?;
        let span = TokenSpan::range(start_position, self.last_consumed_position_or_start());

        Ok(self
            .arena
            .alloc_node(ClassConstDecl { name, value, span }, span))
    }

    fn parse_class_var_declarators(
        &mut self,
    ) -> crate::arena::ArenaVec<'arena, VariableDeclaratorRef<'src, 'arena>> {
        let mut declarators = self.arena.vec();

        loop {
            match self.peek_token_and_position() {
                Some((next_token, declarator_start)) if next_token.is_valid_identifier_name() => {
                    let identifier = self
                        .parse_identifier(ParseErrorKind::VariableDeclaratorBadIdentifier)
                        .unwrap_or(IdentifierToken(declarator_start));

                    let array_size = match self.parse_array_len_expr() {
                        Ok(value) => value,
                        Err(error) => {
                            self.report_error(error);
                            self.recover_until(SyncLevel::CloseBracket);
                            let _ = self.eat(Token::RightBracket);
                            None
                        }
                    };

                    let span =
                        TokenSpan::range(identifier.0, self.last_consumed_position_or_start());
                    declarators.push(self.arena.alloc_node(
                        VariableDeclarator {
                            name: identifier,
                            initializer: None,
                            array_size,
                        },
                        span,
                    ));

                    if self.eat(Token::Comma) {
                        if self.peek_token() == Some(Token::Semicolon) {
                            break;
                        }
                        continue;
                    }
                    break;
                }
                Some((_, _)) if declarators.is_empty() => {
                    self.report_error_here(ParseErrorKind::VariableDeclaratorBadIdentifier);
                    self.recover_until(SyncLevel::StatementStart);
                    let _ = self.eat(Token::Semicolon);
                    break;
                }
                _ => break,
            }
        }

        declarators
    }

    pub(crate) fn parse_identifier_list(
        &mut self,
    ) -> crate::arena::ArenaVec<'arena, IdentifierToken> {
        let list_start = self.last_consumed_position_or_start();
        let mut identifiers = self.arena.vec();

        while let Some((token, _lexeme, identifier_position)) =
            self.peek_token_lexeme_and_position()
        {
            match token {
                Token::RightParenthesis => break,
                Token::Comma => {
                    self.advance();
                    self.report_error_here(ParseErrorKind::ListMissingIdentifierBeforeSeparator);
                }
                _ if token.is_valid_identifier_name() => {
                    self.advance();
                    identifiers.push(IdentifierToken(identifier_position));
                    if !self.eat(Token::Comma)
                        && let Some(next_token) = self.peek_token()
                        && next_token != Token::RightParenthesis
                    {
                        self.report_error_here(ParseErrorKind::ListMissingSeparator);
                    }
                }
                _ => {
                    self.make_error_at_last_consumed(ParseErrorKind::ListInvalidIdentifier)
                        .sync_error_until(self, SyncLevel::ListSeparator)
                        .report_error(self);
                }
            }
        }

        if identifiers.is_empty() {
            let list_end = self.last_consumed_position_or_start();
            self.report_error(crate::parser::ParseError {
                kind: ParseErrorKind::ListEmpty,
                anchor: list_start,
                blame_span: TokenSpan::range(list_start, list_end),
                covered_span: TokenSpan::range(list_start, list_end),
                related_spans: HashMap::new(),
                flags: HashSet::new(),
            });
        }

        identifiers
    }
}
