cvlr_macros/lib.rs
1use proc_macro::TokenStream;
2use quote::ToTokens;
3use syn::{parse_macro_input, parse_quote, ItemFn};
4
5mod assert_that;
6mod mock;
7/// Mark a method as a CVT rule
8///
9/// # Example
10///
11/// ```rust,no_run
12/// use cvlr::prelude::*;
13/// #[rule]
14/// fn foo() {
15/// cvlr_assert!(false);
16/// }
17/// ```
18#[proc_macro_attribute]
19pub fn rule(_attr: TokenStream, item: TokenStream) -> TokenStream {
20 let mut fn_ast = parse_macro_input!(item as ItemFn);
21 // add #[no_mangle] attribute
22 fn_ast.attrs.push(parse_quote! { #[no_mangle] });
23 // The first statement in rules is a call to the macro `cvlr_rule_location!`
24 // to automatically insert the location of the rule.
25 fn_ast
26 .block
27 .stmts
28 .insert(0, parse_quote! { cvlr::log::cvlr_rule_location!(); });
29 fn_ast
30 .block
31 .stmts
32 .push(parse_quote! { cvlr::cvlr_vacuity_check!(); });
33 fn_ast.into_token_stream().into()
34}
35
36#[proc_macro_attribute]
37pub fn mock_fn(attr: TokenStream, item: TokenStream) -> TokenStream {
38 mock::mock_fn_impl(attr, item)
39}
40
41/// Assert a condition using a DSL syntax
42///
43/// This macro provides a convenient DSL for writing assertions. It supports both
44/// guarded (conditional) and unguarded assertions, and automatically detects
45/// comparison operators to expand to the appropriate `cvlr_assert_*` macros.
46///
47/// # Syntax
48///
49/// The macro accepts either:
50/// - **Unguarded expression**: `cvlr_assert_that!(condition)`
51/// - **Guarded expression**: `cvlr_assert_that!(if guard { condition })`
52///
53/// The `condition` can be:
54/// - A comparison: `a < b`, `x >= y`, `p == q`, etc.
55/// - A boolean expression: `flag`, `x > 0 && y < 10`, etc.
56///
57/// # Examples
58///
59/// ## Unguarded comparisons
60///
61/// ```rust,no_run
62/// use cvlr_macros::cvlr_assert_that;
63///
64/// let x = 5;
65/// let y = 10;
66///
67/// cvlr_assert_that!(x < y); // expands to cvlr_assert_lt!(x, y)
68/// cvlr_assert_that!(x <= y); // expands to cvlr_assert_le!(x, y)
69/// cvlr_assert_that!(x > 0); // expands to cvlr_assert_gt!(x, 0)
70/// cvlr_assert_that!(x >= 0); // expands to cvlr_assert_ge!(x, 0)
71/// cvlr_assert_that!(x == 5); // expands to cvlr_assert_eq!(x, 5)
72/// cvlr_assert_that!(x != 0); // expands to cvlr_assert_ne!(x, 0)
73/// ```
74///
75/// ## Guarded comparisons
76///
77/// ```rust,no_run
78/// use cvlr_macros::cvlr_assert_that;
79///
80/// let flag = true;
81/// let a = 1;
82/// let b = 2;
83/// let x = 5;
84/// let y = 10;
85/// let z = 15;
86///
87/// // Assert b < a only if flag is true
88/// cvlr_assert_that!(if flag { a < b }); // expands to cvlr_assert_lt_if!(flag, a, b)
89/// cvlr_assert_that!(if x > 0 { y <= z }); // expands to cvlr_assert_le_if!(x > 0, y, z)
90/// ```
91///
92/// ## Boolean expressions
93///
94/// ```rust,no_run
95/// use cvlr_macros::cvlr_assert_that;
96///
97/// let flag = true;
98/// let x = 5;
99/// let y = 3;
100/// let z = 7;
101///
102/// // Unguarded boolean
103/// cvlr_assert_that!(flag); // expands to cvlr_assert!(flag)
104/// cvlr_assert_that!(x > 0 && y < 10); // expands to cvlr_assert!(x > 0 && y < 10)
105///
106/// // Guarded boolean
107/// cvlr_assert_that!(if flag { x > 0 }); // expands to cvlr_assert_if!(flag, x > 0)
108/// cvlr_assert_that!(if x > 0 { y > 0 && z < 10 }); // expands to cvlr_assert_if!(x > 0, y > 0 && z < 10)
109/// ```
110///
111/// ## Complex expressions
112///
113/// ```rust,no_run
114/// use cvlr_macros::cvlr_assert_that;
115///
116/// let a = 1;
117/// let c = 3;
118/// let d = 4;
119/// let p = 5;
120/// let x = 5;
121/// let y = 3;
122/// let z = 10;
123///
124/// // Complex guard and condition
125/// cvlr_assert_that!(if a > c { d < p }); // expands to cvlr_assert_lt_if!(a > c, d, p)
126/// cvlr_assert_that!(if x + 1 > 0 { y * 2 < z }); // expands to cvlr_assert_lt_if!(x + 1 > 0, y * 2, z)
127/// ```
128///
129/// # Expansion
130///
131/// The macro automatically detects comparison operators and expands to the
132/// appropriate assertion macro:
133///
134/// - Comparisons (`<`, `<=`, `>`, `>=`, `==`, `!=`) expand to `cvlr_assert_<op>!` or `cvlr_assert_<op>_if!`
135/// - Boolean expressions expand to `cvlr_assert!` or `cvlr_assert_if!`
136#[proc_macro]
137pub fn cvlr_assert_that(input: TokenStream) -> TokenStream {
138 assert_that::assert_that_impl(input)
139}
140
141/// Assert multiple conditions using the same DSL syntax as `cvlr_assert_that!`
142///
143/// This macro takes a list of DSL expressions (same syntax as `cvlr_assert_that!`)
144/// and expands to multiple calls to `cvlr_assert_that!`. Expressions can be
145/// separated by either commas (`,`) or semicolons (`;`).
146///
147/// # Syntax
148///
149/// Expressions can be separated by commas or semicolons:
150/// - `cvlr_assert_all!(expr1, expr2, expr3);`
151/// - `cvlr_assert_all!(expr1; expr2; expr3);`
152/// - `cvlr_assert_all!(expr1, expr2; expr3);` // Mixed separators are also allowed
153///
154/// Each expression follows the same syntax as `cvlr_assert_that!`:
155/// - Unguarded: `condition`
156/// - Guarded: `if guard { condition }`
157///
158/// # Examples
159///
160/// ```rust,no_run
161/// use cvlr_macros::cvlr_assert_all;
162///
163/// let x = 5;
164/// let y = 10;
165/// let c = true;
166///
167/// // Multiple unguarded assertions
168/// cvlr_assert_all!(x > 0, y < 20, x < y);
169///
170/// // Mixed guarded and unguarded
171/// cvlr_assert_all!(x > 0, if c { x < y });
172///
173/// // Using semicolons
174/// cvlr_assert_all!(x > 0; y < 20; if c { x < y });
175///
176/// // Mixed separators
177/// cvlr_assert_all!(x > 0, y < 20; if c { x < y });
178/// ```
179///
180/// # Expansion
181///
182/// This macro expands directly to the underlying assertion macros (not to `cvlr_assert_that!` calls):
183///
184/// ```text
185/// // Input:
186/// cvlr_assert_all!(x > 0, if c { x < y });
187///
188/// // Expands to:
189/// ::cvlr::asserts::cvlr_assert_gt!(x, 0);
190/// ::cvlr::asserts::cvlr_assert_lt_if!(c, x, y);
191/// ```
192#[proc_macro]
193pub fn cvlr_assert_all(input: TokenStream) -> TokenStream {
194 assert_that::assert_all_impl(input)
195}
196
197/// Assume a condition using a DSL syntax (analogous to `cvlr_assert_that!`)
198///
199/// This macro provides the same DSL syntax as `cvlr_assert_that!` but expands to
200/// `cvlr_assume_*` macros instead of `cvlr_assert_*` macros.
201///
202/// # Syntax
203///
204/// The macro accepts either:
205/// - **Unguarded expression**: `cvlr_assume_that!(condition)`
206/// - **Guarded expression**: `cvlr_assume_that!(if guard { condition })`
207///
208/// The `condition` can be:
209/// - A comparison: `a < b`, `x >= y`, `p == q`, etc.
210/// - A boolean expression: `flag`, `x > 0 && y < 10`, etc.
211///
212/// # Examples
213///
214/// ## Unguarded comparisons
215///
216/// ```rust,no_run
217/// use cvlr_macros::cvlr_assume_that;
218///
219/// let x = 5;
220/// let y = 10;
221///
222/// cvlr_assume_that!(x < y); // expands to cvlr_assume_lt!(x, y)
223/// cvlr_assume_that!(x <= y); // expands to cvlr_assume_le!(x, y)
224/// cvlr_assume_that!(x > 0); // expands to cvlr_assume_gt!(x, 0)
225/// cvlr_assume_that!(x >= 0); // expands to cvlr_assume_ge!(x, 0)
226/// cvlr_assume_that!(x == 5); // expands to cvlr_assume_eq!(x, 5)
227/// cvlr_assume_that!(x != 0); // expands to cvlr_assume_ne!(x, 0)
228/// ```
229///
230/// ## Guarded comparisons
231///
232/// ```rust,no_run
233/// use cvlr_macros::cvlr_assume_that;
234///
235/// let flag = true;
236/// let a = 1;
237/// let b = 2;
238///
239/// // Assume a < b only if flag is true
240/// cvlr_assume_that!(if flag { a < b }); // expands to: if flag { cvlr_assume_lt!(a, b); }
241/// ```
242///
243/// ## Boolean expressions
244///
245/// ```rust,no_run
246/// use cvlr_macros::cvlr_assume_that;
247///
248/// let flag = true;
249/// let x = 5;
250/// let y = 3;
251///
252/// // Unguarded boolean
253/// cvlr_assume_that!(flag); // expands to cvlr_assume!(flag)
254/// cvlr_assume_that!(x > 0 && y < 10); // expands to cvlr_assume!(x > 0 && y < 10)
255///
256/// // Guarded boolean
257/// cvlr_assume_that!(if flag { x > 0 }); // expands to: if flag { cvlr_assume!(x > 0); }
258/// ```
259///
260/// # Expansion
261///
262/// The macro automatically detects comparison operators and expands to the
263/// appropriate assume macro:
264///
265/// - Comparisons (`<`, `<=`, `>`, `>=`, `==`, `!=`) expand to `cvlr_assume_<op>!`
266/// - For guarded expressions, the assume is wrapped in an `if` block
267/// - Boolean expressions expand to `cvlr_assume!`
268#[proc_macro]
269pub fn cvlr_assume_that(input: TokenStream) -> TokenStream {
270 assert_that::assume_that_impl(input)
271}
272
273/// Assume multiple conditions using the same DSL syntax as `cvlr_assume_that!`
274///
275/// This macro takes a list of DSL expressions (same syntax as `cvlr_assume_that!`)
276/// and expands directly to the underlying `cvlr_assume_*` macros. Expressions can be
277/// separated by either commas (`,`) or semicolons (`;`).
278///
279/// # Syntax
280///
281/// Expressions can be separated by commas or semicolons:
282/// - `cvlr_assume_all!(expr1, expr2, expr3);`
283/// - `cvlr_assume_all!(expr1; expr2; expr3);`
284/// - `cvlr_assume_all!(expr1, expr2; expr3);` // Mixed separators are also allowed
285///
286/// Each expression follows the same syntax as `cvlr_assume_that!`:
287/// - Unguarded: `condition`
288/// - Guarded: `if guard { condition }`
289///
290/// # Examples
291///
292/// ```rust,no_run
293/// use cvlr_macros::cvlr_assume_all;
294///
295/// let x = 5;
296/// let y = 10;
297/// let c = true;
298///
299/// // Multiple unguarded assumptions
300/// cvlr_assume_all!(x > 0, y < 20, x < y);
301///
302/// // Mixed guarded and unguarded
303/// cvlr_assume_all!(x > 0, if c { x < y });
304///
305/// // Using semicolons
306/// cvlr_assume_all!(x > 0; y < 20; if c { x < y });
307/// ```
308///
309/// # Expansion
310///
311/// This macro expands directly to the underlying assume macros:
312///
313/// ```text
314/// // Input:
315/// cvlr_assume_all!(x > 0, if c { x < y });
316///
317/// // Expands to:
318/// ::cvlr::asserts::cvlr_assume_gt!(x, 0);
319/// if c {
320/// ::cvlr::asserts::cvlr_assume_lt!(x, y);
321/// }
322/// ```
323#[proc_macro]
324pub fn cvlr_assume_all(input: TokenStream) -> TokenStream {
325 assert_that::assume_all_impl(input)
326}