From ebfdb1dafa430786db10dad2ef7d5467c1bdbed1 Mon Sep 17 00:00:00 2001 From: Laurenz Date: Sun, 2 Jul 2023 19:59:52 +0200 Subject: Move everything into `crates/` directory --- macros/src/func.rs | 268 ----------------------------------------------------- 1 file changed, 268 deletions(-) delete mode 100644 macros/src/func.rs (limited to 'macros/src/func.rs') diff --git a/macros/src/func.rs b/macros/src/func.rs deleted file mode 100644 index 4a68e846..00000000 --- a/macros/src/func.rs +++ /dev/null @@ -1,268 +0,0 @@ -use super::*; - -/// Expand the `#[func]` macro. -pub fn func(stream: TokenStream, item: &syn::ItemFn) -> Result { - let func = prepare(stream, item)?; - Ok(create(&func, item)) -} - -struct Func { - name: String, - display: String, - category: String, - keywords: Option, - docs: String, - vis: syn::Visibility, - ident: Ident, - ident_func: Ident, - parent: Option, - vm: bool, - vt: bool, - args: bool, - span: bool, - params: Vec, - returns: syn::Type, - scope: Option, -} - -struct Param { - name: String, - docs: String, - external: bool, - named: bool, - variadic: bool, - default: Option, - ident: Ident, - ty: syn::Type, -} - -fn prepare(stream: TokenStream, item: &syn::ItemFn) -> Result { - let sig = &item.sig; - - let Parent(parent) = syn::parse2(stream)?; - - let mut vm = false; - let mut vt = false; - let mut args = false; - let mut span = false; - let mut params = vec![]; - for input in &sig.inputs { - let syn::FnArg::Typed(typed) = input else { - bail!(input, "self is not allowed here"); - }; - - let syn::Pat::Ident(syn::PatIdent { - by_ref: None, - mutability: None, - ident, - .. - }) = &*typed.pat else { - bail!(typed.pat, "expected identifier"); - }; - - match ident.to_string().as_str() { - "vm" => vm = true, - "vt" => vt = true, - "args" => args = true, - "span" => span = true, - _ => { - let mut attrs = typed.attrs.clone(); - params.push(Param { - name: kebab_case(ident), - docs: documentation(&attrs), - external: has_attr(&mut attrs, "external"), - named: has_attr(&mut attrs, "named"), - variadic: has_attr(&mut attrs, "variadic"), - default: parse_attr(&mut attrs, "default")?.map(|expr| { - expr.unwrap_or_else( - || parse_quote! { ::std::default::Default::default() }, - ) - }), - ident: ident.clone(), - ty: (*typed.ty).clone(), - }); - - validate_attrs(&attrs)?; - } - } - } - - let mut attrs = item.attrs.clone(); - let docs = documentation(&attrs); - let mut lines = docs.split('\n').collect(); - let keywords = meta_line(&mut lines, "Keywords").ok().map(Into::into); - let category = meta_line(&mut lines, "Category")?.into(); - let display = meta_line(&mut lines, "Display")?.into(); - let docs = lines.join("\n").trim().into(); - - let func = Func { - name: sig.ident.to_string().trim_end_matches('_').replace('_', "-"), - display, - category, - keywords, - docs, - vis: item.vis.clone(), - ident: sig.ident.clone(), - ident_func: Ident::new( - &format!("{}_func", sig.ident.to_string().trim_end_matches('_')), - sig.ident.span(), - ), - parent, - params, - returns: match &sig.output { - syn::ReturnType::Default => parse_quote! { () }, - syn::ReturnType::Type(_, ty) => ty.as_ref().clone(), - }, - scope: parse_attr(&mut attrs, "scope")?.flatten(), - vm, - vt, - args, - span, - }; - - Ok(func) -} - -fn create(func: &Func, item: &syn::ItemFn) -> TokenStream { - let Func { - name, - display, - category, - docs, - vis, - ident, - ident_func, - returns, - .. - } = func; - - let handlers = func - .params - .iter() - .filter(|param| !param.external) - .map(create_param_parser); - - let args = func - .params - .iter() - .filter(|param| !param.external) - .map(|param| ¶m.ident); - - let parent = func.parent.as_ref().map(|ty| quote! { #ty:: }); - let vm_ = func.vm.then(|| quote! { vm, }); - let vt_ = func.vt.then(|| quote! { &mut vm.vt, }); - let args_ = func.args.then(|| quote! { args.take(), }); - let span_ = func.span.then(|| quote! { args.span, }); - let wrapper = quote! { - |vm, args| { - let __typst_func = #parent #ident; - #(#handlers)* - let output = __typst_func(#(#args,)* #vm_ #vt_ #args_ #span_); - ::typst::eval::IntoResult::into_result(output, args.span) - } - }; - - let mut item = item.clone(); - item.attrs.clear(); - - let inputs = item.sig.inputs.iter().cloned().filter_map(|mut input| { - if let syn::FnArg::Typed(typed) = &mut input { - if typed.attrs.iter().any(|attr| attr.path().is_ident("external")) { - return None; - } - typed.attrs.clear(); - } - Some(input) - }); - - item.sig.inputs = parse_quote! { #(#inputs),* }; - - let keywords = quote_option(&func.keywords); - let params = func.params.iter().map(create_param_info); - let scope = create_scope_builder(func.scope.as_ref()); - - quote! { - #[doc(hidden)] - #vis fn #ident_func() -> &'static ::typst::eval::NativeFunc { - static FUNC: ::typst::eval::NativeFunc = ::typst::eval::NativeFunc { - func: #wrapper, - info: ::typst::eval::Lazy::new(|| typst::eval::FuncInfo { - name: #name, - display: #display, - keywords: #keywords, - category: #category, - docs: #docs, - params: ::std::vec![#(#params),*], - returns: <#returns as ::typst::eval::Reflect>::describe(), - scope: #scope, - }), - }; - &FUNC - } - - #[doc = #docs] - #item - } -} - -/// Create a parameter info for a field. -fn create_param_info(param: &Param) -> TokenStream { - let Param { name, docs, named, variadic, ty, default, .. } = param; - let positional = !named; - let required = default.is_none(); - let default = quote_option(&default.as_ref().map(|_default| { - quote! { - || { - let typed: #ty = #default; - ::typst::eval::IntoValue::into_value(typed) - } - } - })); - let ty = if *variadic { - quote! { <#ty as ::typst::eval::Variadics>::Inner } - } else { - quote! { #ty } - }; - quote! { - ::typst::eval::ParamInfo { - name: #name, - docs: #docs, - cast: <#ty as ::typst::eval::Reflect>::describe(), - default: #default, - positional: #positional, - named: #named, - variadic: #variadic, - required: #required, - settable: false, - } - } -} - -/// Create argument parsing code for a parameter. -fn create_param_parser(param: &Param) -> TokenStream { - let Param { name, ident, ty, .. } = param; - - let mut value = if param.variadic { - quote! { args.all()? } - } else if param.named { - quote! { args.named(#name)? } - } else if param.default.is_some() { - quote! { args.eat()? } - } else { - quote! { args.expect(#name)? } - }; - - if let Some(default) = ¶m.default { - value = quote! { #value.unwrap_or_else(|| #default) } - } - - quote! { let mut #ident: #ty = #value; } -} - -struct Parent(Option); - -impl Parse for Parent { - fn parse(input: ParseStream) -> Result { - Ok(Self(if !input.is_empty() { Some(input.parse()?) } else { None })) - } -} -- cgit v1.2.3