darklua_core/nodes/
function_call.rs

1use crate::nodes::{Arguments, Expression, Identifier, Prefix, Token};
2
3/// Tokens associated with a function call.
4#[derive(Clone, Debug, PartialEq, Eq)]
5pub struct FunctionCallTokens {
6    pub colon: Option<Token>,
7}
8
9impl FunctionCallTokens {
10    super::impl_token_fns!(iter = [colon]);
11}
12
13/// Represents a function call expression (e.g., `func()`, `obj:method()`, `a.b.c()`).
14#[derive(Clone, Debug, PartialEq, Eq)]
15pub struct FunctionCall {
16    prefix: Box<Prefix>,
17    arguments: Arguments,
18    method: Option<Identifier>,
19    tokens: Option<FunctionCallTokens>,
20}
21
22impl FunctionCall {
23    /// Creates a new function call with the given prefix, arguments, and optional method.
24    pub fn new(prefix: Prefix, arguments: Arguments, method: Option<Identifier>) -> Self {
25        Self {
26            prefix: Box::new(prefix),
27            arguments,
28            method,
29            tokens: None,
30        }
31    }
32
33    /// Creates a new function call with the given name.
34    pub fn from_name<T: Into<Identifier>>(name: T) -> Self {
35        Self {
36            prefix: Box::new(name.into().into()),
37            arguments: Arguments::default(),
38            method: None,
39            tokens: None,
40        }
41    }
42
43    /// Creates a new function call with the given prefix.
44    pub fn from_prefix<T: Into<Prefix>>(prefix: T) -> Self {
45        Self {
46            prefix: Box::new(prefix.into()),
47            arguments: Arguments::default(),
48            method: None,
49            tokens: None,
50        }
51    }
52
53    /// Sets the tokens for this function call.
54    pub fn with_tokens(mut self, tokens: FunctionCallTokens) -> Self {
55        self.tokens = Some(tokens);
56        self
57    }
58
59    /// Sets the tokens for this function call.
60    #[inline]
61    pub fn set_tokens(&mut self, tokens: FunctionCallTokens) {
62        self.tokens = Some(tokens);
63    }
64
65    /// Returns the tokens for this function call, if any.
66    #[inline]
67    pub fn get_tokens(&self) -> Option<&FunctionCallTokens> {
68        self.tokens.as_ref()
69    }
70
71    /// Sets the arguments for this function call.
72    pub fn with_arguments<A: Into<Arguments>>(mut self, arguments: A) -> Self {
73        self.arguments = arguments.into();
74        self
75    }
76
77    /// Adds an argument to this function call.
78    pub fn with_argument<T: Into<Expression>>(mut self, argument: T) -> Self {
79        self.arguments = self.arguments.with_argument(argument);
80        self
81    }
82
83    /// Sets the method name for this function call (for method calls like `obj:method()`).
84    pub fn with_method<IntoString: Into<Identifier>>(mut self, method: IntoString) -> Self {
85        self.method.replace(method.into());
86        self
87    }
88
89    /// Returns the arguments of this function call.
90    #[inline]
91    pub fn get_arguments(&self) -> &Arguments {
92        &self.arguments
93    }
94
95    /// Returns the method name, if this is a method call.
96    #[inline]
97    pub fn get_method(&self) -> Option<&Identifier> {
98        self.method.as_ref()
99    }
100
101    /// Returns if this call uses a method.
102    #[inline]
103    pub fn has_method(&self) -> bool {
104        self.method.is_some()
105    }
106
107    /// Returns the prefix (what is being called) of this function call.
108    #[inline]
109    pub fn get_prefix(&self) -> &Prefix {
110        &self.prefix
111    }
112
113    /// Removes and returns the method name, if any.
114    #[inline]
115    pub fn take_method(&mut self) -> Option<Identifier> {
116        let method = self.method.take();
117        if let Some(tokens) = self.tokens.as_mut() {
118            tokens.colon = None;
119        }
120        method
121    }
122
123    /// Sets the arguments for this function call.
124    #[inline]
125    pub fn set_arguments(&mut self, arguments: Arguments) {
126        self.arguments = arguments;
127    }
128
129    /// Sets the method name for this function call.
130    #[inline]
131    pub fn set_method(&mut self, method: Identifier) {
132        self.method.replace(method);
133    }
134
135    /// Returns a mutable reference to the arguments.
136    #[inline]
137    pub fn mutate_arguments(&mut self) -> &mut Arguments {
138        &mut self.arguments
139    }
140
141    /// Returns a mutable reference to the prefix.
142    #[inline]
143    pub fn mutate_prefix(&mut self) -> &mut Prefix {
144        &mut self.prefix
145    }
146
147    /// Returns a mutable reference to the first token of this function call,
148    /// creating it if missing.
149    pub fn mutate_first_token(&mut self) -> &mut Token {
150        self.prefix.mutate_first_token()
151    }
152
153    /// Returns a mutable reference to the last token of this function call,
154    /// creating it if missing.
155    pub fn mutate_last_token(&mut self) -> &mut Token {
156        self.arguments.mutate_last_token()
157    }
158
159    super::impl_token_fns!(iter = [tokens, method]);
160}
161
162#[cfg(test)]
163mod tests {
164    use super::*;
165    use crate::{nodes::Statement, Parser};
166
167    fn parse_call(code: &str) -> FunctionCall {
168        let parser = Parser::default().preserve_tokens();
169        let block = parser.parse(code).expect("code should parse");
170        if let Some(statement) = block.first_statement() {
171            if let Statement::Call(call) = statement {
172                return call.clone();
173            }
174        }
175        panic!("failed to parse call from: {}", code);
176    }
177
178    #[test]
179    fn test_take_method_removes_colon_token() {
180        let mut call = parse_call("obj:method()");
181
182        assert!(call.get_tokens().unwrap().colon.is_some());
183        call.take_method();
184        assert!(call.get_tokens().unwrap().colon.is_none());
185    }
186}