darklua_core/nodes/
function_call.rs1use crate::nodes::{
2 Arguments, Expression, Identifier, Prefix, Token, Type, TypeInstantiationTokens,
3};
4
5#[derive(Clone, Debug, PartialEq, Eq)]
7pub struct FunctionCallTokens {
8 pub colon: Option<Token>,
9 pub type_instantiation_tokens: Option<TypeInstantiationTokens>,
10}
11
12impl FunctionCallTokens {
13 super::impl_token_fns!(iter = [colon, type_instantiation_tokens]);
14}
15
16#[derive(Clone, Debug, PartialEq, Eq)]
18pub struct FunctionCall {
19 prefix: Box<Prefix>,
20 arguments: Arguments,
21 method: Option<Method>,
22 tokens: Option<FunctionCallTokens>,
23}
24
25#[derive(Clone, Debug, PartialEq, Eq)]
26struct Method {
27 name: Identifier,
28 types: Option<Vec<Type>>,
29}
30
31impl Method {
32 super::impl_token_fns!(target = [name]);
33}
34
35impl FunctionCall {
36 pub fn new(prefix: Prefix, arguments: Arguments, method: Option<Identifier>) -> Self {
38 Self {
39 prefix: Box::new(prefix),
40 arguments,
41 method: method.map(|name| Method { name, types: None }),
42 tokens: None,
43 }
44 }
45
46 pub fn from_name<T: Into<Identifier>>(name: T) -> Self {
48 Self {
49 prefix: Box::new(name.into().into()),
50 arguments: Arguments::default(),
51 method: None,
52 tokens: None,
53 }
54 }
55
56 pub fn from_prefix<T: Into<Prefix>>(prefix: T) -> Self {
58 Self {
59 prefix: Box::new(prefix.into()),
60 arguments: Arguments::default(),
61 method: None,
62 tokens: None,
63 }
64 }
65
66 pub fn with_tokens(mut self, tokens: FunctionCallTokens) -> Self {
68 self.tokens = Some(tokens);
69 self
70 }
71
72 #[inline]
74 pub fn set_tokens(&mut self, tokens: FunctionCallTokens) {
75 self.tokens = Some(tokens);
76 }
77
78 #[inline]
80 pub fn get_tokens(&self) -> Option<&FunctionCallTokens> {
81 self.tokens.as_ref()
82 }
83
84 pub fn with_arguments<A: Into<Arguments>>(mut self, arguments: A) -> Self {
86 self.arguments = arguments.into();
87 self
88 }
89
90 pub fn with_argument<T: Into<Expression>>(mut self, argument: T) -> Self {
92 self.arguments = self.arguments.with_argument(argument);
93 self
94 }
95
96 pub fn with_method(mut self, method: impl Into<Identifier>) -> Self {
98 self.set_method(method.into());
99 self
100 }
101
102 pub fn with_type_instantiation_method(
104 mut self,
105 method: impl Into<Identifier>,
106 types: Vec<Type>,
107 ) -> Self {
108 self.set_type_instantiation_method(method.into(), types);
109 self
110 }
111
112 pub fn set_type_instantiation_method(
114 &mut self,
115 method: impl Into<Identifier>,
116 types: Vec<Type>,
117 ) {
118 self.method = Some(Method {
119 name: method.into(),
120 types: Some(types),
121 });
122 }
123
124 pub fn remove_type_instantiation_from_method(&mut self) -> bool {
126 self.method
127 .as_mut()
128 .and_then(|method| method.types.take())
129 .is_some()
130 }
131
132 #[inline]
134 pub fn get_arguments(&self) -> &Arguments {
135 &self.arguments
136 }
137
138 #[inline]
140 pub fn get_method(&self) -> Option<&Identifier> {
141 self.method.as_ref().map(|method| &method.name)
142 }
143
144 pub fn get_method_type_instantiation(&self) -> impl Iterator<Item = &Type> {
146 self.method
147 .iter()
148 .flat_map(|method| method.types.iter().flatten())
149 }
150
151 pub fn has_method_type_instantiation(&self) -> bool {
153 self.method
154 .as_ref()
155 .map(|method| method.types.is_some())
156 .unwrap_or_default()
157 }
158
159 #[inline]
161 pub fn has_method(&self) -> bool {
162 self.method.is_some()
163 }
164
165 #[inline]
167 pub fn get_prefix(&self) -> &Prefix {
168 &self.prefix
169 }
170
171 #[inline]
173 pub fn take_method(&mut self) -> Option<Identifier> {
174 let method = self.method.take();
175 if let Some(tokens) = self.tokens.as_mut() {
176 tokens.colon = None;
177 }
178 method.map(|method| method.name)
179 }
180
181 #[inline]
183 pub fn set_arguments(&mut self, arguments: Arguments) {
184 self.arguments = arguments;
185 }
186
187 #[inline]
189 pub fn set_method(&mut self, method: Identifier) {
190 if let Some(current_method) = &mut self.method {
191 current_method.name = method;
192 } else {
193 self.method = Some(Method {
194 name: method,
195 types: None,
196 });
197 }
198 }
199
200 #[inline]
202 pub fn mutate_arguments(&mut self) -> &mut Arguments {
203 &mut self.arguments
204 }
205
206 #[inline]
208 pub fn mutate_prefix(&mut self) -> &mut Prefix {
209 &mut self.prefix
210 }
211
212 pub fn mutate_first_token(&mut self) -> &mut Token {
215 self.prefix.mutate_first_token()
216 }
217
218 pub fn mutate_last_token(&mut self) -> &mut Token {
221 self.arguments.mutate_last_token()
222 }
223
224 super::impl_token_fns!(iter = [tokens, method]);
225}
226
227#[cfg(test)]
228mod tests {
229 use super::*;
230 use crate::{nodes::Statement, Parser};
231
232 fn parse_call(code: &str) -> FunctionCall {
233 let parser = Parser::default().preserve_tokens();
234 let block = parser.parse(code).expect("code should parse");
235 if let Some(Statement::Call(call)) = block.first_statement() {
236 return call.clone();
237 }
238 panic!("failed to parse call from: {}", code);
239 }
240
241 #[test]
242 fn test_take_method_removes_colon_token() {
243 let mut call = parse_call("obj:method()");
244
245 assert!(call.get_tokens().unwrap().colon.is_some());
246 call.take_method();
247 assert!(call.get_tokens().unwrap().colon.is_none());
248 }
249}