1use 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#[derive(Clone, Copy, Debug, PartialEq, Eq, Hash)]
52#[non_exhaustive]
53pub struct ScriptFormatConfig {
54 pub margin: u16,
59
60 pub inline: u16,
66
67 pub indent: u16,
71
72 pub preserve_expr_groups: bool,
81
82 pub preserve_blank_lines: bool,
88
89 pub preserve_blocks: bool,
99
100 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 #[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#[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}