1 // SPDX-License-Identifier: GPL-2.0 2 3 use proc_macro::{token_stream, Group, Ident, TokenStream, TokenTree}; 4 5 pub(crate) fn try_ident(it: &mut token_stream::IntoIter) -> Option<String> { 6 if let Some(TokenTree::Ident(ident)) = it.next() { 7 Some(ident.to_string()) 8 } else { 9 None 10 } 11 } 12 13 pub(crate) fn try_sign(it: &mut token_stream::IntoIter) -> Option<char> { 14 let peek = it.clone().next(); 15 match peek { 16 Some(TokenTree::Punct(punct)) if punct.as_char() == '-' => { 17 let _ = it.next(); 18 Some(punct.as_char()) 19 } 20 _ => None, 21 } 22 } 23 24 pub(crate) fn try_literal(it: &mut token_stream::IntoIter) -> Option<String> { 25 if let Some(TokenTree::Literal(literal)) = it.next() { 26 Some(literal.to_string()) 27 } else { 28 None 29 } 30 } 31 32 pub(crate) fn try_string(it: &mut token_stream::IntoIter) -> Option<String> { 33 try_literal(it).and_then(|string| { 34 if string.starts_with('\"') && string.ends_with('\"') { 35 let content = &string[1..string.len() - 1]; 36 if content.contains('\\') { 37 panic!("Escape sequences in string literals not yet handled"); 38 } 39 Some(content.to_string()) 40 } else if string.starts_with("r\"") { 41 panic!("Raw string literals are not yet handled"); 42 } else { 43 None 44 } 45 }) 46 } 47 48 pub(crate) fn expect_ident(it: &mut token_stream::IntoIter) -> String { 49 try_ident(it).expect("Expected Ident") 50 } 51 52 pub(crate) fn expect_punct(it: &mut token_stream::IntoIter) -> char { 53 if let TokenTree::Punct(punct) = it.next().expect("Reached end of token stream for Punct") { 54 punct.as_char() 55 } else { 56 panic!("Expected Punct"); 57 } 58 } 59 60 pub(crate) fn expect_string(it: &mut token_stream::IntoIter) -> String { 61 try_string(it).expect("Expected string") 62 } 63 64 pub(crate) fn expect_string_ascii(it: &mut token_stream::IntoIter) -> String { 65 let string = try_string(it).expect("Expected string"); 66 assert!(string.is_ascii(), "Expected ASCII string"); 67 string 68 } 69 70 pub(crate) fn expect_group(it: &mut token_stream::IntoIter) -> Group { 71 if let TokenTree::Group(group) = it.next().expect("Reached end of token stream for Group") { 72 group 73 } else { 74 panic!("Expected Group"); 75 } 76 } 77 78 pub(crate) fn expect_end(it: &mut token_stream::IntoIter) { 79 if it.next().is_some() { 80 panic!("Expected end"); 81 } 82 } 83 84 /// Given a function declaration, finds the name of the function. 85 pub(crate) fn function_name(input: TokenStream) -> Option<Ident> { 86 let mut input = input.into_iter(); 87 while let Some(token) = input.next() { 88 match token { 89 TokenTree::Ident(i) if i.to_string() == "fn" => { 90 if let Some(TokenTree::Ident(i)) = input.next() { 91 return Some(i); 92 } 93 return None; 94 } 95 _ => continue, 96 } 97 } 98 None 99 } 100 101 pub(crate) fn file() -> String { 102 #[cfg(not(CONFIG_RUSTC_HAS_SPAN_FILE))] 103 { 104 proc_macro::Span::call_site() 105 .source_file() 106 .path() 107 .to_string_lossy() 108 .into_owned() 109 } 110 111 #[cfg(CONFIG_RUSTC_HAS_SPAN_FILE)] 112 #[allow(clippy::incompatible_msrv)] 113 { 114 proc_macro::Span::call_site().file() 115 } 116 } 117 118 /// Parse a token stream of the form `expected_name: "value",` and return the 119 /// string in the position of "value". 120 /// 121 /// # Panics 122 /// 123 /// - On parse error. 124 pub(crate) fn expect_string_field(it: &mut token_stream::IntoIter, expected_name: &str) -> String { 125 assert_eq!(expect_ident(it), expected_name); 126 assert_eq!(expect_punct(it), ':'); 127 let string = expect_string(it); 128 assert_eq!(expect_punct(it), ','); 129 string 130 } 131