use crate::error::Error; use crate::prelude::{Delimiter, Group, Ident, Punct, TokenTree}; use std::iter::Peekable; mod attributes; mod body; mod data_type; mod generics; mod visibility; pub use self::attributes::{Attribute, AttributeLocation, FieldAttribute}; pub use self::body::{EnumBody, EnumVariant, Fields, StructBody, UnnamedField}; pub use self::data_type::DataType; pub use self::generics::{GenericConstraints, Generics, Lifetime, SimpleGeneric}; pub use self::visibility::Visibility; pub(self) fn assume_group(t: Option) -> Group { match t { Some(TokenTree::Group(group)) => group, _ => unreachable!(), } } pub(self) fn assume_ident(t: Option) -> Ident { match t { Some(TokenTree::Ident(ident)) => ident, _ => unreachable!(), } } pub(self) fn assume_punct(t: Option, punct: char) -> Punct { match t { Some(TokenTree::Punct(p)) => { debug_assert_eq!(punct, p.as_char()); p } _ => unreachable!(), } } pub(self) fn consume_punct_if( input: &mut Peekable>, punct: char, ) -> Option { if let Some(TokenTree::Punct(p)) = input.peek() { if p.as_char() == punct { match input.next() { Some(TokenTree::Punct(p)) => return Some(p), _ => unreachable!(), } } } None } #[cfg(test)] pub(self) fn ident_eq(ident: &Ident, text: &str) -> bool { ident == text } #[cfg(not(test))] pub(self) fn ident_eq(ident: &Ident, text: &str) -> bool { ident.to_string() == text } fn check_if_arrow(tokens: &[TokenTree], punct: &Punct) -> bool { if punct.as_char() == '>' { if let Some(TokenTree::Punct(previous_punct)) = tokens.last() { if previous_punct.as_char() == '-' { return true; } } } false } const OPEN_BRACKETS: &[char] = &['<', '(', '[', '{']; const CLOSING_BRACKETS: &[char] = &['>', ')', ']', '}']; const BRACKET_DELIMITER: &[Option] = &[ None, Some(Delimiter::Parenthesis), Some(Delimiter::Bracket), Some(Delimiter::Brace), ]; pub(self) fn read_tokens_until_punct( input: &mut Peekable>, expected_puncts: &[char], ) -> Result, Error> { let mut result = Vec::new(); let mut open_brackets = Vec::::new(); 'outer: loop { match input.peek() { Some(TokenTree::Punct(punct)) => { if check_if_arrow(&result, punct) { // do nothing } else if OPEN_BRACKETS.contains(&punct.as_char()) { open_brackets.push(punct.as_char()); } else if let Some(index) = CLOSING_BRACKETS.iter().position(|c| c == &punct.as_char()) { let last_bracket = match open_brackets.pop() { Some(bracket) => bracket, None => { if expected_puncts.contains(&punct.as_char()) { break; } return Err(Error::InvalidRustSyntax { span: punct.span(), expected: format!( "one of {:?}, got '{}'", expected_puncts, punct.as_char() ), }); } }; let expected = OPEN_BRACKETS[index]; assert_eq!( expected, last_bracket, "Unexpected closing bracket: found {}, expected {}", punct.as_char(), expected ); } else if expected_puncts.contains(&punct.as_char()) && open_brackets.is_empty() { break; } result.push(input.next().unwrap()); } Some(TokenTree::Group(g)) if open_brackets.is_empty() => { for punct in expected_puncts { if let Some(idx) = OPEN_BRACKETS.iter().position(|c| c == punct) { if let Some(delim) = BRACKET_DELIMITER[idx] { if delim == g.delimiter() { // we need to split on this delimiter break 'outer; } } } } result.push(input.next().unwrap()); } Some(_) => result.push(input.next().unwrap()), None => { break; } } } Ok(result) }