darklua_core/nodes/
identifier.rs

1use crate::nodes::Token;
2
3use super::{Type, TypedIdentifier};
4
5/// Represents an identifier (variable name).
6#[derive(Clone, Debug, PartialEq, Eq)]
7pub struct Identifier {
8    name: String,
9    token: Option<Token>,
10}
11
12impl Identifier {
13    /// Creates a new identifier with the given name.
14    pub fn new<S: Into<String>>(name: S) -> Self {
15        Self {
16            name: name.into(),
17            token: None,
18        }
19    }
20
21    /// Converts this identifier into a typed identifier.
22    pub fn with_type(self, r#type: impl Into<Type>) -> TypedIdentifier {
23        TypedIdentifier::from(self).with_type(r#type.into())
24    }
25
26    /// Attaches token information to this identifier.
27    pub fn with_token(mut self, token: Token) -> Self {
28        self.token = Some(token);
29        self
30    }
31
32    /// Sets the token information for this identifier.
33    #[inline]
34    pub fn set_token(&mut self, token: Token) {
35        self.token = Some(token);
36    }
37
38    /// Returns a reference to the token information attached to this identifier, if any.
39    #[inline]
40    pub fn get_token(&self) -> Option<&Token> {
41        self.token.as_ref()
42    }
43
44    /// Returns a mutable reference to the token information attached to this identifier, if any.
45    #[inline]
46    pub fn mutate_token(&mut self) -> Option<&mut Token> {
47        self.token.as_mut()
48    }
49
50    /// Returns a mutable reference to the token information attached to this identifier.
51    /// If no token is attached, it creates one from the name.
52    pub(crate) fn mutate_or_insert_token(&mut self) -> &mut Token {
53        if self.token.is_none() {
54            let name = self.get_name().to_owned();
55            self.token = Some(Token::from_content(name));
56        }
57        self.token.as_mut().unwrap()
58    }
59
60    /// Returns a reference to the name of this identifier.
61    #[inline]
62    pub fn get_name(&self) -> &String {
63        &self.name
64    }
65
66    /// Returns a mutable reference to the name of this identifier.
67    #[inline]
68    pub fn mutate_name(&mut self) -> &mut String {
69        &mut self.name
70    }
71
72    /// Changes the name of this identifier.
73    ///
74    /// If token information is attached, it's updated to reflect the new name.
75    #[inline]
76    pub fn set_name<IntoString: Into<String>>(&mut self, name: IntoString) {
77        let name = name.into();
78        if let Some(token) = &mut self.token {
79            token.replace_with_content(name.clone());
80        }
81        self.name = name;
82    }
83
84    /// Consumes the identifier and returns just the name as a String.
85    #[inline]
86    pub fn into_name(self) -> String {
87        self.name
88    }
89
90    super::impl_token_fns!(iter = [token]);
91}
92
93impl<IntoString: Into<String>> From<IntoString> for Identifier {
94    fn from(identifier: IntoString) -> Self {
95        Self {
96            name: identifier.into(),
97            token: None,
98        }
99    }
100}
101
102#[cfg(test)]
103mod test {
104    use crate::nodes::Position;
105
106    use super::*;
107
108    #[test]
109    fn set_name_replaces_the_token_content() {
110        let token = Token::new_with_line(7, 10, 1);
111        let mut identifier = Identifier::new("var").with_token(token);
112
113        identifier.set_name("newVar");
114
115        assert_eq!(
116            identifier.get_token().unwrap(),
117            &Token::from_position(Position::LineNumber {
118                line_number: 1,
119                content: "newVar".into(),
120            })
121        );
122    }
123}