mirror of
https://github.com/erg-lang/erg.git
synced 2025-09-28 04:09:05 +00:00
201 lines
5.8 KiB
Rust
201 lines
5.8 KiB
Rust
use proc_macro::TokenStream;
|
|
|
|
use quote::quote;
|
|
use syn::{
|
|
punctuated::Punctuated, AngleBracketedGenericArguments, GenericArgument, PathArguments,
|
|
ReturnType, Type, TypePath, TypeReference, TypeSlice,
|
|
};
|
|
|
|
/// ```rust_
|
|
/// #[exec_new_thread]
|
|
/// fn foo() -> Result<isize, Box<dyn std::error::Error>> {
|
|
/// ...
|
|
/// }
|
|
/// ```
|
|
/// ↓ ↓
|
|
/// ```rust_
|
|
/// fn foo() -> Result<isize, Box<dyn std::error::Error>> {
|
|
/// fn error(msg: impl Into<String>) -> std::io::Error {
|
|
/// std::io::Error::new(std::io::ErrorKind::Other, msg.into())
|
|
/// }
|
|
/// fn f() -> Result<(), Box<dyn std::error::Error + Send>> {
|
|
/// {...}.map_err(|e| Box::new(error(e.to_string())) as _)
|
|
/// }
|
|
/// exec_new_thread(f, "foo").map_err(|e| e as _)
|
|
/// }
|
|
/// ```
|
|
#[proc_macro_attribute]
|
|
pub fn exec_new_thread(_attr: TokenStream, item: TokenStream) -> TokenStream {
|
|
let mut item_fn = syn::parse_macro_input!(item as syn::ItemFn);
|
|
let name = item_fn.sig.ident.to_string();
|
|
let ReturnType::Type(_, out) = &item_fn.sig.output else {
|
|
todo!()
|
|
};
|
|
let Type::Path(TypePath { path, .. }) = out.as_ref() else {
|
|
todo!()
|
|
};
|
|
let result_t = path.segments.first().unwrap();
|
|
let PathArguments::AngleBracketed(args) = &result_t.arguments else {
|
|
todo!()
|
|
};
|
|
let t = args.args.first().unwrap();
|
|
let name = syn::LitStr::new(&name, item_fn.sig.ident.span());
|
|
let block = item_fn.block;
|
|
let block = syn::parse_quote! {{
|
|
fn error(msg: impl Into<String>) -> std::io::Error {
|
|
std::io::Error::new(std::io::ErrorKind::Other, msg.into())
|
|
}
|
|
fn _f() -> Result<#t, Box<dyn std::error::Error>> {
|
|
#block
|
|
}
|
|
fn f() -> Result<#t, Box<dyn std::error::Error + Send>> {
|
|
_f().map_err(|e| Box::new(error(e.to_string())) as _)
|
|
}
|
|
erg_common::spawn::exec_new_thread(f, #name).map_err(|e| e as _)
|
|
}};
|
|
item_fn.block = Box::new(block);
|
|
let item = quote! { #item_fn };
|
|
item.into()
|
|
}
|
|
|
|
/// dummy attribute
|
|
#[proc_macro_attribute]
|
|
pub fn pyo3(_attr: TokenStream, item: TokenStream) -> TokenStream {
|
|
item
|
|
}
|
|
|
|
/// dummy attribute
|
|
#[proc_macro_attribute]
|
|
pub fn pyclass(_attr: TokenStream, item: TokenStream) -> TokenStream {
|
|
item
|
|
}
|
|
|
|
/// dummy attribute
|
|
#[proc_macro_attribute]
|
|
pub fn pymethods(_attr: TokenStream, item: TokenStream) -> TokenStream {
|
|
item
|
|
}
|
|
|
|
/// dummy attribute
|
|
#[proc_macro_attribute]
|
|
pub fn staticmethod(_attr: TokenStream, item: TokenStream) -> TokenStream {
|
|
item
|
|
}
|
|
|
|
/// dummy attribute
|
|
#[proc_macro_attribute]
|
|
pub fn classmethod(_attr: TokenStream, item: TokenStream) -> TokenStream {
|
|
item
|
|
}
|
|
|
|
/// dummy attribute
|
|
#[proc_macro_attribute]
|
|
pub fn getter(_attr: TokenStream, item: TokenStream) -> TokenStream {
|
|
item
|
|
}
|
|
|
|
/// dummy attribute
|
|
#[proc_macro_attribute]
|
|
pub fn setter(_attr: TokenStream, item: TokenStream) -> TokenStream {
|
|
item
|
|
}
|
|
|
|
/// dummy attribute
|
|
#[proc_macro_attribute]
|
|
pub fn new(_attr: TokenStream, item: TokenStream) -> TokenStream {
|
|
item
|
|
}
|
|
|
|
fn args_to_owned(args: &PathArguments) -> PathArguments {
|
|
match args {
|
|
PathArguments::AngleBracketed(args) => {
|
|
let res = args
|
|
.args
|
|
.iter()
|
|
.map(|arg| match arg {
|
|
GenericArgument::Type(t) => GenericArgument::Type(type_to_owned(t)),
|
|
_ => arg.clone(),
|
|
})
|
|
.collect::<Vec<_>>();
|
|
let mut punc = Punctuated::new();
|
|
punc.extend(res);
|
|
let args = AngleBracketedGenericArguments {
|
|
colon2_token: args.colon2_token,
|
|
lt_token: args.lt_token,
|
|
args: punc,
|
|
gt_token: args.gt_token,
|
|
};
|
|
PathArguments::AngleBracketed(args)
|
|
}
|
|
_ => args.clone(),
|
|
}
|
|
}
|
|
|
|
fn type_to_owned(t: &Type) -> Type {
|
|
match t {
|
|
Type::Reference(TypeReference { elem, .. }) => match elem.as_ref() {
|
|
Type::Slice(TypeSlice { elem, .. }) => syn::parse_quote! { Vec<#elem> },
|
|
Type::Path(TypePath { path, .. }) => {
|
|
match path.segments.first().unwrap().ident.to_string().as_str() {
|
|
"str" => syn::parse_quote! { String },
|
|
_ => elem.as_ref().clone(),
|
|
}
|
|
}
|
|
_ => elem.as_ref().clone(),
|
|
},
|
|
Type::Path(TypePath { qself, path }) => {
|
|
let mut segments = Punctuated::new();
|
|
segments.extend(path.segments.iter().map(|seg| {
|
|
let mut seg = seg.clone();
|
|
seg.arguments = args_to_owned(&seg.arguments);
|
|
seg
|
|
}));
|
|
let path = syn::Path {
|
|
leading_colon: path.leading_colon,
|
|
segments,
|
|
};
|
|
Type::Path(TypePath {
|
|
qself: qself.to_owned(),
|
|
path,
|
|
})
|
|
}
|
|
_ => t.clone(),
|
|
}
|
|
}
|
|
|
|
/// ```rust
|
|
/// #[erg_proc_macros::to_owned]
|
|
/// fn foo(s: &str) -> &str { s }
|
|
/// ```
|
|
/// ↓ ↓
|
|
/// ```rust
|
|
/// fn foo(s: &str) -> String { let r = s; r.to_owned() }
|
|
/// ```
|
|
#[proc_macro_attribute]
|
|
pub fn to_owned(attr: TokenStream, item: TokenStream) -> TokenStream {
|
|
let mut item_fn = syn::parse_macro_input!(item as syn::ItemFn);
|
|
let ReturnType::Type(_, out) = &item_fn.sig.output else {
|
|
todo!()
|
|
};
|
|
let out = type_to_owned(out);
|
|
let block = item_fn.block;
|
|
let block = if attr
|
|
.into_iter()
|
|
.next()
|
|
.is_some_and(|attr| attr.to_string().as_str() == "cloned")
|
|
{
|
|
syn::parse_quote! {{
|
|
let r = #block;
|
|
r.cloned()
|
|
}}
|
|
} else {
|
|
syn::parse_quote! {{
|
|
let r = #block;
|
|
r.to_owned()
|
|
}}
|
|
};
|
|
item_fn.block = Box::new(block);
|
|
item_fn.sig.output = syn::parse_quote! { -> #out };
|
|
let item = quote! { #item_fn };
|
|
item.into()
|
|
}
|