rust_cel_parser/
builder.rs

1// src/ast/builder.rs
2
3//! Fluent functions for constructing AST nodes program by programmatically.
4//!
5//! These functions leverage the `From` trait implementations defined in `ast.rs`
6//! to allow users to pass primitive types directly as arguments where an `Expr` is expected.
7
8use super::{BinaryOperator, ComprehensionOp, Expr, Literal, UnaryOperator};
9
10// --- Leaf & Simple Nodes ---
11
12/// Creates an `Expr::Identifier` node.
13pub fn ident(name: &str) -> Expr {
14    Expr::Identifier(name.to_string())
15}
16
17/// Creates an `Expr::Literal` node from any type implementing `Into<Literal>`.
18pub fn lit(val: impl Into<Literal>) -> Expr {
19    Expr::Literal(val.into())
20}
21
22/// Creates an `Expr::Literal(Literal::Null)` node.
23pub fn null() -> Expr {
24    Expr::Literal(Literal::Null)
25}
26
27/// Creates an `Expr::List` node.
28pub fn list(elements: Vec<Expr>) -> Expr {
29    Expr::List { elements }
30}
31
32/// Creates an `Expr::MapLiteral` node.
33pub fn map(entries: Vec<(Expr, Expr)>) -> Expr {
34    Expr::MapLiteral { entries }
35}
36
37// --- Unary Operations ---
38
39/// Creates an `Expr::UnaryOp` node with the `Not` operator (`!`).
40pub fn not(operand: impl Into<Expr>) -> Expr {
41    Expr::UnaryOp {
42        op: UnaryOperator::Not,
43        operand: Box::new(operand.into()),
44    }
45}
46
47/// Creates an `Expr::UnaryOp` node with the `Neg` operator (`-`).
48pub fn neg(operand: impl Into<Expr>) -> Expr {
49    Expr::UnaryOp {
50        op: UnaryOperator::Neg,
51        operand: Box::new(operand.into()),
52    }
53}
54
55// --- Binary Operations (Arithmetic & Comparison) ---
56
57macro_rules! define_binary_op {
58    ($name:ident, $op:expr) => {
59        #[doc = concat!("Creates an `Expr::BinaryOp` node with the `", stringify!($op), "` operator.")]
60        pub fn $name(left: impl Into<Expr>, right: impl Into<Expr>) -> Expr {
61            Expr::BinaryOp {
62                op: $op,
63                left: Box::new(left.into()),
64                right: Box::new(right.into()),
65            }
66        }
67    };
68}
69
70define_binary_op!(add, BinaryOperator::Add);
71define_binary_op!(sub, BinaryOperator::Sub);
72define_binary_op!(mul, BinaryOperator::Mul);
73define_binary_op!(div, BinaryOperator::Div);
74define_binary_op!(rem, BinaryOperator::Rem);
75
76define_binary_op!(eq, BinaryOperator::Eq);
77define_binary_op!(ne, BinaryOperator::Ne);
78define_binary_op!(lt, BinaryOperator::Lt);
79define_binary_op!(le, BinaryOperator::Le);
80define_binary_op!(gt, BinaryOperator::Gt);
81define_binary_op!(ge, BinaryOperator::Ge);
82define_binary_op!(and, BinaryOperator::And);
83define_binary_op!(or, BinaryOperator::Or);
84define_binary_op!(r#in, BinaryOperator::In); // Use raw identifier for 'in'
85
86// --- Accessors & Calls ---
87
88/// Creates an `Expr::FieldAccess` node (e.g., `base.field`).
89pub fn field_access(base: impl Into<Expr>, field: &str) -> Expr {
90    Expr::FieldAccess {
91        base: Box::new(base.into()),
92        field: field.to_string(),
93    }
94}
95
96/// Creates an `Expr::Index` node (e.g., `base[index]`).
97pub fn index(base: impl Into<Expr>, index: impl Into<Expr>) -> Expr {
98    Expr::Index {
99        base: Box::new(base.into()),
100        index: Box::new(index.into()),
101    }
102}
103
104/// Creates an `Expr::Call` node.
105///
106/// The target must be an expression that resolves to a function,
107/// typically an `Expr::Identifier` or an `Expr::FieldAccess`.
108pub fn call(target: impl Into<Expr>, args: Vec<Expr>) -> Expr {
109    Expr::Call {
110        target: Box::new(target.into()),
111        args,
112    }
113}
114
115// --- Conditional ---
116
117/// Creates an `Expr::Conditional` node (ternary operator).
118pub fn conditional(
119    cond: impl Into<Expr>,
120    true_branch: impl Into<Expr>,
121    false_branch: impl Into<Expr>,
122) -> Expr {
123    Expr::Conditional {
124        cond: Box::new(cond.into()),
125        true_branch: Box::new(true_branch.into()),
126        false_branch: Box::new(false_branch.into()),
127    }
128}
129
130// --- Macros ---
131
132/// Creates an `Expr::Has` macro node.
133pub fn has(target: impl Into<Expr>) -> Expr {
134    Expr::Has {
135        target: Box::new(target.into()),
136    }
137}
138
139/// Creates an `Expr::Comprehension` node (e.g., `list.all(i, i > 0)`).
140pub fn comprehension(
141    op: ComprehensionOp,
142    target: impl Into<Expr>,
143    iter_var: &str,
144    predicate: impl Into<Expr>,
145) -> Expr {
146    Expr::Comprehension {
147        op,
148        target: Box::new(target.into()),
149        iter_var: iter_var.to_string(),
150        predicate: Box::new(predicate.into()),
151    }
152}
153
154/// Creates an `Expr::Map` macro node.
155pub fn map_macro(
156    target: impl Into<Expr>,
157    iter_var: &str,
158    filter: Option<impl Into<Expr>>,
159    transform: impl Into<Expr>,
160) -> Expr {
161    let filter_box = filter.map(|f| Box::new(f.into()));
162    Expr::Map {
163        target: Box::new(target.into()),
164        iter_var: iter_var.to_string(),
165        filter: filter_box,
166        transform: Box::new(transform.into()),
167    }
168}