aboutsummaryrefslogtreecommitdiff
path: root/embassy-macros/src
diff options
context:
space:
mode:
Diffstat (limited to 'embassy-macros/src')
-rw-r--r--embassy-macros/src/lib.rs73
1 files changed, 68 insertions, 5 deletions
diff --git a/embassy-macros/src/lib.rs b/embassy-macros/src/lib.rs
index ce643ae89..590289f94 100644
--- a/embassy-macros/src/lib.rs
+++ b/embassy-macros/src/lib.rs
@@ -3,9 +3,13 @@
3extern crate proc_macro; 3extern crate proc_macro;
4 4
5use darling::FromMeta; 5use darling::FromMeta;
6use proc_macro::{Span, TokenStream}; 6use proc_macro::TokenStream;
7use proc_macro2::Span;
7use quote::{format_ident, quote}; 8use quote::{format_ident, quote};
9use std::iter;
8use syn::spanned::Spanned; 10use syn::spanned::Spanned;
11use syn::{parse, Type, Visibility};
12use syn::{ItemFn, ReturnType};
9 13
10mod path; 14mod path;
11 15
@@ -58,10 +62,9 @@ pub fn task(args: TokenStream, item: TokenStream) -> TokenStream {
58 fail = true; 62 fail = true;
59 } 63 }
60 if pool_size < 1 { 64 if pool_size < 1 {
61 Span::call_site() 65 return parse::Error::new(Span::call_site(), "pool_size must be 1 or greater")
62 .error("pool_size must be 1 or greater") 66 .to_compile_error()
63 .emit(); 67 .into();
64 fail = true
65 } 68 }
66 69
67 let mut arg_names: syn::punctuated::Punctuated<syn::Ident, syn::Token![,]> = 70 let mut arg_names: syn::punctuated::Punctuated<syn::Ident, syn::Token![,]> =
@@ -120,6 +123,66 @@ pub fn task(args: TokenStream, item: TokenStream) -> TokenStream {
120 result.into() 123 result.into()
121} 124}
122 125
126#[proc_macro_attribute]
127pub fn interrupt(args: TokenStream, input: TokenStream) -> TokenStream {
128 let mut f: ItemFn = syn::parse(input).expect("`#[interrupt]` must be applied to a function");
129
130 if !args.is_empty() {
131 return parse::Error::new(Span::call_site(), "This attribute accepts no arguments")
132 .to_compile_error()
133 .into();
134 }
135
136 let fspan = f.span();
137 let ident = f.sig.ident.clone();
138 let ident_s = ident.to_string();
139
140 // XXX should we blacklist other attributes?
141
142 let valid_signature = f.sig.constness.is_none()
143 && f.vis == Visibility::Inherited
144 && f.sig.abi.is_none()
145 && f.sig.inputs.is_empty()
146 && f.sig.generics.params.is_empty()
147 && f.sig.generics.where_clause.is_none()
148 && f.sig.variadic.is_none()
149 && match f.sig.output {
150 ReturnType::Default => true,
151 ReturnType::Type(_, ref ty) => match **ty {
152 Type::Tuple(ref tuple) => tuple.elems.is_empty(),
153 Type::Never(..) => true,
154 _ => false,
155 },
156 };
157
158 if !valid_signature {
159 return parse::Error::new(
160 fspan,
161 "`#[interrupt]` handlers must have signature `[unsafe] fn() [-> !]`",
162 )
163 .to_compile_error()
164 .into();
165 }
166
167 f.block.stmts = iter::once(
168 syn::parse2(quote! {{
169 // Check that this interrupt actually exists
170 let __irq_exists_check: interrupt::#ident;
171 }})
172 .unwrap(),
173 )
174 .chain(f.block.stmts)
175 .collect();
176
177 quote!(
178 #[doc(hidden)]
179 #[export_name = #ident_s]
180 #[allow(non_snake_case)]
181 #f
182 )
183 .into()
184}
185
123#[proc_macro] 186#[proc_macro]
124pub fn interrupt_declare(item: TokenStream) -> TokenStream { 187pub fn interrupt_declare(item: TokenStream) -> TokenStream {
125 let name = syn::parse_macro_input!(item as syn::Ident); 188 let name = syn::parse_macro_input!(item as syn::Ident);