~ubuntu-branches/ubuntu/utopic/golang/utopic

« back to all changes in this revision

Viewing changes to src/pkg/go/printer/printer.go

  • Committer: Package Import Robot
  • Author(s): James Page
  • Date: 2013-08-20 14:06:23 UTC
  • mfrom: (14.1.23 saucy-proposed)
  • Revision ID: package-import@ubuntu.com-20130820140623-b414jfxi3m0qkmrq
Tags: 2:1.1.2-2ubuntu1
* Merge from Debian unstable (LP: #1211749, #1202027). Remaining changes:
  - 016-armhf-elf-header.patch: Use correct ELF header for armhf binaries.
  - d/control,control.cross: Update Breaks/Replaces for Ubuntu
    versions to ensure smooth upgrades, regenerate control file.

Show diffs side-by-side

added added

removed removed

Lines of Context:
14
14
        "strconv"
15
15
        "strings"
16
16
        "text/tabwriter"
 
17
        "unicode"
17
18
)
18
19
 
19
20
const (
164
165
        // write indentation
165
166
        // use "hard" htabs - indentation columns
166
167
        // must not be discarded by the tabwriter
167
 
        for i := 0; i < p.indent; i++ {
 
168
        n := p.Config.Indent + p.indent // include base indentation
 
169
        for i := 0; i < n; i++ {
168
170
                p.output = append(p.output, '\t')
169
171
        }
170
172
 
171
173
        // update positions
172
 
        i := p.indent
173
 
        p.pos.Offset += i
174
 
        p.pos.Column += i
175
 
        p.out.Column += i
 
174
        p.pos.Offset += n
 
175
        p.pos.Column += n
 
176
        p.out.Column += n
176
177
}
177
178
 
178
179
// writeByte writes ch n times to p.output and updates p.pos.
220
221
                // atLineBegin updates p.pos if there's indentation, but p.pos
221
222
                // is the position of s.
222
223
                p.pos = pos
223
 
                // reset state if the file changed
224
 
                // (used when printing merged ASTs of different files
225
 
                // e.g., the result of ast.MergePackageFiles)
226
 
                if p.last.IsValid() && p.last.Filename != pos.Filename {
227
 
                        p.indent = 0
228
 
                        p.mode = 0
229
 
                        p.wsbuf = p.wsbuf[0:0]
230
 
                }
231
224
        }
232
225
 
233
226
        if isLit {
402
395
        }
403
396
}
404
397
 
405
 
// Split comment text into lines
406
 
// (using strings.Split(text, "\n") is significantly slower for
407
 
// this specific purpose, as measured with: go test -bench=Print)
408
 
func split(text string) []string {
409
 
        // count lines (comment text never ends in a newline)
410
 
        n := 1
411
 
        for i := 0; i < len(text); i++ {
412
 
                if text[i] == '\n' {
413
 
                        n++
414
 
                }
415
 
        }
416
 
 
417
 
        // split
418
 
        lines := make([]string, n)
419
 
        n = 0
420
 
        i := 0
421
 
        for j := 0; j < len(text); j++ {
422
 
                if text[j] == '\n' {
423
 
                        lines[n] = text[i:j] // exclude newline
424
 
                        i = j + 1            // discard newline
425
 
                        n++
426
 
                }
427
 
        }
428
 
        lines[n] = text[i:]
429
 
 
430
 
        return lines
431
 
}
432
 
 
433
398
// Returns true if s contains only white space
434
399
// (only tabs and blanks can appear in the printer's context).
 
400
//
435
401
func isBlank(s string) bool {
436
402
        for i := 0; i < len(s); i++ {
437
403
                if s[i] > ' ' {
441
407
        return true
442
408
}
443
409
 
 
410
// commonPrefix returns the common prefix of a and b.
444
411
func commonPrefix(a, b string) string {
445
412
        i := 0
446
413
        for i < len(a) && i < len(b) && a[i] == b[i] && (a[i] <= ' ' || a[i] == '*') {
449
416
        return a[0:i]
450
417
}
451
418
 
 
419
// trimRight returns s with trailing whitespace removed.
 
420
func trimRight(s string) string {
 
421
        return strings.TrimRightFunc(s, unicode.IsSpace)
 
422
}
 
423
 
 
424
// stripCommonPrefix removes a common prefix from /*-style comment lines (unless no
 
425
// comment line is indented, all but the first line have some form of space prefix).
 
426
// The prefix is computed using heuristics such that is likely that the comment
 
427
// contents are nicely laid out after re-printing each line using the printer's
 
428
// current indentation.
 
429
//
452
430
func stripCommonPrefix(lines []string) {
453
 
        if len(lines) < 2 {
 
431
        if len(lines) <= 1 {
454
432
                return // at most one line - nothing to do
455
433
        }
456
 
        // len(lines) >= 2
 
434
        // len(lines) > 1
457
435
 
458
436
        // The heuristic in this function tries to handle a few
459
437
        // common patterns of /*-style comments: Comments where
479
457
                for i, line := range lines[1 : len(lines)-1] {
480
458
                        switch {
481
459
                        case isBlank(line):
482
 
                                lines[1+i] = "" // range starts at line 1
 
460
                                lines[1+i] = "" // range starts with lines[1]
483
461
                        case first:
484
462
                                prefix = commonPrefix(line, line)
485
463
                                first = false
544
522
                        }
545
523
                        // Shorten the computed common prefix by the length of
546
524
                        // suffix, if it is found as suffix of the prefix.
547
 
                        if strings.HasSuffix(prefix, string(suffix)) {
548
 
                                prefix = prefix[0 : len(prefix)-len(suffix)]
549
 
                        }
 
525
                        prefix = strings.TrimSuffix(prefix, string(suffix))
550
526
                }
551
527
        }
552
528
 
570
546
        }
571
547
 
572
548
        // Remove the common prefix from all but the first and empty lines.
573
 
        for i, line := range lines[1:] {
574
 
                if len(line) != 0 {
575
 
                        lines[1+i] = line[len(prefix):] // range starts at line 1
 
549
        for i, line := range lines {
 
550
                if i > 0 && line != "" {
 
551
                        lines[i] = line[len(prefix):]
576
552
                }
577
553
        }
578
554
}
605
581
 
606
582
        // shortcut common case of //-style comments
607
583
        if text[1] == '/' {
608
 
                p.writeString(pos, text, true)
 
584
                p.writeString(pos, trimRight(text), true)
609
585
                return
610
586
        }
611
587
 
612
588
        // for /*-style comments, print line by line and let the
613
589
        // write function take care of the proper indentation
614
 
        lines := split(text)
 
590
        lines := strings.Split(text, "\n")
 
591
 
 
592
        // The comment started in the first column but is going
 
593
        // to be indented. For an idempotent result, add indentation
 
594
        // to all lines such that they look like they were indented
 
595
        // before - this will make sure the common prefix computation
 
596
        // is the same independent of how many times formatting is
 
597
        // applied (was issue 1835).
 
598
        if pos.IsValid() && pos.Column == 1 && p.indent > 0 {
 
599
                for i, line := range lines[1:] {
 
600
                        lines[1+i] = "   " + line
 
601
                }
 
602
        }
 
603
 
615
604
        stripCommonPrefix(lines)
616
605
 
617
606
        // write comment lines, separated by formfeed,
622
611
                        pos = p.pos
623
612
                }
624
613
                if len(line) > 0 {
625
 
                        p.writeString(pos, line, true)
 
614
                        p.writeString(pos, trimRight(line), true)
626
615
                }
627
616
        }
628
617
}
1012
1001
        case ast.Expr:
1013
1002
                p.expr(n)
1014
1003
        case ast.Stmt:
1015
 
                // A labeled statement will un-indent to position the
1016
 
                // label. Set indent to 1 so we don't get indent "underflow".
1017
 
                if _, labeledStmt := n.(*ast.LabeledStmt); labeledStmt {
 
1004
                // A labeled statement will un-indent to position the label.
 
1005
                // Set p.indent to 1 so we don't get indent "underflow".
 
1006
                if _, ok := n.(*ast.LabeledStmt); ok {
1018
1007
                        p.indent = 1
1019
1008
                }
1020
1009
                p.stmt(n, false)
1022
1011
                p.decl(n)
1023
1012
        case ast.Spec:
1024
1013
                p.spec(n, 1, false)
 
1014
        case []ast.Stmt:
 
1015
                // A labeled statement will un-indent to position the label.
 
1016
                // Set p.indent to 1 so we don't get indent "underflow".
 
1017
                for _, s := range n {
 
1018
                        if _, ok := s.(*ast.LabeledStmt); ok {
 
1019
                                p.indent = 1
 
1020
                        }
 
1021
                }
 
1022
                p.stmtList(n, 0, false)
 
1023
        case []ast.Decl:
 
1024
                p.declList(n)
1025
1025
        case *ast.File:
1026
1026
                p.file(n)
1027
1027
        default:
1140
1140
// ----------------------------------------------------------------------------
1141
1141
// Public interface
1142
1142
 
1143
 
// A Mode value is a set of flags (or 0). They coontrol printing. 
 
1143
// A Mode value is a set of flags (or 0). They control printing.
1144
1144
type Mode uint
1145
1145
 
1146
1146
const (
1154
1154
type Config struct {
1155
1155
        Mode     Mode // default: 0
1156
1156
        Tabwidth int  // default: 8
 
1157
        Indent   int  // default: 0 (all code is indented at least by this much)
1157
1158
}
1158
1159
 
1159
1160
// fprint implements Fprint and takes a nodesSizes map for setting up the printer state.
1198
1199
        }
1199
1200
 
1200
1201
        // flush tabwriter, if any
1201
 
        if tw, _ := (output).(*tabwriter.Writer); tw != nil {
 
1202
        if tw, _ := output.(*tabwriter.Writer); tw != nil {
1202
1203
                err = tw.Flush()
1203
1204
        }
1204
1205
 
1215
1216
 
1216
1217
// Fprint "pretty-prints" an AST node to output for a given configuration cfg.
1217
1218
// Position information is interpreted relative to the file set fset.
1218
 
// The node type must be *ast.File, *CommentedNode, or assignment-compatible
1219
 
// to ast.Expr, ast.Decl, ast.Spec, or ast.Stmt.
 
1219
// The node type must be *ast.File, *CommentedNode, []ast.Decl, []ast.Stmt,
 
1220
// or assignment-compatible to ast.Expr, ast.Decl, ast.Spec, or ast.Stmt.
1220
1221
//
1221
1222
func (cfg *Config) Fprint(output io.Writer, fset *token.FileSet, node interface{}) error {
1222
1223
        return cfg.fprint(output, fset, node, make(map[ast.Node]int))