luaparser 0.1.1

Read Lua 5.1 code and produce an abstract syntax tree
Documentation
use crate::parser::{
    parse_expression_list,
    parse_function_body,
    OptionParsingResult,
    ParsingError,
};
use crate::parser::token_utils::{
    skip_first_token,
    skip_first_token_if_is_keyword,
    skip_first_token_if_is_symbol,
    LuaKeyword,
    LuaSymbol,
};
use crate::parser::node_types::NodeTypes;

use lualexer::{Token, TokenType};

pub fn try_parse_local_assign_or_function<'a, T: NodeTypes>(
    tokens: &'a [Token<'a>]
) -> OptionParsingResult<'a, T::Statement> {
    if let Some(after_local_tokens) = skip_first_token_if_is_keyword(tokens, LuaKeyword::Local) {
        if let Some(after_function_tokens) = skip_first_token_if_is_keyword(after_local_tokens, LuaKeyword::Function) {
            let identifier = after_function_tokens.first()
                .filter(|token| token.is_type(TokenType::Identifier))
                .map(Token::get_content)
                .ok_or(ParsingError::IdentifierExpectedAfterForKeyword)?;

            let (values, next_tokens) = parse_function_body::<T>(skip_first_token(after_function_tokens))?;
            let (parameters, is_variadic, block) = values;

            let statement = T::LocalFunctionStatement::from((
                identifier.to_owned(),
                parameters,
                is_variadic,
                block,
            ));

            Ok(Some((statement.into(), next_tokens)))
        } else {
            let first_variable = after_local_tokens.first()
                .filter(|token| token.is_type(TokenType::Identifier))
                .map(Token::get_content)
                .ok_or(ParsingError::IdentifierExpectedForLocalAssign)?;

            let mut variables = vec![first_variable.to_owned()];
            let mut next_tokens = skip_first_token(after_local_tokens);

            while let Some(after_comma_tokens) = skip_first_token_if_is_symbol(next_tokens, LuaSymbol::Comma) {
                let identifier = after_comma_tokens.first()
                    .filter(|token| token.is_type(TokenType::Identifier))
                    .map(Token::get_content)
                    .ok_or(ParsingError::IdentifierExpectedForLocalAssign)?;

                variables.push(identifier.to_owned());
                next_tokens = skip_first_token(after_comma_tokens);
            }

            let (values, next_tokens) = skip_first_token_if_is_symbol(next_tokens, LuaSymbol::Assign)
                .map(|tokens| parse_expression_list::<T>(tokens))
                .unwrap_or_else(|| Ok((Vec::new(), next_tokens)))?;

            let statement = T::LocalAssignStatement::from((variables, values));

            Ok(Some((statement.into(), next_tokens)))
        }
    } else {
        Ok(None)
    }
}