1#![doc = "This crate provides a set of macros and derive attributes to simplify the process of writing"]
2#![doc = "smart contracts for the Odra platform."]
3#![feature(box_patterns, result_flattening)]
4use crate::utils::IntoCode;
5use ast::*;
6use ir::{ModuleImplIR, ModuleStructIR, TypeIR};
7use proc_macro::TokenStream;
8use proc_macro2::TokenStream as TokenStream2;
9
10mod ast;
11mod ir;
12#[cfg(test)]
13mod test_utils;
14mod utils;
15
16macro_rules! span_error {
17 ($span:ident, $msg:expr) => {
18 syn::Error::new(syn::spanned::Spanned::span(&$span), $msg)
19 .to_compile_error()
20 .into()
21 };
22}
23
24#[proc_macro_attribute]
33pub fn module(attr: TokenStream, item: TokenStream) -> TokenStream {
34 let attr: TokenStream2 = attr.into();
35 let item: TokenStream2 = item.into();
36 if let Ok(ir) = ModuleImplIR::try_from((&attr, &item)) {
37 return ModuleImplItem::try_from(&ir).into_code();
38 }
39 if let Ok(ir) = ModuleStructIR::try_from((&attr, &item)) {
40 return ModuleStructItem::try_from(&ir).into_code();
41 }
42 span_error!(item, "Struct or impl block expected")
43}
44
45#[proc_macro_attribute]
50pub fn odra_type(_attr: TokenStream, item: TokenStream) -> TokenStream {
51 let item = item.into();
52 if let Ok(ir) = TypeIR::try_from(&item) {
53 return OdraTypeAttrItem::try_from(&ir).into_code();
54 }
55 span_error!(item, "Struct or Enum expected")
56}
57
58#[proc_macro_attribute]
60pub fn odra_error(_attr: TokenStream, item: TokenStream) -> TokenStream {
61 let item = item.into();
62 if let Ok(ir) = TypeIR::try_from(&item) {
63 return OdraErrorAttrItem::try_from(&ir).into_code();
64 }
65 span_error!(item, "Struct or Enum expected")
66}
67
68#[proc_macro_attribute]
74pub fn external_contract(attr: TokenStream, item: TokenStream) -> TokenStream {
75 let attr: TokenStream2 = attr.into();
76 let item: TokenStream2 = item.into();
77 if let Ok(ir) = ModuleImplIR::try_from((&attr, &item)) {
78 return ExternalContractImpl::try_from(&ir).into_code();
79 }
80 span_error!(
81 item,
82 "#[external_contract] can be only applied to trait only"
83 )
84}
85
86#[proc_macro_attribute]
88pub fn event(_attr: TokenStream, input: TokenStream) -> TokenStream {
89 let input: TokenStream2 = input.into();
90 OdraEventItem::try_from(&input).into_code()
91}
92
93#[proc_macro_derive(IntoRuntimeArgs)]
98pub fn derive_into_runtime_args(item: TokenStream) -> TokenStream {
99 let item = syn::parse_macro_input!(item as syn::DeriveInput);
100 let args_ident = syn::Ident::new("args", item.ident.span());
101 match item {
102 syn::DeriveInput {
103 ident,
104 data: syn::Data::Struct(syn::DataStruct { fields, .. }),
105 ..
106 } => {
107 let fields = fields
108 .into_iter()
109 .map(|f| {
110 let name = f.ident.unwrap();
111 quote::quote!(odra::args::EntrypointArgument::insert_runtime_arg(self.#name, stringify!(#name), &mut #args_ident);)
112 })
113 .collect::<proc_macro2::TokenStream>();
114 let res = quote::quote! {
115 impl Into<odra::casper_types::RuntimeArgs> for #ident {
116 fn into(self) -> odra::casper_types::RuntimeArgs {
117 let mut #args_ident = odra::casper_types::RuntimeArgs::new();
118 #fields
119 #args_ident
120 }
121 }
122 };
123 res.into()
124 }
125 _ => panic!("Struct expected")
126 }
127}