ident.rs 3.1 KB

123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108109110
  1. // SPDX-License-Identifier: Apache-2.0 OR MIT
  2. #[cfg(feature = "parsing")]
  3. use crate::lookahead;
  4. pub use proc_macro2::Ident;
  5. #[cfg(feature = "parsing")]
  6. pub_if_not_doc! {
  7. #[doc(hidden)]
  8. #[allow(non_snake_case)]
  9. pub fn Ident(marker: lookahead::TokenMarker) -> Ident {
  10. match marker {}
  11. }
  12. }
  13. macro_rules! ident_from_token {
  14. ($token:ident) => {
  15. impl From<Token![$token]> for Ident {
  16. fn from(token: Token![$token]) -> Ident {
  17. Ident::new(stringify!($token), token.span)
  18. }
  19. }
  20. };
  21. }
  22. ident_from_token!(self);
  23. ident_from_token!(Self);
  24. ident_from_token!(super);
  25. ident_from_token!(crate);
  26. ident_from_token!(extern);
  27. impl From<Token![_]> for Ident {
  28. fn from(token: Token![_]) -> Ident {
  29. Ident::new("_", token.span)
  30. }
  31. }
  32. pub(crate) fn xid_ok(symbol: &str) -> bool {
  33. let mut chars = symbol.chars();
  34. let first = chars.next().unwrap();
  35. if !(first == '_' || first.is_ascii_alphabetic()) {
  36. return false;
  37. }
  38. for ch in chars {
  39. if !(ch == '_' || ch.is_ascii_alphanumeric()) {
  40. return false;
  41. }
  42. }
  43. true
  44. }
  45. #[cfg(feature = "parsing")]
  46. mod parsing {
  47. use crate::buffer::Cursor;
  48. use crate::error::Result;
  49. use crate::parse::{Parse, ParseStream};
  50. use crate::token::Token;
  51. use proc_macro2::Ident;
  52. fn accept_as_ident(ident: &Ident) -> bool {
  53. match ident.to_string().as_str() {
  54. "_" |
  55. // Based on https://doc.rust-lang.org/1.65.0/reference/keywords.html
  56. "abstract" | "as" | "async" | "await" | "become" | "box" | "break" |
  57. "const" | "continue" | "crate" | "do" | "dyn" | "else" | "enum" |
  58. "extern" | "false" | "final" | "fn" | "for" | "if" | "impl" | "in" |
  59. "let" | "loop" | "macro" | "match" | "mod" | "move" | "mut" |
  60. "override" | "priv" | "pub" | "ref" | "return" | "Self" | "self" |
  61. "static" | "struct" | "super" | "trait" | "true" | "try" | "type" |
  62. "typeof" | "unsafe" | "unsized" | "use" | "virtual" | "where" |
  63. "while" | "yield" => false,
  64. _ => true,
  65. }
  66. }
  67. #[cfg_attr(docsrs, doc(cfg(feature = "parsing")))]
  68. impl Parse for Ident {
  69. fn parse(input: ParseStream) -> Result<Self> {
  70. input.step(|cursor| {
  71. if let Some((ident, rest)) = cursor.ident() {
  72. if accept_as_ident(&ident) {
  73. Ok((ident, rest))
  74. } else {
  75. Err(cursor.error(format_args!(
  76. "expected identifier, found keyword `{}`",
  77. ident,
  78. )))
  79. }
  80. } else {
  81. Err(cursor.error("expected identifier"))
  82. }
  83. })
  84. }
  85. }
  86. impl Token for Ident {
  87. fn peek(cursor: Cursor) -> bool {
  88. if let Some((ident, _rest)) = cursor.ident() {
  89. accept_as_ident(&ident)
  90. } else {
  91. false
  92. }
  93. }
  94. fn display() -> &'static str {
  95. "identifier"
  96. }
  97. }
  98. }