zink_codegen/
revert.rs

1//! Revert macro
2
3use proc_macro::TokenStream;
4use proc_macro2::{Literal, Span};
5use quote::{quote, ToTokens};
6use syn::{
7    parse::{Parse, ParseStream},
8    parse2, Expr, Ident, LitStr, Token,
9};
10
11/// Revert with message
12pub fn parse(input: LitStr) -> TokenStream {
13    let message = input.value();
14    let len = message.len() as i32;
15    if len > 128 {
16        panic!("Only support revert message less than 128 bytes atm.");
17    }
18
19    // TODO: handle the string correctly
20    let lit = Literal::string(&message.replace("\"", ""));
21    let rev = Ident::new(
22        &format!(
23            "revert{}",
24            match len {
25                len if len > 96 => 4,
26                len if len > 64 => 3,
27                len if len > 32 => 2,
28                len if len > 0 => 1,
29                _ => panic!("Only support revert message less than 128 bytes atm."),
30            },
31        ),
32        Span::call_site(),
33    );
34
35    quote! {
36        unsafe { zink::ffi::asm::#rev(#lit) }
37    }
38    .into()
39}
40
41/// Parse assert macro
42pub fn parse_assert(input: AssertInput) -> TokenStream {
43    let cond = input.cond;
44    let revert: Expr = syn::parse2(
45        parse(
46            input
47                .message
48                .unwrap_or(LitStr::new("unknown error", Span::call_site())),
49        )
50        .into(),
51    )
52    .expect("Invalid revert message");
53
54    quote! {
55        if !#cond {
56            #revert
57        }
58    }
59    .into()
60}
61
62/// Assert input
63pub struct AssertInput {
64    pub cond: Expr,
65    pub comma: Token![,],
66    pub message: Option<LitStr>,
67}
68
69impl Parse for AssertInput {
70    fn parse(input: ParseStream) -> syn::Result<Self> {
71        Ok(AssertInput {
72            cond: input.parse()?,
73            comma: input.parse()?,
74            message: input.parse()?,
75        })
76    }
77}