linkrs-query 0.1.0

Query engine, parser, and executor for Linkrs
Documentation
use super::unary::{parse_not_expression, parse_unary_expression};
use super::{parse_postfix_expression, ParseResult};
use crate::parser::core::error::ParseError;
use crate::parser::parsing::parse_context::ParseContext;
use crate::parser::TokenKind;
use linkrs_core::types::expr::Expression;
use linkrs_core::types::operators::BinaryOperator;

pub(crate) fn parse_or_expression(ctx: &mut ParseContext<'_>) -> Result<ParseResult, ParseError> {
    let mut left = parse_and_expression(ctx)?;

    while ctx.match_token(TokenKind::Or) {
        let op = BinaryOperator::Or;
        let right = parse_and_expression(ctx)?;
        let span = ctx.merge_span(left.span.start, right.span.end);
        left = ParseResult {
            expr: Expression::binary(left.expr, op, right.expr),
            span,
        };
    }

    Ok(left)
}

pub(crate) fn parse_and_expression(ctx: &mut ParseContext<'_>) -> Result<ParseResult, ParseError> {
    let mut left = parse_not_expression(ctx)?;

    while ctx.match_token(TokenKind::And) {
        let op = BinaryOperator::And;
        let right = parse_not_expression(ctx)?;
        let span = ctx.merge_span(left.span.start, right.span.end);
        left = ParseResult {
            expr: Expression::binary(left.expr, op, right.expr),
            span,
        };
    }

    Ok(left)
}

pub(crate) fn parse_comparison_expression(
    ctx: &mut ParseContext<'_>,
) -> Result<ParseResult, ParseError> {
    let mut left = parse_bitwise_expression(ctx)?;

    if let Some(op) = parse_comparison_op(ctx) {
        let right = parse_additive_expression(ctx)?;
        let span = ctx.merge_span(left.span.start, right.span.end);
        left = ParseResult {
            expr: Expression::binary(left.expr, op, right.expr),
            span,
        };
    }

    Ok(left)
}

pub(crate) fn parse_comparison_op(ctx: &mut ParseContext<'_>) -> Option<BinaryOperator> {
    match ctx.current_token().kind {
        TokenKind::Eq | TokenKind::Assign => {
            ctx.next_token();
            Some(BinaryOperator::Equal)
        }
        TokenKind::Ne => {
            ctx.next_token();
            Some(BinaryOperator::NotEqual)
        }
        TokenKind::Lt => {
            ctx.next_token();
            Some(BinaryOperator::LessThan)
        }
        TokenKind::Le => {
            ctx.next_token();
            Some(BinaryOperator::LessThanOrEqual)
        }
        TokenKind::Gt => {
            ctx.next_token();
            Some(BinaryOperator::GreaterThan)
        }
        TokenKind::Ge => {
            ctx.next_token();
            Some(BinaryOperator::GreaterThanOrEqual)
        }
        TokenKind::Regex => {
            ctx.next_token();
            Some(BinaryOperator::Like)
        }
        TokenKind::Contains => {
            ctx.next_token();
            Some(BinaryOperator::Contains)
        }
        TokenKind::StartsWith => {
            ctx.next_token();
            ctx.match_token(TokenKind::With);
            Some(BinaryOperator::StartsWith)
        }
        TokenKind::EndsWith => {
            ctx.next_token();
            ctx.match_token(TokenKind::With);
            Some(BinaryOperator::EndsWith)
        }
        _ => None,
    }
}

pub(crate) fn parse_bitwise_expression(
    ctx: &mut ParseContext<'_>,
) -> Result<ParseResult, ParseError> {
    let mut left = parse_additive_expression(ctx)?;

    while let Some(op) = parse_bitwise_op(ctx) {
        let right = parse_additive_expression(ctx)?;
        let span = ctx.merge_span(left.span.start, right.span.end);
        left = ParseResult {
            expr: Expression::binary(left.expr, op, right.expr),
            span,
        };
    }

    Ok(left)
}

pub(crate) fn parse_bitwise_op(ctx: &mut ParseContext<'_>) -> Option<BinaryOperator> {
    match ctx.current_token().kind {
        TokenKind::Pipe => {
            if ctx.is_pipe_or_suppressed() {
                return None;
            }
            ctx.next_token();
            Some(BinaryOperator::BitwiseOr)
        }
        TokenKind::Ampersand => {
            ctx.next_token();
            Some(BinaryOperator::BitwiseAnd)
        }
        TokenKind::ShiftLeft => {
            ctx.next_token();
            Some(BinaryOperator::ShiftLeft)
        }
        TokenKind::ShiftRight => {
            ctx.next_token();
            Some(BinaryOperator::ShiftRight)
        }
        _ => None,
    }
}

pub(crate) fn parse_additive_expression(
    ctx: &mut ParseContext<'_>,
) -> Result<ParseResult, ParseError> {
    let mut left = parse_multiplicative_expression(ctx)?;

    while let Some(op) = parse_additive_op(ctx) {
        let right = parse_multiplicative_expression(ctx)?;
        let span = ctx.merge_span(left.span.start, right.span.end);
        left = ParseResult {
            expr: Expression::binary(left.expr, op, right.expr),
            span,
        };
    }

    Ok(left)
}

pub(crate) fn parse_additive_op(ctx: &mut ParseContext<'_>) -> Option<BinaryOperator> {
    match ctx.current_token().kind {
        TokenKind::Plus => {
            ctx.next_token();
            Some(BinaryOperator::Add)
        }
        TokenKind::Minus => {
            ctx.next_token();
            Some(BinaryOperator::Subtract)
        }
        _ => None,
    }
}

pub(crate) fn parse_multiplicative_expression(
    ctx: &mut ParseContext<'_>,
) -> Result<ParseResult, ParseError> {
    let mut left = parse_unary_expression(ctx)?;

    while let Some(op) = parse_multiplicative_op(ctx) {
        let right = parse_unary_expression(ctx)?;
        let span = ctx.merge_span(left.span.start, right.span.end);
        left = ParseResult {
            expr: Expression::binary(left.expr, op, right.expr),
            span,
        };
    }

    Ok(left)
}

pub(crate) fn parse_multiplicative_op(ctx: &mut ParseContext<'_>) -> Option<BinaryOperator> {
    match ctx.current_token().kind {
        TokenKind::Star => {
            ctx.next_token();
            Some(BinaryOperator::Multiply)
        }
        TokenKind::Div => {
            ctx.next_token();
            Some(BinaryOperator::Divide)
        }
        TokenKind::Mod => {
            ctx.next_token();
            Some(BinaryOperator::Modulo)
        }
        _ => None,
    }
}

pub(crate) fn parse_exponentiation_expression(
    ctx: &mut ParseContext<'_>,
) -> Result<ParseResult, ParseError> {
    let mut expression = parse_postfix_expression(ctx)?;

    if ctx.match_token(TokenKind::Exp) {
        let mut right_operands = Vec::new();

        while ctx.match_token(TokenKind::Exp) {
            right_operands.push(parse_unary_expression(ctx)?);
        }

        for operand in right_operands.into_iter().rev() {
            let span = ctx.merge_span(expression.span.start, operand.span.end);
            expression = ParseResult {
                expr: Expression::binary(expression.expr, BinaryOperator::Exponent, operand.expr),
                span,
            };
        }
    }

    Ok(expression)
}