]> Cypherpunks repositories - gostls13.git/commitdiff
format composite literal types that are "short" struct type literals
authorRobert Griesemer <gri@golang.org>
Sat, 7 Nov 2009 00:34:19 +0000 (16:34 -0800)
committerRobert Griesemer <gri@golang.org>
Sat, 7 Nov 2009 00:34:19 +0000 (16:34 -0800)
on one line for a more compact representation of some composite Literals

R=rsc
http://go/go-review/1025008

src/pkg/go/printer/nodes.go
src/pkg/go/printer/testdata/expressions.golden
src/pkg/go/printer/testdata/expressions.input
src/pkg/go/printer/testdata/expressions.raw

index 4c2f0c57f45a136bfd60f89551a76abc7b5e6261..7ffb73e695ba30dfa3b7aeaebaa8e344a7b0c869 100644 (file)
@@ -25,7 +25,6 @@ const (
 
 // Other formatting issues:
 // - replacement of expression spacing algorithm with rsc's algorithm
-// - support for one-line composite types (e.g. structs) as composite literals types
 // - better comment formatting for /*-style comments at the end of a line (e.g. a declaration)
 //   when the comment spans multiple lines; if such a comment is just two lines, formatting is
 //   not idempotent
@@ -262,16 +261,70 @@ func (p *printer) signature(params, result []*ast.Field, multiLine *bool) (optSe
 }
 
 
-func (p *printer) fieldList(lbrace token.Position, list []*ast.Field, rbrace token.Position, isIncomplete, isStruct bool) {
-       if len(list) == 0 && !isIncomplete && !p.commentBefore(rbrace) {
-               // no blank between keyword and {} in this case
-               p.print(lbrace, token.LBRACE, rbrace, token.RBRACE);
-               return;
+func identListSize(list []*ast.Ident, maxSize int) (size int) {
+       for i, x := range list {
+               if i > 0 {
+                       size += 2;      // ", "
+               }
+               size += len(x.Value);
+               if size >= maxSize {
+                       break;
+               }
+       }
+       return;
+}
+
+
+func (p *printer) isOneLineFieldList(list []*ast.Field) bool {
+       if len(list) != 1 {
+               return false;   // allow only one field
+       }
+       f := list[0];
+       if f.Tag != nil || f.Comment != nil {
+               return false;   // don't allow tags or comments
+       }
+       // only name(s) and type
+       const maxSize = 30;     // adjust as appropriate, this is an approximate value
+       namesSize := identListSize(f.Names, maxSize);
+       if namesSize > 0 {
+               namesSize = 1;  // blank between names and types
+       }
+       typeSize := p.nodeSize(f.Type, maxSize);
+       return namesSize + typeSize <= maxSize;
+}
+
+
+func (p *printer) fieldList(lbrace token.Position, list []*ast.Field, rbrace token.Position, isIncomplete bool, ctxt Context) {
+       if !isIncomplete && !p.commentBefore(rbrace) {
+               // possibly a one-line struct/interface
+               if len(list) == 0 {
+                       // no blank between keyword and {} in this case
+                       p.print(lbrace, token.LBRACE, rbrace, token.RBRACE);
+                       return;
+               } else if ctxt&(compositeLit | structType) == compositeLit | structType &&
+                       p.isOneLineFieldList(list) {    // for now ignore interfaces
+                       // small enough - print on one line
+                       // (don't use identList and ignore source line breaks)
+                       p.print(lbrace, token.LBRACE, blank);
+                       f := list[0];
+                       for i, x := range f.Names {
+                               if i > 0 {
+                                       p.print(token.COMMA, blank);
+                               }
+                               p.expr(x, ignoreMultiLine);
+                       }
+                       if len(f.Names) > 0 {
+                               p.print(blank);
+                       }
+                       p.expr(f.Type, ignoreMultiLine);
+                       p.print(blank, rbrace, token.RBRACE);
+                       return;
+               }
        }
 
        // at least one entry or incomplete
        p.print(blank, lbrace, token.LBRACE, indent, formfeed);
-       if isStruct {
+       if ctxt & structType != 0 {
 
                sep := vtab;
                if len(list) == 1 {
@@ -286,11 +339,13 @@ func (p *printer) fieldList(lbrace token.Position, list []*ast.Field, rbrace tok
                        extraTabs := 0;
                        p.leadComment(f.Doc);
                        if len(f.Names) > 0 {
+                               // named fields
                                p.identList(f.Names, &ml);
                                p.print(sep);
                                p.expr(f.Type, &ml);
                                extraTabs = 1;
                        } else {
+                               // anonymous field
                                p.expr(f.Type, &ml);
                                extraTabs = 2;
                        }
@@ -354,6 +409,15 @@ func (p *printer) fieldList(lbrace token.Position, list []*ast.Field, rbrace tok
 // ----------------------------------------------------------------------------
 // Expressions
 
+// Context describes the syntactic environment in which an expression node is printed.
+type Context uint
+
+const (
+       compositeLit    = 1<<iota;
+       structType;
+)
+
+
 func needsBlanks(expr ast.Expr) bool {
        switch x := expr.(type) {
        case *ast.Ident:
@@ -420,7 +484,7 @@ func (p *printer) binaryExpr(x *ast.BinaryExpr, prec1 int, multiLine *bool) {
 
        // Print collected operations left-to-right, with blanks if necessary.
        ws := indent;
-       p.expr1(x.X, prec, multiLine);
+       p.expr1(x.X, prec, 0, multiLine);
        for list.Len() > 0 {
                x = list.Pop().(*ast.BinaryExpr);
                prev := line;
@@ -443,7 +507,7 @@ func (p *printer) binaryExpr(x *ast.BinaryExpr, prec1 int, multiLine *bool) {
                        }
                        p.print(x.OpPos, x.Op);
                }
-               p.expr1(x.Y, prec, multiLine);
+               p.expr1(x.Y, prec, 0, multiLine);
        }
        if ws == ignore {
                p.print(unindent);
@@ -453,7 +517,7 @@ func (p *printer) binaryExpr(x *ast.BinaryExpr, prec1 int, multiLine *bool) {
 
 // Returns true if a separating semicolon is optional.
 // Sets multiLine to true if the expression spans multiple lines.
-func (p *printer) expr1(expr ast.Expr, prec1 int, multiLine *bool) (optSemi bool) {
+func (p *printer) expr1(expr ast.Expr, prec1 int, ctxt Context, multiLine *bool) (optSemi bool) {
        p.print(expr.Pos());
 
        switch x := expr.(type) {
@@ -488,7 +552,7 @@ func (p *printer) expr1(expr ast.Expr, prec1 int, multiLine *bool) (optSemi bool
                        if x.Op == token.RANGE {
                                p.print(blank);
                        }
-                       p.expr1(x.X, prec, multiLine);
+                       p.expr1(x.X, prec, 0, multiLine);
                }
 
        case *ast.BasicLit:
@@ -507,12 +571,12 @@ func (p *printer) expr1(expr ast.Expr, prec1 int, multiLine *bool) (optSemi bool
                p.print(x.Rparen, token.RPAREN);
 
        case *ast.SelectorExpr:
-               p.expr1(x.X, token.HighestPrec, multiLine);
+               p.expr1(x.X, token.HighestPrec, 0, multiLine);
                p.print(token.PERIOD);
-               p.expr1(x.Sel, token.HighestPrec, multiLine);
+               p.expr1(x.Sel, token.HighestPrec, 0, multiLine);
 
        case *ast.TypeAssertExpr:
-               p.expr1(x.X, token.HighestPrec, multiLine);
+               p.expr1(x.X, token.HighestPrec, 0, multiLine);
                p.print(token.PERIOD, token.LPAREN);
                if x.Type != nil {
                        p.expr(x.Type, multiLine);
@@ -522,9 +586,9 @@ func (p *printer) expr1(expr ast.Expr, prec1 int, multiLine *bool) (optSemi bool
                p.print(token.RPAREN);
 
        case *ast.IndexExpr:
-               p.expr1(x.X, token.HighestPrec, multiLine);
+               p.expr1(x.X, token.HighestPrec, 0, multiLine);
                p.print(token.LBRACK);
-               p.expr1(x.Index, token.LowestPrec, multiLine);
+               p.expr1(x.Index, token.LowestPrec, 0, multiLine);
                if x.End != nil {
                        if needsBlanks(x.Index) || needsBlanks(x.End) {
                                // blanks around ":"
@@ -538,13 +602,13 @@ func (p *printer) expr1(expr ast.Expr, prec1 int, multiLine *bool) (optSemi bool
                p.print(token.RBRACK);
 
        case *ast.CallExpr:
-               p.expr1(x.Fun, token.HighestPrec, multiLine);
+               p.expr1(x.Fun, token.HighestPrec, 0, multiLine);
                p.print(x.Lparen, token.LPAREN);
                p.exprList(x.Lparen, x.Args, commaSep, multiLine);
                p.print(x.Rparen, token.RPAREN);
 
        case *ast.CompositeLit:
-               p.expr1(x.Type, token.HighestPrec, multiLine);
+               p.expr1(x.Type, token.HighestPrec, compositeLit, multiLine);
                if compositeLitBlank && x.Lbrace.Line < x.Rbrace.Line {
                        // add a blank before the opening { for multi-line composites
                        // TODO(gri): for now this decision is made by looking at the
@@ -569,7 +633,7 @@ func (p *printer) expr1(expr ast.Expr, prec1 int, multiLine *bool) (optSemi bool
 
        case *ast.StructType:
                p.print(token.STRUCT);
-               p.fieldList(x.Lbrace, x.Fields, x.Rbrace, x.Incomplete, true);
+               p.fieldList(x.Lbrace, x.Fields, x.Rbrace, x.Incomplete, ctxt | structType);
                optSemi = true;
 
        case *ast.FuncType:
@@ -578,7 +642,7 @@ func (p *printer) expr1(expr ast.Expr, prec1 int, multiLine *bool) (optSemi bool
 
        case *ast.InterfaceType:
                p.print(token.INTERFACE);
-               p.fieldList(x.Lbrace, x.Methods, x.Rbrace, x.Incomplete, false);
+               p.fieldList(x.Lbrace, x.Methods, x.Rbrace, x.Incomplete, ctxt);
                optSemi = true;
 
        case *ast.MapType:
@@ -610,7 +674,7 @@ func (p *printer) expr1(expr ast.Expr, prec1 int, multiLine *bool) (optSemi bool
 // Returns true if a separating semicolon is optional.
 // Sets multiLine to true if the expression spans multiple lines.
 func (p *printer) expr(x ast.Expr, multiLine *bool) (optSemi bool) {
-       return p.expr1(x, token.LowestPrec, multiLine);
+       return p.expr1(x, token.LowestPrec, 0, multiLine);
 }
 
 
index f9cd03e2b513168b738fa5733b795232ae300667..4d105f7d30b1faf57255670acce7fa1490f5e3ee 100644 (file)
@@ -104,6 +104,20 @@ func _() {
 }
 
 
+// one-line structs/interfaces in composite literals (up to a threshold)
+func _() {
+       _ = struct{}{};
+       _ = struct{ x int }{0};
+       _ = struct{ x, y, z int }{0, 1, 2};
+       _ = struct{ int }{0};
+       _ = struct {
+               s struct {
+                       int;
+               };
+       }{struct{ int }{0}};    // compositeLit context not propagated => multiLine result
+}
+
+
 func _() {
        // do not modify literals
        _ = "tab1       tab2    tab3    end";   // string contains 3 tabs
index 0ff4c42ee0eb180508a56776f82357982ddb8ef4..387a1a9769ec1e1272951483d55784f245e7de93 100644 (file)
@@ -104,6 +104,16 @@ func _() {
 }
 
 
+// one-line structs/interfaces in composite literals (up to a threshold)
+func _() {
+       _ = struct{}{};
+       _ = struct{ x int }{0};
+       _ = struct{ x, y, z int }{0, 1, 2};
+       _ = struct{ int }{0};
+       _ = struct{ s struct { int } }{struct{ int}{0}};  // compositeLit context not propagated => multiLine result
+}
+
+
 func _() {
        // do not modify literals
        _ = "tab1       tab2    tab3    end";  // string contains 3 tabs
index 20b78552b15fbe9614720e3a50066fdfaea2cbcd..ae11b7b16ed7f3fb18fc3f6a114384be7853ae74 100644 (file)
@@ -104,6 +104,20 @@ func _() {
 }
 
 
+// one-line structs/interfaces in composite literals (up to a threshold)
+func _() {
+       _ = struct{}{};
+       _ = struct{ x int }{0};
+       _ = struct{ x, y, z int }{0, 1, 2};
+       _ = struct{ int }{0};
+       _ = struct {
+               s struct {
+                       int;
+               };
+       }{struct{ int }{0}};    // compositeLit context not propagated => multiLine result
+}
+
+
 func _() {
        // do not modify literals
        _ = "tab1       tab2    tab3    end";   // string contains 3 tabs