luaparser 0.1.1

Read Lua 5.1 code and produce an abstract syntax tree
Documentation
use crate::parser::{
    parse_statement,
    try_parse_last_statement,
    ParsingError,
    ParsingResult,
};
use crate::parser::token_utils::{
    is_keyword,
    skip_first_token,
    skip_first_token_if_is_symbol,
    LuaKeyword,
    LuaSymbol,
};
use crate::parser::node_types::NodeTypes;
use std::marker::PhantomData;

use lualexer::Token;

pub fn parse_block<'a, T: NodeTypes>(tokens: &'a [Token<'a>], keyword: LuaKeyword) -> ParsingResult<'a, T::Block> {
    parse_block_with_end(PhantomData::<T>, tokens, |token| is_keyword(token, keyword))
        .map(|((block, _last_token), tokens)| (block, tokens))
}

pub fn parse_block_with_end<'a, T: NodeTypes, F>(
    _: PhantomData<T>,
    tokens: &'a [Token<'a>],
    is_end_of_block: F,
) -> ParsingResult<'a, (T::Block, &'a Token<'a>)>
    where F: Fn(&Token) -> bool
{
    let mut statements = vec!();
    let mut current_tokens = tokens;

    while let Some(token) = current_tokens.first() {
        if is_end_of_block(token) {
            let block = T::Block::from((statements, None));

            return Ok(((block, token), skip_first_token(current_tokens)));
        }

        if let Some((last_statement, mut next_tokens)) = try_parse_last_statement::<T>(current_tokens)? {
            next_tokens = skip_first_token_if_is_symbol(next_tokens, LuaSymbol::SemiColon)
                .unwrap_or(next_tokens);
            let block = T::Block::from((statements, Some(last_statement)));

            if let Some(next_token) = next_tokens.first() {
                if is_end_of_block(next_token) {
                    return Ok(((block, next_token), skip_first_token(next_tokens)));
                } else {
                    return Err(ParsingError::EndOfBlockExpectedAfterLastStatement)
                }
            } else {
                return Err(ParsingError::TokenExpectedToCloseBlock)
            }
        }

        let (statement, next_tokens) = parse_statement::<T>(current_tokens)?;
        statements.push(statement);
        current_tokens = skip_first_token_if_is_symbol(next_tokens, LuaSymbol::SemiColon)
            .unwrap_or(next_tokens);
    };

    Err(ParsingError::TokenExpectedToCloseBlock)
}