Skip to content

Commit 454886e

Browse files
authored
Merge pull request #794 from rust-embedded/idents
Custom prefix/case/suffix for identifiers
2 parents 8deac04 + 6e1185f commit 454886e

File tree

10 files changed

+252
-186
lines changed

10 files changed

+252
-186
lines changed

CHANGELOG.md

Lines changed: 2 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -7,6 +7,8 @@ and this project adheres to [Semantic Versioning](https://semver.org/).
77

88
## [Unreleased]
99

10+
- Custom prefix/case/suffix for identifiers
11+
1012
## [v0.31.3] - 2023-12-25
1113

1214
- Add `svd::Device` validation after parsing by `serde`

Cargo.lock

Lines changed: 15 additions & 24 deletions
Some generated files are not rendered by default. Learn more about customizing how changed files appear on GitHub.

Cargo.toml

Lines changed: 2 additions & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -60,11 +60,11 @@ html-escape = "0.2"
6060

6161
[dependencies.svd-parser]
6262
features = ["expand"]
63-
version = "0.14.4"
63+
version = "0.14.5"
6464

6565
[dependencies.svd-rs]
6666
features = ["serde"]
67-
version = "0.14.6"
67+
version = "0.14.7"
6868

6969
[dependencies.syn]
7070
version = "2.0"

src/config.rs

Lines changed: 83 additions & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -1,9 +1,8 @@
11
use anyhow::{bail, Result};
22
use std::path::{Path, PathBuf};
33

4-
#[cfg_attr(feature = "serde", derive(serde::Deserialize))]
4+
#[cfg_attr(feature = "serde", derive(serde::Deserialize), serde(default))]
55
#[derive(Clone, PartialEq, Eq, Debug, Default)]
6-
#[cfg_attr(feature = "serde", serde(default))]
76
pub struct Config {
87
pub target: Target,
98
pub atomics: bool,
@@ -28,6 +27,7 @@ pub struct Config {
2827
pub interrupt_link_section: Option<String>,
2928
pub reexport_core_peripherals: bool,
3029
pub reexport_interrupt: bool,
30+
pub ident_formats: IdentFormats,
3131
}
3232

3333
#[allow(clippy::upper_case_acronyms)]
@@ -116,3 +116,84 @@ impl SourceType {
116116
.unwrap_or_default()
117117
}
118118
}
119+
120+
#[cfg_attr(
121+
feature = "serde",
122+
derive(serde::Deserialize),
123+
serde(rename_all = "lowercase")
124+
)]
125+
#[derive(Clone, Debug, PartialEq, Eq, Default)]
126+
#[non_exhaustive]
127+
pub enum Case {
128+
#[default]
129+
Constant,
130+
Pascal,
131+
Snake,
132+
}
133+
134+
#[derive(Clone, Debug, Default, PartialEq, Eq)]
135+
#[cfg_attr(feature = "serde", derive(serde::Deserialize), serde(default))]
136+
pub struct IdentFormat {
137+
pub case: Option<Case>,
138+
pub prefix: String,
139+
pub suffix: String,
140+
}
141+
142+
impl IdentFormat {
143+
pub fn case(mut self, case: Case) -> Self {
144+
self.case = Some(case);
145+
self
146+
}
147+
pub fn constant_case(mut self) -> Self {
148+
self.case = Some(Case::Constant);
149+
self
150+
}
151+
pub fn pascal_case(mut self) -> Self {
152+
self.case = Some(Case::Pascal);
153+
self
154+
}
155+
pub fn scake_case(mut self) -> Self {
156+
self.case = Some(Case::Pascal);
157+
self
158+
}
159+
pub fn prefix(mut self, prefix: &str) -> Self {
160+
self.prefix = prefix.into();
161+
self
162+
}
163+
pub fn suffix(mut self, suffix: &str) -> Self {
164+
self.suffix = suffix.into();
165+
self
166+
}
167+
}
168+
169+
#[derive(Clone, Debug, PartialEq, Eq)]
170+
#[cfg_attr(feature = "serde", derive(serde::Deserialize), serde(default))]
171+
pub struct IdentFormats {
172+
pub field_reader: IdentFormat,
173+
pub field_writer: IdentFormat,
174+
pub enum_name: IdentFormat,
175+
pub enum_write_name: IdentFormat,
176+
pub enum_value: IdentFormat,
177+
pub interrupt: IdentFormat,
178+
pub cluster: IdentFormat,
179+
pub register: IdentFormat,
180+
pub register_spec: IdentFormat,
181+
pub peripheral: IdentFormat,
182+
}
183+
184+
impl Default for IdentFormats {
185+
fn default() -> Self {
186+
Self {
187+
field_reader: IdentFormat::default().constant_case().suffix("_R"),
188+
field_writer: IdentFormat::default().constant_case().suffix("_W"),
189+
enum_name: IdentFormat::default().constant_case().suffix("_A"),
190+
enum_write_name: IdentFormat::default().constant_case().suffix("_AW"),
191+
enum_value: IdentFormat::default().constant_case(),
192+
interrupt: IdentFormat::default().constant_case(),
193+
cluster: IdentFormat::default().constant_case(),
194+
register: IdentFormat::default().constant_case(),
195+
register_spec: IdentFormat::default().constant_case().suffix("_SPEC"),
196+
peripheral: IdentFormat::default().constant_case(),
197+
}
198+
}
199+
}

src/generate/device.rs

Lines changed: 20 additions & 33 deletions
Original file line numberDiff line numberDiff line change
@@ -1,15 +1,14 @@
11
use crate::svd::{array::names, Device, Peripheral};
2-
use proc_macro2::{Ident, Span, TokenStream};
2+
use proc_macro2::{Span, TokenStream};
33
use quote::{quote, ToTokens};
44

55
use log::debug;
6-
use std::borrow::Cow;
76
use std::fs::File;
87
use std::io::Write;
98
use std::path::Path;
109

1110
use crate::config::{Config, Target};
12-
use crate::util::{self, ToSanitizedCase};
11+
use crate::util::{self, ident, ToSanitizedCase};
1312
use anyhow::{Context, Result};
1413

1514
use crate::generate::{interrupt, peripheral};
@@ -231,48 +230,36 @@ pub fn render(d: &Device, config: &Config, device_x: &mut String) -> Result<Toke
231230
feature_attribute.extend(quote! { #[cfg(feature = #feature_name)] })
232231
};
233232

233+
let span = Span::call_site();
234234
match p {
235235
Peripheral::Single(_p) => {
236236
let p_name = util::name_of(p, config.ignore_groups);
237237
let p_snake = p_name.to_sanitized_snake_case();
238-
let p = p_name.to_sanitized_constant_case();
239-
let id = Ident::new(&p, Span::call_site());
238+
let p_ty = ident(&p_name, &config.ident_formats.peripheral, span);
240239
if config.feature_peripheral {
241240
feature_attribute.extend(quote! { #[cfg(feature = #p_snake)] })
242241
};
243242
fields.extend(quote! {
244-
#[doc = #p]
243+
#[doc = #p_name]
245244
#feature_attribute
246-
pub #id: #id,
245+
pub #p_ty: #p_ty,
247246
});
248-
exprs.extend(quote!(#feature_attribute #id: #id { _marker: PhantomData },));
247+
exprs.extend(quote!(#feature_attribute #p_ty: #p_ty { _marker: PhantomData },));
249248
}
250-
Peripheral::Array(_p, dim_element) => {
251-
let p_names: Vec<Cow<str>> = names(p, dim_element).map(|n| n.into()).collect();
252-
let p = p_names.iter().map(|p| p.to_sanitized_constant_case());
253-
let ids_f = p.clone().map(|p| Ident::new(&p, Span::call_site()));
254-
let ids_e = ids_f.clone();
255-
let feature_attribute = p_names
256-
.iter()
257-
.map(|p_name| {
258-
let p_snake = p_name.to_sanitized_snake_case();
259-
let mut feature_attribute = feature_attribute.clone();
260-
if config.feature_peripheral {
261-
feature_attribute.extend(quote! { #[cfg(feature = #p_snake)] })
262-
};
263-
feature_attribute
264-
})
265-
.collect::<Vec<_>>();
266-
fields.extend(quote! {
267-
#(
268-
#[doc = #p]
249+
Peripheral::Array(p, dim_element) => {
250+
for p_name in names(p, dim_element) {
251+
let p_snake = p_name.to_sanitized_snake_case();
252+
let p_ty = ident(&p_name, &config.ident_formats.peripheral, span);
253+
if config.feature_peripheral {
254+
feature_attribute.extend(quote! { #[cfg(feature = #p_snake)] })
255+
};
256+
fields.extend(quote! {
257+
#[doc = #p_name]
269258
#feature_attribute
270-
pub #ids_f: #ids_f,
271-
)*
272-
});
273-
exprs.extend(
274-
quote!(#(#feature_attribute #ids_e: #ids_e { _marker: PhantomData },)*),
275-
);
259+
pub #p_ty: #p_ty,
260+
});
261+
exprs.extend(quote!(#feature_attribute #p_ty: #p_ty { _marker: PhantomData },));
262+
}
276263
}
277264
}
278265
}

src/generate/interrupt.rs

Lines changed: 8 additions & 7 deletions
Original file line numberDiff line numberDiff line change
@@ -5,7 +5,7 @@ use crate::svd::Peripheral;
55
use proc_macro2::{Span, TokenStream};
66
use quote::quote;
77

8-
use crate::util::{self, ToSanitizedCase};
8+
use crate::util::{self, ident, ToSanitizedCase};
99
use crate::{Config, Target};
1010
use anyhow::Result;
1111

@@ -46,14 +46,15 @@ pub fn render(
4646
// Current position in the vector table
4747
let mut pos = 0;
4848
let mut mod_items = TokenStream::new();
49+
let span = Span::call_site();
4950
for interrupt in &interrupts {
5051
while pos < interrupt.0.value {
5152
elements.extend(quote!(Vector { _reserved: 0 },));
5253
pos += 1;
5354
}
5455
pos += 1;
5556

56-
let name_constant_case = interrupt.0.name.to_constant_case_ident(Span::call_site());
57+
let i_ty = ident(&interrupt.0.name, &config.ident_formats.interrupt, span);
5758
let description = format!(
5859
"{} - {}",
5960
interrupt.0.value,
@@ -89,25 +90,25 @@ pub fn render(
8990
variants.extend(quote! {
9091
#[doc = #description]
9192
#feature_attribute
92-
#name_constant_case = #value,
93+
#i_ty = #value,
9394
});
9495

9596
from_arms.extend(quote! {
9697
#feature_attribute
97-
#value => Ok(Interrupt::#name_constant_case),
98+
#value => Ok(Interrupt::#i_ty),
9899
});
99100

100101
if feature_attribute_flag {
101102
elements.extend(quote! {
102103
#not_feature_attribute
103104
Vector { _reserved: 0 },
104105
#feature_attribute
105-
Vector { _handler: #name_constant_case },
106+
Vector { _handler: #i_ty },
106107
});
107108
} else {
108-
elements.extend(quote!(Vector { _handler: #name_constant_case },));
109+
elements.extend(quote!(Vector { _handler: #i_ty },));
109110
}
110-
names.push(name_constant_case);
111+
names.push(i_ty);
111112
names_cfg_attr.push(feature_attribute);
112113
}
113114

0 commit comments

Comments
 (0)