paste.rs 4.5 KB

123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108109110111112113
  1. // SPDX-License-Identifier: GPL-2.0
  2. use proc_macro2::{Delimiter, Group, Ident, Spacing, Span, TokenTree};
  3. fn concat_helper(tokens: &[TokenTree]) -> Vec<(String, Span)> {
  4. let mut tokens = tokens.iter();
  5. let mut segments = Vec::new();
  6. let mut span = None;
  7. loop {
  8. match tokens.next() {
  9. None => break,
  10. Some(TokenTree::Literal(lit)) => {
  11. // Allow us to concat string literals by stripping quotes
  12. let mut value = lit.to_string();
  13. if value.starts_with('"') && value.ends_with('"') {
  14. value.remove(0);
  15. value.pop();
  16. }
  17. segments.push((value, lit.span()));
  18. }
  19. Some(TokenTree::Ident(ident)) => {
  20. let mut value = ident.to_string();
  21. if value.starts_with("r#") {
  22. value.replace_range(0..2, "");
  23. }
  24. segments.push((value, ident.span()));
  25. }
  26. Some(TokenTree::Punct(p)) if p.as_char() == ':' => {
  27. let Some(TokenTree::Ident(ident)) = tokens.next() else {
  28. panic!("expected identifier as modifier");
  29. };
  30. let (mut value, sp) = segments.pop().expect("expected identifier before modifier");
  31. match ident.to_string().as_str() {
  32. // Set the overall span of concatenated token as current span
  33. "span" => {
  34. assert!(
  35. span.is_none(),
  36. "span modifier should only appear at most once"
  37. );
  38. span = Some(sp);
  39. }
  40. "lower" => value = value.to_lowercase(),
  41. "upper" => value = value.to_uppercase(),
  42. v => panic!("unknown modifier `{v}`"),
  43. };
  44. segments.push((value, sp));
  45. }
  46. Some(TokenTree::Group(group)) if group.delimiter() == Delimiter::None => {
  47. let tokens = group.stream().into_iter().collect::<Vec<TokenTree>>();
  48. segments.append(&mut concat_helper(tokens.as_slice()));
  49. }
  50. token => panic!("unexpected token in paste segments: {token:?}"),
  51. };
  52. }
  53. segments
  54. }
  55. fn concat(tokens: &[TokenTree], group_span: Span) -> TokenTree {
  56. let segments = concat_helper(tokens);
  57. let pasted: String = segments.into_iter().map(|x| x.0).collect();
  58. TokenTree::Ident(Ident::new(&pasted, group_span))
  59. }
  60. pub(crate) fn expand(tokens: &mut Vec<TokenTree>) {
  61. for token in tokens.iter_mut() {
  62. if let TokenTree::Group(group) = token {
  63. let delimiter = group.delimiter();
  64. let span = group.span();
  65. let mut stream: Vec<_> = group.stream().into_iter().collect();
  66. // Find groups that looks like `[< A B C D >]`
  67. if delimiter == Delimiter::Bracket
  68. && stream.len() >= 3
  69. && matches!(&stream[0], TokenTree::Punct(p) if p.as_char() == '<')
  70. && matches!(&stream[stream.len() - 1], TokenTree::Punct(p) if p.as_char() == '>')
  71. {
  72. // Replace the group with concatenated token
  73. *token = concat(&stream[1..stream.len() - 1], span);
  74. } else {
  75. // Recursively expand tokens inside the group
  76. expand(&mut stream);
  77. let mut group = Group::new(delimiter, stream.into_iter().collect());
  78. group.set_span(span);
  79. *token = TokenTree::Group(group);
  80. }
  81. }
  82. }
  83. // Path segments cannot contain invisible delimiter group, so remove them if any.
  84. for i in (0..tokens.len().saturating_sub(3)).rev() {
  85. // Looking for a double colon
  86. if matches!(
  87. (&tokens[i + 1], &tokens[i + 2]),
  88. (TokenTree::Punct(a), TokenTree::Punct(b))
  89. if a.as_char() == ':' && a.spacing() == Spacing::Joint && b.as_char() == ':'
  90. ) {
  91. match &tokens[i + 3] {
  92. TokenTree::Group(group) if group.delimiter() == Delimiter::None => {
  93. tokens.splice(i + 3..i + 4, group.stream());
  94. }
  95. _ => (),
  96. }
  97. match &tokens[i] {
  98. TokenTree::Group(group) if group.delimiter() == Delimiter::None => {
  99. tokens.splice(i..i + 1, group.stream());
  100. }
  101. _ => (),
  102. }
  103. }
  104. }
  105. }