Skip to content

Commit 127a11b

Browse files
committed
rust: separate parse and codegen in module!
Doing so allows `module_misc_device!` to do codegen directly instead of generating a `module!` invocation. Generating `module!` invocation is error-prone and would require significant effort when features are added to `module!` macro or when syntax is changed. Signed-off-by: Gary Guo <gary@garyguo.net>
1 parent 1b842c3 commit 127a11b

File tree

1 file changed

+137
-128
lines changed

1 file changed

+137
-128
lines changed

rust/macros/module.rs

Lines changed: 137 additions & 128 deletions
Original file line numberDiff line numberDiff line change
@@ -56,7 +56,7 @@ fn expect_byte_string(it: &mut token_stream::IntoIter) -> String {
5656
try_byte_string(it).expect("Expected byte string")
5757
}
5858

59-
#[derive(Clone, PartialEq)]
59+
#[derive(Debug, Clone, PartialEq)]
6060
enum ParamType {
6161
Ident(String),
6262
Array { vals: String, max_length: usize },
@@ -285,6 +285,44 @@ fn generated_array_ops_name(vals: &str, max_length: usize) -> String {
285285
)
286286
}
287287

288+
#[derive(Debug)]
289+
struct ParamInfo {
290+
name: String,
291+
type_: ParamType,
292+
default: String,
293+
permission: String,
294+
description: String,
295+
}
296+
297+
impl ParamInfo {
298+
fn try_parse(it: &mut token_stream::IntoIter) -> Option<Self> {
299+
let param_name = match it.next() {
300+
Some(TokenTree::Ident(ident)) => ident.to_string(),
301+
Some(_) => panic!("Expected Ident or end"),
302+
None => return None,
303+
};
304+
305+
assert_eq!(expect_punct(it), ':');
306+
let param_type = expect_type(it);
307+
let group = expect_group(it);
308+
assert_eq!(group.delimiter(), Delimiter::Brace);
309+
310+
let mut param_it = group.stream().into_iter();
311+
let param_default = get_default(&param_type, &mut param_it);
312+
let param_permissions = get_literal(&mut param_it, "permissions");
313+
let param_description = get_byte_string(&mut param_it, "description");
314+
expect_end(&mut param_it);
315+
316+
Some(ParamInfo {
317+
name: param_name,
318+
type_: param_type,
319+
default: param_default,
320+
permission: param_permissions,
321+
description: param_description,
322+
})
323+
}
324+
}
325+
288326
#[derive(Debug, Default)]
289327
struct ModuleInfo {
290328
type_: String,
@@ -293,7 +331,7 @@ struct ModuleInfo {
293331
author: Option<String>,
294332
description: Option<String>,
295333
alias: Option<String>,
296-
params: Option<Group>,
334+
params: Vec<ParamInfo>,
297335
}
298336

299337
impl ModuleInfo {
@@ -339,7 +377,17 @@ impl ModuleInfo {
339377
"alias_rtnl_link" => {
340378
info.alias = Some(format!("rtnl-link-{}", expect_byte_string(it)))
341379
}
342-
"params" => info.params = Some(expect_group(it)),
380+
"params" => {
381+
let group = expect_group(it);
382+
assert_eq!(group.delimiter(), Delimiter::Brace);
383+
let mut inner_it = group.stream().into_iter();
384+
let mut params = Vec::new();
385+
while let Some(param) = ParamInfo::try_parse(&mut inner_it) {
386+
assert_eq!(expect_punct(&mut inner_it), ',');
387+
params.push(param);
388+
}
389+
info.params = params;
390+
}
343391
_ => panic!(
344392
"Unknown key \"{}\". Valid keys are: {:?}.",
345393
key, EXPECTED_KEYS
@@ -375,73 +423,46 @@ impl ModuleInfo {
375423

376424
info
377425
}
378-
}
379-
380-
pub fn module(ts: TokenStream) -> TokenStream {
381-
let mut it = ts.into_iter();
382-
383-
let info = ModuleInfo::parse(&mut it);
384-
385-
let name = info.name.clone();
386-
387-
let mut modinfo = ModInfoBuilder::new(&name);
388-
if let Some(author) = info.author {
389-
modinfo.emit("author", &author);
390-
}
391-
if let Some(description) = info.description {
392-
modinfo.emit("description", &description);
393-
}
394-
modinfo.emit("license", &info.license);
395-
if let Some(alias) = info.alias {
396-
modinfo.emit("alias", &alias);
397-
}
398-
399-
// Built-in modules also export the `file` modinfo string
400-
let file =
401-
std::env::var("RUST_MODFILE").expect("Unable to fetch RUST_MODFILE environmental variable");
402-
modinfo.emit_only_builtin("file", &file);
403-
404-
let mut array_types_to_generate = Vec::new();
405-
if let Some(params) = info.params {
406-
assert_eq!(params.delimiter(), Delimiter::Brace);
407426

408-
let mut it = params.stream().into_iter();
409-
410-
loop {
411-
let param_name = match it.next() {
412-
Some(TokenTree::Ident(ident)) => ident.to_string(),
413-
Some(_) => panic!("Expected Ident or end"),
414-
None => break,
415-
};
416-
417-
assert_eq!(expect_punct(&mut it), ':');
418-
let param_type = expect_type(&mut it);
419-
let group = expect_group(&mut it);
420-
assert_eq!(expect_punct(&mut it), ',');
427+
fn generate(&self) -> TokenStream {
428+
let name = &self.name;
429+
let mut modinfo = ModInfoBuilder::new(name);
430+
if let Some(author) = &self.author {
431+
modinfo.emit("author", author);
432+
}
433+
if let Some(description) = &self.description {
434+
modinfo.emit("description", description);
435+
}
436+
modinfo.emit("license", &self.license);
437+
if let Some(alias) = &self.alias {
438+
modinfo.emit("alias", alias);
439+
}
421440

422-
assert_eq!(group.delimiter(), Delimiter::Brace);
441+
// Built-in modules also export the `file` modinfo string
442+
let file = std::env::var("RUST_MODFILE")
443+
.expect("Unable to fetch RUST_MODFILE environmental variable");
444+
modinfo.emit_only_builtin("file", &file);
423445

424-
let mut param_it = group.stream().into_iter();
425-
let param_default = get_default(&param_type, &mut param_it);
426-
let param_permissions = get_literal(&mut param_it, "permissions");
427-
let param_description = get_byte_string(&mut param_it, "description");
428-
expect_end(&mut param_it);
446+
let mut array_types_to_generate = Vec::new();
447+
for param in self.params.iter() {
448+
let param_name = &param.name;
449+
let param_type = &param.type_;
450+
let param_default = &param.default;
451+
let param_permissions = &param.permission;
452+
let param_description = &param.description;
429453

430454
// TODO: more primitive types
431455
// TODO: other kinds: unsafes, etc.
432456
let (param_kernel_type, ops): (String, _) = match param_type {
433-
ParamType::Ident(ref param_type) => (
457+
ParamType::Ident(param_type) => (
434458
param_type.to_string(),
435459
param_ops_path(param_type).to_string(),
436460
),
437-
ParamType::Array {
438-
ref vals,
439-
max_length,
440-
} => {
441-
array_types_to_generate.push((vals.clone(), max_length));
461+
ParamType::Array { vals, max_length } => {
462+
array_types_to_generate.push((vals.clone(), *max_length));
442463
(
443464
format!("__rust_array_param_{}_{}", vals, max_length),
444-
generated_array_ops_name(vals, max_length),
465+
generated_array_ops_name(vals, *max_length),
445466
)
446467
}
447468
};
@@ -465,10 +486,10 @@ pub fn module(ts: TokenStream) -> TokenStream {
465486
let read_func = if permissions_are_readonly(&param_permissions) {
466487
format!(
467488
"
468-
fn read(&self) -> &<{param_type_internal} as kernel::module_param::ModuleParam>::Value {{
469-
// SAFETY: Parameters do not need to be locked because they are read only or sysfs is not enabled.
470-
unsafe {{ <{param_type_internal} as kernel::module_param::ModuleParam>::value(&__{name}_{param_name}_value) }}
471-
}}
489+
fn read(&self) -> &<{param_type_internal} as kernel::module_param::ModuleParam>::Value {{
490+
// SAFETY: Parameters do not need to be locked because they are read only or sysfs is not enabled.
491+
unsafe {{ <{param_type_internal} as kernel::module_param::ModuleParam>::value(&__{name}_{param_name}_value) }}
492+
}}
472493
",
473494
name = name,
474495
param_name = param_name,
@@ -477,10 +498,10 @@ pub fn module(ts: TokenStream) -> TokenStream {
477498
} else {
478499
format!(
479500
"
480-
fn read<'lck>(&self, lock: &'lck kernel::KParamGuard) -> &'lck <{param_type_internal} as kernel::module_param::ModuleParam>::Value {{
481-
// SAFETY: Parameters are locked by `KParamGuard`.
482-
unsafe {{ <{param_type_internal} as kernel::module_param::ModuleParam>::value(&__{name}_{param_name}_value) }}
483-
}}
501+
fn read<'lck>(&self, lock: &'lck kernel::KParamGuard) -> &'lck <{param_type_internal} as kernel::module_param::ModuleParam>::Value {{
502+
// SAFETY: Parameters are locked by `KParamGuard`.
503+
unsafe {{ <{param_type_internal} as kernel::module_param::ModuleParam>::value(&__{name}_{param_name}_value) }}
504+
}}
484505
",
485506
name = name,
486507
param_name = param_name,
@@ -553,27 +574,26 @@ pub fn module(ts: TokenStream) -> TokenStream {
553574
)
554575
);
555576
}
556-
}
557577

558-
let mut generated_array_types = String::new();
578+
let mut generated_array_types = String::new();
559579

560-
for (vals, max_length) in array_types_to_generate {
561-
let ops_name = generated_array_ops_name(&vals, max_length);
562-
generated_array_types.push_str(&format!(
563-
"
580+
for (vals, max_length) in array_types_to_generate {
581+
let ops_name = generated_array_ops_name(&vals, max_length);
582+
generated_array_types.push_str(&format!(
583+
"
564584
kernel::make_param_ops!(
565585
{ops_name},
566586
kernel::module_param::ArrayParam<{vals}, {{ {max_length} }}>
567587
);
568-
",
569-
ops_name = ops_name,
570-
vals = vals,
571-
max_length = max_length,
572-
));
573-
}
588+
",
589+
ops_name = ops_name,
590+
vals = vals,
591+
max_length = max_length,
592+
));
593+
}
574594

575-
format!(
576-
"
595+
format!(
596+
"
577597
/// The module name.
578598
///
579599
/// Used by the printing macros, e.g. [`info!`].
@@ -659,69 +679,58 @@ pub fn module(ts: TokenStream) -> TokenStream {
659679
{modinfo}
660680
661681
{generated_array_types}
662-
",
663-
type_ = info.type_,
664-
name = info.name,
665-
modinfo = modinfo.buffer,
666-
generated_array_types = generated_array_types,
667-
initcall_section = ".initcall6.init"
668-
).parse().expect("Error parsing formatted string into token stream.")
682+
",
683+
type_ = self.type_,
684+
name = self.name,
685+
modinfo = modinfo.buffer,
686+
generated_array_types = generated_array_types,
687+
initcall_section = ".initcall6.init"
688+
).parse().expect("Error parsing formatted string into token stream.")
689+
}
669690
}
670691

671-
pub fn module_misc_device(ts: TokenStream) -> TokenStream {
692+
pub fn module(ts: TokenStream) -> TokenStream {
672693
let mut it = ts.into_iter();
673-
674694
let info = ModuleInfo::parse(&mut it);
695+
info.generate()
696+
}
675697

676-
let module = format!("__internal_ModuleFor{}", info.type_);
698+
pub fn module_misc_device(ts: TokenStream) -> TokenStream {
699+
let mut it = ts.into_iter();
677700

678-
format!(
679-
"
680-
#[doc(hidden)]
681-
struct {module} {{
682-
_dev: core::pin::Pin<alloc::boxed::Box<kernel::miscdev::Registration>>,
683-
}}
701+
let mut info = ModuleInfo::parse(&mut it);
702+
let type_ = info.type_;
684703

685-
impl kernel::KernelModule for {module} {{
686-
fn init() -> kernel::Result<Self> {{
687-
Ok(Self {{
688-
_dev: kernel::miscdev::Registration::new_pinned::<{type_}>(
689-
kernel::c_str!(\"{name}\"),
690-
None,
691-
(),
692-
)?,
693-
}})
694-
}}
695-
}}
704+
let module = format!("__internal_ModuleFor{}", type_);
705+
info.type_ = module.clone();
696706

697-
kernel::prelude::module! {{
698-
type: {module},
699-
name: b\"{name}\",
700-
{author}
701-
{description}
702-
license: b\"{license}\",
703-
{alias}
707+
let extra = format!(
708+
"
709+
#[doc(hidden)]
710+
struct {module} {{
711+
_dev: core::pin::Pin<alloc::boxed::Box<kernel::miscdev::Registration>>,
712+
}}
713+
714+
impl kernel::KernelModule for {module} {{
715+
fn init() -> kernel::Result<Self> {{
716+
Ok(Self {{
717+
_dev: kernel::miscdev::Registration::new_pinned::<{type_}>(
718+
kernel::c_str!(\"{name}\"),
719+
None,
720+
(),
721+
)?,
722+
}})
704723
}}
724+
}}
705725
",
706726
module = module,
707727
type_ = info.type_,
708728
name = info.name,
709-
author = info
710-
.author
711-
.map(|v| format!("author: b\"{}\",", v))
712-
.unwrap_or_else(|| "".to_string()),
713-
description = info
714-
.description
715-
.map(|v| format!("description: b\"{}\",", v))
716-
.unwrap_or_else(|| "".to_string()),
717-
alias = info
718-
.alias
719-
.map(|v| format!("alias: b\"{}\",", v))
720-
.unwrap_or_else(|| "".to_string()),
721-
license = info.license
722729
)
723730
.parse()
724-
.expect("Error parsing formatted string into token stream.")
731+
.expect("Error parsing formatted string into token stream.");
732+
733+
vec![extra, info.generate()].into_iter().collect()
725734
}
726735

727736
#[cfg(test)]

0 commit comments

Comments
 (0)