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