1use std::{iter, mem};
2
3use crate::nodes::{Expression, StringExpression, TableExpression, Token};
4
5#[derive(Clone, Debug, PartialEq, Eq)]
7pub struct TupleArgumentsTokens {
8 pub opening_parenthese: Token,
9 pub closing_parenthese: Token,
10 pub commas: Vec<Token>,
11}
12
13impl TupleArgumentsTokens {
14 super::impl_token_fns!(
15 target = [opening_parenthese, closing_parenthese]
16 iter = [commas]
17 );
18}
19
20#[derive(Clone, Debug, Default, PartialEq, Eq)]
22pub struct TupleArguments {
23 values: Vec<Expression>,
24 tokens: Option<TupleArgumentsTokens>,
25}
26
27impl TupleArguments {
28 pub fn new(values: Vec<Expression>) -> Self {
30 Self {
31 values,
32 tokens: None,
33 }
34 }
35
36 #[inline]
38 pub fn to_expressions(self) -> Vec<Expression> {
39 self.values
40 }
41
42 pub fn with_tokens(mut self, tokens: TupleArgumentsTokens) -> Self {
44 self.tokens = Some(tokens);
45 self
46 }
47
48 #[inline]
50 pub fn set_tokens(&mut self, tokens: TupleArgumentsTokens) {
51 self.tokens = Some(tokens);
52 }
53
54 #[inline]
56 pub fn get_tokens(&self) -> Option<&TupleArgumentsTokens> {
57 self.tokens.as_ref()
58 }
59
60 pub fn with_argument<T: Into<Expression>>(mut self, argument: T) -> Self {
62 self.push(argument.into());
63 self
64 }
65
66 pub fn push(&mut self, argument: impl Into<Expression>) {
68 let argument = argument.into();
69 let initial_len = self.values.len();
70
71 self.values.push(argument);
72
73 if initial_len != 0 {
74 if let Some(tokens) = &mut self.tokens {
75 if tokens.commas.len() == initial_len - 1 {
76 tokens.commas.push(Token::from_content(","));
77 }
78 }
79 }
80 }
81
82 pub fn insert(&mut self, index: usize, argument: impl Into<Expression>) {
84 if index >= self.values.len() {
85 self.push(argument.into());
86 } else {
87 self.values.insert(index, argument.into());
88
89 if let Some(tokens) = &mut self.tokens {
90 if index <= tokens.commas.len() {
91 tokens.commas.insert(index, Token::from_content(","));
92 }
93 }
94 }
95 }
96
97 pub fn mutate_last_token(&mut self) -> &mut Token {
100 if self.get_tokens().is_none() {
101 self.set_tokens(TupleArgumentsTokens {
102 opening_parenthese: Token::from_content("("),
103 closing_parenthese: Token::from_content(")"),
104 commas: (0..self.len().saturating_sub(1))
105 .map(|_| Token::from_content(","))
106 .collect(),
107 });
108 }
109 &mut self.tokens.as_mut().unwrap().closing_parenthese
110 }
111
112 #[inline]
114 pub fn len(&self) -> usize {
115 self.values.len()
116 }
117
118 #[inline]
120 pub fn is_empty(&self) -> bool {
121 self.values.is_empty()
122 }
123
124 #[inline]
126 pub fn iter_values(&self) -> impl Iterator<Item = &Expression> {
127 self.values.iter()
128 }
129
130 #[inline]
132 pub fn iter_mut_values(&mut self) -> impl Iterator<Item = &mut Expression> {
133 self.values.iter_mut()
134 }
135
136 super::impl_token_fns!(iter = [tokens]);
137}
138
139impl From<Arguments> for TupleArguments {
140 fn from(arguments: Arguments) -> Self {
141 match arguments {
142 Arguments::Tuple(tuple) => tuple,
143 Arguments::String(string) => TupleArguments::default().with_argument(string),
144 Arguments::Table(table) => TupleArguments::default().with_argument(table),
145 }
146 }
147}
148
149impl iter::FromIterator<Expression> for TupleArguments {
150 fn from_iter<T: IntoIterator<Item = Expression>>(iter: T) -> Self {
151 Self {
152 values: iter.into_iter().collect(),
153 tokens: None,
154 }
155 }
156}
157
158#[derive(Clone, Debug, PartialEq, Eq)]
160pub enum Arguments {
161 Tuple(TupleArguments),
163 String(StringExpression),
165 Table(TableExpression),
167}
168
169impl Arguments {
170 #[inline]
172 pub fn len(&self) -> usize {
173 match self {
174 Self::Tuple(tuple) => tuple.len(),
175 Self::String(_) | Self::Table(_) => 1,
176 }
177 }
178
179 #[inline]
181 pub fn is_empty(&self) -> bool {
182 match self {
183 Self::Tuple(tuple) => tuple.is_empty(),
184 Self::String(_) | Self::Table(_) => false,
185 }
186 }
187
188 pub fn to_expressions(self) -> Vec<Expression> {
190 match self {
191 Self::Tuple(expressions) => expressions.to_expressions(),
192 Self::String(string) => vec![string.into()],
193 Self::Table(table) => vec![table.into()],
194 }
195 }
196
197 pub fn with_argument<T: Into<Expression>>(self, argument: T) -> Self {
199 TupleArguments::from(self).with_argument(argument).into()
200 }
201
202 pub fn push(&mut self, argument: impl Into<Expression>) {
204 let argument = argument.into();
205
206 let tuple_args = match self {
207 Arguments::Tuple(tuple) => {
208 tuple.push(argument);
209 return;
210 }
211 Arguments::String(value) => TupleArguments::default()
212 .with_argument(mem::replace(value, StringExpression::empty())),
213 Arguments::Table(value) => TupleArguments::default().with_argument(mem::take(value)),
214 };
215
216 *self = tuple_args.with_argument(argument).into();
217 }
218
219 pub fn insert(&mut self, index: usize, argument: impl Into<Expression>) {
221 let argument = argument.into();
222
223 let mut tuple_args = match self {
224 Arguments::Tuple(tuple) => {
225 tuple.insert(index, argument);
226 return;
227 }
228 Arguments::String(value) => {
229 let string = mem::replace(value, StringExpression::empty());
230 TupleArguments::default().with_argument(Expression::from(string))
231 }
232 Arguments::Table(value) => {
233 let table = mem::take(value);
234 TupleArguments::default().with_argument(Expression::from(table))
235 }
236 };
237
238 tuple_args.insert(index, argument);
239
240 *self = tuple_args.into();
241 }
242
243 pub fn mutate_last_token(&mut self) -> &mut Token {
246 match self {
247 Arguments::Tuple(tuple) => tuple.mutate_last_token(),
248 Arguments::String(string) => string.mutate_or_insert_token(),
249 Arguments::Table(table) => table.mutate_last_token(),
250 }
251 }
252
253 pub fn clear_comments(&mut self) {
255 match self {
256 Arguments::Tuple(tuple) => tuple.clear_comments(),
257 Arguments::String(_) | Arguments::Table(_) => {}
258 }
259 }
260
261 pub fn clear_whitespaces(&mut self) {
263 match self {
264 Arguments::Tuple(tuple) => tuple.clear_whitespaces(),
265 Arguments::String(_) | Arguments::Table(_) => {}
266 }
267 }
268
269 pub(crate) fn replace_referenced_tokens(&mut self, code: &str) {
271 match self {
272 Arguments::Tuple(tuple) => tuple.replace_referenced_tokens(code),
273 Arguments::String(_) | Arguments::Table(_) => {}
274 }
275 }
276
277 pub(crate) fn shift_token_line(&mut self, amount: isize) {
279 match self {
280 Arguments::Tuple(tuple) => tuple.shift_token_line(amount),
281 Arguments::String(_) | Arguments::Table(_) => {}
282 }
283 }
284
285 pub(crate) fn filter_comments(&mut self, filter: impl Fn(&super::Trivia) -> bool) {
287 match self {
288 Arguments::Tuple(tuple) => tuple.filter_comments(filter),
289 Arguments::String(_) | Arguments::Table(_) => {}
290 }
291 }
292}
293
294impl Default for Arguments {
295 fn default() -> Self {
296 Self::Tuple(TupleArguments::default())
297 }
298}
299
300impl From<TupleArguments> for Arguments {
301 fn from(tuple: TupleArguments) -> Self {
302 Self::Tuple(tuple)
303 }
304}
305
306impl From<TableExpression> for Arguments {
307 fn from(table: TableExpression) -> Self {
308 Self::Table(table)
309 }
310}
311
312impl From<StringExpression> for Arguments {
313 fn from(string: StringExpression) -> Self {
314 Self::String(string)
315 }
316}
317
318#[cfg(test)]
319mod tests {
320 use super::*;
321 use crate::{
322 nodes::{Identifier, Statement},
323 Parser,
324 };
325
326 fn parse_arguments_with_tokens(lua: &str) -> Arguments {
327 let parser = Parser::default().preserve_tokens();
328
329 let code = format!("f {}", lua);
330
331 let block = parser.parse(&code).expect("code should parse");
332 if let Some(statement) = block.first_statement() {
333 if let Statement::Call(call) = statement {
334 return call.get_arguments().clone();
335 }
336 }
337 panic!("failed to parse call arguments from: {}", lua);
338 }
339
340 fn get_tuple_tokens(args: &Arguments) -> &TupleArgumentsTokens {
341 match args {
342 Arguments::Tuple(tuple) => tuple.get_tokens().expect("tuple should have tokens"),
343 Arguments::String(_) | Arguments::Table(_) => panic!("expected tuple arguments"),
344 }
345 }
346
347 fn expect_comma_tokens(args: &Arguments, index: usize) {
348 let tokens = get_tuple_tokens(args);
349 assert_eq!(tokens.commas[index], Token::from_content(","));
350 }
351
352 mod arguments_len {
353 use super::*;
354
355 #[test]
356 fn empty_tuple() {
357 let empty_tuple = Arguments::Tuple(TupleArguments::new(vec![]));
358 assert_eq!(empty_tuple.len(), 0);
359 }
360
361 #[test]
362 fn single_tuple() {
363 let single_tuple = Arguments::Tuple(TupleArguments::new(vec![Expression::Identifier(
364 Identifier::new("x"),
365 )]));
366 assert_eq!(single_tuple.len(), 1);
367 }
368
369 #[test]
370 fn multi_tuple() {
371 let multi_tuple = Arguments::Tuple(TupleArguments::new(vec![
372 Expression::Identifier(Identifier::new("x")),
373 Expression::Identifier(Identifier::new("y")),
374 Expression::Identifier(Identifier::new("z")),
375 ]));
376 assert_eq!(multi_tuple.len(), 3);
377 }
378
379 #[test]
380 fn string() {
381 let string_args = Arguments::String(StringExpression::from_value("test"));
382 assert_eq!(string_args.len(), 1);
383 }
384
385 #[test]
386 fn table() {
387 let table_args = Arguments::Table(TableExpression::new(vec![]));
388 assert_eq!(table_args.len(), 1);
389 }
390 }
391
392 mod arguments_is_empty {
393 use super::*;
394
395 #[test]
396 fn empty_tuple() {
397 let empty_tuple = Arguments::Tuple(TupleArguments::new(vec![]));
398 assert!(empty_tuple.is_empty());
399 }
400
401 #[test]
402 fn single_tuple() {
403 let single_tuple = Arguments::Tuple(TupleArguments::new(vec![Expression::Identifier(
404 Identifier::new("x"),
405 )]));
406 assert!(!single_tuple.is_empty());
407 }
408
409 #[test]
410 fn multi_tuple() {
411 let multi_tuple = Arguments::Tuple(TupleArguments::new(vec![
412 Expression::Identifier(Identifier::new("x")),
413 Expression::Identifier(Identifier::new("y")),
414 ]));
415 assert!(!multi_tuple.is_empty());
416 }
417
418 #[test]
419 fn string() {
420 let string_args = Arguments::String(StringExpression::from_value("test"));
421 assert!(!string_args.is_empty());
422 }
423
424 #[test]
425 fn table() {
426 let table_args = Arguments::Table(TableExpression::new(vec![]));
427 assert!(!table_args.is_empty());
428 }
429 }
430
431 #[test]
432 fn push_argument_handles_commas() {
433 let mut args = parse_arguments_with_tokens("()");
434
435 args.push(Identifier::new("first"));
436 assert_eq!(get_tuple_tokens(&args).commas.len(), 0);
437
438 args.push(Identifier::new("second"));
439 assert_eq!(get_tuple_tokens(&args).commas.len(), 1);
440 expect_comma_tokens(&args, 0);
441
442 args.push(Identifier::new("third"));
443 assert_eq!(get_tuple_tokens(&args).commas.len(), 2);
444 expect_comma_tokens(&args, 1);
445 }
446
447 #[test]
448 fn insert_argument_handles_commas() {
449 let mut args = parse_arguments_with_tokens("(first, third)");
450
451 args.insert(1, Identifier::new("second"));
452 assert_eq!(get_tuple_tokens(&args).commas.len(), 2);
453 expect_comma_tokens(&args, 1);
454
455 args.insert(3, Identifier::new("fourth"));
456 assert_eq!(get_tuple_tokens(&args).commas.len(), 3);
457
458 args.insert(0, Identifier::new("zero"));
459 assert_eq!(get_tuple_tokens(&args).commas.len(), 4);
460 }
461}