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)))
}