1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
51
52
53
54
55
56
57
58
59
60
61
62
63
64
65
66
67
68
69
70
71
72
73
74
75
76
77
78
79
80
81
82
83
84
85
86
87
88
89
90
91
92
93
94
use TokenStream;
use quote;
use ;
/// `preprocessor::op!(...)` — Expression-level macro for compile-time evaluation.
///
/// Parses the input expression, evaluates it at compile time,
/// and replaces it with the literal result.
///
/// **Important**: If the expression cannot be fully evaluated at compile time
/// (e.g., contains free variables, unknown functions, etc.), the macro will
/// generate a compile-time error instead of passing through unchanged.
///
/// # Example
/// ```ignore
/// let result = preprocessor::op!(1 + 2 * 3); // → let result = 7;
/// let x = preprocessor::op!(a + 1); // → COMPILE ERROR: cannot evaluate at compile time
/// ```
/// `#[preprocessor::optimize]` — Function-level attribute macro for compile-time optimization.
///
/// Recursively traverses all statements and expressions in the function body,
/// identifies sub-expressions that can be evaluated at compile time,
/// and rewrites them as pre-computed literals.
///
/// # Example
/// ```ignore
/// #[preprocessor::optimize]
/// fn compute() -> i32 {
/// let x = 1 + 2; // → let x = 3;
/// let y = x * 10; // kept as-is (depends on local variable)
/// y
/// }
/// ```
/// `#[preprocessor::prelude]` — Crate-level attribute macro for automatic dependency resolution.
///
/// Scans the crate for `op!` macro usages, identifies unqualified paths (like `Local`),
/// resolves them to their full crate paths (like `chrono::Local`) based on `use` statements,
/// and rewrites the `op!` calls to use these full paths. This allows `op!` to work
/// without requiring fully qualified paths inside the macro invocation.
///
/// # Example
/// ```ignore
/// #![preprocessor::prelude]
///
/// fn main() {
/// // Works even without `use chrono::Local;` if `Local` is imported elsewhere
/// let time = preprocessor::op!(Local::now().to_string());
/// }
/// ```