summaryrefslogtreecommitdiff
diff options
context:
space:
mode:
authorRobert Griesemer <gri@golang.org>2009-10-19 13:57:51 -0700
committerRobert Griesemer <gri@golang.org>2009-10-19 13:57:51 -0700
commit76a608808e7979a77e34722fa40f22480b7d549f (patch)
treeebefc7f88b6a2ee05509aa9006ee5d00894672d5
parentdde38c3a32b2eb0b7ce5dc83e90c9182593dad46 (diff)
downloadgolang-76a608808e7979a77e34722fa40f22480b7d549f.tar.gz
support one-line functions
R=rsc DELTA=207 (160 added, 42 deleted, 5 changed) OCL=35854 CL=35887
-rw-r--r--src/pkg/go/printer/printer.go140
-rw-r--r--src/pkg/go/printer/testdata/declarations.go10
-rw-r--r--src/pkg/go/printer/testdata/declarations.golden10
-rw-r--r--src/pkg/go/printer/testdata/expressions.go20
-rw-r--r--src/pkg/go/printer/testdata/expressions.golden12
-rw-r--r--src/pkg/go/printer/testdata/expressions.raw12
6 files changed, 161 insertions, 43 deletions
diff --git a/src/pkg/go/printer/printer.go b/src/pkg/go/printer/printer.go
index 1db836fb3..0e799eceb 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 577e32cdd..3e926664f 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 0b2f23c9f..3a8fa8546 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 f771bfcee..07cb261aa 100644
--- a/src/pkg/go/printer/testdata/expressions.go
+++ b/src/pkg/go/printer/testdata/expressions.go
@@ -118,6 +118,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";
_ = "foo"
diff --git a/src/pkg/go/printer/testdata/expressions.golden b/src/pkg/go/printer/testdata/expressions.golden
index b7a4493e8..48a6e6a4a 100644
--- a/src/pkg/go/printer/testdata/expressions.golden
+++ b/src/pkg/go/printer/testdata/expressions.golden
@@ -118,6 +118,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";
_ = "foo"
diff --git a/src/pkg/go/printer/testdata/expressions.raw b/src/pkg/go/printer/testdata/expressions.raw
index a9b7b9436..6ee80ed94 100644
--- a/src/pkg/go/printer/testdata/expressions.raw
+++ b/src/pkg/go/printer/testdata/expressions.raw
@@ -118,6 +118,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";
_ = "foo"