Commit 2b87d95f authored by Robert Griesemer's avatar Robert Griesemer

- allow more general type switch syntax

- support for reverse printing of AST
  (for compiler testing)
- added -reverse flag to gofmt

R=rsc
DELTA=163  (125 added, 11 deleted, 27 changed)
OCL=32808
CL=32853
parent c6839861
...@@ -38,6 +38,7 @@ var ( ...@@ -38,6 +38,7 @@ var (
usespaces = flag.Bool("spaces", false, "align with blanks instead of tabs"); usespaces = flag.Bool("spaces", false, "align with blanks instead of tabs");
optcommas = flag.Bool("optcommas", false, "print optional commas"); optcommas = flag.Bool("optcommas", false, "print optional commas");
optsemis = flag.Bool("optsemis", false, "print optional semicolons"); optsemis = flag.Bool("optsemis", false, "print optional semicolons");
reverse = flag.Bool("reverse", false, "print top-level declarations in reverse order without forward-declarations");
) )
...@@ -116,6 +117,9 @@ func printerMode() uint { ...@@ -116,6 +117,9 @@ func printerMode() uint {
if *optsemis { if *optsemis {
mode |= printer.OptSemis; mode |= printer.OptSemis;
} }
if *reverse {
mode |= printer.Reverse;
}
return mode; return mode;
} }
......
...@@ -219,7 +219,7 @@ type ( ...@@ -219,7 +219,7 @@ type (
// //
TypeAssertExpr struct { TypeAssertExpr struct {
X Expr; // expression X Expr; // expression
Type Expr; // asserted type Type Expr; // asserted type; nil means type switch X.(type)
}; };
// A CallExpr node represents an expression followed by an argument list. // A CallExpr node represents an expression followed by an argument list.
...@@ -546,7 +546,7 @@ type ( ...@@ -546,7 +546,7 @@ type (
// A TypeCaseClause represents a case of a type switch statement. // A TypeCaseClause represents a case of a type switch statement.
TypeCaseClause struct { TypeCaseClause struct {
token.Position; // position of "case" or "default" keyword token.Position; // position of "case" or "default" keyword
Type Expr; // nil means default case Types []Expr; // nil means default case
Colon token.Position; // position of ":" Colon token.Position; // position of ":"
Body []Stmt; // statement list; or nil Body []Stmt; // statement list; or nil
}; };
......
...@@ -952,8 +952,7 @@ func (p *parser) parseSelectorOrTypeAssertion(x ast.Expr) ast.Expr { ...@@ -952,8 +952,7 @@ func (p *parser) parseSelectorOrTypeAssertion(x ast.Expr) ast.Expr {
p.expect(token.LPAREN); p.expect(token.LPAREN);
var typ ast.Expr; var typ ast.Expr;
if p.tok == token.TYPE { if p.tok == token.TYPE {
// special case for type switch // type switch: typ == nil
typ = &ast.Ident{p.pos, "type"};
p.next(); p.next();
} else { } else {
typ = p.parseType(); typ = p.parseType();
...@@ -1078,6 +1077,11 @@ func (p *parser) checkExpr(x ast.Expr) ast.Expr { ...@@ -1078,6 +1077,11 @@ func (p *parser) checkExpr(x ast.Expr) ast.Expr {
case *ast.SelectorExpr: case *ast.SelectorExpr:
case *ast.IndexExpr: case *ast.IndexExpr:
case *ast.TypeAssertExpr: case *ast.TypeAssertExpr:
if t.Type == nil {
// the form X.(type) is only allowed in type switch expressions
p.errorExpected(x.Pos(), "expression");
x = &ast.BadExpr{x.Pos()};
}
case *ast.CallExpr: case *ast.CallExpr:
case *ast.StarExpr: case *ast.StarExpr:
case *ast.UnaryExpr: case *ast.UnaryExpr:
...@@ -1353,15 +1357,6 @@ func (p *parser) parseBranchStmt(tok token.Token) *ast.BranchStmt { ...@@ -1353,15 +1357,6 @@ func (p *parser) parseBranchStmt(tok token.Token) *ast.BranchStmt {
} }
func (p *parser) isExpr(s ast.Stmt) bool {
if s == nil {
return true;
}
dummy, isExpr := s.(*ast.ExprStmt);
return isExpr;
}
func (p *parser) makeExpr(s ast.Stmt) ast.Expr { func (p *parser) makeExpr(s ast.Stmt) ast.Expr {
if s == nil { if s == nil {
return nil; return nil;
...@@ -1411,7 +1406,7 @@ func (p *parser) parseIfStmt() *ast.IfStmt { ...@@ -1411,7 +1406,7 @@ func (p *parser) parseIfStmt() *ast.IfStmt {
} }
pos := p.expect(token.IF); pos := p.expect(token.IF);
s1, s2, dummy := p.parseControlClause(false); s1, s2, _ := p.parseControlClause(false);
body := p.parseBlockStmt(); body := p.parseBlockStmt();
var else_ ast.Stmt; var else_ ast.Stmt;
if p.tok == token.ELSE { if p.tok == token.ELSE {
...@@ -1445,6 +1440,28 @@ func (p *parser) parseCaseClause() *ast.CaseClause { ...@@ -1445,6 +1440,28 @@ func (p *parser) parseCaseClause() *ast.CaseClause {
} }
func (p *parser) parseTypeList() []ast.Expr {
if p.trace {
defer un(trace(p, "TypeList"));
}
list := vector.New(0);
list.Push(p.parseType());
for p.tok == token.COMMA {
p.next();
list.Push(p.parseType());
}
// convert list
exprs := make([]ast.Expr, list.Len());
for i := 0; i < list.Len(); i++ {
exprs[i] = list.At(i).(ast.Expr);
}
return exprs;
}
func (p *parser) parseTypeCaseClause() *ast.TypeCaseClause { func (p *parser) parseTypeCaseClause() *ast.TypeCaseClause {
if p.trace { if p.trace {
defer un(trace(p, "TypeCaseClause")); defer un(trace(p, "TypeCaseClause"));
...@@ -1452,10 +1469,10 @@ func (p *parser) parseTypeCaseClause() *ast.TypeCaseClause { ...@@ -1452,10 +1469,10 @@ func (p *parser) parseTypeCaseClause() *ast.TypeCaseClause {
// TypeSwitchCase // TypeSwitchCase
pos := p.pos; pos := p.pos;
var typ ast.Expr; var types []ast.Expr;
if p.tok == token.CASE { if p.tok == token.CASE {
p.next(); p.next();
typ = p.parseType(); types = p.parseTypeList();
} else { } else {
p.expect(token.DEFAULT); p.expect(token.DEFAULT);
} }
...@@ -1463,7 +1480,21 @@ func (p *parser) parseTypeCaseClause() *ast.TypeCaseClause { ...@@ -1463,7 +1480,21 @@ func (p *parser) parseTypeCaseClause() *ast.TypeCaseClause {
colon := p.expect(token.COLON); colon := p.expect(token.COLON);
body := p.parseStmtList(); body := p.parseStmtList();
return &ast.TypeCaseClause{pos, typ, colon, body}; return &ast.TypeCaseClause{pos, types, colon, body};
}
func isExprSwitch(s ast.Stmt) bool {
if s == nil {
return true;
}
if e, ok := s.(*ast.ExprStmt); ok {
if a, ok := e.X.(*ast.TypeAssertExpr); ok {
return a.Type != nil; // regular type assertion
}
return true;
}
return false;
} }
...@@ -1473,10 +1504,9 @@ func (p *parser) parseSwitchStmt() ast.Stmt { ...@@ -1473,10 +1504,9 @@ func (p *parser) parseSwitchStmt() ast.Stmt {
} }
pos := p.expect(token.SWITCH); pos := p.expect(token.SWITCH);
s1, s2, dummy := p.parseControlClause(false); s1, s2, _ := p.parseControlClause(false);
if p.isExpr(s2) { if isExprSwitch(s2) {
// expression switch
lbrace := p.expect(token.LBRACE); lbrace := p.expect(token.LBRACE);
cases := vector.New(0); cases := vector.New(0);
for p.tok == token.CASE || p.tok == token.DEFAULT { for p.tok == token.CASE || p.tok == token.DEFAULT {
......
...@@ -32,6 +32,7 @@ const ( ...@@ -32,6 +32,7 @@ const (
UseSpaces; // use spaces instead of tabs for indentation and alignment UseSpaces; // use spaces instead of tabs for indentation and alignment
OptCommas; // print optional commas OptCommas; // print optional commas
OptSemis; // print optional semicolons OptSemis; // print optional semicolons
Reverse; // print top-level declarations in reverse order without forward-declarations
) )
...@@ -682,7 +683,11 @@ func (p *printer) expr1(expr ast.Expr, prec1 int) (optSemi bool) { ...@@ -682,7 +683,11 @@ func (p *printer) expr1(expr ast.Expr, prec1 int) (optSemi bool) {
case *ast.TypeAssertExpr: case *ast.TypeAssertExpr:
p.expr1(x.X, token.HighestPrec); p.expr1(x.X, token.HighestPrec);
p.print(token.PERIOD, token.LPAREN); p.print(token.PERIOD, token.LPAREN);
p.expr(x.Type); if x.Type != nil {
p.expr(x.Type);
} else {
p.print(token.TYPE);
}
p.print(token.RPAREN); p.print(token.RPAREN);
case *ast.IndexExpr: case *ast.IndexExpr:
...@@ -722,6 +727,10 @@ func (p *printer) expr1(expr ast.Expr, prec1 int) (optSemi bool) { ...@@ -722,6 +727,10 @@ func (p *printer) expr1(expr ast.Expr, prec1 int) (optSemi bool) {
p.expr(x.Elt); p.expr(x.Elt);
case *ast.StructType: case *ast.StructType:
if x.Fields == nil && p.mode & Reverse != 0 && p.level == 0 {
// omit top-level forward declarations in reverse mode
return true;
}
p.print(token.STRUCT); p.print(token.STRUCT);
optSemi = p.fieldList(x.Lbrace, x.Fields, x.Rbrace, false); optSemi = p.fieldList(x.Lbrace, x.Fields, x.Rbrace, false);
...@@ -730,6 +739,10 @@ func (p *printer) expr1(expr ast.Expr, prec1 int) (optSemi bool) { ...@@ -730,6 +739,10 @@ func (p *printer) expr1(expr ast.Expr, prec1 int) (optSemi bool) {
p.signature(x.Params, x.Results); p.signature(x.Params, x.Results);
case *ast.InterfaceType: case *ast.InterfaceType:
if x.Methods == nil && p.mode & Reverse != 0 && p.level == 0 {
// omit top-level forward declarations in reverse mode
return true;
}
p.print(token.INTERFACE); p.print(token.INTERFACE);
optSemi = p.fieldList(x.Lbrace, x.Methods, x.Rbrace, true); optSemi = p.fieldList(x.Lbrace, x.Methods, x.Rbrace, true);
...@@ -941,9 +954,9 @@ func (p *printer) stmt(stmt ast.Stmt) (optSemi bool) { ...@@ -941,9 +954,9 @@ func (p *printer) stmt(stmt ast.Stmt) (optSemi bool) {
optSemi = true; optSemi = true;
case *ast.TypeCaseClause: case *ast.TypeCaseClause:
if s.Type != nil { if s.Types != nil {
p.print(token.CASE, blank); p.print(token.CASE, blank);
p.expr(s.Type); p.exprList(s.Types);
} else { } else {
p.print(token.DEFAULT); p.print(token.DEFAULT);
} }
...@@ -1070,13 +1083,25 @@ func (p *printer) decl(decl ast.Decl) (comment *ast.CommentGroup, optSemi bool) ...@@ -1070,13 +1083,25 @@ func (p *printer) decl(decl ast.Decl) (comment *ast.CommentGroup, optSemi bool)
p.print(d.Lparen, token.LPAREN); p.print(d.Lparen, token.LPAREN);
if len(d.Specs) > 0 { if len(d.Specs) > 0 {
p.print(+1, newline); p.print(+1, newline);
for i, s := range d.Specs { if p.mode & Reverse != 0 && p.level == 0 {
if i > 0 { for i := len(d.Specs)-1; i >= 0; i-- {
p.print(token.SEMICOLON); s := d.Specs[i];
p.lineComment(comment); if i < len(d.Specs)-1 {
p.print(newline); p.print(token.SEMICOLON);
p.lineComment(comment);
p.print(newline);
}
comment, optSemi = p.spec(s);
}
} else {
for i, s := range d.Specs {
if i > 0 {
p.print(token.SEMICOLON);
p.lineComment(comment);
p.print(newline);
}
comment, optSemi = p.spec(s);
} }
comment, optSemi = p.spec(s);
} }
if p.optSemis() { if p.optSemis() {
p.print(token.SEMICOLON); p.print(token.SEMICOLON);
...@@ -1094,6 +1119,10 @@ func (p *printer) decl(decl ast.Decl) (comment *ast.CommentGroup, optSemi bool) ...@@ -1094,6 +1119,10 @@ func (p *printer) decl(decl ast.Decl) (comment *ast.CommentGroup, optSemi bool)
} }
case *ast.FuncDecl: case *ast.FuncDecl:
if d.Body == nil && p.mode & Reverse != 0 {
// omit forward declarations in reverse mode
break;
}
p.leadComment(d.Doc); p.leadComment(d.Doc);
p.print(lineTag(d.Pos()), token.FUNC, blank); p.print(lineTag(d.Pos()), token.FUNC, blank);
if recv := d.Recv; recv != nil { if recv := d.Recv; recv != nil {
...@@ -1131,13 +1160,25 @@ func (p *printer) file(src *ast.File) { ...@@ -1131,13 +1160,25 @@ func (p *printer) file(src *ast.File) {
p.print(src.Pos(), token.PACKAGE, blank); p.print(src.Pos(), token.PACKAGE, blank);
p.expr(src.Name); p.expr(src.Name);
for _, d := range src.Decls { if p.mode & Reverse != 0 {
p.print(newline, newline); for i := len(src.Decls)-1; i >= 0; i-- {
comment, _ := p.decl(d); d := src.Decls[i];
if p.optSemis() { p.print(newline, newline);
p.print(token.SEMICOLON); comment, _ := p.decl(d);
if p.optSemis() {
p.print(token.SEMICOLON);
}
p.lineComment(comment);
}
} else {
for _, d := range src.Decls {
p.print(newline, newline);
comment, _ := p.decl(d);
if p.optSemis() {
p.print(token.SEMICOLON);
}
p.lineComment(comment);
} }
p.lineComment(comment);
} }
p.print(newline); p.print(newline);
...@@ -1181,7 +1222,10 @@ func Fprint(output io.Writer, node interface{}, mode uint, tabwidth int) (int, o ...@@ -1181,7 +1222,10 @@ func Fprint(output io.Writer, node interface{}, mode uint, tabwidth int) (int, o
comment, _ := p.decl(n); comment, _ := p.decl(n);
p.lineComment(comment); // no newline at end p.lineComment(comment); // no newline at end
case *ast.File: case *ast.File:
p.comment = n.Comments; if mode & Reverse == 0 {
// don't print comments in reverse mode
p.comment = n.Comments;
}
p.file(n); p.file(n);
default: default:
p.errors <- os.NewError("unsupported node type"); p.errors <- os.NewError("unsupported node type");
......
...@@ -57,3 +57,18 @@ func abs(x int) int { ...@@ -57,3 +57,18 @@ func abs(x int) int {
} }
return x return x
} }
func typeswitch(x interface {}) {
switch v := x.(type) {
case bool, int, float:
case string:
default:
}
switch x.(type) {}
switch v0, ok := x.(int); v := x.(type) {}
switch v0, ok := x.(int); x.(type) {
case bool, int, float:
case string:
default:
}
}
...@@ -58,3 +58,24 @@ func abs(x int) int { ...@@ -58,3 +58,24 @@ func abs(x int) int {
} }
return x; return x;
} }
func typeswitch(x interface{}) {
switch v := x.(type) {
case bool, int, float:
case string:
default:
}
switch x.(type) {
}
switch v0, ok := x.(int); v := x.(type) {
}
switch v0, ok := x.(int); x.(type) {
case bool, int, float:
case string:
default:
}
}
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