ad_astra/format/
formatter.rs

1////////////////////////////////////////////////////////////////////////////////
2// This file is part of "Ad Astra", an embeddable scripting programming       //
3// language platform.                                                         //
4//                                                                            //
5// This work is proprietary software with source-available code.              //
6//                                                                            //
7// To copy, use, distribute, or contribute to this work, you must agree to    //
8// the terms of the General License Agreement:                                //
9//                                                                            //
10// https://github.com/Eliah-Lakhin/ad-astra/blob/master/EULA.md               //
11//                                                                            //
12// The agreement grants a Basic Commercial License, allowing you to use       //
13// this work in non-commercial and limited commercial products with a total   //
14// gross revenue cap. To remove this commercial limit for one of your         //
15// products, you must acquire a Full Commercial License.                      //
16//                                                                            //
17// If you contribute to the source code, documentation, or related materials, //
18// you must grant me an exclusive license to these contributions.             //
19// Contributions are governed by the "Contributions" section of the General   //
20// License Agreement.                                                         //
21//                                                                            //
22// Copying the work in parts is strictly forbidden, except as permitted       //
23// under the General License Agreement.                                       //
24//                                                                            //
25// If you do not or cannot agree to the terms of this Agreement,              //
26// do not use this work.                                                      //
27//                                                                            //
28// This work is provided "as is", without any warranties, express or implied, //
29// except where such disclaimers are legally invalid.                         //
30//                                                                            //
31// Copyright (c) 2024 Ilya Lakhin (Илья Александрович Лахин).                 //
32// All rights reserved.                                                       //
33////////////////////////////////////////////////////////////////////////////////
34
35use lady_deirdre::{
36    format::{PrettyPrintConfig, PrettyPrinter},
37    lexis::{Line, SourceCode, TokenBuffer, TokenRule},
38    syntax::{AbstractNode, ParseNode, ParseNodeChild, ParseToken, ParseTree, PolyRef, SyntaxTree},
39};
40
41use crate::syntax::{Assoc, Precedence, ScriptDoc, ScriptNode, ScriptToken};
42
43/// Configuration options for the Ad Astra script formatting utility.
44///
45/// Used as an argument for the [format_script_text] and
46/// [ModuleText::format](crate::analysis::ModuleText::format) functions.
47///
48/// The [Default] implementation of this object provides canonical configuration
49/// options, though you can customize some formatting options at your
50/// discretion.
51#[derive(Clone, Copy, Debug, PartialEq, Eq, Hash)]
52#[non_exhaustive]
53pub struct ScriptFormatConfig {
54    /// The number of characters the formatter should keep in a line before
55    /// breaking the content into multiple lines.
56    ///
57    /// The default value is `80`.
58    pub margin: u16,
59
60    /// If the formatter breaks a line into multiple lines, it should attempt
61    /// to keep at least the `inline` number of characters in each line,
62    /// relative to the current indentation.
63    ///
64    /// The default value is `60`.
65    pub inline: u16,
66
67    /// The number of whitespace characters for a single level of indentation.
68    ///
69    /// The default value is `4`.
70    pub indent: u16,
71
72    /// If set to true, the formatter preserves excessive parentheses in
73    /// expressions.
74    ///
75    /// For example, the formatter will keep the expression `(1 + 2) + 3` as it
76    /// is, even though it could otherwise be rewritten as `1 + 2 + 3`.
77    ///
78    /// The default value is `false`, meaning that the formatter will attempt
79    /// to remove unnecessary parentheses whenever possible.
80    pub preserve_expr_groups: bool,
81
82    /// If set to true, the formatter preserves at most one blank line between
83    /// script code statements. Otherwise, the formatter will eliminate
84    /// excessive blank lines.
85    ///
86    /// The default value is `true`.
87    pub preserve_blank_lines: bool,
88
89    /// If set to true, the formatter preserves statement blocks even if they
90    /// could clearly be merged into the surrounding code.
91    ///
92    /// For example, the formatter will keep the code `foo(); { bar(); } baz();`
93    /// as it is, even though it could otherwise be rewritten as
94    /// `foo(); bar(); baz();`.
95    ///
96    /// The default value is `false`, meaning that the formatter will attempt
97    /// to merge blocks together.
98    pub preserve_blocks: bool,
99
100    /// When set to true, the formatter attempts to keep short code blocks
101    /// in line.
102    ///
103    /// For example, the formatter will keep the code `{ foo(); }` in line
104    /// instead of breaking it into three lines:
105    ///
106    /// ```text
107    /// {
108    ///     foo();
109    /// }
110    /// ```
111    ///
112    /// The default value is `false`, meaning that the formatter will typically
113    /// break single-statement blocks into multiple lines.
114    pub compact_blocks: bool,
115}
116
117impl Default for ScriptFormatConfig {
118    #[inline(always)]
119    fn default() -> Self {
120        Self::new()
121    }
122}
123
124impl ScriptFormatConfig {
125    /// The default constructor for the configuration.
126    #[inline(always)]
127    pub const fn new() -> Self {
128        Self {
129            margin: 80,
130            inline: 60,
131            indent: 4,
132            preserve_expr_groups: false,
133            preserve_blank_lines: true,
134            preserve_blocks: false,
135            compact_blocks: false,
136        }
137    }
138}
139
140/// Formats source code text according to the Ad Astra formatting rules.
141///
142/// The function formats the specified source code `text` in accordance with the
143/// rules and the `config` options, preserving code comments and other elements
144/// as per the original author's intentions, whenever the original code format
145/// does not contradict the canonical formatting rules.
146///
147/// The function returns None if the source code contains parse errors.
148/// Currently, Ad Astra cannot format source code with syntax errors, but
149/// it can format code regardless of its semantics.
150///
151/// Unlike the [ModuleText::format](crate::analysis::ModuleText::format)
152/// function, this function does not require creating a dedicated
153/// [ScriptModule](crate::analysis::ScriptModule) when you need to format
154/// arbitrary Ad Astra text one time.
155#[inline(always)]
156pub fn format_script_text(config: ScriptFormatConfig, text: impl AsRef<str>) -> Option<String> {
157    let buffer = TokenBuffer::from(text);
158    let tree = ParseTree::new(&buffer, ..);
159
160    ScriptFormatter::format(config, &tree)
161}
162
163#[inline(always)]
164pub(crate) fn format_script_doc(config: ScriptFormatConfig, doc: &ScriptDoc) -> Option<String> {
165    let tree = ParseTree::new(doc, ..);
166
167    ScriptFormatter::format(config, &tree)
168}
169
170struct ScriptFormatter<'a, C: SourceCode<Token = ScriptToken>> {
171    config: ScriptFormatConfig,
172    tree: &'a ParseTree<'a, ScriptNode, C>,
173    printer: PrettyPrinter,
174    state: State,
175}
176
177impl<'a, C: SourceCode<Token = ScriptToken>> ScriptFormatter<'a, C> {
178    fn format(
179        config: ScriptFormatConfig,
180        tree: &'a ParseTree<'a, ScriptNode, C>,
181    ) -> Option<String> {
182        if tree.errors().next().is_some() {
183            return None;
184        }
185
186        let mut printer_config = PrettyPrintConfig::new();
187
188        printer_config.margin = config.margin;
189        printer_config.inline = config.inline;
190        printer_config.indent = config.indent;
191        printer_config.debug = false;
192
193        let printer = PrettyPrinter::new(printer_config);
194
195        let mut formatter = Self {
196            config,
197            tree,
198            printer,
199            state: State::Break1,
200        };
201
202        formatter.format_node(tree.parse_tree_root());
203
204        match &formatter.state {
205            State::Break1 | State::PendingBreak2 => (),
206            _ => formatter.printer.hardbreak(),
207        }
208
209        Some(formatter.printer.finish())
210    }
211
212    fn format_node(&mut self, parse_node: &ParseNode) {
213        if !parse_node.well_formed {
214            self.print_node_as_is(parse_node);
215            return;
216        }
217
218        let Some(syntax_node) = parse_node.node_ref.deref(self.tree) else {
219            return;
220        };
221
222        match syntax_node {
223            ScriptNode::InlineComment { .. } => self.format_inline_comment(parse_node),
224            ScriptNode::MultilineComment { .. } => self.format_multiline_comment(parse_node),
225            ScriptNode::Root { .. } => {
226                let _ = self.format_block(parse_node, BlockUnwrap::AsIs);
227            }
228            ScriptNode::Clause { .. } => self.format_concat(parse_node),
229            ScriptNode::Use { .. } => self.format_concat(parse_node),
230            ScriptNode::Package { .. } => self.format_concat(parse_node),
231            ScriptNode::If { .. } => self.format_concat(parse_node),
232            ScriptNode::Match { .. } => self.format_concat(parse_node),
233            ScriptNode::MatchBody { .. } => self.format_list(parse_node),
234            ScriptNode::MatchArm { .. } => {
235                let _ = self.format_match_arm(parse_node);
236            }
237            ScriptNode::Else { .. } => self.format_concat(parse_node),
238            ScriptNode::Let { .. } => self.format_concat(parse_node),
239            ScriptNode::Var { .. } => self.format_concat(parse_node),
240            ScriptNode::For { .. } => self.format_concat(parse_node),
241            ScriptNode::Loop { .. } => self.format_concat(parse_node),
242            ScriptNode::Block { .. } => {
243                let _ = self.format_block(parse_node, BlockUnwrap::AsIs);
244            }
245            ScriptNode::Break { .. } => self.format_concat(parse_node),
246            ScriptNode::Continue { .. } => self.format_concat(parse_node),
247            ScriptNode::Return { .. } => self.format_concat(parse_node),
248            ScriptNode::Fn { .. } => self.format_fn(parse_node),
249            ScriptNode::FnParams { .. } => self.format_list(parse_node),
250            ScriptNode::Struct { .. } => self.format_concat(parse_node),
251            ScriptNode::StructBody { .. } => self.format_list(parse_node),
252            ScriptNode::StructEntry { .. } => self.format_concat(parse_node),
253            ScriptNode::StructEntryKey { .. } => self.format_concat(parse_node),
254            ScriptNode::Array { .. } => self.format_list(parse_node),
255            ScriptNode::String { .. } => self.print_node_as_is(parse_node),
256            ScriptNode::Crate { .. } => self.format_concat(parse_node),
257            ScriptNode::This { .. } => self.format_concat(parse_node),
258            ScriptNode::Ident { .. } => self.format_concat(parse_node),
259            ScriptNode::Number { .. } => self.format_concat(parse_node),
260            ScriptNode::Max { .. } => self.format_concat(parse_node),
261            ScriptNode::Bool { .. } => self.format_concat(parse_node),
262            ScriptNode::UnaryLeft { .. } => self.format_expr(parse_node),
263            ScriptNode::Binary { .. } => self.format_expr(parse_node),
264            ScriptNode::Op { .. } => self.format_concat(parse_node),
265            ScriptNode::Query { .. } => self.format_expr(parse_node),
266            ScriptNode::Call { .. } => self.format_expr(parse_node),
267            ScriptNode::CallArgs { .. } => self.format_list(parse_node),
268            ScriptNode::Index { .. } => self.format_expr(parse_node),
269            ScriptNode::IndexArg { .. } => self.format_list(parse_node),
270            ScriptNode::Field { .. } => self.format_concat(parse_node),
271            ScriptNode::Expr { .. } => self.format_expr(parse_node),
272        }
273    }
274
275    fn format_inline_comment(&mut self, parse_node: &ParseNode) {
276        let text = match parse_node.breaks() > 0 {
277            false => self.tree.substring(&parse_node.site_span).into_owned(),
278
279            true => self
280                .tree
281                .substring(parse_node.site_span.start..(parse_node.site_span.end - 1))
282                .into_owned(),
283        };
284
285        match &self.state {
286            State::Break1 => (),
287
288            State::PendingBreak2 => self.printer.hardbreak(),
289
290            State::Word { line, .. } | State::EmbeddedEnd { line } => {
291                match line == &parse_node.start_line() {
292                    true => self.printer.word(" "),
293                    false => self.printer.hardbreak(),
294                }
295            }
296
297            State::ParenOpen {
298                consistent,
299                dedent_next,
300                ..
301            }
302            | State::BracketOpen {
303                consistent,
304                dedent_next,
305                ..
306            } => {
307                match *consistent {
308                    true => self.printer.cbox(1),
309                    false => self.printer.ibox(1),
310                }
311
312                self.printer.hardbreak();
313
314                if *dedent_next {
315                    match *consistent {
316                        true => self.printer.cbox(-1),
317                        false => self.printer.ibox(-1),
318                    }
319                }
320            }
321
322            State::BraceOpen {
323                reenter,
324                reenter_consistency,
325                ..
326            } => {
327                self.printer.neverbreak();
328                self.printer.cbox(1);
329                self.printer.hardbreak();
330
331                if *reenter {
332                    match *reenter_consistency {
333                        true => {
334                            self.printer.cbox(1);
335                            self.printer.cbox(-1);
336                        }
337
338                        false => {
339                            self.printer.ibox(1);
340                            self.printer.ibox(-1);
341                        }
342                    }
343                }
344            }
345
346            State::PendingSep {
347                sep,
348                line,
349                embedded_after,
350                ..
351            } => {
352                if !sep.is_empty() {
353                    self.printer.word(*sep);
354                }
355
356                for comment in embedded_after {
357                    self.printer.word(" ");
358                    self.printer.word(comment);
359                }
360
361                match line == &parse_node.start_line() {
362                    true => self.printer.word(" "),
363                    false => self.printer.hardbreak(),
364                }
365            }
366        }
367
368        self.printer.word(text);
369        self.printer.hardbreak();
370
371        self.state = State::Break1;
372    }
373
374    fn format_multiline_comment(&mut self, parse_node: &ParseNode) {
375        let text = self.tree.substring(&parse_node.site_span).into_owned();
376
377        let embedded = parse_node.breaks() == 0;
378
379        match &mut self.state {
380            State::Break1 => (),
381
382            State::PendingBreak2 => self.printer.hardbreak(),
383
384            State::Word { line, .. } | State::EmbeddedEnd { line } => {
385                match embedded && line == &parse_node.start_line() {
386                    true => self.printer.word(" "),
387                    false => self.printer.hardbreak(),
388                }
389            }
390
391            State::ParenOpen {
392                line,
393                consistent,
394                dedent_next,
395            }
396            | State::BracketOpen {
397                line,
398                consistent,
399                dedent_next,
400            } => {
401                match *consistent {
402                    true => self.printer.cbox(1),
403                    false => self.printer.ibox(0),
404                }
405
406                match embedded && line == &parse_node.start_line() {
407                    true => self.printer.softbreak(),
408                    false => self.printer.hardbreak(),
409                }
410
411                if *dedent_next {
412                    match *consistent {
413                        true => self.printer.cbox(-1),
414                        false => self.printer.ibox(0),
415                    }
416                }
417            }
418
419            State::BraceOpen {
420                line,
421                reenter,
422                reenter_consistency,
423            } => {
424                self.printer.neverbreak();
425                self.printer.cbox(1);
426
427                match embedded && self.config.compact_blocks && line == &parse_node.start_line() {
428                    true => self.printer.blank(),
429                    false => self.printer.hardbreak(),
430                }
431
432                if *reenter {
433                    match *reenter_consistency {
434                        true => {
435                            self.printer.cbox(1);
436                            self.printer.cbox(-1);
437                        }
438
439                        false => {
440                            self.printer.ibox(1);
441                            self.printer.ibox(-1);
442                        }
443                    }
444                }
445            }
446
447            State::PendingSep {
448                sep,
449                line,
450                is_last,
451                embedded_after,
452            } => match embedded && (line == &parse_node.start_line() || *is_last) {
453                true => {
454                    embedded_after.push(text);
455                    return;
456                }
457
458                false => {
459                    if !sep.is_empty() {
460                        self.printer.word(*sep);
461                    }
462
463                    for comment in embedded_after {
464                        self.printer.word(" ");
465                        self.printer.word(comment.to_string());
466                    }
467
468                    self.printer.hardbreak();
469                }
470            },
471        }
472
473        let alignment = parse_node
474            .position_span
475            .start
476            .column
477            .checked_sub(1)
478            .unwrap_or_default();
479
480        let mut is_first = true;
481
482        for mut string in text.as_str().split("\n") {
483            match is_first {
484                true => is_first = false,
485
486                false => {
487                    self.printer.hardbreak();
488                    string = dedent_line(string, alignment);
489                }
490            }
491
492            self.printer.word(string);
493        }
494
495        match embedded {
496            true => {
497                self.state = State::EmbeddedEnd {
498                    line: parse_node.end_line(),
499                };
500            }
501
502            false => {
503                self.printer.hardbreak();
504                self.state = State::Break1;
505            }
506        }
507    }
508
509    fn format_block(&mut self, parse_node: &ParseNode, mut unwrap: BlockUnwrap) -> BlockUnwrap {
510        fn find_one(children: &[ParseNodeChild]) -> Option<&ParseNode> {
511            let mut candidate = None;
512
513            for child in children {
514                if let ParseNodeChild::Node(child) = child {
515                    if let ScriptNode::INLINE_COMMENT | ScriptNode::MULTILINE_COMMENT = child.rule {
516                        return None;
517                    }
518
519                    if candidate.is_some() {
520                        return None;
521                    }
522
523                    candidate = Some(child);
524                }
525            }
526
527            candidate
528        }
529
530        if self.config.preserve_blocks {
531            unwrap = BlockUnwrap::AsIs;
532        }
533
534        match &unwrap {
535            BlockUnwrap::AsIs => (),
536
537            BlockUnwrap::UnwrapOuter | BlockUnwrap::UnwrapOuterEmpty => {
538                for child in &parse_node.children {
539                    if let ParseNodeChild::Node(child) = child {
540                        if let ScriptNode::INLINE_COMMENT
541                        | ScriptNode::MULTILINE_COMMENT
542                        | ScriptNode::LET = child.rule
543                        {
544                            unwrap = BlockUnwrap::AsIs;
545                            break;
546                        }
547                    }
548                }
549            }
550
551            BlockUnwrap::UnwrapClause => {
552                if let Some(single) = find_one(&parse_node.children) {
553                    if single.rule == ScriptNode::CLAUSE {
554                        if let Some(single) = find_one(&single.children) {
555                            self.format_node(single);
556
557                            return unwrap;
558                        }
559                    }
560                }
561
562                unwrap = BlockUnwrap::AsIs;
563            }
564
565            BlockUnwrap::UnwrapReturn => {
566                if let Some(single) = find_one(&parse_node.children) {
567                    if single.rule == ScriptNode::RETURN {
568                        if let Some(single) = find_one(&single.children) {
569                            let mut is_fn = false;
570
571                            if let Some(ScriptNode::Expr { inner, .. }) =
572                                single.node_ref.deref(self.tree)
573                            {
574                                if let Some(ScriptNode::Fn { .. }) = inner.deref(self.tree) {
575                                    is_fn = true;
576                                }
577                            }
578
579                            if !is_fn {
580                                self.format_node(single);
581
582                                return unwrap;
583                            }
584                        }
585                    }
586                }
587
588                unwrap = BlockUnwrap::AsIs;
589            }
590        }
591
592        let mut inner_empty = true;
593        let mut st_printed = false;
594
595        for (index, child) in parse_node.children.iter().enumerate() {
596            match child {
597                ParseNodeChild::Blank(child) => {
598                    if !self.config.preserve_blank_lines {
599                        continue;
600                    }
601
602                    if inner_empty {
603                        continue;
604                    }
605
606                    let next = parse_node.children.get(index + 1);
607
608                    if let Some(ParseNodeChild::Token(token)) = next {
609                        if let Some((_, open_or_close)) = Group::from_token_rule(token.rule) {
610                            if let OpenOrClose::Close = open_or_close {
611                                continue;
612                            };
613                        }
614                    }
615
616                    let breaks = child.breaks();
617
618                    self.format_break(breaks, false);
619                }
620
621                ParseNodeChild::Token(child) => {
622                    if child.rule == ScriptToken::Semicolon as u8 {
623                        continue;
624                    }
625
626                    if let Some((group, open_or_close)) = Group::from_token_rule(child.rule) {
627                        if !unwrap.as_is() {
628                            continue;
629                        }
630
631                        match open_or_close {
632                            OpenOrClose::Open => self.print_open(group, child.start_line(), true),
633                            OpenOrClose::Close => self.print_close(group, child.start_line()),
634                        }
635
636                        continue;
637                    }
638
639                    self.format_token(child, false, false);
640                }
641
642                ParseNodeChild::Node(child) => match child.rule {
643                    ScriptNode::BLOCK => {
644                        match &self.state {
645                            State::Break1 | State::PendingBreak2 => self.flush(child.start_line()),
646
647                            _ => {
648                                if st_printed {
649                                    self.format_break(1, true);
650                                }
651                            }
652                        }
653
654                        match self.format_block(child, BlockUnwrap::UnwrapOuter) {
655                            BlockUnwrap::UnwrapOuterEmpty => (),
656
657                            _ => {
658                                inner_empty = false;
659                                st_printed = true;
660                            }
661                        }
662                    }
663
664                    ScriptNode::INLINE_COMMENT => {
665                        self.format_node(child);
666                        inner_empty = false;
667                    }
668
669                    ScriptNode::MULTILINE_COMMENT => {
670                        self.format_node(child);
671                        inner_empty = false;
672                    }
673
674                    _ => {
675                        match &self.state {
676                            State::Break1 | State::PendingBreak2 => self.flush(child.start_line()),
677
678                            _ => {
679                                if st_printed {
680                                    self.format_break(1, true);
681                                }
682                            }
683                        }
684
685                        self.format_node(child);
686
687                        inner_empty = false;
688                        st_printed = true;
689                    }
690                },
691            }
692        }
693
694        if let BlockUnwrap::UnwrapOuter = &unwrap {
695            if inner_empty {
696                return BlockUnwrap::UnwrapOuterEmpty;
697            }
698        }
699
700        unwrap
701    }
702
703    fn format_list(&mut self, parse_node: &ParseNode) {
704        enum ListState {
705            Begin,
706            Next,
707            ItemPrinted {
708                end_line: Line,
709                is_last: bool,
710                is_block: bool,
711            },
712        }
713
714        let mut last_item = 0;
715        let mut consistent = false;
716
717        for (index, child) in parse_node.children.iter().enumerate() {
718            match child {
719                ParseNodeChild::Blank(_) => (),
720
721                ParseNodeChild::Token(child) => {
722                    if child.rule == ScriptToken::BraceOpen as u8 {
723                        consistent = true;
724                    }
725                }
726
727                ParseNodeChild::Node(child) => {
728                    match child.rule {
729                        ScriptNode::INLINE_COMMENT | ScriptNode::MULTILINE_COMMENT => {
730                            consistent = true;
731
732                            continue;
733                        }
734
735                        ScriptNode::EXPR => {
736                            if !is_simple_expr(child) {
737                                consistent = true;
738                            }
739                        }
740
741                        _ => (),
742                    }
743
744                    last_item = index;
745                }
746            }
747        }
748
749        let mut state = ListState::Begin;
750
751        'outer: for (index, child) in parse_node.children.iter().enumerate() {
752            match child {
753                ParseNodeChild::Blank(child) => {
754                    if !self.config.preserve_blank_lines {
755                        continue;
756                    }
757
758                    if !consistent {
759                        continue;
760                    }
761
762                    match &state {
763                        ListState::Begin => continue,
764
765                        ListState::ItemPrinted { .. } => {
766                            let mut lookahead = index + 1;
767
768                            while let Some(next) = parse_node.children.get(lookahead) {
769                                match next {
770                                    ParseNodeChild::Blank(..) => (),
771                                    ParseNodeChild::Token(..) => continue 'outer,
772                                    ParseNodeChild::Node(next) => {
773                                        let (ScriptNode::MULTILINE_COMMENT
774                                        | ScriptNode::INLINE_COMMENT) = next.rule
775                                        else {
776                                            break;
777                                        };
778                                    }
779                                }
780
781                                lookahead += 1;
782                            }
783                        }
784
785                        ListState::Next => (),
786                    }
787
788                    let next = parse_node.children.get(index + 1);
789
790                    if let Some(ParseNodeChild::Token(token)) = next {
791                        if let Some((_, open_or_close)) = Group::from_token_rule(token.rule) {
792                            if let OpenOrClose::Close = open_or_close {
793                                continue;
794                            };
795                        }
796                    }
797
798                    self.format_break(child.breaks(), false);
799                }
800
801                ParseNodeChild::Token(child) => {
802                    let start_line = child.start_line();
803
804                    if let Some((group, open_or_close)) = Group::from_token_rule(child.rule) {
805                        match open_or_close {
806                            OpenOrClose::Open => self.print_open(group, start_line, consistent),
807
808                            OpenOrClose::Close => {
809                                if let ListState::ItemPrinted {
810                                    end_line,
811                                    is_last,
812                                    is_block,
813                                    ..
814                                } = &state
815                                {
816                                    self.print_sep(
817                                        match *is_block {
818                                            true => "",
819                                            false => ",",
820                                        },
821                                        *end_line,
822                                        *is_last,
823                                    );
824                                }
825
826                                self.print_close(group, start_line);
827                            }
828                        }
829
830                        continue;
831                    }
832
833                    if child.rule == ScriptToken::Comma as u8 {
834                        let ListState::ItemPrinted {
835                            is_last, is_block, ..
836                        } = &state
837                        else {
838                            continue;
839                        };
840
841                        self.print_sep(
842                            match *is_block {
843                                true => "",
844                                false => ",",
845                            },
846                            start_line,
847                            *is_last,
848                        );
849
850                        state = ListState::Next;
851
852                        continue;
853                    }
854
855                    self.format_token(child, !consistent, false);
856                }
857
858                ParseNodeChild::Node(child) => match child.rule {
859                    ScriptNode::INLINE_COMMENT => match &state {
860                        ListState::Begin | ListState::Next => {
861                            self.format_node(child);
862                            state = ListState::Next;
863                        }
864
865                        ListState::ItemPrinted {
866                            end_line,
867                            is_last,
868                            is_block,
869                        } => {
870                            self.print_sep(
871                                match *is_block {
872                                    true => "",
873                                    false => ",",
874                                },
875                                *end_line,
876                                *is_last,
877                            );
878
879                            self.format_node(child);
880                            state = ListState::Next;
881                        }
882                    },
883
884                    ScriptNode::MULTILINE_COMMENT => match &state {
885                        ListState::Begin | ListState::Next => {
886                            self.format_node(child);
887                            state = ListState::Next;
888                        }
889
890                        ListState::ItemPrinted {
891                            end_line,
892                            is_last,
893                            is_block,
894                        } => {
895                            if child.breaks() == 0 && end_line == &child.start_line() {
896                                self.format_node(child);
897                                continue;
898                            }
899
900                            self.print_sep(
901                                match *is_block {
902                                    true => "",
903                                    false => ",",
904                                },
905                                *end_line,
906                                *is_last,
907                            );
908
909                            self.format_node(child);
910                            state = ListState::Next;
911                        }
912                    },
913
914                    ScriptNode::MATCH_ARM => {
915                        if let ListState::ItemPrinted {
916                            end_line, is_block, ..
917                        } = &state
918                        {
919                            self.print_sep(
920                                match *is_block {
921                                    true => "",
922                                    false => ",",
923                                },
924                                *end_line,
925                                false,
926                            );
927                        }
928
929                        self.format_break(1, true);
930
931                        let end_line = child.end_line();
932
933                        let format = self.format_match_arm(child);
934
935                        state = ListState::ItemPrinted {
936                            end_line,
937                            is_last: last_item == index,
938                            is_block: match format {
939                                MatchArmFormat::EndsWithExpr => false,
940                                MatchArmFormat::EndsWithBlock => true,
941                            },
942                        };
943                    }
944
945                    _ => {
946                        self.format_node(child);
947
948                        state = ListState::ItemPrinted {
949                            end_line: child.end_line(),
950                            is_last: last_item == index,
951                            is_block: false,
952                        };
953                    }
954                },
955            }
956        }
957    }
958
959    fn format_match_arm(&mut self, parse_node: &ParseNode) -> MatchArmFormat {
960        let mut result = MatchArmFormat::EndsWithExpr;
961
962        let mut arrow_scanned = false;
963
964        for child in &parse_node.children {
965            match child {
966                ParseNodeChild::Blank(_) => (),
967
968                ParseNodeChild::Token(child) => {
969                    if child.rule == ScriptToken::Arrow as u8 {
970                        arrow_scanned = true;
971                    }
972
973                    self.format_token(child, true, true);
974                }
975
976                ParseNodeChild::Node(child) => {
977                    if arrow_scanned {
978                        if child.rule == ScriptNode::BLOCK {
979                            if let BlockUnwrap::AsIs =
980                                self.format_block(child, BlockUnwrap::UnwrapClause)
981                            {
982                                result = MatchArmFormat::EndsWithBlock;
983                            }
984
985                            continue;
986                        }
987                    }
988
989                    self.format_node(child);
990                }
991            }
992        }
993
994        result
995    }
996
997    fn format_fn(&mut self, parse_node: &ParseNode) {
998        for child in &parse_node.children {
999            match child {
1000                ParseNodeChild::Blank(_) => (),
1001
1002                ParseNodeChild::Token(child) => {
1003                    self.format_token(child, true, false);
1004                }
1005
1006                ParseNodeChild::Node(child) => {
1007                    if child.rule == ScriptNode::BLOCK {
1008                        if let Some(script_node) = parse_node.node_ref.deref(self.tree) {
1009                            if let Some(script_node) = script_node.parent_ref().deref(self.tree) {
1010                                if let ScriptNode::Expr { .. } = script_node {
1011                                    let _ = self.format_block(child, BlockUnwrap::UnwrapReturn);
1012                                    return;
1013                                }
1014                            }
1015                        }
1016                    }
1017
1018                    self.format_node(child);
1019                }
1020            }
1021        }
1022    }
1023
1024    fn format_expr(&mut self, parse_node: &ParseNode) {
1025        let Some(ScriptNode::Expr { start, .. }) = parse_node.node_ref.deref(self.tree) else {
1026            return;
1027        };
1028
1029        if !start.is_nil() {
1030            self.format_group(parse_node);
1031            return;
1032        }
1033
1034        let mut flatten = Vec::new();
1035
1036        self.flat_expr(parse_node, &mut flatten);
1037
1038        self.format_flatten(flatten);
1039    }
1040
1041    fn format_group(&mut self, parse_node: &ParseNode) {
1042        let mut flatten = Vec::new();
1043
1044        self.flat_expr(parse_node, &mut flatten);
1045
1046        let mut consistent = false;
1047
1048        for child in &flatten {
1049            if child.requires_consistency(self.tree) {
1050                consistent = true;
1051                break;
1052            }
1053        }
1054
1055        self.print_open(Group::Paren, parse_node.start_line(), consistent);
1056
1057        self.format_flatten(flatten);
1058
1059        self.print_close(Group::Paren, parse_node.end_line());
1060    }
1061
1062    fn format_flatten(&mut self, flatten: Vec<FlatChild>) {
1063        let mut first_binary_operator = None;
1064
1065        for (index, child) in flatten.iter().enumerate() {
1066            let FlatChild::OperatorMiddle(_) = child else {
1067                continue;
1068            };
1069
1070            first_binary_operator = Some(index);
1071            break;
1072        }
1073
1074        let mut boxed = false;
1075
1076        if first_binary_operator.is_some() {
1077            let mut consistent = false;
1078
1079            for child in &flatten {
1080                if child.requires_consistency(self.tree) {
1081                    consistent = true;
1082                    break;
1083                }
1084            }
1085
1086            match &mut self.state {
1087                State::ParenOpen { dedent_next, .. } | State::BracketOpen { dedent_next, .. } => {
1088                    *dedent_next = true;
1089                }
1090
1091                State::BraceOpen {
1092                    reenter,
1093                    reenter_consistency,
1094                    ..
1095                } => {
1096                    *reenter = true;
1097                    *reenter_consistency = consistent;
1098                    boxed = true;
1099                }
1100
1101                _ => {
1102                    match consistent {
1103                        true => {
1104                            self.printer.cbox(1);
1105                            self.printer.cbox(-1);
1106                        }
1107
1108                        false => {
1109                            self.printer.ibox(1);
1110                            self.printer.ibox(-1);
1111                        }
1112                    }
1113
1114                    boxed = true;
1115                }
1116            };
1117        }
1118
1119        for (index, child) in flatten.iter().enumerate() {
1120            match child {
1121                FlatChild::OperatorLeft(child) => {
1122                    let mut has_comment_after = false;
1123
1124                    if let Some(next_child) = flatten.get(index + 1) {
1125                        if let FlatChild::Comment(_) = next_child {
1126                            has_comment_after = true;
1127                        }
1128                    }
1129
1130                    for child in &child.children {
1131                        let ParseNodeChild::Token(token) = child else {
1132                            continue;
1133                        };
1134
1135                        let Some(text) = token.token_ref.string(self.tree) else {
1136                            continue;
1137                        };
1138
1139                        let line = child.start_line();
1140
1141                        self.print_word(text, line, true, !has_comment_after, true);
1142                    }
1143                }
1144
1145                FlatChild::OperatorMiddle(child) => {
1146                    if let Some(first_binary_operator) = first_binary_operator {
1147                        if first_binary_operator == index {
1148                            self.printer.end();
1149                        }
1150                    }
1151
1152                    for child in &child.children {
1153                        let ParseNodeChild::Token(token) = child else {
1154                            continue;
1155                        };
1156
1157                        let Some(text) = token.token_ref.string(self.tree) else {
1158                            continue;
1159                        };
1160
1161                        let line = child.start_line();
1162
1163                        self.print_word(text, line, false, false, true);
1164                    }
1165                }
1166
1167                FlatChild::OperatorRight(child) => self.format_node(child),
1168
1169                FlatChild::Operand(child) => {
1170                    self.format_node(child);
1171                }
1172
1173                FlatChild::Group(child) => self.format_group(child),
1174
1175                FlatChild::Comment(child) => self.format_node(child),
1176            }
1177        }
1178
1179        if boxed {
1180            self.printer.end();
1181        }
1182    }
1183
1184    fn format_concat(&mut self, parse_node: &ParseNode) {
1185        for child in &parse_node.children {
1186            match child {
1187                ParseNodeChild::Blank(_) => (),
1188
1189                ParseNodeChild::Token(child) => {
1190                    self.format_token(child, true, false);
1191                }
1192
1193                ParseNodeChild::Node(child) => {
1194                    self.format_node(child);
1195                }
1196            }
1197        }
1198    }
1199
1200    fn format_break(&mut self, breaks: usize, force: bool) {
1201        match &self.state {
1202            State::PendingBreak2
1203            | State::ParenOpen { .. }
1204            | State::BraceOpen { .. }
1205            | State::BracketOpen { .. } => (),
1206
1207            State::Break1 => {
1208                if breaks >= 1 {
1209                    self.state = State::PendingBreak2;
1210                }
1211            }
1212
1213            State::Word { .. } => {
1214                if breaks >= 2 || force {
1215                    self.printer.hardbreak();
1216                    self.state = State::Break1;
1217                }
1218
1219                if breaks >= 2 {
1220                    self.state = State::PendingBreak2;
1221                }
1222            }
1223
1224            State::EmbeddedEnd { .. } => {
1225                if breaks >= 1 {
1226                    self.printer.hardbreak();
1227                    self.state = State::Break1;
1228                }
1229
1230                if breaks >= 2 {
1231                    self.state = State::PendingBreak2;
1232                }
1233            }
1234
1235            State::PendingSep {
1236                sep,
1237                embedded_after,
1238                ..
1239            } => {
1240                if breaks >= 2 || force {
1241                    if !sep.is_empty() {
1242                        self.printer.word(*sep);
1243                    }
1244
1245                    for comment in embedded_after {
1246                        self.printer.word(" ");
1247                        self.printer.word(comment);
1248                    }
1249
1250                    self.printer.hardbreak();
1251                    self.state = State::Break1;
1252                }
1253
1254                if breaks >= 2 {
1255                    self.state = State::PendingBreak2;
1256                }
1257            }
1258        }
1259    }
1260
1261    fn format_token(&mut self, parse_token: &ParseToken, concat: bool, concat_next: bool) {
1262        let Some(text) = parse_token.token_ref.string(self.tree) else {
1263            return;
1264        };
1265
1266        let line = parse_token.start_line();
1267
1268        self.print_word(text, line, concat, false, concat_next);
1269    }
1270
1271    fn print_node_as_is(&mut self, parse_node: &ParseNode) {
1272        let text = self.tree.substring(&parse_node.site_span).into_owned();
1273
1274        let alignment = parse_node
1275            .position_span
1276            .start
1277            .column
1278            .checked_sub(1)
1279            .unwrap_or_default();
1280
1281        let mut line = parse_node.start_line();
1282
1283        let mut is_first = true;
1284
1285        for mut string in text.as_str().split("\n") {
1286            match is_first {
1287                true => is_first = false,
1288                false => {
1289                    self.printer.hardbreak();
1290                    string = dedent_line(string, alignment);
1291                }
1292            }
1293
1294            self.print_word(string, line, true, false, false);
1295            line += 1;
1296        }
1297    }
1298
1299    fn print_sep(&mut self, sep: &'static str, line: Line, is_last: bool) {
1300        self.state = State::PendingSep {
1301            sep,
1302            line,
1303            is_last,
1304            embedded_after: Vec::new(),
1305        };
1306    }
1307
1308    fn print_open(&mut self, group: Group, line: Line, consistent: bool) {
1309        self.print_word(group.open(), line, true, false, false);
1310
1311        match group {
1312            Group::Paren => {
1313                self.state = State::ParenOpen {
1314                    line,
1315                    consistent,
1316                    dedent_next: false,
1317                }
1318            }
1319            Group::Brace => {
1320                self.state = State::BraceOpen {
1321                    line,
1322                    reenter: false,
1323                    reenter_consistency: false,
1324                }
1325            }
1326            Group::Bracket => {
1327                self.state = State::BracketOpen {
1328                    line,
1329                    consistent,
1330                    dedent_next: false,
1331                }
1332            }
1333        }
1334    }
1335
1336    fn print_close(&mut self, group: Group, line: Line) {
1337        let stickiness = match &group {
1338            Group::Brace => 2,
1339            _ => 0,
1340        };
1341
1342        match &self.state {
1343            State::Break1 | State::PendingBreak2 => (),
1344
1345            State::Word { .. } | State::EmbeddedEnd { .. } => match group {
1346                Group::Brace if self.config.compact_blocks => self.printer.blank(),
1347                Group::Brace => self.printer.hardbreak(),
1348                _ => self.printer.softbreak(),
1349            },
1350
1351            State::ParenOpen { .. } | State::BraceOpen { .. } | State::BracketOpen { .. } => {
1352                self.printer.word(group.close());
1353                self.state = State::Word {
1354                    stickiness,
1355                    concat_next: false,
1356                    line,
1357                };
1358                return;
1359            }
1360
1361            State::PendingSep {
1362                sep,
1363                embedded_after,
1364                ..
1365            } => {
1366                let mut embedded = String::new();
1367
1368                for comment in embedded_after.iter() {
1369                    embedded.push(' ');
1370                    embedded.push_str(comment);
1371                }
1372
1373                match group {
1374                    Group::Brace => self.printer.blank(),
1375                    _ => self.printer.softbreak(),
1376                }
1377
1378                self.printer.pre_space(&embedded);
1379                self.printer.pre_break(format!("{sep}{embedded}"));
1380            }
1381        }
1382
1383        self.printer.indent(-1);
1384        self.printer.end();
1385        self.printer.word(group.close());
1386
1387        self.state = State::Word {
1388            stickiness,
1389            concat_next: false,
1390            line,
1391        }
1392    }
1393
1394    fn print_word(
1395        &mut self,
1396        text: &str,
1397        line: Line,
1398        mut concat: bool,
1399        stick_next: bool,
1400        concat_next: bool,
1401    ) {
1402        let stickiness_left;
1403        let mut stickiness_right;
1404
1405        match text {
1406            "{" | "}" => {
1407                stickiness_left = 2;
1408                stickiness_right = 2;
1409            }
1410
1411            "(" | ")" | "[" | "]" | "." | ".." => {
1412                stickiness_left = -1;
1413                stickiness_right = -1;
1414            }
1415
1416            ";" | ":" | "?" => {
1417                concat = true;
1418                stickiness_left = -2;
1419                stickiness_right = 2;
1420            }
1421
1422            _ => {
1423                let is_alphanum = text
1424                    .chars()
1425                    .any(|ch| ch.is_ascii_alphanumeric() || ch == '_' || ch == '"');
1426
1427                match is_alphanum {
1428                    true => {
1429                        stickiness_left = 1;
1430                        stickiness_right = 1;
1431                    }
1432                    false => {
1433                        stickiness_left = 2;
1434                        stickiness_right = 2;
1435                    }
1436                }
1437            }
1438        };
1439
1440        if stick_next {
1441            stickiness_right = -2;
1442        }
1443
1444        match &self.state {
1445            State::Break1 => (),
1446
1447            State::PendingBreak2 => {
1448                self.printer.hardbreak();
1449            }
1450
1451            State::Word {
1452                concat_next,
1453                stickiness,
1454                ..
1455            } => {
1456                let sticky = *stickiness + stickiness_left <= 0;
1457                let concat = concat || *concat_next;
1458
1459                match (sticky, concat) {
1460                    (true, true) => (),
1461                    (true, false) => self.printer.softbreak(),
1462                    (false, true) => self.printer.word(" "),
1463                    (false, false) => self.printer.blank(),
1464                }
1465            }
1466
1467            State::ParenOpen {
1468                consistent,
1469                dedent_next,
1470                ..
1471            }
1472            | State::BracketOpen {
1473                consistent,
1474                dedent_next,
1475                ..
1476            } => match (*consistent, *dedent_next) {
1477                (true, false) => {
1478                    self.printer.cbox(1);
1479                    self.printer.softbreak();
1480                }
1481                (false, false) => {
1482                    self.printer.ibox(1);
1483                }
1484                (true, true) => {
1485                    self.printer.cbox(1);
1486                    self.printer.softbreak();
1487
1488                    self.printer.cbox(-1);
1489                }
1490                (false, true) => {
1491                    self.printer.ibox(1);
1492                    self.printer.ibox(-1);
1493                }
1494            },
1495
1496            State::BraceOpen {
1497                reenter,
1498                reenter_consistency,
1499                ..
1500            } => {
1501                self.printer.neverbreak();
1502                self.printer.cbox(1);
1503
1504                match self.config.compact_blocks {
1505                    true => self.printer.blank(),
1506                    false => self.printer.hardbreak(),
1507                }
1508
1509                if *reenter {
1510                    match *reenter_consistency {
1511                        true => {
1512                            self.printer.cbox(1);
1513                            self.printer.cbox(-1);
1514                        }
1515
1516                        false => {
1517                            self.printer.ibox(1);
1518                            self.printer.ibox(-1);
1519                        }
1520                    }
1521                }
1522            }
1523
1524            State::EmbeddedEnd {
1525                line: embedded_line,
1526            } => {
1527                let sticky = 2 + stickiness_left <= 0;
1528                let concat = concat && embedded_line == &line;
1529
1530                match (sticky, concat) {
1531                    (true, true) => (),
1532                    (true, false) => self.printer.softbreak(),
1533                    (false, true) => self.printer.word(" "),
1534                    (false, false) => self.printer.blank(),
1535                }
1536            }
1537
1538            State::PendingSep {
1539                sep,
1540                line: sep_line,
1541                is_last,
1542                embedded_after,
1543            } => match sep_line == &line {
1544                true => {
1545                    match *is_last {
1546                        true => {
1547                            self.printer.softbreak();
1548                            self.printer.pre_break(*sep);
1549                        }
1550
1551                        false => {
1552                            self.printer.blank();
1553                            self.printer.pre_space(*sep);
1554                            self.printer.pre_break(*sep);
1555                        }
1556                    }
1557
1558                    for comment in embedded_after.iter() {
1559                        self.printer.word(comment);
1560                        self.printer.word(" ");
1561                    }
1562                }
1563
1564                false => {
1565                    let mut embedded = String::new();
1566
1567                    for comment in embedded_after.iter() {
1568                        embedded.push(' ');
1569                        embedded.push_str(comment);
1570                    }
1571
1572                    match *is_last {
1573                        true => {
1574                            self.printer.softbreak();
1575                            self.printer.pre_space(&embedded);
1576                            self.printer.pre_break(format!("{sep}{embedded}"));
1577                        }
1578
1579                        false => {
1580                            embedded = format!("{sep}{embedded}");
1581
1582                            self.printer.blank();
1583                            self.printer.pre_space(&embedded);
1584                            self.printer.pre_break(embedded);
1585                        }
1586                    }
1587                }
1588            },
1589        }
1590
1591        self.printer.word(text);
1592
1593        self.state = State::Word {
1594            stickiness: stickiness_right,
1595            concat_next,
1596            line,
1597        };
1598    }
1599
1600    fn flush(&mut self, line: Line) {
1601        self.print_word("", line, true, true, true);
1602    }
1603
1604    fn flat<'b>(
1605        &self,
1606        parse_node: &'b ParseNode,
1607        parent_op: Precedence,
1608        assoc: Assoc,
1609        unwrap: bool,
1610        result: &mut Vec<FlatChild<'b>>,
1611    ) {
1612        if !parse_node.well_formed {
1613            result.push(FlatChild::Operand(parse_node));
1614            return;
1615        }
1616
1617        match parse_node.rule {
1618            ScriptNode::MULTILINE_COMMENT | ScriptNode::INLINE_COMMENT => {
1619                result.push(FlatChild::Comment(parse_node))
1620            }
1621
1622            ScriptNode::STRING
1623            | ScriptNode::CRATE
1624            | ScriptNode::THIS
1625            | ScriptNode::IDENT
1626            | ScriptNode::NUMBER
1627            | ScriptNode::BOOL
1628            | ScriptNode::MAX
1629            | ScriptNode::FIELD
1630            | ScriptNode::FN
1631            | ScriptNode::STRUCT
1632            | ScriptNode::ARRAY => result.push(FlatChild::Operand(parse_node)),
1633
1634            ScriptNode::UNARY_LEFT
1635            | ScriptNode::BINARY
1636            | ScriptNode::QUERY
1637            | ScriptNode::CALL
1638            | ScriptNode::INDEX => self.flat_infix(parse_node, result),
1639
1640            ScriptNode::EXPR => {
1641                let Some(ScriptNode::Expr { start, .. }) = parse_node.node_ref.deref(self.tree)
1642                else {
1643                    return;
1644                };
1645
1646                match start.is_nil() {
1647                    true => self.flat_expr(parse_node, result),
1648                    false => self.flat_group(parse_node, parent_op, assoc, unwrap, result),
1649                }
1650            }
1651
1652            _ => (),
1653        }
1654    }
1655
1656    fn flat_infix<'b>(&self, parse_node: &'b ParseNode, result: &mut Vec<FlatChild<'b>>) {
1657        enum ScanState {
1658            Begin,
1659            LeftOperand,
1660            Operator,
1661            RightOperand,
1662        }
1663
1664        let mut scan_state = ScanState::Begin;
1665
1666        for child in &parse_node.children {
1667            let ParseNodeChild::Node(child) = &child else {
1668                continue;
1669            };
1670
1671            match child.rule {
1672                ScriptNode::OP | ScriptNode::CALL_ARGS | ScriptNode::INDEX_ARG => {
1673                    scan_state = ScanState::Operator;
1674                }
1675
1676                _ => {
1677                    scan_state = match &scan_state {
1678                        ScanState::Begin | ScanState::LeftOperand => ScanState::LeftOperand,
1679                        ScanState::Operator | ScanState::RightOperand => ScanState::RightOperand,
1680                    }
1681                }
1682            }
1683        }
1684
1685        let has_right_operand = match &scan_state {
1686            ScanState::RightOperand => true,
1687            _ => false,
1688        };
1689
1690        scan_state = ScanState::Begin;
1691
1692        let Some(script_node) = parse_node.node_ref.deref(self.tree) else {
1693            return;
1694        };
1695
1696        let parent_op = script_node.precedence(self.tree);
1697
1698        for child in &parse_node.children {
1699            let ParseNodeChild::Node(child) = &child else {
1700                continue;
1701            };
1702
1703            match child.rule {
1704                ScriptNode::MULTILINE_COMMENT | ScriptNode::INLINE_COMMENT => {
1705                    result.push(FlatChild::Comment(child));
1706                }
1707
1708                ScriptNode::OP | ScriptNode::CALL_ARGS | ScriptNode::INDEX_ARG => {
1709                    match &scan_state {
1710                        ScanState::Begin => result.push(FlatChild::OperatorLeft(child)),
1711                        ScanState::LeftOperand => match has_right_operand {
1712                            true => result.push(FlatChild::OperatorMiddle(child)),
1713                            false => result.push(FlatChild::OperatorRight(child)),
1714                        },
1715
1716                        _ => continue,
1717                    }
1718
1719                    scan_state = ScanState::Operator;
1720                }
1721
1722                _ => {
1723                    let Some(script_node) = child.node_ref.deref(self.tree) else {
1724                        return;
1725                    };
1726
1727                    let operand_op = script_node.precedence(self.tree);
1728
1729                    scan_state = match &scan_state {
1730                        ScanState::Begin | ScanState::LeftOperand => {
1731                            self.flat(
1732                                child,
1733                                parent_op,
1734                                Assoc::Left,
1735                                operand_op.as_operand(Assoc::Left).of(parent_op),
1736                                result,
1737                            );
1738
1739                            ScanState::LeftOperand
1740                        }
1741
1742                        ScanState::Operator | ScanState::RightOperand => {
1743                            self.flat(
1744                                child,
1745                                parent_op,
1746                                Assoc::Right,
1747                                operand_op.as_operand(Assoc::Right).of(parent_op),
1748                                result,
1749                            );
1750
1751                            ScanState::RightOperand
1752                        }
1753                    }
1754                }
1755            }
1756        }
1757    }
1758
1759    fn flat_expr<'b>(&self, parse_node: &'b ParseNode, result: &mut Vec<FlatChild<'b>>) {
1760        let mut unwrap = true;
1761
1762        for child in &parse_node.children {
1763            let ParseNodeChild::Node(child) = &child else {
1764                continue;
1765            };
1766
1767            if let ScriptNode::MULTILINE_COMMENT | ScriptNode::INLINE_COMMENT = child.rule {
1768                unwrap = false;
1769                break;
1770            }
1771        }
1772
1773        for child in &parse_node.children {
1774            let ParseNodeChild::Node(child) = &child else {
1775                continue;
1776            };
1777
1778            self.flat(child, Precedence::Outer, Assoc::Left, unwrap, result);
1779        }
1780    }
1781
1782    fn flat_group<'b>(
1783        &self,
1784        parse_node: &'b ParseNode,
1785        parent_op: Precedence,
1786        assoc: Assoc,
1787        unwrap: bool,
1788        result: &mut Vec<FlatChild<'b>>,
1789    ) {
1790        if self.config.preserve_expr_groups || !unwrap {
1791            result.push(FlatChild::Group(parse_node));
1792            return;
1793        }
1794
1795        let mut inner = None;
1796
1797        for child in &parse_node.children {
1798            let ParseNodeChild::Node(child) = &child else {
1799                continue;
1800            };
1801
1802            match child.rule {
1803                ScriptNode::MULTILINE_COMMENT | ScriptNode::INLINE_COMMENT => {
1804                    result.push(FlatChild::Group(parse_node));
1805                    return;
1806                }
1807
1808                _ => inner = Some(child),
1809            }
1810        }
1811
1812        let Some(inner) = inner else {
1813            result.push(FlatChild::Group(parse_node));
1814            return;
1815        };
1816
1817        if let ScriptNode::FN = inner.rule {
1818            result.push(FlatChild::Group(parse_node));
1819            return;
1820        }
1821
1822        let Some(inner_node) = inner.node_ref.deref(self.tree) else {
1823            result.push(FlatChild::Group(parse_node));
1824            return;
1825        };
1826
1827        let fits = inner_node
1828            .precedence(self.tree)
1829            .as_operand(assoc)
1830            .of(parent_op);
1831
1832        if !fits {
1833            result.push(FlatChild::Group(parse_node));
1834            return;
1835        }
1836
1837        self.flat(inner, parent_op, assoc, true, result);
1838    }
1839}
1840
1841enum State {
1842    Break1,
1843
1844    PendingBreak2,
1845
1846    Word {
1847        stickiness: i8,
1848        concat_next: bool,
1849        line: Line,
1850    },
1851
1852    ParenOpen {
1853        line: Line,
1854        consistent: bool,
1855        dedent_next: bool,
1856    },
1857
1858    BraceOpen {
1859        line: Line,
1860        reenter: bool,
1861        reenter_consistency: bool,
1862    },
1863
1864    BracketOpen {
1865        line: Line,
1866        consistent: bool,
1867        dedent_next: bool,
1868    },
1869
1870    EmbeddedEnd {
1871        line: Line,
1872    },
1873
1874    PendingSep {
1875        sep: &'static str,
1876        line: Line,
1877        is_last: bool,
1878        embedded_after: Vec<String>,
1879    },
1880}
1881
1882enum Group {
1883    Paren,
1884    Brace,
1885    Bracket,
1886}
1887
1888impl Group {
1889    #[inline(always)]
1890    fn from_token_rule(rule: TokenRule) -> Option<(Self, OpenOrClose)> {
1891        if rule == ScriptToken::ParenOpen as u8 {
1892            return Some((Self::Paren, OpenOrClose::Open));
1893        }
1894
1895        if rule == ScriptToken::BraceOpen as u8 {
1896            return Some((Self::Brace, OpenOrClose::Open));
1897        }
1898
1899        if rule == ScriptToken::BracketOpen as u8 {
1900            return Some((Self::Bracket, OpenOrClose::Open));
1901        }
1902
1903        if rule == ScriptToken::ParenClose as u8 {
1904            return Some((Self::Paren, OpenOrClose::Close));
1905        }
1906
1907        if rule == ScriptToken::BraceClose as u8 {
1908            return Some((Self::Brace, OpenOrClose::Close));
1909        }
1910
1911        if rule == ScriptToken::BracketClose as u8 {
1912            return Some((Self::Bracket, OpenOrClose::Close));
1913        }
1914
1915        None
1916    }
1917
1918    #[inline(always)]
1919    fn open(&self) -> &'static str {
1920        match self {
1921            Self::Paren => "(",
1922            Self::Brace => "{",
1923            Self::Bracket => "[",
1924        }
1925    }
1926
1927    #[inline(always)]
1928    fn close(&self) -> &'static str {
1929        match self {
1930            Self::Paren => ")",
1931            Self::Brace => "}",
1932            Self::Bracket => "]",
1933        }
1934    }
1935}
1936
1937enum OpenOrClose {
1938    Open,
1939    Close,
1940}
1941
1942enum BlockUnwrap {
1943    AsIs,
1944    UnwrapOuter,
1945    UnwrapOuterEmpty,
1946    UnwrapClause,
1947    UnwrapReturn,
1948}
1949
1950impl BlockUnwrap {
1951    #[inline(always)]
1952    fn as_is(&self) -> bool {
1953        match self {
1954            Self::AsIs => true,
1955            _ => false,
1956        }
1957    }
1958}
1959
1960enum MatchArmFormat {
1961    EndsWithExpr,
1962    EndsWithBlock,
1963}
1964
1965enum FlatChild<'a> {
1966    OperatorLeft(&'a ParseNode),
1967    OperatorMiddle(&'a ParseNode),
1968    OperatorRight(&'a ParseNode),
1969    Operand(&'a ParseNode),
1970    Group(&'a ParseNode),
1971    Comment(&'a ParseNode),
1972}
1973
1974impl<'a> FlatChild<'a> {
1975    fn requires_consistency<C: SourceCode<Token = ScriptToken>>(
1976        &self,
1977        tree: &ParseTree<ScriptNode, C>,
1978    ) -> bool {
1979        match self {
1980            Self::Comment(_) => return true,
1981
1982            Self::OperatorRight(operator) => {
1983                let Some(script_node) = operator.node_ref.deref(tree) else {
1984                    return true;
1985                };
1986
1987                match script_node {
1988                    ScriptNode::CallArgs { .. } | ScriptNode::IndexArg { .. } => {
1989                        for child in &operator.children {
1990                            match child {
1991                                ParseNodeChild::Blank(_) => (),
1992                                ParseNodeChild::Token(_) => (),
1993                                ParseNodeChild::Node(child) => {
1994                                    if !is_simple_expr(child) {
1995                                        return true;
1996                                    }
1997                                }
1998                            }
1999                        }
2000                    }
2001
2002                    _ => (),
2003                }
2004            }
2005
2006            Self::Operand(operand) => {
2007                if let ScriptNode::FIELD | ScriptNode::ARRAY | ScriptNode::FN | ScriptNode::STRUCT =
2008                    operand.rule
2009                {
2010                    return true;
2011                }
2012            }
2013
2014            _ => (),
2015        }
2016
2017        false
2018    }
2019}
2020
2021fn is_simple_expr(parse_node: &ParseNode) -> bool {
2022    for child in &parse_node.children {
2023        let ParseNodeChild::Node(child) = &child else {
2024            continue;
2025        };
2026
2027        match child.rule {
2028            ScriptNode::PACKAGE
2029            | ScriptNode::ELSE
2030            | ScriptNode::VAR
2031            | ScriptNode::STRUCT_ENTRY_KEY
2032            | ScriptNode::STRING
2033            | ScriptNode::CRATE
2034            | ScriptNode::THIS
2035            | ScriptNode::IDENT
2036            | ScriptNode::NUMBER
2037            | ScriptNode::BOOL
2038            | ScriptNode::OP => (),
2039
2040            ScriptNode::EXPR => {
2041                if !is_simple_expr(child) {
2042                    return false;
2043                }
2044            }
2045
2046            _ => return false,
2047        };
2048    }
2049
2050    true
2051}
2052
2053fn dedent_line(string: &str, mut alignment: usize) -> &str {
2054    let bytes = string.as_bytes();
2055    let mut index = 0;
2056
2057    while alignment > 0 {
2058        let Some(&b' ') = bytes.get(index) else {
2059            break;
2060        };
2061
2062        index += 1;
2063        alignment -= 1;
2064    }
2065
2066    &string[index..]
2067}