polyhal_macro/
lib.rs

1use proc_macro::TokenStream;
2use proc_macro2::Span;
3use proc_macro_crate::{crate_name, FoundCrate};
4use quote::{format_ident, quote};
5use syn::{
6    parse_macro_input, spanned::Spanned, Error, Ident, ItemFn, ItemStatic, StaticMutability, Token,
7};
8
9#[proc_macro_attribute]
10pub fn arch_entry(_input: TokenStream, annotated_item: TokenStream) -> TokenStream {
11    let annotated_item = parse_macro_input!(annotated_item as ItemFn);
12    TokenStream::from(quote! {
13        #[export_name = "_main_for_arch"]
14        #annotated_item
15    })
16}
17
18#[proc_macro_attribute]
19pub fn arch_interrupt(_input: TokenStream, annotated_item: TokenStream) -> TokenStream {
20    let annotated_item = parse_macro_input!(annotated_item as ItemFn);
21    TokenStream::from(quote! {
22        #[export_name = "_interrupt_for_arch"]
23        #annotated_item
24    })
25}
26
27#[proc_macro_attribute]
28pub fn percpu(attr: TokenStream, item: TokenStream) -> TokenStream {
29    if !attr.is_empty() {
30        return compiler_error(Error::new(
31            Span::call_site(),
32            "expect an empty attribute: `#[def_percpu]`",
33        ));
34    }
35
36    let found_crate = crate_name("polyhal").expect("polyhal is present in `Cargo.toml`");
37    let mut ast = syn::parse_macro_input!(item as ItemStatic);
38    ast.mutability = StaticMutability::Mut(Token![mut](ast.span()));
39
40    let raw_name = ast.ident.clone();
41    ast.ident = format_ident!("__PERCPU_{}", raw_name);
42    let ast_name = &ast.ident;
43    let vis = &ast.vis;
44
45    let raw_ty = ast.ty.clone();
46
47    let ty_path = match found_crate {
48        FoundCrate::Itself => quote!(crate::utils::percpu::PerCPU),
49        FoundCrate::Name(name) => {
50            let ident = Ident::new(&name, Span::call_site());
51            quote!( #ident::utils::percpu::PerCPU )
52        }
53    };
54
55    quote! {
56        #[unsafe(link_section = "percpu")]
57        #ast
58
59        #vis static #raw_name: #ty_path<#raw_ty> = #ty_path::new(&raw mut #ast_name);
60    }
61    .into()
62}
63
64#[proc_macro]
65pub fn define_arch_mods(_input: TokenStream) -> TokenStream {
66    quote! {
67        #[cfg(target_arch = "riscv64")]
68        mod riscv64;
69        #[cfg(target_arch = "riscv64")]
70        #[allow(unused_imports)]
71        pub use riscv64::*;
72        #[cfg(target_arch = "aarch64")]
73        mod aarch64;
74        #[cfg(target_arch = "aarch64")]
75        #[allow(unused_imports)]
76        pub use aarch64::*;
77        #[cfg(target_arch = "x86_64")]
78        mod x86_64;
79        #[cfg(target_arch = "x86_64")]
80        #[allow(unused_imports)]
81        pub use x86_64::*;
82        #[cfg(target_arch = "loongarch64")]
83        mod loongarch64;
84        #[cfg(target_arch = "loongarch64")]
85        #[allow(unused_imports)]
86        pub use loongarch64::*;
87    }
88    .into()
89}
90
91fn compiler_error(err: Error) -> TokenStream {
92    err.to_compile_error().into()
93}