git.delta.rocks / jrsonnet / refs/commits / 393dcbd419fd

difftreelog

source

crates/jrsonnet-macros/src/lib.rs2.5 KiBsourcehistory
1use proc_macro2::Span;2use quote::quote;3use syn::{parse_macro_input, FnArg, Ident, ItemFn, Pat, PatType};45fn is_location_arg(t: &PatType) -> bool {6	t.attrs.iter().any(|a| a.path.is_ident("location"))7}89#[proc_macro_attribute]10pub fn builtin(11	_attr: proc_macro::TokenStream,12	item: proc_macro::TokenStream,13) -> proc_macro::TokenStream {14	// syn::ItemFn::parse(input)15	let mut fun: ItemFn = parse_macro_input!(item);1617	let result = match fun.sig.output {18		syn::ReturnType::Default => panic!("builtin should return something"),19		syn::ReturnType::Type(_, ref ty) => ty.clone(),20	};2122	let params = fun23		.sig24		.inputs25		.iter()26		.map(|i| match i {27			FnArg::Receiver(_) => unreachable!(),28			FnArg::Typed(t) => t,29		})30		.filter(|a| !is_location_arg(a))31		.map(|t| {32			let ident = match &t.pat as &Pat {33				Pat::Ident(i) => i.ident.to_string(),34				_ => panic!("only idents supported yet"),35			};36			// TODO: Check if ty == Option<_>37			let optional = false;38			quote! {39				BuiltinParam {40					name: #ident,41					has_default: #optional,42				}43			}44		})45		.collect::<Vec<_>>();4647	let args = fun48		.sig49		.inputs50		.iter_mut()51		.map(|i| match i {52			FnArg::Receiver(_) => unreachable!(),53			FnArg::Typed(t) => t,54		})55		.map(|t| {56			let count_before = t.attrs.len();57			t.attrs.retain(|a| !a.path.is_ident("location"));58			let count_after = t.attrs.len();59			let is_location = count_before != count_after;60			if is_location {61				quote! {{62					loc63				}}64			} else {65				let ident = match &t.pat as &Pat {66					Pat::Ident(i) => i.ident.to_string(),67					_ => panic!("only idents supported yet"),68				};69				let ty = &t.ty;70				quote! {{71					let value = parsed.get(#ident).unwrap();7273					jrsonnet_evaluator::push_description_frame(74						|| format!("argument <{}> evaluation", #ident),75						|| <#ty>::try_from(value.evaluate()?),76					)?77				}}78			}79		}).collect::<Vec<_>>();80	81	let inner_name = Ident::new("inner", Span::call_site());82	let mut inner_fun = fun.clone();83	inner_fun.sig.ident = inner_name.clone();8485	let attrs = &fun.attrs;86	let vis = &fun.vis;87	let name = &fun.sig.ident;88	(quote! {89		#(#attrs)*90		#vis fn #name(context: Context, loc: &ExprLocation, args: &ArgsDesc) -> Result<Val> {91			#inner_fun92			use jrsonnet_evaluator::function::BuiltinParam;93			const PARAMS: &'static [BuiltinParam] = &[94				#(#params),*95			];96			let parsed = jrsonnet_evaluator::function::parse_builtin_call(context, &PARAMS, args, false)?;9798			let result: #result = #inner_name(#(#args),*);99			let result = result?;100			result.try_into()101		}102	})103	.into()104}