refactor(downgrade): use bumpalo
This commit is contained in:
@@ -8,5 +8,6 @@ proc-macro = true
|
||||
|
||||
[dependencies]
|
||||
convert_case = "0.11"
|
||||
proc-macro2 = "1.0"
|
||||
quote = "1.0"
|
||||
syn = { version = "2.0", features = ["full"] }
|
||||
|
||||
@@ -4,22 +4,22 @@
|
||||
//! an Intermediate Representation (IR) that follows a specific pattern. It generates:
|
||||
//! 1. An enum representing the different kinds of IR nodes.
|
||||
//! 2. Structs for each of the variants that have fields.
|
||||
//! 3. `Ref` and `Mut` versions of the main enum for ergonomic pattern matching on references.
|
||||
//! 4. `From` implementations to easily convert from a struct variant (e.g., `BinOp`) to the main enum (`Ir::BinOp`).
|
||||
//! 5. A `To[IrName]` trait to provide a convenient `.to_ir()` method on the variant structs.
|
||||
//! 3. `From` implementations to easily convert from a struct variant (e.g., `BinOp`) to the main enum (`Ir::BinOp`).
|
||||
//! 4. A `To[IrName]` trait to provide a convenient `.to_ir()` method on the variant structs.
|
||||
|
||||
use convert_case::{Case, Casing};
|
||||
use proc_macro::TokenStream;
|
||||
use quote::{format_ident, quote};
|
||||
use syn::{
|
||||
FieldsNamed, Ident, Token, Type, parenthesized,
|
||||
Expr, ExprPath, FieldsNamed, GenericArgument, GenericParam, Generics, Ident, Path, PathSegment,
|
||||
Token, Type, TypePath, parenthesized,
|
||||
parse::{Parse, ParseStream, Result},
|
||||
punctuated::Punctuated,
|
||||
token,
|
||||
};
|
||||
|
||||
/// Represents one of the variants passed to the `ir!` macro.
|
||||
pub enum VariantInput {
|
||||
enum VariantInput {
|
||||
/// A unit-like variant, e.g., `Arg`.
|
||||
Unit(Ident),
|
||||
/// A tuple-like variant with one unnamed field, e.g., `ExprRef(ExprId)`.
|
||||
@@ -29,11 +29,12 @@ pub enum VariantInput {
|
||||
}
|
||||
|
||||
/// The top-level input for the `ir!` macro.
|
||||
pub struct MacroInput {
|
||||
struct MacroInput {
|
||||
/// The name of the main IR enum to be generated (e.g., `Ir`).
|
||||
pub base_name: Ident,
|
||||
base_name: Ident,
|
||||
generics: Generics,
|
||||
/// The list of variants for the enum.
|
||||
pub variants: Punctuated<VariantInput, Token![,]>,
|
||||
variants: Punctuated<VariantInput, Token![,]>,
|
||||
}
|
||||
|
||||
impl Parse for VariantInput {
|
||||
@@ -64,13 +65,14 @@ impl Parse for VariantInput {
|
||||
|
||||
impl Parse for MacroInput {
|
||||
fn parse(input: ParseStream) -> Result<Self> {
|
||||
// The macro input is expected to be: `IrName, Variant1, Variant2, ...`
|
||||
let base_name = input.parse()?;
|
||||
input.parse::<Token![,]>()?;
|
||||
let generics = Generics::parse(input)?;
|
||||
input.parse::<Token![;]>()?;
|
||||
let variants = Punctuated::parse_terminated(input)?;
|
||||
|
||||
Ok(MacroInput {
|
||||
base_name,
|
||||
generics,
|
||||
variants,
|
||||
})
|
||||
}
|
||||
@@ -81,17 +83,39 @@ pub fn ir_impl(input: TokenStream) -> TokenStream {
|
||||
let parsed_input = syn::parse_macro_input!(input as MacroInput);
|
||||
|
||||
let base_name = &parsed_input.base_name;
|
||||
let ref_name = format_ident!("{}Ref", base_name);
|
||||
let mut_name = format_ident!("{}Mut", base_name);
|
||||
let generic_params = &parsed_input.generics.params;
|
||||
let mk_ident_path = |ident| Path {
|
||||
leading_colon: None,
|
||||
segments: Punctuated::from_iter(std::iter::once(PathSegment {
|
||||
ident,
|
||||
arguments: Default::default(),
|
||||
})),
|
||||
};
|
||||
let generic_args = {
|
||||
generic_params
|
||||
.iter()
|
||||
.map(|arg| match arg {
|
||||
GenericParam::Lifetime(lifetime) => {
|
||||
GenericArgument::Lifetime(lifetime.lifetime.clone())
|
||||
}
|
||||
GenericParam::Const(cnst) => GenericArgument::Const(Expr::Path(ExprPath {
|
||||
path: mk_ident_path(cnst.ident.clone()),
|
||||
attrs: Vec::new(),
|
||||
qself: None,
|
||||
})),
|
||||
GenericParam::Type(ty) => GenericArgument::Type(Type::Path(TypePath {
|
||||
path: mk_ident_path(ty.ident.clone()),
|
||||
qself: None,
|
||||
})),
|
||||
})
|
||||
.collect::<Punctuated<_, Token![,]>>()
|
||||
};
|
||||
let where_clause = &parsed_input.generics.where_clause;
|
||||
let to_trait_name = format_ident!("To{}", base_name);
|
||||
let to_trait_fn_name = format_ident!("to_{}", base_name.to_string().to_case(Case::Snake));
|
||||
|
||||
let mut enum_variants = Vec::new();
|
||||
let mut struct_defs = Vec::new();
|
||||
let mut ref_variants = Vec::new();
|
||||
let mut mut_variants = Vec::new();
|
||||
let mut as_ref_arms = Vec::new();
|
||||
let mut as_mut_arms = Vec::new();
|
||||
let mut span_arms = Vec::new();
|
||||
let mut from_impls = Vec::new();
|
||||
let mut to_trait_impls = Vec::new();
|
||||
@@ -109,19 +133,15 @@ pub fn ir_impl(input: TokenStream) -> TokenStream {
|
||||
});
|
||||
|
||||
enum_variants.push(quote! { #name(#inner_type) });
|
||||
ref_variants.push(quote! { #name(&'a #inner_type) });
|
||||
mut_variants.push(quote! { #name(&'a mut #inner_type) });
|
||||
as_ref_arms.push(quote! { Self::#name(inner) => #ref_name::#name(inner) });
|
||||
as_mut_arms.push(quote! { Self::#name(inner) => #mut_name::#name(inner) });
|
||||
span_arms.push(quote! { Self::#name(inner) => inner.span });
|
||||
from_impls.push(quote! {
|
||||
impl From<#inner_type> for #base_name {
|
||||
impl <#generic_params> From<#inner_type> for #base_name <#generic_args> #where_clause {
|
||||
fn from(val: #inner_type) -> Self { #base_name::#name(val) }
|
||||
}
|
||||
});
|
||||
to_trait_impls.push(quote! {
|
||||
impl #to_trait_name for #name {
|
||||
fn #to_trait_fn_name(self) -> #base_name { #base_name::from(self) }
|
||||
impl <#generic_params> #to_trait_name <#generic_args> for #name #where_clause {
|
||||
fn #to_trait_fn_name(self) -> #base_name <#generic_args> { #base_name::from(self) }
|
||||
}
|
||||
});
|
||||
}
|
||||
@@ -138,25 +158,24 @@ pub fn ir_impl(input: TokenStream) -> TokenStream {
|
||||
|
||||
let inner_type = name.clone();
|
||||
enum_variants.push(quote! { #name(#inner_type) });
|
||||
ref_variants.push(quote! { #name(&'a #inner_type) });
|
||||
mut_variants.push(quote! { #name(&'a mut #inner_type) });
|
||||
as_ref_arms.push(quote! { Self::#name(inner) => #ref_name::#name(inner) });
|
||||
as_mut_arms.push(quote! { Self::#name(inner) => #mut_name::#name(inner) });
|
||||
span_arms.push(quote! { Self::#name(inner) => inner.span });
|
||||
from_impls.push(quote! {
|
||||
impl From<#inner_type> for #base_name {
|
||||
impl <#generic_params> From<#inner_type> for #base_name <#generic_args> #where_clause {
|
||||
fn from(val: #inner_type) -> Self { #base_name::#name(val) }
|
||||
}
|
||||
});
|
||||
to_trait_impls.push(quote! {
|
||||
impl #to_trait_name for #name {
|
||||
fn #to_trait_fn_name(self) -> #base_name { #base_name::from(self) }
|
||||
impl <#generic_params> #to_trait_name <#generic_args> for #name #where_clause {
|
||||
fn #to_trait_fn_name(self) -> #base_name <#generic_args> { #base_name::from(self) }
|
||||
}
|
||||
});
|
||||
}
|
||||
VariantInput::Struct(name, mut fields) => {
|
||||
let inner_type = name.clone();
|
||||
|
||||
fields.named.iter_mut().for_each(|field| {
|
||||
field.vis = syn::Visibility::Public(syn::token::Pub::default());
|
||||
});
|
||||
fields.named.push(syn::Field {
|
||||
attrs: vec![],
|
||||
vis: syn::Visibility::Public(syn::token::Pub::default()),
|
||||
@@ -168,22 +187,18 @@ pub fn ir_impl(input: TokenStream) -> TokenStream {
|
||||
|
||||
struct_defs.push(quote! {
|
||||
#[derive(Debug)]
|
||||
pub struct #name #fields
|
||||
pub struct #name <#generic_params> #where_clause #fields
|
||||
});
|
||||
enum_variants.push(quote! { #name(#inner_type) });
|
||||
ref_variants.push(quote! { #name(&'a #inner_type) });
|
||||
mut_variants.push(quote! { #name(&'a mut #inner_type) });
|
||||
as_ref_arms.push(quote! { Self::#name(inner) => #ref_name::#name(inner) });
|
||||
as_mut_arms.push(quote! { Self::#name(inner) => #mut_name::#name(inner) });
|
||||
enum_variants.push(quote! { #name(#inner_type <#generic_args>) });
|
||||
span_arms.push(quote! { Self::#name(inner) => inner.span });
|
||||
from_impls.push(quote! {
|
||||
impl From<#inner_type> for #base_name {
|
||||
fn from(val: #inner_type) -> Self { #base_name::#name(val) }
|
||||
impl <#generic_params> From<#inner_type <#generic_args>> for #base_name <#generic_args> #where_clause {
|
||||
fn from(val: #inner_type <#generic_args>) -> Self { #base_name::#name(val) }
|
||||
}
|
||||
});
|
||||
to_trait_impls.push(quote! {
|
||||
impl #to_trait_name for #name {
|
||||
fn #to_trait_fn_name(self) -> #base_name { #base_name::from(self) }
|
||||
impl <#generic_params> #to_trait_name <#generic_args> for #name <#generic_args> #where_clause {
|
||||
fn #to_trait_fn_name(self) -> #base_name <#generic_args> { #base_name::from(self) }
|
||||
}
|
||||
});
|
||||
}
|
||||
@@ -193,41 +208,15 @@ pub fn ir_impl(input: TokenStream) -> TokenStream {
|
||||
// Assemble the final generated code.
|
||||
let expanded = quote! {
|
||||
/// The main IR enum, generated by the `ir!` macro.
|
||||
#[derive(Debug, IsVariant, Unwrap, TryUnwrap)]
|
||||
pub enum #base_name {
|
||||
#[derive(Debug)]
|
||||
pub enum #base_name <#generic_params> #where_clause {
|
||||
#( #enum_variants ),*
|
||||
}
|
||||
|
||||
// The struct definitions for the enum variants.
|
||||
#( #struct_defs )*
|
||||
|
||||
/// An immutable reference version of the IR enum.
|
||||
#[derive(Debug, IsVariant, Unwrap, TryUnwrap)]
|
||||
pub enum #ref_name<'a> {
|
||||
#( #ref_variants ),*
|
||||
}
|
||||
|
||||
/// A mutable reference version of the IR enum.
|
||||
#[derive(Debug, IsVariant, Unwrap, TryUnwrap)]
|
||||
pub enum #mut_name<'a> {
|
||||
#( #mut_variants ),*
|
||||
}
|
||||
|
||||
impl #base_name {
|
||||
/// Converts a `&Ir` into a `IrRef`.
|
||||
pub fn as_ref(&self) -> #ref_name<'_> {
|
||||
match self {
|
||||
#( #as_ref_arms ),*
|
||||
}
|
||||
}
|
||||
|
||||
/// Converts a `&mut Ir` into a `IrMut`.
|
||||
pub fn as_mut(&mut self) -> #mut_name<'_> {
|
||||
match self {
|
||||
#( #as_mut_arms ),*
|
||||
}
|
||||
}
|
||||
|
||||
impl <#generic_params> #base_name <#generic_args> #where_clause {
|
||||
pub fn span(&self) -> rnix::TextRange {
|
||||
match self {
|
||||
#( #span_arms ),*
|
||||
@@ -239,9 +228,9 @@ pub fn ir_impl(input: TokenStream) -> TokenStream {
|
||||
#( #from_impls )*
|
||||
|
||||
/// A trait for converting a variant struct into the main IR enum.
|
||||
pub trait #to_trait_name {
|
||||
pub trait #to_trait_name <#generic_params> #where_clause {
|
||||
/// Performs the conversion.
|
||||
fn #to_trait_fn_name(self) -> #base_name;
|
||||
fn #to_trait_fn_name(self) -> #base_name <#generic_args>;
|
||||
}
|
||||
|
||||
// Implement the `ToIr` trait for each variant struct.
|
||||
|
||||
Reference in New Issue
Block a user