From fc3ef0a25133ad27c7b82dd1dfcdaff9cbd24670 Mon Sep 17 00:00:00 2001 From: Daniel Almeida Date: Wed, 12 Apr 2023 18:38:30 -0300 Subject: [PATCH] nak: derive From for Op through a proc macro Derive From for Op through a proc macro. This is much less verbose than adding a manual impl From {..} for all Ops in the NAK IR. Part-of: --- src/nouveau/compiler/nak_ir.rs | 2 +- src/nouveau/compiler/nak_ir_proc.rs | 44 ++++++++++++++++++++++++++++- 2 files changed, 44 insertions(+), 2 deletions(-) diff --git a/src/nouveau/compiler/nak_ir.rs b/src/nouveau/compiler/nak_ir.rs index 93fc42f9a39..b8a23f795aa 100644 --- a/src/nouveau/compiler/nak_ir.rs +++ b/src/nouveau/compiler/nak_ir.rs @@ -2190,7 +2190,7 @@ impl fmt::Display for OpFSOut { } } -#[derive(Display, DstsAsSlice, SrcsAsSlice)] +#[derive(Display, DstsAsSlice, SrcsAsSlice, FromOps)] pub enum Op { FAdd(OpFAdd), FFma(OpFFma), diff --git a/src/nouveau/compiler/nak_ir_proc.rs b/src/nouveau/compiler/nak_ir_proc.rs index 923d32284ab..e0ad4a22ed2 100644 --- a/src/nouveau/compiler/nak_ir_proc.rs +++ b/src/nouveau/compiler/nak_ir_proc.rs @@ -10,7 +10,8 @@ extern crate quote; extern crate syn; use proc_macro::TokenStream; -use proc_macro2::{Span, TokenStream as TokenStream2}; +use proc_macro2::{Span, TokenStream as TokenStream2, TokenTree}; +use quote::ToTokens; use syn::*; fn count_type(ty: &Type, search_type: &str) -> TokenStream2 { @@ -196,3 +197,44 @@ pub fn enum_derive_display(input: TokenStream) -> TokenStream { panic!("Not an enum type"); } } + +#[proc_macro_derive(FromOps)] +pub fn derive_from_ops(input: TokenStream) -> TokenStream { + let DeriveInput { data, .. } = parse_macro_input!(input); + + let mut impls = TokenStream2::new(); + + if let Data::Enum(e) = data { + for v in e.variants { + let (old_token, new_token) = match v.fields { + Fields::Unnamed(FieldsUnnamed { unnamed, .. }) => { + let mut tt: Vec<_> = + unnamed.to_token_stream().into_iter().collect(); + + let old_ident = match tt.pop() { + Some(TokenTree::Ident(ident)) => ident, + _ => panic!("Expected Op(OpFoo)"), + }; + let new_ident = Ident::new( + &old_ident.to_string().replace("Op", ""), + old_ident.span(), + ); + (old_ident, new_ident) + } + _ => panic!("Expected Op(OpFoo)"), + }; + + let quote = quote! { + impl From<#old_token> for crate::nak_ir::Op { + fn from (op: #old_token) -> crate::nak_ir::Op { + crate::nak_ir::Op::#new_token(op) + } + } + }; + + impls.extend(quote); + } + } + + impls.into() +}