1use proc_macro::TokenStream;
2use quote::quote;
3use syn::{parse_macro_input, spanned::Spanned, ItemImpl};
4
5fn validate_fn(item: &syn::ImplItemFn, errors: &mut Vec<syn::Error>) {
6 if item.sig.unsafety.is_some() {
7 errors.push(syn::Error::new(item.sig.span(), "Function must not be unsafe."));
8 }
9
10 if item.sig.abi.is_some() {
11 errors.push(syn::Error::new(
12 item.sig.span(),
13 "Function must not have an ABI(extern C).",
14 ));
15 }
16
17 if item.sig.constness.is_some() {
18 errors.push(syn::Error::new(item.sig.span(), "Function must not be const."));
19 }
20
21 if item.sig.asyncness.is_some() {
22 errors.push(syn::Error::new(item.sig.span(), "Function must not be async."));
23 }
24
25 if !item.sig.generics.params.is_empty() {
26 errors.push(syn::Error::new(
27 item.sig.generics.span(),
28 "Function must not have generics or lifetimes.",
29 ));
30 }
31
32 if !item.sig.inputs.is_empty() {
33 errors.push(syn::Error::new(
34 item.sig.inputs.span(),
35 "Function must not take any arguments.",
36 ));
37 }
38
39 if item.sig.variadic.is_some() {
40 errors.push(syn::Error::new(
41 item.sig.variadic.span(),
42 "Function must not be variadic.",
43 ));
44 }
45
46 match &item.sig.output {
47 syn::ReturnType::Default => {}
48 _ => {
49 errors.push(syn::Error::new(
50 item.sig.output.span(),
51 "Function must not have a return type.",
52 ));
53 }
54 }
55}
56
57#[proc_macro_attribute]
58pub fn oracle_program(_attr: TokenStream, item: TokenStream) -> TokenStream {
59 let input = parse_macro_input!(item as ItemImpl);
60
61 let mut execute_fn = None;
63 let mut tally_fn = None;
64
65 let mut errors = Vec::new();
66 let input_span = input.span();
67 for item in input.items {
68 match item {
69 syn::ImplItem::Const(item) => errors.push(syn::Error::new(
70 item.span(),
71 "Consts are not allowed to be defined in this macro.",
72 )),
73 syn::ImplItem::Fn(item) => {
74 if item.sig.ident == "execute" {
75 execute_fn = Some(item);
76 } else if item.sig.ident == "tally" {
77 tally_fn = Some(item);
78 } else {
79 errors.push(syn::Error::new(
80 item.span(),
81 "Only the functions tally and execute are allowed.",
82 ));
83 }
84 }
85 syn::ImplItem::Type(item) => errors.push(syn::Error::new(
86 item.span(),
87 "Only the type Error is allowed to be defined in this macro.",
88 )),
89 syn::ImplItem::Macro(item) => errors.push(syn::Error::new(
90 item.span(),
91 "Macros are not allowed to be defined in this macro.",
92 )),
93 syn::ImplItem::Verbatim(item) => errors.push(syn::Error::new(
94 item.span(),
95 "Verbatims are not allowed to be defined in this macro.",
96 )),
97 _ => unreachable!(),
98 }
99 }
100
101 let (execute_fn, tally_fn) = match (execute_fn, tally_fn) {
104 (Some(execute_fn), Some(tally_fn)) => {
105 validate_fn(&execute_fn, &mut errors);
106 validate_fn(&tally_fn, &mut errors);
107 (execute_fn, tally_fn)
108 }
109 (Some(execute_fn), None) => {
110 let tally_fn: syn::ImplItemFn = syn::parse_quote! {
111 fn tally() {
112 seda_sdk_rs::Process::error(&"Tally is not implemented.".to_bytes());
113 }
114 };
115 validate_fn(&execute_fn, &mut errors);
116 (execute_fn, tally_fn)
117 }
118 (None, Some(tally_fn)) => {
119 let execute_fn: syn::ImplItemFn = syn::parse_quote! {
120 fn execute() {
121 seda_sdk_rs::Process::error(&"Execute is not implemented.".to_bytes());
122 }
123 };
124 validate_fn(&tally_fn, &mut errors);
125 (execute_fn, tally_fn)
126 }
127 (None, None) => {
128 let mut combined_error = syn::Error::new(
129 input_span,
130 "At least one of the functions execute or tally must be defined.",
131 );
132 for e in errors {
133 combined_error.combine(e);
134 }
135 return combined_error.to_compile_error().into();
136 }
137 };
138
139 if !errors.is_empty() {
140 let mut combined_error = errors.remove(0);
141 for e in errors {
142 combined_error.combine(e);
143 }
144 return combined_error.to_compile_error().into();
145 }
146
147 let expanded = quote! {
148
149 fn main() {
150
151 #execute_fn
152 #tally_fn
153
154 if seda_sdk_rs::Process::is_dr_vm_mode() {
155 return execute();
156 }
157 return tally();
158 }
159 };
160
161 TokenStream::from(expanded)
162}