diff options
| author | Dario Nieuwenhuis <[email protected]> | 2021-05-12 01:00:43 +0200 |
|---|---|---|
| committer | Dario Nieuwenhuis <[email protected]> | 2021-05-17 00:57:20 +0200 |
| commit | 92be72e0e3917782aade44e5b4cdbebb2dbab46e (patch) | |
| tree | db8a0b83ecb9006525ef5934e42d5ce92a2a3593 /embassy-macros/src | |
| parent | eb4571dc4ce46ef7d2689de881077a9d3c6bcc27 (diff) | |
Add `#[interrupt]` macro to register static interrupts.
Diffstat (limited to 'embassy-macros/src')
| -rw-r--r-- | embassy-macros/src/lib.rs | 73 |
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 @@ | |||
| 3 | extern crate proc_macro; | 3 | extern crate proc_macro; |
| 4 | 4 | ||
| 5 | use darling::FromMeta; | 5 | use darling::FromMeta; |
| 6 | use proc_macro::{Span, TokenStream}; | 6 | use proc_macro::TokenStream; |
| 7 | use proc_macro2::Span; | ||
| 7 | use quote::{format_ident, quote}; | 8 | use quote::{format_ident, quote}; |
| 9 | use std::iter; | ||
| 8 | use syn::spanned::Spanned; | 10 | use syn::spanned::Spanned; |
| 11 | use syn::{parse, Type, Visibility}; | ||
| 12 | use syn::{ItemFn, ReturnType}; | ||
| 9 | 13 | ||
| 10 | mod path; | 14 | mod 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] | ||
| 127 | pub 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] |
| 124 | pub fn interrupt_declare(item: TokenStream) -> TokenStream { | 187 | pub 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); |
