#![warn(unreachable_pub)]
#![cfg_attr(docsrs, feature(doc_cfg))]
mod task;
mod nano;
use proc_macro::TokenStream;
use quote::quote;
use syn::spanned::Spanned;
use syn::{parse_macro_input, parse_quote, Error, Item, ItemMod};
fn _nya_attr_checker(attr: TokenStream) -> bool {
let mut iter = attr.clone().into_iter();
match iter.next() {
Some(proc_macro::TokenTree::Punct(p)) if p.as_char() == '^' => {}
_ => return true,
}
match iter.next() {
Some(proc_macro::TokenTree::Ident(i)) if i.to_string() == "v" => {}
_ => return true,
}
match iter.next() {
Some(proc_macro::TokenTree::Punct(p)) if p.as_char() == '^' => {}
_ => return true,
}
let _ = iter.next().is_none();
let attr_str = attr.to_string().replace(" ", "");
const ALLOWED_MASCOTS: &[&str] = &[
"^v^",
"^^v",
">v<",
">v<ノ",
"^_^",
"^v^ノ",
];
ALLOWED_MASCOTS.contains(&attr_str.as_str())
}
#[proc_macro_attribute]
pub fn ヽ(attr: TokenStream, item: TokenStream) -> TokenStream {
match attr.to_string().as_str() {
"'ε'" => init(item),
_ => init(item)
}
}
fn init(item: TokenStream) -> TokenStream {
let mut input_mod = parse_macro_input!(item as ItemMod);
let (_, items) = match &input_mod.content {
Some(content) => content,
None => return Error::new_spanned(&input_mod, "必须使用 'mod xxx { ... }' 格式").to_compile_error().into(),
};
let allowed_functions = [
("master_setup", true),
("agent_setup", true),
("agent_main", true),
("agent_idle", false),
("on_panic", false),
("on_error", false),
("on_exit", false),
];
for item in items {
match item {
Item::Fn(f) => {
let fn_name = f.sig.ident.to_string();
let fn_span = f.sig.ident.span();
let (is_allowed, should_be_async) = match allowed_functions.iter().find(|(name, _)| *name == fn_name) {
Some(found) => (true, found.1),
None => (false, false),
};
if !is_allowed {
return Error::new(fn_span, format!("非法函数 '{}':#[v] 模块内只允许定义特定的框架函数", fn_name))
.to_compile_error().into();
}
let is_async = f.sig.asyncness.is_some();
if is_async != should_be_async {
let msg = if should_be_async { "必须是 async fn" } else { "不能是 async fn" };
return Error::new(f.sig.span(), format!("函数 '{}' {}", fn_name, msg))
.to_compile_error().into();
}
if !f.sig.inputs.is_empty() {
return Error::new(f.sig.inputs.span(), format!("函数 '{}' 不应该携带参数", fn_name))
.to_compile_error().into();
}
}
Item::Use(_) => {}, _ => {
return Error::new_spanned(item, "#[v] 模块内只能包含指定的函数和 use 语句")
.to_compile_error().into();
}
}
}
let entry_fn: Item = parse_quote! {
#[::uefi::entry] fn main() -> ::uefi::Status {
::uefi::println!("Hello, World!");
::uefi::boot::stall(::core::time::Duration::from_secs(120));
::uefi::Status::SUCCESS
}
};
if let Some((_, items)) = &mut input_mod.content {
items.push(entry_fn);
} else {
return Error::new_spanned(input_mod, "模块必须带有大括号内容")
.to_compile_error()
.into();
}
let expanded = quote! {
#[doc(hidden)]
pub static __ONLY_ONE_V_MACRO_ALLOWED__: () = ();
#input_mod
};
expanded.into()
}
#[proc_macro_attribute]
pub fn task(attr: TokenStream, item: TokenStream) -> TokenStream {
task::task(attr.into(), item.into()).into()
}
#[proc_macro]
pub fn nano(input: TokenStream) -> TokenStream { nano::task(input.into()).into() }
#[proc_macro]
pub fn join(input: TokenStream) -> TokenStream { nano::join::join(input.into(), false).into() }
#[proc_macro]
pub fn try_join(input: TokenStream) -> TokenStream { nano::join::join(input.into(), true).into() }
#[proc_macro]
pub fn join_all(input: TokenStream) -> TokenStream { nano::join::join_all(input.into()).into() }