1use std::borrow::Cow;
2
3#[cfg(feature = "serde")]
4use serde::Serialize;
5
6use crate::Span;
7
8use super::ArenaVec;
9
10#[derive(Clone, Copy)]
23pub struct Ident<'src> {
24 name: &'src str,
25 pub span: Span,
27}
28
29impl<'src> Ident<'src> {
30 #[inline]
33 pub fn new(name: &'src str, span: Span) -> Self {
34 debug_assert!(!name.is_empty(), "Ident::new() called with empty name");
35 Self { name, span }
36 }
37
38 #[inline]
40 pub const fn error(span: Span) -> Self {
41 Self { name: "", span }
42 }
43
44 #[inline]
46 pub fn as_str(&self) -> Option<&'src str> {
47 if self.name.is_empty() {
48 None
49 } else {
50 Some(self.name)
51 }
52 }
53
54 #[inline]
56 pub fn is_error(&self) -> bool {
57 self.name.is_empty()
58 }
59
60 #[inline]
63 pub fn or_error(&self) -> &'src str {
64 if self.name.is_empty() {
65 "<error>"
66 } else {
67 self.name
68 }
69 }
70}
71
72impl<'src> std::fmt::Debug for Ident<'src> {
73 fn fmt(&self, f: &mut std::fmt::Formatter<'_>) -> std::fmt::Result {
74 if self.name.is_empty() {
75 write!(f, "Ident::error({:?})", self.span)
76 } else {
77 write!(f, "Ident({:?}, {:?})", self.name, self.span)
78 }
79 }
80}
81
82impl<'src> std::fmt::Display for Ident<'src> {
83 fn fmt(&self, f: &mut std::fmt::Formatter<'_>) -> std::fmt::Result {
84 f.write_str(self.or_error())
85 }
86}
87
88#[cfg(feature = "serde")]
89impl<'src> serde::Serialize for Ident<'src> {
90 fn serialize<S: serde::Serializer>(&self, s: S) -> Result<S::Ok, S::Error> {
91 use serde::ser::SerializeStruct;
92 if self.name.is_empty() {
93 return s.serialize_none();
94 }
95 let mut st = s.serialize_struct("Ident", 2)?;
96 st.serialize_field("name", self.name)?;
97 st.serialize_field("span", &self.span)?;
98 st.end()
99 }
100}
101
102impl<'src> PartialEq<&str> for Ident<'src> {
103 fn eq(&self, other: &&str) -> bool {
104 !self.name.is_empty() && self.name == *other
105 }
106}
107
108#[non_exhaustive]
121pub enum Name<'arena, 'src> {
122 Simple {
125 value: &'src str,
127 span: Span,
129 },
130 Complex {
132 parts: ArenaVec<'arena, &'src str>,
134 kind: NameKind,
136 span: Span,
138 },
139 Error {
143 span: Span,
145 },
146}
147
148impl<'arena, 'src> Name<'arena, 'src> {
149 #[inline]
151 pub fn span(&self) -> Span {
152 match self {
153 Self::Simple { span, .. } | Self::Complex { span, .. } | Self::Error { span } => *span,
154 }
155 }
156
157 #[inline]
159 pub fn kind(&self) -> NameKind {
160 match self {
161 Self::Simple { .. } => NameKind::Unqualified,
162 Self::Complex { kind, .. } => *kind,
163 Self::Error { .. } => NameKind::Error,
164 }
165 }
166
167 #[inline]
176 pub fn src_repr(&self, src: &'src str) -> &'src str {
177 match self {
178 Self::Simple { value, .. } => value,
179 Self::Complex { span, .. } => &src[span.start as usize..span.end as usize],
180 Self::Error { .. } => "",
181 }
182 }
183
184 #[inline]
188 pub fn to_string_repr(&self) -> Cow<'src, str> {
189 match self {
190 Self::Complex {
191 parts,
192 kind: NameKind::FullyQualified,
193 ..
194 } => Cow::Owned(fully_qualified(parts)),
195 _ => self.join_parts(),
196 }
197 }
198
199 #[inline]
206 pub fn join_parts(&self) -> Cow<'src, str> {
207 match self {
208 Self::Simple { value, .. } => Cow::Borrowed(value),
209 Self::Complex { parts, .. } if parts.len() == 1 => Cow::Borrowed(parts[0]),
210 Self::Complex { parts, .. } => Cow::Owned(parts.join("\\")),
211 Self::Error { .. } => Cow::Borrowed(""),
212 }
213 }
214
215 pub fn join_parts_in(&self, src: &'src str) -> Cow<'src, str> {
223 let Self::Complex { parts, .. } = self else {
224 return self.join_parts();
225 };
226 if parts.len() == 1 {
227 return Cow::Borrowed(parts[0]);
228 }
229 match contiguous_in(parts, src) {
230 Some(joined) => Cow::Borrowed(joined),
231 None => Cow::Owned(parts.join("\\")),
232 }
233 }
234
235 #[inline]
238 pub fn parts_slice(&self) -> &[&'src str] {
239 match self {
240 Self::Simple { value, .. } => std::slice::from_ref(value),
241 Self::Complex { parts, .. } => parts,
242 Self::Error { .. } => &[],
243 }
244 }
245}
246
247pub(crate) fn fully_qualified<S: AsRef<str>>(parts: &[S]) -> String {
249 let mut s =
250 String::with_capacity(parts.iter().map(|p| p.as_ref().len() + 1).sum::<usize>() + 1);
251 s.push('\\');
252 for (i, part) in parts.iter().enumerate() {
253 if i > 0 {
254 s.push('\\');
255 }
256 s.push_str(part.as_ref());
257 }
258 s
259}
260
261fn contiguous_in<'src>(parts: &[&'src str], src: &'src str) -> Option<&'src str> {
263 let base = src.as_ptr() as usize;
264 let start = (parts.first()?.as_ptr() as usize).checked_sub(base)?;
265 let len = parts.iter().map(|p| p.len()).sum::<usize>() + parts.len() - 1;
266 let joined = src.get(start..start.checked_add(len)?)?;
267 let bytes = joined.as_bytes();
268 let mut offset = 0;
269 for (i, part) in parts.iter().enumerate() {
270 if part.as_ptr() as usize != base + start + offset {
272 return None;
273 }
274 offset += part.len();
275 if i + 1 < parts.len() {
276 if bytes[offset] != b'\\' {
277 return None;
278 }
279 offset += 1;
280 }
281 }
282 Some(joined)
283}
284
285impl<'arena, 'src> std::fmt::Debug for Name<'arena, 'src> {
286 fn fmt(&self, f: &mut std::fmt::Formatter<'_>) -> std::fmt::Result {
287 match self {
288 Self::Simple { value, span } => f
289 .debug_struct("Name")
290 .field("parts", &std::slice::from_ref(value))
291 .field("kind", &NameKind::Unqualified)
292 .field("span", span)
293 .finish(),
294 Self::Complex { parts, kind, span } => f
295 .debug_struct("Name")
296 .field("parts", parts)
297 .field("kind", kind)
298 .field("span", span)
299 .finish(),
300 Self::Error { span } => {
301 let empty: [&str; 0] = [];
302 f.debug_struct("Name")
303 .field("parts", &empty)
304 .field("kind", &NameKind::Error)
305 .field("span", span)
306 .finish()
307 }
308 }
309 }
310}
311
312#[cfg(feature = "serde")]
313impl<'arena, 'src> serde::Serialize for Name<'arena, 'src> {
314 fn serialize<S: serde::Serializer>(&self, s: S) -> Result<S::Ok, S::Error> {
315 use serde::ser::SerializeStruct;
316 let mut st = s.serialize_struct("Name", 3)?;
317 match self {
318 Self::Simple { value, span } => {
319 st.serialize_field("parts", std::slice::from_ref(value))?;
320 st.serialize_field("kind", &NameKind::Unqualified)?;
321 st.serialize_field("span", span)?;
322 }
323 Self::Complex { parts, kind, span } => {
324 st.serialize_field("parts", parts)?;
325 st.serialize_field("kind", kind)?;
326 st.serialize_field("span", span)?;
327 }
328 Self::Error { span } => {
329 let empty: [&str; 0] = [];
330 st.serialize_field("parts", &empty[..])?;
331 st.serialize_field("kind", &NameKind::Error)?;
332 st.serialize_field("span", span)?;
333 }
334 }
335 st.end()
336 }
337}
338
339#[derive(Debug, Clone, Copy, PartialEq, Eq)]
341#[cfg_attr(feature = "serde", derive(Serialize))]
342#[non_exhaustive]
343pub enum NameKind {
344 Unqualified,
346 Qualified,
348 FullyQualified,
350 Relative,
352 Error,
354}
355
356#[repr(u8)]
359#[derive(Debug, Clone, Copy, PartialEq, Eq)]
360#[cfg_attr(feature = "serde", derive(Serialize))]
361#[non_exhaustive]
362pub enum BuiltinType {
363 Int,
365 Float,
367 String,
369 Bool,
371 Void,
373 Never,
375 Mixed,
377 Object,
379 Iterable,
381 Callable,
383 Array,
385 Self_,
387 Parent_,
389 Static,
391 Null,
393 True,
395 False,
397}
398
399impl BuiltinType {
400 #[inline]
402 pub fn as_str(self) -> &'static str {
403 match self {
404 Self::Int => "int",
405 Self::Float => "float",
406 Self::String => "string",
407 Self::Bool => "bool",
408 Self::Void => "void",
409 Self::Never => "never",
410 Self::Mixed => "mixed",
411 Self::Object => "object",
412 Self::Iterable => "iterable",
413 Self::Callable => "callable",
414 Self::Array => "array",
415 Self::Self_ => "self",
416 Self::Parent_ => "parent",
417 Self::Static => "static",
418 Self::Null => "null",
419 Self::True => "true",
420 Self::False => "false",
421 }
422 }
423}
424
425#[derive(Debug)]
427#[cfg_attr(feature = "serde", derive(Serialize))]
428pub struct TypeHint<'arena, 'src> {
429 pub kind: TypeHintKind<'arena, 'src>,
431 pub span: Span,
433}
434
435#[derive(Debug)]
443#[non_exhaustive]
444pub enum TypeHintKind<'arena, 'src> {
445 Named(Name<'arena, 'src>),
447 Keyword(BuiltinType, Span),
449 Nullable(&'arena TypeHint<'arena, 'src>),
451 Union(ArenaVec<'arena, TypeHint<'arena, 'src>>),
453 Intersection(ArenaVec<'arena, TypeHint<'arena, 'src>>),
455}
456
457#[cfg(feature = "serde")]
458impl<'arena, 'src> serde::Serialize for TypeHintKind<'arena, 'src> {
459 fn serialize<S: serde::Serializer>(&self, s: S) -> Result<S::Ok, S::Error> {
460 match self {
461 Self::Named(name) => s.serialize_newtype_variant("TypeHintKind", 0, "Named", name),
463 Self::Nullable(inner) => {
464 s.serialize_newtype_variant("TypeHintKind", 2, "Nullable", inner)
465 }
466 Self::Union(types) => s.serialize_newtype_variant("TypeHintKind", 3, "Union", types),
467 Self::Intersection(types) => {
468 s.serialize_newtype_variant("TypeHintKind", 4, "Intersection", types)
469 }
470 Self::Keyword(builtin, span) => {
473 struct BuiltinNameRepr<'a>(&'a BuiltinType, &'a Span);
474 impl serde::Serialize for BuiltinNameRepr<'_> {
475 fn serialize<S: serde::Serializer>(&self, s: S) -> Result<S::Ok, S::Error> {
476 use serde::ser::SerializeStruct;
477 let mut st = s.serialize_struct("Name", 3)?;
478 st.serialize_field("parts", &[self.0.as_str()])?;
479 st.serialize_field("kind", &NameKind::Unqualified)?;
480 st.serialize_field("span", self.1)?;
481 st.end()
482 }
483 }
484 s.serialize_newtype_variant(
485 "TypeHintKind",
486 0,
487 "Named",
488 &BuiltinNameRepr(builtin, span),
489 )
490 }
491 }
492 }
493}