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 named 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/// `refine` and `order` may also be written behind a `cfg_attr`, e.g.
466/// `#[cfg_attr(hax_backend_fstar, refine(..))]` to refine a field for one
467/// backend only. At most one `refine` and one `order` may be enabled per field.
468///
469/// ### `decreases`, `ensures` and `requires` (on a `fn` in an `impl`)
470/// `decreases`, `ensures`, `requires`: behave exactly as documented above on
471/// the proc attributes of the same name.
472///
473/// Those may also be written behind a `cfg_attr`, e.g.
474/// `#[cfg_attr(hax, requires(..))]`: the predicate is preserved, so the
475/// specification appears exactly when the predicate holds. This makes
476/// `hax-lib` usable as a `cfg(hax)`-gated dependency.
477///
478/// # Example
479///
480/// ```
481/// #[hax_lib_macros::attributes]
482/// mod foo {
483/// pub struct Hello {
484/// pub x: u32,
485/// #[refine(y > 3)]
486/// pub y: u32,
487/// #[refine(y + x + z > 3)]
488/// pub z: u32,
489/// }
490/// impl Hello {
491/// fn sum(&self) -> u32 {
492/// self.x + self.y + self.z
493/// }
494/// #[ensures(|result| result - n == self.sum())]
495/// fn plus(self, n: u32) -> u32 {
496/// self.sum() + n
497/// }
498/// }
499/// }
500/// ```
501#[proc_macro_attribute]
502pub fn attributes(attr: TokenStream, item: TokenStream) -> TokenStream {
503 #[cfg(hax)]
504 {
505 implementation::attributes(attr, item)
506 }
507 #[cfg(not(hax))]
508 {
509 let _ = attr;
510 dummy::attributes(item)
511 }
512}
513
514/// Create a mathematical integer. This macro expects a Rust integer
515/// literal without suffix.
516///
517/// ## Examples:
518/// - `int!(0x101010)`
519/// - `int!(42)`
520/// - `int!(0o52)`
521/// - `int!(0h2A)`
522#[proc_macro]
523pub fn int(payload: TokenStream) -> TokenStream {
524 #[cfg(hax)]
525 {
526 implementation::int(payload)
527 }
528 #[cfg(not(hax))]
529 {
530 dummy::int(payload)
531 }
532}
533
534/// Add an invariant to a loop which deals with an index. The
535/// invariant cannot refer to any variable introduced within the
536/// loop. An invariant is a closure that takes one argument, the
537/// index, and returns a proposition.
538///
539/// Note that loop invariants are unstable (this will be handled in a
540/// better way in the future, see
541/// <https://github.com/hacspec/hax/issues/858>) and only supported on
542/// specific `for` loops with specific iterators:
543///
544/// - `for i in start..end {...}`
545/// - `for i in (start..end).step_by(n) {...}`
546/// - `for i in slice.enumerate() {...}`
547/// - `for i in slice.chunks_exact(n).enumerate() {...}`
548///
549/// This function must be called on the first line of a loop body to
550/// be effective. Note that in the invariant expression, `forall`,
551/// `exists`, and `BACKEND!` (`BACKEND` can be `fstar`, `proverif`,
552/// `coq`...) are in scope.
553#[proc_macro]
554pub fn loop_invariant(predicate: TokenStream) -> TokenStream {
555 #[cfg(hax)]
556 {
557 implementation::loop_invariant(predicate)
558 }
559 #[cfg(not(hax))]
560 {
561 let _ = predicate;
562 TokenStream::new()
563 }
564}
565
566/// Must be used to prove termination of while loops. This takes an
567/// expression that should be a usize that decreases at every iteration
568///
569/// This function must be called just after `loop_invariant`, or at the first
570/// line of the loop if there is no invariant.
571#[proc_macro]
572pub fn loop_decreases(predicate: TokenStream) -> TokenStream {
573 #[cfg(hax)]
574 {
575 implementation::loop_decreases(predicate)
576 }
577 #[cfg(not(hax))]
578 {
579 let _ = predicate;
580 TokenStream::new()
581 }
582}
583
584/// Internal macro for dealing with function decorations
585/// (`#[decreases(...)]`, `#[ensures(...)]`, `#[requires(...)]`) on
586/// `fn` items within an `impl` block. There is special handling since
587/// such functions might have a `self` argument: in such cases, we
588/// rewrite function decorations as `#[impl_fn_decoration(<KIND>,
589/// <GENERICS>, <WHERE CLAUSE>, <SELF TYPE> [as <TRAIT>], <BODY>)]`, where
590/// `<TRAIT>` is the trait implemented by the enclosing `impl` block.
591#[proc_macro_attribute]
592pub fn impl_fn_decoration(attr: TokenStream, item: TokenStream) -> TokenStream {
593 #[cfg(hax)]
594 {
595 implementation::impl_fn_decoration(attr, item)
596 }
597 #[cfg(not(hax))]
598 {
599 let _ = (attr, item);
600 dummy::internal_macro_misuse("impl_fn_decoration")
601 }
602}
603
604/// Internal macro for dealing with function decorations on `fn` items within a
605/// `trait`. See [`macro@impl_fn_decoration`].
606#[proc_macro_attribute]
607pub fn trait_fn_decoration(attr: TokenStream, item: TokenStream) -> TokenStream {
608 #[cfg(hax)]
609 {
610 implementation::trait_fn_decoration(attr, item)
611 }
612 #[cfg(not(hax))]
613 {
614 let _ = (attr, item);
615 dummy::internal_macro_misuse("trait_fn_decoration")
616 }
617}
618
619/// Defines the item-level quoting attributes of a backend: `<BACKEND>_before`
620/// and `<BACKEND>_after`.
621macro_rules! item_quoting_proc_macros {
622 ($backend:ident, $(($name:ident, $position:literal)),*) => {$(
623 #[doc = concat!("This macro inlines verbatim ", stringify!($backend), " code ", $position, " a Rust item.")]
624 ///
625 /// This macro takes a string literal containing backend
626 /// code. Just as backend expression macros, this literal can
627 /// contains dollar-prefixed Rust names.
628 ///
629 /// Note: when targetting F*, you can prepend a first
630 /// comma-separated argument: `interface`, `impl` or
631 /// `both`. This controls where the code will apprear: in the
632 /// `fst` or `fsti` files or both.
633 #[proc_macro_attribute]
634 pub fn $name(payload: TokenStream, item: TokenStream) -> TokenStream {
635 #[cfg(hax)]
636 { implementation::$name(payload, item) }
637 #[cfg(not(hax))]
638 { let _ = payload; item }
639 }
640 )*};
641}
642
643/// Defines every proc-macro attached to a given backend.
644macro_rules! quoting_proc_macros {
645 ($backend:ident, $expr:ident, $prop_expr:ident, $unsafe_expr:ident,
646 $before:ident, $after:ident, $replace:ident, $replace_body:ident) => {
647 #[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.")]
648 ///
649 /// While it is possible to directly write raw backend code,
650 /// sometimes it can be inconvenient. For example, referencing
651 /// Rust names can be a bit cumbersome: for example, the name
652 /// `my_crate::my_module::CONSTANT` might be translated
653 /// differently in a backend (e.g. in the F* backend, it will
654 /// probably be `My_crate.My_module.v_CONSTANT`).
655 ///
656 /// To facilitate this, you can write Rust names directly,
657 /// using the prefix `$`: `f $my_crate::my_module__CONSTANT + 3`
658 /// will be replaced with `f My_crate.My_module.v_CONSTANT + 3`
659 /// in the F* backend for instance.
660 ///
661 /// If you want to refer to the Rust constructor
662 /// `Enum::Variant`, you should write `$$Enum::Variant` (note
663 /// the double dollar).
664 ///
665 /// If the name refers to something polymorphic, you need to
666 /// signal it by adding _any_ type informations,
667 /// e.g. `${my_module::function<()>}`. The curly braces are
668 /// needed for such more complex expressions.
669 ///
670 /// You can also write Rust patterns with the `$?{SYNTAX}`
671 /// syntax, where `SYNTAX` is a Rust pattern. The syntax
672 /// `${EXPR}` also allows any Rust expressions
673 /// `EXPR` to be embedded.
674 ///
675 /// Types can be refered to with the syntax `$:{TYPE}`.
676 #[proc_macro]
677 pub fn $expr(payload: TokenStream) -> TokenStream {
678 #[cfg(hax)]
679 { implementation::$expr(payload) }
680 #[cfg(not(hax))]
681 { let _ = payload; dummy::unit_expr() }
682 }
683
684 #[doc = concat!("The `Prop` version of `", stringify!($backend), "_expr`.")]
685 #[proc_macro]
686 pub fn $prop_expr(payload: TokenStream) -> TokenStream {
687 #[cfg(hax)]
688 { implementation::$prop_expr(payload) }
689 #[cfg(not(hax))]
690 { let _ = payload; dummy::prop_expr() }
691 }
692
693 #[doc = concat!("The unsafe (because polymorphic: even computationally relevant code can be inlined!) version of `", stringify!($backend), "_expr`.")]
694 #[proc_macro]
695 #[doc(hidden)]
696 pub fn $unsafe_expr(payload: TokenStream) -> TokenStream {
697 #[cfg(hax)]
698 { implementation::$unsafe_expr(payload) }
699 #[cfg(not(hax))]
700 { let _ = payload; dummy::unsafe_expr() }
701 }
702
703 item_quoting_proc_macros!($backend, ($before, "before"), ($after, "after"));
704
705 #[doc = concat!("Replaces a Rust item with some verbatim ", stringify!($backend)," code.")]
706 #[proc_macro_attribute]
707 pub fn $replace(payload: TokenStream, item: TokenStream) -> TokenStream {
708 #[cfg(hax)]
709 { implementation::$replace(payload, item) }
710 #[cfg(not(hax))]
711 { let _ = payload; item }
712 }
713
714 #[doc = concat!("Replaces the body of a Rust function with some verbatim ", stringify!($backend)," code.")]
715 #[proc_macro_attribute]
716 pub fn $replace_body(payload: TokenStream, item: TokenStream) -> TokenStream {
717 #[cfg(hax)]
718 { implementation::$replace_body(payload, item) }
719 #[cfg(not(hax))]
720 { let _ = payload; item }
721 }
722 };
723}
724
725quoting_proc_macros!(
726 fstar,
727 fstar_expr,
728 fstar_prop_expr,
729 fstar_unsafe_expr,
730 fstar_before,
731 fstar_after,
732 fstar_replace,
733 fstar_replace_body
734);
735quoting_proc_macros!(
736 coq,
737 coq_expr,
738 coq_prop_expr,
739 coq_unsafe_expr,
740 coq_before,
741 coq_after,
742 coq_replace,
743 coq_replace_body
744);
745quoting_proc_macros!(
746 proverif,
747 proverif_expr,
748 proverif_prop_expr,
749 proverif_unsafe_expr,
750 proverif_before,
751 proverif_after,
752 proverif_replace,
753 proverif_replace_body
754);
755quoting_proc_macros!(
756 legacy_lean,
757 legacy_lean_expr,
758 legacy_lean_prop_expr,
759 legacy_lean_unsafe_expr,
760 legacy_lean_before,
761 legacy_lean_after,
762 legacy_lean_replace,
763 legacy_lean_replace_body
764);