mirror of
https://gitee.com/bianbu-linux/linux-6.6
synced 2025-04-24 14:07:52 -04:00
rust: macros: refactor generics parsing of #[pin_data]
into its own function
Other macros might also want to parse generics. Additionally this makes the code easier to read, as the next commit will introduce more code in `#[pin_data]`. Also add more comments to explain how parsing generics work. Signed-off-by: Benno Lossin <benno.lossin@proton.me> Reviewed-by: Alice Ryhl <aliceryhl@google.com> Reviewed-by: Gary Guo <gary@garyguo.net> Reviewed-by: Martin Rodriguez Reboredo <yakoyoku@gmail.com> Link: https://lore.kernel.org/r/20230424081112.99890-2-benno.lossin@proton.me Signed-off-by: Miguel Ojeda <ojeda@kernel.org>
This commit is contained in:
parent
b8342addde
commit
e957b9cda3
2 changed files with 94 additions and 62 deletions
|
@ -1,6 +1,6 @@
|
||||||
// SPDX-License-Identifier: GPL-2.0
|
// SPDX-License-Identifier: GPL-2.0
|
||||||
|
|
||||||
use proc_macro::{token_stream, Group, TokenTree};
|
use proc_macro::{token_stream, Group, Punct, Spacing, TokenStream, TokenTree};
|
||||||
|
|
||||||
pub(crate) fn try_ident(it: &mut token_stream::IntoIter) -> Option<String> {
|
pub(crate) fn try_ident(it: &mut token_stream::IntoIter) -> Option<String> {
|
||||||
if let Some(TokenTree::Ident(ident)) = it.next() {
|
if let Some(TokenTree::Ident(ident)) = it.next() {
|
||||||
|
@ -69,3 +69,87 @@ pub(crate) fn expect_end(it: &mut token_stream::IntoIter) {
|
||||||
panic!("Expected end");
|
panic!("Expected end");
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
pub(crate) struct Generics {
|
||||||
|
pub(crate) impl_generics: Vec<TokenTree>,
|
||||||
|
pub(crate) ty_generics: Vec<TokenTree>,
|
||||||
|
}
|
||||||
|
|
||||||
|
/// Parses the given `TokenStream` into `Generics` and the rest.
|
||||||
|
///
|
||||||
|
/// The generics are not present in the rest, but a where clause might remain.
|
||||||
|
pub(crate) fn parse_generics(input: TokenStream) -> (Generics, Vec<TokenTree>) {
|
||||||
|
// `impl_generics`, the declared generics with their bounds.
|
||||||
|
let mut impl_generics = vec![];
|
||||||
|
// Only the names of the generics, without any bounds.
|
||||||
|
let mut ty_generics = vec![];
|
||||||
|
// Tokens not related to the generics e.g. the `where` token and definition.
|
||||||
|
let mut rest = vec![];
|
||||||
|
// The current level of `<`.
|
||||||
|
let mut nesting = 0;
|
||||||
|
let mut toks = input.into_iter();
|
||||||
|
// If we are at the beginning of a generic parameter.
|
||||||
|
let mut at_start = true;
|
||||||
|
for tt in &mut toks {
|
||||||
|
match tt.clone() {
|
||||||
|
TokenTree::Punct(p) if p.as_char() == '<' => {
|
||||||
|
if nesting >= 1 {
|
||||||
|
// This is inside of the generics and part of some bound.
|
||||||
|
impl_generics.push(tt);
|
||||||
|
}
|
||||||
|
nesting += 1;
|
||||||
|
}
|
||||||
|
TokenTree::Punct(p) if p.as_char() == '>' => {
|
||||||
|
// This is a parsing error, so we just end it here.
|
||||||
|
if nesting == 0 {
|
||||||
|
break;
|
||||||
|
} else {
|
||||||
|
nesting -= 1;
|
||||||
|
if nesting >= 1 {
|
||||||
|
// We are still inside of the generics and part of some bound.
|
||||||
|
impl_generics.push(tt);
|
||||||
|
}
|
||||||
|
if nesting == 0 {
|
||||||
|
break;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
tt => {
|
||||||
|
if nesting == 1 {
|
||||||
|
// Here depending on the token, it might be a generic variable name.
|
||||||
|
match &tt {
|
||||||
|
// Ignore const.
|
||||||
|
TokenTree::Ident(i) if i.to_string() == "const" => {}
|
||||||
|
TokenTree::Ident(_) if at_start => {
|
||||||
|
ty_generics.push(tt.clone());
|
||||||
|
// We also already push the `,` token, this makes it easier to append
|
||||||
|
// generics.
|
||||||
|
ty_generics.push(TokenTree::Punct(Punct::new(',', Spacing::Alone)));
|
||||||
|
at_start = false;
|
||||||
|
}
|
||||||
|
TokenTree::Punct(p) if p.as_char() == ',' => at_start = true,
|
||||||
|
// Lifetimes begin with `'`.
|
||||||
|
TokenTree::Punct(p) if p.as_char() == '\'' && at_start => {
|
||||||
|
ty_generics.push(tt.clone());
|
||||||
|
}
|
||||||
|
_ => {}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
if nesting >= 1 {
|
||||||
|
impl_generics.push(tt);
|
||||||
|
} else if nesting == 0 {
|
||||||
|
// If we haven't entered the generics yet, we still want to keep these tokens.
|
||||||
|
rest.push(tt);
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
rest.extend(toks);
|
||||||
|
(
|
||||||
|
Generics {
|
||||||
|
impl_generics,
|
||||||
|
ty_generics,
|
||||||
|
},
|
||||||
|
rest,
|
||||||
|
)
|
||||||
|
}
|
||||||
|
|
|
@ -1,71 +1,19 @@
|
||||||
// SPDX-License-Identifier: Apache-2.0 OR MIT
|
// SPDX-License-Identifier: Apache-2.0 OR MIT
|
||||||
|
|
||||||
use proc_macro::{Punct, Spacing, TokenStream, TokenTree};
|
use crate::helpers::{parse_generics, Generics};
|
||||||
|
use proc_macro::TokenStream;
|
||||||
|
|
||||||
pub(crate) fn pin_data(args: TokenStream, input: TokenStream) -> TokenStream {
|
pub(crate) fn pin_data(args: TokenStream, input: TokenStream) -> TokenStream {
|
||||||
// This proc-macro only does some pre-parsing and then delegates the actual parsing to
|
// This proc-macro only does some pre-parsing and then delegates the actual parsing to
|
||||||
// `kernel::__pin_data!`.
|
// `kernel::__pin_data!`.
|
||||||
//
|
|
||||||
// In here we only collect the generics, since parsing them in declarative macros is very
|
|
||||||
// elaborate. We also do not need to analyse their structure, we only need to collect them.
|
|
||||||
|
|
||||||
// `impl_generics`, the declared generics with their bounds.
|
let (
|
||||||
let mut impl_generics = vec![];
|
Generics {
|
||||||
// Only the names of the generics, without any bounds.
|
impl_generics,
|
||||||
let mut ty_generics = vec![];
|
ty_generics,
|
||||||
// Tokens not related to the generics e.g. the `impl` token.
|
},
|
||||||
let mut rest = vec![];
|
mut rest,
|
||||||
// The current level of `<`.
|
) = parse_generics(input);
|
||||||
let mut nesting = 0;
|
|
||||||
let mut toks = input.into_iter();
|
|
||||||
// If we are at the beginning of a generic parameter.
|
|
||||||
let mut at_start = true;
|
|
||||||
for tt in &mut toks {
|
|
||||||
match tt.clone() {
|
|
||||||
TokenTree::Punct(p) if p.as_char() == '<' => {
|
|
||||||
if nesting >= 1 {
|
|
||||||
impl_generics.push(tt);
|
|
||||||
}
|
|
||||||
nesting += 1;
|
|
||||||
}
|
|
||||||
TokenTree::Punct(p) if p.as_char() == '>' => {
|
|
||||||
if nesting == 0 {
|
|
||||||
break;
|
|
||||||
} else {
|
|
||||||
nesting -= 1;
|
|
||||||
if nesting >= 1 {
|
|
||||||
impl_generics.push(tt);
|
|
||||||
}
|
|
||||||
if nesting == 0 {
|
|
||||||
break;
|
|
||||||
}
|
|
||||||
}
|
|
||||||
}
|
|
||||||
tt => {
|
|
||||||
if nesting == 1 {
|
|
||||||
match &tt {
|
|
||||||
TokenTree::Ident(i) if i.to_string() == "const" => {}
|
|
||||||
TokenTree::Ident(_) if at_start => {
|
|
||||||
ty_generics.push(tt.clone());
|
|
||||||
ty_generics.push(TokenTree::Punct(Punct::new(',', Spacing::Alone)));
|
|
||||||
at_start = false;
|
|
||||||
}
|
|
||||||
TokenTree::Punct(p) if p.as_char() == ',' => at_start = true,
|
|
||||||
TokenTree::Punct(p) if p.as_char() == '\'' && at_start => {
|
|
||||||
ty_generics.push(tt.clone());
|
|
||||||
}
|
|
||||||
_ => {}
|
|
||||||
}
|
|
||||||
}
|
|
||||||
if nesting >= 1 {
|
|
||||||
impl_generics.push(tt);
|
|
||||||
} else if nesting == 0 {
|
|
||||||
rest.push(tt);
|
|
||||||
}
|
|
||||||
}
|
|
||||||
}
|
|
||||||
}
|
|
||||||
rest.extend(toks);
|
|
||||||
// This should be the body of the struct `{...}`.
|
// This should be the body of the struct `{...}`.
|
||||||
let last = rest.pop();
|
let last = rest.pop();
|
||||||
quote!(::kernel::__pin_data! {
|
quote!(::kernel::__pin_data! {
|
||||||
|
|
Loading…
Add table
Add a link
Reference in a new issue