fix: add parent_name to CodeGen to properly refer to parent name, and add Reg to register children

One more: if parent is RegisterInterface, lifetime param is omitted
This commit is contained in:
Wataru Otsubo 2025-02-02 16:55:37 +09:00
parent 5f7db47fcf
commit 9e7a83242b

View file

@ -111,20 +111,28 @@ mod util {
}
pub trait CodeGen {
fn generate_register_interface(self) -> Result<proc_macro2::TokenStream, CodeGenError>;
/// `parent_name` in UpperCamelCase.
fn generate_register_interface(
self,
parent_name: proc_macro2::Ident,
) -> Result<proc_macro2::TokenStream, CodeGenError>;
}
impl CodeGen for Module {
fn generate_register_interface(self) -> Result<proc_macro2::TokenStream, CodeGenError> {
fn generate_register_interface(
self,
_: proc_macro2::Ident,
) -> Result<proc_macro2::TokenStream, CodeGenError> {
let mut out = TokenStream::new();
if !self.elements_bitstring.is_empty() {
todo!("bitstring generation is not yet implemented")
}
let ident_register_interface = util::parse_to_ident("RegisterInterface").unwrap();
let child_mods = self
.elements_other
.into_iter()
.map(|e| e.generate_register_interface())
.map(|e| e.generate_register_interface(ident_register_interface.clone()))
.collect::<Result<Vec<_>, _>>()?;
for child in child_mods {
out.extend(child);
@ -135,10 +143,13 @@ impl CodeGen for Module {
}
impl CodeGen for ModuleBlockElements {
fn generate_register_interface(self) -> Result<proc_macro2::TokenStream, CodeGenError> {
fn generate_register_interface(
self,
parent: proc_macro2::Ident,
) -> Result<proc_macro2::TokenStream, CodeGenError> {
match self {
ModuleBlockElements::Block(block) => block.generate_register_interface(),
ModuleBlockElements::Register(register) => register.generate_register_interface(),
ModuleBlockElements::Block(block) => block.generate_register_interface(parent),
ModuleBlockElements::Register(register) => register.generate_register_interface(parent),
ModuleBlockElements::Memory(_memory) => todo!(),
ModuleBlockElements::Fifo(_fifo) => todo!(),
}
@ -146,7 +157,10 @@ impl CodeGen for ModuleBlockElements {
}
impl CodeGen for Block {
fn generate_register_interface(self) -> Result<proc_macro2::TokenStream, CodeGenError> {
fn generate_register_interface(
self,
parent: proc_macro2::Ident,
) -> Result<proc_macro2::TokenStream, CodeGenError> {
let snake_case_name = util::parse_to_ident(&self.name.to_snake_case())?;
let upper_camel_name = util::parse_to_ident(&self.name.to_upper_camel_case())?;
let addr = util::parse_to_literal(&format!("0x{:x}", self.addr))?;
@ -154,13 +168,22 @@ impl CodeGen for Block {
let accessor_methods = {
let mut out = TokenStream::new();
for child_name in self.elements.iter().map(|e| e.get_name()) {
for e in self.elements.iter() {
let child_name = e.get_name();
let snake_case_name = util::parse_to_ident(&child_name.to_snake_case())?;
let upper_camel_name = util::parse_to_ident(&child_name.to_upper_camel_case())?;
let child_type_name = match e {
ModuleBlockElements::Block(_) => &child_name.to_upper_camel_case(),
ModuleBlockElements::Register(_) => {
&format!("Reg{}", child_name.to_upper_camel_case())
}
ModuleBlockElements::Memory(_) => todo!(),
ModuleBlockElements::Fifo(_) => todo!(),
};
let child_upper_camel_name = util::parse_to_ident(child_type_name)?;
out.extend(quote! {
pub fn #snake_case_name(&self) -> #snake_case_name::#upper_camel_name {
#snake_case_name::#upper_camel_name::new(self.mem_ptr)
pub fn #snake_case_name(&self) -> #snake_case_name::#child_upper_camel_name {
#snake_case_name::#child_upper_camel_name::new(self.mem_ptr)
}
});
}
@ -171,9 +194,15 @@ impl CodeGen for Block {
let code_children = self
.elements
.into_iter()
.map(|e| e.generate_register_interface())
.map(|e| e.generate_register_interface(upper_camel_name.clone()))
.collect::<Result<Vec<_>, _>>()?;
let parent_struct = if parent == util::parse_to_ident("RegisterInterface").unwrap() {
quote! {#parent}
} else {
quote! {#parent<'a>}
};
Ok(quote! {
pub mod #snake_case_name {
#[doc = #desc]
@ -211,7 +240,10 @@ mod codegen_registerspec_impl;
/// Internally calls functions in [`codegen_register`]
impl CodeGen for Register {
fn generate_register_interface(self) -> Result<proc_macro2::TokenStream, CodeGenError> {
fn generate_register_interface(
self,
parent: proc_macro2::Ident,
) -> Result<proc_macro2::TokenStream, CodeGenError> {
let snake_case_name = util::parse_to_ident(&self.name.to_snake_case())?;
let upper_camel_name = util::parse_to_ident(&self.name.to_upper_camel_case())?;
let reg_name = util::parse_to_ident(&format!("Reg{upper_camel_name}"))?;