Commit e76cce1a authored by Robert Griesemer's avatar Robert Griesemer

support one-line functions

R=rsc
DELTA=207  (160 added, 42 deleted, 5 changed)
OCL=35854
CL=35887
parent d4d4ff0d
...@@ -81,6 +81,7 @@ type printer struct { ...@@ -81,6 +81,7 @@ type printer struct {
// Configuration (does not change after initialization) // Configuration (does not change after initialization)
output io.Writer; output io.Writer;
mode uint; mode uint;
tabwidth int;
errors chan os.Error; errors chan os.Error;
// Current state // Current state
...@@ -110,9 +111,10 @@ type printer struct { ...@@ -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.output = output;
p.mode = mode; p.mode = mode;
p.tabwidth = tabwidth;
p.errors = make(chan os.Error); p.errors = make(chan os.Error);
p.buffer = make([]whiteSpace, 0, 16); // whitespace sequences are short 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) { ...@@ -999,8 +1001,7 @@ func (p *printer) expr1(expr ast.Expr, prec1 int) (optSemi bool) {
case *ast.FuncLit: case *ast.FuncLit:
p.expr(x.Type); p.expr(x.Type);
p.print(blank); p.funcBody(x.Body, true);
p.block(x.Body, 1);
case *ast.ParenExpr: case *ast.ParenExpr:
p.print(token.LPAREN); p.print(token.LPAREN);
...@@ -1448,55 +1449,108 @@ func (p *printer) spec(spec ast.Spec, n int, context declContext) { ...@@ -1448,55 +1449,108 @@ func (p *printer) spec(spec ast.Spec, n int, context declContext) {
} }
func (p *printer) decl(decl ast.Decl, context declContext) { func (p *printer) genDecl(d *ast.GenDecl, context declContext) {
switch d := decl.(type) { p.leadComment(d.Doc);
case *ast.BadDecl: p.print(lineTag(d.Pos()), d.Tok, blank);
p.print(d.Pos(), "BadDecl");
case *ast.GenDecl: if d.Lparen.IsValid() {
p.leadComment(d.Doc); // group of parenthesized declarations
p.print(lineTag(d.Pos()), d.Tok, blank); p.print(d.Lparen, token.LPAREN);
if len(d.Specs) > 0 {
if d.Lparen.IsValid() { p.print(indent, formfeed);
// group of parenthesized declarations for i, s := range d.Specs {
p.print(d.Lparen, token.LPAREN); if i > 0 {
if len(d.Specs) > 0 { p.print(newline);
p.print(indent, formfeed);
for i, s := range d.Specs {
if i > 0 {
p.print(newline);
}
p.spec(s, len(d.Specs), inGroup);
} }
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 { } else {
// single declaration // single declaration
p.spec(d.Specs[0], 1, context); 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: return true;
p.leadComment(d.Doc); }
p.print(lineTag(d.Pos()), token.FUNC, blank);
if recv := d.Recv; recv != nil {
// method: print receiver func (p *printer) funcBody(b *ast.BlockStmt, isLit bool) {
p.print(token.LPAREN); if b == nil {
if len(recv.Names) > 0 { return;
p.expr(recv.Names[0]); }
p.print(blank);
} // TODO(gri): enable for function declarations, eventually.
p.expr(recv.Type); if isLit && p.isOneLiner(b) {
p.print(token.RPAREN, blank); sep := vtab;
if isLit {
sep = blank;
} }
p.expr(d.Name); p.print(sep, b.Pos(), token.LBRACE, blank);
p.signature(d.Type.Params, d.Type.Results); p.stmt(b.List[0]);
if d.Body != nil { 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.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: default:
panic("unreachable"); panic("unreachable");
} }
...@@ -1667,7 +1721,7 @@ func Fprint(output io.Writer, node interface{}, mode uint, tabwidth int) (int, o ...@@ -1667,7 +1721,7 @@ func Fprint(output io.Writer, node interface{}, mode uint, tabwidth int) (int, o
// setup printer and print node // setup printer and print node
var p printer; var p printer;
p.init(output, mode); p.init(output, mode, tabwidth);
go func() { go func() {
switch n := node.(type) { switch n := node.(type) {
case ast.Expr: case ast.Expr:
......
...@@ -360,3 +360,13 @@ func _() {} ...@@ -360,3 +360,13 @@ func _() {}
func _() {} // an empty line before this function func _() {} // an empty line before this function
func _() {} func _() {}
func _() {} func _() {}
func _() {
f(1, 2, 3);
}
func _(x int) int {
return x+1
}
func _() int {
type T struct{}
}
...@@ -360,3 +360,13 @@ func _() {} ...@@ -360,3 +360,13 @@ func _() {}
func _() {} // an empty line before this function func _() {} // an empty line before this function
func _() {} func _() {}
func _() {} func _() {}
func _() {
f(1, 2, 3);
}
func _(x int) int {
return x+1;
}
func _() int {
type T struct{}
}
...@@ -117,6 +117,26 @@ _ = `foo ...@@ -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 _() { func _() {
// not not add extra indentation to multi-line string lists // not not add extra indentation to multi-line string lists
_ = "foo" "bar"; _ = "foo" "bar";
......
...@@ -117,6 +117,18 @@ func _() { ...@@ -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 _() { func _() {
// not not add extra indentation to multi-line string lists // not not add extra indentation to multi-line string lists
_ = "foo" "bar"; _ = "foo" "bar";
......
...@@ -117,6 +117,18 @@ func _() { ...@@ -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 _() { func _() {
// not not add extra indentation to multi-line string lists // not not add extra indentation to multi-line string lists
_ = "foo" "bar"; _ = "foo" "bar";
......
Markdown is supported
0%
or
You are about to add 0 people to the discussion. Proceed with caution.
Finish editing this message first!
Please register or to comment