Add #[interrupt] macro to register static interrupts.
				
					
				
			This commit is contained in:
		@@ -3,9 +3,13 @@
 | 
				
			|||||||
extern crate proc_macro;
 | 
					extern crate proc_macro;
 | 
				
			||||||
 | 
					
 | 
				
			||||||
use darling::FromMeta;
 | 
					use darling::FromMeta;
 | 
				
			||||||
use proc_macro::{Span, TokenStream};
 | 
					use proc_macro::TokenStream;
 | 
				
			||||||
 | 
					use proc_macro2::Span;
 | 
				
			||||||
use quote::{format_ident, quote};
 | 
					use quote::{format_ident, quote};
 | 
				
			||||||
 | 
					use std::iter;
 | 
				
			||||||
use syn::spanned::Spanned;
 | 
					use syn::spanned::Spanned;
 | 
				
			||||||
 | 
					use syn::{parse, Type, Visibility};
 | 
				
			||||||
 | 
					use syn::{ItemFn, ReturnType};
 | 
				
			||||||
 | 
					
 | 
				
			||||||
mod path;
 | 
					mod path;
 | 
				
			||||||
 | 
					
 | 
				
			||||||
@@ -58,10 +62,9 @@ pub fn task(args: TokenStream, item: TokenStream) -> TokenStream {
 | 
				
			|||||||
        fail = true;
 | 
					        fail = true;
 | 
				
			||||||
    }
 | 
					    }
 | 
				
			||||||
    if pool_size < 1 {
 | 
					    if pool_size < 1 {
 | 
				
			||||||
        Span::call_site()
 | 
					        return parse::Error::new(Span::call_site(), "pool_size must be 1 or greater")
 | 
				
			||||||
            .error("pool_size must be 1 or greater")
 | 
					            .to_compile_error()
 | 
				
			||||||
            .emit();
 | 
					            .into();
 | 
				
			||||||
        fail = true
 | 
					 | 
				
			||||||
    }
 | 
					    }
 | 
				
			||||||
 | 
					
 | 
				
			||||||
    let mut arg_names: syn::punctuated::Punctuated<syn::Ident, syn::Token![,]> =
 | 
					    let mut arg_names: syn::punctuated::Punctuated<syn::Ident, syn::Token![,]> =
 | 
				
			||||||
@@ -120,6 +123,66 @@ pub fn task(args: TokenStream, item: TokenStream) -> TokenStream {
 | 
				
			|||||||
    result.into()
 | 
					    result.into()
 | 
				
			||||||
}
 | 
					}
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					#[proc_macro_attribute]
 | 
				
			||||||
 | 
					pub fn interrupt(args: TokenStream, input: TokenStream) -> TokenStream {
 | 
				
			||||||
 | 
					    let mut f: ItemFn = syn::parse(input).expect("`#[interrupt]` must be applied to a function");
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					    if !args.is_empty() {
 | 
				
			||||||
 | 
					        return parse::Error::new(Span::call_site(), "This attribute accepts no arguments")
 | 
				
			||||||
 | 
					            .to_compile_error()
 | 
				
			||||||
 | 
					            .into();
 | 
				
			||||||
 | 
					    }
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					    let fspan = f.span();
 | 
				
			||||||
 | 
					    let ident = f.sig.ident.clone();
 | 
				
			||||||
 | 
					    let ident_s = ident.to_string();
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					    // XXX should we blacklist other attributes?
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					    let valid_signature = f.sig.constness.is_none()
 | 
				
			||||||
 | 
					        && f.vis == Visibility::Inherited
 | 
				
			||||||
 | 
					        && f.sig.abi.is_none()
 | 
				
			||||||
 | 
					        && f.sig.inputs.is_empty()
 | 
				
			||||||
 | 
					        && f.sig.generics.params.is_empty()
 | 
				
			||||||
 | 
					        && f.sig.generics.where_clause.is_none()
 | 
				
			||||||
 | 
					        && f.sig.variadic.is_none()
 | 
				
			||||||
 | 
					        && match f.sig.output {
 | 
				
			||||||
 | 
					            ReturnType::Default => true,
 | 
				
			||||||
 | 
					            ReturnType::Type(_, ref ty) => match **ty {
 | 
				
			||||||
 | 
					                Type::Tuple(ref tuple) => tuple.elems.is_empty(),
 | 
				
			||||||
 | 
					                Type::Never(..) => true,
 | 
				
			||||||
 | 
					                _ => false,
 | 
				
			||||||
 | 
					            },
 | 
				
			||||||
 | 
					        };
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					    if !valid_signature {
 | 
				
			||||||
 | 
					        return parse::Error::new(
 | 
				
			||||||
 | 
					            fspan,
 | 
				
			||||||
 | 
					            "`#[interrupt]` handlers must have signature `[unsafe] fn() [-> !]`",
 | 
				
			||||||
 | 
					        )
 | 
				
			||||||
 | 
					        .to_compile_error()
 | 
				
			||||||
 | 
					        .into();
 | 
				
			||||||
 | 
					    }
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					    f.block.stmts = iter::once(
 | 
				
			||||||
 | 
					        syn::parse2(quote! {{
 | 
				
			||||||
 | 
					            // Check that this interrupt actually exists
 | 
				
			||||||
 | 
					            let __irq_exists_check: interrupt::#ident;
 | 
				
			||||||
 | 
					        }})
 | 
				
			||||||
 | 
					        .unwrap(),
 | 
				
			||||||
 | 
					    )
 | 
				
			||||||
 | 
					    .chain(f.block.stmts)
 | 
				
			||||||
 | 
					    .collect();
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					    quote!(
 | 
				
			||||||
 | 
					        #[doc(hidden)]
 | 
				
			||||||
 | 
					        #[export_name = #ident_s]
 | 
				
			||||||
 | 
					        #[allow(non_snake_case)]
 | 
				
			||||||
 | 
					        #f
 | 
				
			||||||
 | 
					    )
 | 
				
			||||||
 | 
					    .into()
 | 
				
			||||||
 | 
					}
 | 
				
			||||||
 | 
					
 | 
				
			||||||
#[proc_macro]
 | 
					#[proc_macro]
 | 
				
			||||||
pub fn interrupt_declare(item: TokenStream) -> TokenStream {
 | 
					pub fn interrupt_declare(item: TokenStream) -> TokenStream {
 | 
				
			||||||
    let name = syn::parse_macro_input!(item as syn::Ident);
 | 
					    let name = syn::parse_macro_input!(item as syn::Ident);
 | 
				
			||||||
 
 | 
				
			|||||||
@@ -72,3 +72,4 @@ pub mod interrupt {
 | 
				
			|||||||
    pub use embassy::interrupt::{declare, take, Interrupt};
 | 
					    pub use embassy::interrupt::{declare, take, Interrupt};
 | 
				
			||||||
    pub use embassy_extras::interrupt::Priority3 as Priority;
 | 
					    pub use embassy_extras::interrupt::Priority3 as Priority;
 | 
				
			||||||
}
 | 
					}
 | 
				
			||||||
 | 
					pub use embassy_macros::interrupt;
 | 
				
			||||||
 
 | 
				
			|||||||
		Reference in New Issue
	
	Block a user