mathlex 0.4.1

Mathematical expression parser for LaTeX and plain text notation, producing a language-agnostic AST
Documentation
//! Expression and logical operator parsing for the text parser.

use super::*;

impl TextParser {
    pub(super) fn parse_expression(&mut self) -> ParseResult<Expression> {
        self.parse_logical()
    }

    pub(super) fn parse_logical(&mut self) -> ParseResult<Expression> {
        if let Some(token) = self.peek() {
            if matches!(token.value, Token::Not) {
                self.next();
                let operand = self.parse_logical()?;
                return Ok(ExprKind::Logical {
                    op: LogicalOp::Not,
                    operands: vec![operand],
                }
                .into());
            }
        }
        let mut left = self.parse_quantifier()?;
        while let Some(token) = self.peek() {
            let op = match &token.value {
                Token::Iff => LogicalOp::Iff,
                Token::Implies => LogicalOp::Implies,
                Token::Or => LogicalOp::Or,
                Token::And => LogicalOp::And,
                _ => break,
            };
            self.next();
            let right = self.parse_quantifier()?;
            left = ExprKind::Logical {
                op,
                operands: vec![left, right],
            }
            .into();
        }
        Ok(left)
    }

    pub(super) fn parse_quantifier(&mut self) -> ParseResult<Expression> {
        if let Some(token) = self.peek() {
            match &token.value {
                Token::ForAll => {
                    self.next();
                    return self.parse_quantifier_body(false);
                }
                Token::Exists => {
                    self.next();
                    return self.parse_quantifier_body(true);
                }
                _ => {}
            }
        }
        self.parse_set_operation()
    }

    /// Parses the body of a quantifier: variable [in domain], body
    pub(super) fn parse_quantifier_body(&mut self, is_exists: bool) -> ParseResult<Expression> {
        let variable = if let Some(token) = self.peek() {
            if let Token::Identifier(name) = &token.value {
                let var = name.clone();
                self.next();
                var
            } else {
                return Err(ParseError::unexpected_token(
                    vec!["variable"],
                    format!("{}", token.value),
                    Some(token.span),
                ));
            }
        } else {
            return Err(ParseError::unexpected_eof(
                vec!["variable"],
                Some(self.current_span()),
            ));
        };

        let domain = if let Some(token) = self.peek() {
            if matches!(token.value, Token::In) {
                self.next();
                Some(Box::new(self.parse_set_operation()?))
            } else {
                None
            }
        } else {
            None
        };

        self.consume(Token::Comma)?;
        let body = Box::new(self.parse_logical()?);

        if is_exists {
            Ok(ExprKind::Exists {
                variable,
                domain,
                body,
                unique: false,
            }
            .into())
        } else {
            Ok(ExprKind::ForAll {
                variable,
                domain,
                body,
            }
            .into())
        }
    }
}