1use 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
11pub 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 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
41pub 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
62pub 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}