haz-query-lang 0.2.0

Parser and AST for the haz task query language.
Documentation
//! Errors produced by the filter-expression parser.

use snafu::Snafu;

/// A parse failure produced by [`crate::parser::parse`].
///
/// Variants describe shape-level problems only: the empty input,
/// unmatched parens, operators in disallowed positions, and
/// trailing characters after a complete expression. Atom-content
/// validation (identifier rules, path-pattern grammar, relational
/// kind) is the consumer crate's responsibility.
#[derive(Debug, Clone, PartialEq, Eq, Snafu)]
pub enum ParseError {
    /// The input contained no atoms after trimming whitespace.
    #[snafu(display("filter expression is empty"))]
    EmptyExpression,

    /// An atom was expected at the given byte offset but the
    /// next character was an operator or end-of-input.
    #[snafu(display("expected atom at byte {position}"))]
    ExpectedAtom {
        /// Byte offset where the atom was expected.
        position: usize,
    },

    /// An operator appeared in a position the grammar does not
    /// permit (for example, as the leading character of an
    /// expression, or immediately after another binary operator).
    #[snafu(display("unexpected operator '{op}' at byte {position}"))]
    UnexpectedOperator {
        /// The offending operator byte.
        op: char,
        /// Byte offset at which it appears.
        position: usize,
    },

    /// Unconsumed input remained after a complete expression was
    /// parsed (typically a missing operator between two atoms).
    #[snafu(display("unexpected character '{ch}' at byte {position}"))]
    UnexpectedChar {
        /// The offending character.
        ch: char,
        /// Byte offset at which it appears.
        position: usize,
    },

    /// An opening parenthesis was never matched by a closing one.
    #[snafu(display("unmatched '(' at byte {position}"))]
    UnmatchedOpenParen {
        /// Byte offset of the unmatched opener.
        position: usize,
    },

    /// A closing parenthesis appeared with no matching opener.
    #[snafu(display("unmatched ')' at byte {position}"))]
    UnmatchedCloseParen {
        /// Byte offset of the unmatched closer.
        position: usize,
    },
}