]> Cypherpunks repositories - gostls13.git/commitdiff
support one-line functions
authorRobert Griesemer <gri@golang.org>
Mon, 19 Oct 2009 20:57:51 +0000 (13:57 -0700)
committerRobert Griesemer <gri@golang.org>
Mon, 19 Oct 2009 20:57:51 +0000 (13:57 -0700)
R=rsc
DELTA=207  (160 added, 42 deleted, 5 changed)
OCL=35854
CL=35887

src/pkg/go/printer/printer.go
src/pkg/go/printer/testdata/declarations.go
src/pkg/go/printer/testdata/declarations.golden
src/pkg/go/printer/testdata/expressions.go
src/pkg/go/printer/testdata/expressions.golden
src/pkg/go/printer/testdata/expressions.raw

index 1db836fb3277201ea35a2bc4ecc70918767c5563..0e799eceb9ae24d3ae1a92e6debaf3e875567ee0 100644 (file)
@@ -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:
index 577e32cdd6b92edcc34a40edf67c6d3d6899cb5e..3e926664f3ceb147c4ff15eac9a87b84b1c234aa 100644 (file)
@@ -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{}
+}
index 0b2f23c9f2695ace813428ae333f6fc585a42cc1..3a8fa8546c054afed7166ff2d9a9562068b8bc14 100644 (file)
@@ -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{}
+}
index f771bfcee8f3c911f02c25a436193ad99074b48d..07cb261aa2bc9875609bb2cdc819196db7a0bd2e 100644 (file)
@@ -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";
index b7a4493e8b32157d747c0ee86e2583b6bebf6277..48a6e6a4afcfea3533449de39e9f9478acf39bef 100644 (file)
@@ -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";
index a9b7b9436218677bfc87799ce4d9001713f8b406..6ee80ed94e62be513b4a0dd8c30fc737d606fa05 100644 (file)
@@ -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";