Skip to main content

hax_lib_macros/
lib.rs

1//! Proc-macros for hax.
2//!
3//! Proc-macros must reside in the root of the crate: this module defines all of
4//! them, in every configuration, so that their documentation is always
5//! available. Small ones carry their implementation here, right under their
6//! documentation; bigger ones dispatch to `implementation`. Either way the
7//! implementation is gated on `--cfg hax`, since it needs
8//! `hax-lib-macros-types`, which is a `cfg(hax)`-only dependency.
9
10#![cfg_attr(hax, feature(macro_metavar_expr_concat))]
11
12mod hax_paths;
13
14#[cfg(hax)]
15mod impl_fn_decoration;
16#[cfg(hax)]
17mod implementation;
18#[cfg(hax)]
19mod quote;
20#[cfg(hax)]
21mod rewrite_self;
22#[cfg(hax)]
23mod syn_ext;
24#[cfg(hax)]
25mod utils;
26
27#[cfg(hax)]
28mod prelude {
29    pub use crate::hax_paths::*;
30    pub use crate::syn_ext::*;
31    pub use proc_macro as pm;
32    pub use proc_macro2::*;
33    pub use quote::*;
34    pub use std::collections::HashSet;
35    pub use syn::spanned::Spanned;
36    pub use syn::{visit_mut::VisitMut, *};
37
38    pub use AttrPayload::Language as AttrHaxLang;
39    pub use hax_lib_macros_types::*;
40    pub type FnLike = syn::ImplItemFn;
41}
42
43#[cfg(not(hax))]
44mod dummy;
45
46use proc_macro::TokenStream;
47
48/// Defines attribute proc-macros that forward to `implementation` under
49/// `--cfg hax`, and are the identity otherwise.
50macro_rules! passthrough_attributes {
51    ($($(#[$meta:meta])* $name:ident;)*) => {
52        $(
53            $(#[$meta])*
54            #[proc_macro_attribute]
55            pub fn $name(attr: TokenStream, item: TokenStream) -> TokenStream {
56                #[cfg(hax)]
57                { implementation::$name(attr, item) }
58                #[cfg(not(hax))]
59                { let _ = attr; item }
60            }
61        )*
62    };
63}
64
65/// Defines attribute proc-macros whose implementation is inlined below, next to
66/// their documentation. The body is compiled only under `--cfg hax`; otherwise
67/// the macro is the identity.
68macro_rules! attribute_macros {
69    ($($(#[$meta:meta])* fn $name:ident($attr:ident, $item:ident) $body:block)*) => {
70        $(
71            $(#[$meta])*
72            #[proc_macro_attribute]
73            pub fn $name($attr: TokenStream, $item: TokenStream) -> TokenStream {
74                #[cfg(hax)]
75                {
76                    #[allow(unused_imports)]
77                    use crate::{
78                        impl_fn_decoration::*, prelude::*, rewrite_self::SelfProjection, utils::*,
79                    };
80                    $body
81                }
82                #[cfg(not(hax))]
83                { let _ = $attr; $item }
84            }
85        )*
86    };
87}
88
89passthrough_attributes! {
90    /// When extracting to F*, inform about what is the current
91    /// verification status for an item. It can either be `lax` or
92    /// `panic_free`.
93    fstar_verification_status;
94
95    /// Add a logical postcondition to a function. Note you can use the
96    /// `forall` and `exists` operators.
97    ///
98    /// You can use the (unqualified) macro `fstar!` (`BACKEND!` for any
99    /// backend `BACKEND`) to inline F* (or Coq, ProVerif, etc.) code in
100    /// the postcondition, e.g. `fstar!("true")`.
101    ///
102    /// # Example
103    ///
104    /// ```
105    /// use hax_lib_macros::*;
106    /// #[ensures(|result| result == x * 2)]
107    /// pub fn twice(x: u64) -> u64 {
108    ///     x + x
109    /// }
110    /// ```
111    ensures;
112
113    /// Same as [`macro@ensures`], but the closure takes the result by
114    /// reference: the binder has type `&T` where `T` is the function's return
115    /// type.
116    ///
117    /// # Example
118    ///
119    /// ```
120    /// use hax_lib_macros::*;
121    /// #[ensures_ref(|result| result.len() == 2)]
122    /// pub fn pair(x: u64) -> Vec<u64> {
123    ///     vec![x, x]
124    /// }
125    /// ```
126    ensures_ref;
127
128    /// Mark an item opaque: the extraction will assume the
129    /// type without revealing its definition.
130    #[deprecated(note = "Please use 'opaque' instead")]
131    opaque_type;
132
133    /// Mark an item opaque: the extraction will assume the
134    /// type without revealing its definition.
135    opaque;
136
137    /// Marks a newtype `struct RefinedT(T);` as a refinement type. The
138    /// struct should have exactly one unnamed private field.
139    ///
140    /// This macro takes one argument: a `Prop` proposition that refines
141    /// values of type `SomeType`.
142    ///
143    /// For example, the following type defines bounded `u64` integers.
144    ///
145    /// ```
146    /// #[hax_lib::refinement_type(|x| x >= MIN && x <= MAX)]
147    /// pub struct BoundedU64<const MIN: u64, const MAX: u64>(u64);
148    /// ```
149    ///
150    /// This macro will generate an implementation of the [`Deref`](core::ops::Deref)
151    /// trait and of the `hax_lib::Refinement` trait. Those two traits are
152    /// the only interface to this newtype: one is allowed only to
153    /// construct or destruct refined type via those smart constructors
154    /// and destructors, ensuring the abstraction.
155    ///
156    /// A refinement of a type `T` with a formula `f` can be seen as a box
157    /// that contains a value of type `T` and a proof that this value
158    /// satisfies the formula `f`.
159    ///
160    /// In debug mode, the refinement will be checked at run-time. This
161    /// requires the base type `T` to implement `Clone`. Pass a first
162    /// parameter `no_debug_runtime_check` to disable this behavior.
163    ///
164    /// When extracted via hax, this is interpreted in the backend as a
165    /// refinement type: the use of such a type yields static proof
166    /// obligations.
167    refinement_type;
168}
169
170attribute_macros! {
171    /// When extracting to F*, wrap this item in `#push-options "..."` and
172    /// `#pop-options`.
173    fn fstar_options(attr, item) {
174        let item: TokenStream = item.into();
175        let lit_str = parse_macro_input!(attr as LitStr);
176        let payload = format!(r#"#push-options "{}""#, lit_str.value());
177        let payload = LitStr::new(&payload, lit_str.span());
178        quote! {
179            #[::hax_lib::fstar::before(#payload)]
180            #[::hax_lib::fstar::after(r#"#pop-options"#)]
181            #item
182        }
183        .into()
184    }
185
186    /// Postprocess an item with a given tactic. This macro takes the tactic in
187    /// parameter: this may be a Rust identifier or a raw snippet of F* code as a
188    /// string literal.
189    fn fstar_postprocess_with(attr, item) {
190        let item: TokenStream = item.into();
191        let payload: String = if let Ok(s) = syn::parse::<LitStr>(attr.clone()) {
192            s.value()
193        } else {
194            let e = parse_macro_input!(attr as Expr);
195            format!(" ${{ {} }} ", e.to_token_stream())
196        };
197        let payload = format!("[@@FStar.Tactics.postprocess_with ({payload})]");
198        let payload: Lit = Lit::Str(syn::LitStr::new(&payload, Span::call_site()));
199        quote! {#[::hax_lib::fstar::before(#payload)] #item}.into()
200    }
201
202    /// Allows to add SMT patterns to a lemma.
203    /// For more informations about SMT patterns, please take a look here:
204    /// <https://fstar-lang.org/tutorial/book/under_the_hood/uth_smt.html#designing-a-library-with-smt-patterns>.
205    fn fstar_smt_pat(attr, item) {
206        let phi: syn::Expr = parse_macro_input!(attr);
207        let item: FnLike = parse_macro_input!(item);
208        let (requires, attr) = make_fn_decoration(
209            phi,
210            item.sig.clone(),
211            FnDecorationKind::SMTPat,
212            None,
213            None,
214            SelfProjection::Unknown,
215        );
216        quote! {#requires #attr #item}.into()
217    }
218
219    /// Include this item in the Hax translation. This overrides any exclusion resulting of `-i` flag.
220    fn include(attr, item) {
221        let item: TokenStream = item.into();
222        let _ = parse_macro_input!(attr as parse::Nothing);
223        let attr = AttrPayload::ItemStatus(ItemStatus::Included { late_skip: false });
224        quote! {#attr #item}.into()
225    }
226
227    /// Exclude this item from the Hax translation.
228    fn exclude(attr, item) {
229        let item: TokenStream = item.into();
230        let _ = parse_macro_input!(attr as parse::Nothing);
231        let attr = AttrPayload::ItemStatus(ItemStatus::Excluded { modeled_by: None });
232        let charon = charon_attr(quote! {exclude});
233        quote! {#attr #charon #item}.into()
234    }
235
236    /// Provide a measure for a function: this measure will be used once
237    /// extracted in a backend for checking termination. The expression
238    /// that decreases can be of any type. (TODO: this is probably as it
239    /// is true only for F*, see #297)
240    ///
241    /// # Example
242    ///
243    /// ```
244    /// use hax_lib_macros::*;
245    /// #[decreases((m, n))]
246    /// pub fn ackermann(m: u64, n: u64) -> u64 {
247    ///     match (m, n) {
248    ///         (0, _) => n + 1,
249    ///         (_, 0) => ackermann(m - 1, 1),
250    ///         _ => ackermann(m - 1, ackermann(m, n - 1)),
251    ///     }
252    /// }
253    /// ```
254    fn decreases(attr, item) {
255        let phi: syn::Expr = parse_macro_input!(attr);
256        let item: FnLike = parse_macro_input!(item);
257        let (requires, attr) = make_fn_decoration(
258            phi,
259            item.sig.clone(),
260            FnDecorationKind::Decreases,
261            None,
262            None,
263            SelfProjection::Unknown,
264        );
265        quote! {#requires #attr #item}.into()
266    }
267
268    /// Add a logical precondition to a function.
269    // Note you can use the `forall` and `exists` operators. (TODO: commented out for now, see #297)
270    /// In the case of a function that has one or more `&mut` inputs, in
271    /// the `ensures` clause, you can refer to such an `&mut` input `x` as
272    /// `x` for its "past" value and `future(x)` for its "future" value.
273    /// Where those future values sit relative to the result in the generated
274    /// postcondition is backend-dependent, since each backend orders the tuple
275    /// its functions return differently.
276    ///
277    /// You can use the (unqualified) macro `fstar!` (`BACKEND!` for any
278    /// backend `BACKEND`) to inline F* (or Coq, ProVerif, etc.) code in
279    /// the precondition, e.g. `fstar!("true")`.
280    ///
281    /// # Example
282    ///
283    /// ```
284    /// use hax_lib_macros::*;
285    /// #[requires(x.len() == y.len())]
286    // #[requires(x.len() == y.len() && forall(|i: usize| i >= x.len() || y[i] > 0))] (TODO: commented out for now, see #297)
287    /// pub fn div_pairwise(x: Vec<u64>, y: Vec<u64>) -> Vec<u64> {
288    ///     x.iter()
289    ///         .copied()
290    ///         .zip(y.iter().copied())
291    ///         .map(|(x, y)| x / y)
292    ///         .collect()
293    /// }
294    /// ```
295    fn requires(attr, item) {
296        let phi: syn::Expr = parse_macro_input!(attr);
297        let item: FnLike = parse_macro_input!(item);
298        let (requires, attr) = make_fn_decoration(
299            phi.clone(),
300            item.sig.clone(),
301            FnDecorationKind::Requires,
302            None,
303            None,
304            SelfProjection::Unknown,
305        );
306        let mut item_with_debug = item.clone();
307        item_with_debug
308            .block
309            .stmts
310            .insert(0, parse_quote! {debug_assert!(#phi);});
311        quote! {
312            #requires #attr
313            // TODO: disable `assert!`s for now (see #297)
314            #item
315            // #[cfg(    all(not(#HaxCfgOptionName),     debug_assertions )) ] #item_with_debug
316            // #[cfg(not(all(not(#HaxCfgOptionName),     debug_assertions )))] #item
317        }
318        .into()
319    }
320
321    /// Mark an item transparent: the extraction will not
322    /// make it opaque regardless of the `-i` flag default.
323    fn transparent(_attr, item) {
324        let item: Item = parse_macro_input!(item);
325        let attr = AttrPayload::NeverErased;
326        quote! {#attr #item}.into()
327    }
328
329    /// A marker indicating a `fn` as a ProVerif process read.
330    fn process_read(_attr, item) {
331        let item: ItemFn = parse_macro_input!(item);
332        let attr = AttrPayload::ProcessRead;
333        quote! {#attr #item}.into()
334    }
335
336    /// A marker indicating a `fn` as a ProVerif process write.
337    fn process_write(_attr, item) {
338        let item: ItemFn = parse_macro_input!(item);
339        let attr = AttrPayload::ProcessWrite;
340        quote! {#attr #item}.into()
341    }
342
343    /// A marker indicating a `fn` as a ProVerif process initialization.
344    fn process_init(_attr, item) {
345        let item: ItemFn = parse_macro_input!(item);
346        let attr = AttrPayload::ProcessInit;
347        quote! {#attr #item}.into()
348    }
349
350    /// A marker indicating an `enum` as describing the protocol messages.
351    fn protocol_messages(_attr, item) {
352        let item: ItemEnum = parse_macro_input!(item);
353        let attr = AttrPayload::ProtocolMessages;
354        quote! {#attr #item}.into()
355    }
356
357    /// A marker indicating a `fn` should be automatically translated to a ProVerif constructor.
358    fn pv_constructor(_attr, item) {
359        let item: ItemFn = parse_macro_input!(item);
360        let attr = AttrPayload::PVConstructor;
361        quote! {#attr #item}.into()
362    }
363
364    /// A marker indicating a `fn` requires manual modelling in ProVerif.
365    fn pv_handwritten(_attr, item) {
366        let item: ItemFn = parse_macro_input!(item);
367        let attr = AttrPayload::PVHandwritten;
368        quote! {#attr #item}.into()
369    }
370
371    /// This macro inserts a verbatim Lean proof into the extracted code.
372    fn legacy_lean_proof(payload, item) {
373        let item: ItemFn = parse_macro_input!(item);
374        let payload = parse_macro_input!(payload as LitStr).value();
375        let attr = AttrPayload::Proof(payload);
376        quote! {#attr #item}.into()
377    }
378
379    /// This macro inserts a verbatim Lean proof showing that the `requires`-condition is panic-free.
380    /// The proof is inserted into the `pureRequires` field of the Lean spec.
381    fn legacy_lean_pure_requires_proof(payload, item) {
382        let item: ItemFn = parse_macro_input!(item);
383        let payload = parse_macro_input!(payload as LitStr).value();
384        let attr = AttrPayload::PureRequiresProof(payload);
385        quote! {#attr #item}.into()
386    }
387
388    /// This macro inserts a verbatim Lean proof showing that the `ensures`-condition is panic-free.
389    /// The proof is inserted into the `pureEnsures` field of the Lean spec.
390    fn legacy_lean_pure_ensures_proof(payload, item) {
391        let item: ItemFn = parse_macro_input!(item);
392        let payload = parse_macro_input!(payload as LitStr).value();
393        let attr = AttrPayload::PureEnsuresProof(payload);
394        quote! {#attr #item}.into()
395    }
396
397    /// Use the proof method `grind`. This influences the tactic and spec set used by Lean.
398    fn legacy_lean_proof_method_grind(_attr, item) {
399        let item: ItemFn = parse_macro_input!(item);
400        let attr = AttrPayload::ProofMethod(hax_lib_macros_types::ProofMethod::Grind);
401        quote! {#attr #item}.into()
402    }
403
404    /// Use the proof method `bv_decide`. This influences the tactic and spec set used by Lean.
405    fn legacy_lean_proof_method_bv_decide(_attr, item) {
406        let item: ItemFn = parse_macro_input!(item);
407        let attr = AttrPayload::ProofMethod(hax_lib_macros_types::ProofMethod::BvDecide);
408        quote! {#attr #item}.into()
409    }
410}
411
412/// Mark a `Proof<{STATEMENT}>`-returning function as a lemma, where
413/// `STATEMENT` is a `Prop` expression capturing any input
414/// variable.
415/// In the backends, this will generate a lemma with an empty proof.
416///
417/// # Example
418///
419/// ```
420/// use hax_lib_macros::*;
421// #[decreases((m, n))] (TODO: see #297)
422/// pub fn ackermann(m: u64, n: u64) -> u64 {
423///     match (m, n) {
424///         (0, _) => n + 1,
425///         (_, 0) => ackermann(m - 1, 1),
426///         _ => ackermann(m - 1, ackermann(m, n - 1)),
427///     }
428/// }
429///
430/// #[lemma]
431/// /// $`\forall n \in \mathbb{N}, \textrm{ackermann}(2, n) = 2 (n + 3) - 3`$
432/// pub fn ackermann_property_m1(n: u64) -> Proof<{ ackermann(2, n) == 2 * (n + 3) - 3 }> {}
433/// ```
434#[proc_macro_attribute]
435pub fn lemma(attr: TokenStream, item: TokenStream) -> TokenStream {
436    #[cfg(hax)]
437    {
438        implementation::lemma(attr, item)
439    }
440    #[cfg(not(hax))]
441    {
442        let _ = (attr, item);
443        TokenStream::new()
444    }
445}
446
447/// Enable the following attributes in the annotated item and sub-items.
448///
449/// ### `refine` (on a field in a struct)
450/// Refine a type with a logical formula.
451///
452/// ### `order` (on a field in a struct or an enum)
453/// Reorders a field in the extracted code.
454///
455/// Rust fields order matters for bit-level representation. Similarly, in some
456/// situations, fields order matters in the backends: for instance in F*, one
457/// may refine a field with a formula referring to a later field.
458///
459/// Those two orders may conflict. Adding `#[hax_lib::order(n)]` on a field with
460/// override its order at extraction time.
461///
462/// By default, the order of a field is its index, e.g. the first field has
463/// order 0, the i-th field has order i+1.
464///
465/// ### `decreases`, `ensures` and `requires` (on a `fn` in an `impl`)
466/// `decreases`, `ensures`, `requires`: behave exactly as documented above on
467/// the proc attributes of the same name.
468///
469/// Those may also be written behind a `cfg_attr`, e.g.
470/// `#[cfg_attr(hax, requires(..))]`: the predicate is preserved, so the
471/// specification appears exactly when the predicate holds. This makes
472/// `hax-lib` usable as a `cfg(hax)`-gated dependency.
473///
474/// # Example
475///
476/// ```
477/// #[hax_lib_macros::attributes]
478/// mod foo {
479///     pub struct Hello {
480///         pub x: u32,
481///         #[refine(y > 3)]
482///         pub y: u32,
483///         #[refine(y + x + z > 3)]
484///         pub z: u32,
485///     }
486///     impl Hello {
487///         fn sum(&self) -> u32 {
488///             self.x + self.y + self.z
489///         }
490///         #[ensures(|result| result - n == self.sum())]
491///         fn plus(self, n: u32) -> u32 {
492///             self.sum() + n
493///         }
494///     }
495/// }
496/// ```
497#[proc_macro_attribute]
498pub fn attributes(attr: TokenStream, item: TokenStream) -> TokenStream {
499    #[cfg(hax)]
500    {
501        implementation::attributes(attr, item)
502    }
503    #[cfg(not(hax))]
504    {
505        let _ = attr;
506        dummy::attributes(item)
507    }
508}
509
510/// Create a mathematical integer. This macro expects a Rust integer
511/// literal without suffix.
512///
513/// ## Examples:
514/// - `int!(0x101010)`
515/// - `int!(42)`
516/// - `int!(0o52)`
517/// - `int!(0h2A)`
518#[proc_macro]
519pub fn int(payload: TokenStream) -> TokenStream {
520    #[cfg(hax)]
521    {
522        implementation::int(payload)
523    }
524    #[cfg(not(hax))]
525    {
526        dummy::int(payload)
527    }
528}
529
530/// Add an invariant to a loop which deals with an index. The
531/// invariant cannot refer to any variable introduced within the
532/// loop. An invariant is a closure that takes one argument, the
533/// index, and returns a proposition.
534///
535/// Note that loop invariants are unstable (this will be handled in a
536/// better way in the future, see
537/// <https://github.com/hacspec/hax/issues/858>) and only supported on
538/// specific `for` loops with specific iterators:
539///
540///  - `for i in start..end {...}`
541///  - `for i in (start..end).step_by(n) {...}`
542///  - `for i in slice.enumerate() {...}`
543///  - `for i in slice.chunks_exact(n).enumerate() {...}`
544///
545/// This function must be called on the first line of a loop body to
546/// be effective. Note that in the invariant expression, `forall`,
547/// `exists`, and `BACKEND!` (`BACKEND` can be `fstar`, `proverif`,
548/// `coq`...) are in scope.
549#[proc_macro]
550pub fn loop_invariant(predicate: TokenStream) -> TokenStream {
551    #[cfg(hax)]
552    {
553        implementation::loop_invariant(predicate)
554    }
555    #[cfg(not(hax))]
556    {
557        let _ = predicate;
558        TokenStream::new()
559    }
560}
561
562/// Must be used to prove termination of while loops. This takes an
563/// expression that should be a usize that decreases at every iteration
564///
565/// This function must be called just after `loop_invariant`, or at the first
566/// line of the loop if there is no invariant.
567#[proc_macro]
568pub fn loop_decreases(predicate: TokenStream) -> TokenStream {
569    #[cfg(hax)]
570    {
571        implementation::loop_decreases(predicate)
572    }
573    #[cfg(not(hax))]
574    {
575        let _ = predicate;
576        TokenStream::new()
577    }
578}
579
580/// Internal macro for dealing with function decorations
581/// (`#[decreases(...)]`, `#[ensures(...)]`, `#[requires(...)]`) on
582/// `fn` items within an `impl` block. There is special handling since
583/// such functions might have a `self` argument: in such cases, we
584/// rewrite function decorations as `#[impl_fn_decoration(<KIND>,
585/// <GENERICS>, <WHERE CLAUSE>, <SELF TYPE> [as <TRAIT>], <BODY>)]`, where
586/// `<TRAIT>` is the trait implemented by the enclosing `impl` block.
587#[proc_macro_attribute]
588pub fn impl_fn_decoration(attr: TokenStream, item: TokenStream) -> TokenStream {
589    #[cfg(hax)]
590    {
591        implementation::impl_fn_decoration(attr, item)
592    }
593    #[cfg(not(hax))]
594    {
595        let _ = (attr, item);
596        dummy::internal_macro_misuse("impl_fn_decoration")
597    }
598}
599
600/// Internal macro for dealing with function decorations on `fn` items within a
601/// `trait`. See [`macro@impl_fn_decoration`].
602#[proc_macro_attribute]
603pub fn trait_fn_decoration(attr: TokenStream, item: TokenStream) -> TokenStream {
604    #[cfg(hax)]
605    {
606        implementation::trait_fn_decoration(attr, item)
607    }
608    #[cfg(not(hax))]
609    {
610        let _ = (attr, item);
611        dummy::internal_macro_misuse("trait_fn_decoration")
612    }
613}
614
615/// Defines the item-level quoting attributes of a backend: `<BACKEND>_before`
616/// and `<BACKEND>_after`.
617macro_rules! item_quoting_proc_macros {
618    ($backend:ident, $(($name:ident, $position:literal)),*) => {$(
619        #[doc = concat!("This macro inlines verbatim ", stringify!($backend), " code ", $position, " a Rust item.")]
620        ///
621        /// This macro takes a string literal containing backend
622        /// code. Just as backend expression macros, this literal can
623        /// contains dollar-prefixed Rust names.
624        ///
625        /// Note: when targetting F*, you can prepend a first
626        /// comma-separated argument: `interface`, `impl` or
627        /// `both`. This controls where the code will apprear: in the
628        /// `fst` or `fsti` files or both.
629        #[proc_macro_attribute]
630        pub fn $name(payload: TokenStream, item: TokenStream) -> TokenStream {
631            #[cfg(hax)]
632            { implementation::$name(payload, item) }
633            #[cfg(not(hax))]
634            { let _ = payload; item }
635        }
636    )*};
637}
638
639/// Defines every proc-macro attached to a given backend.
640macro_rules! quoting_proc_macros {
641    ($backend:ident, $expr:ident, $prop_expr:ident, $unsafe_expr:ident,
642     $before:ident, $after:ident, $replace:ident, $replace_body:ident) => {
643        #[doc = concat!("Embed ", stringify!($backend), " expression inside a Rust expression. This macro takes only one argument: some raw ", stringify!($backend), " code as a string literal.")]
644        ///
645        /// While it is possible to directly write raw backend code,
646        /// sometimes it can be inconvenient. For example, referencing
647        /// Rust names can be a bit cumbersome: for example, the name
648        /// `my_crate::my_module::CONSTANT` might be translated
649        /// differently in a backend (e.g. in the F* backend, it will
650        /// probably be `My_crate.My_module.v_CONSTANT`).
651        ///
652        /// To facilitate this, you can write Rust names directly,
653        /// using the prefix `$`: `f $my_crate::my_module__CONSTANT + 3`
654        /// will be replaced with `f My_crate.My_module.v_CONSTANT + 3`
655        /// in the F* backend for instance.
656        ///
657        /// If you want to refer to the Rust constructor
658        /// `Enum::Variant`, you should write `$$Enum::Variant` (note
659        /// the double dollar).
660        ///
661        /// If the name refers to something polymorphic, you need to
662        /// signal it by adding _any_ type informations,
663        /// e.g. `${my_module::function<()>}`. The curly braces are
664        /// needed for such more complex expressions.
665        ///
666        /// You can also write Rust patterns with the `$?{SYNTAX}`
667        /// syntax, where `SYNTAX` is a Rust pattern. The syntax
668        /// `${EXPR}` also allows any Rust expressions
669        /// `EXPR` to be embedded.
670        ///
671        /// Types can be refered to with the syntax `$:{TYPE}`.
672        #[proc_macro]
673        pub fn $expr(payload: TokenStream) -> TokenStream {
674            #[cfg(hax)]
675            { implementation::$expr(payload) }
676            #[cfg(not(hax))]
677            { let _ = payload; dummy::unit_expr() }
678        }
679
680        #[doc = concat!("The `Prop` version of `", stringify!($backend), "_expr`.")]
681        #[proc_macro]
682        pub fn $prop_expr(payload: TokenStream) -> TokenStream {
683            #[cfg(hax)]
684            { implementation::$prop_expr(payload) }
685            #[cfg(not(hax))]
686            { let _ = payload; dummy::prop_expr() }
687        }
688
689        #[doc = concat!("The unsafe (because polymorphic: even computationally relevant code can be inlined!) version of `", stringify!($backend), "_expr`.")]
690        #[proc_macro]
691        #[doc(hidden)]
692        pub fn $unsafe_expr(payload: TokenStream) -> TokenStream {
693            #[cfg(hax)]
694            { implementation::$unsafe_expr(payload) }
695            #[cfg(not(hax))]
696            { let _ = payload; dummy::unsafe_expr() }
697        }
698
699        item_quoting_proc_macros!($backend, ($before, "before"), ($after, "after"));
700
701        #[doc = concat!("Replaces a Rust item with some verbatim ", stringify!($backend)," code.")]
702        #[proc_macro_attribute]
703        pub fn $replace(payload: TokenStream, item: TokenStream) -> TokenStream {
704            #[cfg(hax)]
705            { implementation::$replace(payload, item) }
706            #[cfg(not(hax))]
707            { let _ = payload; item }
708        }
709
710        #[doc = concat!("Replaces the body of a Rust function with some verbatim ", stringify!($backend)," code.")]
711        #[proc_macro_attribute]
712        pub fn $replace_body(payload: TokenStream, item: TokenStream) -> TokenStream {
713            #[cfg(hax)]
714            { implementation::$replace_body(payload, item) }
715            #[cfg(not(hax))]
716            { let _ = payload; item }
717        }
718    };
719}
720
721quoting_proc_macros!(
722    fstar,
723    fstar_expr,
724    fstar_prop_expr,
725    fstar_unsafe_expr,
726    fstar_before,
727    fstar_after,
728    fstar_replace,
729    fstar_replace_body
730);
731quoting_proc_macros!(
732    coq,
733    coq_expr,
734    coq_prop_expr,
735    coq_unsafe_expr,
736    coq_before,
737    coq_after,
738    coq_replace,
739    coq_replace_body
740);
741quoting_proc_macros!(
742    proverif,
743    proverif_expr,
744    proverif_prop_expr,
745    proverif_unsafe_expr,
746    proverif_before,
747    proverif_after,
748    proverif_replace,
749    proverif_replace_body
750);
751quoting_proc_macros!(
752    legacy_lean,
753    legacy_lean_expr,
754    legacy_lean_prop_expr,
755    legacy_lean_unsafe_expr,
756    legacy_lean_before,
757    legacy_lean_after,
758    legacy_lean_replace,
759    legacy_lean_replace_body
760);