1
16
17
18
19 package build
20
21 import (
22 "bytes"
23 "fmt"
24 "strings"
25
26 "github.com/bazelbuild/buildtools/tables"
27 )
28
29 const (
30 nestedIndentation = 4
31 listIndentation = 4
32 defIndentation = 8
33 )
34
35
36
37 func FormatWithoutRewriting(f *File) []byte {
38 pr := &printer{fileType: f.Type}
39 pr.file(f)
40 return pr.Bytes()
41 }
42
43
44 func Format(f *File) []byte {
45 Rewrite(f)
46 return FormatWithoutRewriting(f)
47 }
48
49
50 func FormatWithRewriter(w *Rewriter, f *File) []byte {
51 w.Rewrite(f)
52 return FormatWithoutRewriting(f)
53 }
54
55
56 func FormatString(x Expr) string {
57
58 if x == nil {
59 return ""
60 }
61
62 fileType := TypeBuild
63 if file, ok := x.(*File); ok {
64 fileType = file.Type
65 }
66
67 pr := &printer{fileType: fileType}
68 switch x := x.(type) {
69 case *File:
70 pr.file(x)
71 default:
72 pr.expr(x, precLow)
73 }
74 return pr.String()
75 }
76
77
78 type printer struct {
79 fileType FileType
80 bytes.Buffer
81 comment []Comment
82 margin int
83 depth int
84 level int
85 needsNewLine bool
86 }
87
88
89
90 func (p *printer) formattingMode() FileType {
91 switch p.fileType {
92 case TypeBuild, TypeWorkspace, TypeModule:
93 return TypeBuild
94 default:
95 return TypeDefault
96 }
97 }
98
99
100 func (p *printer) printf(format string, args ...interface{}) {
101 fmt.Fprintf(p, format, args...)
102 }
103
104
105 func (p *printer) indent() int {
106 b := p.Bytes()
107 n := 0
108 for n < len(b) && b[len(b)-1-n] != '\n' {
109 n++
110 }
111 return n
112 }
113
114
115
116
117
118
119 func (p *printer) newline() {
120 p.needsNewLine = false
121 if len(p.comment) > 0 {
122 p.printf(" ")
123 for i, com := range p.comment {
124 if i > 0 {
125 p.trim()
126 p.printf("\n%*s", p.margin, "")
127 }
128 p.printf("%s", strings.TrimSpace(com.Token))
129 }
130 p.comment = p.comment[:0]
131 }
132
133 p.trim()
134 p.printf("\n%*s", p.margin, "")
135 }
136
137
138
139
140
141
142
143
144
145
146
147
148 func (p *printer) softNewline() {
149 p.needsNewLine = true
150 }
151
152
153 func (p *printer) newlineIfNeeded() {
154 if p.needsNewLine == true {
155 p.newline()
156 }
157 }
158
159
160
161 func (p *printer) breakline() {
162 if p.depth == 0 {
163
164 p.printf(" \\\n%*s", p.margin, "")
165 return
166 }
167
168
169 p.newline()
170 }
171
172
173 func (p *printer) trim() {
174
175 b := p.Bytes()
176 n := len(b)
177 for n > 0 && b[n-1] == ' ' {
178 n--
179 }
180 p.Truncate(n)
181 }
182
183
184 func (p *printer) file(f *File) {
185 for _, com := range f.Before {
186 p.printf("%s", strings.TrimSpace(com.Token))
187 p.newline()
188 }
189
190 p.statements(f.Stmt)
191
192 for _, com := range f.After {
193 p.printf("%s", strings.TrimSpace(com.Token))
194 p.newline()
195 }
196
197 p.newlineIfNeeded()
198 }
199
200 func (p *printer) nestedStatements(stmts []Expr) {
201 p.margin += nestedIndentation
202 p.level++
203 p.newline()
204
205 p.statements(stmts)
206
207 p.margin -= nestedIndentation
208 p.level--
209 }
210
211 func (p *printer) statements(rawStmts []Expr) {
212
213
214
215 stmts := []Expr{}
216 for _, stmt := range rawStmts {
217 if stmt != nil {
218 stmts = append(stmts, stmt)
219 }
220 }
221
222 for i, stmt := range stmts {
223 p.expr(stmt, precLow)
224
225
226
227 if _, ok := stmt.(*CommentBlock); !ok {
228 p.softNewline()
229 }
230
231 for _, com := range stmt.Comment().After {
232 p.newlineIfNeeded()
233 p.printf("%s", strings.TrimSpace(com.Token))
234 p.softNewline()
235 }
236
237
238
239 if i < len(stmts)-1 {
240 p.newline()
241 }
242
243 if i+1 < len(stmts) && !p.compactStmt(stmt, stmts[i+1]) {
244 p.newline()
245 }
246 }
247 }
248
249
250
251
252
253 func (p *printer) compactStmt(s1, s2 Expr) bool {
254 if len(s2.Comment().Before) > 0 || len(s1.Comment().After) > 0 {
255 return false
256 } else if isLoad(s1) && isLoad(s2) {
257
258 return true
259 } else if isLoad(s1) || isLoad(s2) {
260
261 return false
262 } else if p.fileType == TypeModule && areBazelDepsOfSameType(s1, s2) {
263
264
265 return true
266 } else if p.fileType == TypeModule && isBazelDepWithOverride(s1, s2) {
267
268 return true
269 } else if p.fileType == TypeModule && useSameModuleExtensionProxy(s1, s2) {
270
271
272
273
274
275 return true
276 } else if isCommentBlock(s1) || isCommentBlock(s2) {
277
278 return false
279 } else if (p.formattingMode() == TypeBuild) && p.level == 0 {
280
281 return false
282 } else if isFunctionDefinition(s1) || isFunctionDefinition(s2) {
283
284 return false
285 } else {
286
287 _, end := s1.Span()
288 start, _ := s2.Span()
289 return start.Line-end.Line <= 1
290 }
291 }
292
293
294 func isLoad(x Expr) bool {
295 _, ok := x.(*LoadStmt)
296 return ok
297 }
298
299
300
301 func areBazelDepsOfSameType(x, y Expr) bool {
302 if !isBazelDep(x) || !isBazelDep(y) {
303 return false
304 }
305 isXDevDep := getKeywordBoolArgument(x.(*CallExpr), "dev_dependency", false)
306 isYDevDep := getKeywordBoolArgument(y.(*CallExpr), "dev_dependency", false)
307 return isXDevDep == isYDevDep
308 }
309
310 func isBazelDep(x Expr) bool {
311 call, ok := x.(*CallExpr)
312 if !ok {
313 return false
314 }
315 if ident, ok := call.X.(*Ident); ok && ident.Name == "bazel_dep" {
316 return true
317 }
318 return false
319 }
320
321 func isUseRepoOrUseExtension(x Expr) bool {
322 call, ok := x.(*CallExpr)
323 if !ok {
324 return false
325 }
326 if ident, ok := call.X.(*Ident); ok && (ident.Name == "use_repo" || ident.Name == "use_extension") {
327 return true
328 }
329 return false
330 }
331
332 func isModuleOverride(x Expr) bool {
333 call, ok := x.(*CallExpr)
334 if !ok {
335 return false
336 }
337 ident, ok := call.X.(*Ident)
338 if !ok {
339 return false
340 }
341 return tables.IsModuleOverride[ident.Name]
342 }
343
344 func getKeywordBoolArgument(call *CallExpr, keyword string, defaultValue bool) bool {
345 arg := getKeywordArgument(call, keyword)
346 if arg == nil {
347 return defaultValue
348 }
349 ident, ok := arg.(*Ident)
350 if !ok {
351
352 return !defaultValue
353 }
354 return ident.Name == "True"
355 }
356
357 func getKeywordArgument(call *CallExpr, param string) Expr {
358 for _, arg := range call.List {
359 kwarg, ok := arg.(*AssignExpr)
360 if !ok {
361 continue
362 }
363 ident, ok := kwarg.LHS.(*Ident)
364 if !ok {
365 continue
366 }
367 if ident.Name == param {
368 return kwarg.RHS
369 }
370 }
371 return nil
372 }
373
374 func isBazelDepWithOverride(x, y Expr) bool {
375 if !isBazelDep(x) || !isModuleOverride(y) {
376 return false
377 }
378 bazelDepName, ok := getKeywordArgument(x.(*CallExpr), "name").(*StringExpr)
379 if !ok {
380 return false
381 }
382 overrideModuleName, ok := getKeywordArgument(y.(*CallExpr), "module_name").(*StringExpr)
383 if !ok {
384 return false
385 }
386 return bazelDepName.Value == overrideModuleName.Value
387 }
388
389 func useSameModuleExtensionProxy(x, y Expr) bool {
390 extX := usedModuleExtensionProxy(x)
391 if extX == "" {
392 return false
393 }
394 extY := usedModuleExtensionProxy(y)
395 return extX == extY
396 }
397
398 func usedModuleExtensionProxy(x Expr) string {
399 if call, ok := x.(*CallExpr); ok {
400 if callee, isIdent := call.X.(*Ident); isIdent && callee.Name == "use_repo" {
401
402
403 if len(call.List) < 1 {
404 return ""
405 }
406 proxy, isIdent := call.List[0].(*Ident)
407 if !isIdent {
408 return ""
409 }
410 return proxy.Name
411 } else if dot, isDot := call.X.(*DotExpr); isDot {
412
413
414 extension, isIdent := dot.X.(*Ident)
415 if !isIdent {
416 return ""
417 }
418 return extension.Name
419 } else {
420 return ""
421 }
422 } else if assign, ok := x.(*AssignExpr); ok {
423
424
425 assignee, isIdent := assign.LHS.(*Ident)
426 if !isIdent {
427 return ""
428 }
429 call, isCall := assign.RHS.(*CallExpr)
430 if !isCall {
431 return ""
432 }
433 callee, isIdent := call.X.(*Ident)
434 if !isIdent || callee.Name != "use_extension" {
435 return ""
436 }
437 return assignee.Name
438 } else {
439 return ""
440 }
441 }
442
443
444 func isCommentBlock(x Expr) bool {
445 _, ok := x.(*CommentBlock)
446 return ok
447 }
448
449
450 func isFunctionDefinition(x Expr) bool {
451 _, ok := x.(*DefStmt)
452 return ok
453 }
454
455
456
457
458 func isDifferentLines(p1, p2 *Position) bool {
459 if p1.Line == 0 || p2.Line == 0 {
460 return false
461 }
462 return p1.Line != p2.Line
463 }
464
465
466
467
468
469
470
471
472
473
474
475
476
477
478
479
480
481
482
483
484
485
486
487
488
489
490 const (
491 precLow = iota
492 precAssign
493 precColon
494 precIfElse
495 precOr
496 precAnd
497 precCmp
498 precBitwiseOr
499 precBitwiseXor
500 precBitwiseAnd
501 precBitwiseShift
502 precAdd
503 precMultiply
504 precUnary
505 precSuffix
506 )
507
508
509 var opPrec = map[string]int{
510 "or": precOr,
511 "and": precAnd,
512 "in": precCmp,
513 "not in": precCmp,
514 "<": precCmp,
515 ">": precCmp,
516 "==": precCmp,
517 "!=": precCmp,
518 "<=": precCmp,
519 ">=": precCmp,
520 "+": precAdd,
521 "-": precAdd,
522 "*": precMultiply,
523 "/": precMultiply,
524 "//": precMultiply,
525 "%": precMultiply,
526 "|": precBitwiseOr,
527 "&": precBitwiseAnd,
528 "^": precBitwiseXor,
529 "<<": precBitwiseShift,
530 ">>": precBitwiseShift,
531 }
532
533
534
535
536
537
538 func (p *printer) expr(v Expr, outerPrec int) {
539
540
541
542
543
544
545
546
547
548
549
550 p.newlineIfNeeded()
551
552 if before := v.Comment().Before; len(before) > 0 {
553
554
555 p.trim()
556 if p.indent() > 0 {
557
558 p.printf("\n")
559 }
560
561 p.printf("%*s", p.margin, "")
562 for _, com := range before {
563 p.printf("%s", strings.TrimSpace(com.Token))
564 p.newline()
565 }
566 }
567
568
569
570
571
572
573
574
575 parenthesized := false
576 addParen := func(prec int) {
577 if prec < outerPrec {
578 p.printf("(")
579 p.depth++
580 parenthesized = true
581 }
582 }
583
584 switch v := v.(type) {
585 default:
586 panic(fmt.Errorf("printer: unexpected type %T", v))
587
588 case *CommentBlock:
589
590
591 case *LiteralExpr:
592 p.printf("%s", v.Token)
593
594 case *Ident:
595 p.printf("%s", v.Name)
596
597 case *TypedIdent:
598 p.expr(v.Ident, precLow)
599 p.printf(": ")
600 p.expr(v.Type, precLow)
601
602 case *BranchStmt:
603 p.printf("%s", v.Token)
604
605 case *StringExpr:
606
607
608
609
610 s, triple, err := Unquote(v.Token)
611 if err == nil && s == v.Value && triple == v.TripleQuote {
612 if strings.HasPrefix(v.Token, `r`) {
613
614 token := v.Token
615 if strings.HasSuffix(v.Token, `'`) && !strings.ContainsRune(v.Value, '"') {
616
617 if strings.HasSuffix(token, `'''`) {
618 token = `r"""` + token[4:len(token)-3] + `"""`
619 } else if strings.HasSuffix(token, `'`) {
620 token = `r"` + token[2:len(token)-1] + `"`
621 }
622 }
623 p.printf("%s", token)
624 break
625 }
626
627
628 if strings.HasPrefix(v.Token, `"`) || strings.ContainsRune(v.Value, '"') {
629
630 if IsCorrectEscaping(v.Token) {
631 p.printf("%s", v.Token)
632 break
633 }
634 }
635 }
636
637 p.printf("%s", quote(v.Value, v.TripleQuote))
638
639 case *DotExpr:
640 addParen(precSuffix)
641 p.expr(v.X, precSuffix)
642 _, xEnd := v.X.Span()
643 isMultiline := isDifferentLines(&v.NamePos, &xEnd)
644 if isMultiline {
645 p.margin += listIndentation
646 p.breakline()
647 }
648 p.printf(".%s", v.Name)
649 if isMultiline {
650 p.margin -= listIndentation
651 }
652
653 case *IndexExpr:
654 addParen(precSuffix)
655 p.expr(v.X, precSuffix)
656 p.printf("[")
657 p.expr(v.Y, precLow)
658 p.printf("]")
659
660 case *KeyValueExpr:
661 p.expr(v.Key, precLow)
662 p.printf(": ")
663 p.expr(v.Value, precLow)
664
665 case *SliceExpr:
666 addParen(precSuffix)
667 p.expr(v.X, precSuffix)
668 p.printf("[")
669 if v.From != nil {
670 p.expr(v.From, precLow)
671 }
672 p.printf(":")
673 if v.To != nil {
674 p.expr(v.To, precLow)
675 }
676 if v.SecondColon.Byte != 0 {
677 p.printf(":")
678 if v.Step != nil {
679 p.expr(v.Step, precLow)
680 }
681 }
682 p.printf("]")
683
684 case *UnaryExpr:
685 addParen(precUnary)
686 if v.Op == "not" {
687 p.printf("not ")
688 } else {
689 p.printf("%s", v.Op)
690 }
691
692
693 if v.X != nil {
694 p.expr(v.X, precSuffix)
695 }
696
697 case *LambdaExpr:
698 addParen(precColon)
699 p.printf("lambda")
700 for i, param := range v.Params {
701 if i > 0 {
702 p.printf(",")
703 }
704 p.printf(" ")
705 p.expr(param, precLow)
706 }
707 p.printf(": ")
708 p.expr(v.Body[0], precLow)
709
710 case *BinaryExpr:
711
712
713
714
715
716
717
718
719
720
721
722
723
724
725
726 prec := opPrec[v.Op]
727 addParen(prec)
728 m := p.margin
729 if v.LineBreak {
730 p.margin = p.indent()
731 }
732
733 p.expr(v.X, prec)
734 p.printf(" %s", v.Op)
735 if v.LineBreak {
736 p.breakline()
737 } else {
738 p.printf(" ")
739 }
740 p.expr(v.Y, prec+1)
741 p.margin = m
742
743 case *AssignExpr:
744 addParen(precAssign)
745 m := p.margin
746 if v.LineBreak {
747 p.margin = p.indent() + listIndentation
748 }
749
750 p.expr(v.LHS, precAssign)
751 p.printf(" %s", v.Op)
752 if v.LineBreak {
753 p.breakline()
754 } else {
755 p.printf(" ")
756 }
757 p.expr(v.RHS, precAssign+1)
758 p.margin = m
759
760 case *ParenExpr:
761 p.seq("()", &v.Start, &[]Expr{v.X}, &v.End, modeParen, false, v.ForceMultiLine)
762
763 case *CallExpr:
764 forceCompact := v.ForceCompact
765 if p.fileType == TypeModule && (isBazelDep(v) || isUseRepoOrUseExtension(v)) {
766 start, end := v.Span()
767 forceCompact = start.Line == end.Line
768 }
769 addParen(precSuffix)
770 p.expr(v.X, precSuffix)
771 p.seq("()", &v.ListStart, &v.List, &v.End, modeCall, forceCompact, v.ForceMultiLine)
772
773 case *LoadStmt:
774 addParen(precSuffix)
775 p.printf("load")
776 args := []Expr{v.Module}
777 for i := range v.From {
778 from := v.From[i]
779 to := v.To[i]
780 var arg Expr
781 if from.Name == to.Name {
782
783
784
785 arg = from.asString()
786 arg.Comment().Before = to.Comment().Before
787 } else {
788 arg = &AssignExpr{
789 LHS: to,
790 Op: "=",
791 RHS: from.asString(),
792 }
793 }
794 args = append(args, arg)
795 }
796 p.seq("()", &v.Load, &args, &v.Rparen, modeLoad, v.ForceCompact, false)
797
798 case *ListExpr:
799 p.seq("[]", &v.Start, &v.List, &v.End, modeList, false, v.ForceMultiLine)
800
801 case *SetExpr:
802 p.seq("{}", &v.Start, &v.List, &v.End, modeList, false, v.ForceMultiLine)
803
804 case *TupleExpr:
805 mode := modeTuple
806 if v.NoBrackets {
807 mode = modeSeq
808 }
809 p.seq("()", &v.Start, &v.List, &v.End, mode, v.ForceCompact, v.ForceMultiLine)
810
811 case *DictExpr:
812 var list []Expr
813 for _, x := range v.List {
814 list = append(list, x)
815 }
816 p.seq("{}", &v.Start, &list, &v.End, modeDict, false, v.ForceMultiLine)
817
818 case *Comprehension:
819 p.listFor(v)
820
821 case *ConditionalExpr:
822 addParen(precSuffix)
823 p.expr(v.Then, precIfElse)
824 p.printf(" if ")
825 p.expr(v.Test, precIfElse)
826 p.printf(" else ")
827 p.expr(v.Else, precIfElse)
828
829 case *ReturnStmt:
830 p.printf("return")
831 if v.Result != nil {
832 p.printf(" ")
833 p.expr(v.Result, precLow)
834 }
835
836 case *DefStmt:
837 p.printf("def ")
838 p.printf(v.Name)
839 p.seq("()", &v.StartPos, &v.Params, nil, modeDef, v.ForceCompact, v.ForceMultiLine)
840 if v.Type != nil {
841 p.printf(" -> ")
842 p.expr(v.Type, precLow)
843 }
844 p.printf(":")
845 p.nestedStatements(v.Body)
846
847 case *ForStmt:
848 p.printf("for ")
849 p.expr(v.Vars, precLow)
850 p.printf(" in ")
851 p.expr(v.X, precLow)
852 p.printf(":")
853 p.nestedStatements(v.Body)
854
855 case *IfStmt:
856 block := v
857 isFirst := true
858 needsEmptyLine := false
859 for {
860 p.newlineIfNeeded()
861 if !isFirst {
862 if needsEmptyLine {
863 p.newline()
864 }
865 p.printf("el")
866 }
867 p.printf("if ")
868 p.expr(block.Cond, precLow)
869 p.printf(":")
870 p.nestedStatements(block.True)
871
872 isFirst = false
873 _, end := block.True[len(block.True)-1].Span()
874 needsEmptyLine = block.ElsePos.Pos.Line-end.Line > 1
875
876
877
878
879
880 if len(block.False) != 1 {
881 break
882 }
883 next, ok := block.False[0].(*IfStmt)
884 if !ok {
885 break
886 }
887 if len(block.ElsePos.Comment().Suffix) == 0 && len(next.Comment().Before) == 0 {
888 block = next
889 continue
890 }
891 break
892 }
893
894 if len(block.False) > 0 {
895 p.newlineIfNeeded()
896 if needsEmptyLine {
897 p.newline()
898 }
899 p.printf("else:")
900 p.comment = append(p.comment, block.ElsePos.Comment().Suffix...)
901 p.nestedStatements(block.False)
902 }
903 case *ForClause:
904 p.printf("for ")
905 p.expr(v.Vars, precLow)
906 p.printf(" in ")
907 p.expr(v.X, precLow)
908 case *IfClause:
909 p.printf("if ")
910 p.expr(v.Cond, precLow)
911 }
912
913
914 if parenthesized {
915 p.depth--
916 p.printf(")")
917 }
918
919
920
921 p.comment = append(p.comment, v.Comment().Suffix...)
922 }
923
924
925
926 type seqMode int
927
928 const (
929 _ seqMode = iota
930
931 modeCall
932 modeList
933 modeTuple
934 modeParen
935 modeDict
936 modeSeq
937 modeDef
938 modeLoad
939 )
940
941
942 func (p *printer) useCompactMode(start *Position, list *[]Expr, end *End, mode seqMode, forceCompact, forceMultiLine bool) bool {
943
944
945 for _, x := range *list {
946 if len(x.Comment().Before) > 0 || (len(x.Comment().Suffix) > 0 && mode != modeDef) {
947 return false
948 }
949 }
950 if end != nil && len(end.Before) > 0 {
951 return false
952 }
953
954
955 if mode == modeSeq {
956 return true
957 }
958
959
960
961
962 if (p.level != 0 || p.formattingMode() == TypeDefault || mode == modeDef) && mode != modeLoad {
963
964
965
966
967
968 previousEnd := start
969 isNewSeq := start.Line == 0
970 for _, x := range *list {
971 start, end := x.Span()
972 isNewSeq = isNewSeq && start.Line == 0
973 if isDifferentLines(&start, previousEnd) {
974 return false
975 }
976 if end.Line != 0 {
977 previousEnd = &end
978 }
979 }
980 if end != nil {
981 isNewSeq = isNewSeq && end.Pos.Line == 0
982 if isDifferentLines(previousEnd, &end.Pos) {
983 return false
984 }
985 }
986 if !isNewSeq {
987 return true
988 }
989
990 return !forceMultiLine
991 }
992
993 if forceMultiLine {
994 return false
995 }
996 if forceCompact {
997 return true
998 }
999
1000 return len(*list) <= 1
1001 }
1002
1003
1004
1005
1006
1007
1008
1009 func (p *printer) seq(brack string, start *Position, list *[]Expr, end *End, mode seqMode, forceCompact, forceMultiLine bool) {
1010 args := &[]Expr{}
1011 for _, x := range *list {
1012
1013
1014 if x != nil {
1015 *args = append(*args, x)
1016 }
1017 }
1018
1019 if mode != modeSeq {
1020 p.printf("%s", brack[:1])
1021 }
1022 p.depth++
1023 defer func() {
1024 p.depth--
1025 if mode != modeSeq {
1026 p.printf("%s", brack[1:])
1027 }
1028 }()
1029
1030 if p.useCompactMode(start, args, end, mode, forceCompact, forceMultiLine) {
1031 for i, x := range *args {
1032 if i > 0 {
1033 p.printf(", ")
1034 }
1035 p.expr(x, precLow)
1036 }
1037
1038 if len(*args) == 1 && mode == modeTuple {
1039 p.printf(",")
1040 }
1041 return
1042 }
1043
1044 indentation := listIndentation
1045 if mode == modeDef {
1046 indentation = defIndentation
1047 }
1048 p.margin += indentation
1049
1050 for i, x := range *args {
1051
1052
1053
1054
1055
1056
1057
1058 if i == 0 && len(p.comment) > 0 {
1059 p.printf("\n%*s", p.margin-2, "")
1060 }
1061
1062 p.newline()
1063 p.expr(x, precLow)
1064
1065 if i+1 < len(*args) || needsTrailingComma(mode, x) {
1066 p.printf(",")
1067 }
1068 }
1069
1070 if end != nil {
1071 for _, com := range end.Before {
1072 p.newline()
1073 p.printf("%s", strings.TrimSpace(com.Token))
1074 }
1075 }
1076 p.margin -= indentation
1077
1078 if mode != modeDef {
1079 p.newline()
1080 }
1081 }
1082
1083 func needsTrailingComma(mode seqMode, v Expr) bool {
1084 switch mode {
1085 case modeDef:
1086 return false
1087 case modeParen:
1088 return false
1089 case modeCall:
1090
1091 switch v := v.(type) {
1092 case *UnaryExpr:
1093 if v.Op == "*" || v.Op == "**" {
1094 return false
1095 }
1096 }
1097 }
1098 return true
1099 }
1100
1101
1102
1103
1104
1105
1106
1107
1108
1109
1110
1111
1112
1113 func (p *printer) listFor(v *Comprehension) {
1114 multiLine := v.ForceMultiLine || len(v.End.Before) > 0
1115
1116
1117
1118 space := func() {
1119 if multiLine {
1120 p.breakline()
1121 } else {
1122 p.printf(" ")
1123 }
1124 }
1125
1126 open, close := "[", "]"
1127 if v.Curly {
1128 open, close = "{", "}"
1129 }
1130 p.depth++
1131 p.printf("%s", open)
1132
1133 if multiLine {
1134 p.margin += listIndentation
1135 p.newline()
1136 }
1137
1138 p.expr(v.Body, precLow)
1139
1140 for _, c := range v.Clauses {
1141 space()
1142 p.expr(c, precLow)
1143 }
1144
1145 if multiLine {
1146 for _, com := range v.End.Before {
1147 p.newline()
1148 p.printf("%s", strings.TrimSpace(com.Token))
1149 }
1150 p.margin -= listIndentation
1151 p.newline()
1152 }
1153
1154 p.printf("%s", close)
1155 p.depth--
1156 }
1157
1158 func (p *printer) isTopLevel() bool {
1159 return p.margin == 0
1160 }
1161
View as plain text