kitt_score 0.1.0

Decision engine at the core of Project KITT — in-memory stateful matching with pluggable scoring backends.
Documentation
//! Predicate DSL AST.
//!
//! Grammar (informal):
//!
//! ```text
//! expr      := or
//! or        := and ("||" and)*
//! and       := cmp ("&&" cmp)*
//! cmp       := sum (("<"|"<="|">"|">="|"=="|"!=") sum)?
//! sum       := prod (("+"|"-") prod)*
//! prod      := unary (("*"|"/") unary)*
//! unary     := "-" unary | "!" unary | call
//! call      := ident "(" args ")" | atom
//! atom      := number | slot_ref | "(" expr ")"
//! slot_ref  := "$" ident "." ident
//! args      := expr ("," expr)*
//! ```
//!
//! Supported builtins: `min`, `max`, `abs`, `sum`, `len`, `dot`.
//! The scorer's output is the `f32` value of the top-level expression.
//! Boolean values are carried as f32 (0.0 / 1.0) to keep a single scalar
//! stack in the VM.

/// Expression node in the predicate DSL AST.
#[derive(Clone, Debug, PartialEq)]
pub enum Expr {
    /// Numeric literal.
    Num(f64),
    /// Slot reference `$kind.attr`.
    Slot {
        /// Kind name (e.g. `audience`).
        kind: String,
        /// Attribute name (e.g. `male_frac`).
        attr: String,
    },
    /// Unary negation `-x`.
    Neg(Box<Expr>),
    /// Logical NOT `!x`.
    Not(Box<Expr>),
    /// Binary op.
    Bin(BinOp, Box<Expr>, Box<Expr>),
    /// Function call `name(arg, ...)`.
    Call(String, Vec<Expr>),
}

/// Binary operator.
#[derive(Clone, Copy, Debug, PartialEq, Eq)]
pub enum BinOp {
    /// `+`
    Add,
    /// `-`
    Sub,
    /// `*`
    Mul,
    /// `/`
    Div,
    /// `<`
    Lt,
    /// `<=`
    Le,
    /// `>`
    Gt,
    /// `>=`
    Ge,
    /// `==`
    Eq,
    /// `!=`
    Ne,
    /// `&&`
    And,
    /// `||`
    Or,
}

#[cfg(test)]
mod tests {
    use super::*;

    #[test]
    fn expr_is_size_bounded() {
        assert!(std::mem::size_of::<Expr>() <= 64);
    }
}