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