OLD | NEW |
1 // Copyright 2009 The Go Authors. All rights reserved. | 1 // Copyright 2009 The Go Authors. All rights reserved. |
2 // Use of this source code is governed by a BSD-style | 2 // Use of this source code is governed by a BSD-style |
3 // license that can be found in the LICENSE file. | 3 // license that can be found in the LICENSE file. |
4 | 4 |
5 // This file implements printing of AST nodes; specifically | 5 // This file implements printing of AST nodes; specifically |
6 // expressions, statements, declarations, and files. It uses | 6 // expressions, statements, declarations, and files. It uses |
7 // the print functionality implemented in printer.go. | 7 // the print functionality implemented in printer.go. |
8 | 8 |
9 package printer | 9 package printer |
10 | 10 |
11 import ( | 11 import ( |
12 "bytes" | 12 "bytes" |
13 "go/ast" | 13 "go/ast" |
14 "go/token" | 14 "go/token" |
15 ) | 15 ) |
16 | 16 |
17 | |
18 // Other formatting issues: | 17 // Other formatting issues: |
19 // - better comment formatting for /*-style comments at the end of a line (e.g.
a declaration) | 18 // - better comment formatting for /*-style comments at the end of a line (e.g.
a declaration) |
20 // when the comment spans multiple lines; if such a comment is just two lines,
formatting is | 19 // when the comment spans multiple lines; if such a comment is just two lines,
formatting is |
21 // not idempotent | 20 // not idempotent |
22 // - formatting of expression lists | 21 // - formatting of expression lists |
23 // - should use blank instead of tab to separate one-line function bodies from | 22 // - should use blank instead of tab to separate one-line function bodies from |
24 // the function header unless there is a group of consecutive one-liners | 23 // the function header unless there is a group of consecutive one-liners |
25 | 24 |
26 | |
27 // ---------------------------------------------------------------------------- | 25 // ---------------------------------------------------------------------------- |
28 // Common AST nodes. | 26 // Common AST nodes. |
29 | 27 |
30 // Print as many newlines as necessary (but at least min newlines) to get to | 28 // Print as many newlines as necessary (but at least min newlines) to get to |
31 // the current line. ws is printed before the first line break. If newSection | 29 // the current line. ws is printed before the first line break. If newSection |
32 // is set, the first line break is printed as formfeed. Returns true if any | 30 // is set, the first line break is printed as formfeed. Returns true if any |
33 // line break was printed; returns false otherwise. | 31 // line break was printed; returns false otherwise. |
34 // | 32 // |
35 // TODO(gri): linebreak may add too many lines if the next statement at "line" | 33 // TODO(gri): linebreak may add too many lines if the next statement at "line" |
36 // is preceded by comments because the computation of n assumes | 34 // is preceded by comments because the computation of n assumes |
(...skipping 12 matching lines...) Expand all Loading... |
49 n-- | 47 n-- |
50 } | 48 } |
51 for ; n > 0; n-- { | 49 for ; n > 0; n-- { |
52 p.print(newline) | 50 p.print(newline) |
53 } | 51 } |
54 printedBreak = true | 52 printedBreak = true |
55 } | 53 } |
56 return | 54 return |
57 } | 55 } |
58 | 56 |
59 | |
60 // setComment sets g as the next comment if g != nil and if node comments | 57 // setComment sets g as the next comment if g != nil and if node comments |
61 // are enabled - this mode is used when printing source code fragments such | 58 // are enabled - this mode is used when printing source code fragments such |
62 // as exports only. It assumes that there are no other pending comments to | 59 // as exports only. It assumes that there are no other pending comments to |
63 // intersperse. | 60 // intersperse. |
64 func (p *printer) setComment(g *ast.CommentGroup) { | 61 func (p *printer) setComment(g *ast.CommentGroup) { |
65 if g == nil || !p.useNodeComments { | 62 if g == nil || !p.useNodeComments { |
66 return | 63 return |
67 } | 64 } |
68 if p.comments == nil { | 65 if p.comments == nil { |
69 // initialize p.comments lazily | 66 // initialize p.comments lazily |
70 p.comments = make([]*ast.CommentGroup, 1) | 67 p.comments = make([]*ast.CommentGroup, 1) |
71 } else if p.cindex < len(p.comments) { | 68 } else if p.cindex < len(p.comments) { |
72 // for some reason there are pending comments; this | 69 // for some reason there are pending comments; this |
73 // should never happen - handle gracefully and flush | 70 // should never happen - handle gracefully and flush |
74 // all comments up to g, ignore anything after that | 71 // all comments up to g, ignore anything after that |
75 p.flush(p.fset.Position(g.List[0].Pos()), token.ILLEGAL) | 72 p.flush(p.fset.Position(g.List[0].Pos()), token.ILLEGAL) |
76 } | 73 } |
77 p.comments[0] = g | 74 p.comments[0] = g |
78 p.cindex = 0 | 75 p.cindex = 0 |
79 } | 76 } |
80 | 77 |
81 | |
82 type exprListMode uint | 78 type exprListMode uint |
83 | 79 |
84 const ( | 80 const ( |
85 blankStart exprListMode = 1 << iota // print a blank before a non-empty
list | 81 blankStart exprListMode = 1 << iota // print a blank before a non-empty
list |
86 blankEnd // print a blank after a non-empty l
ist | 82 blankEnd // print a blank after a non-empty l
ist |
87 commaSep // elements are separated by commas | 83 commaSep // elements are separated by commas |
88 commaTerm // list is optionally terminated by
a comma | 84 commaTerm // list is optionally terminated by
a comma |
89 noIndent // no extra indentation in multi-lin
e lists | 85 noIndent // no extra indentation in multi-lin
e lists |
90 periodSep // elements are separated by periods | 86 periodSep // elements are separated by periods |
91 ) | 87 ) |
92 | 88 |
93 | |
94 // Sets multiLine to true if the identifier list spans multiple lines. | 89 // Sets multiLine to true if the identifier list spans multiple lines. |
95 // If indent is set, a multi-line identifier list is indented after the | 90 // If indent is set, a multi-line identifier list is indented after the |
96 // first linebreak encountered. | 91 // first linebreak encountered. |
97 func (p *printer) identList(list []*ast.Ident, indent bool, multiLine *bool) { | 92 func (p *printer) identList(list []*ast.Ident, indent bool, multiLine *bool) { |
98 // convert into an expression list so we can re-use exprList formatting | 93 // convert into an expression list so we can re-use exprList formatting |
99 xlist := make([]ast.Expr, len(list)) | 94 xlist := make([]ast.Expr, len(list)) |
100 for i, x := range list { | 95 for i, x := range list { |
101 xlist[i] = x | 96 xlist[i] = x |
102 } | 97 } |
103 mode := commaSep | 98 mode := commaSep |
104 if !indent { | 99 if !indent { |
105 mode |= noIndent | 100 mode |= noIndent |
106 } | 101 } |
107 p.exprList(token.NoPos, xlist, 1, mode, multiLine, token.NoPos) | 102 p.exprList(token.NoPos, xlist, 1, mode, multiLine, token.NoPos) |
108 } | 103 } |
109 | 104 |
110 | |
111 // Print a list of expressions. If the list spans multiple | 105 // Print a list of expressions. If the list spans multiple |
112 // source lines, the original line breaks are respected between | 106 // source lines, the original line breaks are respected between |
113 // expressions. Sets multiLine to true if the list spans multiple | 107 // expressions. Sets multiLine to true if the list spans multiple |
114 // lines. | 108 // lines. |
115 // | 109 // |
116 // TODO(gri) Consider rewriting this to be independent of []ast.Expr | 110 // TODO(gri) Consider rewriting this to be independent of []ast.Expr |
117 // so that we can use the algorithm for any kind of list | 111 // so that we can use the algorithm for any kind of list |
118 // (e.g., pass list via a channel over which to range). | 112 // (e.g., pass list via a channel over which to range). |
119 func (p *printer) exprList(prev0 token.Pos, list []ast.Expr, depth int, mode exp
rListMode, multiLine *bool, next0 token.Pos) { | 113 func (p *printer) exprList(prev0 token.Pos, list []ast.Expr, depth int, mode exp
rListMode, multiLine *bool, next0 token.Pos) { |
120 if len(list) == 0 { | 114 if len(list) == 0 { |
(...skipping 143 matching lines...) Expand 10 before | Expand all | Expand 10 after Loading... |
264 if mode&blankEnd != 0 { | 258 if mode&blankEnd != 0 { |
265 p.print(blank) | 259 p.print(blank) |
266 } | 260 } |
267 | 261 |
268 if ws == ignore && mode&noIndent == 0 { | 262 if ws == ignore && mode&noIndent == 0 { |
269 // unindent if we indented | 263 // unindent if we indented |
270 p.print(unindent) | 264 p.print(unindent) |
271 } | 265 } |
272 } | 266 } |
273 | 267 |
274 | |
275 // Sets multiLine to true if the the parameter list spans multiple lines. | 268 // Sets multiLine to true if the the parameter list spans multiple lines. |
276 func (p *printer) parameters(fields *ast.FieldList, multiLine *bool) { | 269 func (p *printer) parameters(fields *ast.FieldList, multiLine *bool) { |
277 p.print(fields.Opening, token.LPAREN) | 270 p.print(fields.Opening, token.LPAREN) |
278 if len(fields.List) > 0 { | 271 if len(fields.List) > 0 { |
279 var prevLine, line int | 272 var prevLine, line int |
280 for i, par := range fields.List { | 273 for i, par := range fields.List { |
281 if i > 0 { | 274 if i > 0 { |
282 p.print(token.COMMA) | 275 p.print(token.COMMA) |
283 if len(par.Names) > 0 { | 276 if len(par.Names) > 0 { |
284 line = p.fset.Position(par.Names[0].Pos(
)).Line | 277 line = p.fset.Position(par.Names[0].Pos(
)).Line |
(...skipping 10 matching lines...) Expand all Loading... |
295 p.identList(par.Names, false, multiLine) | 288 p.identList(par.Names, false, multiLine) |
296 p.print(blank) | 289 p.print(blank) |
297 } | 290 } |
298 p.expr(par.Type, multiLine) | 291 p.expr(par.Type, multiLine) |
299 prevLine = p.fset.Position(par.Type.Pos()).Line | 292 prevLine = p.fset.Position(par.Type.Pos()).Line |
300 } | 293 } |
301 } | 294 } |
302 p.print(fields.Closing, token.RPAREN) | 295 p.print(fields.Closing, token.RPAREN) |
303 } | 296 } |
304 | 297 |
305 | |
306 // Sets multiLine to true if the signature spans multiple lines. | 298 // Sets multiLine to true if the signature spans multiple lines. |
307 func (p *printer) signature(params, result *ast.FieldList, multiLine *bool) { | 299 func (p *printer) signature(params, result *ast.FieldList, multiLine *bool) { |
308 p.parameters(params, multiLine) | 300 p.parameters(params, multiLine) |
309 n := result.NumFields() | 301 n := result.NumFields() |
310 if n > 0 { | 302 if n > 0 { |
311 p.print(blank) | 303 p.print(blank) |
312 if n == 1 && result.List[0].Names == nil { | 304 if n == 1 && result.List[0].Names == nil { |
313 // single anonymous result; no ()'s | 305 // single anonymous result; no ()'s |
314 p.expr(result.List[0].Type, multiLine) | 306 p.expr(result.List[0].Type, multiLine) |
315 return | 307 return |
316 } | 308 } |
317 p.parameters(result, multiLine) | 309 p.parameters(result, multiLine) |
318 } | 310 } |
319 } | 311 } |
320 | 312 |
321 | |
322 func identListSize(list []*ast.Ident, maxSize int) (size int) { | 313 func identListSize(list []*ast.Ident, maxSize int) (size int) { |
323 for i, x := range list { | 314 for i, x := range list { |
324 if i > 0 { | 315 if i > 0 { |
325 size += 2 // ", " | 316 size += 2 // ", " |
326 } | 317 } |
327 size += len(x.Name) | 318 size += len(x.Name) |
328 if size >= maxSize { | 319 if size >= maxSize { |
329 break | 320 break |
330 } | 321 } |
331 } | 322 } |
332 return | 323 return |
333 } | 324 } |
334 | 325 |
335 | |
336 func (p *printer) isOneLineFieldList(list []*ast.Field) bool { | 326 func (p *printer) isOneLineFieldList(list []*ast.Field) bool { |
337 if len(list) != 1 { | 327 if len(list) != 1 { |
338 return false // allow only one field | 328 return false // allow only one field |
339 } | 329 } |
340 f := list[0] | 330 f := list[0] |
341 if f.Tag != nil || f.Comment != nil { | 331 if f.Tag != nil || f.Comment != nil { |
342 return false // don't allow tags or comments | 332 return false // don't allow tags or comments |
343 } | 333 } |
344 // only name(s) and type | 334 // only name(s) and type |
345 const maxSize = 30 // adjust as appropriate, this is an approximate valu
e | 335 const maxSize = 30 // adjust as appropriate, this is an approximate valu
e |
346 namesSize := identListSize(f.Names, maxSize) | 336 namesSize := identListSize(f.Names, maxSize) |
347 if namesSize > 0 { | 337 if namesSize > 0 { |
348 namesSize = 1 // blank between names and types | 338 namesSize = 1 // blank between names and types |
349 } | 339 } |
350 typeSize := p.nodeSize(f.Type, maxSize) | 340 typeSize := p.nodeSize(f.Type, maxSize) |
351 return namesSize+typeSize <= maxSize | 341 return namesSize+typeSize <= maxSize |
352 } | 342 } |
353 | 343 |
354 | |
355 func (p *printer) setLineComment(text string) { | 344 func (p *printer) setLineComment(text string) { |
356 p.setComment(&ast.CommentGroup{[]*ast.Comment{&ast.Comment{token.NoPos,
text}}}) | 345 p.setComment(&ast.CommentGroup{[]*ast.Comment{&ast.Comment{token.NoPos,
text}}}) |
357 } | 346 } |
358 | 347 |
359 | |
360 func (p *printer) fieldList(fields *ast.FieldList, isStruct, isIncomplete bool)
{ | 348 func (p *printer) fieldList(fields *ast.FieldList, isStruct, isIncomplete bool)
{ |
361 p.nesting++ | 349 p.nesting++ |
362 defer func() { | 350 defer func() { |
363 p.nesting-- | 351 p.nesting-- |
364 }() | 352 }() |
365 | 353 |
366 lbrace := fields.Opening | 354 lbrace := fields.Opening |
367 list := fields.List | 355 list := fields.List |
368 rbrace := fields.Closing | 356 rbrace := fields.Closing |
369 srcIsOneLine := lbrace.IsValid() && rbrace.IsValid() && p.fset.Position(
lbrace).Line == p.fset.Position(rbrace).Line | 357 srcIsOneLine := lbrace.IsValid() && rbrace.IsValid() && p.fset.Position(
lbrace).Line == p.fset.Position(rbrace).Line |
(...skipping 98 matching lines...) Expand 10 before | Expand all | Expand 10 after Loading... |
468 p.print(formfeed) | 456 p.print(formfeed) |
469 } | 457 } |
470 p.flush(p.fset.Position(rbrace), token.RBRACE) // make s
ure we don't lose the last line comment | 458 p.flush(p.fset.Position(rbrace), token.RBRACE) // make s
ure we don't lose the last line comment |
471 p.setLineComment("// contains filtered or unexported met
hods") | 459 p.setLineComment("// contains filtered or unexported met
hods") |
472 } | 460 } |
473 | 461 |
474 } | 462 } |
475 p.print(unindent, formfeed, rbrace, token.RBRACE) | 463 p.print(unindent, formfeed, rbrace, token.RBRACE) |
476 } | 464 } |
477 | 465 |
478 | |
479 // ---------------------------------------------------------------------------- | 466 // ---------------------------------------------------------------------------- |
480 // Expressions | 467 // Expressions |
481 | 468 |
482 func walkBinary(e *ast.BinaryExpr) (has4, has5 bool, maxProblem int) { | 469 func walkBinary(e *ast.BinaryExpr) (has4, has5 bool, maxProblem int) { |
483 switch e.Op.Precedence() { | 470 switch e.Op.Precedence() { |
484 case 4: | 471 case 4: |
485 has4 = true | 472 has4 = true |
486 case 5: | 473 case 5: |
487 has5 = true | 474 has5 = true |
488 } | 475 } |
(...skipping 38 matching lines...) Expand 10 before | Expand all | Expand 10 after Loading... |
527 maxProblem = 5 | 514 maxProblem = 5 |
528 case "++", "--": | 515 case "++", "--": |
529 if maxProblem < 4 { | 516 if maxProblem < 4 { |
530 maxProblem = 4 | 517 maxProblem = 4 |
531 } | 518 } |
532 } | 519 } |
533 } | 520 } |
534 return | 521 return |
535 } | 522 } |
536 | 523 |
537 | |
538 func cutoff(e *ast.BinaryExpr, depth int) int { | 524 func cutoff(e *ast.BinaryExpr, depth int) int { |
539 has4, has5, maxProblem := walkBinary(e) | 525 has4, has5, maxProblem := walkBinary(e) |
540 if maxProblem > 0 { | 526 if maxProblem > 0 { |
541 return maxProblem + 1 | 527 return maxProblem + 1 |
542 } | 528 } |
543 if has4 && has5 { | 529 if has4 && has5 { |
544 if depth == 1 { | 530 if depth == 1 { |
545 return 5 | 531 return 5 |
546 } | 532 } |
547 return 4 | 533 return 4 |
548 } | 534 } |
549 if depth == 1 { | 535 if depth == 1 { |
550 return 6 | 536 return 6 |
551 } | 537 } |
552 return 4 | 538 return 4 |
553 } | 539 } |
554 | 540 |
555 | |
556 func diffPrec(expr ast.Expr, prec int) int { | 541 func diffPrec(expr ast.Expr, prec int) int { |
557 x, ok := expr.(*ast.BinaryExpr) | 542 x, ok := expr.(*ast.BinaryExpr) |
558 if !ok || prec != x.Op.Precedence() { | 543 if !ok || prec != x.Op.Precedence() { |
559 return 1 | 544 return 1 |
560 } | 545 } |
561 return 0 | 546 return 0 |
562 } | 547 } |
563 | 548 |
564 | |
565 func reduceDepth(depth int) int { | 549 func reduceDepth(depth int) int { |
566 depth-- | 550 depth-- |
567 if depth < 1 { | 551 if depth < 1 { |
568 depth = 1 | 552 depth = 1 |
569 } | 553 } |
570 return depth | 554 return depth |
571 } | 555 } |
572 | 556 |
573 | |
574 // Format the binary expression: decide the cutoff and then format. | 557 // Format the binary expression: decide the cutoff and then format. |
575 // Let's call depth == 1 Normal mode, and depth > 1 Compact mode. | 558 // Let's call depth == 1 Normal mode, and depth > 1 Compact mode. |
576 // (Algorithm suggestion by Russ Cox.) | 559 // (Algorithm suggestion by Russ Cox.) |
577 // | 560 // |
578 // The precedences are: | 561 // The precedences are: |
579 // 5 * / % << >> & &^ | 562 // 5 * / % << >> & &^ |
580 // 4 + - | ^ | 563 // 4 + - | ^ |
581 // 3 == != < <= > >= | 564 // 3 == != < <= > >= |
582 // 2 && | 565 // 2 && |
583 // 1 || | 566 // 1 || |
(...skipping 57 matching lines...) Expand 10 before | Expand all | Expand 10 after Loading... |
641 } | 624 } |
642 if printBlank { | 625 if printBlank { |
643 p.print(blank) | 626 p.print(blank) |
644 } | 627 } |
645 p.expr1(x.Y, prec+1, depth+1, multiLine) | 628 p.expr1(x.Y, prec+1, depth+1, multiLine) |
646 if ws == ignore { | 629 if ws == ignore { |
647 p.print(unindent) | 630 p.print(unindent) |
648 } | 631 } |
649 } | 632 } |
650 | 633 |
651 | |
652 func isBinary(expr ast.Expr) bool { | 634 func isBinary(expr ast.Expr) bool { |
653 _, ok := expr.(*ast.BinaryExpr) | 635 _, ok := expr.(*ast.BinaryExpr) |
654 return ok | 636 return ok |
655 } | 637 } |
656 | 638 |
657 | |
658 // If the expression contains one or more selector expressions, splits it into | 639 // If the expression contains one or more selector expressions, splits it into |
659 // two expressions at the rightmost period. Writes entire expr to suffix when | 640 // two expressions at the rightmost period. Writes entire expr to suffix when |
660 // selector isn't found. Rewrites AST nodes for calls, index expressions and | 641 // selector isn't found. Rewrites AST nodes for calls, index expressions and |
661 // type assertions, all of which may be found in selector chains, to make them | 642 // type assertions, all of which may be found in selector chains, to make them |
662 // parts of the chain. | 643 // parts of the chain. |
663 func splitSelector(expr ast.Expr) (body, suffix ast.Expr) { | 644 func splitSelector(expr ast.Expr) (body, suffix ast.Expr) { |
664 switch x := expr.(type) { | 645 switch x := expr.(type) { |
665 case *ast.SelectorExpr: | 646 case *ast.SelectorExpr: |
666 body, suffix = x.X, x.Sel | 647 body, suffix = x.X, x.Sel |
667 return | 648 return |
(...skipping 19 matching lines...) Expand all Loading... |
687 body, suffix = splitSelector(x.X) | 668 body, suffix = splitSelector(x.X) |
688 if body != nil { | 669 if body != nil { |
689 suffix = &ast.TypeAssertExpr{suffix, x.Type} | 670 suffix = &ast.TypeAssertExpr{suffix, x.Type} |
690 return | 671 return |
691 } | 672 } |
692 } | 673 } |
693 suffix = expr | 674 suffix = expr |
694 return | 675 return |
695 } | 676 } |
696 | 677 |
697 | |
698 // Convert an expression into an expression list split at the periods of | 678 // Convert an expression into an expression list split at the periods of |
699 // selector expressions. | 679 // selector expressions. |
700 func selectorExprList(expr ast.Expr) (list []ast.Expr) { | 680 func selectorExprList(expr ast.Expr) (list []ast.Expr) { |
701 // split expression | 681 // split expression |
702 for expr != nil { | 682 for expr != nil { |
703 var suffix ast.Expr | 683 var suffix ast.Expr |
704 expr, suffix = splitSelector(expr) | 684 expr, suffix = splitSelector(expr) |
705 list = append(list, suffix) | 685 list = append(list, suffix) |
706 } | 686 } |
707 | 687 |
708 // reverse list | 688 // reverse list |
709 for i, j := 0, len(list)-1; i < j; i, j = i+1, j-1 { | 689 for i, j := 0, len(list)-1; i < j; i, j = i+1, j-1 { |
710 list[i], list[j] = list[j], list[i] | 690 list[i], list[j] = list[j], list[i] |
711 } | 691 } |
712 | 692 |
713 return | 693 return |
714 } | 694 } |
715 | 695 |
716 | |
717 // Sets multiLine to true if the expression spans multiple lines. | 696 // Sets multiLine to true if the expression spans multiple lines. |
718 func (p *printer) expr1(expr ast.Expr, prec1, depth int, multiLine *bool) { | 697 func (p *printer) expr1(expr ast.Expr, prec1, depth int, multiLine *bool) { |
719 p.print(expr.Pos()) | 698 p.print(expr.Pos()) |
720 | 699 |
721 switch x := expr.(type) { | 700 switch x := expr.(type) { |
722 case *ast.BadExpr: | 701 case *ast.BadExpr: |
723 p.print("BadExpr") | 702 p.print("BadExpr") |
724 | 703 |
725 case *ast.Ident: | 704 case *ast.Ident: |
726 p.print(x) | 705 p.print(x) |
(...skipping 166 matching lines...) Expand 10 before | Expand all | Expand 10 after Loading... |
893 p.print(blank) | 872 p.print(blank) |
894 p.expr(x.Value, multiLine) | 873 p.expr(x.Value, multiLine) |
895 | 874 |
896 default: | 875 default: |
897 panic("unreachable") | 876 panic("unreachable") |
898 } | 877 } |
899 | 878 |
900 return | 879 return |
901 } | 880 } |
902 | 881 |
903 | |
904 func (p *printer) expr0(x ast.Expr, depth int, multiLine *bool) { | 882 func (p *printer) expr0(x ast.Expr, depth int, multiLine *bool) { |
905 p.expr1(x, token.LowestPrec, depth, multiLine) | 883 p.expr1(x, token.LowestPrec, depth, multiLine) |
906 } | 884 } |
907 | 885 |
908 | |
909 // Sets multiLine to true if the expression spans multiple lines. | 886 // Sets multiLine to true if the expression spans multiple lines. |
910 func (p *printer) expr(x ast.Expr, multiLine *bool) { | 887 func (p *printer) expr(x ast.Expr, multiLine *bool) { |
911 const depth = 1 | 888 const depth = 1 |
912 p.expr1(x, token.LowestPrec, depth, multiLine) | 889 p.expr1(x, token.LowestPrec, depth, multiLine) |
913 } | 890 } |
914 | 891 |
915 | |
916 // ---------------------------------------------------------------------------- | 892 // ---------------------------------------------------------------------------- |
917 // Statements | 893 // Statements |
918 | 894 |
919 // Print the statement list indented, but without a newline after the last state
ment. | 895 // Print the statement list indented, but without a newline after the last state
ment. |
920 // Extra line breaks between statements in the source are respected but at most
one | 896 // Extra line breaks between statements in the source are respected but at most
one |
921 // empty line is printed between statements. | 897 // empty line is printed between statements. |
922 func (p *printer) stmtList(list []ast.Stmt, _indent int, nextIsRBrace bool) { | 898 func (p *printer) stmtList(list []ast.Stmt, _indent int, nextIsRBrace bool) { |
923 // TODO(gri): fix _indent code | 899 // TODO(gri): fix _indent code |
924 if _indent > 0 { | 900 if _indent > 0 { |
925 p.print(indent) | 901 p.print(indent) |
926 } | 902 } |
927 var multiLine bool | 903 var multiLine bool |
928 for i, s := range list { | 904 for i, s := range list { |
929 // _indent == 0 only for lists of switch/select case clauses; | 905 // _indent == 0 only for lists of switch/select case clauses; |
930 // in those cases each clause is a new section | 906 // in those cases each clause is a new section |
931 p.linebreak(p.fset.Position(s.Pos()).Line, 1, ignore, i == 0 ||
_indent == 0 || multiLine) | 907 p.linebreak(p.fset.Position(s.Pos()).Line, 1, ignore, i == 0 ||
_indent == 0 || multiLine) |
932 multiLine = false | 908 multiLine = false |
933 p.stmt(s, nextIsRBrace && i == len(list)-1, &multiLine) | 909 p.stmt(s, nextIsRBrace && i == len(list)-1, &multiLine) |
934 } | 910 } |
935 if _indent > 0 { | 911 if _indent > 0 { |
936 p.print(unindent) | 912 p.print(unindent) |
937 } | 913 } |
938 } | 914 } |
939 | 915 |
940 | |
941 // block prints an *ast.BlockStmt; it always spans at least two lines. | 916 // block prints an *ast.BlockStmt; it always spans at least two lines. |
942 func (p *printer) block(s *ast.BlockStmt, indent int) { | 917 func (p *printer) block(s *ast.BlockStmt, indent int) { |
943 p.print(s.Pos(), token.LBRACE) | 918 p.print(s.Pos(), token.LBRACE) |
944 p.stmtList(s.List, indent, true) | 919 p.stmtList(s.List, indent, true) |
945 p.linebreak(p.fset.Position(s.Rbrace).Line, 1, ignore, true) | 920 p.linebreak(p.fset.Position(s.Rbrace).Line, 1, ignore, true) |
946 p.print(s.Rbrace, token.RBRACE) | 921 p.print(s.Rbrace, token.RBRACE) |
947 } | 922 } |
948 | 923 |
949 | |
950 func isTypeName(x ast.Expr) bool { | 924 func isTypeName(x ast.Expr) bool { |
951 switch t := x.(type) { | 925 switch t := x.(type) { |
952 case *ast.Ident: | 926 case *ast.Ident: |
953 return true | 927 return true |
954 case *ast.SelectorExpr: | 928 case *ast.SelectorExpr: |
955 return isTypeName(t.X) | 929 return isTypeName(t.X) |
956 } | 930 } |
957 return false | 931 return false |
958 } | 932 } |
959 | 933 |
960 | |
961 func stripParens(x ast.Expr) ast.Expr { | 934 func stripParens(x ast.Expr) ast.Expr { |
962 if px, strip := x.(*ast.ParenExpr); strip { | 935 if px, strip := x.(*ast.ParenExpr); strip { |
963 // parentheses must not be stripped if there are any | 936 // parentheses must not be stripped if there are any |
964 // unparenthesized composite literals starting with | 937 // unparenthesized composite literals starting with |
965 // a type name | 938 // a type name |
966 ast.Inspect(px.X, func(node ast.Node) bool { | 939 ast.Inspect(px.X, func(node ast.Node) bool { |
967 switch x := node.(type) { | 940 switch x := node.(type) { |
968 case *ast.ParenExpr: | 941 case *ast.ParenExpr: |
969 // parentheses protect enclosed composite litera
ls | 942 // parentheses protect enclosed composite litera
ls |
970 return false | 943 return false |
971 case *ast.CompositeLit: | 944 case *ast.CompositeLit: |
972 if isTypeName(x.Type) { | 945 if isTypeName(x.Type) { |
973 strip = false // do not strip parenthese
s | 946 strip = false // do not strip parenthese
s |
974 } | 947 } |
975 return false | 948 return false |
976 } | 949 } |
977 // in all other cases, keep inspecting | 950 // in all other cases, keep inspecting |
978 return true | 951 return true |
979 }) | 952 }) |
980 if strip { | 953 if strip { |
981 return stripParens(px.X) | 954 return stripParens(px.X) |
982 } | 955 } |
983 } | 956 } |
984 return x | 957 return x |
985 } | 958 } |
986 | 959 |
987 | |
988 func (p *printer) controlClause(isForStmt bool, init ast.Stmt, expr ast.Expr, po
st ast.Stmt) { | 960 func (p *printer) controlClause(isForStmt bool, init ast.Stmt, expr ast.Expr, po
st ast.Stmt) { |
989 p.print(blank) | 961 p.print(blank) |
990 needsBlank := false | 962 needsBlank := false |
991 if init == nil && post == nil { | 963 if init == nil && post == nil { |
992 // no semicolons required | 964 // no semicolons required |
993 if expr != nil { | 965 if expr != nil { |
994 p.expr(stripParens(expr), ignoreMultiLine) | 966 p.expr(stripParens(expr), ignoreMultiLine) |
995 needsBlank = true | 967 needsBlank = true |
996 } | 968 } |
997 } else { | 969 } else { |
(...skipping 14 matching lines...) Expand all Loading... |
1012 p.stmt(post, false, ignoreMultiLine) | 984 p.stmt(post, false, ignoreMultiLine) |
1013 needsBlank = true | 985 needsBlank = true |
1014 } | 986 } |
1015 } | 987 } |
1016 } | 988 } |
1017 if needsBlank { | 989 if needsBlank { |
1018 p.print(blank) | 990 p.print(blank) |
1019 } | 991 } |
1020 } | 992 } |
1021 | 993 |
1022 | |
1023 // Sets multiLine to true if the statements spans multiple lines. | 994 // Sets multiLine to true if the statements spans multiple lines. |
1024 func (p *printer) stmt(stmt ast.Stmt, nextIsRBrace bool, multiLine *bool) { | 995 func (p *printer) stmt(stmt ast.Stmt, nextIsRBrace bool, multiLine *bool) { |
1025 p.print(stmt.Pos()) | 996 p.print(stmt.Pos()) |
1026 | 997 |
1027 switch s := stmt.(type) { | 998 switch s := stmt.(type) { |
1028 case *ast.BadStmt: | 999 case *ast.BadStmt: |
1029 p.print("BadStmt") | 1000 p.print("BadStmt") |
1030 | 1001 |
1031 case *ast.DeclStmt: | 1002 case *ast.DeclStmt: |
1032 p.decl(s.Decl, multiLine) | 1003 p.decl(s.Decl, multiLine) |
(...skipping 153 matching lines...) Expand 10 before | Expand all | Expand 10 after Loading... |
1186 p.block(s.Body, 1) | 1157 p.block(s.Body, 1) |
1187 *multiLine = true | 1158 *multiLine = true |
1188 | 1159 |
1189 default: | 1160 default: |
1190 panic("unreachable") | 1161 panic("unreachable") |
1191 } | 1162 } |
1192 | 1163 |
1193 return | 1164 return |
1194 } | 1165 } |
1195 | 1166 |
1196 | |
1197 // ---------------------------------------------------------------------------- | 1167 // ---------------------------------------------------------------------------- |
1198 // Declarations | 1168 // Declarations |
1199 | 1169 |
1200 // The keepTypeColumn function determines if the type column of a series of | 1170 // The keepTypeColumn function determines if the type column of a series of |
1201 // consecutive const or var declarations must be kept, or if initialization | 1171 // consecutive const or var declarations must be kept, or if initialization |
1202 // values (V) can be placed in the type column (T) instead. The i'th entry | 1172 // values (V) can be placed in the type column (T) instead. The i'th entry |
1203 // in the result slice is true if the type column in spec[i] must be kept. | 1173 // in the result slice is true if the type column in spec[i] must be kept. |
1204 // | 1174 // |
1205 // For example, the declaration: | 1175 // For example, the declaration: |
1206 // | 1176 // |
(...skipping 48 matching lines...) Expand 10 before | Expand all | Expand 10 after Loading... |
1255 } | 1225 } |
1256 } | 1226 } |
1257 if i0 >= 0 { | 1227 if i0 >= 0 { |
1258 // end of a run | 1228 // end of a run |
1259 populate(i0, len(specs), keepType) | 1229 populate(i0, len(specs), keepType) |
1260 } | 1230 } |
1261 | 1231 |
1262 return m | 1232 return m |
1263 } | 1233 } |
1264 | 1234 |
1265 | |
1266 func (p *printer) valueSpec(s *ast.ValueSpec, keepType, doIndent bool, multiLine
*bool) { | 1235 func (p *printer) valueSpec(s *ast.ValueSpec, keepType, doIndent bool, multiLine
*bool) { |
1267 p.setComment(s.Doc) | 1236 p.setComment(s.Doc) |
1268 p.identList(s.Names, doIndent, multiLine) // always present | 1237 p.identList(s.Names, doIndent, multiLine) // always present |
1269 extraTabs := 3 | 1238 extraTabs := 3 |
1270 if s.Type != nil || keepType { | 1239 if s.Type != nil || keepType { |
1271 p.print(vtab) | 1240 p.print(vtab) |
1272 extraTabs-- | 1241 extraTabs-- |
1273 } | 1242 } |
1274 if s.Type != nil { | 1243 if s.Type != nil { |
1275 p.expr(s.Type, multiLine) | 1244 p.expr(s.Type, multiLine) |
1276 } | 1245 } |
1277 if s.Values != nil { | 1246 if s.Values != nil { |
1278 p.print(vtab, token.ASSIGN) | 1247 p.print(vtab, token.ASSIGN) |
1279 p.exprList(token.NoPos, s.Values, 1, blankStart|commaSep, multiL
ine, token.NoPos) | 1248 p.exprList(token.NoPos, s.Values, 1, blankStart|commaSep, multiL
ine, token.NoPos) |
1280 extraTabs-- | 1249 extraTabs-- |
1281 } | 1250 } |
1282 if s.Comment != nil { | 1251 if s.Comment != nil { |
1283 for ; extraTabs > 0; extraTabs-- { | 1252 for ; extraTabs > 0; extraTabs-- { |
1284 p.print(vtab) | 1253 p.print(vtab) |
1285 } | 1254 } |
1286 p.setComment(s.Comment) | 1255 p.setComment(s.Comment) |
1287 } | 1256 } |
1288 } | 1257 } |
1289 | 1258 |
1290 | |
1291 // The parameter n is the number of specs in the group. If doIndent is set, | 1259 // The parameter n is the number of specs in the group. If doIndent is set, |
1292 // multi-line identifier lists in the spec are indented when the first | 1260 // multi-line identifier lists in the spec are indented when the first |
1293 // linebreak is encountered. | 1261 // linebreak is encountered. |
1294 // Sets multiLine to true if the spec spans multiple lines. | 1262 // Sets multiLine to true if the spec spans multiple lines. |
1295 // | 1263 // |
1296 func (p *printer) spec(spec ast.Spec, n int, doIndent bool, multiLine *bool) { | 1264 func (p *printer) spec(spec ast.Spec, n int, doIndent bool, multiLine *bool) { |
1297 switch s := spec.(type) { | 1265 switch s := spec.(type) { |
1298 case *ast.ImportSpec: | 1266 case *ast.ImportSpec: |
1299 p.setComment(s.Doc) | 1267 p.setComment(s.Doc) |
1300 if s.Name != nil { | 1268 if s.Name != nil { |
(...skipping 28 matching lines...) Expand all Loading... |
1329 p.print(vtab) | 1297 p.print(vtab) |
1330 } | 1298 } |
1331 p.expr(s.Type, multiLine) | 1299 p.expr(s.Type, multiLine) |
1332 p.setComment(s.Comment) | 1300 p.setComment(s.Comment) |
1333 | 1301 |
1334 default: | 1302 default: |
1335 panic("unreachable") | 1303 panic("unreachable") |
1336 } | 1304 } |
1337 } | 1305 } |
1338 | 1306 |
1339 | |
1340 // Sets multiLine to true if the declaration spans multiple lines. | 1307 // Sets multiLine to true if the declaration spans multiple lines. |
1341 func (p *printer) genDecl(d *ast.GenDecl, multiLine *bool) { | 1308 func (p *printer) genDecl(d *ast.GenDecl, multiLine *bool) { |
1342 p.setComment(d.Doc) | 1309 p.setComment(d.Doc) |
1343 p.print(d.Pos(), d.Tok, blank) | 1310 p.print(d.Pos(), d.Tok, blank) |
1344 | 1311 |
1345 if d.Lparen.IsValid() { | 1312 if d.Lparen.IsValid() { |
1346 // group of parenthesized declarations | 1313 // group of parenthesized declarations |
1347 p.print(d.Lparen, token.LPAREN) | 1314 p.print(d.Lparen, token.LPAREN) |
1348 if n := len(d.Specs); n > 0 { | 1315 if n := len(d.Specs); n > 0 { |
1349 p.print(indent, formfeed) | 1316 p.print(indent, formfeed) |
(...skipping 23 matching lines...) Expand all Loading... |
1373 *multiLine = true | 1340 *multiLine = true |
1374 } | 1341 } |
1375 p.print(d.Rparen, token.RPAREN) | 1342 p.print(d.Rparen, token.RPAREN) |
1376 | 1343 |
1377 } else { | 1344 } else { |
1378 // single declaration | 1345 // single declaration |
1379 p.spec(d.Specs[0], 1, true, multiLine) | 1346 p.spec(d.Specs[0], 1, true, multiLine) |
1380 } | 1347 } |
1381 } | 1348 } |
1382 | 1349 |
1383 | |
1384 // nodeSize determines the size of n in chars after formatting. | 1350 // nodeSize determines the size of n in chars after formatting. |
1385 // The result is <= maxSize if the node fits on one line with at | 1351 // The result is <= maxSize if the node fits on one line with at |
1386 // most maxSize chars and the formatted output doesn't contain | 1352 // most maxSize chars and the formatted output doesn't contain |
1387 // any control chars. Otherwise, the result is > maxSize. | 1353 // any control chars. Otherwise, the result is > maxSize. |
1388 // | 1354 // |
1389 func (p *printer) nodeSize(n ast.Node, maxSize int) (size int) { | 1355 func (p *printer) nodeSize(n ast.Node, maxSize int) (size int) { |
1390 // nodeSize invokes the printer, which may invoke nodeSize | 1356 // nodeSize invokes the printer, which may invoke nodeSize |
1391 // recursively. For deep composite literal nests, this can | 1357 // recursively. For deep composite literal nests, this can |
1392 // lead to an exponential algorithm. Remember previous | 1358 // lead to an exponential algorithm. Remember previous |
1393 // results to prune the recursion (was issue 1628). | 1359 // results to prune the recursion (was issue 1628). |
(...skipping 17 matching lines...) Expand all Loading... |
1411 if ch < ' ' { | 1377 if ch < ' ' { |
1412 return | 1378 return |
1413 } | 1379 } |
1414 } | 1380 } |
1415 size = buf.Len() // n fits | 1381 size = buf.Len() // n fits |
1416 p.nodeSizes[n] = size | 1382 p.nodeSizes[n] = size |
1417 } | 1383 } |
1418 return | 1384 return |
1419 } | 1385 } |
1420 | 1386 |
1421 | |
1422 func (p *printer) isOneLineFunc(b *ast.BlockStmt, headerSize int) bool { | 1387 func (p *printer) isOneLineFunc(b *ast.BlockStmt, headerSize int) bool { |
1423 pos1 := b.Pos() | 1388 pos1 := b.Pos() |
1424 pos2 := b.Rbrace | 1389 pos2 := b.Rbrace |
1425 if pos1.IsValid() && pos2.IsValid() && p.fset.Position(pos1).Line != p.f
set.Position(pos2).Line { | 1390 if pos1.IsValid() && pos2.IsValid() && p.fset.Position(pos1).Line != p.f
set.Position(pos2).Line { |
1426 // opening and closing brace are on different lines - don't make
it a one-liner | 1391 // opening and closing brace are on different lines - don't make
it a one-liner |
1427 return false | 1392 return false |
1428 } | 1393 } |
1429 if len(b.List) > 5 || p.commentBefore(p.fset.Position(pos2)) { | 1394 if len(b.List) > 5 || p.commentBefore(p.fset.Position(pos2)) { |
1430 // too many statements or there is a comment inside - don't make
it a one-liner | 1395 // too many statements or there is a comment inside - don't make
it a one-liner |
1431 return false | 1396 return false |
1432 } | 1397 } |
1433 // otherwise, estimate body size | 1398 // otherwise, estimate body size |
1434 const maxSize = 100 | 1399 const maxSize = 100 |
1435 bodySize := 0 | 1400 bodySize := 0 |
1436 for i, s := range b.List { | 1401 for i, s := range b.List { |
1437 if i > 0 { | 1402 if i > 0 { |
1438 bodySize += 2 // space for a semicolon and blank | 1403 bodySize += 2 // space for a semicolon and blank |
1439 } | 1404 } |
1440 bodySize += p.nodeSize(s, maxSize) | 1405 bodySize += p.nodeSize(s, maxSize) |
1441 } | 1406 } |
1442 return headerSize+bodySize <= maxSize | 1407 return headerSize+bodySize <= maxSize |
1443 } | 1408 } |
1444 | 1409 |
1445 | |
1446 // Sets multiLine to true if the function body spans multiple lines. | 1410 // Sets multiLine to true if the function body spans multiple lines. |
1447 func (p *printer) funcBody(b *ast.BlockStmt, headerSize int, isLit bool, multiLi
ne *bool) { | 1411 func (p *printer) funcBody(b *ast.BlockStmt, headerSize int, isLit bool, multiLi
ne *bool) { |
1448 if b == nil { | 1412 if b == nil { |
1449 return | 1413 return |
1450 } | 1414 } |
1451 | 1415 |
1452 p.nesting++ | 1416 p.nesting++ |
1453 defer func() { | 1417 defer func() { |
1454 p.nesting-- | 1418 p.nesting-- |
1455 }() | 1419 }() |
(...skipping 16 matching lines...) Expand all Loading... |
1472 } | 1436 } |
1473 p.print(b.Rbrace, token.RBRACE) | 1437 p.print(b.Rbrace, token.RBRACE) |
1474 return | 1438 return |
1475 } | 1439 } |
1476 | 1440 |
1477 p.print(blank) | 1441 p.print(blank) |
1478 p.block(b, 1) | 1442 p.block(b, 1) |
1479 *multiLine = true | 1443 *multiLine = true |
1480 } | 1444 } |
1481 | 1445 |
1482 | |
1483 // distance returns the column difference between from and to if both | 1446 // distance returns the column difference between from and to if both |
1484 // are on the same line; if they are on different lines (or unknown) | 1447 // are on the same line; if they are on different lines (or unknown) |
1485 // the result is infinity. | 1448 // the result is infinity. |
1486 func (p *printer) distance(from0 token.Pos, to token.Position) int { | 1449 func (p *printer) distance(from0 token.Pos, to token.Position) int { |
1487 from := p.fset.Position(from0) | 1450 from := p.fset.Position(from0) |
1488 if from.IsValid() && to.IsValid() && from.Line == to.Line { | 1451 if from.IsValid() && to.IsValid() && from.Line == to.Line { |
1489 return to.Column - from.Column | 1452 return to.Column - from.Column |
1490 } | 1453 } |
1491 return infinity | 1454 return infinity |
1492 } | 1455 } |
1493 | 1456 |
1494 | |
1495 // Sets multiLine to true if the declaration spans multiple lines. | 1457 // Sets multiLine to true if the declaration spans multiple lines. |
1496 func (p *printer) funcDecl(d *ast.FuncDecl, multiLine *bool) { | 1458 func (p *printer) funcDecl(d *ast.FuncDecl, multiLine *bool) { |
1497 p.setComment(d.Doc) | 1459 p.setComment(d.Doc) |
1498 p.print(d.Pos(), token.FUNC, blank) | 1460 p.print(d.Pos(), token.FUNC, blank) |
1499 if d.Recv != nil { | 1461 if d.Recv != nil { |
1500 p.parameters(d.Recv, multiLine) // method: print receiver | 1462 p.parameters(d.Recv, multiLine) // method: print receiver |
1501 p.print(blank) | 1463 p.print(blank) |
1502 } | 1464 } |
1503 p.expr(d.Name, multiLine) | 1465 p.expr(d.Name, multiLine) |
1504 p.signature(d.Type.Params, d.Type.Results, multiLine) | 1466 p.signature(d.Type.Params, d.Type.Results, multiLine) |
1505 p.funcBody(d.Body, p.distance(d.Pos(), p.pos), false, multiLine) | 1467 p.funcBody(d.Body, p.distance(d.Pos(), p.pos), false, multiLine) |
1506 } | 1468 } |
1507 | 1469 |
1508 | |
1509 // Sets multiLine to true if the declaration spans multiple lines. | 1470 // Sets multiLine to true if the declaration spans multiple lines. |
1510 func (p *printer) decl(decl ast.Decl, multiLine *bool) { | 1471 func (p *printer) decl(decl ast.Decl, multiLine *bool) { |
1511 switch d := decl.(type) { | 1472 switch d := decl.(type) { |
1512 case *ast.BadDecl: | 1473 case *ast.BadDecl: |
1513 p.print(d.Pos(), "BadDecl") | 1474 p.print(d.Pos(), "BadDecl") |
1514 case *ast.GenDecl: | 1475 case *ast.GenDecl: |
1515 p.genDecl(d, multiLine) | 1476 p.genDecl(d, multiLine) |
1516 case *ast.FuncDecl: | 1477 case *ast.FuncDecl: |
1517 p.funcDecl(d, multiLine) | 1478 p.funcDecl(d, multiLine) |
1518 default: | 1479 default: |
1519 panic("unreachable") | 1480 panic("unreachable") |
1520 } | 1481 } |
1521 } | 1482 } |
1522 | 1483 |
1523 | |
1524 // ---------------------------------------------------------------------------- | 1484 // ---------------------------------------------------------------------------- |
1525 // Files | 1485 // Files |
1526 | 1486 |
1527 func declToken(decl ast.Decl) (tok token.Token) { | 1487 func declToken(decl ast.Decl) (tok token.Token) { |
1528 tok = token.ILLEGAL | 1488 tok = token.ILLEGAL |
1529 switch d := decl.(type) { | 1489 switch d := decl.(type) { |
1530 case *ast.GenDecl: | 1490 case *ast.GenDecl: |
1531 tok = d.Tok | 1491 tok = d.Tok |
1532 case *ast.FuncDecl: | 1492 case *ast.FuncDecl: |
1533 tok = token.FUNC | 1493 tok = token.FUNC |
1534 } | 1494 } |
1535 return | 1495 return |
1536 } | 1496 } |
1537 | 1497 |
1538 | |
1539 func (p *printer) file(src *ast.File) { | 1498 func (p *printer) file(src *ast.File) { |
1540 p.setComment(src.Doc) | 1499 p.setComment(src.Doc) |
1541 p.print(src.Pos(), token.PACKAGE, blank) | 1500 p.print(src.Pos(), token.PACKAGE, blank) |
1542 p.expr(src.Name, ignoreMultiLine) | 1501 p.expr(src.Name, ignoreMultiLine) |
1543 | 1502 |
1544 if len(src.Decls) > 0 { | 1503 if len(src.Decls) > 0 { |
1545 tok := token.ILLEGAL | 1504 tok := token.ILLEGAL |
1546 for _, d := range src.Decls { | 1505 for _, d := range src.Decls { |
1547 prev := tok | 1506 prev := tok |
1548 tok = declToken(d) | 1507 tok = declToken(d) |
1549 // if the declaration token changed (e.g., from CONST to
TYPE) | 1508 // if the declaration token changed (e.g., from CONST to
TYPE) |
1550 // print an empty line between top-level declarations | 1509 // print an empty line between top-level declarations |
1551 min := 1 | 1510 min := 1 |
1552 if prev != tok { | 1511 if prev != tok { |
1553 min = 2 | 1512 min = 2 |
1554 } | 1513 } |
1555 p.linebreak(p.fset.Position(d.Pos()).Line, min, ignore,
false) | 1514 p.linebreak(p.fset.Position(d.Pos()).Line, min, ignore,
false) |
1556 p.decl(d, ignoreMultiLine) | 1515 p.decl(d, ignoreMultiLine) |
1557 } | 1516 } |
1558 } | 1517 } |
1559 | 1518 |
1560 p.print(newline) | 1519 p.print(newline) |
1561 } | 1520 } |
OLD | NEW |