src/filter/dsl/ast/mod.rs

//! AST types for the filter DSL.
//!
//! See the documentation at <https://mercemay.top/src/ripgrab/> for an overview
//! of how these nodes map back to the source grammar.

pub mod display;

/// The comparison operator used in a [`Expr::Compare`] node.
#[derive(Debug, Clone, Copy, PartialEq, Eq)]
pub enum Cmp {
    Eq,
    Ne,
    Lt,
    Le,
    Gt,
    Ge,
    Match,
}

/// A literal value on the right-hand side of a comparison.
#[derive(Debug, Clone, PartialEq, Eq)]
pub enum Value {
    Str(String),
    Int(i64),
    Regex(String),
}

/// A parsed expression tree.
#[derive(Debug, Clone, PartialEq, Eq)]
pub enum Expr {
    Compare {
        field: String,
        op: Cmp,
        value: Value,
    },
    And(Box<Expr>, Box<Expr>),
    Or(Box<Expr>, Box<Expr>),
    Not(Box<Expr>),
}

impl Expr {
    /// Walk every subtree and return the set of field names referenced.
    ///
    /// Used by the compiler to check whether a filter needs JSON body parsing
    /// or can be evaluated directly against the raw line.
    pub fn fields(&self) -> Vec<&str> {
        let mut out = Vec::new();
        fn walk<'a>(expr: &'a Expr, out: &mut Vec<&'a str>) {
            match expr {
                Expr::Compare { field, .. } => out.push(field.as_str()),
                Expr::And(l, r) | Expr::Or(l, r) => {
                    walk(l, out);
                    walk(r, out);
                }
                Expr::Not(inner) => walk(inner, out),
            }
        }
        walk(self, &mut out);
        out.sort();
        out.dedup();
        out
    }
}