libsdb_register_codegen 0.2.0

Register Code generation part in the book: Building a Debugger, rust port of C++ debugger Sdb https://github.com/TartanLlama/sdb/tree/main.
Documentation
use core::mem::offset_of;
use libc::user;
use nix::libc;
use proc_macro::TokenStream;
use proc_macro2::Ident;
use quote::{format_ident, quote};
use regex::Regex;

#[proc_macro]
pub fn generate_registers(_input: TokenStream) -> TokenStream {
    let content = include_str!("reg_info.txt");

    let mut variants = Vec::new();
    let mut infos = Vec::new();

    let mut push = |name: Ident,
                    dwarf_id: proc_macro2::TokenStream,
                    size_expr: proc_macro2::TokenStream,
                    offset_expr: proc_macro2::TokenStream,
                    typ: proc_macro2::TokenStream,
                    fmt: proc_macro2::TokenStream| {
        variants.push(quote! { #name });
        infos.push(quote! {
            RegisterInfo {
                id: RegisterId::#name,
                name: stringify!(#name),
                dwarf_id: #dwarf_id,
                size: #size_expr,
                offset: #offset_expr,
                type_: #typ,
                format: #fmt,
            }
        });
    };

    let re = Regex::new(r"DEFINE_GPR_64\((.+?),(.+?)\)").unwrap();
    for cap in re.captures_iter(&content) {
        let name = cap[1].trim();
        let dwarf_id = cap[2].trim().parse::<i32>().unwrap();
        let ident = format_ident!("{name}");
        push(
            ident.clone(),
            quote! {#dwarf_id},
            quote!(8),
            quote!(gpr_offset!(#ident)),
            quote!(RegisterType::Gpr),
            quote!(RegisterFormat::UInt),
        );
    }

    let re = Regex::new(r"DEFINE_GPR_32\((.+?),(.+?)\)").expect("regex compilation failed");
    for cap in re.captures_iter(&content) {
        let name = cap[1].trim();
        let super_ = cap[2].trim();
        let ident = format_ident!("{super_}");
        push(
            format_ident!("{name}"),
            quote! {-1},
            quote! {4},
            quote!(gpr_offset!(#ident)),
            quote!(RegisterType::SubGpr),
            quote!(RegisterFormat::UInt),
        );
    }

    let re = Regex::new(r"DEFINE_GPR_16\((.+?),(.+?)\)").expect("regex compilation failed");
    for cap in re.captures_iter(&content) {
        let name = cap[1].trim();
        let super_ = cap[2].trim();
        let ident = format_ident!("{super_}");
        push(
            format_ident!("{name}"),
            quote! {-1},
            quote! {2},
            quote!(gpr_offset!(#ident)),
            quote!(RegisterType::SubGpr),
            quote!(RegisterFormat::UInt),
        );
    }

    let re = Regex::new(r"DEFINE_GPR_8H\((.+?),(.+?)\)").expect("regex compilation failed");
    for cap in re.captures_iter(&content) {
        let name = cap[1].trim();
        let super_ = cap[2].trim();
        let ident = format_ident!("{super_}");
        push(
            format_ident!("{name}"),
            quote! {-1},
            quote! {1},
            quote!(gpr_offset!(#ident) + 1),
            quote!(RegisterType::SubGpr),
            quote!(RegisterFormat::UInt),
        );
    }

    let re = Regex::new(r"DEFINE_GPR_8L\((.+?),(.+?)\)").expect("regex compilation failed");
    for cap in re.captures_iter(&content) {
        let name = cap[1].trim();
        let super_ = cap[2].trim();
        let ident = format_ident!("{super_}");
        push(
            format_ident!("{name}"),
            quote! {-1},
            quote! {1},
            quote!(gpr_offset!(#ident)),
            quote!(RegisterType::SubGpr),
            quote!(RegisterFormat::UInt),
        );
    }

    let re = Regex::new(r"DEFINE_FPR\((.+?),(.+?),(.+?)\)").expect("regex compilation failed");
    for cap in re.captures_iter(&content) {
        let name = cap[1].trim();
        let dwarf_id = cap[2].trim().parse::<i32>().unwrap();
        let user_name = cap[3].trim();
        let ident = format_ident!("{user_name}");
        push(
            format_ident!("{name}"),
            quote! {#dwarf_id},
            quote!(fpr_size!(#ident)),
            quote!(fpr_offset!(#ident)),
            quote!(RegisterType::Fpr),
            quote!(RegisterFormat::UInt),
        );
    }

    let re = Regex::new(r"DEFINE_FP_ST\((.+?)\)").expect("regex compilation failed");
    for cap in re.captures_iter(&content) {
        let number = cap[1].trim().parse::<usize>().unwrap();
        let number_i32 = cap[1].trim().parse::<i32>().unwrap();
        push(
            format_ident!("st{number}"),
            quote! {33+#number_i32},
            quote! {16},
            quote!(fpr_offset!(st_space)+#number*16),
            quote!(RegisterType::Fpr),
            quote!(RegisterFormat::LongDouble),
        );
    }

    let re = Regex::new(r"DEFINE_FP_MM\((.+?)\)").expect("regex compilation failed");
    for cap in re.captures_iter(&content) {
        let number = cap[1].trim().parse::<usize>().unwrap();
        let number_i32 = cap[1].trim().parse::<i32>().unwrap();
        push(
            format_ident!("mm{number}"),
            quote! {41+#number_i32},
            quote! {8},
            quote!(fpr_offset!(st_space)+#number*16),
            quote!(RegisterType::Fpr),
            quote!(RegisterFormat::Vector),
        );
    }

    let re = Regex::new(r"DEFINE_FP_XMM\((.+?)\)").expect("regex compilation failed");
    for cap in re.captures_iter(&content) {
        let number = cap[1].trim().parse::<usize>().unwrap();
        let number_i32 = cap[1].trim().parse::<i32>().unwrap();
        push(
            format_ident!("xmm{number}"),
            quote! {17+#number_i32},
            quote! {16},
            quote!(fpr_offset!(xmm_space)+#number*16),
            quote!(RegisterType::Fpr),
            quote!(RegisterFormat::Vector),
        );
    }

    let re = Regex::new(r"DEFINE_DR\((.+?)\)").expect("regex compilation failed");
    for cap in re.captures_iter(&content) {
        let number = cap[1].trim();
        let num = number.parse::<usize>().unwrap();
        let offset = offset_of!(user, u_debugreg) + num * 8;
        push(
            format_ident!("dr{number}"),
            quote! {-1},
            quote! {8},
            quote!(#offset),
            quote!(RegisterType::Dr),
            quote!(RegisterFormat::UInt),
        );
    }

    let expanded = quote! {
        #[derive(Debug, Clone, Copy, Eq, PartialEq, TryFromPrimitive)]
        #[repr(i32)]
        pub enum RegisterId { #( #variants, )* }

        pub static GRegisterInfos: &[RegisterInfo] = &[
            #( #infos, )*
        ];
    };
    TokenStream::from(expanded)
}