1use std::hash::Hash;
2
3use serde::{de::Visitor, Deserialize, Serialize};
4
5use crate::{
6 interning::INTERNER,
7 location_info::{Loc, WithLocation},
8};
9
10#[derive(PartialEq, Debug, Clone, Serialize, Deserialize)]
11pub enum Visibility {
12 Implicit,
13 Public,
14 AtLib,
15 AtSelf,
16 AtSuper,
17 AtSuperSuper,
22}
23
24#[derive(Debug, Clone, Copy, Eq)]
25#[repr(transparent)]
26pub struct Identifier(&'static str);
27
28impl Identifier {
29 pub fn intern(ident: &str) -> Self {
30 Self(INTERNER.intern(ident))
31 }
32
33 pub fn as_str(&self) -> &'static str {
34 self.0
35 }
36}
37
38impl std::fmt::Display for Identifier {
39 fn fmt(&self, f: &mut std::fmt::Formatter<'_>) -> std::fmt::Result {
40 write!(f, "{}", self.0)
41 }
42}
43
44impl PartialEq for Identifier {
45 fn eq(&self, other: &Self) -> bool {
46 ::core::ptr::eq(self.0, other.0)
47 }
48}
49
50impl std::hash::Hash for Identifier {
51 fn hash<H: std::hash::Hasher>(&self, state: &mut H) {
52 self.0.as_ptr().hash(state);
53 }
54}
55
56impl Serialize for Identifier {
57 fn serialize<S>(&self, serializer: S) -> Result<S::Ok, S::Error>
58 where
59 S: serde::Serializer,
60 {
61 serializer.serialize_str(self.0)
62 }
63}
64
65impl<'de> Deserialize<'de> for Identifier {
66 fn deserialize<D>(deserializer: D) -> Result<Self, D::Error>
67 where
68 D: serde::Deserializer<'de>,
69 {
70 struct IdentVisitor;
71 impl<'de> Visitor<'de> for IdentVisitor {
72 type Value = Identifier;
73
74 fn expecting(&self, formatter: &mut std::fmt::Formatter) -> std::fmt::Result {
75 formatter.write_str("Identifier")
76 }
77
78 fn visit_str<E>(self, v: &str) -> Result<Self::Value, E>
79 where
80 E: serde::de::Error,
81 {
82 Ok(Identifier::intern(v))
83 }
84 }
85
86 deserializer.deserialize_str(IdentVisitor)
87 }
88}
89
90#[derive(Debug)]
91pub enum PathPrefix {
92 FromLib,
93 FromSelf,
94 FromSuper(usize),
95 None,
96}
97
98#[derive(PartialEq, Debug, Clone, Eq, Hash, Serialize, Deserialize)]
99pub enum PathSegment {
100 Named(Loc<Identifier>),
101 Impl(u64),
102 IfT,
103 IfF,
104}
105
106impl PathSegment {
107 pub fn is_named(&self) -> bool {
108 match self {
109 PathSegment::Named(_) => true,
110 PathSegment::Impl(_) | PathSegment::IfT | PathSegment::IfF => false,
111 }
112 }
113
114 pub fn to_named_str(&self) -> Option<&str> {
115 match self {
116 PathSegment::Named(s) => Some(s.0),
117 PathSegment::Impl(_) | PathSegment::IfT | PathSegment::IfF => None,
118 }
119 }
120
121 pub fn loc(&self) -> Loc<()> {
122 match self {
123 PathSegment::Named(ident) => ident.loc(),
124 PathSegment::Impl(_) | PathSegment::IfT | PathSegment::IfF => ().nowhere(),
125 }
126 }
127
128 pub fn unwrap_named(&self) -> &Loc<Identifier> {
129 match self {
130 PathSegment::Named(ident) => ident,
131 PathSegment::Impl(_) | PathSegment::IfT | PathSegment::IfF => {
132 panic!("called `PathSegment::unwrap_named()` on a generated path segment")
133 }
134 }
135 }
136}
137
138impl std::fmt::Display for PathSegment {
139 fn fmt(&self, f: &mut std::fmt::Formatter<'_>) -> std::fmt::Result {
140 match self {
141 PathSegment::Named(ident) => write!(f, "{}", ident),
142 PathSegment::Impl(n) => write!(f, "impl#{n}"),
143 PathSegment::IfT => write!(f, "if#true"),
144 PathSegment::IfF => write!(f, "if#false"),
145 }
146 }
147}
148
149#[derive(PartialEq, Debug, Clone, Eq, Hash, Serialize, Deserialize)]
150pub struct Path(pub Vec<PathSegment>);
151
152impl Path {
153 pub fn to_strings(&self) -> Vec<String> {
154 self.0.iter().map(PathSegment::to_string).collect()
155 }
156
157 pub fn to_named_strs(&self) -> Vec<Option<&str>> {
158 self.0.iter().map(PathSegment::to_named_str).collect()
159 }
160
161 pub fn from_strs(elems: &[&str]) -> Self {
163 Path(
164 elems
165 .iter()
166 .map(|x| PathSegment::Named(Identifier::intern(x).nowhere()))
167 .collect(),
168 )
169 }
170
171 pub fn from_idents(elems: &[&Loc<Identifier>]) -> Self {
173 Path(
174 elems
175 .iter()
176 .map(|x| PathSegment::Named((*x).clone()))
177 .collect(),
178 )
179 }
180
181 pub fn ident(ident: Loc<Identifier>) -> Self {
182 Self(vec![PathSegment::Named(ident)])
183 }
184
185 pub fn ident_with_loc(ident: Loc<Identifier>) -> Loc<Self> {
186 let loc = ident.loc();
187 Self::ident(ident).at_loc(&loc)
188 }
189
190 pub fn push_segment(&self, segment: PathSegment) -> Path {
191 let mut result = self.clone();
192 result.0.push(segment);
193 result
194 }
195
196 pub fn push_ident(&self, ident: Loc<Identifier>) -> Path {
197 let mut result = self.clone();
198 result.0.push(PathSegment::Named(ident));
199 result
200 }
201
202 pub fn pop(&self) -> Self {
203 let mut result = self.clone();
204 result.0.pop().expect("Failed to pop identifier from path");
205 result
206 }
207
208 pub fn join(&self, other: Path) -> Path {
209 let mut result = self.clone();
210 for segment in other.0 {
211 result.0.push(segment);
212 }
213 result
214 }
215
216 pub fn extract_prefix(&self) -> (PathPrefix, Path) {
217 let Some(segment) = self.0.first() else {
218 return (PathPrefix::None, self.clone());
219 };
220
221 let (prefix, count) = match segment.to_named_str() {
222 Some("lib") => (PathPrefix::FromLib, 1),
223 Some("self") => (PathPrefix::FromSelf, 1),
224 Some("super") => {
225 let levels = self
226 .0
227 .iter()
228 .take_while(|s| s.to_named_str() == Some("super"))
229 .count();
230 (PathPrefix::FromSuper(levels), levels)
231 }
232 _ => (PathPrefix::None, 0),
233 };
234
235 let path_without_prefix = Path(Vec::from(&self.0[count..]));
236 (prefix, path_without_prefix)
237 }
238
239 pub fn tail(&self) -> PathSegment {
241 self.0
242 .last()
243 .expect("Tried getting tail of empty path")
244 .clone()
245 }
246
247 pub fn prelude(&self) -> Path {
249 Self(self.0[0..self.0.len() - 1].to_owned())
250 }
251
252 pub fn starts_with(&self, other: &Path) -> bool {
253 self.0.iter().zip(&other.0).all(|(l, r)| l == r)
254 }
255}
256
257impl std::fmt::Display for Path {
258 fn fmt(&self, f: &mut std::fmt::Formatter<'_>) -> std::fmt::Result {
259 write!(f, "{}", self.to_strings().join("::"))
260 }
261}
262
263#[derive(Clone, Serialize, Deserialize)]
269pub struct NameID(pub u64, pub Path);
270
271impl std::cmp::PartialEq for NameID {
272 fn eq(&self, other: &Self) -> bool {
273 self.0 == other.0
274 }
275}
276
277impl std::cmp::Eq for NameID {}
278
279impl std::cmp::PartialOrd for NameID {
280 fn partial_cmp(&self, other: &Self) -> Option<std::cmp::Ordering> {
281 Some(self.0.cmp(&other.0))
282 }
283}
284
285impl std::cmp::Ord for NameID {
286 fn cmp(&self, other: &Self) -> std::cmp::Ordering {
287 self.0.cmp(&other.0)
288 }
289}
290
291impl std::hash::Hash for NameID {
292 fn hash<H: std::hash::Hasher>(&self, state: &mut H) {
293 self.0.hash(state);
294 }
295}
296
297impl std::fmt::Debug for NameID {
298 fn fmt(&self, f: &mut std::fmt::Formatter<'_>) -> std::fmt::Result {
299 write!(f, "{}#{}", self.1, self.0)
300 }
301}
302impl std::fmt::Display for NameID {
303 fn fmt(&self, f: &mut std::fmt::Formatter<'_>) -> std::fmt::Result {
304 write!(f, "{}", self.1)
305 }
306}
307
308pub mod testutil {
309 use super::*;
310 pub fn name_id(id: u64, name: &str) -> Loc<NameID> {
311 NameID(id, Path::from_strs(&[name])).nowhere()
312 }
313
314 pub fn name_id_p(id: u64, name: &[&str]) -> Loc<NameID> {
316 NameID(id, Path::from_strs(name)).nowhere()
317 }
318}