//! Statement parsing for the language front-end.
//!
//! Implements a simple recursive-descent parser for
//! *Fermented `UnrealScript` statements*.

use crate::ast::{Statement, StatementRef};
use crate::lexer::{Keyword, Token, TokenSpan};
use crate::parser::{ParseErrorKind, ResultRecoveryExt};

impl<'src, 'arena> crate::parser::Parser<'src, 'arena> {
    /// Parses a single statement.
    ///
    /// Does not consume a trailing `;` except for [`Statement::Empty`].
    /// The caller handles semicolons (WRONG NOW - WE MUST HANDLE THEM). Returns [`Some`] if a statement is
    /// recognized; otherwise [`None`].
    /// ALSO WE SPECIFICALLY DONT HANDLE EXPRESSION TYPE STATEMENTS
    #[must_use]
    pub(crate) fn parse_statement(&mut self) -> Option<StatementRef<'src, 'arena>> {
        let Some((token, lexeme, position)) = self.peek_token_lexeme_and_position() else {
            self.report_error_here(ParseErrorKind::UnexpectedEndOfFile);
            return None;
        };

        match token {
            // Empty statement
            Token::Semicolon => {
                self.advance(); // `;`
                Some(
                    self.arena
                        .alloc_node(Statement::Empty, TokenSpan::new(position)),
                )
            }

            // UnrealScript `local` declaration
            Token::Keyword(Keyword::Local) => {
                self.advance(); // `local`
                let start = position;

                let type_spec = self.parse_type_specifier().unwrap_or_fallback(self);
                let declarators = self.parse_variable_declarators();
                // TODO: parse

                let span = TokenSpan::range(start, self.last_consumed_position_or_start());
                Some(self.arena.alloc_node(
                    Statement::LocalVariableDeclaration {
                        type_spec,
                        declarators,
                    },
                    span,
                ))
            }

            // Label: Ident ':'  (also tolerate Begin:/End:)
            Token::Identifier | Token::Keyword(Keyword::Begin | Keyword::End)
                if matches!(self.peek_token_at(1), Some(Token::Colon)) =>
            {
                self.advance(); // ident/begin/end
                self.advance(); // :
                Some(self.arena.alloc_node(
                    Statement::Label(self.arena.string(lexeme)),
                    TokenSpan::range(position, self.last_consumed_position_or_start()),
                ))
            }

            // Nested function/event/operator inside blocks
            t if t == Token::Keyword(Keyword::Function)
                || t == Token::Keyword(Keyword::Event)
                || t.is_valid_function_modifier() =>
            {
                let f = self.parse_callable_definition();

                let span = *f.span();
                Some(self.arena.alloc_node(Statement::Function(f), span))
            }

            // C-like variable declaration starting with a TypeSpec
            /*token if self.looks_like_variable_declaration_start(token) => Some(
                self.parse_variable_declaration_start()
                    .sync_error_until(self, SyncLevel::Statement)
                    .unwrap_or_fallback(self),
            ),*/
            // Not a statement
            _ => None,
        }
    }
}
