luaparser 0.1.1

Read Lua 5.1 code and produce an abstract syntax tree
Documentation
use crate::parser::{
    try_parse_single_expression,
    ParsingResult,
    ParsingError,
};
use crate::parser::token_utils::skip_first_token;
use crate::parser::node_types::NodeTypes;
use crate::parser::node_types::builders::BinaryOperator;

use lualexer::{Token, TokenType};

const BINARY_OPERATOR_OR_PRECEDENCE: usize = 1;
const BINARY_OPERATOR_AND_PRECEDENCE: usize = 2;
const BINARY_OPERATOR_EQUAL_PRECEDENCE: usize = 3;
const BINARY_OPERATOR_NOT_EQUAL_PRECEDENCE: usize = 3;
const BINARY_OPERATOR_LESS_PRECEDENCE: usize = 3;
const BINARY_OPERATOR_LESS_OR_EQUAL_PRECEDENCE: usize = 3;
const BINARY_OPERATOR_GREATER_PRECEDENCE: usize = 3;
const BINARY_OPERATOR_GREATER_OR_EQUAL_PRECEDENCE: usize = 3;
const BINARY_OPERATOR_CONCAT_PRECEDENCE: usize = 4;
const BINARY_OPERATOR_PLUS_PRECEDENCE: usize = 5;
const BINARY_OPERATOR_MINUS_PRECEDENCE: usize = 5;
const BINARY_OPERATOR_ASTERISK_PRECEDENCE: usize = 6;
const BINARY_OPERATOR_SLASH_PRECEDENCE: usize = 6;
const BINARY_OPERATOR_PERCENT_PRECEDENCE: usize = 6;
const BINARY_OPERATOR_CARET_PRECEDENCE: usize = 8;

pub fn parse_right_expression<'a, T: NodeTypes>(
    mut left: T::Expression,
    mut tokens: &'a [Token<'a>],
    minimum_precedence: usize,
) -> ParsingResult<'a, T::Expression> {

    while let Some(first_operator) = try_parse_binary_operator::<T>(tokens) {

        let (operator, first_precedence, after_first_op_tokens) = first_operator;

        if first_precedence < minimum_precedence {
            return Ok((left, tokens))
        }

        let next_expression = try_parse_single_expression::<T>(after_first_op_tokens)?;

        if let Some((mut right, mut next_expression_tokens)) = next_expression {

            while let Some(next_operator) = try_parse_binary_operator::<T>(next_expression_tokens) {

                let (operator, precedence, _tokens) = next_operator;

                if precedence <= first_precedence {
                    if operator == T::BinaryOperator::caret()
                    || operator == T::BinaryOperator::concat() {
                        if precedence < first_precedence {
                            break
                        }
                    } else {
                        break
                    }
                }

                let result = parse_right_expression::<T>(right, next_expression_tokens, precedence)?;
                right = result.0;
                next_expression_tokens = result.1;
            }

            tokens = next_expression_tokens;
            left = T::BinaryExpression::from((left, operator, right)).into();

        } else {
            return Err(ParsingError::RightExpressionExpected)
        }
    }

    Ok((left, tokens))
}

fn try_parse_binary_operator<'a, T: NodeTypes>(
    tokens: &'a [Token<'a>]
) -> Option<(T::BinaryOperator, usize, &'a [Token<'a>])> {
    tokens.first()
        .and_then(|next_token| match (next_token.get_type(), next_token.get_content()) {
            (TokenType::Keyword, "and") => Some((
                T::BinaryOperator::and(),
                BINARY_OPERATOR_AND_PRECEDENCE
            )),
            (TokenType::Keyword, "or") => Some((
                T::BinaryOperator::or(),
                BINARY_OPERATOR_OR_PRECEDENCE
            )),
            (TokenType::Symbol, "==") => Some((
                T::BinaryOperator::equal(),
                BINARY_OPERATOR_EQUAL_PRECEDENCE
            )),
            (TokenType::Symbol, "~=") => Some((
                T::BinaryOperator::not_equal(),
                BINARY_OPERATOR_NOT_EQUAL_PRECEDENCE
            )),
            (TokenType::Symbol, "<") => Some((
                T::BinaryOperator::lower_than(),
                BINARY_OPERATOR_LESS_PRECEDENCE
            )),
            (TokenType::Symbol, "<=") => Some((
                T::BinaryOperator::lower_or_equal_than(),
                BINARY_OPERATOR_LESS_OR_EQUAL_PRECEDENCE
            )),
            (TokenType::Symbol, ">") => Some((
                T::BinaryOperator::greather_than(),
                BINARY_OPERATOR_GREATER_PRECEDENCE
            )),
            (TokenType::Symbol, ">=") => Some((
                T::BinaryOperator::greather_or_equal_than(),
                BINARY_OPERATOR_GREATER_OR_EQUAL_PRECEDENCE
            )),
            (TokenType::Symbol, "+") => Some((
                T::BinaryOperator::plus(),
                BINARY_OPERATOR_PLUS_PRECEDENCE
            )),
            (TokenType::Symbol, "-") => Some((
                T::BinaryOperator::minus(),
                BINARY_OPERATOR_MINUS_PRECEDENCE
            )),
            (TokenType::Symbol, "*") => Some((
                T::BinaryOperator::asterisk(),
                BINARY_OPERATOR_ASTERISK_PRECEDENCE
            )),
            (TokenType::Symbol, "/") => Some((
                T::BinaryOperator::slash(),
                BINARY_OPERATOR_SLASH_PRECEDENCE
            )),
            (TokenType::Symbol, "%") => Some((
                T::BinaryOperator::percent(),
                BINARY_OPERATOR_PERCENT_PRECEDENCE
            )),
            (TokenType::Symbol, "^") => Some((
                T::BinaryOperator::caret(),
                BINARY_OPERATOR_CARET_PRECEDENCE
            )),
            (TokenType::Symbol, "..") => Some((
                T::BinaryOperator::concat(),
                BINARY_OPERATOR_CONCAT_PRECEDENCE
            )),
            _ => None
        })
        .map(|(operator, precedence)| (operator, precedence, skip_first_token(tokens)))
}