This lets us avoid the cost of `cranelift_codegen::ir::Opcode` to `peepmatic_runtime::Operator` conversion overhead, and paves the way for allowing Peepmatic to support non-clif optimizations (e.g. vcode optimizations). Rather than defining our own `peepmatic::Operator` type like we used to, now the whole `peepmatic` crate is effectively generic over a `TOperator` type parameter. For the Cranelift integration, we use `cranelift_codegen::ir::Opcode` as the concrete type for our `TOperator` type parameter. For testing, we also define a `TestOperator` type, so that we can test Peepmatic code without building all of Cranelift, and we can keep them somewhat isolated from each other. The methods that `peepmatic::Operator` had are now translated into trait bounds on the `TOperator` type. These traits need to be shared between all of `peepmatic`, `peepmatic-runtime`, and `cranelift-codegen`'s Peepmatic integration. Therefore, these new traits live in a new crate: `peepmatic-traits`. This crate acts as a header file of sorts for shared trait/type/macro definitions. Additionally, the `peepmatic-runtime` crate no longer depends on the `peepmatic-macro` procedural macro crate, which should lead to faster build times for Cranelift when it is using pre-built peephole optimizers.
56 lines
1.7 KiB
Rust
56 lines
1.7 KiB
Rust
use quote::quote;
|
|
use syn::DeriveInput;
|
|
use syn::{parse_quote, GenericParam, Generics, Result};
|
|
|
|
pub fn derive_span(input: &DeriveInput) -> Result<impl quote::ToTokens> {
|
|
let ty = &input.ident;
|
|
|
|
let body = match &input.data {
|
|
syn::Data::Struct(_) => quote! { self.span },
|
|
syn::Data::Enum(e) => {
|
|
let variants = e.variants.iter().map(|v| match v.fields {
|
|
syn::Fields::Unnamed(ref fields) if fields.unnamed.len() == 1 => {
|
|
let variant = &v.ident;
|
|
quote! { #ty::#variant(x) => x.span(), }
|
|
}
|
|
_ => panic!(
|
|
"derive(Ast) on enums only supports variants with a single, unnamed field"
|
|
),
|
|
});
|
|
quote! {
|
|
match self {
|
|
#( #variants )*
|
|
}
|
|
}
|
|
}
|
|
syn::Data::Union(_) => {
|
|
panic!("derive(Ast) can only be used with structs and enums, not unions")
|
|
}
|
|
};
|
|
|
|
let generics = add_span_trait_bounds(input.generics.clone());
|
|
let (impl_generics, ty_generics, where_clause) = generics.split_for_impl();
|
|
|
|
Ok(quote! {
|
|
impl #impl_generics Span for #ty #ty_generics #where_clause {
|
|
#[inline]
|
|
fn span(&self) -> wast::Span {
|
|
#body
|
|
}
|
|
}
|
|
})
|
|
}
|
|
|
|
// Add a bound `T: Span` to every type parameter `T`.
|
|
fn add_span_trait_bounds(mut generics: Generics) -> Generics {
|
|
for param in &mut generics.params {
|
|
if let GenericParam::Type(ref mut type_param) = *param {
|
|
if type_param.ident == "TOperator" {
|
|
continue;
|
|
}
|
|
type_param.bounds.push(parse_quote!(Span));
|
|
}
|
|
}
|
|
generics
|
|
}
|