Rietveld Code Review Tool
Help | Bug tracker | Discussion group | Source code | Sign in
(1128)

Delta Between Two Patch Sets: src/pkg/go/printer/printer.go

Issue 4291070: code review 4291070: go/scanner: return literal as string instead of []byte (Closed)
Left Patch Set: diff -r f75a02fd83be https://go.googlecode.com/hg/ Created 13 years ago
Right Patch Set: diff -r 4073ecdfc054 https://go.googlecode.com/hg/ Created 13 years ago
Left:
Right:
Use n/p to move between diff chunks; N/P to move between comments. Please Sign in to add in-line comments.
Jump to:
Left: Side by side diff | Download
Right: Side by side diff | Download
LEFTRIGHT
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 // The printer package implements printing of AST nodes. 5 // The printer package implements printing of AST nodes.
6 package printer 6 package printer
7 7
8 import ( 8 import (
9 "bytes" 9 "bytes"
10 "fmt" 10 "fmt"
11 "go/ast" 11 "go/ast"
12 "go/token" 12 "go/token"
13 "io" 13 "io"
14 "os" 14 "os"
15 "path/filepath" 15 "path/filepath"
16 "runtime" 16 "runtime"
17 "strings"
17 "tabwriter" 18 "tabwriter"
18 ) 19 )
19 20
20 21
21 const debug = false // enable for debugging 22 const debug = false // enable for debugging
22 23
23 24
24 type whiteSpace int 25 type whiteSpace int
25 26
26 const ( 27 const (
27 ignore = whiteSpace(0) 28 ignore = whiteSpace(0)
28 blank = whiteSpace(' ') 29 blank = whiteSpace(' ')
29 vtab = whiteSpace('\v') 30 vtab = whiteSpace('\v')
30 newline = whiteSpace('\n') 31 newline = whiteSpace('\n')
31 formfeed = whiteSpace('\f') 32 formfeed = whiteSpace('\f')
32 indent = whiteSpace('>') 33 indent = whiteSpace('>')
33 unindent = whiteSpace('<') 34 unindent = whiteSpace('<')
34 ) 35 )
35 36
36 37
37 const ( 38 const (
38 » esc2 = '\xfe' // an escape byte that cannot occur in regular UTF-8 39 » esc2 = '\xfe' // an escape byte that cannot oc cur in regular UTF-8
39 » _ = 1 / (esc2 - tabwriter.Escape) // cause compiler error if esc2 == tabwriter.Escape 40 » _ = 1 / (esc2 - tabwriter.Escape) // cause compiler error if esc2 == tabwriter.Escape
41 » esc2str = "\xfe"
40 ) 42 )
41 43
42 44
43 var ( 45 var (
44 esc = []byte{tabwriter.Escape} 46 esc = []byte{tabwriter.Escape}
45 htab = []byte{'\t'} 47 htab = []byte{'\t'}
46 htabs = []byte("\t\t\t\t\t\t\t\t") 48 htabs = []byte("\t\t\t\t\t\t\t\t")
47 newlines = []byte("\n\n\n\n\n\n\n\n") // more than the max determined b y nlines 49 newlines = []byte("\n\n\n\n\n\n\n\n") // more than the max determined b y nlines
48 formfeeds = []byte("\f\f\f\f\f\f\f\f") // more than the max determined b y nlines 50 formfeeds = []byte("\f\f\f\f\f\f\f\f") // more than the max determined b y nlines
49 ) 51 )
(...skipping 24 matching lines...) Expand all
74 fset *token.FileSet 76 fset *token.FileSet
75 errors chan os.Error 77 errors chan os.Error
76 78
77 // Current state 79 // Current state
78 nesting int // nesting level (0: top-level (package scope), >0: functions/decls.) 80 nesting int // nesting level (0: top-level (package scope), >0: functions/decls.)
79 written int // number of bytes written 81 written int // number of bytes written
80 indent int // current indentation 82 indent int // current indentation
81 mode pmode // current printer mode 83 mode pmode // current printer mode
82 lastTok token.Token // the last token printed (token.ILLEGAL if it's whi tespace) 84 lastTok token.Token // the last token printed (token.ILLEGAL if it's whi tespace)
83 85
84 » // Buffered whitespace 86 » // Reused buffers
85 » buffer []whiteSpace 87 » wsbuf []whiteSpace // delayed white space
88 » litbuf bytes.Buffer // for creation of escaped literals and comments
86 89
87 // The (possibly estimated) position in the generated output; 90 // The (possibly estimated) position in the generated output;
88 // in AST space (i.e., pos is set whenever a token position is 91 // in AST space (i.e., pos is set whenever a token position is
89 // known accurately, and updated dependending on what has been 92 // known accurately, and updated dependending on what has been
90 // written). 93 // written).
91 pos token.Position 94 pos token.Position
92 95
93 // The value of pos immediately after the last item has been 96 // The value of pos immediately after the last item has been
94 // written using writeItem. 97 // written using writeItem.
95 last token.Position 98 last token.Position
96 99
97 // The list of all source comments, in order of appearance. 100 // The list of all source comments, in order of appearance.
98 comments []*ast.CommentGroup // may be nil 101 comments []*ast.CommentGroup // may be nil
99 cindex int // current comment index 102 cindex int // current comment index
100 useNodeComments bool // if not set, ignore lead and line comments of nodes 103 useNodeComments bool // if not set, ignore lead and line comments of nodes
101 104
102 // Cache of already computed node sizes. 105 // Cache of already computed node sizes.
103 nodeSizes map[ast.Node]int 106 nodeSizes map[ast.Node]int
104 } 107 }
105 108
106 109
107 func (p *printer) init(output io.Writer, cfg *Config, fset *token.FileSet, nodeS izes map[ast.Node]int) { 110 func (p *printer) init(output io.Writer, cfg *Config, fset *token.FileSet, nodeS izes map[ast.Node]int) {
108 p.output = output 111 p.output = output
109 p.Config = *cfg 112 p.Config = *cfg
110 p.fset = fset 113 p.fset = fset
111 p.errors = make(chan os.Error) 114 p.errors = make(chan os.Error)
112 » p.buffer = make([]whiteSpace, 0, 16) // whitespace sequences are short 115 » p.wsbuf = make([]whiteSpace, 0, 16) // whitespace sequences are short
113 p.nodeSizes = nodeSizes 116 p.nodeSizes = nodeSizes
114 } 117 }
115 118
116 119
117 func (p *printer) internalError(msg ...interface{}) { 120 func (p *printer) internalError(msg ...interface{}) {
118 if debug { 121 if debug {
119 fmt.Print(p.pos.String() + ": ") 122 fmt.Print(p.pos.String() + ": ")
120 fmt.Println(msg...) 123 fmt.Println(msg...)
121 panic("go/printer") 124 panic("go/printer")
122 } 125 }
126 }
127
128
129 // escape escapes string s by bracketing it with tabwriter.Escape.
130 // Escapes strings pass through tabwriter unchanged. (Note that
rsc 2011/03/29 03:52:20 s/Escapes/Escaped/
gri 2011/03/29 04:44:34 Done.
131 // valid Go programs cannot contain tabwriter.Escape bytes since
132 // they do not appear in legal UTF-8 sequences).
133 //
134 func (p *printer) escape(s string) string {
135 p.litbuf.Reset()
136 p.litbuf.WriteByte(tabwriter.Escape)
137 p.litbuf.WriteString(s)
138 p.litbuf.WriteByte(tabwriter.Escape)
139 return p.litbuf.String()
rsc 2011/03/29 03:52:20 I haven't examined this in detail, but it appears
gri 2011/03/29 04:44:34 Correct. I want to push the strings a bit further
123 } 140 }
124 141
125 142
126 // nlines returns the adjusted number of linebreaks given the desired number 143 // nlines returns the adjusted number of linebreaks given the desired number
127 // of breaks n such that min <= result <= max where max depends on the current 144 // of breaks n such that min <= result <= max where max depends on the current
128 // nesting level. 145 // nesting level.
129 // 146 //
130 func (p *printer) nlines(n, min int) int { 147 func (p *printer) nlines(n, min int) int {
131 if n < min { 148 if n < min {
132 return min 149 return min
(...skipping 90 matching lines...) Expand 10 before | Expand all | Expand 10 after
223 } 240 }
224 } 241 }
225 242
226 243
227 // writeItem writes data at position pos. data is the text corresponding to 244 // writeItem writes data at position pos. data is the text corresponding to
228 // a single lexical token, but may also be comment text. pos is the actual 245 // a single lexical token, but may also be comment text. pos is the actual
229 // (or at least very accurately estimated) position of the data in the original 246 // (or at least very accurately estimated) position of the data in the original
230 // source text. writeItem updates p.last to the position immediately following 247 // source text. writeItem updates p.last to the position immediately following
231 // the data. 248 // the data.
232 // 249 //
233 func (p *printer) writeItem(pos token.Position, data []byte) { 250 func (p *printer) writeItem(pos token.Position, data string) {
234 if pos.IsValid() { 251 if pos.IsValid() {
235 // continue with previous position if we don't have a valid pos 252 // continue with previous position if we don't have a valid pos
236 if p.last.IsValid() && p.last.Filename != pos.Filename { 253 if p.last.IsValid() && p.last.Filename != pos.Filename {
237 // the file has changed - reset state 254 // the file has changed - reset state
238 // (used when printing merged ASTs of different files 255 // (used when printing merged ASTs of different files
239 // e.g., the result of ast.MergePackageFiles) 256 // e.g., the result of ast.MergePackageFiles)
240 p.indent = 0 257 p.indent = 0
241 p.mode = 0 258 p.mode = 0
242 » » » p.buffer = p.buffer[0:0] 259 » » » p.wsbuf = p.wsbuf[0:0]
243 } 260 }
244 p.pos = pos 261 p.pos = pos
245 } 262 }
246 if debug { 263 if debug {
247 // do not update p.pos - use write0 264 // do not update p.pos - use write0
248 _, filename := filepath.Split(pos.Filename) 265 _, filename := filepath.Split(pos.Filename)
249 p.write0([]byte(fmt.Sprintf("[%s:%d:%d]", filename, pos.Line, po s.Column))) 266 p.write0([]byte(fmt.Sprintf("[%s:%d:%d]", filename, pos.Line, po s.Column)))
250 } 267 }
251 » p.write(data) 268 » p.write([]byte(data))
252 p.last = p.pos 269 p.last = p.pos
253 } 270 }
254 271
255 272
256 // writeCommentPrefix writes the whitespace before a comment. 273 // writeCommentPrefix writes the whitespace before a comment.
257 // If there is any pending whitespace, it consumes as much of 274 // If there is any pending whitespace, it consumes as much of
258 // it as is likely to help position the comment nicely. 275 // it as is likely to help position the comment nicely.
259 // pos is the comment position, next the position of the item 276 // pos is the comment position, next the position of the item
260 // after all pending comments, prev is the previous comment in 277 // after all pending comments, prev is the previous comment in
261 // a group of comments (or nil), and isKeyword indicates if the 278 // a group of comments (or nil), and isKeyword indicates if the
(...skipping 11 matching lines...) Expand all
273 return 290 return
274 } 291 }
275 292
276 if pos.Line == p.last.Line && (prev == nil || prev.Text[1] != '/') { 293 if pos.Line == p.last.Line && (prev == nil || prev.Text[1] != '/') {
277 // comment on the same line as last item: 294 // comment on the same line as last item:
278 // separate with at least one separator 295 // separate with at least one separator
279 hasSep := false 296 hasSep := false
280 if prev == nil { 297 if prev == nil {
281 // first comment of a comment group 298 // first comment of a comment group
282 j := 0 299 j := 0
283 » » » for i, ch := range p.buffer { 300 » » » for i, ch := range p.wsbuf {
284 switch ch { 301 switch ch {
285 case blank: 302 case blank:
286 // ignore any blanks before a comment 303 // ignore any blanks before a comment
287 » » » » » p.buffer[i] = ignore 304 » » » » » p.wsbuf[i] = ignore
288 continue 305 continue
289 case vtab: 306 case vtab:
290 // respect existing tabs - important 307 // respect existing tabs - important
291 // for proper formatting of commented st ructs 308 // for proper formatting of commented st ructs
292 hasSep = true 309 hasSep = true
293 continue 310 continue
294 case indent: 311 case indent:
295 // apply pending indentation 312 // apply pending indentation
296 continue 313 continue
297 } 314 }
(...skipping 13 matching lines...) Expand all
311 p.write(htab) 328 p.write(htab)
312 } 329 }
313 } 330 }
314 331
315 } else { 332 } else {
316 // comment on a different line: 333 // comment on a different line:
317 // separate with at least one line break 334 // separate with at least one line break
318 if prev == nil { 335 if prev == nil {
319 // first comment of a comment group 336 // first comment of a comment group
320 j := 0 337 j := 0
321 » » » for i, ch := range p.buffer { 338 » » » for i, ch := range p.wsbuf {
322 switch ch { 339 switch ch {
323 case blank, vtab: 340 case blank, vtab:
324 // ignore any horizontal whitespace befo re line breaks 341 // ignore any horizontal whitespace befo re line breaks
325 » » » » » p.buffer[i] = ignore 342 » » » » » p.wsbuf[i] = ignore
326 continue 343 continue
327 case indent: 344 case indent:
328 // apply pending indentation 345 // apply pending indentation
329 continue 346 continue
330 case unindent: 347 case unindent:
331 // if the next token is a keyword, apply the outdent 348 // if the next token is a keyword, apply the outdent
332 // if it appears that the comment is ali gned with the 349 // if it appears that the comment is ali gned with the
333 // keyword; otherwise assume the outdent is part of a 350 // keyword; otherwise assume the outdent is part of a
334 // closing block and stop (this scenario appears with 351 // closing block and stop (this scenario appears with
335 // comments before a case label where th e comments 352 // comments before a case label where th e comments
336 // apply to the next case instead of the current one) 353 // apply to the next case instead of the current one)
337 if isKeyword && pos.Column == next.Colum n { 354 if isKeyword && pos.Column == next.Colum n {
338 continue 355 continue
339 } 356 }
340 case newline, formfeed: 357 case newline, formfeed:
341 // TODO(gri): may want to keep formfeed info in some cases 358 // TODO(gri): may want to keep formfeed info in some cases
342 » » » » » p.buffer[i] = ignore 359 » » » » » p.wsbuf[i] = ignore
343 } 360 }
344 j = i 361 j = i
345 break 362 break
346 } 363 }
347 p.writeWhitespace(j) 364 p.writeWhitespace(j)
348 } 365 }
349 // use formfeeds to break columns before a comment; 366 // use formfeeds to break columns before a comment;
350 // this is analogous to using formfeeds to separate 367 // this is analogous to using formfeeds to separate
351 // individual lines of /*-style comments - but make 368 // individual lines of /*-style comments - but make
352 // sure there is at least one line break if the previous 369 // sure there is at least one line break if the previous
353 // comment was a line comment 370 // comment was a line comment
354 n := pos.Line - p.last.Line // if !pos.IsValid(), pos.Line == 0, and n will be 0 371 n := pos.Line - p.last.Line // if !pos.IsValid(), pos.Line == 0, and n will be 0
355 if n <= 0 && prev != nil && prev.Text[1] == '/' { 372 if n <= 0 && prev != nil && prev.Text[1] == '/' {
356 n = 1 373 n = 1
357 } 374 }
358 p.writeNewlines(n, true) 375 p.writeNewlines(n, true)
359 } 376 }
360 } 377 }
361 378
362 379
363 func (p *printer) writeCommentLine(comment *ast.Comment, pos token.Position, lin e []byte) { 380 // TODO(gri): It should be possible to convert the code below from using
364 » // line must pass through unchanged, bracket it with tabwriter.Escape 381 // []byte to string and in the process eliminate some conversions.
365 » line = bytes.Join([][]byte{esc, line, esc}, nil)
366 » p.writeItem(pos, line)
367 }
368
369 382
370 // Split comment text into lines 383 // Split comment text into lines
371 func split(text []byte) [][]byte { 384 func split(text []byte) [][]byte {
372 // count lines (comment text never ends in a newline) 385 // count lines (comment text never ends in a newline)
373 n := 1 386 n := 1
374 for _, c := range text { 387 for _, c := range text {
375 if c == '\n' { 388 if c == '\n' {
376 n++ 389 n++
377 } 390 }
378 } 391 }
(...skipping 156 matching lines...) Expand 10 before | Expand all | Expand 10 after
535 // Remove the common prefix from all but the first and empty lines. 548 // Remove the common prefix from all but the first and empty lines.
536 for i, line := range lines[1:] { 549 for i, line := range lines[1:] {
537 if len(line) != 0 { 550 if len(line) != 0 {
538 lines[1+i] = line[len(prefix):] // range starts at line 1 551 lines[1+i] = line[len(prefix):] // range starts at line 1
539 } 552 }
540 } 553 }
541 } 554 }
542 555
543 556
544 func (p *printer) writeComment(comment *ast.Comment) { 557 func (p *printer) writeComment(comment *ast.Comment) {
545 » text := []byte(comment.Text) 558 » text := comment.Text
546 559
547 // shortcut common case of //-style comments 560 // shortcut common case of //-style comments
548 if text[1] == '/' { 561 if text[1] == '/' {
549 » » p.writeCommentLine(comment, p.fset.Position(comment.Pos()), text ) 562 » » p.writeItem(p.fset.Position(comment.Pos()), p.escape(text))
550 return 563 return
551 } 564 }
552 565
553 // for /*-style comments, print line by line and let the 566 // for /*-style comments, print line by line and let the
554 // write function take care of the proper indentation 567 // write function take care of the proper indentation
555 » lines := split(text) 568 » lines := split([]byte(text))
556 stripCommonPrefix(lines) 569 stripCommonPrefix(lines)
557 570
558 // write comment lines, separated by formfeed, 571 // write comment lines, separated by formfeed,
559 // without a line break after the last line 572 // without a line break after the last line
560 linebreak := formfeeds[0:1] 573 linebreak := formfeeds[0:1]
561 pos := p.fset.Position(comment.Pos()) 574 pos := p.fset.Position(comment.Pos())
562 for i, line := range lines { 575 for i, line := range lines {
563 if i > 0 { 576 if i > 0 {
564 p.write(linebreak) 577 p.write(linebreak)
565 pos = p.pos 578 pos = p.pos
566 } 579 }
567 if len(line) > 0 { 580 if len(line) > 0 {
568 » » » p.writeCommentLine(comment, pos, line) 581 » » » p.writeItem(pos, p.escape(string(line)))
569 } 582 }
570 } 583 }
571 } 584 }
572 585
573 586
574 // writeCommentSuffix writes a line break after a comment if indicated 587 // writeCommentSuffix writes a line break after a comment if indicated
575 // and processes any leftover indentation information. If a line break 588 // and processes any leftover indentation information. If a line break
576 // is needed, the kind of break (newline vs formfeed) depends on the 589 // is needed, the kind of break (newline vs formfeed) depends on the
577 // pending whitespace. writeCommentSuffix returns true if a pending 590 // pending whitespace. writeCommentSuffix returns true if a pending
578 // formfeed was dropped from the whitespace buffer. 591 // formfeed was dropped from the whitespace buffer.
579 // 592 //
580 func (p *printer) writeCommentSuffix(needsLinebreak bool) (droppedFF bool) { 593 func (p *printer) writeCommentSuffix(needsLinebreak bool) (droppedFF bool) {
581 » for i, ch := range p.buffer { 594 » for i, ch := range p.wsbuf {
582 switch ch { 595 switch ch {
583 case blank, vtab: 596 case blank, vtab:
584 // ignore trailing whitespace 597 // ignore trailing whitespace
585 » » » p.buffer[i] = ignore 598 » » » p.wsbuf[i] = ignore
586 case indent, unindent: 599 case indent, unindent:
587 // don't loose indentation information 600 // don't loose indentation information
588 case newline, formfeed: 601 case newline, formfeed:
589 // if we need a line break, keep exactly one 602 // if we need a line break, keep exactly one
590 // but remember if we dropped any formfeeds 603 // but remember if we dropped any formfeeds
591 if needsLinebreak { 604 if needsLinebreak {
592 needsLinebreak = false 605 needsLinebreak = false
593 } else { 606 } else {
594 if ch == formfeed { 607 if ch == formfeed {
595 droppedFF = true 608 droppedFF = true
596 } 609 }
597 » » » » p.buffer[i] = ignore 610 » » » » p.wsbuf[i] = ignore
598 » » » } 611 » » » }
599 » » } 612 » » }
600 » } 613 » }
601 » p.writeWhitespace(len(p.buffer)) 614 » p.writeWhitespace(len(p.wsbuf))
602 615
603 // make sure we have a line break 616 // make sure we have a line break
604 if needsLinebreak { 617 if needsLinebreak {
605 p.write([]byte{'\n'}) 618 p.write([]byte{'\n'})
606 } 619 }
607 620
608 return 621 return
609 } 622 }
610 623
611 624
(...skipping 33 matching lines...) Expand 10 before | Expand all | Expand 10 after
645 p.internalError("intersperseComments called without pending comments") 658 p.internalError("intersperseComments called without pending comments")
646 return false 659 return false
647 } 660 }
648 661
649 662
650 // whiteWhitespace writes the first n whitespace entries. 663 // whiteWhitespace writes the first n whitespace entries.
651 func (p *printer) writeWhitespace(n int) { 664 func (p *printer) writeWhitespace(n int) {
652 // write entries 665 // write entries
653 var data [1]byte 666 var data [1]byte
654 for i := 0; i < n; i++ { 667 for i := 0; i < n; i++ {
655 » » switch ch := p.buffer[i]; ch { 668 » » switch ch := p.wsbuf[i]; ch {
656 case ignore: 669 case ignore:
657 // ignore! 670 // ignore!
658 case indent: 671 case indent:
659 p.indent++ 672 p.indent++
660 case unindent: 673 case unindent:
661 p.indent-- 674 p.indent--
662 if p.indent < 0 { 675 if p.indent < 0 {
663 p.internalError("negative indentation:", p.inden t) 676 p.internalError("negative indentation:", p.inden t)
664 p.indent = 0 677 p.indent = 0
665 } 678 }
666 case newline, formfeed: 679 case newline, formfeed:
667 // A line break immediately followed by a "correcting" 680 // A line break immediately followed by a "correcting"
668 // unindent is swapped with the unindent - this permits 681 // unindent is swapped with the unindent - this permits
669 // proper label positioning. If a comment is between 682 // proper label positioning. If a comment is between
670 // the line break and the label, the unindent is not 683 // the line break and the label, the unindent is not
671 // part of the comment whitespace prefix and the comment 684 // part of the comment whitespace prefix and the comment
672 // will be positioned correctly indented. 685 // will be positioned correctly indented.
673 » » » if i+1 < n && p.buffer[i+1] == unindent { 686 » » » if i+1 < n && p.wsbuf[i+1] == unindent {
674 // Use a formfeed to terminate the current secti on. 687 // Use a formfeed to terminate the current secti on.
675 // Otherwise, a long label name on the next line leading 688 // Otherwise, a long label name on the next line leading
676 // to a wide column may increase the indentation column 689 // to a wide column may increase the indentation column
677 // of lines before the label; effectively leadin g to wrong 690 // of lines before the label; effectively leadin g to wrong
678 // indentation. 691 // indentation.
679 » » » » p.buffer[i], p.buffer[i+1] = unindent, formfeed 692 » » » » p.wsbuf[i], p.wsbuf[i+1] = unindent, formfeed
680 i-- // do it again 693 i-- // do it again
681 continue 694 continue
682 } 695 }
683 fallthrough 696 fallthrough
684 default: 697 default:
685 data[0] = byte(ch) 698 data[0] = byte(ch)
686 p.write(data[0:]) 699 p.write(data[0:])
687 } 700 }
688 } 701 }
689 702
690 // shift remaining entries down 703 // shift remaining entries down
691 i := 0 704 i := 0
692 » for ; n < len(p.buffer); n++ { 705 » for ; n < len(p.wsbuf); n++ {
693 » » p.buffer[i] = p.buffer[n] 706 » » p.wsbuf[i] = p.wsbuf[n]
694 i++ 707 i++
695 } 708 }
696 » p.buffer = p.buffer[0:i] 709 » p.wsbuf = p.wsbuf[0:i]
697 } 710 }
698 711
699 712
700 // ---------------------------------------------------------------------------- 713 // ----------------------------------------------------------------------------
701 // Printing interface 714 // Printing interface
702 715
703 716
704 func mayCombine(prev token.Token, next byte) (b bool) { 717 func mayCombine(prev token.Token, next byte) (b bool) {
705 switch prev { 718 switch prev {
706 case token.INT: 719 case token.INT:
(...skipping 20 matching lines...) Expand all
727 // 740 //
728 // Whitespace is accumulated until a non-whitespace token appears. Any 741 // Whitespace is accumulated until a non-whitespace token appears. Any
729 // comments that need to appear before that token are printed first, 742 // comments that need to appear before that token are printed first,
730 // taking into account the amount and structure of any pending white- 743 // taking into account the amount and structure of any pending white-
731 // space for best comment placement. Then, any leftover whitespace is 744 // space for best comment placement. Then, any leftover whitespace is
732 // printed, followed by the actual token. 745 // printed, followed by the actual token.
733 // 746 //
734 func (p *printer) print(args ...interface{}) { 747 func (p *printer) print(args ...interface{}) {
735 for _, f := range args { 748 for _, f := range args {
736 next := p.pos // estimated position of next item 749 next := p.pos // estimated position of next item
737 » » var data []byte 750 » » var data string
738 var tok token.Token 751 var tok token.Token
739 752
740 switch x := f.(type) { 753 switch x := f.(type) {
741 case pmode: 754 case pmode:
742 // toggle printer mode 755 // toggle printer mode
743 p.mode ^= x 756 p.mode ^= x
744 case whiteSpace: 757 case whiteSpace:
745 if x == ignore { 758 if x == ignore {
746 // don't add ignore's to the buffer; they 759 // don't add ignore's to the buffer; they
747 // may screw up "correcting" unindents (see 760 // may screw up "correcting" unindents (see
748 // LabeledStmt) 761 // LabeledStmt)
749 break 762 break
750 } 763 }
751 » » » i := len(p.buffer) 764 » » » i := len(p.wsbuf)
752 » » » if i == cap(p.buffer) { 765 » » » if i == cap(p.wsbuf) {
753 // Whitespace sequences are very short so this s hould 766 // Whitespace sequences are very short so this s hould
754 // never happen. Handle gracefully (but possibly with 767 // never happen. Handle gracefully (but possibly with
755 // bad comment placement) if it does happen. 768 // bad comment placement) if it does happen.
756 p.writeWhitespace(i) 769 p.writeWhitespace(i)
757 i = 0 770 i = 0
758 } 771 }
759 » » » p.buffer = p.buffer[0 : i+1] 772 » » » p.wsbuf = p.wsbuf[0 : i+1]
760 » » » p.buffer[i] = x 773 » » » p.wsbuf[i] = x
761 case *ast.Ident: 774 case *ast.Ident:
762 » » » data = []byte(x.Name) 775 » » » data = x.Name
763 tok = token.IDENT 776 tok = token.IDENT
764 case *ast.BasicLit: 777 case *ast.BasicLit:
765 // escape all literals so they pass through unchanged
766 // (note that valid Go programs cannot contain
767 // tabwriter.Escape bytes since they do not appear in
768 // legal UTF-8 sequences)
769 data = make([]byte, 0, len(x.Value)+2)
770 data = append(data, tabwriter.Escape)
771 data = append(data, []byte(x.Value)...)
772 data = append(data, tabwriter.Escape)
773 tok = x.Kind
774 // If we have a raw string that spans multiple lines and 778 // If we have a raw string that spans multiple lines and
775 // the opening quote (`) is on a line preceded only by 779 // the opening quote (`) is on a line preceded only by
776 // indentation, we don't want to write that indentation 780 // indentation, we don't want to write that indentation
777 // because the following lines of the raw string are not 781 // because the following lines of the raw string are not
778 // indented. It's easiest to correct the output at the e nd 782 // indented. It's easiest to correct the output at the e nd
779 // via the trimmer (because of the complex handling of 783 // via the trimmer (because of the complex handling of
780 // white space). 784 // white space).
781 // Mark multi-line raw strings by replacing the opening 785 // Mark multi-line raw strings by replacing the opening
782 // quote with esc2 and have the trimmer take care of fix ing 786 // quote with esc2 and have the trimmer take care of fix ing
783 » » » // it up. (Do this _after_ making a copy of data!) 787 » » » // it up.
784 » » » if data[1] == '`' && bytes.IndexByte(data, '\n') > 0 { 788 » » » if x.Value[0] == '`' && strings.Index(x.Value, "\n") > 0 {
785 » » » » data[1] = esc2 789 » » » » data = p.escape(esc2str + x.Value[1:])
786 » » » } 790 » » » } else {
791 » » » » data = p.escape(x.Value)
792 » » » }
793 » » » tok = x.Kind
787 case token.Token: 794 case token.Token:
788 s := x.String() 795 s := x.String()
789 if mayCombine(p.lastTok, s[0]) { 796 if mayCombine(p.lastTok, s[0]) {
790 // the previous and the current token must be 797 // the previous and the current token must be
791 // separated by a blank otherwise they combine 798 // separated by a blank otherwise they combine
792 // into a different incorrect token sequence 799 // into a different incorrect token sequence
793 // (except for token.INT followed by a '.' this 800 // (except for token.INT followed by a '.' this
794 // should never happen because it is taken care 801 // should never happen because it is taken care
795 // of via binary expression formatting) 802 // of via binary expression formatting)
796 » » » » if len(p.buffer) != 0 { 803 » » » » if len(p.wsbuf) != 0 {
797 p.internalError("whitespace buffer not e mpty") 804 p.internalError("whitespace buffer not e mpty")
798 } 805 }
799 » » » » p.buffer = p.buffer[0:1] 806 » » » » p.wsbuf = p.wsbuf[0:1]
800 » » » » p.buffer[0] = ' ' 807 » » » » p.wsbuf[0] = ' '
801 » » » } 808 » » » }
802 » » » data = []byte(s) 809 » » » data = s
803 tok = x 810 tok = x
804 case token.Pos: 811 case token.Pos:
805 if x.IsValid() { 812 if x.IsValid() {
806 next = p.fset.Position(x) // accurate position o f next item 813 next = p.fset.Position(x) // accurate position o f next item
807 } 814 }
808 tok = p.lastTok 815 tok = p.lastTok
809 default: 816 default:
810 fmt.Fprintf(os.Stderr, "print: unsupported argument type %T\n", f) 817 fmt.Fprintf(os.Stderr, "print: unsupported argument type %T\n", f)
811 panic("go/printer type") 818 panic("go/printer type")
812 } 819 }
813 p.lastTok = tok 820 p.lastTok = tok
814 p.pos = next 821 p.pos = next
815 822
816 » » if data != nil { 823 » » if data != "" {
817 droppedFF := p.flush(next, tok) 824 droppedFF := p.flush(next, tok)
818 825
819 // intersperse extra newlines if present in the source 826 // intersperse extra newlines if present in the source
820 // (don't do this in flush as it will cause extra newlin es 827 // (don't do this in flush as it will cause extra newlin es
821 // at the end of a file) - use formfeeds if we dropped o ne 828 // at the end of a file) - use formfeeds if we dropped o ne
822 // before 829 // before
823 p.writeNewlines(next.Line-p.pos.Line, droppedFF) 830 p.writeNewlines(next.Line-p.pos.Line, droppedFF)
824 831
825 p.writeItem(next, data) 832 p.writeItem(next, data)
826 } 833 }
(...skipping 14 matching lines...) Expand all
841 // returns true if a pending formfeed character was dropped 848 // returns true if a pending formfeed character was dropped
842 // from the whitespace buffer as a result of interspersing 849 // from the whitespace buffer as a result of interspersing
843 // comments. 850 // comments.
844 // 851 //
845 func (p *printer) flush(next token.Position, tok token.Token) (droppedFF bool) { 852 func (p *printer) flush(next token.Position, tok token.Token) (droppedFF bool) {
846 if p.commentBefore(next) { 853 if p.commentBefore(next) {
847 // if there are comments before the next item, intersperse them 854 // if there are comments before the next item, intersperse them
848 droppedFF = p.intersperseComments(next, tok) 855 droppedFF = p.intersperseComments(next, tok)
849 } else { 856 } else {
850 // otherwise, write any leftover whitespace 857 // otherwise, write any leftover whitespace
851 » » p.writeWhitespace(len(p.buffer)) 858 » » p.writeWhitespace(len(p.wsbuf))
852 } 859 }
853 return 860 return
854 } 861 }
855 862
856 863
857 // ---------------------------------------------------------------------------- 864 // ----------------------------------------------------------------------------
858 // Trimmer 865 // Trimmer
859 866
860 // A trimmer is an io.Writer filter for stripping tabwriter.Escape 867 // A trimmer is an io.Writer filter for stripping tabwriter.Escape
861 // characters, trailing blanks and tabs, and for converting formfeed 868 // characters, trailing blanks and tabs, and for converting formfeed
(...skipping 221 matching lines...) Expand 10 before | Expand all | Expand 10 after
1083 } 1090 }
1084 1091
1085 1092
1086 // Fprint "pretty-prints" an AST node to output. 1093 // Fprint "pretty-prints" an AST node to output.
1087 // It calls Config.Fprint with default settings. 1094 // It calls Config.Fprint with default settings.
1088 // 1095 //
1089 func Fprint(output io.Writer, fset *token.FileSet, node interface{}) os.Error { 1096 func Fprint(output io.Writer, fset *token.FileSet, node interface{}) os.Error {
1090 _, err := (&Config{Tabwidth: 8}).Fprint(output, fset, node) // don't car e about number of bytes written 1097 _, err := (&Config{Tabwidth: 8}).Fprint(output, fset, node) // don't car e about number of bytes written
1091 return err 1098 return err
1092 } 1099 }
LEFTRIGHT

Powered by Google App Engine
RSS Feeds Recent Issues | This issue
This is Rietveld f62528b