darklua_core/generator/
token_based.rs

1use std::iter;
2
3use crate::{
4    generator::{utils, LuaGenerator},
5    nodes::*,
6};
7
8/// This implementation of [LuaGenerator](trait.LuaGenerator.html) outputs the
9/// AST nodes from the tokens associated with each of them.
10#[derive(Debug, Clone)]
11pub struct TokenBasedLuaGenerator<'a> {
12    original_code: &'a str,
13    output: String,
14    currently_commenting: bool,
15    current_line: usize,
16}
17
18impl<'a> TokenBasedLuaGenerator<'a> {
19    pub fn new(original_code: &'a str) -> Self {
20        Self {
21            original_code,
22            output: String::new(),
23            currently_commenting: false,
24            current_line: 1,
25        }
26    }
27
28    fn push_str(&mut self, string: &str) {
29        self.current_line += utils::count_new_lines(string.as_bytes());
30        self.output.push_str(string);
31    }
32
33    fn write_trivia(&mut self, trivia: &Trivia) {
34        let content = trivia.read(self.original_code);
35
36        let is_comment = matches!(trivia.kind(), TriviaKind::Comment);
37        let is_line_comment = is_comment && is_single_line_comment(content);
38        let is_multiline_comment = is_comment && !is_line_comment;
39
40        if is_multiline_comment && self.currently_commenting {
41            self.uncomment();
42        }
43
44        self.push_str(content);
45
46        match trivia.kind() {
47            TriviaKind::Comment => {
48                if is_line_comment {
49                    self.currently_commenting = true;
50                }
51            }
52            TriviaKind::Whitespace => {
53                if self.currently_commenting && content.contains('\n') {
54                    self.currently_commenting = false
55                }
56            }
57        }
58    }
59
60    #[inline]
61    fn write_token(&mut self, token: &Token) {
62        self.write_token_options(token, true)
63    }
64
65    fn write_token_options(&mut self, token: &Token, space_check: bool) {
66        for trivia in token.iter_leading_trivia() {
67            self.write_trivia(trivia);
68        }
69
70        let content = token.read(self.original_code);
71
72        if !content.is_empty() {
73            if self.currently_commenting {
74                self.uncomment();
75            }
76
77            if let Some(line_number) = token.get_line_number() {
78                while line_number > self.current_line {
79                    self.output.push('\n');
80                    self.current_line += 1;
81                }
82            }
83
84            if space_check {
85                if let Some(next_character) = content.chars().next() {
86                    if self.needs_space(next_character) {
87                        self.output.push(' ');
88                    }
89                }
90            }
91
92            self.push_str(content);
93        }
94
95        for trivia in token.iter_trailing_trivia() {
96            self.write_trivia(trivia);
97        }
98    }
99
100    fn write_block_with_tokens(&mut self, block: &Block, tokens: &BlockTokens) {
101        let mut iterator = block.iter_statements().enumerate().peekable();
102
103        while let Some((index, statement)) = iterator.next() {
104            self.write_statement(statement);
105
106            if let Some(semicolon) = tokens.semicolons.get(index).unwrap_or(&None) {
107                self.write_token(semicolon);
108            } else if let Some((_, next_statement)) = iterator.peek() {
109                if utils::starts_with_parenthese(next_statement)
110                    && utils::ends_with_prefix(statement)
111                {
112                    self.write_symbol(";");
113                }
114            };
115        }
116
117        if let Some(statement) = block.get_last_statement() {
118            self.write_last_statement(statement);
119        }
120
121        if let Some(token) = &tokens.final_token {
122            self.write_token(token);
123        }
124    }
125
126    fn write_return_with_tokens(&mut self, statement: &ReturnStatement, tokens: &ReturnTokens) {
127        self.write_token(&tokens.r#return);
128
129        let last_index = statement.len().saturating_sub(1);
130        statement
131            .iter_expressions()
132            .enumerate()
133            .for_each(|(i, expression)| {
134                self.write_expression(expression);
135                if i < last_index {
136                    if let Some(comma) = tokens.commas.get(i) {
137                        self.write_token(comma);
138                    } else {
139                        self.write_symbol(",");
140                    }
141                }
142            });
143    }
144
145    fn write_assign_with_tokens(&mut self, assign: &AssignStatement, tokens: &AssignTokens) {
146        let last_variable_index = assign.variables_len().saturating_sub(1);
147        assign
148            .iter_variables()
149            .enumerate()
150            .for_each(|(i, variable)| {
151                self.write_variable(variable);
152                if i < last_variable_index {
153                    if let Some(comma) = tokens.variable_commas.get(i) {
154                        self.write_token(comma);
155                    } else {
156                        self.write_symbol(",");
157                    }
158                }
159            });
160
161        self.write_token(&tokens.equal);
162        let last_value_index = assign.values_len().saturating_sub(1);
163        assign.iter_values().enumerate().for_each(|(i, value)| {
164            self.write_expression(value);
165            if i < last_value_index {
166                if let Some(comma) = tokens.value_commas.get(i) {
167                    self.write_token(comma);
168                } else {
169                    self.write_symbol(",");
170                }
171            }
172        });
173    }
174
175    fn write_do_with_tokens(&mut self, do_statement: &DoStatement, tokens: &DoTokens) {
176        self.write_token(&tokens.r#do);
177        self.write_block(do_statement.get_block());
178        self.write_token(&tokens.end);
179    }
180
181    fn write_function_call_with_tokens(
182        &mut self,
183        call: &FunctionCall,
184        tokens: &FunctionCallTokens,
185    ) {
186        self.write_prefix(call.get_prefix());
187        if let Some(method) = call.get_method() {
188            if let Some(colon) = &tokens.colon {
189                self.write_token(colon);
190            } else {
191                self.write_symbol(":");
192            }
193            self.write_identifier(method);
194        }
195        self.write_arguments(call.get_arguments());
196    }
197
198    fn write_parenthese_with_tokens(
199        &mut self,
200        parenthese: &ParentheseExpression,
201        tokens: &ParentheseTokens,
202    ) {
203        self.write_token(&tokens.left_parenthese);
204        self.write_expression(parenthese.inner_expression());
205        self.write_token(&tokens.right_parenthese);
206    }
207
208    fn write_type_cast_with_tokens(&mut self, type_cast: &TypeCastExpression, token: &Token) {
209        let inner_expression = type_cast.get_expression();
210
211        if TypeCastExpression::needs_parentheses(inner_expression) {
212            self.write_symbol("(");
213            self.write_expression(inner_expression);
214            self.write_symbol(")");
215        } else {
216            self.write_expression(inner_expression);
217        }
218
219        self.write_token(token);
220        self.write_type(type_cast.get_type());
221    }
222
223    fn write_tuple_arguments_with_tokens(
224        &mut self,
225        arguments: &TupleArguments,
226        tokens: &TupleArgumentsTokens,
227    ) {
228        self.write_token(&tokens.opening_parenthese);
229
230        let last_value_index = arguments.len().saturating_sub(1);
231        arguments.iter_values().enumerate().for_each(|(i, value)| {
232            self.write_expression(value);
233            if i < last_value_index {
234                if let Some(comma) = tokens.commas.get(i) {
235                    self.write_token(comma);
236                } else {
237                    self.write_symbol(",");
238                }
239            }
240        });
241
242        self.write_token(&tokens.closing_parenthese);
243    }
244
245    fn write_table_with_tokens(&mut self, table: &TableExpression, tokens: &TableTokens) {
246        self.write_token(&tokens.opening_brace);
247
248        let last_index = table.len().saturating_sub(1);
249        table.iter_entries().enumerate().for_each(|(i, entry)| {
250            self.write_table_entry(entry);
251            if let Some(separator) = tokens.separators.get(i) {
252                self.write_token(separator);
253            } else if i < last_index {
254                self.write_symbol(",");
255            }
256        });
257
258        self.write_token(&tokens.closing_brace);
259    }
260
261    fn write_table_field_with_tokens(&mut self, entry: &TableFieldEntry, token: &Token) {
262        self.write_identifier(entry.get_field());
263        self.write_token(token);
264        self.write_expression(entry.get_value());
265    }
266
267    fn write_table_index_with_tokens(
268        &mut self,
269        entry: &TableIndexEntry,
270        tokens: &TableIndexEntryTokens,
271    ) {
272        self.write_token(&tokens.opening_bracket);
273        self.write_expression(entry.get_key());
274        self.write_token(&tokens.closing_bracket);
275        self.write_token(&tokens.equal);
276        self.write_expression(entry.get_value());
277    }
278
279    fn write_field_with_token(&mut self, field: &FieldExpression, token: &Token) {
280        self.write_prefix(field.get_prefix());
281        self.write_token_options(token, false);
282        self.write_identifier(field.get_field());
283    }
284
285    fn write_index_with_tokens(&mut self, index: &IndexExpression, tokens: &IndexExpressionTokens) {
286        self.write_prefix(index.get_prefix());
287        self.write_token(&tokens.opening_bracket);
288        self.write_expression(index.get_index());
289        self.write_token(&tokens.closing_bracket);
290    }
291
292    fn write_if_expression_with_token(
293        &mut self,
294        if_expression: &IfExpression,
295        tokens: &IfExpressionTokens,
296    ) {
297        self.write_token(&tokens.r#if);
298        self.write_expression(if_expression.get_condition());
299        self.write_token(&tokens.then);
300        self.write_expression(if_expression.get_result());
301
302        for branch in if_expression.iter_branches() {
303            if let Some(tokens) = branch.get_tokens() {
304                self.write_if_expression_branch_with_tokens(branch, tokens);
305            } else {
306                self.write_if_expression_branch_with_tokens(
307                    branch,
308                    &self.generate_if_expression_branch_tokens(branch),
309                );
310            }
311        }
312
313        self.write_token(&tokens.r#else);
314        self.write_expression(if_expression.get_else_result());
315    }
316
317    fn write_if_expression_branch_with_tokens(
318        &mut self,
319        branch: &ElseIfExpressionBranch,
320        tokens: &ElseIfExpressionBranchTokens,
321    ) {
322        self.write_token(&tokens.elseif);
323        self.write_expression(branch.get_condition());
324        self.write_token(&tokens.then);
325        self.write_expression(branch.get_result());
326    }
327
328    fn write_compound_assign_with_tokens(
329        &mut self,
330        assign: &CompoundAssignStatement,
331        tokens: &CompoundAssignTokens,
332    ) {
333        self.write_variable(assign.get_variable());
334        self.write_token(&tokens.operator);
335        self.write_expression(assign.get_value());
336    }
337
338    #[allow(clippy::too_many_arguments)]
339    fn write_function_attributes<'b>(
340        &mut self,
341        tokens: &FunctionBodyTokens,
342        generic_parameters: Option<&GenericParameters>,
343        parameter_count: usize,
344        parameters: impl Iterator<Item = &'b TypedIdentifier>,
345        is_variadic: bool,
346        variadic_type: Option<&FunctionVariadicType>,
347        return_type: Option<&FunctionReturnType>,
348        block: &Block,
349    ) {
350        if let Some(generics) = generic_parameters {
351            self.write_function_generics(generics);
352        }
353
354        self.write_token(&tokens.opening_parenthese);
355
356        let last_parameter_index = parameter_count.saturating_sub(1);
357        parameters.enumerate().for_each(|(i, param)| {
358            self.write_typed_identifier(param);
359            if i < last_parameter_index {
360                if let Some(comma) = tokens.parameter_commas.get(i) {
361                    self.write_token(comma);
362                } else {
363                    self.write_symbol(",");
364                }
365            }
366        });
367
368        if is_variadic {
369            if parameter_count > 0 {
370                if let Some(comma) = tokens.parameter_commas.get(last_parameter_index) {
371                    self.write_token(comma);
372                } else {
373                    self.write_symbol(",");
374                }
375            }
376
377            if let Some(token) = &tokens.variable_arguments {
378                self.write_token(token);
379            } else {
380                self.write_symbol("...");
381            }
382
383            if let Some(variadic_type) = variadic_type {
384                if let Some(colon) = &tokens.variable_arguments_colon {
385                    self.write_token(colon);
386                } else {
387                    self.write_symbol(":")
388                }
389                self.write_function_variadic_type(variadic_type);
390            }
391        }
392
393        self.write_token(&tokens.closing_parenthese);
394
395        if let Some(return_type) = return_type {
396            if let Some(colon) = &tokens.return_type_colon {
397                self.write_token(colon);
398            } else {
399                self.write_symbol(":")
400            }
401
402            self.write_function_return_type(return_type);
403        }
404
405        self.write_block(block);
406
407        self.write_token(&tokens.end);
408    }
409
410    fn write_function_statement_with_tokens(
411        &mut self,
412        function: &FunctionStatement,
413        tokens: &FunctionBodyTokens,
414    ) {
415        self.write_token(&tokens.function);
416
417        let name = function.get_name();
418        if let Some(tokens) = name.get_tokens() {
419            self.write_function_name_with_tokens(name, tokens);
420        } else {
421            self.write_function_name_with_tokens(name, &self.generate_function_name_tokens(name));
422        }
423
424        self.write_function_attributes(
425            tokens,
426            function.get_generic_parameters(),
427            function.parameters_count(),
428            function.iter_parameters(),
429            function.is_variadic(),
430            function.get_variadic_type(),
431            function.get_return_type(),
432            function.get_block(),
433        );
434    }
435
436    fn write_function_name_with_tokens(
437        &mut self,
438        name: &FunctionName,
439        tokens: &FunctionNameTokens,
440    ) {
441        self.write_identifier(name.get_name());
442
443        name.get_field_names()
444            .iter()
445            .enumerate()
446            .for_each(|(i, field)| {
447                if let Some(period) = tokens.periods.get(i) {
448                    self.write_token_options(period, false);
449                } else {
450                    self.write_symbol_without_space_check(".");
451                }
452                self.write_identifier(field);
453            });
454
455        if let Some(method) = name.get_method() {
456            if let Some(colon) = &tokens.colon {
457                self.write_token(colon);
458            } else {
459                self.write_symbol(":");
460            }
461            self.write_identifier(method);
462        }
463    }
464
465    fn write_generic_for_with_tokens(
466        &mut self,
467        generic_for: &GenericForStatement,
468        tokens: &GenericForTokens,
469    ) {
470        self.write_token(&tokens.r#for);
471
472        let last_identifier_index = generic_for.identifiers_len().saturating_sub(1);
473        generic_for
474            .iter_identifiers()
475            .enumerate()
476            .for_each(|(i, identifier)| {
477                self.write_typed_identifier(identifier);
478                if i < last_identifier_index {
479                    if let Some(comma) = tokens.identifier_commas.get(i) {
480                        self.write_token(comma);
481                    } else {
482                        self.write_symbol(",");
483                    }
484                }
485            });
486
487        self.write_token(&tokens.r#in);
488
489        let last_expression_index = generic_for.expressions_len().saturating_sub(1);
490        generic_for
491            .iter_expressions()
492            .enumerate()
493            .for_each(|(i, expression)| {
494                self.write_expression(expression);
495                if i < last_expression_index {
496                    if let Some(comma) = tokens.value_commas.get(i) {
497                        self.write_token(comma);
498                    } else {
499                        self.write_symbol(",");
500                    }
501                }
502            });
503
504        self.write_token(&tokens.r#do);
505        self.write_block(generic_for.get_block());
506        self.write_token(&tokens.end);
507    }
508
509    fn write_if_statement_with_tokens(
510        &mut self,
511        if_statement: &IfStatement,
512        tokens: &IfStatementTokens,
513    ) {
514        let mut branches = if_statement.iter_branches();
515        if let Some(branch) = branches.next() {
516            self.write_token(&tokens.r#if);
517            self.write_expression(branch.get_condition());
518            self.write_token(&tokens.then);
519            self.write_block(branch.get_block());
520
521            for branch in branches {
522                if let Some(tokens) = branch.get_tokens() {
523                    self.write_if_branch_with_tokens(branch, tokens);
524                } else {
525                    self.write_if_branch_with_tokens(
526                        branch,
527                        &self.generate_if_branch_tokens(branch),
528                    );
529                }
530            }
531
532            if let Some(else_block) = if_statement.get_else_block() {
533                if let Some(token) = &tokens.r#else {
534                    self.write_token(token);
535                } else {
536                    self.write_symbol("else");
537                }
538                self.write_block(else_block);
539            }
540
541            self.write_token(&tokens.end);
542        }
543    }
544
545    fn write_if_branch_with_tokens(&mut self, branch: &IfBranch, tokens: &IfBranchTokens) {
546        self.write_token(&tokens.elseif);
547        self.write_expression(branch.get_condition());
548        self.write_token(&tokens.then);
549        self.write_block(branch.get_block());
550    }
551
552    fn write_local_assign_with_tokens(
553        &mut self,
554        assign: &LocalAssignStatement,
555        tokens: &LocalAssignTokens,
556    ) {
557        self.write_token(&tokens.local);
558        let last_variable_index = assign.variables_len().saturating_sub(1);
559        assign
560            .iter_variables()
561            .enumerate()
562            .for_each(|(i, identifier)| {
563                self.write_typed_identifier(identifier);
564                if i < last_variable_index {
565                    if let Some(comma) = tokens.variable_commas.get(i) {
566                        self.write_token(comma);
567                    } else {
568                        self.write_symbol(",");
569                    }
570                }
571            });
572
573        if assign.has_values() {
574            if let Some(token) = &tokens.equal {
575                self.write_token(token);
576            } else {
577                self.write_symbol("=");
578            }
579            let last_value_index = assign.values_len().saturating_sub(1);
580            assign.iter_values().enumerate().for_each(|(i, value)| {
581                self.write_expression(value);
582                if i < last_value_index {
583                    if let Some(comma) = tokens.value_commas.get(i) {
584                        self.write_token(comma);
585                    } else {
586                        self.write_symbol(",");
587                    }
588                }
589            });
590        }
591    }
592
593    fn write_local_function_with_tokens(
594        &mut self,
595        function: &LocalFunctionStatement,
596        tokens: &LocalFunctionTokens,
597    ) {
598        self.write_token(&tokens.local);
599        self.write_token(&tokens.function);
600        self.write_identifier(function.get_identifier());
601
602        self.write_function_attributes(
603            tokens,
604            function.get_generic_parameters(),
605            function.parameters_count(),
606            function.iter_parameters(),
607            function.is_variadic(),
608            function.get_variadic_type(),
609            function.get_return_type(),
610            function.get_block(),
611        );
612    }
613
614    fn write_numeric_for_with_tokens(
615        &mut self,
616        numeric_for: &NumericForStatement,
617        tokens: &NumericForTokens,
618    ) {
619        self.write_token(&tokens.r#for);
620        self.write_typed_identifier(numeric_for.get_identifier());
621        self.write_token(&tokens.equal);
622        self.write_expression(numeric_for.get_start());
623        self.write_token(&tokens.end_comma);
624        self.write_expression(numeric_for.get_end());
625
626        if let Some(step) = numeric_for.get_step() {
627            if let Some(comma) = &tokens.step_comma {
628                self.write_token(comma);
629            } else {
630                self.write_symbol(",");
631            }
632            self.write_expression(step);
633        }
634
635        self.write_token(&tokens.r#do);
636        self.write_block(numeric_for.get_block());
637        self.write_token(&tokens.end);
638    }
639
640    fn write_repeat_with_tokens(&mut self, repeat: &RepeatStatement, tokens: &RepeatTokens) {
641        self.write_token(&tokens.repeat);
642        self.write_block(repeat.get_block());
643        self.write_token(&tokens.until);
644        self.write_expression(repeat.get_condition());
645    }
646
647    fn write_while_with_tokens(&mut self, while_statement: &WhileStatement, tokens: &WhileTokens) {
648        self.write_token(&tokens.r#while);
649        self.write_expression(while_statement.get_condition());
650        self.write_token(&tokens.r#do);
651        self.write_block(while_statement.get_block());
652        self.write_token(&tokens.end);
653    }
654
655    fn write_type_declaration_with_tokens(
656        &mut self,
657        statement: &TypeDeclarationStatement,
658        tokens: &TypeDeclarationTokens,
659    ) {
660        if statement.is_exported() {
661            if let Some(export_token) = &tokens.export {
662                self.write_token(export_token);
663            } else {
664                self.write_symbol("export");
665            }
666        }
667        self.write_token(&tokens.r#type);
668
669        self.write_identifier(statement.get_name());
670
671        if let Some(generic_parameters) = statement
672            .get_generic_parameters()
673            .filter(|generic_parameters| !generic_parameters.is_empty())
674        {
675            if let Some(tokens) = generic_parameters.get_tokens() {
676                self.write_generic_parameters_with_default_with_tokens(generic_parameters, tokens);
677            } else {
678                self.write_generic_parameters_with_default_with_tokens(
679                    generic_parameters,
680                    &self.generate_generic_parameters_with_defaults_tokens(generic_parameters),
681                );
682            }
683        }
684
685        self.write_token(&tokens.equal);
686
687        self.write_type(statement.get_type());
688    }
689
690    fn write_generic_parameters_with_default_with_tokens(
691        &mut self,
692        generic_parameters: &GenericParametersWithDefaults,
693        tokens: &GenericParametersTokens,
694    ) {
695        self.write_token(&tokens.opening_list);
696
697        let last_index = generic_parameters.len().saturating_sub(1);
698
699        for (i, parameter) in generic_parameters.iter().enumerate() {
700            match parameter {
701                GenericParameterRef::TypeVariable(identifier) => {
702                    self.write_identifier(identifier);
703                }
704                GenericParameterRef::TypeVariableWithDefault(identifier_with_default) => {
705                    self.write_identifier(identifier_with_default.get_type_variable());
706                    if let Some(token) = identifier_with_default.get_token() {
707                        self.write_token(token);
708                    } else {
709                        self.write_symbol("=");
710                    }
711                    self.write_type(identifier_with_default.get_default_type());
712                }
713                GenericParameterRef::GenericTypePack(generic_type_pack) => {
714                    self.write_generic_type_pack(generic_type_pack);
715                }
716                GenericParameterRef::GenericTypePackWithDefault(generic_pack_with_default) => {
717                    self.write_generic_type_pack(generic_pack_with_default.get_generic_type_pack());
718                    if let Some(token) = generic_pack_with_default.get_token() {
719                        self.write_token(token);
720                    } else {
721                        self.write_symbol("=");
722                    }
723                    self.write_generic_type_pack_default(
724                        generic_pack_with_default.get_default_type(),
725                    );
726                }
727            }
728
729            if i < last_index {
730                if let Some(comma) = tokens.commas.get(i) {
731                    self.write_token(comma);
732                } else {
733                    self.write_symbol(",");
734                }
735            }
736        }
737
738        self.write_token(&tokens.closing_list);
739    }
740
741    fn write_function_with_tokens(
742        &mut self,
743        function: &FunctionExpression,
744        tokens: &FunctionBodyTokens,
745    ) {
746        self.write_token(&tokens.function);
747
748        self.write_function_attributes(
749            tokens,
750            function.get_generic_parameters(),
751            function.parameters_count(),
752            function.iter_parameters(),
753            function.is_variadic(),
754            function.get_variadic_type(),
755            function.get_return_type(),
756            function.get_block(),
757        );
758    }
759
760    fn write_type_parameters_with_tokens(
761        &mut self,
762        parameters: &TypeParameters,
763        tokens: &TypeParametersTokens,
764    ) {
765        self.write_token(&tokens.opening_list);
766        let last_index = parameters.len().saturating_sub(1);
767
768        for (i, parameter) in parameters.iter().enumerate() {
769            self.write_type_parameter(parameter);
770
771            if i < last_index {
772                if let Some(comma) = tokens.commas.get(i) {
773                    self.write_token(comma);
774                } else {
775                    self.write_symbol(",");
776                }
777            }
778        }
779
780        self.write_token(&tokens.closing_list);
781    }
782
783    fn write_type_field_with_token(&mut self, type_field: &TypeField, token: &Token) {
784        self.write_identifier(type_field.get_namespace());
785        self.write_token_options(token, false);
786        self.write_type_name(type_field.get_type_name());
787    }
788
789    fn write_array_type_with_tokens(&mut self, array_type: &ArrayType, tokens: &ArrayTypeTokens) {
790        self.write_token(&tokens.opening_brace);
791        self.write_type(array_type.get_element_type());
792        self.write_token(&tokens.closing_brace);
793    }
794
795    fn write_table_type_with_tokens(&mut self, table_type: &TableType, tokens: &TableTypeTokens) {
796        self.write_token(&tokens.opening_brace);
797
798        let last_index = table_type.len().saturating_sub(1);
799
800        for (i, property) in table_type.iter_entries().enumerate() {
801            match property {
802                TableEntryType::Property(property) => {
803                    self.write_identifier(property.get_identifier());
804
805                    if let Some(colon) = property.get_token() {
806                        self.write_token(colon);
807                    } else {
808                        self.write_symbol(":");
809                    }
810
811                    self.write_type(property.get_type());
812                }
813                TableEntryType::Literal(property) => {
814                    if let Some(tokens) = property.get_tokens() {
815                        self.write_table_literal_property_type_with_tokens(property, tokens);
816                    } else {
817                        self.write_table_literal_property_type_with_tokens(
818                            property,
819                            &self.generate_table_indexer_type_tokens(),
820                        );
821                    }
822                }
823                TableEntryType::Indexer(indexer) => {
824                    if let Some(tokens) = indexer.get_tokens() {
825                        self.write_table_indexer_type_with_tokens(indexer, tokens);
826                    } else {
827                        self.write_table_indexer_type_with_tokens(
828                            indexer,
829                            &self.generate_table_indexer_type_tokens(),
830                        );
831                    }
832                }
833            }
834
835            if let Some(comma) = tokens.separators.get(i) {
836                self.write_token(comma);
837            } else if i < last_index {
838                self.write_symbol(",");
839            }
840        }
841
842        self.write_token(&tokens.closing_brace);
843    }
844
845    fn write_table_indexer_type_with_tokens(
846        &mut self,
847        indexer_type: &TableIndexerType,
848        tokens: &TableIndexTypeTokens,
849    ) {
850        self.write_token(&tokens.opening_bracket);
851
852        let key_type = indexer_type.get_key_type();
853
854        let need_parentheses = matches!(
855            key_type,
856            Type::Optional(_) | Type::Intersection(_) | Type::Union(_)
857        );
858
859        if need_parentheses {
860            self.write_symbol("(");
861            self.write_type(key_type);
862            self.write_symbol(")");
863        } else {
864            self.write_type(key_type);
865        }
866
867        self.write_token(&tokens.closing_bracket);
868        self.write_token(&tokens.colon);
869        self.write_type(indexer_type.get_value_type());
870    }
871
872    fn write_table_literal_property_type_with_tokens(
873        &mut self,
874        property: &TableLiteralPropertyType,
875        tokens: &TableIndexTypeTokens,
876    ) {
877        self.write_token(&tokens.opening_bracket);
878        self.write_string_type(property.get_string());
879        self.write_token(&tokens.closing_bracket);
880        self.write_token(&tokens.colon);
881        self.write_type(property.get_type());
882    }
883
884    fn write_expression_type_with_tokens(
885        &mut self,
886        expression_type: &ExpressionType,
887        tokens: &ExpressionTypeTokens,
888    ) {
889        self.write_token(&tokens.r#typeof);
890        self.write_token(&tokens.opening_parenthese);
891        self.write_expression(expression_type.get_expression());
892        self.write_token(&tokens.closing_parenthese);
893    }
894
895    fn write_parenthese_type_with_tokens(
896        &mut self,
897        parenthese_type: &ParentheseType,
898        tokens: &ParentheseTypeTokens,
899    ) {
900        self.write_token(&tokens.left_parenthese);
901        self.write_type(parenthese_type.get_inner_type());
902        self.write_token(&tokens.right_parenthese);
903    }
904
905    fn write_function_type_with_tokens(
906        &mut self,
907        function_type: &FunctionType,
908        tokens: &FunctionTypeTokens,
909    ) {
910        if let Some(generic_parameters) = function_type.get_generic_parameters() {
911            self.write_function_generics(generic_parameters);
912        }
913
914        self.write_token(&tokens.opening_parenthese);
915
916        let argument_len = function_type.argument_len();
917        let last_index = argument_len.saturating_sub(1);
918
919        for (i, argument) in function_type.iter_arguments().enumerate() {
920            if let Some(name) = argument.get_name() {
921                self.write_identifier(name);
922
923                if let Some(token) = argument.get_token() {
924                    self.write_token(token);
925                } else {
926                    self.write_symbol(":");
927                }
928            }
929
930            self.write_type(argument.get_type());
931
932            if i < last_index {
933                if let Some(comma) = tokens.commas.get(i) {
934                    self.write_token(comma);
935                } else {
936                    self.write_symbol(",");
937                }
938            }
939        }
940
941        if let Some(variadic_argument_type) = function_type.get_variadic_argument_type() {
942            if argument_len > 0 {
943                if let Some(comma) = tokens.commas.get(argument_len) {
944                    self.write_token(comma);
945                } else {
946                    self.write_symbol(",");
947                }
948            }
949            self.write_variadic_argument_type(variadic_argument_type);
950        }
951
952        self.write_token(&tokens.closing_parenthese);
953        self.write_token(&tokens.arrow);
954        self.write_function_return_type(function_type.get_return_type());
955    }
956
957    fn write_function_generics(&mut self, generic_parameters: &GenericParameters) {
958        if generic_parameters.is_empty() {
959            return;
960        }
961        if let Some(generic_tokens) = generic_parameters.get_tokens() {
962            self.write_generic_parameters_with_tokens(generic_parameters, generic_tokens);
963        } else {
964            self.write_generic_parameters_with_tokens(
965                generic_parameters,
966                &self.generate_generic_parameters_tokens(generic_parameters),
967            );
968        }
969    }
970
971    fn write_generic_parameters_with_tokens(
972        &mut self,
973        generic_parameters: &GenericParameters,
974        tokens: &GenericParametersTokens,
975    ) {
976        self.write_token(&tokens.opening_list);
977
978        let last_index = generic_parameters.len().saturating_sub(1);
979
980        for (i, type_variable) in generic_parameters.iter_type_variable().enumerate() {
981            self.write_identifier(type_variable);
982
983            if i < last_index {
984                if let Some(comma) = tokens.commas.get(i) {
985                    self.write_token(comma);
986                } else {
987                    self.write_symbol(",");
988                }
989            }
990        }
991
992        let type_variables_len = generic_parameters.type_variables_len();
993
994        for (i, generic_type_pack) in generic_parameters.iter_generic_type_pack().enumerate() {
995            self.write_generic_type_pack(generic_type_pack);
996
997            if (i + type_variables_len) < last_index {
998                if let Some(comma) = tokens.commas.get(i) {
999                    self.write_token(comma);
1000                } else {
1001                    self.write_symbol(",");
1002                }
1003            }
1004        }
1005
1006        self.write_token(&tokens.closing_list);
1007    }
1008
1009    fn write_type_pack_with_tokens(&mut self, type_pack: &TypePack, tokens: &TypePackTokens) {
1010        self.write_token(&tokens.left_parenthese);
1011
1012        let last_index = type_pack
1013            .len()
1014            .saturating_sub(if type_pack.has_variadic_type() { 0 } else { 1 });
1015
1016        for (i, r#type) in type_pack.iter().enumerate() {
1017            self.write_type(r#type);
1018
1019            if i < last_index {
1020                if let Some(comma) = tokens.commas.get(i) {
1021                    self.write_token(comma);
1022                } else {
1023                    self.write_symbol(",");
1024                }
1025            }
1026        }
1027
1028        if let Some(variadic_argument_type) = type_pack.get_variadic_type() {
1029            self.write_variadic_argument_type(variadic_argument_type);
1030        }
1031
1032        self.write_token(&tokens.right_parenthese);
1033    }
1034
1035    fn write_optional_type_with_token(&mut self, optional: &OptionalType, token: &Token) {
1036        let inner_type = optional.get_inner_type();
1037        if OptionalType::needs_parentheses(inner_type) {
1038            self.write_symbol("(");
1039            self.write_type(inner_type);
1040            self.write_symbol(")");
1041        } else {
1042            self.write_type(inner_type);
1043        }
1044        self.write_token(token);
1045    }
1046
1047    fn write_intersection_type_with_token(
1048        &mut self,
1049        intersection: &IntersectionType,
1050        tokens: &IntersectionTypeTokens,
1051    ) {
1052        let length = intersection.len();
1053        let last_index = length.saturating_sub(1);
1054
1055        for (i, r#type) in intersection.iter_types().enumerate() {
1056            if i == 0 {
1057                if let Some(leading) = &tokens.leading_token {
1058                    self.write_token(leading);
1059                }
1060            } else if let Some(token) = tokens.separators.get(i.saturating_sub(1)) {
1061                self.write_token(token);
1062            } else {
1063                self.write_symbol("&");
1064            }
1065
1066            let need_parentheses = if i == last_index {
1067                IntersectionType::last_needs_parentheses(r#type)
1068            } else {
1069                IntersectionType::intermediate_needs_parentheses(r#type)
1070            };
1071
1072            if need_parentheses {
1073                self.write_symbol("(");
1074                self.write_type(r#type);
1075                self.write_symbol(")");
1076            } else {
1077                self.write_type(r#type);
1078            }
1079        }
1080    }
1081
1082    fn write_union_type_with_token(&mut self, union: &UnionType, tokens: &UnionTypeTokens) {
1083        let length = union.len();
1084        let last_index = length.saturating_sub(1);
1085
1086        for (i, r#type) in union.iter_types().enumerate() {
1087            if i == 0 {
1088                if let Some(leading) = &tokens.leading_token {
1089                    self.write_token(leading);
1090                }
1091            } else if let Some(token) = tokens.separators.get(i.saturating_sub(1)) {
1092                self.write_token(token);
1093            } else {
1094                self.write_symbol("|");
1095            }
1096
1097            let need_parentheses = if i == last_index {
1098                UnionType::last_needs_parentheses(r#type)
1099            } else {
1100                UnionType::intermediate_needs_parentheses(r#type)
1101            };
1102
1103            if need_parentheses {
1104                self.write_symbol("(");
1105                self.write_type(r#type);
1106                self.write_symbol(")");
1107            } else {
1108                self.write_type(r#type);
1109            }
1110        }
1111    }
1112
1113    fn write_interpolated_string_with_tokens(
1114        &mut self,
1115        interpolated_string: &InterpolatedStringExpression,
1116        tokens: &InterpolatedStringTokens,
1117    ) {
1118        self.write_token(&tokens.opening_tick);
1119
1120        for segment in interpolated_string.iter_segments() {
1121            match segment {
1122                InterpolationSegment::String(string_segment) => {
1123                    if let Some(token) = string_segment.get_token() {
1124                        self.write_token(token);
1125                    } else {
1126                        self.write_symbol(&utils::write_interpolated_string_segment(string_segment))
1127                    }
1128                }
1129                InterpolationSegment::Value(value) => {
1130                    if let Some(tokens) = value.get_tokens() {
1131                        self.write_string_value_segment_with_tokens(value, tokens);
1132                    } else {
1133                        self.write_string_value_segment_with_tokens(
1134                            value,
1135                            &self.generate_string_value_segment_tokens(value),
1136                        );
1137                    }
1138                }
1139            }
1140        }
1141
1142        self.write_token(&tokens.closing_tick);
1143    }
1144
1145    fn write_string_value_segment_with_tokens(
1146        &mut self,
1147        value: &ValueSegment,
1148        tokens: &ValueSegmentTokens,
1149    ) {
1150        self.write_token(&tokens.opening_brace);
1151        let expression = value.get_expression();
1152        if self.output.ends_with('{') {
1153            if let Some(table) = utils::starts_with_table(expression) {
1154                if table
1155                    .get_tokens()
1156                    .and_then(|tokens| {
1157                        tokens
1158                            .opening_brace
1159                            .iter_leading_trivia()
1160                            .next()
1161                            .filter(|trivia| !trivia.read(self.original_code).is_empty())
1162                    })
1163                    .is_none()
1164                {
1165                    self.output.push(' ');
1166                }
1167            }
1168        }
1169        self.write_expression(expression);
1170        self.write_token(&tokens.closing_brace);
1171    }
1172
1173    fn generate_block_tokens(&self, _block: &Block) -> BlockTokens {
1174        BlockTokens {
1175            semicolons: Vec::new(),
1176            last_semicolon: None,
1177            final_token: None,
1178        }
1179    }
1180
1181    fn generate_assign_tokens(&self, assign: &AssignStatement) -> AssignTokens {
1182        AssignTokens {
1183            equal: Token::from_content("="),
1184            variable_commas: intersect_with_token(comma_token(), assign.variables_len()),
1185            value_commas: intersect_with_token(comma_token(), assign.values_len()),
1186        }
1187    }
1188
1189    fn generate_do_tokens(&self, _do_statement: &DoStatement) -> DoTokens {
1190        DoTokens {
1191            r#do: Token::from_content("do"),
1192            end: Token::from_content("end"),
1193        }
1194    }
1195
1196    fn generate_compound_assign_tokens(
1197        &self,
1198        assign: &CompoundAssignStatement,
1199    ) -> CompoundAssignTokens {
1200        CompoundAssignTokens {
1201            operator: Token::from_content(assign.get_operator().to_str()),
1202        }
1203    }
1204
1205    fn generate_generic_for_tokens(&self, generic_for: &GenericForStatement) -> GenericForTokens {
1206        GenericForTokens {
1207            r#for: Token::from_content("for"),
1208            r#in: Token::from_content("in"),
1209            r#do: Token::from_content("do"),
1210            end: Token::from_content("end"),
1211            identifier_commas: intersect_with_token(comma_token(), generic_for.identifiers_len()),
1212            value_commas: intersect_with_token(comma_token(), generic_for.expressions_len()),
1213        }
1214    }
1215
1216    fn generate_if_statement_tokens(&self, if_statement: &IfStatement) -> IfStatementTokens {
1217        IfStatementTokens {
1218            r#if: Token::from_content("if"),
1219            then: Token::from_content("then"),
1220            end: Token::from_content("end"),
1221            r#else: if_statement
1222                .get_else_block()
1223                .map(|_| Token::from_content("else")),
1224        }
1225    }
1226
1227    fn generate_if_branch_tokens(&self, _branch: &IfBranch) -> IfBranchTokens {
1228        IfBranchTokens {
1229            elseif: Token::from_content("elseif"),
1230            then: Token::from_content("then"),
1231        }
1232    }
1233
1234    fn generate_function_statement_tokens(
1235        &self,
1236        function: &FunctionStatement,
1237    ) -> FunctionBodyTokens {
1238        FunctionBodyTokens {
1239            function: Token::from_content("function"),
1240            opening_parenthese: Token::from_content("("),
1241            closing_parenthese: Token::from_content(")"),
1242            end: Token::from_content("end"),
1243            parameter_commas: intersect_with_token(
1244                comma_token(),
1245                function.parameters_count() + usize::from(function.is_variadic()),
1246            ),
1247            variable_arguments: if function.is_variadic() {
1248                Some(Token::from_content("..."))
1249            } else {
1250                None
1251            },
1252            variable_arguments_colon: if function.has_variadic_type() {
1253                Some(Token::from_content(":"))
1254            } else {
1255                None
1256            },
1257            return_type_colon: if function.has_return_type() {
1258                Some(Token::from_content(":"))
1259            } else {
1260                None
1261            },
1262        }
1263    }
1264
1265    fn generate_function_name_tokens(&self, name: &FunctionName) -> FunctionNameTokens {
1266        FunctionNameTokens {
1267            periods: iter::repeat_with(|| Token::from_content("."))
1268                .take(name.get_field_names().len())
1269                .collect(),
1270            colon: name.get_method().map(|_| Token::from_content(":")),
1271        }
1272    }
1273
1274    fn generate_return_tokens(&self, return_statement: &ReturnStatement) -> ReturnTokens {
1275        ReturnTokens {
1276            r#return: Token::from_content("return")
1277                .with_trailing_trivia(TriviaKind::Whitespace.with_content(" ")),
1278            commas: intersect_with_token(comma_token(), return_statement.len()),
1279        }
1280    }
1281
1282    fn generate_local_assign_tokens(&self, assign: &LocalAssignStatement) -> LocalAssignTokens {
1283        LocalAssignTokens {
1284            local: Token::from_content("local"),
1285            equal: if assign.has_values() {
1286                Some(Token::from_content("="))
1287            } else {
1288                None
1289            },
1290            variable_commas: intersect_with_token(comma_token(), assign.variables_len()),
1291            value_commas: intersect_with_token(comma_token(), assign.values_len()),
1292        }
1293    }
1294
1295    fn generate_local_function_tokens(
1296        &self,
1297        function: &LocalFunctionStatement,
1298    ) -> LocalFunctionTokens {
1299        LocalFunctionTokens {
1300            local: Token::from_content("local"),
1301            function_body: FunctionBodyTokens {
1302                function: Token::from_content("function"),
1303                opening_parenthese: Token::from_content("("),
1304                closing_parenthese: Token::from_content(")"),
1305                end: Token::from_content("end"),
1306                parameter_commas: intersect_with_token(
1307                    comma_token(),
1308                    function.parameters_count() + usize::from(function.is_variadic()),
1309                ),
1310                variable_arguments: if function.is_variadic() {
1311                    Some(Token::from_content("..."))
1312                } else {
1313                    None
1314                },
1315                variable_arguments_colon: if function.has_variadic_type() {
1316                    Some(Token::from_content(":"))
1317                } else {
1318                    None
1319                },
1320                return_type_colon: if function.has_return_type() {
1321                    Some(Token::from_content(":"))
1322                } else {
1323                    None
1324                },
1325            },
1326        }
1327    }
1328
1329    fn generate_numeric_for_tokens(&self, numeric_for: &NumericForStatement) -> NumericForTokens {
1330        NumericForTokens {
1331            r#for: Token::from_content("for"),
1332            equal: Token::from_content("="),
1333            r#do: Token::from_content("do"),
1334            end: Token::from_content("end"),
1335            end_comma: Token::from_content(","),
1336            step_comma: numeric_for.get_step().map(|_| Token::from_content(",")),
1337        }
1338    }
1339
1340    fn generate_repeat_tokens(&self, _repeat: &RepeatStatement) -> RepeatTokens {
1341        RepeatTokens {
1342            repeat: Token::from_content("repeat"),
1343            until: Token::from_content("until"),
1344        }
1345    }
1346
1347    fn generate_while_tokens(&self, _while_statement: &WhileStatement) -> WhileTokens {
1348        WhileTokens {
1349            r#while: Token::from_content("while"),
1350            r#do: Token::from_content("do"),
1351            end: Token::from_content("end"),
1352        }
1353    }
1354
1355    fn generate_type_declaration_tokens(
1356        &self,
1357        statement: &TypeDeclarationStatement,
1358    ) -> TypeDeclarationTokens {
1359        TypeDeclarationTokens {
1360            r#type: Token::from_content("type"),
1361            equal: Token::from_content("="),
1362            export: if statement.is_exported() {
1363                Some(Token::from_content("export"))
1364            } else {
1365                None
1366            },
1367        }
1368    }
1369
1370    fn generate_function_tokens(&self, function: &FunctionExpression) -> FunctionBodyTokens {
1371        FunctionBodyTokens {
1372            function: Token::from_content("function"),
1373            opening_parenthese: Token::from_content("("),
1374            closing_parenthese: Token::from_content(")"),
1375            end: Token::from_content("end"),
1376            parameter_commas: intersect_with_token(
1377                comma_token(),
1378                function.parameters_count() + usize::from(function.is_variadic()),
1379            ),
1380            variable_arguments: if function.is_variadic() {
1381                Some(Token::from_content("..."))
1382            } else {
1383                None
1384            },
1385            variable_arguments_colon: if function.has_variadic_type() {
1386                Some(Token::from_content(":"))
1387            } else {
1388                None
1389            },
1390            return_type_colon: if function.has_return_type() {
1391                Some(Token::from_content(":"))
1392            } else {
1393                None
1394            },
1395        }
1396    }
1397
1398    fn generate_function_call_tokens(&self, call: &FunctionCall) -> FunctionCallTokens {
1399        FunctionCallTokens {
1400            colon: call.get_method().map(|_| Token::from_content(":")),
1401        }
1402    }
1403
1404    fn generate_field_token(&self, _field: &FieldExpression) -> Token {
1405        Token::from_content(".")
1406    }
1407
1408    fn generate_index_tokens(&self, _index: &IndexExpression) -> IndexExpressionTokens {
1409        IndexExpressionTokens {
1410            opening_bracket: Token::from_content("["),
1411            closing_bracket: Token::from_content("]"),
1412        }
1413    }
1414
1415    fn generate_if_tokens(&self, _if_expression: &IfExpression) -> IfExpressionTokens {
1416        IfExpressionTokens {
1417            r#if: Token::from_content("if"),
1418            then: Token::from_content("then"),
1419            r#else: Token::from_content("else"),
1420        }
1421    }
1422
1423    fn generate_if_expression_branch_tokens(
1424        &self,
1425        _branch: &ElseIfExpressionBranch,
1426    ) -> ElseIfExpressionBranchTokens {
1427        ElseIfExpressionBranchTokens {
1428            elseif: Token::from_content("elseif"),
1429            then: Token::from_content("then"),
1430        }
1431    }
1432
1433    fn generate_table_tokens(&self, table: &TableExpression) -> TableTokens {
1434        TableTokens {
1435            opening_brace: Token::from_content("{"),
1436            closing_brace: Token::from_content("}"),
1437            separators: intersect_with_token(comma_token(), table.len()),
1438        }
1439    }
1440
1441    fn generate_table_field_tokens(&self, _entry: &TableFieldEntry) -> Token {
1442        Token::from_content("=")
1443    }
1444
1445    fn generate_table_index_tokens(&self, _entry: &TableIndexEntry) -> TableIndexEntryTokens {
1446        TableIndexEntryTokens {
1447            opening_bracket: Token::from_content("["),
1448            closing_bracket: Token::from_content("]"),
1449            equal: Token::from_content("="),
1450        }
1451    }
1452
1453    fn generate_tuple_arguments_tokens(&self, arguments: &TupleArguments) -> TupleArgumentsTokens {
1454        TupleArgumentsTokens {
1455            opening_parenthese: Token::from_content("("),
1456            closing_parenthese: Token::from_content(")"),
1457            commas: intersect_with_token(comma_token(), arguments.len()),
1458        }
1459    }
1460
1461    fn generate_parenthese_tokens(&self, _parenthese: &ParentheseExpression) -> ParentheseTokens {
1462        ParentheseTokens {
1463            left_parenthese: Token::from_content("("),
1464            right_parenthese: Token::from_content(")"),
1465        }
1466    }
1467
1468    fn generate_type_cast_token(&self, _type_cast: &TypeCastExpression) -> Token {
1469        Token::from_content("::")
1470    }
1471
1472    fn generate_type_parameters_tokens(&self, parameters: &TypeParameters) -> TypeParametersTokens {
1473        TypeParametersTokens {
1474            opening_list: Token::from_content("<"),
1475            closing_list: Token::from_content(">"),
1476            commas: intersect_with_token(comma_token(), parameters.len()),
1477        }
1478    }
1479
1480    fn generate_type_field_token(&self, _type_field: &TypeField) -> Token {
1481        Token::from_content(".")
1482    }
1483
1484    fn generate_array_type_tokens(&self, _array: &ArrayType) -> ArrayTypeTokens {
1485        ArrayTypeTokens {
1486            opening_brace: Token::from_content("{"),
1487            closing_brace: Token::from_content("}"),
1488        }
1489    }
1490
1491    fn generate_table_type_tokens(&self, table_type: &TableType) -> TableTypeTokens {
1492        TableTypeTokens {
1493            opening_brace: Token::from_content("{"),
1494            closing_brace: Token::from_content("}"),
1495            separators: intersect_with_token(comma_token(), table_type.len()),
1496        }
1497    }
1498
1499    fn generate_table_indexer_type_tokens(&self) -> TableIndexTypeTokens {
1500        TableIndexTypeTokens {
1501            opening_bracket: Token::from_content("["),
1502            closing_bracket: Token::from_content("]"),
1503            colon: Token::from_content(":"),
1504        }
1505    }
1506
1507    fn generate_expression_type_tokens(
1508        &self,
1509        _expression_type: &ExpressionType,
1510    ) -> ExpressionTypeTokens {
1511        ExpressionTypeTokens {
1512            r#typeof: Token::from_content("typeof"),
1513            opening_parenthese: Token::from_content("("),
1514            closing_parenthese: Token::from_content(")"),
1515        }
1516    }
1517
1518    fn generate_parenthese_type_tokens(
1519        &self,
1520        _parenthese_type: &ParentheseType,
1521    ) -> ParentheseTypeTokens {
1522        ParentheseTypeTokens {
1523            left_parenthese: Token::from_content("("),
1524            right_parenthese: Token::from_content(")"),
1525        }
1526    }
1527
1528    fn generate_function_type_tokens(&self, function_type: &FunctionType) -> FunctionTypeTokens {
1529        FunctionTypeTokens {
1530            opening_parenthese: Token::from_content("("),
1531            closing_parenthese: Token::from_content(")"),
1532            arrow: Token::from_content("->"),
1533            commas: intersect_with_token(
1534                comma_token(),
1535                function_type.argument_len()
1536                    + usize::from(function_type.has_variadic_argument_type()),
1537            ),
1538        }
1539    }
1540
1541    fn generate_optional_type_token(&self, _optional: &OptionalType) -> Token {
1542        Token::from_content("?")
1543    }
1544
1545    fn generate_intersection_type_token(
1546        &self,
1547        intersection: &IntersectionType,
1548    ) -> IntersectionTypeTokens {
1549        IntersectionTypeTokens {
1550            leading_token: intersection
1551                .has_leading_token()
1552                .then(|| Token::from_content("&")),
1553            separators: intersect_with_token(Token::from_content("&"), intersection.len()),
1554        }
1555    }
1556
1557    fn generate_union_type_token(&self, union: &UnionType) -> UnionTypeTokens {
1558        UnionTypeTokens {
1559            leading_token: union.has_leading_token().then(|| Token::from_content("|")),
1560            separators: intersect_with_token(Token::from_content("|"), union.len()),
1561        }
1562    }
1563
1564    fn generate_type_pack_tokens(&self, type_pack: &TypePack) -> TypePackTokens {
1565        TypePackTokens {
1566            left_parenthese: Token::from_content("("),
1567            right_parenthese: Token::from_content(")"),
1568            commas: intersect_with_token(
1569                comma_token(),
1570                type_pack.len() + usize::from(type_pack.has_variadic_type()),
1571            ),
1572        }
1573    }
1574
1575    fn generate_generic_parameters_tokens(
1576        &self,
1577        generic_parameters: &GenericParameters,
1578    ) -> GenericParametersTokens {
1579        GenericParametersTokens {
1580            opening_list: Token::from_content("<"),
1581            closing_list: Token::from_content(">"),
1582            commas: intersect_with_token(comma_token(), generic_parameters.len()),
1583        }
1584    }
1585
1586    fn generate_generic_parameters_with_defaults_tokens(
1587        &self,
1588        generic_parameters: &GenericParametersWithDefaults,
1589    ) -> GenericParametersTokens {
1590        GenericParametersTokens {
1591            opening_list: Token::from_content("<"),
1592            closing_list: Token::from_content(">"),
1593            commas: intersect_with_token(comma_token(), generic_parameters.len()),
1594        }
1595    }
1596
1597    fn generate_interpolated_string_tokens(
1598        &self,
1599        _interpolated_string: &InterpolatedStringExpression,
1600    ) -> InterpolatedStringTokens {
1601        InterpolatedStringTokens {
1602            opening_tick: Token::from_content("`"),
1603            closing_tick: Token::from_content("`"),
1604        }
1605    }
1606
1607    fn generate_string_value_segment_tokens(
1608        &self,
1609        _value_segment: &ValueSegment,
1610    ) -> ValueSegmentTokens {
1611        ValueSegmentTokens {
1612            opening_brace: Token::from_content("{"),
1613            closing_brace: Token::from_content("}"),
1614        }
1615    }
1616
1617    fn write_symbol(&mut self, symbol: &str) {
1618        if self.currently_commenting {
1619            self.uncomment();
1620        } else if self.needs_space(symbol.chars().next().expect("symbol cannot be empty")) {
1621            self.output.push(' ');
1622        }
1623        self.push_str(symbol);
1624    }
1625
1626    fn write_symbol_without_space_check(&mut self, symbol: &str) {
1627        if self.currently_commenting {
1628            self.uncomment();
1629        }
1630        self.push_str(symbol);
1631    }
1632
1633    fn write_typed_identifier(&mut self, typed_identifier: &TypedIdentifier) {
1634        if let Some(token) = typed_identifier.get_token() {
1635            let name_in_token = token.read(self.original_code);
1636
1637            if name_in_token == typed_identifier.get_name() {
1638                self.write_token(token);
1639            } else {
1640                let mut new_token = token.clone();
1641                new_token.replace_with_content(typed_identifier.get_name().clone());
1642                self.write_token(&new_token);
1643            }
1644        } else {
1645            let name = typed_identifier.get_name();
1646            self.write_symbol(name);
1647        }
1648
1649        if let Some(r#type) = typed_identifier.get_type() {
1650            if let Some(colon) = typed_identifier.get_colon_token() {
1651                self.write_token(colon);
1652            } else {
1653                self.write_symbol(":");
1654            }
1655            self.write_type(r#type);
1656        }
1657    }
1658
1659    #[inline]
1660    fn needs_space(&self, next_character: char) -> bool {
1661        if let Some(last) = self.output.chars().last() {
1662            utils::should_break_with_space(last, next_character)
1663        } else {
1664            false
1665        }
1666    }
1667
1668    #[inline]
1669    fn uncomment(&mut self) {
1670        self.output.push('\n');
1671        self.current_line += 1;
1672        self.currently_commenting = false;
1673    }
1674}
1675
1676fn is_single_line_comment(content: &str) -> bool {
1677    let is_multiline_comment = content.starts_with("--[") && {
1678        if let Some((closing_bracket_index, _)) =
1679            content.chars().skip(3).enumerate().find(|(_, c)| *c == '[')
1680        {
1681            content
1682                .get(3..closing_bracket_index)
1683                .map(|substring| substring.chars().all(|c| c == '='))
1684                .unwrap_or(true)
1685        } else {
1686            false
1687        }
1688    };
1689
1690    !is_multiline_comment
1691}
1692
1693#[inline]
1694fn comma_token() -> Token {
1695    Token::from_content(",").with_trailing_trivia(TriviaKind::Whitespace.with_content(" "))
1696}
1697
1698impl LuaGenerator for TokenBasedLuaGenerator<'_> {
1699    fn into_string(self) -> String {
1700        self.output
1701    }
1702
1703    fn write_block(&mut self, block: &Block) {
1704        if let Some(tokens) = block.get_tokens() {
1705            self.write_block_with_tokens(block, tokens);
1706        } else {
1707            self.write_block_with_tokens(block, &self.generate_block_tokens(block));
1708        }
1709    }
1710
1711    fn write_assign_statement(&mut self, assign: &AssignStatement) {
1712        if let Some(tokens) = assign.get_tokens() {
1713            self.write_assign_with_tokens(assign, tokens);
1714        } else {
1715            self.write_assign_with_tokens(assign, &self.generate_assign_tokens(assign));
1716        }
1717    }
1718
1719    fn write_do_statement(&mut self, do_statement: &DoStatement) {
1720        if let Some(tokens) = do_statement.get_tokens() {
1721            self.write_do_with_tokens(do_statement, tokens);
1722        } else {
1723            self.write_do_with_tokens(do_statement, &self.generate_do_tokens(do_statement));
1724        }
1725    }
1726
1727    fn write_compound_assign(&mut self, assign: &CompoundAssignStatement) {
1728        if let Some(tokens) = assign.get_tokens() {
1729            self.write_compound_assign_with_tokens(assign, tokens);
1730        } else {
1731            self.write_compound_assign_with_tokens(
1732                assign,
1733                &self.generate_compound_assign_tokens(assign),
1734            );
1735        }
1736    }
1737
1738    fn write_generic_for(&mut self, generic_for: &GenericForStatement) {
1739        if let Some(tokens) = generic_for.get_tokens() {
1740            self.write_generic_for_with_tokens(generic_for, tokens);
1741        } else {
1742            self.write_generic_for_with_tokens(
1743                generic_for,
1744                &self.generate_generic_for_tokens(generic_for),
1745            );
1746        }
1747    }
1748
1749    fn write_if_statement(&mut self, if_statement: &IfStatement) {
1750        if let Some(tokens) = if_statement.get_tokens() {
1751            self.write_if_statement_with_tokens(if_statement, tokens);
1752        } else {
1753            self.write_if_statement_with_tokens(
1754                if_statement,
1755                &self.generate_if_statement_tokens(if_statement),
1756            );
1757        }
1758    }
1759
1760    fn write_function_statement(&mut self, function: &FunctionStatement) {
1761        if let Some(tokens) = function.get_tokens() {
1762            self.write_function_statement_with_tokens(function, tokens);
1763        } else {
1764            self.write_function_statement_with_tokens(
1765                function,
1766                &self.generate_function_statement_tokens(function),
1767            );
1768        }
1769    }
1770
1771    fn write_last_statement(&mut self, statement: &LastStatement) {
1772        match statement {
1773            LastStatement::Break(token) => {
1774                if let Some(token) = token {
1775                    self.write_token(token);
1776                } else {
1777                    self.write_symbol("break");
1778                }
1779            }
1780            LastStatement::Continue(token) => {
1781                if let Some(token) = token {
1782                    self.write_token(token);
1783                } else {
1784                    self.write_symbol("continue");
1785                }
1786            }
1787            LastStatement::Return(return_statement) => {
1788                if let Some(tokens) = return_statement.get_tokens() {
1789                    self.write_return_with_tokens(return_statement, tokens);
1790                } else {
1791                    self.write_return_with_tokens(
1792                        return_statement,
1793                        &self.generate_return_tokens(return_statement),
1794                    );
1795                }
1796            }
1797        }
1798    }
1799
1800    fn write_local_assign(&mut self, assign: &LocalAssignStatement) {
1801        if let Some(tokens) = assign.get_tokens() {
1802            self.write_local_assign_with_tokens(assign, tokens);
1803        } else {
1804            self.write_local_assign_with_tokens(assign, &self.generate_local_assign_tokens(assign));
1805        }
1806    }
1807
1808    fn write_local_function(&mut self, function: &LocalFunctionStatement) {
1809        if let Some(tokens) = function.get_tokens() {
1810            self.write_local_function_with_tokens(function, tokens);
1811        } else {
1812            self.write_local_function_with_tokens(
1813                function,
1814                &self.generate_local_function_tokens(function),
1815            );
1816        }
1817    }
1818
1819    fn write_numeric_for(&mut self, numeric_for: &NumericForStatement) {
1820        if let Some(tokens) = numeric_for.get_tokens() {
1821            self.write_numeric_for_with_tokens(numeric_for, tokens);
1822        } else {
1823            self.write_numeric_for_with_tokens(
1824                numeric_for,
1825                &self.generate_numeric_for_tokens(numeric_for),
1826            );
1827        }
1828    }
1829
1830    fn write_repeat_statement(&mut self, repeat: &RepeatStatement) {
1831        if let Some(tokens) = repeat.get_tokens() {
1832            self.write_repeat_with_tokens(repeat, tokens);
1833        } else {
1834            self.write_repeat_with_tokens(repeat, &self.generate_repeat_tokens(repeat));
1835        }
1836    }
1837
1838    fn write_while_statement(&mut self, while_statement: &WhileStatement) {
1839        if let Some(tokens) = while_statement.get_tokens() {
1840            self.write_while_with_tokens(while_statement, tokens);
1841        } else {
1842            self.write_while_with_tokens(
1843                while_statement,
1844                &self.generate_while_tokens(while_statement),
1845            );
1846        }
1847    }
1848
1849    fn write_type_declaration_statement(&mut self, statement: &TypeDeclarationStatement) {
1850        if let Some(tokens) = statement.get_tokens() {
1851            self.write_type_declaration_with_tokens(statement, tokens);
1852        } else {
1853            self.write_type_declaration_with_tokens(
1854                statement,
1855                &self.generate_type_declaration_tokens(statement),
1856            );
1857        }
1858    }
1859
1860    fn write_false_expression(&mut self, token: &Option<Token>) {
1861        if let Some(token) = token {
1862            self.write_token(token);
1863        } else {
1864            self.write_symbol("false");
1865        }
1866    }
1867
1868    fn write_true_expression(&mut self, token: &Option<Token>) {
1869        if let Some(token) = token {
1870            self.write_token(token);
1871        } else {
1872            self.write_symbol("true");
1873        }
1874    }
1875
1876    fn write_nil_expression(&mut self, token: &Option<Token>) {
1877        if let Some(token) = token {
1878            self.write_token(token);
1879        } else {
1880            self.write_symbol("nil");
1881        }
1882    }
1883
1884    fn write_variable_arguments_expression(&mut self, token: &Option<Token>) {
1885        if let Some(token) = token {
1886            self.write_token(token);
1887        } else {
1888            self.write_symbol("...");
1889        }
1890    }
1891
1892    fn write_binary_expression(&mut self, binary: &BinaryExpression) {
1893        let operator = binary.operator();
1894        let left = binary.left();
1895        let right = binary.right();
1896
1897        if operator.left_needs_parentheses(left) {
1898            self.write_symbol("(");
1899            self.write_expression(left);
1900            self.write_symbol(")");
1901        } else {
1902            self.write_expression(left);
1903        }
1904
1905        if let Some(operator) = binary.get_token() {
1906            self.write_token(operator);
1907        } else {
1908            self.write_token(&Token::from_content(binary.operator().to_str()));
1909        }
1910
1911        if operator.right_needs_parentheses(right) {
1912            self.write_symbol("(");
1913            self.write_expression(right);
1914            self.write_symbol(")");
1915        } else {
1916            self.write_expression(right);
1917        }
1918    }
1919
1920    fn write_unary_expression(&mut self, unary: &UnaryExpression) {
1921        if let Some(operator) = unary.get_token() {
1922            self.write_token(operator);
1923        } else {
1924            self.write_token(&Token::from_content(unary.operator().to_str()));
1925        }
1926
1927        let expression = unary.get_expression();
1928        match expression {
1929            Expression::Binary(binary) if !binary.operator().precedes_unary_expression() => {
1930                self.write_symbol("(");
1931                self.write_expression(expression);
1932                self.write_symbol(")");
1933            }
1934            _ => self.write_expression(expression),
1935        }
1936    }
1937
1938    fn write_function(&mut self, function: &FunctionExpression) {
1939        if let Some(tokens) = function.get_tokens() {
1940            self.write_function_with_tokens(function, tokens);
1941        } else {
1942            self.write_function_with_tokens(function, &self.generate_function_tokens(function));
1943        }
1944    }
1945
1946    fn write_function_call(&mut self, call: &FunctionCall) {
1947        if let Some(tokens) = call.get_tokens() {
1948            self.write_function_call_with_tokens(call, tokens);
1949        } else {
1950            self.write_function_call_with_tokens(call, &self.generate_function_call_tokens(call));
1951        }
1952    }
1953
1954    fn write_field(&mut self, field: &FieldExpression) {
1955        if let Some(token) = field.get_token() {
1956            self.write_field_with_token(field, token);
1957        } else {
1958            self.write_field_with_token(field, &self.generate_field_token(field));
1959        }
1960    }
1961
1962    fn write_index(&mut self, index: &IndexExpression) {
1963        if let Some(tokens) = index.get_tokens() {
1964            self.write_index_with_tokens(index, tokens);
1965        } else {
1966            self.write_index_with_tokens(index, &self.generate_index_tokens(index));
1967        }
1968    }
1969
1970    fn write_if_expression(&mut self, if_expression: &IfExpression) {
1971        if let Some(token) = if_expression.get_tokens() {
1972            self.write_if_expression_with_token(if_expression, token);
1973        } else {
1974            self.write_if_expression_with_token(
1975                if_expression,
1976                &self.generate_if_tokens(if_expression),
1977            );
1978        }
1979    }
1980
1981    fn write_table(&mut self, table: &TableExpression) {
1982        if let Some(tokens) = table.get_tokens() {
1983            self.write_table_with_tokens(table, tokens);
1984        } else {
1985            self.write_table_with_tokens(table, &self.generate_table_tokens(table));
1986        }
1987    }
1988
1989    fn write_table_entry(&mut self, entry: &TableEntry) {
1990        match entry {
1991            TableEntry::Field(entry) => {
1992                if let Some(tokens) = entry.get_token() {
1993                    self.write_table_field_with_tokens(entry, tokens);
1994                } else {
1995                    self.write_table_field_with_tokens(
1996                        entry,
1997                        &self.generate_table_field_tokens(entry),
1998                    );
1999                }
2000            }
2001            TableEntry::Index(entry) => {
2002                if let Some(tokens) = entry.get_tokens() {
2003                    self.write_table_index_with_tokens(entry, tokens);
2004                } else {
2005                    self.write_table_index_with_tokens(
2006                        entry,
2007                        &self.generate_table_index_tokens(entry),
2008                    );
2009                }
2010            }
2011            TableEntry::Value(expression) => self.write_expression(expression),
2012        }
2013    }
2014
2015    fn write_number(&mut self, number: &NumberExpression) {
2016        if let Some(token) = number.get_token() {
2017            self.write_token(token);
2018        } else {
2019            self.write_token(&Token::from_content(utils::write_number(number)));
2020        }
2021    }
2022
2023    fn write_tuple_arguments(&mut self, arguments: &TupleArguments) {
2024        if let Some(tokens) = arguments.get_tokens() {
2025            self.write_tuple_arguments_with_tokens(arguments, tokens);
2026        } else {
2027            self.write_tuple_arguments_with_tokens(
2028                arguments,
2029                &self.generate_tuple_arguments_tokens(arguments),
2030            );
2031        }
2032    }
2033
2034    fn write_string(&mut self, string: &StringExpression) {
2035        if let Some(token) = string.get_token() {
2036            self.write_token(token);
2037        } else {
2038            self.write_symbol(&utils::write_string(string.get_value()));
2039        }
2040    }
2041
2042    fn write_interpolated_string(&mut self, interpolated_string: &InterpolatedStringExpression) {
2043        if let Some(tokens) = interpolated_string.get_tokens() {
2044            self.write_interpolated_string_with_tokens(interpolated_string, tokens);
2045        } else {
2046            self.write_interpolated_string_with_tokens(
2047                interpolated_string,
2048                &self.generate_interpolated_string_tokens(interpolated_string),
2049            );
2050        }
2051    }
2052
2053    fn write_identifier(&mut self, identifier: &Identifier) {
2054        if let Some(token) = identifier.get_token() {
2055            let name_in_token = token.read(self.original_code);
2056
2057            if name_in_token == identifier.get_name() {
2058                self.write_token(token);
2059            } else {
2060                let mut new_token = token.clone();
2061                new_token.replace_with_content(identifier.get_name().clone());
2062                self.write_token(&new_token);
2063            }
2064        } else {
2065            let name = identifier.get_name();
2066            self.write_symbol(name);
2067        }
2068    }
2069
2070    fn write_parenthese(&mut self, parenthese: &ParentheseExpression) {
2071        if let Some(tokens) = parenthese.get_tokens() {
2072            self.write_parenthese_with_tokens(parenthese, tokens);
2073        } else {
2074            self.write_parenthese_with_tokens(
2075                parenthese,
2076                &self.generate_parenthese_tokens(parenthese),
2077            );
2078        }
2079    }
2080
2081    fn write_type_cast(&mut self, type_cast: &TypeCastExpression) {
2082        if let Some(token) = type_cast.get_token() {
2083            self.write_type_cast_with_tokens(type_cast, token);
2084        } else {
2085            self.write_type_cast_with_tokens(type_cast, &self.generate_type_cast_token(type_cast));
2086        }
2087    }
2088
2089    fn write_type_name(&mut self, type_name: &TypeName) {
2090        self.write_identifier(type_name.get_type_name());
2091        if let Some(parameters) = type_name.get_type_parameters() {
2092            if let Some(tokens) = parameters.get_tokens() {
2093                self.write_type_parameters_with_tokens(parameters, tokens);
2094            } else {
2095                self.write_type_parameters_with_tokens(
2096                    parameters,
2097                    &self.generate_type_parameters_tokens(parameters),
2098                );
2099            }
2100        }
2101    }
2102
2103    fn write_type_field(&mut self, type_field: &TypeField) {
2104        if let Some(tokens) = type_field.get_token() {
2105            self.write_type_field_with_token(type_field, tokens);
2106        } else {
2107            self.write_type_field_with_token(
2108                type_field,
2109                &self.generate_type_field_token(type_field),
2110            );
2111        }
2112    }
2113
2114    fn write_true_type(&mut self, token: &Option<Token>) {
2115        if let Some(token) = token {
2116            self.write_token(token);
2117        } else {
2118            self.write_symbol("true");
2119        }
2120    }
2121
2122    fn write_false_type(&mut self, token: &Option<Token>) {
2123        if let Some(token) = token {
2124            self.write_token(token);
2125        } else {
2126            self.write_symbol("false");
2127        }
2128    }
2129
2130    fn write_nil_type(&mut self, token: &Option<Token>) {
2131        if let Some(token) = token {
2132            self.write_token(token);
2133        } else {
2134            self.write_symbol("nil");
2135        }
2136    }
2137
2138    fn write_string_type(&mut self, string_type: &StringType) {
2139        if let Some(token) = string_type.get_token() {
2140            self.write_token(token);
2141        } else {
2142            self.write_symbol(&utils::write_string(string_type.get_value()));
2143        }
2144    }
2145
2146    fn write_array_type(&mut self, array: &ArrayType) {
2147        if let Some(tokens) = array.get_tokens() {
2148            self.write_array_type_with_tokens(array, tokens);
2149        } else {
2150            self.write_array_type_with_tokens(array, &self.generate_array_type_tokens(array));
2151        }
2152    }
2153
2154    fn write_table_type(&mut self, table_type: &TableType) {
2155        if let Some(tokens) = table_type.get_tokens() {
2156            self.write_table_type_with_tokens(table_type, tokens);
2157        } else {
2158            self.write_table_type_with_tokens(
2159                table_type,
2160                &self.generate_table_type_tokens(table_type),
2161            );
2162        }
2163    }
2164
2165    fn write_expression_type(&mut self, expression_type: &ExpressionType) {
2166        if let Some(tokens) = expression_type.get_tokens() {
2167            self.write_expression_type_with_tokens(expression_type, tokens);
2168        } else {
2169            self.write_expression_type_with_tokens(
2170                expression_type,
2171                &self.generate_expression_type_tokens(expression_type),
2172            );
2173        }
2174    }
2175
2176    fn write_parenthese_type(&mut self, parenthese_type: &ParentheseType) {
2177        if let Some(tokens) = parenthese_type.get_tokens() {
2178            self.write_parenthese_type_with_tokens(parenthese_type, tokens);
2179        } else {
2180            self.write_parenthese_type_with_tokens(
2181                parenthese_type,
2182                &self.generate_parenthese_type_tokens(parenthese_type),
2183            );
2184        }
2185    }
2186
2187    fn write_function_type(&mut self, function_type: &FunctionType) {
2188        if let Some(tokens) = function_type.get_tokens() {
2189            self.write_function_type_with_tokens(function_type, tokens);
2190        } else {
2191            self.write_function_type_with_tokens(
2192                function_type,
2193                &self.generate_function_type_tokens(function_type),
2194            );
2195        }
2196    }
2197
2198    fn write_optional_type(&mut self, optional: &OptionalType) {
2199        if let Some(token) = optional.get_token() {
2200            self.write_optional_type_with_token(optional, token);
2201        } else {
2202            self.write_optional_type_with_token(
2203                optional,
2204                &self.generate_optional_type_token(optional),
2205            );
2206        }
2207    }
2208
2209    fn write_intersection_type(&mut self, intersection: &IntersectionType) {
2210        if let Some(token) = intersection.get_token() {
2211            self.write_intersection_type_with_token(intersection, token);
2212        } else {
2213            self.write_intersection_type_with_token(
2214                intersection,
2215                &self.generate_intersection_type_token(intersection),
2216            );
2217        }
2218    }
2219
2220    fn write_union_type(&mut self, union: &UnionType) {
2221        if let Some(token) = union.get_token() {
2222            self.write_union_type_with_token(union, token);
2223        } else {
2224            self.write_union_type_with_token(union, &self.generate_union_type_token(union));
2225        }
2226    }
2227
2228    fn write_type_pack(&mut self, type_pack: &TypePack) {
2229        if let Some(tokens) = type_pack.get_tokens() {
2230            self.write_type_pack_with_tokens(type_pack, tokens);
2231        } else {
2232            self.write_type_pack_with_tokens(type_pack, &self.generate_type_pack_tokens(type_pack));
2233        }
2234    }
2235
2236    fn write_variadic_type_pack(&mut self, variadic_type_pack: &VariadicTypePack) {
2237        self.push_str("...");
2238        self.write_type(variadic_type_pack.get_type());
2239    }
2240
2241    fn write_generic_type_pack(&mut self, generic_type_pack: &GenericTypePack) {
2242        self.write_identifier(generic_type_pack.get_name());
2243        self.push_str("...");
2244    }
2245}
2246
2247fn intersect_with_token(token: Token, list_length: usize) -> Vec<Token> {
2248    iter::repeat_with(|| token.clone())
2249        .take(list_length.saturating_sub(1))
2250        .collect()
2251}
2252
2253#[cfg(test)]
2254mod test {
2255    use super::*;
2256
2257    macro_rules! test_output {
2258        ($($name:ident => $code:literal),* $(,)?) => {
2259            $(
2260                #[test]
2261                fn $name() {
2262                    let parser = crate::Parser::default().preserve_tokens();
2263                    let block = parser.parse($code)
2264                        .expect(&format!("failed to parse `{}`", $code));
2265
2266                    let mut generator = TokenBasedLuaGenerator::new($code);
2267
2268                    generator.write_block(&block);
2269
2270                    let output = generator.into_string();
2271
2272                    assert_eq!($code, &output);
2273                }
2274            )*
2275
2276            mod without_tokens {
2277                use super::*;
2278                $(
2279                    #[test]
2280                    fn $name() {
2281                        let parser = crate::Parser::default();
2282                        let block = parser.parse($code)
2283                            .expect(&format!("failed to parse `{}`", $code));
2284
2285                        let mut generator = TokenBasedLuaGenerator::new($code);
2286
2287                        generator.write_block(&block);
2288
2289                        let output = generator.into_string();
2290
2291                        let parsed_output_block = parser.parse(&output)
2292                            .expect(&format!("failed to parse generated code `{}`", &output));
2293
2294                        pretty_assertions::assert_eq!(block, parsed_output_block);
2295                    }
2296                )*
2297            }
2298        };
2299    }
2300
2301    test_output!(
2302        // statements
2303        assign => "var = true",
2304        assign_multiple => "var, var2 =\n\ttrue,\tfalse\n",
2305        empty_do => "do end\n",
2306        nested_do => "do\n    do end\nend\n",
2307        call_without_arguments => "call()",
2308        call_print => "print('hi')",
2309        call_print_with_string_argument => "print 'hi' -- no parentheses",
2310        call_function_with_table_multiline => "process {\n\targ = true,\n\tflag = false,\n}\n",
2311        call_method_without_arguments => "foo:bar()",
2312        call_method_with_arguments => "foo:bar(true, false)",
2313        call_string_format => "('foo'):rep(3)",
2314        call_math_floor => "math.floor(value)",
2315        call_with_index => "object[ key ](i)",
2316        compound_increment => "i += 1\n",
2317        empty_function_declaration => "function process()\nend",
2318        empty_static_function_declaration => "function Class .new()\nend",
2319        empty_method_function_declaration => "function Class : process()\nend",
2320        empty_nested_method_function_declaration => "function Class . foo.bar : help ()\nend",
2321        empty_function_declaration_with_params => "function process(a, b --[[ optional ]]) end",
2322        empty_variadic_function_declaration => "function process (...) end",
2323        empty_variadic_function_declaration_with_one_param => "function format (str, ... --[[ optional strings ]]) end",
2324        variadic_function_returns => "function identity(...)\n\treturn ...\nend\n",
2325        empty_generic_for => "for key, value in pairs(result) do\n\t-- help\nend",
2326        empty_generic_for_key_only => "for key in pairs(dict) do end",
2327        generic_for_with_next => "for key,value in next, dict do\n\tprint(key, value)\nend\n",
2328        empty_if => "if true then\nend",
2329        if_condition_return => "if condition then\n\treturn\nend",
2330        empty_if_with_empty_elseif => "if true then\nelseif false then\nend\n",
2331        empty_if_with_two_empty_elseif => "if a then\nelseif b then\nelseif c then\n\tprint(c)\nend\n",
2332        empty_if_with_empty_else => "if true then\nelse\nend\n",
2333        empty_if_with_else_block => "if true then\n\t-- help\nelse\n\treturn\nend\n",
2334        declare_one_variable => "local var\n",
2335        declare_two_variables => "local var, var2\n",
2336        local_assign_one_variable => "local var = true",
2337        local_assign_two_variables => "local var, var2 = true, false",
2338        local_empty_function => "local function process()\nend",
2339        local_empty_variadic_function => "local function process(...)\nend",
2340        local_empty_function_with_one_argument => "local function process( a )\nend",
2341        local_empty_function_with_two_arguments => "local function process(a, b)\nend",
2342        local_empty_variadic_function_with_two_arguments => "local function process(a, b, ...)\nend",
2343        local_identity_function => "local function identity(...)\n\treturn ...\nend",
2344        empty_numeric_for => "for i = 1, final do\nend\n",
2345        empty_numeric_for_with_step => "for i = 1, final, step do\nend\n",
2346        numeric_for => "for i = 1, #list do\n\tprocess(list[i])\nend",
2347        empty_repeat => "repeat until false",
2348        repeat_break_immediately => "repeat break until false",
2349        empty_while => "while true do end",
2350        while_break_immediately => "while true do\n\tbreak\nend",
2351
2352        // last statements
2353        break_with_comment => "break -- exit loop",
2354        continue_with_comment => "continue -- skip to next iteration",
2355        empty_return => "return\n",
2356
2357        // expressions
2358        return_true => "return true",
2359        return_false => "return false",
2360        return_nil => "return nil",
2361        return_single_quote_string => "return 'ok'",
2362        return_double_quote_string => "return \"ok\"",
2363        return_identifier => "return var",
2364        return_bracket_string => "return [[   [ok]   ]]",
2365        return_empty_interpolated_string => "return ``",
2366        return_interpolated_string_escape_curly_brace => "return `Open: \\{`",
2367        return_interpolated_string_followed_by_comment => "return `ok` -- comment",
2368        return_interpolated_string_with_true_value => "return `{ true }`",
2369        return_interpolated_string_with_true_value_and_prefix => "return `Result = { true }`",
2370        return_interpolated_string_with_true_value_and_suffix => "return `{ variable } !`",
2371        return_interpolated_string_with_various_segments => "return `Variable = { variable } ({ --[[len]] #variable })` -- display",
2372        return_empty_table => "return { }",
2373        return_table_with_field => "return { field = {} }",
2374        return_table_with_index => "return { [field] = {} }",
2375        return_list_of_one_element => "return { true, }",
2376        return_list_of_two_elements => "return { true, false }",
2377        return_mixed_table => "return { true, field = false, [\"hello\"] = true }",
2378        return_parenthese_call => "return ( call() )",
2379        return_variable_arguments => "return ...",
2380        return_unary_minus => "return - number",
2381        return_unary_length => "return #list\n",
2382        return_unary_not => "return not condition\n",
2383        return_binary_and => "return a and b",
2384        return_binary_or => "return a or b",
2385        return_binary_plus => "return 10 + 15",
2386        return_empty_function => "return function() end",
2387        return_empty_variadic_function => "return function(...)\nend",
2388        return_empty_function_with_one_argument => "return function( a )\nend",
2389        return_empty_function_with_two_arguments => "return function(a, b)\nend",
2390        return_empty_variadic_function_with_two_arguments => "return function(a, b, ...)\nend",
2391        return_identity_function => "return function(...)\n\treturn ...\nend",
2392        return_field => "return math.huge",
2393        return_field_ending_with_number => "return UDim2.new",
2394        return_field_split_on_lines => "return value.\n\tproperty\n\t.name",
2395    );
2396
2397    #[test]
2398    fn inserts_a_new_line_after_a_comment_for_a_token() {
2399        let statement = RepeatStatement::new(Block::default(), true).with_tokens(RepeatTokens {
2400            repeat: Token::from_content("repeat")
2401                .with_trailing_trivia(TriviaKind::Comment.with_content("-- hello")),
2402            until: Token::from_content("until"),
2403        });
2404
2405        let mut generator = TokenBasedLuaGenerator::new("");
2406
2407        generator.write_repeat_statement(&statement);
2408
2409        let output = generator.into_string();
2410
2411        crate::Parser::default()
2412            .parse(&output)
2413            .unwrap_or_else(|_| panic!("failed to parse generated code `{}`", &output));
2414    }
2415
2416    #[test]
2417    fn inserts_a_new_line_after_custom_added_comments() {
2418        let code = "call(a--comment\n\t,b\n)";
2419        let mut block = crate::Parser::default()
2420            .preserve_tokens()
2421            .parse(code)
2422            .unwrap();
2423
2424        let call = match block.iter_mut_statements().last().unwrap() {
2425            Statement::Call(call) => call,
2426            _ => panic!("unexpected statement"),
2427        };
2428        let tuple = match call.mutate_arguments() {
2429            Arguments::Tuple(tuple) => tuple,
2430            _ => panic!("unexpected arguments"),
2431        };
2432        let mut tokens = tuple.get_tokens().unwrap().clone();
2433
2434        tuple.iter_mut_values().for_each(|value| match value {
2435            Expression::Identifier(identifier) => {
2436                let name = identifier.mutate_name();
2437                let new_token = {
2438                    Token::from_content(name.to_owned())
2439                        .with_trailing_trivia(TriviaKind::Comment.with_content("--new comment"))
2440                };
2441                identifier.set_token(new_token);
2442            }
2443            _ => panic!("unexpected expression"),
2444        });
2445
2446        // drop a comma and verify that the generator does not screw things up
2447        tokens.commas.pop();
2448        tuple.set_tokens(tokens);
2449
2450        let mut generator = TokenBasedLuaGenerator::new(code);
2451
2452        generator.write_block(&block);
2453
2454        let output = generator.into_string();
2455
2456        crate::Parser::default()
2457            .parse(&output)
2458            .unwrap_or_else(|_| panic!("failed to parse generated code `{}`", &output));
2459
2460        insta::assert_snapshot!("inserts_a_new_line_after_custom_added_comments", output);
2461    }
2462
2463    #[test]
2464    fn break_long_comments_on_new_lines() {
2465        let token = Token::from_content("")
2466            .with_leading_trivia(TriviaKind::Comment.with_content("-- first line"))
2467            .with_leading_trivia(TriviaKind::Comment.with_content("--[[\nnext comment ]]"));
2468        let block = Block::default().with_tokens(BlockTokens {
2469            semicolons: Default::default(),
2470            last_semicolon: Default::default(),
2471            final_token: Some(token),
2472        });
2473
2474        let mut generator = TokenBasedLuaGenerator::new("");
2475        generator.write_block(&block);
2476
2477        insta::assert_snapshot!(generator.into_string(), @r###"
2478        -- first line
2479        --[[
2480        next comment ]]
2481        "###);
2482    }
2483}