Skip to main content

mago_syntax/ast/ast/
identifier.rs

1use serde::Serialize;
2use strum::Display;
3
4use mago_span::HasSpan;
5use mago_span::Span;
6
7/// Represents an identifier.
8///
9/// An identifier can be a local, qualified, or fully qualified identifier.
10#[derive(Debug, Clone, Copy, Eq, PartialEq, Hash, Serialize, PartialOrd, Ord, Display)]
11#[serde(tag = "type", content = "value")]
12#[repr(u8)]
13pub enum Identifier<'arena> {
14    Local(LocalIdentifier<'arena>),
15    Qualified(QualifiedIdentifier<'arena>),
16    FullyQualified(FullyQualifiedIdentifier<'arena>),
17}
18
19/// Represents a local, unqualified identifier.
20///
21/// Example: `foo`, `Bar`, `BAZ`
22#[derive(Debug, Clone, Copy, Eq, PartialEq, Hash, Serialize, PartialOrd, Ord)]
23pub struct LocalIdentifier<'arena> {
24    pub span: Span,
25    pub value: &'arena str,
26}
27
28/// Represents a qualified identifier.
29///
30/// Example: `Foo\bar`, `Bar\Baz`, `Baz\QUX`
31#[derive(Debug, Clone, Copy, Eq, PartialEq, Hash, Serialize, PartialOrd, Ord)]
32pub struct QualifiedIdentifier<'arena> {
33    pub span: Span,
34    pub value: &'arena str,
35}
36
37/// Represents a fully qualified identifier.
38///
39/// Example: `\Foo\bar`, `\Bar\Baz`, `\Baz\QUX`
40#[derive(Debug, Clone, Copy, Eq, PartialEq, Hash, Serialize, PartialOrd, Ord)]
41pub struct FullyQualifiedIdentifier<'arena> {
42    pub span: Span,
43    pub value: &'arena str,
44}
45
46impl<'arena> Identifier<'arena> {
47    #[inline]
48    #[must_use]
49    pub const fn is_local(&self) -> bool {
50        matches!(self, Identifier::Local(_))
51    }
52
53    #[inline]
54    #[must_use]
55    pub const fn is_qualified(&self) -> bool {
56        matches!(self, Identifier::Qualified(_))
57    }
58
59    #[inline]
60    #[must_use]
61    pub const fn is_fully_qualified(&self) -> bool {
62        matches!(self, Identifier::FullyQualified(_))
63    }
64
65    #[inline]
66    #[must_use]
67    pub const fn value(&self) -> &'arena str {
68        match &self {
69            Identifier::Local(local_identifier) => local_identifier.value,
70            Identifier::Qualified(qualified_identifier) => qualified_identifier.value,
71            Identifier::FullyQualified(fully_qualified_identifier) => fully_qualified_identifier.value,
72        }
73    }
74
75    #[inline]
76    #[must_use]
77    pub fn last_segment(&self) -> &'arena str {
78        let value = self.value();
79
80        match value.rfind('\\') {
81            Some(pos) => &value[pos + 1..],
82            None => value,
83        }
84    }
85}
86
87impl HasSpan for Identifier<'_> {
88    fn span(&self) -> Span {
89        match self {
90            Identifier::Local(local) => local.span(),
91            Identifier::Qualified(qualified) => qualified.span(),
92            Identifier::FullyQualified(fully_qualified) => fully_qualified.span(),
93        }
94    }
95}
96
97impl HasSpan for LocalIdentifier<'_> {
98    fn span(&self) -> Span {
99        self.span
100    }
101}
102
103impl HasSpan for QualifiedIdentifier<'_> {
104    fn span(&self) -> Span {
105        self.span
106    }
107}
108
109impl HasSpan for FullyQualifiedIdentifier<'_> {
110    fn span(&self) -> Span {
111        self.span
112    }
113}