use proc_macro::TokenStream;
use quote::quote;
use syn::{parse_macro_input, DeriveInput};
pub fn sp1_operation_builder_derive(input: TokenStream) -> TokenStream {
let ast = parse_macro_input!(input as DeriveInput);
let name = &ast.ident;
let name_str = name.to_string();
if ast.generics.params.len() > 1 {
panic!("SP1OperationBuilder requires at most one type parameter");
}
let struct_type = if ast.generics.params.is_empty() {
quote! { #name }
} else {
quote! { #name<<sp1_hypercube::ir::ConstraintCompiler as slop_air::AirBuilder>::F> }
};
let expanded = quote! {
impl crate::air::SP1OperationBuilder<#struct_type>
for sp1_hypercube::ir::ConstraintCompiler
{
fn eval_operation(
&mut self,
input: <#struct_type as crate::air::SP1Operation<
sp1_hypercube::ir::ConstraintCompiler
>>::Input,
) -> <#struct_type as crate::air::SP1Operation<
sp1_hypercube::ir::ConstraintCompiler
>>::Output{
type F = <sp1_hypercube::ir::ConstraintCompiler as slop_air::AirBuilder>::F;
type O = <#struct_type as crate::air::SP1Operation<
sp1_hypercube::ir::ConstraintCompiler,
>>::Output;
let result : O = <O as sp1_hypercube::ir::SP1OperationOutput<O>>::alloc();
sp1_hypercube::ir::GLOBAL_AST.lock().unwrap().call_operation(
#name_str.to_string(),
input.clone().params_vec(),
result.into(),
);
if !self.modules().contains_key(#name_str) {
let mut ctx = sp1_hypercube::ir::FuncCtx::new();
let func_input = input.to_input(&mut ctx);
let func_output : O = <O as sp1_hypercube::ir::SP1OperationOutput<O>>::to_output(&result, &mut ctx);
self.register_module(
#name_str.to_string(),
func_input.clone().params_vec(),
|body| {
let output : O = <#struct_type as crate::air::SP1Operation<sp1_hypercube::ir::ConstraintCompiler>>::lower(body, func_input);
<O as sp1_hypercube::ir::SP1OperationOutput<O>>::assign(&func_output, output);
output.into()
},
);
}
result
}
}
};
TokenStream::from(expanded)
}