in amzn-smt-ir-derive/src/lib.rs [69:183]
fn derive_operation(s: &synstructure::Structure) -> TokenStream {
let smt_ir = smt_ir_crate_path();
#[allow(non_snake_case)]
let (Term, Logic, Operation, Parse, NumArgs, InvalidOp, QualIdentifier, IIndex, TryFrom, Vec) = (
quote!(#smt_ir::Term),
quote!(#smt_ir::Logic),
quote!(#smt_ir::term::Operation),
quote!(#smt_ir::term::args::Parse),
quote!(#smt_ir::term::args::NumArgs),
quote!(#smt_ir::term::InvalidOp),
quote!(#smt_ir::QualIdentifier),
quote!(#smt_ir::IIndex),
quote!(std::convert::TryFrom),
quote!(std::vec::Vec),
);
let mut bindings = vec![];
let parse_match_arms: Vec<_> = (s.variants().iter())
.enumerate()
.map(|(idx, variant)| {
let symbol = variant_symbol(variant);
let mut num_indices = None;
let mut min_args = vec![];
let mut max_args = vec![];
// For each field in the variant, try to parse it from the iterator of arguments
let constructed = variant.construct(|field, _| {
let ty = &field.ty;
// Check for array of indices
if let Some(len) = index_array(ty) {
num_indices = Some(len.clone());
quote! {{
let indices: std::vec::Vec<_> = func.indices().iter().map(#IIndex::from).collect();
#TryFrom::try_from(indices).unwrap()
}}
} else {
min_args.push(quote!(<#ty as #NumArgs>::MIN_ARGS));
max_args.push(quote!(<#ty as #NumArgs>::MAX_ARGS));
quote!(#Parse::from_iter(&mut iter).unwrap())
}
});
let min_args = quote!((0 #(+ #min_args)*));
let max_args = quote!((0 #(+ #max_args)*));
let num_indices = num_indices.unwrap_or_else(|| parse_quote!(0));
let min_args_ident = syn::Ident::new(&format!("MIN_ARGS_{}", idx), Span::call_site());
let max_args_ident = syn::Ident::new(&format!("MAX_ARGS_{}", idx), Span::call_site());
let num_indices_ident = syn::Ident::new(&format!("INDICES_{}", idx), Span::call_site());
bindings.push(quote!(let #min_args_ident = #min_args;));
bindings.push(quote!(let #max_args_ident = #max_args;));
bindings.push(quote!(let #num_indices_ident = #num_indices;));
// Construct a match arm e.g. `"and" => { ... }` where `...` constructs the variant from
// a slice of arguments.
quote! {
(#symbol, num_args) if func.indices().len() == #num_indices_ident && (#min_args_ident..=#max_args_ident).contains(&num_args) => {
let mut iter = args.into_iter();
#constructed
}
}
})
.collect();
let parse_fn = quote! {
fn parse(func: #QualIdentifier, args: #Vec<#Term<L>>) -> std::result::Result<Self, #InvalidOp<L>> {
#(#bindings)*
#[deny(unreachable_patterns)]
Ok(match (func.sym_str(), args.len()) {
#(#parse_match_arms)*
_ => return Err(#InvalidOp { func, args })
})
}
};
let func_match_arms = s.each_variant(|variant| {
let symbol = variant_symbol(variant);
quote!(#symbol.into())
});
let func_fn = quote! {
fn func(&self) -> #smt_ir::ISymbol {
match self {
#func_match_arms
}
}
};
let mut where_clause = None;
s.add_trait_bounds(
&parse_quote!(#Parse<L>),
&mut where_clause,
synstructure::AddBounds::Fields,
);
if has_core_op_attr(s.ast()) {
s.gen_impl(quote! {
gen impl<L: #Logic> #Operation<L> for @Self
#where_clause,
<L as #Logic>::Op: #Operation<L>,
{
#parse_fn
#func_fn
}
})
} else {
s.gen_impl(quote! {
gen impl<L: #Logic> #Operation<L> for @Self #where_clause {
#parse_fn
#func_fn
}
})
}
}