1use super::Formatter;
2use super::sequence::{PatternEntry, SiblingEntry};
3use crate::INDENT_WIDTH;
4use crate::comments::prepend_comments;
5use crate::lindig::{Document, concat, flex_break, join, strict_break};
6use syntax::ast::{
7 Annotation, BinaryOperator, Binding, Expression, FormatStringPart, Literal, MatchArm, Pattern,
8 SelectArm, SelectArmPattern, Span, StructFieldAssignment, StructSpread, UnaryOperator,
9};
10
11impl<'a> Formatter<'a> {
12 pub fn expression(&mut self, expression: &'a Expression) -> Document<'a> {
13 let start = expression.get_span().byte_offset;
14 let comments = self.comments.take_comments_before(start);
15
16 let doc = match expression {
17 Expression::Literal { literal, .. } => self.literal(literal),
18 Expression::Identifier { value, .. } => Document::string(value.to_string()),
19 Expression::Unit { .. } => Document::str("()"),
20 Expression::Break { value, .. } => {
21 if let Some(val) = value {
22 Document::str("break ").append(self.expression(val))
23 } else {
24 Document::str("break")
25 }
26 }
27 Expression::Continue { .. } => Document::str("continue"),
28 Expression::NoOp => Document::Sequence(vec![]),
29
30 Expression::Paren { expression, .. } => Document::str("(")
31 .append(self.expression(expression))
32 .append(")"),
33
34 Expression::Block { items, span, .. } => self.block(items, span),
35
36 Expression::Let {
37 binding,
38 value,
39 mutable,
40 else_block,
41 ..
42 } => self.let_(binding, value, *mutable, else_block.as_deref()),
43
44 Expression::Return { expression, .. } => self.return_(expression),
45
46 Expression::If {
47 condition,
48 consequence,
49 alternative,
50 ..
51 } => self.if_(condition, consequence, alternative),
52
53 Expression::IfLet {
54 pattern,
55 scrutinee,
56 consequence,
57 alternative,
58 ..
59 } => self.if_let(pattern, scrutinee, consequence, alternative),
60
61 Expression::Match {
62 subject,
63 arms,
64 span,
65 ..
66 } => self.match_(subject, arms, span),
67
68 Expression::Binary {
69 operator,
70 left,
71 right,
72 ..
73 } => self.binary_operator(operator, left, right),
74
75 Expression::Unary {
76 operator,
77 expression,
78 ..
79 } => self.unary_operator(operator, expression),
80
81 Expression::Call {
82 expression,
83 args,
84 spread,
85 type_args,
86 ..
87 } => self.call(expression, args, spread, type_args),
88
89 Expression::DotAccess {
90 expression, member, ..
91 } => self.dot_access(expression, member),
92
93 Expression::IndexedAccess {
94 expression,
95 index,
96 from_colon_syntax,
97 ..
98 } => self.indexed_access(expression, index, *from_colon_syntax),
99
100 Expression::Tuple { elements, .. } => self.tuple(elements),
101
102 Expression::StructCall {
103 name,
104 field_assignments,
105 spread,
106 ..
107 } => self.struct_call(name, field_assignments, spread),
108
109 Expression::Assignment {
110 target,
111 value,
112 compound_operator,
113 ..
114 } => self.assignment(target, value, *compound_operator),
115
116 Expression::Loop { body, .. } => self.loop_(body),
117
118 Expression::While {
119 condition, body, ..
120 } => self.while_(condition, body),
121
122 Expression::WhileLet {
123 pattern,
124 scrutinee,
125 body,
126 ..
127 } => self.while_let(pattern, scrutinee, body),
128
129 Expression::For {
130 binding,
131 iterable,
132 body,
133 ..
134 } => self.for_(binding, iterable, body),
135
136 Expression::Task { expression, .. } => self.task(expression),
137 Expression::Defer { expression, .. } => self.defer_(expression),
138 Expression::Select { arms, span, .. } => self.select(arms, span),
139 Expression::Propagate { expression, .. } => self.propagate_(expression),
140 Expression::Reference { expression, .. } => self.ref_(expression),
141 Expression::RawGo { text } => Self::raw_go(text),
142
143 Expression::TryBlock { items, span, .. } => self.try_block(items, span),
144 Expression::RecoverBlock { items, span, .. } => self.recover_block(items, span),
145 Expression::Range {
146 start,
147 end,
148 inclusive,
149 ..
150 } => self.range(start, end, *inclusive),
151 Expression::Cast {
152 expression,
153 target_type,
154 ..
155 } => self.cast(expression, target_type),
156
157 Expression::Lambda {
158 params,
159 return_annotation,
160 body,
161 span,
162 ..
163 } => self.lambda(params, return_annotation, body, span),
164
165 _ => self.definition(expression),
166 };
167
168 prepend_comments(doc, comments)
169 }
170
171 pub(super) fn literal(&mut self, literal: &'a Literal) -> Document<'a> {
172 match literal {
173 Literal::Integer { value, text } => {
174 if let Some(original) = text {
175 Document::string(original.clone())
176 } else {
177 Document::string(value.to_string())
178 }
179 }
180 Literal::Float { value, text } => match text {
181 Some(t) => Document::string(t.clone()),
182 None => {
183 let s = value.to_string();
184 if s.contains('.') || s.contains('e') || s.contains('E') {
185 Document::string(s)
186 } else {
187 Document::string(format!("{}.0", s))
188 }
189 }
190 },
191 Literal::Imaginary(coef) => {
192 if *coef == coef.trunc() && coef.abs() < 1e15 {
193 Document::string(format!("{}i", *coef as i64))
194 } else {
195 Document::string(format!("{}i", coef))
196 }
197 }
198 Literal::Boolean(b) => Document::str(if *b { "true" } else { "false" }),
199 Literal::String { value, raw: true } if value.contains('\n') => {
200 Document::verbatim(format!("r\"{value}\""))
201 }
202 Literal::String { value, raw: true } => Document::string(format!("r\"{value}\"")),
203 Literal::String { value, raw: false } if value.contains('\n') => {
204 Document::verbatim(format!("\"{value}\""))
205 }
206 Literal::String { value, raw: false } => Document::string(format!("\"{value}\"")),
207 Literal::Char(c) => Document::string(format!("'{c}'")),
208 Literal::Slice(elements) => self.slice(elements),
209 Literal::FormatString(parts) => self.format_string(parts),
210 }
211 }
212
213 pub(super) fn slice(&mut self, elements: &'a [Expression]) -> Document<'a> {
214 if elements.is_empty() {
215 return Document::str("[]");
216 }
217
218 let elements_docs: Vec<_> = elements.iter().map(|e| self.expression(e)).collect();
219 let elements_doc = join(elements_docs, strict_break(",", ", "));
220
221 Document::str("[")
222 .append(strict_break("", ""))
223 .append(elements_doc)
224 .nest(INDENT_WIDTH)
225 .append(strict_break(",", ""))
226 .append("]")
227 .group()
228 }
229
230 pub(super) fn format_string(&mut self, parts: &'a [FormatStringPart]) -> Document<'a> {
231 let mut docs = vec![Document::str("f\"")];
232
233 for part in parts {
234 match part {
235 FormatStringPart::Text(s) if s.contains('\n') => {
236 docs.push(Document::verbatim(s.clone()))
237 }
238 FormatStringPart::Text(s) => docs.push(Document::string(s.clone())),
239 FormatStringPart::Expression(e) => {
240 docs.push(Document::str("{"));
241 docs.push(self.expression(e));
242 docs.push(Document::str("}"));
243 }
244 }
245 }
246
247 docs.push(Document::str("\""));
248 concat(docs)
249 }
250
251 pub(super) fn block(&mut self, items: &'a [Expression], span: &Span) -> Document<'a> {
252 let block_end = span.byte_offset + span.byte_length;
253
254 if items.is_empty() {
255 return match self.comments.take_comments_before(block_end) {
256 Some(c) => Document::str("{")
257 .append(Document::Newline.append(c).nest(INDENT_WIDTH))
258 .append(Document::Newline)
259 .append("}")
260 .force_break(),
261 None => Document::str("{}"),
262 };
263 }
264
265 let mut docs = Vec::new();
266
267 for (i, item) in items.iter().enumerate() {
268 let start = item.get_span().byte_offset;
269
270 if i > 0 {
271 if self.comments.take_empty_lines_before(start) {
272 docs.push(Document::Newline);
273 docs.push(Document::Newline);
274 } else {
275 docs.push(Document::Newline);
276 }
277 }
278
279 docs.push(self.expression(item));
280 }
281
282 let (same_line, standalone, _) = self.comments.take_split_at_line_start(block_end);
283 if let Some(t) = same_line {
284 docs.push(Document::str(" "));
285 docs.push(t);
286 }
287 if let Some(t) = standalone {
288 docs.push(Document::Newline);
289 docs.push(t.force_break());
290 }
291
292 let body = concat(docs);
293
294 Document::str("{")
295 .append(Document::Newline.append(body).nest(INDENT_WIDTH))
296 .append(Document::Newline)
297 .append("}")
298 .force_break()
299 }
300
301 pub(super) fn let_(
302 &mut self,
303 binding: &'a Binding,
304 value: &'a Expression,
305 mutable: bool,
306 else_block: Option<&'a Expression>,
307 ) -> Document<'a> {
308 let keyword = if mutable { "let mut " } else { "let " };
309
310 let base = Document::str(keyword)
311 .append(self.binding(binding))
312 .append(" = ")
313 .append(self.expression(value));
314
315 if let Some(else_expression) = else_block {
316 base.append(" else ").append(self.as_block(else_expression))
317 } else {
318 base
319 }
320 }
321
322 pub(super) fn return_(&mut self, expression: &'a Expression) -> Document<'a> {
323 if matches!(expression, Expression::Unit { .. }) {
324 Document::str("return")
325 } else {
326 Document::str("return ").append(self.expression(expression))
327 }
328 }
329
330 pub(super) fn if_(
331 &mut self,
332 condition: &'a Expression,
333 consequence: &'a Expression,
334 alternative: &'a Expression,
335 ) -> Document<'a> {
336 let if_doc = Document::str("if ")
337 .append(self.expression(condition))
338 .append(" ")
339 .append(self.as_inline_block(consequence));
340
341 match alternative {
342 Expression::Unit { .. } => if_doc,
343 Expression::If { .. } | Expression::IfLet { .. } => {
344 if_doc.append(" else ").append(self.expression(alternative))
345 }
346 _ => if_doc
347 .append(" else ")
348 .append(self.as_inline_block(alternative)),
349 }
350 .group()
351 }
352
353 pub(super) fn if_let(
354 &mut self,
355 pattern: &'a Pattern,
356 scrutinee: &'a Expression,
357 consequence: &'a Expression,
358 alternative: &'a Expression,
359 ) -> Document<'a> {
360 let if_let_doc = Document::str("if let ")
361 .append(self.pattern(pattern))
362 .append(" = ")
363 .append(self.expression(scrutinee))
364 .append(" ")
365 .append(self.as_inline_block(consequence));
366
367 match alternative {
368 Expression::Unit { .. } => if_let_doc,
369 Expression::If { .. } | Expression::IfLet { .. } => if_let_doc
370 .append(" else ")
371 .append(self.expression(alternative)),
372 _ => if_let_doc
373 .append(" else ")
374 .append(self.as_inline_block(alternative)),
375 }
376 .group()
377 }
378
379 pub(super) fn as_block(&mut self, expression: &'a Expression) -> Document<'a> {
380 match expression {
381 Expression::Block { items, span, .. } => self.block(items, span),
382 Expression::NoOp => Document::Sequence(vec![]),
383 _ => Document::str("{ ")
384 .append(self.expression(expression))
385 .append(" }"),
386 }
387 }
388
389 pub(super) fn as_inline_block(&mut self, expression: &'a Expression) -> Document<'a> {
393 match expression {
394 Expression::Block { items, span, .. } => {
395 if items.len() == 1 && !self.comments.has_comments_in_range(*span) {
396 let expression = self.expression(&items[0]);
397 return Document::str("{")
398 .append(strict_break("", " ").append(expression).nest(INDENT_WIDTH))
399 .append(strict_break("", " "))
400 .append("}");
401 }
402 self.block(items, span)
403 }
404 Expression::NoOp => Document::Sequence(vec![]),
405 _ => {
406 let expression = self.expression(expression);
407 Document::str("{")
408 .append(strict_break("", " ").append(expression).nest(INDENT_WIDTH))
409 .append(strict_break("", " "))
410 .append("}")
411 }
412 }
413 }
414
415 pub(super) fn match_arm_entries(&mut self, arms: &'a [MatchArm]) -> Vec<SiblingEntry<'a>> {
416 let mut entries: Vec<SiblingEntry<'a>> = Vec::with_capacity(arms.len());
417 for arm in arms {
418 let start = arm.pattern.get_span().byte_offset;
419 self.push_sibling_entry(&mut entries, start, |s| {
420 let pattern = s.pattern(&arm.pattern);
421 let expression = s.expression(&arm.expression);
422 let pattern_with_guard = if let Some(guard) = &arm.guard {
423 pattern.append(" if ").append(s.expression(guard))
424 } else {
425 pattern
426 };
427 pattern_with_guard
428 .append(" => ")
429 .append(expression)
430 .append(",")
431 });
432 }
433 entries
434 }
435
436 pub(super) fn match_(
437 &mut self,
438 subject: &'a Expression,
439 arms: &'a [MatchArm],
440 span: &Span,
441 ) -> Document<'a> {
442 let entries = self.match_arm_entries(arms);
443
444 let header = Document::str("match ").append(self.expression(subject));
445 let body = self.join_sibling_body(entries, span.end());
446 Self::braced_body(header, body)
447 }
448
449 pub(super) fn loop_(&mut self, body: &'a Expression) -> Document<'a> {
450 Document::str("loop ").append(self.as_block(body))
451 }
452
453 pub(super) fn while_(
454 &mut self,
455 condition: &'a Expression,
456 body: &'a Expression,
457 ) -> Document<'a> {
458 Document::str("while ")
459 .append(self.expression(condition))
460 .append(" ")
461 .append(self.as_block(body))
462 }
463
464 pub(super) fn while_let(
465 &mut self,
466 pattern: &'a Pattern,
467 scrutinee: &'a Expression,
468 body: &'a Expression,
469 ) -> Document<'a> {
470 Document::str("while let ")
471 .append(self.pattern(pattern))
472 .append(" = ")
473 .append(self.expression(scrutinee))
474 .append(" ")
475 .append(self.as_block(body))
476 }
477
478 pub(super) fn for_(
479 &mut self,
480 binding: &'a Binding,
481 iterable: &'a Expression,
482 body: &'a Expression,
483 ) -> Document<'a> {
484 Document::str("for ")
485 .append(self.binding(binding))
486 .append(" in ")
487 .append(self.expression(iterable))
488 .append(" ")
489 .append(self.as_block(body))
490 }
491
492 pub(super) fn binary_operator(
493 &mut self,
494 operator: &BinaryOperator,
495 left_operand: &'a Expression,
496 right_operand: &'a Expression,
497 ) -> Document<'a> {
498 use BinaryOperator::*;
499
500 if matches!(operator, Pipeline) {
501 return self.pipeline(left_operand, right_operand);
502 }
503
504 let operator_string = match operator {
505 Addition => "+",
506 Subtraction => "-",
507 Multiplication => "*",
508 Division => "/",
509 Remainder => "%",
510 BitwiseAnd => "&",
511 BitwiseOr => "|",
512 BitwiseXor => "^",
513 BitwiseAndNot => "&^",
514 ShiftLeft => "<<",
515 ShiftRight => ">>",
516 LessThan => "<",
517 LessThanOrEqual => "<=",
518 GreaterThan => ">",
519 GreaterThanOrEqual => ">=",
520 Equal => "==",
521 NotEqual => "!=",
522 And => "&&",
523 Or => "||",
524 Pipeline => unreachable!(),
525 };
526
527 self.expression(left_operand)
528 .append(" ")
529 .append(operator_string)
530 .append(strict_break("", " "))
531 .append(self.expression(right_operand))
532 .group()
533 }
534
535 pub(super) fn pipeline(&mut self, left: &'a Expression, right: &'a Expression) -> Document<'a> {
536 let mut segments = vec![right];
537 let mut current = left;
538
539 while let Expression::Binary {
540 operator: BinaryOperator::Pipeline,
541 left: l,
542 right: r,
543 ..
544 } = current
545 {
546 segments.push(r);
547 current = l;
548 }
549 segments.push(current);
550 segments.reverse();
551
552 if segments.len() == 2 {
553 return self
554 .expression(segments[0])
555 .append(flex_break("", " "))
556 .append("|> ")
557 .append(self.expression(segments[1]))
558 .nest_if_broken(INDENT_WIDTH)
559 .group();
560 }
561
562 let docs: Vec<_> = segments
563 .iter()
564 .enumerate()
565 .map(|(i, seg)| {
566 if i == 0 {
567 self.expression(seg)
568 } else {
569 Document::Newline.append("|> ").append(self.expression(seg))
570 }
571 })
572 .collect();
573
574 concat(docs).nest(INDENT_WIDTH)
575 }
576
577 pub(super) fn unary_operator(
578 &mut self,
579 operator: &UnaryOperator,
580 expression: &'a Expression,
581 ) -> Document<'a> {
582 match operator {
583 UnaryOperator::Negative => Document::str("-").append(self.expression(expression)),
584 UnaryOperator::Not => Document::str("!").append(self.expression(expression)),
585 UnaryOperator::BitwiseNot => Document::str("^").append(self.expression(expression)),
586 UnaryOperator::Deref => self.expression(expression).append(".*"),
587 }
588 }
589
590 pub(super) fn call(
591 &mut self,
592 callee: &'a Expression,
593 args: &'a [Expression],
594 spread: &'a Option<Expression>,
595 type_args: &'a [Annotation],
596 ) -> Document<'a> {
597 if let Expression::DotAccess {
598 expression: inner,
599 member,
600 span,
601 ..
602 } = callee
603 {
604 let (root, mut chain_segments) = collect_method_chain(inner);
605 let member_start = span.byte_offset + span.byte_length - member.len() as u32;
606 chain_segments.push(MethodChainSegment {
607 member,
608 member_start,
609 args,
610 spread,
611 type_args,
612 });
613 if chain_segments.len() >= 2 {
614 return self.format_method_chain(root, &chain_segments);
615 }
616 let snapshot = self.comments.cursor_snapshot();
620 let root_doc = self.expression(root);
621 let has_inter_segment_comments = self
622 .comments
623 .has_comments_before(chain_segments[0].member_start);
624 if has_inter_segment_comments {
625 return self.format_method_chain_with_root(root_doc, &chain_segments);
626 }
627 self.comments.restore_cursor(snapshot);
628 }
629
630 let head = self
631 .expression(callee)
632 .append(Self::format_type_args(type_args));
633 self.format_call_with_head(head, args, spread)
634 }
635
636 pub(super) fn format_type_args(type_args: &'a [Annotation]) -> Document<'a> {
637 if type_args.is_empty() {
638 Document::Sequence(vec![])
639 } else {
640 let types: Vec<_> = type_args.iter().map(Self::annotation).collect();
641 Document::str("<")
642 .append(join(types, Document::str(", ")))
643 .append(">")
644 }
645 }
646
647 pub(super) fn format_call_with_head(
648 &mut self,
649 head: Document<'a>,
650 args: &'a [Expression],
651 spread: &'a Option<Expression>,
652 ) -> Document<'a> {
653 if args.is_empty() && spread.is_none() {
654 return head.append("()");
655 }
656
657 if let Some(spread_expr) = spread {
658 if args.is_empty() {
659 let spread_doc = self.expression(spread_expr).append(Document::str("..."));
660 return head
661 .append("(")
662 .append(spread_doc.group().next_break_fits(true))
663 .append(")")
664 .next_break_fits(false)
665 .group();
666 }
667 let mut entries = self.call_arg_entries(args);
668 let spread_start = spread_expr.get_span().byte_offset;
669 let spread_leading = self.split_for_rest(&mut entries, spread_start);
670 let spread_doc = self.expression(spread_expr).append(Document::str("..."));
671 let (body, close_sep) =
672 Self::join_pattern_entries(entries, Some((spread_leading, spread_doc)), "");
673 return head
674 .append("(")
675 .append(strict_break("", ""))
676 .append(body)
677 .nest(INDENT_WIDTH)
678 .append(close_sep)
679 .append(")")
680 .next_break_fits(false)
681 .group();
682 }
683
684 let Some((last, init)) = args
685 .split_last()
686 .filter(|(last, _)| is_inlinable_arg(last, args.len()))
687 else {
688 let entries = self.call_arg_entries(args);
689 let (body, close_sep) = Self::join_pattern_entries(entries, None, "");
690 return head
691 .append("(")
692 .append(strict_break("", ""))
693 .append(body)
694 .nest(INDENT_WIDTH)
695 .append(close_sep)
696 .append(")")
697 .group();
698 };
699
700 if init.is_empty() {
701 let last_doc = self.expression(last).group().next_break_fits(true);
702 head.append("(")
703 .append(last_doc)
704 .append(")")
705 .next_break_fits(false)
706 .group()
707 } else {
708 let mut entries = self.call_arg_entries(init);
709 let last_start = last.get_span().byte_offset;
710 let last_leading = self.split_for_rest(&mut entries, last_start);
711 let last_doc = self.expression(last).group().next_break_fits(true);
712 let (body, close_sep) =
713 Self::join_pattern_entries(entries, Some((last_leading, last_doc)), "");
714 head.append("(")
715 .append(strict_break("", ""))
716 .append(body)
717 .nest(INDENT_WIDTH)
718 .append(close_sep)
719 .append(")")
720 .next_break_fits(false)
721 .group()
722 }
723 }
724
725 pub(super) fn call_arg_entries(&mut self, args: &'a [Expression]) -> Vec<PatternEntry<'a>> {
726 let mut entries: Vec<PatternEntry<'a>> = Vec::with_capacity(args.len());
727 for arg in args {
728 self.push_pattern_entry(&mut entries, arg.get_span().byte_offset, |s| {
729 s.expression(arg)
730 });
731 }
732 entries
733 }
734
735 fn format_method_chain(
736 &mut self,
737 root: &'a Expression,
738 segments: &[MethodChainSegment<'a>],
739 ) -> Document<'a> {
740 let root_doc = self.expression(root);
741 self.format_method_chain_with_root(root_doc, segments)
742 }
743
744 fn format_method_chain_with_root(
745 &mut self,
746 root_doc: Document<'a>,
747 segments: &[MethodChainSegment<'a>],
748 ) -> Document<'a> {
749 let segment_docs: Vec<Document<'a>> = segments
750 .iter()
751 .map(|seg| {
752 let comments = self.comments.take_comments_before(seg.member_start);
753 let head = Document::str(".")
754 .append(seg.member)
755 .append(Self::format_type_args(seg.type_args));
756 let call_doc = strict_break("", "")
757 .append(self.format_call_with_head(head, seg.args, seg.spread));
758 match comments {
759 Some(c) => strict_break("", "")
760 .append(c)
761 .force_break()
762 .append(call_doc),
763 None => call_doc,
764 }
765 })
766 .collect();
767
768 root_doc
769 .append(concat(segment_docs).nest_if_broken(INDENT_WIDTH))
770 .group()
771 }
772
773 pub(super) fn dot_access(
774 &mut self,
775 expression: &'a Expression,
776 member: &'a str,
777 ) -> Document<'a> {
778 self.expression(expression).append(".").append(member)
779 }
780
781 pub(super) fn indexed_access(
782 &mut self,
783 expression: &'a Expression,
784 index: &'a Expression,
785 from_colon_syntax: bool,
786 ) -> Document<'a> {
787 let body = if from_colon_syntax && let Expression::Range { start, end, .. } = index {
788 let start_doc = match start {
789 Some(s) => self.expression(s),
790 None => Document::str(""),
791 };
792 let end_doc = match end {
793 Some(e) => self.expression(e),
794 None => Document::str(""),
795 };
796 start_doc.append(":").append(end_doc)
797 } else {
798 self.expression(index)
799 };
800 self.expression(expression)
801 .append("[")
802 .append(body)
803 .append("]")
804 }
805
806 pub(super) fn tuple(&mut self, elements: &'a [Expression]) -> Document<'a> {
807 if elements.is_empty() {
808 return Document::str("()");
809 }
810
811 let elements_docs: Vec<_> = elements.iter().map(|e| self.expression(e)).collect();
812 let elements_doc = join(elements_docs, strict_break(",", ", "));
813
814 Document::str("(")
815 .append(strict_break("", ""))
816 .append(elements_doc)
817 .nest(INDENT_WIDTH)
818 .append(strict_break(",", ""))
819 .append(")")
820 .group()
821 }
822
823 pub(super) fn struct_call(
824 &mut self,
825 name: &'a str,
826 fields: &'a [StructFieldAssignment],
827 spread: &'a StructSpread,
828 ) -> Document<'a> {
829 let mut entries: Vec<PatternEntry<'a>> = Vec::with_capacity(fields.len());
830 for f in fields {
831 self.push_pattern_entry(&mut entries, f.name_span.byte_offset, |s| {
832 if let Expression::Identifier { value, .. } = &*f.value
833 && value == &f.name
834 {
835 Document::string(f.name.to_string())
836 } else {
837 Document::string(f.name.to_string())
838 .append(": ")
839 .append(s.expression(&f.value))
840 }
841 });
842 }
843
844 let rest_info = match spread {
845 StructSpread::None => None,
846 StructSpread::From(spread_expression) => {
847 let dots_pos = spread_expression.get_span().byte_offset.saturating_sub(2);
848 let leading = self.split_for_rest(&mut entries, dots_pos);
849 Some((
850 leading,
851 Document::str("..").append(self.expression(spread_expression)),
852 ))
853 }
854 StructSpread::ZeroFill { span } => {
855 let leading = self.split_for_rest(&mut entries, span.byte_offset);
856 Some((leading, Document::str("..")))
857 }
858 };
859
860 if entries.is_empty() && rest_info.is_none() {
861 return Document::str(name).append(" {}");
862 }
863
864 let (body, close_sep) = Self::join_pattern_entries(entries, rest_info, " ");
865
866 Document::str(name)
867 .append(" {")
868 .append(strict_break(" ", " "))
869 .append(body)
870 .nest(INDENT_WIDTH)
871 .append(close_sep)
872 .append("}")
873 .group()
874 }
875
876 pub(super) fn assignment(
877 &mut self,
878 target: &'a Expression,
879 value: &'a Expression,
880 compound_operator: Option<BinaryOperator>,
881 ) -> Document<'a> {
882 if let Some(op) = compound_operator
883 && let Some(op_str) = match op {
884 BinaryOperator::Addition => Some("+="),
885 BinaryOperator::Subtraction => Some("-="),
886 BinaryOperator::Multiplication => Some("*="),
887 BinaryOperator::Division => Some("/="),
888 BinaryOperator::Remainder => Some("%="),
889 _ => None,
890 }
891 && let Expression::Binary { right, .. } = value
892 {
893 return self
894 .expression(target)
895 .append(" ")
896 .append(op_str)
897 .append(" ")
898 .append(self.expression(right));
899 }
900
901 self.expression(target)
902 .append(" = ")
903 .append(self.expression(value))
904 }
905
906 pub(super) fn lambda(
907 &mut self,
908 params: &'a [Binding],
909 return_annotation: &'a Annotation,
910 body: &'a Expression,
911 _span: &'a Span,
912 ) -> Document<'a> {
913 let params_docs: Vec<_> = params.iter().map(|p| self.binding(p)).collect();
914
915 let params_doc = if params_docs.is_empty() {
916 Document::str("||")
917 } else {
918 Document::str("|")
919 .append(strict_break("", ""))
920 .append(join(params_docs, strict_break(",", ", ")))
921 .nest(INDENT_WIDTH)
922 .append(strict_break(",", ""))
923 .append("|")
924 .group()
925 };
926
927 let return_doc = if return_annotation.is_unknown() {
928 Document::Sequence(vec![])
929 } else {
930 Document::str(" -> ").append(Self::annotation(return_annotation))
931 };
932
933 let body_doc = self.expression(body);
934
935 params_doc.append(return_doc).append(" ").append(body_doc)
936 }
937
938 pub(super) fn task(&mut self, expression: &'a Expression) -> Document<'a> {
939 Document::str("task ").append(self.expression(expression))
940 }
941
942 pub(super) fn defer_(&mut self, expression: &'a Expression) -> Document<'a> {
943 Document::str("defer ").append(self.expression(expression))
944 }
945
946 pub(super) fn try_block(&mut self, items: &'a [Expression], span: &Span) -> Document<'a> {
947 Document::str("try ").append(self.block(items, span))
948 }
949
950 pub(super) fn recover_block(&mut self, items: &'a [Expression], span: &Span) -> Document<'a> {
951 Document::str("recover ").append(self.block(items, span))
952 }
953
954 pub(super) fn range(
955 &mut self,
956 start: &'a Option<Box<Expression>>,
957 end: &'a Option<Box<Expression>>,
958 inclusive: bool,
959 ) -> Document<'a> {
960 let start_doc = match start {
961 Some(e) => self.expression(e),
962 None => Document::Sequence(vec![]),
963 };
964 let end_doc = match end {
965 Some(e) => self.expression(e),
966 None => Document::Sequence(vec![]),
967 };
968 let op = if inclusive { "..=" } else { ".." };
969 start_doc.append(op).append(end_doc)
970 }
971
972 pub(super) fn cast(
973 &mut self,
974 expression: &'a Expression,
975 target_type: &'a Annotation,
976 ) -> Document<'a> {
977 self.expression(expression)
978 .append(" as ")
979 .append(Self::annotation(target_type))
980 }
981
982 pub(super) fn select(&mut self, arms: &'a [SelectArm], span: &Span) -> Document<'a> {
983 let mut entries: Vec<SiblingEntry<'a>> = Vec::with_capacity(arms.len());
984 for (i, arm) in arms.iter().enumerate() {
985 let start = Self::select_arm_start(arm);
986 let upper_bound = arms
987 .get(i + 1)
988 .map(Self::select_arm_start)
989 .unwrap_or_else(|| span.end());
990 self.push_sibling_entry(&mut entries, start, |s| s.select_arm_body(arm, upper_bound));
991 }
992 let body = self.join_sibling_body(entries, span.end());
993 Self::braced_body(Document::str("select"), body)
994 }
995
996 pub(super) fn select_arm_start(arm: &'a SelectArm) -> u32 {
997 match &arm.pattern {
998 SelectArmPattern::Receive { binding, .. } => binding.get_span().byte_offset,
999 SelectArmPattern::Send {
1000 send_expression, ..
1001 } => send_expression.get_span().byte_offset,
1002 SelectArmPattern::MatchReceive {
1003 receive_expression, ..
1004 } => receive_expression.get_span().byte_offset,
1005 SelectArmPattern::WildCard { body } => body.get_span().byte_offset,
1006 }
1007 }
1008
1009 pub(super) fn select_arm_body(&mut self, arm: &'a SelectArm, upper_bound: u32) -> Document<'a> {
1010 match &arm.pattern {
1011 SelectArmPattern::Receive {
1012 binding,
1013 receive_expression,
1014 body,
1015 ..
1016 } => Document::str("let ")
1017 .append(self.pattern(binding))
1018 .append(" = ")
1019 .append(self.expression(receive_expression))
1020 .append(" => ")
1021 .append(self.expression(body))
1022 .append(","),
1023 SelectArmPattern::Send {
1024 send_expression,
1025 body,
1026 } => self
1027 .expression(send_expression)
1028 .append(" => ")
1029 .append(self.expression(body))
1030 .append(","),
1031 SelectArmPattern::MatchReceive {
1032 receive_expression,
1033 arms,
1034 } => {
1035 let header = Document::str("match ").append(self.expression(receive_expression));
1036 let last_arm_end = arms
1037 .last()
1038 .map(|a| a.expression.get_span().end())
1039 .unwrap_or(0);
1040 let body_end = self
1042 .comments
1043 .next_byte_at(b'}', last_arm_end, upper_bound)
1044 .unwrap_or(last_arm_end);
1045 let entries = self.match_arm_entries(arms);
1046 let body = self.join_sibling_body(entries, body_end);
1047 Self::braced_body(header, body).append(",")
1048 }
1049 SelectArmPattern::WildCard { body } => Document::str("_")
1050 .append(" => ")
1051 .append(self.expression(body))
1052 .append(","),
1053 }
1054 }
1055
1056 pub(super) fn propagate_(&mut self, expression: &'a Expression) -> Document<'a> {
1057 self.expression(expression).append("?")
1058 }
1059
1060 pub(super) fn ref_(&mut self, expression: &'a Expression) -> Document<'a> {
1061 Document::str("&").append(self.expression(expression))
1062 }
1063
1064 pub(super) fn raw_go(text: &'a str) -> Document<'a> {
1065 Document::str("@rawgo(\"")
1066 .append(Document::str(text))
1067 .append("\")")
1068 }
1069}
1070
1071struct MethodChainSegment<'a> {
1072 member: &'a str,
1073 member_start: u32,
1074 args: &'a [Expression],
1075 spread: &'a Option<Expression>,
1076 type_args: &'a [Annotation],
1077}
1078
1079fn collect_method_chain(expression: &Expression) -> (&Expression, Vec<MethodChainSegment<'_>>) {
1080 let mut segments = Vec::new();
1081 let mut current = expression;
1082
1083 while let Expression::Call {
1084 expression,
1085 args,
1086 spread,
1087 type_args,
1088 ..
1089 } = current
1090 {
1091 let Expression::DotAccess {
1092 expression: inner,
1093 member,
1094 span,
1095 ..
1096 } = expression.as_ref()
1097 else {
1098 break;
1099 };
1100 let member_start = span.byte_offset + span.byte_length - member.len() as u32;
1101 segments.push(MethodChainSegment {
1102 member,
1103 member_start,
1104 args,
1105 spread,
1106 type_args,
1107 });
1108 current = inner;
1109 }
1110
1111 segments.reverse();
1112 (current, segments)
1113}
1114
1115fn is_inlinable_arg(expression: &Expression, arity: usize) -> bool {
1116 matches!(
1117 expression,
1118 Expression::Lambda { .. }
1119 | Expression::Block { .. }
1120 | Expression::Match { .. }
1121 | Expression::Tuple { .. }
1122 | Expression::Literal {
1123 literal: Literal::Slice(_),
1124 ..
1125 }
1126 ) || matches!(expression, Expression::Call { .. } if arity == 1)
1127}