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}