1use std::{
2 fmt,
3 hash::{Hash, Hasher},
4};
5
6use crate::span::Span;
7
8#[derive(Clone)]
13pub struct Ident {
14 pub name: String,
15 pub span: Span,
16}
17
18impl Ident {
19 pub fn new(name: String, span: Span) -> Self {
21 Ident { name, span }
22 }
23
24 pub fn new_str(name: &str, span: Span) -> Self {
26 Ident {
27 name: name.to_string(),
28 span,
29 }
30 }
31
32 pub fn name(&self) -> &str {
34 &self.name
35 }
36
37 pub fn span(&self) -> Span {
39 self.span
40 }
41
42 pub fn dummy(name: &str) -> Self {
44 Ident {
45 name: name.to_string(),
46 span: Span::call_site(),
47 }
48 }
49}
50
51impl PartialEq for Ident {
52 fn eq(&self, other: &Self) -> bool {
53 self.name == other.name
54 }
55}
56
57impl Eq for Ident {}
58
59impl Hash for Ident {
60 fn hash<H: Hasher>(&self, state: &mut H) {
61 self.name.hash(state);
62 }
63}
64
65impl PartialOrd for Ident {
66 fn partial_cmp(&self, other: &Self) -> Option<std::cmp::Ordering> {
67 Some(self.cmp(other))
68 }
69}
70
71impl Ord for Ident {
72 fn cmp(&self, other: &Self) -> std::cmp::Ordering {
73 self.name.cmp(&other.name)
74 }
75}
76
77impl fmt::Debug for Ident {
78 fn fmt(&self, f: &mut fmt::Formatter<'_>) -> fmt::Result {
79 write!(f, "Ident({:?})", self.name)
80 }
81}
82
83impl fmt::Display for Ident {
84 fn fmt(&self, f: &mut fmt::Formatter<'_>) -> fmt::Result {
85 write!(f, "{}", self.name)
86 }
87}
88
89impl AsRef<str> for Ident {
90 fn as_ref(&self) -> &str {
91 &self.name
92 }
93}
94
95impl std::borrow::Borrow<str> for Ident {
96 fn borrow(&self) -> &str {
97 &self.name
98 }
99}
100
101#[macro_export]
106macro_rules! format_ident {
107 ($fmt:expr) => {
108 $crate::Ident::new_str($fmt, $crate::span::Span::call_site())
109 };
110 ($fmt:expr, $($arg:tt)*) => {{
111 let s = std::fmt::format(std::format_args!($fmt, $($arg)*));
112 $crate::Ident::new(s, $crate::span::Span::call_site())
113 }};
114}
115
116pub fn is_java_identifier_start(ch: char) -> bool {
118 unicode_xid::UnicodeXID::is_xid_start(ch) || ch == '$' || ch == '_'
119}
120
121pub fn is_java_identifier_continue(ch: char) -> bool {
123 unicode_xid::UnicodeXID::is_xid_continue(ch) || ch == '$'
124}
125
126#[allow(dead_code)]
128pub fn is_valid_java_identifier(s: &str) -> bool {
129 if s.is_empty() {
130 return false;
131 }
132 let mut chars = s.chars();
133 if !is_java_identifier_start(chars.next().unwrap()) {
134 return false;
135 }
136 chars.all(is_java_identifier_continue)
137}
138
139#[allow(dead_code)]
142pub fn is_valid_type_identifier(s: &str) -> bool {
143 is_valid_java_identifier(s)
144 && !matches!(s, "record" | "sealed" | "var" | "yield" | "permits" | "_")
145}