use crate::parser::{
parse_block,
parse_block_with_end,
try_parse_expression,
OptionParsingResult,
ParsingError,
};
use crate::parser::token_utils::{
is_one_of_keywords,
skip_first_token_if_is_keyword,
LuaKeyword,
};
use crate::parser::node_types::NodeTypes;
use lualexer::Token;
use std::marker::PhantomData;
pub fn try_parse_if_statement<'a, T: NodeTypes>(
tokens: &'a [Token<'a>]
) -> OptionParsingResult<'a, T::Statement> {
if let Some(after_if_tokens) = skip_first_token_if_is_keyword(tokens, LuaKeyword::If) {
let (condition, after_condition_tokens) = try_parse_expression::<T>(after_if_tokens)?
.ok_or(ParsingError::ConditionExpectedForIfStatement)?;
let after_then_tokens = skip_first_token_if_is_keyword(after_condition_tokens, LuaKeyword::Then)
.ok_or(ParsingError::ThenKeywordExpectedForIfStatement)?;
let ((block, last_token), after_block_tokens) = parse_block_with_end(
PhantomData::<T>,
after_then_tokens,
|token| is_one_of_keywords(token, &[
LuaKeyword::End,
LuaKeyword::Elseif,
LuaKeyword::Else,
])
)?;
let mut branches = vec![(condition, block)];
let mut next_tokens = after_block_tokens;
let mut last_token = last_token;
while last_token.get_content() == "elseif" {
let (condition, after_condition_tokens) = try_parse_expression::<T>(next_tokens)?
.ok_or(ParsingError::ConditionExpectedForElseIfClause)?;
let after_then_tokens = skip_first_token_if_is_keyword(after_condition_tokens, LuaKeyword::Then)
.ok_or(ParsingError::ThenKeywordExpectedForElseifClause)?;
let ((block, block_end_token), after_block_tokens) = parse_block_with_end(
PhantomData::<T>,
after_then_tokens,
|token| is_one_of_keywords(token, &[
LuaKeyword::End,
LuaKeyword::Elseif,
LuaKeyword::Else,
])
)?;
next_tokens = after_block_tokens;
last_token = block_end_token;
branches.push((condition, block))
}
let else_block = if last_token.get_content() == "else" {
let (block, after_block_tokens) = parse_block::<T>(next_tokens, LuaKeyword::End)?;
next_tokens = after_block_tokens;
Some(block)
} else {
None
};
let if_statement = T::IfStatement::from((branches, else_block));
Ok(Some((if_statement.into(), next_tokens)))
} else {
Ok(None)
}
}