Skip to main content

darklua_core/generator/
readable.rs

1use crate::generator::{utils, LuaGenerator};
2use crate::nodes;
3
4#[derive(Debug, Clone, Copy, PartialEq, Eq)]
5enum StatementType {
6    Assign,
7    Do,
8    Call,
9    CompoundAssign,
10    Function,
11    GenericFor,
12    If,
13    LocalAssign,
14    LocalFunction,
15    NumericFor,
16    Repeat,
17    While,
18    TypeDeclaration,
19    TypeFunction,
20    Return,
21    Break,
22    Continue,
23}
24
25impl From<&nodes::Statement> for StatementType {
26    fn from(statement: &nodes::Statement) -> Self {
27        use nodes::Statement::*;
28        match statement {
29            Assign(_) => Self::Assign,
30            Do(_) => Self::Do,
31            Call(_) => Self::Call,
32            CompoundAssign(_) => Self::CompoundAssign,
33            Function(_) => Self::Function,
34            GenericFor(_) => Self::GenericFor,
35            If(_) => Self::If,
36            LocalAssign(_) => Self::LocalAssign,
37            LocalFunction(_) => Self::LocalFunction,
38            NumericFor(_) => Self::NumericFor,
39            Repeat(_) => Self::Repeat,
40            While(_) => Self::While,
41            TypeDeclaration(_) => Self::TypeDeclaration,
42            TypeFunction(_) => Self::TypeFunction,
43        }
44    }
45}
46
47impl From<&nodes::LastStatement> for StatementType {
48    fn from(statement: &nodes::LastStatement) -> Self {
49        use nodes::LastStatement::*;
50        match statement {
51            Break(_) => Self::Break,
52            Continue(_) => Self::Continue,
53            Return(_) => Self::Return,
54        }
55    }
56}
57
58/// This implementation of [LuaGenerator](trait.LuaGenerator.html) attempts to produce Lua code as
59/// readable as possible.
60#[derive(Debug, Clone)]
61pub struct ReadableLuaGenerator {
62    column_span: usize,
63    indentation: usize,
64    current_line_length: usize,
65    current_indentation: usize,
66    output: String,
67    last_push_length: usize,
68    can_add_new_line_stack: Vec<bool>,
69}
70
71impl ReadableLuaGenerator {
72    pub fn new(column_span: usize) -> Self {
73        Self {
74            column_span,
75            indentation: 4,
76            current_line_length: 0,
77            current_indentation: 0,
78            output: String::new(),
79            last_push_length: 0,
80            can_add_new_line_stack: Vec::new(),
81        }
82    }
83
84    #[inline]
85    fn can_add_new_line(&self) -> bool {
86        self.can_add_new_line_stack.last().copied().unwrap_or(true)
87    }
88
89    #[inline]
90    fn push_can_add_new_line(&mut self, value: bool) {
91        self.can_add_new_line_stack.push(value);
92    }
93
94    #[inline]
95    fn pop_can_add_new_line(&mut self) {
96        self.can_add_new_line_stack.pop();
97    }
98
99    #[inline]
100    fn push_indentation(&mut self) {
101        self.current_indentation += 1;
102    }
103
104    #[inline]
105    fn pop_indentation(&mut self) {
106        self.current_indentation -= 1;
107    }
108
109    #[inline]
110    fn write_indentation(&mut self) {
111        let indentation = " ".repeat(self.indentation * self.current_indentation);
112        self.raw_push_str(&indentation);
113    }
114
115    #[inline]
116    fn push_new_line(&mut self) {
117        self.output.push('\n');
118        self.current_line_length = 0;
119    }
120
121    #[inline]
122    fn fits_on_current_line(&self, length: usize) -> bool {
123        self.current_line_length + length <= self.column_span
124    }
125
126    #[inline]
127    fn push_space(&mut self) {
128        self.output.push(' ');
129        self.current_line_length += 1;
130    }
131
132    /// Appends a string to the current content of the LuaGenerator. A space may be added
133    /// depending of the last character of the current content and the first character pushed.
134    fn push_str(&mut self, content: &str) {
135        if let Some(next_char) = content.chars().next() {
136            self.push_space_if_needed(next_char, content.len());
137            self.raw_push_str(content);
138        }
139    }
140
141    /// Same as the `push_str` function, but for a single character.
142    fn push_char(&mut self, character: char) {
143        self.push_space_if_needed(character, 1);
144
145        self.output.push(character);
146        self.current_line_length += 1;
147        self.last_push_length = 1;
148    }
149
150    #[inline]
151    fn raw_push_str(&mut self, content: &str) {
152        self.output.push_str(content);
153        self.last_push_length = content.len();
154        self.current_line_length += self.last_push_length;
155    }
156
157    #[inline]
158    fn raw_push_char(&mut self, character: char) {
159        self.output.push(character);
160        self.last_push_length = 1;
161        self.current_line_length += 1;
162    }
163
164    #[inline]
165    fn needs_space(&self, next_character: char) -> bool {
166        if let Some(previous) = self.output.chars().last() {
167            utils::should_break_with_space(previous, next_character)
168        } else {
169            false
170        }
171    }
172
173    #[inline]
174    fn indent_and_write_block(&mut self, block: &nodes::Block) {
175        self.push_indentation();
176        self.write_block(block);
177        self.pop_indentation();
178    }
179
180    fn push_new_line_if_needed(&mut self, pushed_length: usize) {
181        if self.current_line_length == 0 && self.current_indentation != 0 {
182            self.write_indentation();
183        }
184
185        if self.can_add_new_line() {
186            if self.current_line_length >= self.column_span {
187                self.push_new_line();
188            } else {
189                let total_length = self.current_line_length + pushed_length;
190
191                if total_length > self.column_span {
192                    self.push_new_line();
193                }
194            }
195        }
196    }
197
198    fn push_space_if_needed(&mut self, next_character: char, pushed_length: usize) {
199        if self.current_line_length == 0 && self.current_indentation != 0 {
200            self.write_indentation();
201        }
202
203        if self.can_add_new_line() {
204            if self.current_line_length >= self.column_span {
205                self.push_new_line();
206            } else {
207                let total_length = self.current_line_length + pushed_length;
208
209                if self.needs_space(next_character) {
210                    if total_length + 1 > self.column_span {
211                        self.push_new_line();
212                    } else {
213                        self.push_space();
214                    }
215                } else if total_length > self.column_span {
216                    self.push_new_line();
217                }
218            }
219        } else if self.needs_space(next_character) {
220            self.push_space();
221        }
222    }
223
224    /// This function only insert a space or a new line if the given predicate returns true. In
225    /// the other case, the string is added to the current generator content.
226    fn push_str_and_break_if<F>(&mut self, content: &str, predicate: F)
227    where
228        F: Fn(&str) -> bool,
229    {
230        if predicate(self.get_last_push_str()) {
231            if self.fits_on_current_line(1 + content.len()) {
232                self.push_space();
233            } else {
234                self.push_new_line();
235            }
236        } else if !self.fits_on_current_line(content.len()) {
237            self.push_new_line();
238        }
239        self.raw_push_str(content);
240    }
241
242    fn get_last_push_str(&self) -> &str {
243        self.output
244            .get((self.output.len() - self.last_push_length)..)
245            .unwrap_or("")
246    }
247
248    fn table_fits_on_line(&self, entries: &[nodes::TableEntry], _width: usize) -> bool {
249        use nodes::TableEntry;
250
251        // small list of simple expressions
252        entries.len() < 4
253            && entries.iter().all(|entry| match entry {
254                TableEntry::Value(value) => self.is_small_expression(value),
255                _ => false,
256            })
257            || entries.len() == 1
258                && entries.iter().all(|entry| match entry {
259                    TableEntry::Field(entry) => self.is_small_expression(entry.get_value()),
260                    TableEntry::Index(entry) => {
261                        self.is_small_expression(entry.get_key())
262                            && self.is_small_expression(entry.get_value())
263                    }
264                    _ => false,
265                })
266    }
267
268    fn is_small_expression(&self, expression: &nodes::Expression) -> bool {
269        use nodes::Expression::*;
270        match expression {
271            True(_) | False(_) | Nil(_) | Identifier(_) | VariableArguments(_) | Number(_) => true,
272            Table(table) => table.is_empty(),
273            _ => false,
274        }
275    }
276
277    fn write_attributes(&mut self, attributes: &nodes::Attributes) {
278        use nodes::Attribute;
279
280        for attribute in attributes.iter_attributes() {
281            match attribute {
282                Attribute::Name(named) => {
283                    let name = named.get_identifier().get_name();
284
285                    self.push_space_if_needed('@', 1 + name.len());
286                    self.raw_push_char('@');
287                    self.raw_push_str(name);
288                    self.push_new_line();
289                }
290                Attribute::Group(group) => {
291                    if !group.is_empty() {
292                        self.push_str("@[");
293
294                        let last_index = group.len().saturating_sub(1);
295
296                        for (index, attribute) in group.iter_attributes().enumerate() {
297                            self.push_str(attribute.name().get_name());
298
299                            if let Some(arguments) = attribute.get_arguments() {
300                                self.write_attribute_arguments(arguments);
301                            }
302
303                            if index != last_index {
304                                self.push_char(',');
305                                self.push_char(' ');
306                            }
307                        }
308
309                        self.push_char(']');
310                        self.push_new_line();
311                    }
312                }
313            }
314        }
315    }
316
317    fn write_function_parameters(
318        &mut self,
319        parameters: &[nodes::TypedIdentifier],
320        is_variadic: bool,
321        variadic_type: Option<&nodes::FunctionVariadicType>,
322    ) {
323        let mut parameters_length = parameters.iter().fold(0, |acc, parameter| {
324            acc + parameter.get_name().len()
325                + if parameter.has_type() {
326                    // put a random estimation of the type probable length
327                    10
328                } else {
329                    0
330                }
331        });
332        // add a comma and a space between each parameter
333        parameters_length += parameters.len() * 2;
334
335        if is_variadic {
336            // add the variadic argument symbol `...`
337            parameters_length += 3;
338            if parameters.len() > 1 {
339                // add comma and space if needed
340                parameters_length += 2;
341            }
342        }
343
344        let last_index = parameters.len().saturating_sub(1);
345
346        if self.fits_on_current_line(parameters_length) {
347            parameters.iter().enumerate().for_each(|(index, variable)| {
348                self.write_typed_identifier(variable);
349
350                if index != last_index {
351                    self.raw_push_char(',');
352                    self.raw_push_char(' ');
353                }
354            });
355
356            if is_variadic {
357                if !parameters.is_empty() {
358                    self.raw_push_char(',');
359                    self.raw_push_char(' ');
360                };
361                self.raw_push_str("...");
362
363                if let Some(variadic_type) = variadic_type {
364                    self.raw_push_char(':');
365                    self.raw_push_char(' ');
366                    self.write_function_variadic_type(r#variadic_type);
367                }
368            };
369        } else {
370            self.push_indentation();
371
372            parameters.iter().enumerate().for_each(|(index, variable)| {
373                self.push_new_line();
374                self.write_indentation();
375                self.write_typed_identifier(variable);
376
377                if index != last_index {
378                    self.raw_push_char(',');
379                }
380            });
381
382            if is_variadic {
383                if !parameters.is_empty() {
384                    self.raw_push_char(',');
385                };
386                self.push_new_line();
387                self.write_indentation();
388                self.raw_push_str("...");
389
390                if let Some(variadic_type) = variadic_type {
391                    self.raw_push_char(':');
392                    self.raw_push_char(' ');
393                    self.write_function_variadic_type(r#variadic_type);
394                }
395            };
396
397            self.pop_indentation();
398            self.push_new_line();
399            self.write_indentation();
400        }
401    }
402
403    fn write_variable(&mut self, variable: &nodes::Variable) {
404        use nodes::Variable::*;
405        match variable {
406            Identifier(identifier) => self.push_str(identifier.get_name()),
407            Field(field) => self.write_field(field),
408            Index(index) => self.write_index(index),
409        }
410    }
411
412    fn write_typed_identifier(&mut self, typed_identifier: &nodes::TypedIdentifier) {
413        self.push_str(typed_identifier.get_name());
414
415        if let Some(r#type) = typed_identifier.get_type() {
416            self.push_char(':');
417            self.push_space();
418            self.write_type(r#type);
419        }
420    }
421
422    fn write_function_return_type(&mut self, return_type: &nodes::FunctionReturnType) {
423        match return_type {
424            nodes::FunctionReturnType::Type(r#type) => self.write_type(r#type),
425            nodes::FunctionReturnType::TypePack(type_pack) => self.write_type_pack(type_pack),
426            nodes::FunctionReturnType::VariadicTypePack(variadic_type_pack) => {
427                self.write_variadic_type_pack(variadic_type_pack);
428            }
429            nodes::FunctionReturnType::GenericTypePack(generic_type_pack) => {
430                self.write_generic_type_pack(generic_type_pack);
431            }
432        }
433    }
434
435    fn write_function_return_type_suffix(&mut self, return_type: &nodes::FunctionReturnType) {
436        self.raw_push_char(':');
437        self.raw_push_char(' ');
438        self.write_function_return_type(return_type);
439    }
440
441    fn write_expression_in_parentheses(&mut self, expression: &nodes::Expression) {
442        self.push_char('(');
443        self.write_expression(expression);
444        self.push_char(')');
445    }
446
447    fn write_type_in_parentheses(&mut self, r#type: &nodes::Type) {
448        self.push_char('(');
449        self.write_type(r#type);
450        self.push_char(')');
451    }
452
453    fn write_function_generics(&mut self, generics: &nodes::GenericParameters) {
454        if generics.is_empty() {
455            return;
456        }
457        self.push_char('<');
458        let mut write_comma = false;
459        for type_variable in generics.iter_type_variable() {
460            if write_comma {
461                self.push_char(',');
462                self.push_char(' ');
463            } else {
464                write_comma = true;
465            }
466            self.write_identifier(type_variable);
467        }
468        for generic_pack in generics.iter_generic_type_pack() {
469            if write_comma {
470                self.push_char(',');
471                self.push_char(' ');
472            } else {
473                write_comma = true;
474            }
475            self.write_generic_type_pack(generic_pack);
476        }
477        self.push_char('>');
478    }
479}
480
481impl Default for ReadableLuaGenerator {
482    fn default() -> Self {
483        Self::new(80)
484    }
485}
486
487impl LuaGenerator for ReadableLuaGenerator {
488    fn into_string(self) -> String {
489        self.output
490    }
491
492    fn write_block(&mut self, block: &nodes::Block) {
493        let mut statements = block.iter_statements().peekable();
494
495        while let Some(statement) = statements.next() {
496            let current_type: StatementType = statement.into();
497
498            self.push_can_add_new_line(false);
499            self.write_statement(statement);
500
501            if let Some(next_statement) = statements.peek() {
502                if utils::starts_with_parenthese(next_statement)
503                    && utils::ends_with_prefix(statement)
504                {
505                    self.push_char(';');
506                }
507
508                if current_type != (*next_statement).into() {
509                    self.push_new_line();
510                }
511            }
512
513            self.pop_can_add_new_line();
514            self.push_new_line();
515        }
516
517        if let Some(last_statement) = block.get_last_statement() {
518            if block.iter_statements().next().is_some() {
519                self.push_new_line();
520            }
521            self.write_last_statement(last_statement);
522            self.push_new_line();
523        }
524    }
525
526    fn write_last_statement(&mut self, statement: &nodes::LastStatement) {
527        use nodes::LastStatement::*;
528
529        match statement {
530            Break(_) => self.push_str("break"),
531            Continue(_) => self.push_str("continue"),
532            Return(expressions) => {
533                self.push_str("return");
534                self.push_can_add_new_line(false);
535                let last_index = expressions.len().saturating_sub(1);
536
537                if !expressions.is_empty() {
538                    self.raw_push_char(' ');
539                }
540
541                expressions
542                    .iter_expressions()
543                    .enumerate()
544                    .for_each(|(index, expression)| {
545                        self.write_expression(expression);
546
547                        if index != last_index {
548                            self.raw_push_char(',');
549                            self.raw_push_char(' ');
550                        }
551                    });
552
553                self.pop_can_add_new_line();
554            }
555        }
556    }
557
558    fn write_assign_statement(&mut self, assign: &nodes::AssignStatement) {
559        self.push_can_add_new_line(false);
560
561        let variables = assign.get_variables();
562        let last_variable_index = variables.len() - 1;
563        variables.iter().enumerate().for_each(|(index, variable)| {
564            self.write_variable(variable);
565
566            if index != last_variable_index {
567                self.raw_push_char(',');
568                self.raw_push_char(' ');
569            }
570        });
571
572        self.raw_push_str(" = ");
573
574        let last_value_index = assign.values_len() - 1;
575        assign.iter_values().enumerate().for_each(|(index, value)| {
576            self.write_expression(value);
577
578            if index != last_value_index {
579                self.raw_push_char(',');
580                self.raw_push_char(' ');
581            }
582        });
583
584        self.pop_can_add_new_line();
585    }
586
587    fn write_local_assign(&mut self, assign: &nodes::VariableAssignment) {
588        self.push_str(assign.get_assignment_kind().as_keyword());
589        self.push_space();
590
591        self.push_can_add_new_line(false);
592
593        let variables_length = assign.variables_len();
594        let last_variable_index = variables_length.saturating_sub(1);
595
596        for (index, variable) in assign.iter_variables().enumerate() {
597            self.write_typed_identifier(variable);
598
599            if index != last_variable_index {
600                self.raw_push_char(',');
601                self.raw_push_char(' ');
602            }
603        }
604
605        // const assignments must have at least one variable per value, so it may need
606        // additional variables
607        for i in 0..assign.required_new_variables() {
608            if i != 0 || variables_length > 0 {
609                self.push_char(',');
610            }
611            utils::THROWAWAY_IDENTIFIER.with(|identifier| {
612                self.write_typed_identifier(identifier);
613            });
614        }
615
616        // const assignments must have a value for each variable, so it may need additional
617        // nil values
618        let required_nil_values = assign.required_nil_values();
619
620        let has_values = assign.has_values();
621
622        if has_values || required_nil_values > 0 {
623            self.raw_push_str(" = ");
624
625            let last_value_index = assign.values_len().saturating_sub(1);
626
627            for (index, value) in assign.iter_values().enumerate() {
628                self.write_expression(value);
629
630                if index != last_value_index {
631                    self.raw_push_char(',');
632                    self.raw_push_char(' ');
633                }
634            }
635
636            for i in 0..required_nil_values {
637                if i != 0 || has_values {
638                    self.push_char(',');
639                }
640                utils::NIL_EXPRESSION.with(|nil| {
641                    self.write_expression(nil);
642                })
643            }
644        };
645
646        self.pop_can_add_new_line();
647    }
648
649    fn write_compound_assign(&mut self, assign: &nodes::CompoundAssignStatement) {
650        self.push_can_add_new_line(false);
651
652        self.write_variable(assign.get_variable());
653
654        self.raw_push_char(' ');
655        self.raw_push_str(assign.get_operator().to_str());
656        self.push_space();
657
658        self.write_expression(assign.get_value());
659
660        self.pop_can_add_new_line();
661    }
662
663    fn write_local_function(&mut self, function: &nodes::FunctionAssignment) {
664        self.write_attributes(function.attributes());
665
666        self.push_str(function.get_assignment_kind().as_keyword());
667        self.push_str(" function ");
668        self.raw_push_str(function.get_name());
669
670        if let Some(generics) = function.get_generic_parameters() {
671            self.write_function_generics(generics);
672        }
673
674        self.raw_push_char('(');
675
676        let parameters = function.get_parameters();
677        self.write_function_parameters(
678            parameters,
679            function.is_variadic(),
680            function.get_variadic_type(),
681        );
682        self.raw_push_char(')');
683
684        if let Some(return_type) = function.get_return_type() {
685            self.write_function_return_type_suffix(return_type);
686        }
687
688        let block = function.get_block();
689
690        if block.is_empty() {
691            self.raw_push_str(" end");
692        } else {
693            self.push_new_line();
694            self.indent_and_write_block(block);
695            self.push_str("end");
696        }
697    }
698
699    fn write_generic_for(&mut self, generic_for: &nodes::GenericForStatement) {
700        self.push_str("for ");
701
702        let identifiers = generic_for.get_identifiers();
703        let last_identifier_index = identifiers.len().saturating_sub(1);
704        identifiers
705            .iter()
706            .enumerate()
707            .for_each(|(index, identifier)| {
708                self.write_typed_identifier(identifier);
709
710                if index != last_identifier_index {
711                    self.raw_push_char(',');
712                    self.raw_push_char(' ');
713                }
714            });
715
716        self.raw_push_str(" in ");
717
718        let expressions = generic_for.get_expressions();
719        let last_expression_index = expressions.len().saturating_sub(1);
720        expressions
721            .iter()
722            .enumerate()
723            .for_each(|(index, expression)| {
724                self.write_expression(expression);
725
726                if index != last_expression_index {
727                    self.raw_push_char(',');
728                    self.raw_push_char(' ');
729                }
730            });
731
732        let block = generic_for.get_block();
733
734        if block.is_empty() {
735            self.raw_push_str(" do end");
736        } else {
737            self.push_str("do");
738            self.push_new_line();
739            self.indent_and_write_block(block);
740            self.push_str("end");
741        }
742    }
743
744    fn write_numeric_for(&mut self, numeric_for: &nodes::NumericForStatement) {
745        self.push_str("for ");
746
747        self.write_typed_identifier(numeric_for.get_identifier());
748        self.raw_push_char(' ');
749        self.raw_push_char('=');
750        self.raw_push_char(' ');
751        self.write_expression(numeric_for.get_start());
752        self.raw_push_char(',');
753        self.raw_push_char(' ');
754        self.write_expression(numeric_for.get_end());
755
756        if let Some(step) = numeric_for.get_step() {
757            self.raw_push_char(',');
758            self.raw_push_char(' ');
759            self.write_expression(step);
760        }
761
762        let block = numeric_for.get_block();
763
764        if block.is_empty() {
765            self.raw_push_str(" do end");
766        } else {
767            self.push_str("do");
768            self.push_new_line();
769            self.indent_and_write_block(block);
770            self.push_str("end");
771        }
772    }
773
774    fn write_if_statement(&mut self, if_statement: &nodes::IfStatement) {
775        let branches = if_statement.get_branches();
776
777        branches.iter().enumerate().for_each(|(index, branch)| {
778            if index == 0 {
779                self.push_str("if ");
780            } else {
781                self.push_str("elseif ");
782            }
783
784            self.write_expression(branch.get_condition());
785            self.raw_push_str(" then");
786            self.push_new_line();
787            self.indent_and_write_block(branch.get_block());
788        });
789
790        if let Some(else_block) = if_statement.get_else_block() {
791            self.push_str("else");
792            self.push_new_line();
793            self.indent_and_write_block(else_block);
794        }
795
796        self.push_str("end");
797    }
798
799    fn write_function_statement(&mut self, function: &nodes::FunctionStatement) {
800        self.write_attributes(function.attributes());
801        self.push_str("function ");
802        let name = function.get_name();
803
804        self.raw_push_str(name.get_name().get_name());
805        name.get_field_names().iter().for_each(|field| {
806            self.raw_push_char('.');
807            self.raw_push_str(field.get_name());
808        });
809
810        if let Some(method) = name.get_method() {
811            self.raw_push_char(':');
812            self.raw_push_str(method.get_name());
813        }
814
815        if let Some(generics) = function.get_generic_parameters() {
816            self.write_function_generics(generics);
817        }
818
819        self.raw_push_char('(');
820        self.write_function_parameters(
821            function.get_parameters(),
822            function.is_variadic(),
823            function.get_variadic_type(),
824        );
825        self.raw_push_char(')');
826
827        if let Some(return_type) = function.get_return_type() {
828            self.write_function_return_type_suffix(return_type);
829        }
830
831        let block = function.get_block();
832
833        if block.is_empty() {
834            self.raw_push_str(" end");
835        } else {
836            self.push_new_line();
837            self.indent_and_write_block(block);
838            self.push_str("end");
839        }
840    }
841
842    fn write_do_statement(&mut self, do_statement: &nodes::DoStatement) {
843        let block = do_statement.get_block();
844
845        if block.is_empty() {
846            self.push_str("do end");
847        } else {
848            self.push_str("do");
849            self.push_new_line();
850            self.indent_and_write_block(block);
851            self.push_str("end");
852        }
853    }
854
855    fn write_repeat_statement(&mut self, repeat: &nodes::RepeatStatement) {
856        self.push_str("repeat");
857
858        let block = repeat.get_block();
859
860        if block.is_empty() {
861            self.raw_push_str(" until ");
862        } else {
863            self.push_new_line();
864            self.indent_and_write_block(block);
865            self.push_str("until ");
866        }
867
868        self.write_expression(repeat.get_condition());
869    }
870
871    fn write_while_statement(&mut self, while_statement: &nodes::WhileStatement) {
872        self.push_str("while");
873        self.push_can_add_new_line(false);
874        self.write_expression(while_statement.get_condition());
875        self.pop_can_add_new_line();
876
877        let block = while_statement.get_block();
878
879        if block.is_empty() {
880            self.raw_push_str(" do end");
881        } else {
882            self.raw_push_str(" do");
883            self.push_new_line();
884            self.indent_and_write_block(block);
885            self.push_str("end");
886        }
887    }
888
889    fn write_type_declaration_statement(&mut self, statement: &nodes::TypeDeclarationStatement) {
890        if statement.is_exported() {
891            self.push_str("export");
892        }
893        self.push_can_add_new_line(false);
894        self.push_str("type");
895
896        self.write_identifier(statement.get_name());
897
898        if let Some(generic_parameters) = statement
899            .get_generic_parameters()
900            .filter(|generic_parameters| !generic_parameters.is_empty())
901        {
902            self.push_char('<');
903            let last_index = generic_parameters.len().saturating_sub(1);
904            for (i, parameter) in generic_parameters.iter().enumerate() {
905                use nodes::GenericParameterRef;
906
907                match parameter {
908                    GenericParameterRef::TypeVariable(identifier) => {
909                        self.write_identifier(identifier);
910                    }
911                    GenericParameterRef::TypeVariableWithDefault(identifier_with_default) => {
912                        self.write_identifier(identifier_with_default.get_type_variable());
913                        self.push_char('=');
914                        self.write_type(identifier_with_default.get_default_type());
915                    }
916                    GenericParameterRef::GenericTypePack(generic_type_pack) => {
917                        self.write_generic_type_pack(generic_type_pack);
918                    }
919                    GenericParameterRef::GenericTypePackWithDefault(generic_pack_with_default) => {
920                        self.write_generic_type_pack(
921                            generic_pack_with_default.get_generic_type_pack(),
922                        );
923                        self.push_char('=');
924                        self.write_generic_type_pack_default(
925                            generic_pack_with_default.get_default_type(),
926                        );
927                    }
928                }
929
930                if i != last_index {
931                    self.push_char(',');
932                    self.push_char(' ');
933                }
934            }
935            self.push_char('>');
936        }
937
938        self.push_char(' ');
939        self.push_char('=');
940        self.push_char(' ');
941
942        self.pop_can_add_new_line();
943
944        self.write_type(statement.get_type());
945    }
946
947    fn write_type_function_statement(&mut self, function: &nodes::TypeFunctionStatement) {
948        self.push_can_add_new_line(false);
949        if function.is_exported() {
950            self.push_str("export");
951        }
952        self.push_str("type function ");
953        self.write_identifier(function.get_identifier());
954
955        if let Some(generics) = function.get_generic_parameters() {
956            self.write_function_generics(generics);
957        }
958
959        self.raw_push_char('(');
960
961        self.pop_can_add_new_line();
962
963        let parameters = function.get_parameters();
964        self.write_function_parameters(
965            parameters,
966            function.is_variadic(),
967            function.get_variadic_type(),
968        );
969        self.raw_push_char(')');
970
971        if let Some(return_type) = function.get_return_type() {
972            self.write_function_return_type_suffix(return_type);
973        }
974
975        let block = function.get_block();
976
977        if block.is_empty() {
978            self.raw_push_str(" end");
979        } else {
980            self.push_new_line();
981            self.indent_and_write_block(block);
982            self.push_str("end");
983        }
984    }
985
986    fn write_false_expression(&mut self, _token: &Option<nodes::Token>) {
987        self.push_str("false");
988    }
989
990    fn write_true_expression(&mut self, _token: &Option<nodes::Token>) {
991        self.push_str("true");
992    }
993
994    fn write_nil_expression(&mut self, _token: &Option<nodes::Token>) {
995        self.push_str("nil");
996    }
997
998    fn write_variable_arguments_expression(&mut self, _token: &Option<nodes::Token>) {
999        self.push_str_and_break_if("...", utils::break_variable_arguments);
1000    }
1001
1002    fn write_binary_expression(&mut self, binary: &nodes::BinaryExpression) {
1003        let operator = binary.operator();
1004        let left = binary.left();
1005        let right = binary.right();
1006
1007        if operator.left_needs_parentheses(left) {
1008            self.write_expression_in_parentheses(left);
1009        } else {
1010            self.write_expression(left);
1011        }
1012
1013        self.push_space();
1014        self.push_str(binary.operator().to_str());
1015        self.push_space();
1016
1017        if operator.right_needs_parentheses(right) {
1018            self.write_expression_in_parentheses(right);
1019        } else {
1020            self.write_expression(right);
1021        }
1022    }
1023
1024    fn write_unary_expression(&mut self, unary: &nodes::UnaryExpression) {
1025        use nodes::{Expression, UnaryOperator::*};
1026
1027        match unary.operator() {
1028            Length => self.push_char('#'),
1029            Minus => self.push_str_and_break_if("-", utils::break_minus),
1030            Not => self.push_str("not "),
1031        }
1032
1033        let expression = unary.get_expression();
1034
1035        match expression {
1036            Expression::Binary(binary) if !binary.operator().precedes_unary_expression() => {
1037                self.write_expression_in_parentheses(expression);
1038            }
1039            _ => self.write_expression(expression),
1040        }
1041    }
1042
1043    fn write_function(&mut self, function: &nodes::FunctionExpression) {
1044        self.push_can_add_new_line(false);
1045        self.write_attributes(function.attributes());
1046        self.pop_can_add_new_line();
1047        self.push_str("function");
1048
1049        if let Some(generics) = function.get_generic_parameters() {
1050            self.write_function_generics(generics);
1051        }
1052
1053        self.push_char('(');
1054
1055        let parameters = function.get_parameters();
1056        self.write_function_parameters(
1057            parameters,
1058            function.is_variadic(),
1059            function.get_variadic_type(),
1060        );
1061        self.raw_push_char(')');
1062
1063        if let Some(return_type) = function.get_return_type() {
1064            self.write_function_return_type_suffix(return_type);
1065        }
1066
1067        let block = function.get_block();
1068
1069        if block.is_empty() {
1070            self.raw_push_str(" end");
1071        } else {
1072            self.push_new_line();
1073            self.indent_and_write_block(block);
1074            self.push_str("end");
1075        }
1076    }
1077
1078    fn write_function_call(&mut self, call: &nodes::FunctionCall) {
1079        self.push_can_add_new_line(false);
1080        self.write_prefix(call.get_prefix());
1081
1082        if let Some(method) = &call.get_method() {
1083            self.push_char(':');
1084            self.push_str(method.get_name());
1085        }
1086
1087        self.write_arguments(call.get_arguments());
1088
1089        self.pop_can_add_new_line();
1090    }
1091
1092    fn write_tuple_arguments(&mut self, arguments: &nodes::TupleArguments) {
1093        self.raw_push_char('(');
1094
1095        let last_index = arguments.len().saturating_sub(1);
1096        arguments
1097            .iter_values()
1098            .enumerate()
1099            .for_each(|(index, expression)| {
1100                self.write_expression(expression);
1101
1102                if index != last_index {
1103                    self.raw_push_char(',');
1104                    self.raw_push_char(' ');
1105                }
1106            });
1107
1108        self.push_char(')');
1109    }
1110
1111    fn write_field(&mut self, field: &nodes::FieldExpression) {
1112        self.push_can_add_new_line(false);
1113        self.write_prefix(field.get_prefix());
1114        self.pop_can_add_new_line();
1115
1116        self.push_new_line_if_needed(1);
1117        self.raw_push_char('.');
1118        self.raw_push_str(field.get_field().get_name());
1119    }
1120
1121    fn write_index(&mut self, index: &nodes::IndexExpression) {
1122        self.push_can_add_new_line(false);
1123
1124        self.write_prefix(index.get_prefix());
1125
1126        self.push_char('[');
1127        self.write_expression(index.get_index());
1128        self.push_char(']');
1129
1130        self.pop_can_add_new_line();
1131    }
1132
1133    fn write_if_expression(&mut self, if_expression: &nodes::IfExpression) {
1134        self.push_str("if");
1135        self.write_expression(if_expression.get_condition());
1136
1137        if if_expression.has_elseif_branch() {
1138            self.push_indentation();
1139
1140            self.push_new_line();
1141            self.write_indentation();
1142            self.push_str("then");
1143            self.write_expression(if_expression.get_result());
1144
1145            for branch in if_expression.iter_branches() {
1146                self.push_new_line();
1147                self.write_indentation();
1148                self.push_str("elseif");
1149                self.write_expression(branch.get_condition());
1150
1151                self.push_new_line();
1152                self.write_indentation();
1153                self.push_str("then");
1154                self.write_expression(branch.get_result());
1155            }
1156
1157            self.push_new_line();
1158            self.write_indentation();
1159            self.push_str("else");
1160            self.write_expression(if_expression.get_else_result());
1161
1162            self.pop_indentation();
1163        } else {
1164            self.push_str("then");
1165            self.write_expression(if_expression.get_result());
1166            self.push_str("else");
1167            self.write_expression(if_expression.get_else_result());
1168        }
1169    }
1170
1171    fn write_table(&mut self, table: &nodes::TableExpression) {
1172        self.push_char('{');
1173
1174        let entries = table.get_entries();
1175        let table_len = entries.len();
1176
1177        if table_len == 0 {
1178            self.raw_push_char('}');
1179        } else {
1180            let column_space = self.column_span.saturating_sub(self.current_line_length);
1181            if self.table_fits_on_line(entries, column_space) {
1182                let last_index = table_len.saturating_sub(1);
1183
1184                entries.iter().enumerate().for_each(|(index, entry)| {
1185                    self.write_table_entry(entry);
1186
1187                    if index != last_index {
1188                        self.raw_push_char(',');
1189                        self.raw_push_char(' ');
1190                    }
1191                });
1192            } else {
1193                self.push_indentation();
1194
1195                entries.iter().for_each(|entry| {
1196                    self.push_new_line();
1197                    self.write_indentation();
1198                    self.write_table_entry(entry);
1199
1200                    self.raw_push_char(',');
1201                });
1202
1203                self.pop_indentation();
1204                self.push_new_line();
1205            }
1206
1207            self.push_char('}');
1208        }
1209    }
1210
1211    fn write_table_entry(&mut self, entry: &nodes::TableEntry) {
1212        match entry {
1213            nodes::TableEntry::Field(entry) => {
1214                self.raw_push_str(entry.get_field().get_name());
1215                self.raw_push_str(" = ");
1216                self.write_expression(entry.get_value());
1217            }
1218            nodes::TableEntry::Index(entry) => {
1219                self.raw_push_char('[');
1220                self.push_can_add_new_line(false);
1221                self.write_expression(entry.get_key());
1222                self.pop_can_add_new_line();
1223                self.raw_push_str("] = ");
1224                self.write_expression(entry.get_value());
1225            }
1226            nodes::TableEntry::Value(expression) => self.write_expression(expression),
1227        }
1228    }
1229
1230    fn write_number(&mut self, number: &nodes::NumberExpression) {
1231        self.push_str(&utils::write_number(number));
1232    }
1233
1234    fn write_string(&mut self, string: &nodes::StringExpression) {
1235        let result = utils::write_string(string.get_value());
1236        if result.starts_with('[') {
1237            self.push_str_and_break_if(&result, utils::break_long_string);
1238        } else {
1239            self.push_str(&result);
1240        }
1241    }
1242
1243    fn write_interpolated_string(
1244        &mut self,
1245        interpolated_string: &nodes::InterpolatedStringExpression,
1246    ) {
1247        self.push_char('`');
1248
1249        for segment in interpolated_string.iter_segments() {
1250            match segment {
1251                nodes::InterpolationSegment::String(string_segment) => {
1252                    self.raw_push_str(&utils::write_interpolated_string_segment(string_segment));
1253                }
1254                nodes::InterpolationSegment::Value(value) => {
1255                    self.raw_push_char('{');
1256                    // add space when value segment is a table
1257                    let expression = value.get_expression();
1258                    if utils::starts_with_table(expression).is_some() {
1259                        self.raw_push_char(' ');
1260                    }
1261                    self.write_expression(expression);
1262                    self.push_char('}');
1263                }
1264            }
1265        }
1266
1267        self.raw_push_char('`');
1268    }
1269
1270    fn write_literal_table(&mut self, table: &nodes::LiteralTable) {
1271        self.push_char('{');
1272        let last_index = table.len().saturating_sub(1);
1273        for (index, entry) in table.iter_entries().enumerate() {
1274            self.write_literal_table_entry(entry);
1275            if index != last_index {
1276                self.push_char(',');
1277            }
1278        }
1279        self.push_char('}');
1280    }
1281
1282    fn write_literal_table_entry(&mut self, entry: &nodes::LiteralTableEntry) {
1283        use nodes::LiteralTableEntry::*;
1284
1285        self.push_can_add_new_line(false);
1286
1287        match entry {
1288            Field(field) => {
1289                self.write_identifier(field.get_field());
1290                self.push_char('=');
1291                self.write_literal_expression(field.get_value());
1292            }
1293            Value(value) => {
1294                self.write_literal_expression(value);
1295            }
1296        }
1297
1298        self.pop_can_add_new_line();
1299    }
1300
1301    fn write_attribute_tuple_arguments(&mut self, tuple: &nodes::AttributeTupleArguments) {
1302        self.push_char('(');
1303        self.push_can_add_new_line(false);
1304
1305        let last_index = tuple.len().saturating_sub(1);
1306        for (index, value) in tuple.iter_values().enumerate() {
1307            self.write_literal_expression(value);
1308            if index != last_index {
1309                self.push_char(',');
1310                self.push_char(' ');
1311            }
1312        }
1313
1314        self.pop_can_add_new_line();
1315        self.push_char(')');
1316    }
1317
1318    fn write_identifier(&mut self, identifier: &nodes::Identifier) {
1319        self.push_str(identifier.get_name());
1320    }
1321
1322    fn write_parenthese(&mut self, parenthese: &nodes::ParentheseExpression) {
1323        self.push_char('(');
1324        self.push_can_add_new_line(false);
1325
1326        self.write_expression(parenthese.inner_expression());
1327
1328        self.pop_can_add_new_line();
1329        self.push_char(')');
1330    }
1331
1332    fn write_type_cast(&mut self, type_cast: &nodes::TypeCastExpression) {
1333        let inner_expression = type_cast.get_expression();
1334
1335        if nodes::TypeCastExpression::needs_parentheses(inner_expression) {
1336            self.push_char('(');
1337            self.push_can_add_new_line(false);
1338            self.write_expression(inner_expression);
1339            self.pop_can_add_new_line();
1340            self.push_char(')');
1341        } else {
1342            self.write_expression(inner_expression);
1343        }
1344
1345        self.push_can_add_new_line(false);
1346        self.push_str("::");
1347        self.write_type(type_cast.get_type());
1348        self.pop_can_add_new_line();
1349    }
1350
1351    fn write_type_instantiation(
1352        &mut self,
1353        type_instantiation: &nodes::TypeInstantiationExpression,
1354    ) {
1355        self.write_prefix(type_instantiation.get_prefix());
1356        self.push_can_add_new_line(false);
1357
1358        self.push_str("<<");
1359
1360        let last_index = type_instantiation.types_len().saturating_sub(1);
1361        for (index, r#type) in type_instantiation.iter_types().enumerate() {
1362            self.write_type(r#type);
1363            if index != last_index {
1364                self.push_char(',');
1365            }
1366        }
1367
1368        self.push_str(">>");
1369
1370        self.pop_can_add_new_line();
1371    }
1372
1373    fn write_type_name(&mut self, type_name: &nodes::TypeName) {
1374        self.write_identifier(type_name.get_type_name());
1375        if let Some(parameters) = type_name.get_type_parameters() {
1376            self.push_char('<');
1377            self.push_can_add_new_line(false);
1378            let last_index = parameters.len().saturating_sub(1);
1379            for (index, parameter) in parameters.iter().enumerate() {
1380                self.write_type_parameter(parameter);
1381                if index != last_index {
1382                    self.push_char(',');
1383                    self.push_char(' ');
1384                }
1385            }
1386
1387            self.pop_can_add_new_line();
1388            self.push_char('>');
1389        }
1390    }
1391
1392    fn write_type_field(&mut self, type_field: &nodes::TypeField) {
1393        self.write_identifier(type_field.get_namespace());
1394        self.push_new_line_if_needed(1);
1395        self.raw_push_char('.');
1396        self.write_type_name(type_field.get_type_name());
1397    }
1398
1399    fn write_true_type(&mut self, _: &Option<nodes::Token>) {
1400        self.push_str("true");
1401    }
1402
1403    fn write_false_type(&mut self, _: &Option<nodes::Token>) {
1404        self.push_str("false");
1405    }
1406
1407    fn write_nil_type(&mut self, _: &Option<nodes::Token>) {
1408        self.push_str("nil");
1409    }
1410
1411    fn write_string_type(&mut self, string_type: &nodes::StringType) {
1412        let result = utils::write_string(string_type.get_value());
1413        if result.starts_with('[') {
1414            self.push_str_and_break_if(&result, utils::break_long_string);
1415        } else {
1416            self.push_str(&result);
1417        }
1418    }
1419
1420    fn write_array_type(&mut self, array: &nodes::ArrayType) {
1421        self.push_char('{');
1422        self.write_type(array.get_element_type());
1423        self.push_char('}');
1424    }
1425
1426    fn write_table_type(&mut self, table_type: &nodes::TableType) {
1427        self.push_char('{');
1428
1429        let last_index = table_type.len().saturating_sub(1);
1430        for (index, property) in table_type.iter_entries().enumerate() {
1431            if let Some(modifier) = property.get_modifier() {
1432                match modifier {
1433                    nodes::TablePropertyModifier::Read => self.push_str("read"),
1434                    nodes::TablePropertyModifier::Write => self.push_str("write"),
1435                }
1436                self.push_char(' ');
1437            }
1438
1439            match property {
1440                nodes::TableEntryType::Property(property) => {
1441                    self.write_identifier(property.get_identifier());
1442                    self.push_char(':');
1443                    self.push_char(' ');
1444                    self.write_type(property.get_type());
1445                }
1446                nodes::TableEntryType::Literal(property) => {
1447                    self.push_char('[');
1448                    self.write_string_type(property.get_string());
1449                    self.push_char(']');
1450                    self.push_char(':');
1451                    self.push_char(' ');
1452                    self.write_type(property.get_type());
1453                }
1454                nodes::TableEntryType::Indexer(indexer) => {
1455                    self.push_char('[');
1456
1457                    let key_type = indexer.get_key_type();
1458
1459                    let need_parentheses = matches!(
1460                        key_type,
1461                        nodes::Type::Optional(_)
1462                            | nodes::Type::Intersection(_)
1463                            | nodes::Type::Union(_)
1464                    );
1465
1466                    if need_parentheses {
1467                        self.push_char('(');
1468                        self.write_type(key_type);
1469                        self.push_char(')');
1470                    } else {
1471                        self.write_type(key_type);
1472                    }
1473
1474                    self.push_char(']');
1475                    self.push_char(':');
1476                    self.push_char(' ');
1477                    self.write_type(indexer.get_value_type());
1478                }
1479            }
1480            if index != last_index {
1481                self.push_char(',');
1482                self.push_char(' ');
1483            }
1484        }
1485
1486        self.push_char('}');
1487    }
1488
1489    fn write_expression_type(&mut self, expression_type: &nodes::ExpressionType) {
1490        self.push_str("typeof(");
1491        self.write_expression(expression_type.get_expression());
1492        self.push_char(')');
1493    }
1494
1495    fn write_parenthese_type(&mut self, parenthese_type: &nodes::ParentheseType) {
1496        self.write_type_in_parentheses(parenthese_type.get_inner_type());
1497    }
1498
1499    fn write_function_type(&mut self, function_type: &nodes::FunctionType) {
1500        if let Some(generics) = function_type.get_generic_parameters() {
1501            self.write_function_generics(generics);
1502        }
1503
1504        self.push_char('(');
1505
1506        let last_index = function_type.argument_len().saturating_sub(1);
1507
1508        for (index, argument) in function_type.iter_arguments().enumerate() {
1509            if let Some(name) = argument.get_name() {
1510                self.write_identifier(name);
1511                self.push_char(':');
1512            }
1513            self.write_type(argument.get_type());
1514
1515            if index != last_index {
1516                self.push_char(',');
1517                self.push_space();
1518            }
1519        }
1520
1521        if let Some(variadic_argument_type) = function_type.get_variadic_argument_type() {
1522            if function_type.argument_len() > 0 {
1523                self.push_char(',');
1524                self.push_space();
1525            }
1526            self.write_variadic_argument_type(variadic_argument_type);
1527        }
1528
1529        self.push_str(") -> ");
1530        self.write_function_return_type(function_type.get_return_type());
1531    }
1532
1533    fn write_optional_type(&mut self, optional: &nodes::OptionalType) {
1534        let inner_type = optional.get_inner_type();
1535        if nodes::OptionalType::needs_parentheses(inner_type) {
1536            self.write_type_in_parentheses(inner_type);
1537        } else {
1538            self.write_type(inner_type);
1539        }
1540        self.push_char('?');
1541    }
1542
1543    fn write_intersection_type(&mut self, intersection: &nodes::IntersectionType) {
1544        if intersection.has_leading_token() {
1545            self.push_char('&');
1546        }
1547
1548        let length = intersection.len();
1549        let last_index = length.saturating_sub(1);
1550
1551        for (i, r#type) in intersection.iter_types().enumerate() {
1552            if i != 0 {
1553                self.push_char('&');
1554            }
1555
1556            let need_parentheses = if i == last_index {
1557                nodes::IntersectionType::last_needs_parentheses(r#type)
1558            } else {
1559                nodes::IntersectionType::intermediate_needs_parentheses(r#type)
1560            };
1561
1562            if need_parentheses {
1563                self.write_type_in_parentheses(r#type);
1564            } else {
1565                self.write_type(r#type);
1566            }
1567        }
1568    }
1569
1570    fn write_union_type(&mut self, union: &nodes::UnionType) {
1571        let length = union.len();
1572        let last_index = length.saturating_sub(1);
1573
1574        if union.has_leading_token() {
1575            self.push_char('|');
1576            self.push_space();
1577        }
1578
1579        for (i, r#type) in union.iter_types().enumerate() {
1580            if i != 0 {
1581                self.push_space();
1582                self.push_char('|');
1583                self.push_space();
1584            }
1585
1586            let need_parentheses = if i == last_index {
1587                nodes::UnionType::last_needs_parentheses(r#type)
1588            } else {
1589                nodes::UnionType::intermediate_needs_parentheses(r#type)
1590            };
1591
1592            if need_parentheses {
1593                self.write_type_in_parentheses(r#type);
1594            } else {
1595                self.write_type(r#type);
1596            }
1597        }
1598    }
1599
1600    fn write_type_pack(&mut self, type_pack: &nodes::TypePack) {
1601        self.push_char('(');
1602
1603        let last_index = type_pack.len().saturating_sub(1);
1604
1605        for (index, r#type) in type_pack.into_iter().enumerate() {
1606            self.write_type(r#type);
1607            if index != last_index {
1608                self.push_char(',');
1609            }
1610        }
1611
1612        if let Some(variadic_argument_type) = type_pack.get_variadic_type() {
1613            if !type_pack.is_empty() {
1614                self.push_char(',');
1615            }
1616            self.write_variadic_argument_type(variadic_argument_type);
1617        }
1618
1619        self.push_char(')');
1620    }
1621
1622    fn write_variadic_type_pack(&mut self, variadic_type_pack: &nodes::VariadicTypePack) {
1623        self.push_str("...");
1624        self.write_type(variadic_type_pack.get_type());
1625    }
1626
1627    fn write_generic_type_pack(&mut self, generic_type_pack: &nodes::GenericTypePack) {
1628        self.write_identifier(generic_type_pack.get_name());
1629        self.push_str("...");
1630    }
1631}