1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
51
52
53
54
55
56
57
58
59
60
61
62
63
64
65
66
67
68
69
70
71
72
73
74
75
76
77
78
79
80
81
82
83
84
85
86
87
88
89
90
91
92
93
94
95
96
97
98
99
100
101
102
103
104
105
106
107
108
109
110
111
112
113
114
115
116
117
118
119
120
121
122
123
124
125
126
127
128
129
130
131
use crate::nodes::{Identifier, Token, Type};
/// Represents an identifier with an optional type annotation.
///
/// TypedIdentifier extends the basic Identifier to support Luau's type system, where
/// variables and parameters can have explicit type annotations. It stores the
/// identifier itself, the optional type, and the colon token for source preservation.
#[derive(Clone, Debug, PartialEq, Eq)]
pub struct TypedIdentifier {
name: Identifier,
r#type: Option<Type>,
token: Option<Token>,
}
impl TypedIdentifier {
/// Creates a new TypedIdentifier with the given name and no type.
pub fn new(name: impl Into<String>) -> Self {
Self {
name: Identifier::new(name.into()),
r#type: None,
token: None,
}
}
/// Sets the type for this identifier and returns the updated typed identifier.
pub fn with_type(mut self, type_value: impl Into<Type>) -> Self {
self.r#type = Some(type_value.into());
self
}
/// Attaches a colon token to this typed identifier and returns the updated identifier.
pub fn with_colon_token(mut self, token: Token) -> Self {
self.token = Some(token);
self
}
/// Sets the colon token for this typed identifier.
#[inline]
pub fn set_colon_token(&mut self, token: Token) {
self.token = Some(token);
}
/// Returns a reference to the colon token of this typed identifier, if any.
#[inline]
pub fn get_colon_token(&self) -> Option<&Token> {
self.token.as_ref()
}
/// Returns a reference to the underlying identifier.
#[inline]
pub fn get_identifier(&self) -> &Identifier {
&self.name
}
/// Returns a reference to the type of this identifier, if any.
#[inline]
pub fn get_type(&self) -> Option<&Type> {
self.r#type.as_ref()
}
/// Checks if this identifier has a type annotation.
#[inline]
pub fn has_type(&self) -> bool {
self.r#type.is_some()
}
/// Returns a mutable reference to the type of this identifier, if any.
#[inline]
pub fn mutate_type(&mut self) -> Option<&mut Type> {
self.r#type.as_mut()
}
/// Removes and returns the type annotation of this identifier, if any.
/// Also removes the colon token, if any.
pub fn remove_type(&mut self) -> Option<Type> {
self.token.take();
self.r#type.take()
}
super::impl_token_fns!(
target = [name]
iter = [token]
);
}
impl<IntoIdentifier: Into<Identifier>> From<IntoIdentifier> for TypedIdentifier {
fn from(name: IntoIdentifier) -> Self {
Self {
name: name.into(),
r#type: None,
token: None,
}
}
}
impl std::ops::Deref for TypedIdentifier {
type Target = Identifier;
fn deref(&self) -> &Self::Target {
&self.name
}
}
impl std::ops::DerefMut for TypedIdentifier {
fn deref_mut(&mut self) -> &mut Self::Target {
&mut self.name
}
}
#[cfg(test)]
mod test {
use crate::nodes::Position;
use super::*;
#[test]
fn set_name_replaces_the_token_content() {
let token = Token::new_with_line(7, 10, 1);
let mut typed_identifier = TypedIdentifier::from(Identifier::new("var").with_token(token));
typed_identifier.set_name("newVar");
assert_eq!(
typed_identifier.get_identifier().get_token().unwrap(),
&Token::from_position(Position::LineNumber {
line_number: 1,
content: "newVar".into(),
})
);
}
}