//! Lookahead for callable headers in Fermented UnrealScript.

use crate::lexer::{Keyword, Token};
use crate::parser::Parser;

impl Parser<'_, '_> {
    /// Returns whether the upcoming tokens have the syntactic shape of
    /// a callable header.
    ///
    /// Returns `true` when the following tokens consist of zero or more
    /// callable modifiers followed by a keyword that defines a callable kind.
    ///
    /// Does not check whether any parenthesized arguments are valid.
    #[must_use]
    pub(crate) fn is_callable_header_ahead(&mut self) -> bool {
        let mut lookahead_offset = 0;
        while let Some(keyword) = self.peek_keyword_at(lookahead_offset) {
            if keyword.is_callable_kind_keyword() {
                return true;
            }
            if let Some(token_width) = self.callable_modifier_width_at(keyword, lookahead_offset) {
                lookahead_offset += token_width;
            } else {
                break;
            }
        }
        false
    }

    fn callable_modifier_width_at(
        &mut self,
        keyword: Keyword,
        lookahead_token_offset: usize,
    ) -> Option<usize> {
        if !keyword.is_callable_modifier() {
            return None;
        }

        if matches!(keyword, Keyword::Native | Keyword::Config)
            && self.peek_token_at(lookahead_token_offset + 1) == Some(Token::LeftParenthesis)
            && self.peek_token_at(lookahead_token_offset + 3) == Some(Token::RightParenthesis)
        {
            // `native(...)` and `config(...)` consume a parenthesized specifier
            // in modifier position, so lookahead must skip the whole modifier.
            Some(4)
        } else {
            Some(1)
        }
    }
}
