From: Robert Griesemer Date: Mon, 19 Oct 2009 20:57:51 +0000 (-0700) Subject: support one-line functions X-Git-Tag: weekly.2009-11-06~264 X-Git-Url: http://www.git.cypherpunks.su/?a=commitdiff_plain;h=e76cce1a6db43af9fa3ecf726a973abe254c0827;p=gostls13.git support one-line functions R=rsc DELTA=207 (160 added, 42 deleted, 5 changed) OCL=35854 CL=35887 --- diff --git a/src/pkg/go/printer/printer.go b/src/pkg/go/printer/printer.go index 1db836fb32..0e799eceb9 100644 --- a/src/pkg/go/printer/printer.go +++ b/src/pkg/go/printer/printer.go @@ -81,6 +81,7 @@ type printer struct { // Configuration (does not change after initialization) output io.Writer; mode uint; + tabwidth int; errors chan os.Error; // Current state @@ -110,9 +111,10 @@ type printer struct { } -func (p *printer) init(output io.Writer, mode uint) { +func (p *printer) init(output io.Writer, mode uint, tabwidth int) { p.output = output; p.mode = mode; + p.tabwidth = tabwidth; p.errors = make(chan os.Error); p.buffer = make([]whiteSpace, 0, 16); // whitespace sequences are short } @@ -999,8 +1001,7 @@ func (p *printer) expr1(expr ast.Expr, prec1 int) (optSemi bool) { case *ast.FuncLit: p.expr(x.Type); - p.print(blank); - p.block(x.Body, 1); + p.funcBody(x.Body, true); case *ast.ParenExpr: p.print(token.LPAREN); @@ -1448,55 +1449,108 @@ func (p *printer) spec(spec ast.Spec, n int, context declContext) { } -func (p *printer) decl(decl ast.Decl, context declContext) { - switch d := decl.(type) { - case *ast.BadDecl: - p.print(d.Pos(), "BadDecl"); +func (p *printer) genDecl(d *ast.GenDecl, context declContext) { + p.leadComment(d.Doc); + p.print(lineTag(d.Pos()), d.Tok, blank); - case *ast.GenDecl: - p.leadComment(d.Doc); - p.print(lineTag(d.Pos()), d.Tok, blank); - - if d.Lparen.IsValid() { - // group of parenthesized declarations - p.print(d.Lparen, token.LPAREN); - if len(d.Specs) > 0 { - p.print(indent, formfeed); - for i, s := range d.Specs { - if i > 0 { - p.print(newline); - } - p.spec(s, len(d.Specs), inGroup); + if d.Lparen.IsValid() { + // group of parenthesized declarations + p.print(d.Lparen, token.LPAREN); + if len(d.Specs) > 0 { + p.print(indent, formfeed); + for i, s := range d.Specs { + if i > 0 { + p.print(newline); } - p.print(unindent, formfeed); + p.spec(s, len(d.Specs), inGroup); } - p.print(d.Rparen, token.RPAREN); + p.print(unindent, formfeed); + } + p.print(d.Rparen, token.RPAREN); - } else { - // single declaration - p.spec(d.Specs[0], 1, context); + } else { + // single declaration + p.spec(d.Specs[0], 1, context); + } +} + + +func (p *printer) isOneLiner(b *ast.BlockStmt) bool { + if len(b.List) != 1 || p.commentBefore(b.Rbrace) { + // too many statements or there is a comment - all bets are off + return false; + } + + // test-print the statement and see if it would fit + var buf bytes.Buffer; + _, err := Fprint(&buf, b.List[0], p.mode, p.tabwidth); + if err != nil { + return false; // don't try + } + + if buf.Len() > 40 { + return false; // too long + } + + for _, ch := range buf.Bytes() { + if ch < ' ' { + return false; // contains control chars (tabs, newlines) } + } - case *ast.FuncDecl: - p.leadComment(d.Doc); - p.print(lineTag(d.Pos()), token.FUNC, blank); - if recv := d.Recv; recv != nil { - // method: print receiver - p.print(token.LPAREN); - if len(recv.Names) > 0 { - p.expr(recv.Names[0]); - p.print(blank); - } - p.expr(recv.Type); - p.print(token.RPAREN, blank); + return true; +} + + +func (p *printer) funcBody(b *ast.BlockStmt, isLit bool) { + if b == nil { + return; + } + + // TODO(gri): enable for function declarations, eventually. + if isLit && p.isOneLiner(b) { + sep := vtab; + if isLit { + sep = blank; } - p.expr(d.Name); - p.signature(d.Type.Params, d.Type.Results); - if d.Body != nil { + p.print(sep, b.Pos(), token.LBRACE, blank); + p.stmt(b.List[0]); + p.print(blank, b.Rbrace, token.RBRACE); + return; + } + + p.print(blank); + p.block(b, 1); +} + + +func (p *printer) funcDecl(d *ast.FuncDecl) { + p.leadComment(d.Doc); + p.print(lineTag(d.Pos()), token.FUNC, blank); + if recv := d.Recv; recv != nil { + // method: print receiver + p.print(token.LPAREN); + if len(recv.Names) > 0 { + p.expr(recv.Names[0]); p.print(blank); - p.block(d.Body, 1); } + p.expr(recv.Type); + p.print(token.RPAREN, blank); + } + p.expr(d.Name); + p.signature(d.Type.Params, d.Type.Results); + p.funcBody(d.Body, false); +} + +func (p *printer) decl(decl ast.Decl, context declContext) { + switch d := decl.(type) { + case *ast.BadDecl: + p.print(d.Pos(), "BadDecl"); + case *ast.GenDecl: + p.genDecl(d, context); + case *ast.FuncDecl: + p.funcDecl(d); default: panic("unreachable"); } @@ -1667,7 +1721,7 @@ func Fprint(output io.Writer, node interface{}, mode uint, tabwidth int) (int, o // setup printer and print node var p printer; - p.init(output, mode); + p.init(output, mode, tabwidth); go func() { switch n := node.(type) { case ast.Expr: diff --git a/src/pkg/go/printer/testdata/declarations.go b/src/pkg/go/printer/testdata/declarations.go index 577e32cdd6..3e926664f3 100644 --- a/src/pkg/go/printer/testdata/declarations.go +++ b/src/pkg/go/printer/testdata/declarations.go @@ -360,3 +360,13 @@ func _() {} func _() {} // an empty line before this function func _() {} func _() {} + +func _() { + f(1, 2, 3); +} +func _(x int) int { + return x+1 +} +func _() int { + type T struct{} +} diff --git a/src/pkg/go/printer/testdata/declarations.golden b/src/pkg/go/printer/testdata/declarations.golden index 0b2f23c9f2..3a8fa8546c 100644 --- a/src/pkg/go/printer/testdata/declarations.golden +++ b/src/pkg/go/printer/testdata/declarations.golden @@ -360,3 +360,13 @@ func _() {} func _() {} // an empty line before this function func _() {} func _() {} + +func _() { + f(1, 2, 3); +} +func _(x int) int { + return x+1; +} +func _() int { + type T struct{} +} diff --git a/src/pkg/go/printer/testdata/expressions.go b/src/pkg/go/printer/testdata/expressions.go index f771bfcee8..07cb261aa2 100644 --- a/src/pkg/go/printer/testdata/expressions.go +++ b/src/pkg/go/printer/testdata/expressions.go @@ -117,6 +117,26 @@ _ = `foo } +func _() { + // one-line function literals + _ = func() {}; + _ = func() int { + return 0; + }; + _ = func(x, y int) bool { + return x < y + }; + + f(func() {}); + f(func() int { + return 0; + }); + f(func(x, y int) bool { + return x < y + }); +} + + func _() { // not not add extra indentation to multi-line string lists _ = "foo" "bar"; diff --git a/src/pkg/go/printer/testdata/expressions.golden b/src/pkg/go/printer/testdata/expressions.golden index b7a4493e8b..48a6e6a4af 100644 --- a/src/pkg/go/printer/testdata/expressions.golden +++ b/src/pkg/go/printer/testdata/expressions.golden @@ -117,6 +117,18 @@ func _() { } +func _() { + // one-line function literals + _ = func() {}; + _ = func() int { return 0 }; + _ = func(x, y int) bool { return x < y }; + + f(func() {}); + f(func() int { return 0 }); + f(func(x, y int) bool { return x < y }); +} + + func _() { // not not add extra indentation to multi-line string lists _ = "foo" "bar"; diff --git a/src/pkg/go/printer/testdata/expressions.raw b/src/pkg/go/printer/testdata/expressions.raw index a9b7b94362..6ee80ed94e 100644 --- a/src/pkg/go/printer/testdata/expressions.raw +++ b/src/pkg/go/printer/testdata/expressions.raw @@ -117,6 +117,18 @@ func _() { } +func _() { + // one-line function literals + _ = func() {}; + _ = func() int { return 0 }; + _ = func(x, y int) bool { return x < y }; + + f(func() {}); + f(func() int { return 0 }); + f(func(x, y int) bool { return x < y }); +} + + func _() { // not not add extra indentation to multi-line string lists _ = "foo" "bar";