cel_cxx/macros/
factory.rs

1use super::expr::*;
2use crate::ffi::{
3    Expr as FfiExpr,
4    ListExprElement as FfiListExprElement,
5    StructExprField as FfiStructExprField,
6    MapExprEntry as FfiMapExprEntry,
7    MacroExprFactory as FfiMacroExprFactory,
8};
9use std::pin::Pin;
10
11/// Factory for constructing CEL expressions during macro expansion.
12///
13/// `MacroExprFactory` provides a safe interface for building new expression trees
14/// within macro expanders. It handles the low-level details of creating properly
15/// structured expressions with unique IDs and correct parent-child relationships.
16///
17/// # Usage
18///
19/// This type is provided to macro expander functions and should not be constructed
20/// directly. All expression construction during macro expansion must go through
21/// this factory to ensure correctness.
22///
23/// # Expression IDs
24///
25/// The factory automatically assigns unique IDs to all created expressions. These
26/// IDs are used for source location tracking and error reporting.
27///
28/// # Examples
29///
30/// ```rust,no_run
31/// # use cel_cxx::macros::{MacroExprFactory, Expr};
32/// fn example_expander(factory: &mut MacroExprFactory, args: Vec<Expr>) -> Option<Expr> {
33///     // Create a constant expression
34///     let const_expr = factory.new_const(42);
35///     
36///     // Create a function call expression
37///     let call_expr = factory.new_call("size", &[args[0].clone()]);
38///     
39///     // Create a binary operation
40///     let result = factory.new_call("_>_", &[call_expr, const_expr]);
41///     
42///     Some(result)
43/// }
44/// ```
45pub struct MacroExprFactory<'a>(pub(crate) std::sync::RwLock<Pin<&'a mut FfiMacroExprFactory>>);
46
47impl<'a> MacroExprFactory<'a> {
48    pub(crate) fn new(ffi_macro_expr_factory: Pin<&'a mut FfiMacroExprFactory>) -> Self {
49        Self(std::sync::RwLock::new(ffi_macro_expr_factory))
50    }
51
52    /// Creates a deep copy of an expression with new IDs.
53    ///
54    /// This method duplicates the entire expression tree, assigning fresh IDs to
55    /// all nodes. This is useful when you need to reuse an expression structure
56    /// in multiple places within a macro expansion.
57    ///
58    /// # Examples
59    ///
60    /// ```rust,no_run
61    /// # use cel_cxx::macros::{MacroExprFactory, Expr};
62    /// # fn example(factory: &mut MacroExprFactory, expr: &Expr) {
63    /// // Create two independent copies of an expression
64    /// let copy1 = factory.copy_expr(expr);
65    /// let copy2 = factory.copy_expr(expr);
66    /// # }
67    /// ```
68    pub fn copy_expr(&self, expr: &Expr) -> Expr {
69        let ffi_expr: cxx::UniquePtr<FfiExpr> = expr.into();
70        let ffi_copied = self.0.write().expect("Failed to write to RwLock")
71            .as_mut().copy(&ffi_expr);
72        ffi_copied.into()
73    }
74
75    /// Creates a deep copy of a list element with a new ID.
76    ///
77    /// Copies a list element, including its expression and optional flag,
78    /// assigning a fresh ID to the element.
79    pub fn copy_list_expr_element(&self, list_expr_element: &ListExprElement) -> ListExprElement {
80        let ffi_list_expr_element: cxx::UniquePtr<FfiListExprElement> = list_expr_element.into();
81        let ffi_copied = self.0.write().expect("Failed to write to RwLock")
82            .as_mut().copy_list_element(&ffi_list_expr_element);
83        ffi_copied.into()
84    }
85
86    /// Creates a deep copy of a struct field with a new ID.
87    ///
88    /// Copies a struct field, including its name, value expression, and optional flag,
89    /// assigning a fresh ID to the field.
90    pub fn copy_struct_expr_field(&self, struct_expr_field: &StructExprField) -> StructExprField {
91        let ffi_struct_expr_field: cxx::UniquePtr<FfiStructExprField> = struct_expr_field.into();
92        let ffi_copied = self.0.write().expect("Failed to write to RwLock")
93            .as_mut().copy_struct_field(&ffi_struct_expr_field);
94        ffi_copied.into()
95    }
96
97    /// Creates a deep copy of a map entry with a new ID.
98    ///
99    /// Copies a map entry, including its key, value expressions, and optional flag,
100    /// assigning a fresh ID to the entry.
101    pub fn copy_map_expr_entry(&self, map_expr_entry: &MapExprEntry) -> MapExprEntry {
102        let ffi_map_expr_entry: cxx::UniquePtr<FfiMapExprEntry> = map_expr_entry.into();
103        let ffi_copied = self.0.write().expect("Failed to write to RwLock")
104            .as_mut().copy_map_entry(&ffi_map_expr_entry);
105        ffi_copied.into()
106    }
107
108    /// Creates an unspecified expression.
109    ///
110    /// An unspecified expression is an empty expression placeholder with no kind set.
111    /// This is rarely needed in user code; prefer using more specific constructors.
112    pub fn new_unspecified(&mut self) -> Expr {
113        let ffi_unspecified = self.0.write().expect("Failed to write to RwLock")
114            .as_mut().new_unspecified();
115        ffi_unspecified.into()
116    }
117
118    /// Creates a constant expression from any value that can be converted to a CEL constant.
119    ///
120    /// This is the primary way to create literal values in macro expansions. The value
121    /// must implement [`IntoConstant`](crate::IntoConstant).
122    ///
123    /// # Supported Types
124    ///
125    /// - Integers: `i64`, `i32`, `u64`, etc.
126    /// - Floating point: `f64`, `f32`
127    /// - Boolean: `bool`
128    /// - String: `String`, `&str`
129    /// - Bytes: `Vec<u8>`, `&[u8]`
130    /// - Null: `()`, `Option::None`
131    /// - Duration: `std::time::Duration`
132    ///
133    /// # Examples
134    ///
135    /// ```rust,no_run
136    /// # use cel_cxx::macros::{MacroExprFactory, Expr};
137    /// # fn example(factory: &mut MacroExprFactory) {
138    /// let int_expr = factory.new_const(42i64);
139    /// let str_expr = factory.new_const("hello");
140    /// let bool_expr = factory.new_const(true);
141    /// let null_expr = factory.new_const(());
142    /// # }
143    /// ```
144    pub fn new_const<T>(&self, value: T) -> Expr
145    where
146        T: crate::IntoConstant,
147    {
148        let mut expr = Expr::from(self.0.write().expect("Failed to write to RwLock")
149            .as_mut().new_unspecified());
150        expr.set_kind(ExprKind::Constant(value.into_constant()));
151        expr
152    }
153
154    /// Creates an identifier expression.
155    ///
156    /// Identifier expressions reference variables or constants by name. This is used
157    /// to create variable references in the expanded macro.
158    ///
159    /// # Examples
160    ///
161    /// ```rust,no_run
162    /// # use cel_cxx::macros::{MacroExprFactory, Expr};
163    /// # fn example(factory: &mut MacroExprFactory) {
164    /// let var_expr = factory.new_ident("my_variable");
165    /// let param_expr = factory.new_ident("x");
166    /// # }
167    /// ```
168    pub fn new_ident(&self, name: &str) -> Expr {
169        let ffi_ident = self.0.write().expect("Failed to write to RwLock")
170            .as_mut().new_ident(name.into());
171        ffi_ident.into()
172    }
173
174    /// Returns the name of the accumulator variable for comprehensions.
175    ///
176    /// When building comprehension expressions, this method provides the name of the
177    /// automatically generated accumulator variable. This is useful for maintaining
178    /// consistency with the compiler's internal naming scheme.
179    pub fn accu_var_name(&self) -> String {
180        let mut guard = self.0.write().expect("Failed to write to RwLock");
181        guard.as_mut().accu_var_name().to_string_lossy().to_string()
182    }
183
184    /// Creates an identifier expression for the accumulator variable.
185    ///
186    /// This is a convenience method that combines [`accu_var_name`](#method.accu_var_name)
187    /// and [`new_ident`](#method.new_ident) to create a reference to the accumulator
188    /// variable used in comprehensions.
189    pub fn new_accu_ident(&self) -> Expr {
190        let ffi_accu_ident = self.0.write().expect("Failed to write to RwLock")
191            .as_mut().new_accu_ident();
192        ffi_accu_ident.into()
193    }
194
195    /// Creates a field selection expression.
196    ///
197    /// A select expression accesses a field on an object or map, e.g., `obj.field`.
198    /// This is equivalent to the dot operator in CEL.
199    ///
200    /// # Examples
201    ///
202    /// ```rust,no_run
203    /// # use cel_cxx::macros::{MacroExprFactory, Expr};
204    /// # fn example(factory: &mut MacroExprFactory) {
205    /// let obj = factory.new_ident("my_object");
206    /// let field_access = factory.new_select(&obj, "field_name");
207    /// // Results in: my_object.field_name
208    /// # }
209    /// ```
210    pub fn new_select(&self, operand: &Expr, field: &str) -> Expr {
211        let ffi_select = self.0.write().expect("Failed to write to RwLock")
212            .as_mut().new_select(operand.into(), field.into());
213        ffi_select.into()
214    }
215
216    /// Creates a field presence test expression.
217    ///
218    /// A presence test checks whether a field exists on an object without accessing
219    /// its value. This is equivalent to the `has(obj.field)` macro in CEL.
220    ///
221    /// # Examples
222    ///
223    /// ```rust,no_run
224    /// # use cel_cxx::macros::{MacroExprFactory, Expr};
225    /// # fn example(factory: &mut MacroExprFactory) {
226    /// let obj = factory.new_ident("my_object");
227    /// let has_field = factory.new_presence_test(&obj, "optional_field");
228    /// // Results in: has(my_object.optional_field)
229    /// # }
230    /// ```
231    pub fn new_presence_test(&self, operand: &Expr, field: &str) -> Expr {
232        let ffi_presence_test = self.0.write().expect("Failed to write to RwLock")
233            .as_mut().new_presence_test(operand.into(), field.into());
234        ffi_presence_test.into()
235    }
236
237    /// Creates a function call expression.
238    ///
239    /// Function calls invoke named functions with the provided arguments. This is used
240    /// for both built-in operators (like `_+_`, `_==_`) and user-defined functions.
241    ///
242    /// # Common Operators
243    ///
244    /// CEL operators are represented as functions with special names:
245    /// - Arithmetic: `_+_`, `_-_`, `_*_`, `_/_`, `_%_`, `_-_` (unary negation)
246    /// - Comparison: `_==_`, `_!=_`, `_<_`, `_<=_`, `_>_`, `_>=_`
247    /// - Logical: `_&&_`, `_||_`, `!_` (negation)
248    /// - Ternary: `_?_:_` (conditional)
249    ///
250    /// # Examples
251    ///
252    /// ```rust,no_run
253    /// # use cel_cxx::macros::{MacroExprFactory, Expr};
254    /// # fn example(factory: &mut MacroExprFactory) {
255    /// let a = factory.new_const(10);
256    /// let b = factory.new_const(20);
257    /// let sum = factory.new_call("_+_", &[a, b]);
258    /// // Results in: 10 + 20
259    /// # }
260    /// ```
261    pub fn new_call(&self, function: &str, args: &[Expr]) -> Expr {
262        let mut ffi_args = cxx::CxxVector::new();
263        for arg in args {
264            use crate::ffi::CxxVectorExt;
265            ffi_args.pin_mut().push_unique(arg.into());
266        }
267        let ffi_call = self.0.write().expect("Failed to write to RwLock")
268            .as_mut().new_call(function.into(), ffi_args);
269        ffi_call.into()
270    }
271
272    /// Creates a member function call expression.
273    ///
274    /// Member calls invoke methods on a target object, e.g., `target.method(args)`.
275    /// This is the method-call form as opposed to global function calls.
276    ///
277    /// # Examples
278    ///
279    /// ```rust,no_run
280    /// # use cel_cxx::macros::{MacroExprFactory, Expr};
281    /// # fn example(factory: &mut MacroExprFactory) {
282    /// let list = factory.new_ident("my_list");
283    /// let index = factory.new_const(0);
284    /// let get_call = factory.new_member_call("get", &list, &[index]);
285    /// // Results in: my_list.get(0)
286    /// # }
287    /// ```
288    pub fn new_member_call(&self, function: &str, target: &Expr, args: &[Expr]) -> Expr {
289        let mut ffi_args = cxx::CxxVector::new();
290        for arg in args {
291            use crate::ffi::CxxVectorExt;
292            ffi_args.pin_mut().push_unique(arg.into());
293        }
294        let ffi_member_call = self.0.write().expect("Failed to write to RwLock")
295            .as_mut()
296            .new_member_call(function.into(), target.into(), ffi_args);
297        ffi_member_call.into()
298    }
299
300    /// Creates a list element for use in list construction.
301    ///
302    /// List elements wrap expressions with an optional flag. The optional flag is
303    /// used for optional element syntax in CEL (e.g., `[1, ?2, 3]` where `?2` might
304    /// be omitted if undefined).
305    ///
306    /// # Parameters
307    ///
308    /// - `expr`: The expression value of this list element
309    /// - `optional`: If `true`, this element can be omitted if the expression is undefined
310    ///
311    /// # Examples
312    ///
313    /// ```rust,no_run
314    /// # use cel_cxx::macros::{MacroExprFactory, Expr};
315    /// # fn example(factory: &mut MacroExprFactory) {
316    /// let required = factory.new_list_element(&factory.new_const(1), false);
317    /// let optional = factory.new_list_element(&factory.new_ident("maybe"), true);
318    /// # }
319    /// ```
320    pub fn new_list_element(&self, expr: &Expr, optional: bool) -> ListExprElement {
321        let ffi_list_element = self.0.write().expect("Failed to write to RwLock")
322            .as_mut().new_list_element(expr.into(), optional);
323        ffi_list_element.into()
324    }
325
326    /// Creates a list literal expression.
327    ///
328    /// List expressions create CEL list values, e.g., `[1, 2, 3]`. Each element
329    /// can be marked as optional for conditional inclusion.
330    ///
331    /// # Examples
332    ///
333    /// ```rust,no_run
334    /// # use cel_cxx::macros::{MacroExprFactory, Expr};
335    /// # fn example(factory: &mut MacroExprFactory) {
336    /// let elem1 = factory.new_list_element(&factory.new_const(1), false);
337    /// let elem2 = factory.new_list_element(&factory.new_const(2), false);
338    /// let elem3 = factory.new_list_element(&factory.new_const(3), false);
339    /// let list = factory.new_list(&[elem1, elem2, elem3]);
340    /// // Results in: [1, 2, 3]
341    /// # }
342    /// ```
343    pub fn new_list(&self, elements: &[ListExprElement]) -> Expr {
344        let mut ffi_elements = cxx::CxxVector::new();
345        for element in elements {
346            use crate::ffi::CxxVectorExt;
347            ffi_elements.pin_mut().push_unique(element.into());
348        }
349        let ffi_list = self.0.write().expect("Failed to write to RwLock")
350            .as_mut().new_list(ffi_elements);
351        ffi_list.into()
352    }
353    
354    /// Creates a struct field for use in struct construction.
355    ///
356    /// Struct fields consist of a field name, value expression, and optional flag.
357    /// The optional flag allows fields to be omitted if their value is undefined.
358    ///
359    /// # Parameters
360    ///
361    /// - `name`: The field name
362    /// - `value`: The expression providing the field value
363    /// - `optional`: If `true`, this field can be omitted if the value is undefined
364    ///
365    /// # Examples
366    ///
367    /// ```rust,no_run
368    /// # use cel_cxx::macros::{MacroExprFactory, Expr};
369    /// # fn example(factory: &mut MacroExprFactory) {
370    /// let field = factory.new_struct_field(
371    ///     "name",
372    ///     &factory.new_const("Alice"),
373    ///     false
374    /// );
375    /// # }
376    /// ```
377    pub fn new_struct_field(&self, name: &str, value: &Expr, optional: bool) -> StructExprField {
378        let ffi_struct_field = self.0.write().expect("Failed to write to RwLock")
379            .as_mut()
380            .new_struct_field(name.into(), value.into(), optional);
381        ffi_struct_field.into()
382    }
383
384    /// Creates a struct literal expression.
385    ///
386    /// Struct expressions create structured objects with named fields, e.g.,
387    /// `Person{name: "Alice", age: 30}`. The struct name is typically a message
388    /// type name.
389    ///
390    /// # Parameters
391    ///
392    /// - `name`: The struct type name (e.g., `"Person"`, `"com.example.Message"`)
393    /// - `fields`: The fields of the struct
394    ///
395    /// # Examples
396    ///
397    /// ```rust,no_run
398    /// # use cel_cxx::macros::{MacroExprFactory, Expr};
399    /// # fn example(factory: &mut MacroExprFactory) {
400    /// let name_field = factory.new_struct_field(
401    ///     "name",
402    ///     &factory.new_const("Alice"),
403    ///     false
404    /// );
405    /// let age_field = factory.new_struct_field(
406    ///     "age",
407    ///     &factory.new_const(30),
408    ///     false
409    /// );
410    /// let person = factory.new_struct("Person", &[name_field, age_field]);
411    /// // Results in: Person{name: "Alice", age: 30}
412    /// # }
413    /// ```
414    pub fn new_struct(&self, name: &str, fields: &[StructExprField]) -> Expr {
415        let mut ffi_fields = cxx::CxxVector::new();
416        for field in fields {
417            use crate::ffi::CxxVectorExt;
418            ffi_fields.pin_mut().push_unique(field.into());
419        }
420        let ffi_struct = self.0.write().expect("Failed to write to RwLock")
421            .as_mut().new_struct(name.into(), ffi_fields);
422        ffi_struct.into()
423    }
424    
425    /// Creates a map entry for use in map construction.
426    ///
427    /// Map entries consist of key and value expressions, plus an optional flag.
428    /// The optional flag allows entries to be omitted if either key or value is undefined.
429    ///
430    /// # Parameters
431    ///
432    /// - `key`: The expression providing the map key
433    /// - `value`: The expression providing the map value
434    /// - `optional`: If `true`, this entry can be omitted if key or value is undefined
435    ///
436    /// # Examples
437    ///
438    /// ```rust,no_run
439    /// # use cel_cxx::macros::{MacroExprFactory, Expr};
440    /// # fn example(factory: &mut MacroExprFactory) {
441    /// let entry = factory.new_map_entry(
442    ///     &factory.new_const("key"),
443    ///     &factory.new_const("value"),
444    ///     false
445    /// );
446    /// # }
447    /// ```
448    pub fn new_map_entry(&self, key: &Expr, value: &Expr, optional: bool) -> MapExprEntry {
449        let ffi_map_entry = self.0.write().expect("Failed to write to RwLock")
450            .as_mut()
451            .new_map_entry(key.into(), value.into(), optional);
452        ffi_map_entry.into()
453    }
454
455    /// Creates a map literal expression.
456    ///
457    /// Map expressions create CEL map values, e.g., `{"key": "value", "foo": "bar"}`.
458    /// Each entry can be marked as optional for conditional inclusion.
459    ///
460    /// # Examples
461    ///
462    /// ```rust,no_run
463    /// # use cel_cxx::macros::{MacroExprFactory, Expr};
464    /// # fn example(factory: &mut MacroExprFactory) {
465    /// let entry1 = factory.new_map_entry(
466    ///     &factory.new_const("name"),
467    ///     &factory.new_const("Alice"),
468    ///     false
469    /// );
470    /// let entry2 = factory.new_map_entry(
471    ///     &factory.new_const("age"),
472    ///     &factory.new_const(30),
473    ///     false
474    /// );
475    /// let map = factory.new_map(&[entry1, entry2]);
476    /// // Results in: {"name": "Alice", "age": 30}
477    /// # }
478    /// ```
479    pub fn new_map(&self, entries: &[MapExprEntry]) -> Expr {
480        let mut ffi_entries = cxx::CxxVector::new();
481        for entry in entries {
482            use crate::ffi::CxxVectorExt;
483            ffi_entries.pin_mut().push_unique(entry.into());
484        }
485        let ffi_map = self.0.write().expect("Failed to write to RwLock")
486            .as_mut().new_map(ffi_entries);
487        ffi_map.into()
488    }
489    
490    
491    /// Creates a comprehension expression with a single iteration variable.
492    ///
493    /// Comprehensions are CEL's powerful list processing construct, similar to list
494    /// comprehensions in Python. They consist of:
495    /// - An iteration variable that ranges over a collection
496    /// - An accumulator variable that maintains state across iterations
497    /// - A loop condition that determines when to continue
498    /// - A loop step that updates the accumulator
499    /// - A result expression that produces the final value
500    ///
501    /// # Parameters
502    ///
503    /// - `iter_var`: Name of the iteration variable (e.g., `"x"`)
504    /// - `iter_range`: Expression providing the collection to iterate over
505    /// - `accu_var`: Name of the accumulator variable (e.g., `"__result__"`)
506    /// - `accu_init`: Initial value of the accumulator
507    /// - `loop_condition`: Condition to continue iterating (e.g., `true` for all elements)
508    /// - `loop_step`: Expression to update the accumulator each iteration
509    /// - `result`: Final expression computed from the accumulator
510    ///
511    /// # Examples
512    ///
513    /// ```rust,no_run
514    /// # use cel_cxx::macros::{MacroExprFactory, Expr};
515    /// # fn example(factory: &mut MacroExprFactory, list: Expr) {
516    /// // Comprehension to filter a list: [x | x in list, x > 0]
517    /// let iter_var = "x";
518    /// let accu_var = factory.accu_var_name();
519    /// let iter_range = list;
520    /// let accu_init = factory.new_list(&[]);
521    /// let loop_condition = factory.new_call("_>_", &[
522    ///     factory.new_ident(iter_var),
523    ///     factory.new_const(0)
524    /// ]);
525    /// let loop_step = factory.new_call("_+_", &[
526    ///     factory.new_accu_ident(),
527    ///     factory.new_list(&[factory.new_list_element(
528    ///         &factory.new_ident(iter_var),
529    ///         false
530    ///     )])
531    /// ]);
532    /// let result = factory.new_accu_ident();
533    /// 
534    /// let comprehension = factory.new_comprehension(
535    ///     iter_var,
536    ///     &iter_range,
537    ///     &accu_var,
538    ///     &accu_init,
539    ///     &loop_condition,
540    ///     &loop_step,
541    ///     &result
542    /// );
543    /// # }
544    /// ```
545    pub fn new_comprehension(
546        &self, 
547        iter_var: &str, 
548        iter_range: &Expr, 
549        accu_var: &str, 
550        accu_init: &Expr, 
551        loop_condition: &Expr, 
552        loop_step: &Expr, 
553        result: &Expr) -> Expr {
554        let ffi_iter_var = iter_var.into();
555        let ffi_iter_range = iter_range.into();
556        let ffi_accu_var = accu_var.into();
557        let ffi_accu_init = accu_init.into();
558        let ffi_loop_condition = loop_condition.into();
559        let ffi_loop_step = loop_step.into();
560        let ffi_result = result.into();
561        let ffi_comprehension = self.0.write().expect("Failed to write to RwLock")
562            .as_mut()
563            .new_comprehension(
564                ffi_iter_var,
565                ffi_iter_range,
566                ffi_accu_var,
567                ffi_accu_init,
568                ffi_loop_condition,
569                ffi_loop_step,
570                ffi_result
571            );
572        ffi_comprehension.into()
573    }
574
575    /// Creates a comprehension expression with two iteration variables.
576    ///
577    /// This variant of comprehension supports iterating over key-value pairs, such
578    /// as when processing maps. The first iteration variable represents keys, and
579    /// the second represents values.
580    ///
581    /// # Parameters
582    ///
583    /// - `iter_var`: Name of the first iteration variable (e.g., key in maps)
584    /// - `iter_var2`: Name of the second iteration variable (e.g., value in maps)
585    /// - `iter_range`: Expression providing the collection to iterate over
586    /// - `accu_var`: Name of the accumulator variable
587    /// - `accu_init`: Initial value of the accumulator
588    /// - `loop_condition`: Condition to continue iterating
589    /// - `loop_step`: Expression to update the accumulator each iteration
590    /// - `result`: Final expression computed from the accumulator
591    ///
592    /// # Examples
593    ///
594    /// ```rust,no_run
595    /// # use cel_cxx::macros::{MacroExprFactory, Expr};
596    /// # fn example(factory: &mut MacroExprFactory, map: Expr) {
597    /// // Comprehension to filter map entries: {k: v | k, v in map, v > 0}
598    /// let comprehension = factory.new_comprehension2(
599    ///     "k",
600    ///     "v",
601    ///     &map,
602    ///     &factory.accu_var_name(),
603    ///     &factory.new_map(&[]),
604    ///     &factory.new_call("_>_", &[factory.new_ident("v"), factory.new_const(0)]),
605    ///     &factory.new_call("_+_", &[
606    ///         factory.new_accu_ident(),
607    ///         factory.new_map(&[factory.new_map_entry(
608    ///             &factory.new_ident("k"),
609    ///             &factory.new_ident("v"),
610    ///             false
611    ///         )])
612    ///     ]),
613    ///     &factory.new_accu_ident()
614    /// );
615    /// # }
616    /// ```
617    pub fn new_comprehension2(
618        &self, 
619        iter_var: &str, 
620        iter_var2: &str, 
621        iter_range: &Expr, 
622        accu_var: &str, 
623        accu_init: &Expr, 
624        loop_condition: &Expr, 
625        loop_step: &Expr, 
626        result: &Expr) -> Expr {
627        let ffi_iter_var = iter_var.into();
628        let ffi_iter_var2 = iter_var2.into();
629        let ffi_iter_range = iter_range.into();
630        let ffi_accu_var = accu_var.into();
631        let ffi_accu_init = accu_init.into();
632        let ffi_loop_condition = loop_condition.into();
633        let ffi_loop_step = loop_step.into();
634        let ffi_result = result.into();
635        let ffi_comprehension = self.0.write().expect("Failed to write to RwLock")
636            .as_mut()
637            .new_comprehension2(
638                ffi_iter_var,
639                ffi_iter_var2,
640                ffi_iter_range,
641                ffi_accu_var,
642                ffi_accu_init,
643                ffi_loop_condition,
644                ffi_loop_step,
645                ffi_result
646            );
647        ffi_comprehension.into()
648    }
649    
650    /// Reports a compilation error at the current location.
651    ///
652    /// This method creates an error expression that will cause compilation to fail
653    /// with the specified error message. Use this when a macro detects invalid
654    /// usage or unsupported patterns.
655    ///
656    /// # Examples
657    ///
658    /// ```rust,no_run
659    /// # use cel_cxx::macros::{MacroExprFactory, Expr};
660    /// # fn example(factory: &mut MacroExprFactory, args: Vec<Expr>) {
661    /// if args.len() != 2 {
662    ///     // Return an error if argument count is wrong
663    ///     let error = factory.report_error("expected exactly 2 arguments");
664    ///     return;
665    /// }
666    /// # }
667    /// ```
668    pub fn report_error(&self, message: &str) -> Expr {
669        let ffi_report_error = self.0.write().expect("Failed to write to RwLock")
670            .as_mut().report_error(message.into());
671        ffi_report_error.into()
672    }
673
674    /// Reports a compilation error at the location of a specific expression.
675    ///
676    /// This method creates an error expression that will cause compilation to fail
677    /// with the specified error message, associating the error with the source
678    /// location of the given expression. This provides better error messages by
679    /// pointing to the exact location of the problem.
680    ///
681    /// # Examples
682    ///
683    /// ```rust,no_run
684    /// # use cel_cxx::macros::{MacroExprFactory, Expr};
685    /// # fn example(factory: &mut MacroExprFactory, arg: &Expr) {
686    /// // Check if argument is a constant
687    /// if arg.kind().and_then(|k| k.as_constant()).is_none() {
688    ///     // Report error at the argument's location
689    ///     let error = factory.report_error_at(arg, "expected a constant value");
690    ///     return;
691    /// }
692    /// # }
693    /// ```
694    pub fn report_error_at(&self, expr: &Expr, message: &str) -> Expr {
695        let ffi_expr: cxx::UniquePtr<FfiExpr> = expr.into();
696        let ffi_report_error = self.0.write().expect("Failed to write to RwLock")
697            .as_mut().report_error_at(&ffi_expr, message.into());
698        ffi_report_error.into()
699    }
700}
701
702impl std::fmt::Debug for MacroExprFactory<'_> {
703    fn fmt(&self, f: &mut std::fmt::Formatter<'_>) -> std::fmt::Result {
704        write!(f, "MacroExprFactory(..)")
705    }
706}