-
Notifications
You must be signed in to change notification settings - Fork 5
Commit
This commit does not belong to any branch on this repository, and may belong to a fork outside of the repository.
Move generics parsing into helper file
- Loading branch information
Showing
3 changed files
with
87 additions
and
84 deletions.
There are no files selected for viewing
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
Original file line number | Diff line number | Diff line change |
---|---|---|
@@ -0,0 +1,85 @@ | ||
use proc_macro2::{Punct, Spacing, TokenStream, TokenTree}; | ||
|
||
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, | ||
) | ||
} |
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
Original file line number | Diff line number | Diff line change |
---|---|---|
@@ -1,3 +1,4 @@ | ||
mod helpers; | ||
mod pin_data; | ||
mod pinned_drop; | ||
|
||
|
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters