diff options
author | Ian Lance Taylor <ian@gcc.gnu.org> | 2012-10-23 04:31:11 +0000 |
---|---|---|
committer | Ian Lance Taylor <ian@gcc.gnu.org> | 2012-10-23 04:31:11 +0000 |
commit | 4ccad563d2a3559f0557bfb177bcf45144219bdf (patch) | |
tree | 46bb86f514fbf6bad82da48e69a18fb09d878834 /libgo/go/go/printer | |
parent | 0b7463235f0e23c624d1911c9b15f531108cc5a6 (diff) |
libgo: Update to current sources.
From-SVN: r192704
Diffstat (limited to 'libgo/go/go/printer')
-rw-r--r-- | libgo/go/go/printer/nodes.go | 45 | ||||
-rw-r--r-- | libgo/go/go/printer/printer.go | 33 | ||||
-rw-r--r-- | libgo/go/go/printer/printer_test.go | 150 | ||||
-rw-r--r-- | libgo/go/go/printer/testdata/comments2.golden | 79 | ||||
-rw-r--r-- | libgo/go/go/printer/testdata/comments2.input | 79 | ||||
-rw-r--r-- | libgo/go/go/printer/testdata/declarations.golden | 29 | ||||
-rw-r--r-- | libgo/go/go/printer/testdata/declarations.input | 29 | ||||
-rw-r--r-- | libgo/go/go/printer/testdata/expressions.golden | 15 | ||||
-rw-r--r-- | libgo/go/go/printer/testdata/expressions.input | 15 | ||||
-rw-r--r-- | libgo/go/go/printer/testdata/expressions.raw | 15 | ||||
-rw-r--r-- | libgo/go/go/printer/testdata/statements.golden | 26 | ||||
-rw-r--r-- | libgo/go/go/printer/testdata/statements.input | 24 |
12 files changed, 458 insertions, 81 deletions
diff --git a/libgo/go/go/printer/nodes.go b/libgo/go/go/printer/nodes.go index e346b93643b..e99a2e36d4f 100644 --- a/libgo/go/go/printer/nodes.go +++ b/libgo/go/go/printer/nodes.go @@ -203,7 +203,7 @@ func (p *printer) exprList(prev0 token.Pos, list []ast.Expr, depth int, mode exp } else { const r = 4 // threshold ratio := float64(size) / float64(prevSize) - useFF = ratio <= 1/r || r <= ratio + useFF = ratio <= 1.0/r || r <= ratio } } @@ -791,7 +791,14 @@ func (p *printer) expr1(expr ast.Expr, prec1, depth int) { if len(x.Args) > 1 { depth++ } - p.expr1(x.Fun, token.HighestPrec, depth) + if _, ok := x.Fun.(*ast.FuncType); ok { + // conversions to literal function types require parentheses around the type + p.print(token.LPAREN) + p.expr1(x.Fun, token.HighestPrec, depth) + p.print(token.RPAREN) + } else { + p.expr1(x.Fun, token.HighestPrec, depth) + } p.print(x.Lparen, token.LPAREN) if x.Ellipsis.IsValid() { p.exprList(x.Lparen, x.Args, depth, 0, x.Ellipsis) @@ -853,9 +860,9 @@ func (p *printer) expr1(expr ast.Expr, prec1, depth int) { case ast.SEND | ast.RECV: p.print(token.CHAN) case ast.RECV: - p.print(token.ARROW, token.CHAN) + p.print(token.ARROW, token.CHAN) // x.Arrow and x.Pos() are the same case ast.SEND: - p.print(token.CHAN, token.ARROW) + p.print(token.CHAN, x.Arrow, token.ARROW) } p.print(blank) p.expr(x.Value) @@ -882,28 +889,32 @@ func (p *printer) expr(x ast.Expr) { // Print the statement list indented, but without a newline after the last statement. // Extra line breaks between statements in the source are respected but at most one // empty line is printed between statements. -func (p *printer) stmtList(list []ast.Stmt, _indent int, nextIsRBrace bool) { - // TODO(gri): fix _indent code - if _indent > 0 { +func (p *printer) stmtList(list []ast.Stmt, nindent int, nextIsRBrace bool) { + if nindent > 0 { p.print(indent) } multiLine := false - for i, s := range list { - // _indent == 0 only for lists of switch/select case clauses; - // in those cases each clause is a new section - p.linebreak(p.lineFor(s.Pos()), 1, ignore, i == 0 || _indent == 0 || multiLine) - p.stmt(s, nextIsRBrace && i == len(list)-1) - multiLine = p.isMultiLine(s) - } - if _indent > 0 { + i := 0 + for _, s := range list { + // ignore empty statements (was issue 3466) + if _, isEmpty := s.(*ast.EmptyStmt); !isEmpty { + // _indent == 0 only for lists of switch/select case clauses; + // in those cases each clause is a new section + p.linebreak(p.lineFor(s.Pos()), 1, ignore, i == 0 || nindent == 0 || multiLine) + p.stmt(s, nextIsRBrace && i == len(list)-1) + multiLine = p.isMultiLine(s) + i++ + } + } + if nindent > 0 { p.print(unindent) } } // block prints an *ast.BlockStmt; it always spans at least two lines. -func (p *printer) block(s *ast.BlockStmt, indent int) { +func (p *printer) block(s *ast.BlockStmt, nindent int) { p.print(s.Pos(), token.LBRACE) - p.stmtList(s.List, indent, true) + p.stmtList(s.List, nindent, true) p.linebreak(p.lineFor(s.Rbrace), 1, ignore, true) p.print(s.Rbrace, token.RBRACE) } diff --git a/libgo/go/go/printer/printer.go b/libgo/go/go/printer/printer.go index a027d32da89..516c37161c1 100644 --- a/libgo/go/go/printer/printer.go +++ b/libgo/go/go/printer/printer.go @@ -449,11 +449,17 @@ func commonPrefix(a, b string) string { return a[0:i] } +// stripCommonPrefix removes a common prefix from /*-style comment lines (unless no +// comment line is indented, all but the first line have some form of space prefix). +// The prefix is computed using heuristics such that is is likely that the comment +// contents are nicely laid out after re-printing each line using the printer's +// current indentation. +// func stripCommonPrefix(lines []string) { - if len(lines) < 2 { + if len(lines) <= 1 { return // at most one line - nothing to do } - // len(lines) >= 2 + // len(lines) > 1 // The heuristic in this function tries to handle a few // common patterns of /*-style comments: Comments where @@ -479,7 +485,7 @@ func stripCommonPrefix(lines []string) { for i, line := range lines[1 : len(lines)-1] { switch { case isBlank(line): - lines[1+i] = "" // range starts at line 1 + lines[1+i] = "" // range starts with lines[1] case first: prefix = commonPrefix(line, line) first = false @@ -570,9 +576,9 @@ func stripCommonPrefix(lines []string) { } // Remove the common prefix from all but the first and empty lines. - for i, line := range lines[1:] { - if len(line) != 0 { - lines[1+i] = line[len(prefix):] // range starts at line 1 + for i, line := range lines { + if i > 0 && line != "" { + lines[i] = line[len(prefix):] } } } @@ -612,6 +618,19 @@ func (p *printer) writeComment(comment *ast.Comment) { // for /*-style comments, print line by line and let the // write function take care of the proper indentation lines := split(text) + + // The comment started in the first column but is going + // to be indented. For an idempotent result, add indentation + // to all lines such that they look like they were indented + // before - this will make sure the common prefix computation + // is the same independent of how many times formatting is + // applied (was issue 1835). + if pos.IsValid() && pos.Column == 1 && p.indent > 0 { + for i, line := range lines[1:] { + lines[1+i] = " " + line + } + } + stripCommonPrefix(lines) // write comment lines, separated by formfeed, @@ -1140,7 +1159,7 @@ func (p *trimmer) Write(data []byte) (n int, err error) { // ---------------------------------------------------------------------------- // Public interface -// A Mode value is a set of flags (or 0). They coontrol printing. +// A Mode value is a set of flags (or 0). They control printing. type Mode uint const ( diff --git a/libgo/go/go/printer/printer_test.go b/libgo/go/go/printer/printer_test.go index ab9e9b2ec8c..36d1bf74d3f 100644 --- a/libgo/go/go/printer/printer_test.go +++ b/libgo/go/go/printer/printer_test.go @@ -6,7 +6,9 @@ package printer import ( "bytes" + "errors" "flag" + "fmt" "go/ast" "go/parser" "go/token" @@ -25,33 +27,28 @@ var update = flag.Bool("update", false, "update golden files") var fset = token.NewFileSet() -func lineString(text []byte, i int) string { - i0 := i - for i < len(text) && text[i] != '\n' { - i++ - } - return string(text[i0:i]) -} - type checkMode uint const ( export checkMode = 1 << iota rawFormat + idempotent ) -func runcheck(t *testing.T, source, golden string, mode checkMode) { - // parse source - prog, err := parser.ParseFile(fset, source, nil, parser.ParseComments) +// format parses src, prints the corresponding AST, verifies the resulting +// src is syntactically correct, and returns the resulting src or an error +// if any. +func format(src []byte, mode checkMode) ([]byte, error) { + // parse src + f, err := parser.ParseFile(fset, "", src, parser.ParseComments) if err != nil { - t.Error(err) - return + return nil, fmt.Errorf("parse: %s\n%s", err, src) } // filter exports if necessary if mode&export != 0 { - ast.FileExports(prog) // ignore result - prog.Comments = nil // don't print comments that are not in AST + ast.FileExports(f) // ignore result + f.Comments = nil // don't print comments that are not in AST } // determine printer configuration @@ -60,17 +57,72 @@ func runcheck(t *testing.T, source, golden string, mode checkMode) { cfg.Mode |= RawFormat } - // format source + // print AST var buf bytes.Buffer - if err := cfg.Fprint(&buf, fset, prog); err != nil { - t.Error(err) + if err := cfg.Fprint(&buf, fset, f); err != nil { + return nil, fmt.Errorf("print: %s", err) } - res := buf.Bytes() - // formatted source must be valid + // make sure formated output is syntactically correct + res := buf.Bytes() if _, err := parser.ParseFile(fset, "", res, 0); err != nil { + return nil, fmt.Errorf("re-parse: %s\n%s", err, buf.Bytes()) + } + + return res, nil +} + +// lineAt returns the line in text starting at offset offs. +func lineAt(text []byte, offs int) []byte { + i := offs + for i < len(text) && text[i] != '\n' { + i++ + } + return text[offs:i] +} + +// diff compares a and b. +func diff(aname, bname string, a, b []byte) error { + var buf bytes.Buffer // holding long error message + + // compare lengths + if len(a) != len(b) { + fmt.Fprintf(&buf, "\nlength changed: len(%s) = %d, len(%s) = %d", aname, len(a), bname, len(b)) + } + + // compare contents + line := 1 + offs := 1 + for i := 0; i < len(a) && i < len(b); i++ { + ch := a[i] + if ch != b[i] { + fmt.Fprintf(&buf, "\n%s:%d:%d: %s", aname, line, i-offs+1, lineAt(a, offs)) + fmt.Fprintf(&buf, "\n%s:%d:%d: %s", bname, line, i-offs+1, lineAt(b, offs)) + fmt.Fprintf(&buf, "\n\n") + break + } + if ch == '\n' { + line++ + offs = i + 1 + } + } + + if buf.Len() > 0 { + return errors.New(buf.String()) + } + return nil +} + +func runcheck(t *testing.T, source, golden string, mode checkMode) { + src, err := ioutil.ReadFile(source) + if err != nil { + t.Error(err) + return + } + + res, err := format(src, mode) + if err != nil { t.Error(err) - t.Logf("\n%s", res) return } @@ -89,23 +141,19 @@ func runcheck(t *testing.T, source, golden string, mode checkMode) { return } - // compare lengths - if len(res) != len(gld) { - t.Errorf("len = %d, expected %d (= len(%s))", len(res), len(gld), golden) + // formatted source and golden must be the same + if err := diff(source, golden, res, gld); err != nil { + t.Error(err) + return } - // compare contents - for i, line, offs := 0, 1, 0; i < len(res) && i < len(gld); i++ { - ch := res[i] - if ch != gld[i] { - t.Errorf("%s:%d:%d: %s", source, line, i-offs+1, lineString(res, offs)) - t.Errorf("%s:%d:%d: %s", golden, line, i-offs+1, lineString(gld, offs)) - t.Error() - return - } - if ch == '\n' { - line++ - offs = i + 1 + if mode&idempotent != 0 { + // formatting golden must be idempotent + // (This is very difficult to achieve in general and for now + // it is only checked for files explicitly marked as such.) + res, err = format(gld, mode) + if err := diff(golden, fmt.Sprintf("format(%s)", golden), gld, res); err != nil { + t.Errorf("golden is not idempotent: %s", err) } } } @@ -142,15 +190,16 @@ type entry struct { // Use go test -update to create/update the respective golden files. var data = []entry{ - {"empty.input", "empty.golden", 0}, + {"empty.input", "empty.golden", idempotent}, {"comments.input", "comments.golden", 0}, {"comments.input", "comments.x", export}, - {"linebreaks.input", "linebreaks.golden", 0}, - {"expressions.input", "expressions.golden", 0}, - {"expressions.input", "expressions.raw", rawFormat}, + {"comments2.input", "comments2.golden", idempotent}, + {"linebreaks.input", "linebreaks.golden", idempotent}, + {"expressions.input", "expressions.golden", idempotent}, + {"expressions.input", "expressions.raw", rawFormat | idempotent}, {"declarations.input", "declarations.golden", 0}, {"statements.input", "statements.golden", 0}, - {"slow.input", "slow.golden", 0}, + {"slow.input", "slow.golden", idempotent}, } func TestFiles(t *testing.T) { @@ -248,7 +297,7 @@ func testComment(t *testing.T, f *ast.File, srclen int, comment *ast.Comment) { } } -// Verify that the printer produces always produces a correct program +// Verify that the printer produces a correct program // even if the position information of comments introducing newlines // is incorrect. func TestBadComments(t *testing.T) { @@ -421,21 +470,8 @@ func TestX(t *testing.T) { package p func _() {} ` - // parse original - f, err := parser.ParseFile(fset, "src", src, parser.ParseComments) + _, err := format([]byte(src), 0) if err != nil { - t.Fatal(err) - } - - // pretty-print original - var buf bytes.Buffer - if err = (&Config{Mode: UseSpaces, Tabwidth: 8}).Fprint(&buf, fset, f); err != nil { - t.Fatal(err) - } - - // parse pretty printed original - if _, err := parser.ParseFile(fset, "", buf.Bytes(), 0); err != nil { - t.Fatalf("%s\n%s", err, buf.Bytes()) + t.Error(err) } - } diff --git a/libgo/go/go/printer/testdata/comments2.golden b/libgo/go/go/printer/testdata/comments2.golden new file mode 100644 index 00000000000..d3b50bf3e05 --- /dev/null +++ b/libgo/go/go/printer/testdata/comments2.golden @@ -0,0 +1,79 @@ +// Copyright 2012 The Go Authors. All rights reserved. +// Use of this source code is governed by a BSD-style +// license that can be found in the LICENSE file. + +// This is a package for testing comment placement by go/printer. +// +package main + +// Test cases for idempotent comment formatting (was issue 1835). +/* +c1a +*/ +/* + c1b +*/ +/* foo +c1c +*/ +/* foo + c1d +*/ +/* +c1e +foo */ +/* + c1f + foo */ + +func f() { + /* + c2a + */ + /* + c2b + */ + /* foo + c2c + */ + /* foo + c2d + */ + /* + c2e + foo */ + /* + c2f + foo */ +} + +func g() { + /* + c3a + */ + /* + c3b + */ + /* foo + c3c + */ + /* foo + c3d + */ + /* + c3e + foo */ + /* + c3f + foo */ +} + +// Test case taken literally from issue 1835. +func main() { + /* + prints test 5 times + */ + for i := 0; i < 5; i++ { + println("test") + } +} diff --git a/libgo/go/go/printer/testdata/comments2.input b/libgo/go/go/printer/testdata/comments2.input new file mode 100644 index 00000000000..6f8c85c94aa --- /dev/null +++ b/libgo/go/go/printer/testdata/comments2.input @@ -0,0 +1,79 @@ +// Copyright 2012 The Go Authors. All rights reserved. +// Use of this source code is governed by a BSD-style +// license that can be found in the LICENSE file. + +// This is a package for testing comment placement by go/printer. +// +package main + +// Test cases for idempotent comment formatting (was issue 1835). +/* +c1a +*/ +/* + c1b +*/ +/* foo +c1c +*/ +/* foo + c1d +*/ +/* +c1e +foo */ +/* + c1f + foo */ + +func f() { +/* +c2a +*/ +/* + c2b +*/ +/* foo +c2c +*/ +/* foo + c2d +*/ +/* +c2e +foo */ +/* + c2f + foo */ +} + +func g() { +/* +c3a +*/ +/* + c3b +*/ +/* foo +c3c +*/ +/* foo + c3d +*/ +/* +c3e +foo */ +/* + c3f + foo */ +} + +// Test case taken literally from issue 1835. +func main() { +/* +prints test 5 times +*/ + for i := 0; i < 5; i++ { + println("test") + } +}
\ No newline at end of file diff --git a/libgo/go/go/printer/testdata/declarations.golden b/libgo/go/go/printer/testdata/declarations.golden index 71ed32ed145..21bbf2b2d42 100644 --- a/libgo/go/go/printer/testdata/declarations.golden +++ b/libgo/go/go/printer/testdata/declarations.golden @@ -654,6 +654,35 @@ var _ = map[int]int{ abcde: a, // align with previous line } +// alignment of map composite entries: test cases from issue 3965 +// aligned +var _ = T1{ + a: x, + b: y, + cccccccccccccccccccc: z, +} + +// not aligned +var _ = T2{ + a: x, + b: y, + ccccccccccccccccccccc: z, +} + +// aligned +var _ = T3{ + aaaaaaaaaaaaaaaaaaaa: x, + b: y, + c: z, +} + +// not aligned +var _ = T4{ + aaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaa: x, + b: y, + c: z, +} + func _() { var _ = T{ a, // must introduce trailing comma diff --git a/libgo/go/go/printer/testdata/declarations.input b/libgo/go/go/printer/testdata/declarations.input index d74cff25d1f..6ac00369926 100644 --- a/libgo/go/go/printer/testdata/declarations.input +++ b/libgo/go/go/printer/testdata/declarations.input @@ -667,6 +667,35 @@ var _ = map[int]int{ abcde: a, // align with previous line } +// alignment of map composite entries: test cases from issue 3965 +// aligned +var _ = T1{ + a: x, + b: y, + cccccccccccccccccccc: z, +} + +// not aligned +var _ = T2{ + a: x, + b: y, + ccccccccccccccccccccc: z, +} + +// aligned +var _ = T3{ + aaaaaaaaaaaaaaaaaaaa: x, + b: y, + c: z, +} + +// not aligned +var _ = T4{ + aaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaa: x, + b: y, + c: z, +} + func _() { var _ = T{ diff --git a/libgo/go/go/printer/testdata/expressions.golden b/libgo/go/go/printer/testdata/expressions.golden index 45fa4d97a4a..4291c557ce2 100644 --- a/libgo/go/go/printer/testdata/expressions.golden +++ b/libgo/go/go/printer/testdata/expressions.golden @@ -647,3 +647,18 @@ func _() { a..., ) } + +// Literal function types in conversions must be parenthesized; +// for now go/parser accepts the unparenthesized form where it +// is non-ambiguous. +func _() { + // these conversions should be rewritten to look + // the same as the parenthesized conversions below + _ = (func())(nil) + _ = (func(x int) float)(nil) + _ = (func() func() func())(nil) + + _ = (func())(nil) + _ = (func(x int) float)(nil) + _ = (func() func() func())(nil) +} diff --git a/libgo/go/go/printer/testdata/expressions.input b/libgo/go/go/printer/testdata/expressions.input index f545c66057c..1ec12a05049 100644 --- a/libgo/go/go/printer/testdata/expressions.input +++ b/libgo/go/go/printer/testdata/expressions.input @@ -676,3 +676,18 @@ func _() { a..., ) } + +// Literal function types in conversions must be parenthesized; +// for now go/parser accepts the unparenthesized form where it +// is non-ambiguous. +func _() { + // these conversions should be rewritten to look + // the same as the parenthesized conversions below + _ = func()()(nil) + _ = func(x int)(float)(nil) + _ = func() func() func()()(nil) + + _ = (func()())(nil) + _ = (func(x int)(float))(nil) + _ = (func() func() func()())(nil) +} diff --git a/libgo/go/go/printer/testdata/expressions.raw b/libgo/go/go/printer/testdata/expressions.raw index 87a4b00836d..062900e0724 100644 --- a/libgo/go/go/printer/testdata/expressions.raw +++ b/libgo/go/go/printer/testdata/expressions.raw @@ -647,3 +647,18 @@ func _() { a..., ) } + +// Literal function types in conversions must be parenthesized; +// for now go/parser accepts the unparenthesized form where it +// is non-ambiguous. +func _() { + // these conversions should be rewritten to look + // the same as the parenthesized conversions below + _ = (func())(nil) + _ = (func(x int) float)(nil) + _ = (func() func() func())(nil) + + _ = (func())(nil) + _ = (func(x int) float)(nil) + _ = (func() func() func())(nil) +} diff --git a/libgo/go/go/printer/testdata/statements.golden b/libgo/go/go/printer/testdata/statements.golden index 4d70617bf13..1f3cabe75ec 100644 --- a/libgo/go/go/printer/testdata/statements.golden +++ b/libgo/go/go/printer/testdata/statements.golden @@ -527,3 +527,29 @@ AVeryLongLabelThatShouldNotAffectFormatting: // There should be a single empty line before this comment. MoreCode() } + +// Formatting of empty statements. +func _() { + +} + +func _() { +} + +func _() { +} + +func _() { + f() +} + +func _() { +L: + ; +} + +func _() { +L: + ; + f() +} diff --git a/libgo/go/go/printer/testdata/statements.input b/libgo/go/go/printer/testdata/statements.input index bd03bc98b77..f93eea89253 100644 --- a/libgo/go/go/printer/testdata/statements.input +++ b/libgo/go/go/printer/testdata/statements.input @@ -468,3 +468,27 @@ AVeryLongLabelThatShouldNotAffectFormatting: // There should be a single empty line before this comment. MoreCode() } + + +// Formatting of empty statements. +func _() { + ;;;;;;;;;;;;;;;;;;;;;;;;; +} + +func _() {;;;;;;;;;;;;;;;;;;;;;;;;; +} + +func _() {;;;;;;;;;;;;;;;;;;;;;;;;;} + +func _() { +f();;;;;;;;;;;;;;;;;;;;;;;;; +} + +func _() { +L:;;;;;;;;;;;; +} + +func _() { +L:;;;;;;;;;;;; + f() +} |