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 LessThan => "<",
511 LessThanOrEqual => "<=",
512 GreaterThan => ">",
513 GreaterThanOrEqual => ">=",
514 Equal => "==",
515 NotEqual => "!=",
516 And => "&&",
517 Or => "||",
518 Pipeline => unreachable!(),
519 };
520
521 self.expression(left_operand)
522 .append(" ")
523 .append(operator_string)
524 .append(strict_break("", " "))
525 .append(self.expression(right_operand))
526 .group()
527 }
528
529 pub(super) fn pipeline(&mut self, left: &'a Expression, right: &'a Expression) -> Document<'a> {
530 let mut segments = vec![right];
531 let mut current = left;
532
533 while let Expression::Binary {
534 operator: BinaryOperator::Pipeline,
535 left: l,
536 right: r,
537 ..
538 } = current
539 {
540 segments.push(r);
541 current = l;
542 }
543 segments.push(current);
544 segments.reverse();
545
546 if segments.len() == 2 {
547 return self
548 .expression(segments[0])
549 .append(flex_break("", " "))
550 .append("|> ")
551 .append(self.expression(segments[1]))
552 .nest_if_broken(INDENT_WIDTH)
553 .group();
554 }
555
556 let docs: Vec<_> = segments
557 .iter()
558 .enumerate()
559 .map(|(i, seg)| {
560 if i == 0 {
561 self.expression(seg)
562 } else {
563 Document::Newline.append("|> ").append(self.expression(seg))
564 }
565 })
566 .collect();
567
568 concat(docs).nest(INDENT_WIDTH)
569 }
570
571 pub(super) fn unary_operator(
572 &mut self,
573 operator: &UnaryOperator,
574 expression: &'a Expression,
575 ) -> Document<'a> {
576 match operator {
577 UnaryOperator::Negative => Document::str("-").append(self.expression(expression)),
578 UnaryOperator::Not => Document::str("!").append(self.expression(expression)),
579 UnaryOperator::Deref => self.expression(expression).append(".*"),
580 }
581 }
582
583 pub(super) fn call(
584 &mut self,
585 callee: &'a Expression,
586 args: &'a [Expression],
587 spread: &'a Option<Expression>,
588 type_args: &'a [Annotation],
589 ) -> Document<'a> {
590 if let Expression::DotAccess {
591 expression: inner,
592 member,
593 span,
594 ..
595 } = callee
596 {
597 let (root, mut chain_segments) = collect_method_chain(inner);
598 let member_start = span.byte_offset + span.byte_length - member.len() as u32;
599 chain_segments.push(MethodChainSegment {
600 member,
601 member_start,
602 args,
603 spread,
604 type_args,
605 });
606 if chain_segments.len() >= 2 {
607 return self.format_method_chain(root, &chain_segments);
608 }
609 let snapshot = self.comments.cursor_snapshot();
613 let root_doc = self.expression(root);
614 let has_inter_segment_comments = self
615 .comments
616 .has_comments_before(chain_segments[0].member_start);
617 if has_inter_segment_comments {
618 return self.format_method_chain_with_root(root_doc, &chain_segments);
619 }
620 self.comments.restore_cursor(snapshot);
621 }
622
623 let head = self
624 .expression(callee)
625 .append(Self::format_type_args(type_args));
626 self.format_call_with_head(head, args, spread)
627 }
628
629 pub(super) fn format_type_args(type_args: &'a [Annotation]) -> Document<'a> {
630 if type_args.is_empty() {
631 Document::Sequence(vec![])
632 } else {
633 let types: Vec<_> = type_args.iter().map(Self::annotation).collect();
634 Document::str("<")
635 .append(join(types, Document::str(", ")))
636 .append(">")
637 }
638 }
639
640 pub(super) fn format_call_with_head(
641 &mut self,
642 head: Document<'a>,
643 args: &'a [Expression],
644 spread: &'a Option<Expression>,
645 ) -> Document<'a> {
646 if args.is_empty() && spread.is_none() {
647 return head.append("()");
648 }
649
650 if let Some(spread_expr) = spread {
651 if args.is_empty() {
652 let spread_doc = self.expression(spread_expr).append(Document::str("..."));
653 return head
654 .append("(")
655 .append(spread_doc.group().next_break_fits(true))
656 .append(")")
657 .next_break_fits(false)
658 .group();
659 }
660 let mut entries = self.call_arg_entries(args);
661 let spread_start = spread_expr.get_span().byte_offset;
662 let spread_leading = self.split_for_rest(&mut entries, spread_start);
663 let spread_doc = self.expression(spread_expr).append(Document::str("..."));
664 let (body, close_sep) =
665 Self::join_pattern_entries(entries, Some((spread_leading, spread_doc)), "");
666 return head
667 .append("(")
668 .append(strict_break("", ""))
669 .append(body)
670 .nest(INDENT_WIDTH)
671 .append(close_sep)
672 .append(")")
673 .next_break_fits(false)
674 .group();
675 }
676
677 let Some((last, init)) = args
678 .split_last()
679 .filter(|(last, _)| is_inlinable_arg(last, args.len()))
680 else {
681 let entries = self.call_arg_entries(args);
682 let (body, close_sep) = Self::join_pattern_entries(entries, None, "");
683 return head
684 .append("(")
685 .append(strict_break("", ""))
686 .append(body)
687 .nest(INDENT_WIDTH)
688 .append(close_sep)
689 .append(")")
690 .group();
691 };
692
693 if init.is_empty() {
694 let last_doc = self.expression(last).group().next_break_fits(true);
695 head.append("(")
696 .append(last_doc)
697 .append(")")
698 .next_break_fits(false)
699 .group()
700 } else {
701 let mut entries = self.call_arg_entries(init);
702 let last_start = last.get_span().byte_offset;
703 let last_leading = self.split_for_rest(&mut entries, last_start);
704 let last_doc = self.expression(last).group().next_break_fits(true);
705 let (body, close_sep) =
706 Self::join_pattern_entries(entries, Some((last_leading, last_doc)), "");
707 head.append("(")
708 .append(strict_break("", ""))
709 .append(body)
710 .nest(INDENT_WIDTH)
711 .append(close_sep)
712 .append(")")
713 .next_break_fits(false)
714 .group()
715 }
716 }
717
718 pub(super) fn call_arg_entries(&mut self, args: &'a [Expression]) -> Vec<PatternEntry<'a>> {
719 let mut entries: Vec<PatternEntry<'a>> = Vec::with_capacity(args.len());
720 for arg in args {
721 self.push_pattern_entry(&mut entries, arg.get_span().byte_offset, |s| {
722 s.expression(arg)
723 });
724 }
725 entries
726 }
727
728 fn format_method_chain(
729 &mut self,
730 root: &'a Expression,
731 segments: &[MethodChainSegment<'a>],
732 ) -> Document<'a> {
733 let root_doc = self.expression(root);
734 self.format_method_chain_with_root(root_doc, segments)
735 }
736
737 fn format_method_chain_with_root(
738 &mut self,
739 root_doc: Document<'a>,
740 segments: &[MethodChainSegment<'a>],
741 ) -> Document<'a> {
742 let segment_docs: Vec<Document<'a>> = segments
743 .iter()
744 .map(|seg| {
745 let comments = self.comments.take_comments_before(seg.member_start);
746 let head = Document::str(".")
747 .append(seg.member)
748 .append(Self::format_type_args(seg.type_args));
749 let call_doc = strict_break("", "")
750 .append(self.format_call_with_head(head, seg.args, seg.spread));
751 match comments {
752 Some(c) => strict_break("", "")
753 .append(c)
754 .force_break()
755 .append(call_doc),
756 None => call_doc,
757 }
758 })
759 .collect();
760
761 root_doc
762 .append(concat(segment_docs).nest_if_broken(INDENT_WIDTH))
763 .group()
764 }
765
766 pub(super) fn dot_access(
767 &mut self,
768 expression: &'a Expression,
769 member: &'a str,
770 ) -> Document<'a> {
771 self.expression(expression).append(".").append(member)
772 }
773
774 pub(super) fn indexed_access(
775 &mut self,
776 expression: &'a Expression,
777 index: &'a Expression,
778 from_colon_syntax: bool,
779 ) -> Document<'a> {
780 let body = if from_colon_syntax && let Expression::Range { start, end, .. } = index {
781 let start_doc = match start {
782 Some(s) => self.expression(s),
783 None => Document::str(""),
784 };
785 let end_doc = match end {
786 Some(e) => self.expression(e),
787 None => Document::str(""),
788 };
789 start_doc.append(":").append(end_doc)
790 } else {
791 self.expression(index)
792 };
793 self.expression(expression)
794 .append("[")
795 .append(body)
796 .append("]")
797 }
798
799 pub(super) fn tuple(&mut self, elements: &'a [Expression]) -> Document<'a> {
800 if elements.is_empty() {
801 return Document::str("()");
802 }
803
804 let elements_docs: Vec<_> = elements.iter().map(|e| self.expression(e)).collect();
805 let elements_doc = join(elements_docs, strict_break(",", ", "));
806
807 Document::str("(")
808 .append(strict_break("", ""))
809 .append(elements_doc)
810 .nest(INDENT_WIDTH)
811 .append(strict_break(",", ""))
812 .append(")")
813 .group()
814 }
815
816 pub(super) fn struct_call(
817 &mut self,
818 name: &'a str,
819 fields: &'a [StructFieldAssignment],
820 spread: &'a StructSpread,
821 ) -> Document<'a> {
822 let mut entries: Vec<PatternEntry<'a>> = Vec::with_capacity(fields.len());
823 for f in fields {
824 self.push_pattern_entry(&mut entries, f.name_span.byte_offset, |s| {
825 if let Expression::Identifier { value, .. } = &*f.value
826 && value == &f.name
827 {
828 Document::string(f.name.to_string())
829 } else {
830 Document::string(f.name.to_string())
831 .append(": ")
832 .append(s.expression(&f.value))
833 }
834 });
835 }
836
837 let rest_info = match spread {
838 StructSpread::None => None,
839 StructSpread::From(spread_expression) => {
840 let dots_pos = spread_expression.get_span().byte_offset.saturating_sub(2);
841 let leading = self.split_for_rest(&mut entries, dots_pos);
842 Some((
843 leading,
844 Document::str("..").append(self.expression(spread_expression)),
845 ))
846 }
847 StructSpread::ZeroFill { span } => {
848 let leading = self.split_for_rest(&mut entries, span.byte_offset);
849 Some((leading, Document::str("..")))
850 }
851 };
852
853 if entries.is_empty() && rest_info.is_none() {
854 return Document::str(name).append(" {}");
855 }
856
857 let (body, close_sep) = Self::join_pattern_entries(entries, rest_info, " ");
858
859 Document::str(name)
860 .append(" {")
861 .append(strict_break(" ", " "))
862 .append(body)
863 .nest(INDENT_WIDTH)
864 .append(close_sep)
865 .append("}")
866 .group()
867 }
868
869 pub(super) fn assignment(
870 &mut self,
871 target: &'a Expression,
872 value: &'a Expression,
873 compound_operator: Option<BinaryOperator>,
874 ) -> Document<'a> {
875 if let Some(op) = compound_operator
876 && let Some(op_str) = match op {
877 BinaryOperator::Addition => Some("+="),
878 BinaryOperator::Subtraction => Some("-="),
879 BinaryOperator::Multiplication => Some("*="),
880 BinaryOperator::Division => Some("/="),
881 BinaryOperator::Remainder => Some("%="),
882 _ => None,
883 }
884 && let Expression::Binary { right, .. } = value
885 {
886 return self
887 .expression(target)
888 .append(" ")
889 .append(op_str)
890 .append(" ")
891 .append(self.expression(right));
892 }
893
894 self.expression(target)
895 .append(" = ")
896 .append(self.expression(value))
897 }
898
899 pub(super) fn lambda(
900 &mut self,
901 params: &'a [Binding],
902 return_annotation: &'a Annotation,
903 body: &'a Expression,
904 _span: &'a Span,
905 ) -> Document<'a> {
906 let params_docs: Vec<_> = params.iter().map(|p| self.binding(p)).collect();
907
908 let params_doc = if params_docs.is_empty() {
909 Document::str("||")
910 } else {
911 Document::str("|")
912 .append(strict_break("", ""))
913 .append(join(params_docs, strict_break(",", ", ")))
914 .nest(INDENT_WIDTH)
915 .append(strict_break(",", ""))
916 .append("|")
917 .group()
918 };
919
920 let return_doc = if return_annotation.is_unknown() {
921 Document::Sequence(vec![])
922 } else {
923 Document::str(" -> ").append(Self::annotation(return_annotation))
924 };
925
926 let body_doc = self.expression(body);
927
928 params_doc.append(return_doc).append(" ").append(body_doc)
929 }
930
931 pub(super) fn task(&mut self, expression: &'a Expression) -> Document<'a> {
932 Document::str("task ").append(self.expression(expression))
933 }
934
935 pub(super) fn defer_(&mut self, expression: &'a Expression) -> Document<'a> {
936 Document::str("defer ").append(self.expression(expression))
937 }
938
939 pub(super) fn try_block(&mut self, items: &'a [Expression], span: &Span) -> Document<'a> {
940 Document::str("try ").append(self.block(items, span))
941 }
942
943 pub(super) fn recover_block(&mut self, items: &'a [Expression], span: &Span) -> Document<'a> {
944 Document::str("recover ").append(self.block(items, span))
945 }
946
947 pub(super) fn range(
948 &mut self,
949 start: &'a Option<Box<Expression>>,
950 end: &'a Option<Box<Expression>>,
951 inclusive: bool,
952 ) -> Document<'a> {
953 let start_doc = match start {
954 Some(e) => self.expression(e),
955 None => Document::Sequence(vec![]),
956 };
957 let end_doc = match end {
958 Some(e) => self.expression(e),
959 None => Document::Sequence(vec![]),
960 };
961 let op = if inclusive { "..=" } else { ".." };
962 start_doc.append(op).append(end_doc)
963 }
964
965 pub(super) fn cast(
966 &mut self,
967 expression: &'a Expression,
968 target_type: &'a Annotation,
969 ) -> Document<'a> {
970 self.expression(expression)
971 .append(" as ")
972 .append(Self::annotation(target_type))
973 }
974
975 pub(super) fn select(&mut self, arms: &'a [SelectArm], span: &Span) -> Document<'a> {
976 let mut entries: Vec<SiblingEntry<'a>> = Vec::with_capacity(arms.len());
977 for (i, arm) in arms.iter().enumerate() {
978 let start = Self::select_arm_start(arm);
979 let upper_bound = arms
980 .get(i + 1)
981 .map(Self::select_arm_start)
982 .unwrap_or_else(|| span.end());
983 self.push_sibling_entry(&mut entries, start, |s| s.select_arm_body(arm, upper_bound));
984 }
985 let body = self.join_sibling_body(entries, span.end());
986 Self::braced_body(Document::str("select"), body)
987 }
988
989 pub(super) fn select_arm_start(arm: &'a SelectArm) -> u32 {
990 match &arm.pattern {
991 SelectArmPattern::Receive { binding, .. } => binding.get_span().byte_offset,
992 SelectArmPattern::Send {
993 send_expression, ..
994 } => send_expression.get_span().byte_offset,
995 SelectArmPattern::MatchReceive {
996 receive_expression, ..
997 } => receive_expression.get_span().byte_offset,
998 SelectArmPattern::WildCard { body } => body.get_span().byte_offset,
999 }
1000 }
1001
1002 pub(super) fn select_arm_body(&mut self, arm: &'a SelectArm, upper_bound: u32) -> Document<'a> {
1003 match &arm.pattern {
1004 SelectArmPattern::Receive {
1005 binding,
1006 receive_expression,
1007 body,
1008 ..
1009 } => Document::str("let ")
1010 .append(self.pattern(binding))
1011 .append(" = ")
1012 .append(self.expression(receive_expression))
1013 .append(" => ")
1014 .append(self.expression(body))
1015 .append(","),
1016 SelectArmPattern::Send {
1017 send_expression,
1018 body,
1019 } => self
1020 .expression(send_expression)
1021 .append(" => ")
1022 .append(self.expression(body))
1023 .append(","),
1024 SelectArmPattern::MatchReceive {
1025 receive_expression,
1026 arms,
1027 } => {
1028 let header = Document::str("match ").append(self.expression(receive_expression));
1029 let last_arm_end = arms
1030 .last()
1031 .map(|a| a.expression.get_span().end())
1032 .unwrap_or(0);
1033 let body_end = self
1035 .comments
1036 .next_byte_at(b'}', last_arm_end, upper_bound)
1037 .unwrap_or(last_arm_end);
1038 let entries = self.match_arm_entries(arms);
1039 let body = self.join_sibling_body(entries, body_end);
1040 Self::braced_body(header, body).append(",")
1041 }
1042 SelectArmPattern::WildCard { body } => Document::str("_")
1043 .append(" => ")
1044 .append(self.expression(body))
1045 .append(","),
1046 }
1047 }
1048
1049 pub(super) fn propagate_(&mut self, expression: &'a Expression) -> Document<'a> {
1050 self.expression(expression).append("?")
1051 }
1052
1053 pub(super) fn ref_(&mut self, expression: &'a Expression) -> Document<'a> {
1054 Document::str("&").append(self.expression(expression))
1055 }
1056
1057 pub(super) fn raw_go(text: &'a str) -> Document<'a> {
1058 Document::str("@rawgo(\"")
1059 .append(Document::str(text))
1060 .append("\")")
1061 }
1062}
1063
1064struct MethodChainSegment<'a> {
1065 member: &'a str,
1066 member_start: u32,
1067 args: &'a [Expression],
1068 spread: &'a Option<Expression>,
1069 type_args: &'a [Annotation],
1070}
1071
1072fn collect_method_chain(expression: &Expression) -> (&Expression, Vec<MethodChainSegment<'_>>) {
1073 let mut segments = Vec::new();
1074 let mut current = expression;
1075
1076 while let Expression::Call {
1077 expression,
1078 args,
1079 spread,
1080 type_args,
1081 ..
1082 } = current
1083 {
1084 let Expression::DotAccess {
1085 expression: inner,
1086 member,
1087 span,
1088 ..
1089 } = expression.as_ref()
1090 else {
1091 break;
1092 };
1093 let member_start = span.byte_offset + span.byte_length - member.len() as u32;
1094 segments.push(MethodChainSegment {
1095 member,
1096 member_start,
1097 args,
1098 spread,
1099 type_args,
1100 });
1101 current = inner;
1102 }
1103
1104 segments.reverse();
1105 (current, segments)
1106}
1107
1108fn is_inlinable_arg(expression: &Expression, arity: usize) -> bool {
1109 matches!(
1110 expression,
1111 Expression::Lambda { .. }
1112 | Expression::Block { .. }
1113 | Expression::Match { .. }
1114 | Expression::Tuple { .. }
1115 | Expression::Literal {
1116 literal: Literal::Slice(_),
1117 ..
1118 }
1119 ) || matches!(expression, Expression::Call { .. } if arity == 1)
1120}