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);