use proc_macro::{Delimiter, Group, Ident, Spacing, Span, TokenTree};
fn concat_helper(tokens: &[TokenTree]) -> Vec<(String, Span)> { letmut tokens = tokens.iter(); letmut segments = Vec::new(); letmut span = None; loop { match tokens.next() {
None => break,
Some(TokenTree::Literal(lit)) => { // Allow us to concat string literals by stripping quotes letmut value = lit.to_string(); if value.starts_with('"') && value.ends_with('"') {
value.remove(0);
value.pop();
}
segments.push((value, lit.span()));
}
Some(TokenTree::Ident(ident)) => { letmut value = ident.to_string(); if value.starts_with("r#") {
value.replace_range(0..2, "");
}
segments.push((value, ident.span()));
}
Some(TokenTree::Punct(p)) if p.as_char() == ':' => { let Some(TokenTree::Ident(ident)) = tokens.next() else {
panic!("expected identifier as modifier");
};
let (mut value, sp) = segments.pop().expect("expected identifier before modifier"); match ident.to_string().as_str() { // Set the overall span of concatenated token as current span "span" => {
assert!(
span.is_none(), "span modifier should only appear at most once"
);
span = Some(sp);
} "lower" => value = value.to_lowercase(), "upper" => value = value.to_uppercase(),
v => panic!("unknown modifier `{v}`"),
};
segments.push((value, sp));
}
Some(TokenTree::Group(group)) if group.delimiter() == Delimiter::None => { let tokens = group.stream().into_iter().collect::<Vec<TokenTree>>();
segments.append(&mut concat_helper(tokens.as_slice()));
}
token => panic!("unexpected token in paste segments: {token:?}"),
};
}
Die Informationen auf dieser Webseite wurden
nach bestem Wissen sorgfältig zusammengestellt. Es wird jedoch weder Vollständigkeit, noch Richtigkeit,
noch Qualität der bereit gestellten Informationen zugesichert.
Bemerkung:
Die farbliche Syntaxdarstellung und die Messung sind noch experimentell.