This simplifies the code and removes a premature optimization.
It increases the amount of allocated syntax.Node space by ~0.4%
for parsing all of std lib, which is negligible.
Before the change (best of 5 runs):
$ go test -run StdLib -fast
parsed
1517022 lines (3394 files) in 793.487886ms (
1911840 lines/s)
allocated 387.086Mb (267B/line, 487.828Mb/s)
After the change (best of 5 runs):
$ go test -run StdLib -fast
parsed
1516911 lines (3392 files) in 805.028655ms (
1884294 lines/s)
allocated 388.466Mb (268B/line, 482.549Mb/s)
Change-Id: Id19d6210fdc62393862ba3b04913352d95c599be
Reviewed-on: https://go-review.googlesource.com/38439
Run-TryBot: Robert Griesemer <gri@golang.org>
TryBot-Result: Gobot Gobot <gobot@golang.org>
Reviewed-by: Matthew Dempsky <mdempsky@google.com>
var body []*Node
if fun.Body != nil {
- body = p.stmts(fun.Body)
+ body = p.stmts(fun.Body.List)
if body == nil {
body = []*Node{p.nod(fun, OEMPTY, nil, nil)}
}
yyerror("go:nosplit and go:systemstack cannot be combined")
}
f.Func.Pragma = pragma
- lineno = Ctxt.PosTable.XPos(fun.Rbrace)
+ var rbrace src.Pos
+ if fun.Body != nil {
+ rbrace = fun.Body.Rbrace
+ }
+ lineno = Ctxt.PosTable.XPos(rbrace)
f.Func.Endlineno = lineno
funcbody(f)
return p.nod(expr, OKEY, p.expr(expr.Key), p.wrapname(expr.Value, p.expr(expr.Value)))
case *syntax.FuncLit:
closurehdr(p.typeExpr(expr.Type))
- body := p.stmts(expr.Body)
- lineno = Ctxt.PosTable.XPos(expr.Rbrace)
+ body := p.stmts(expr.Body.List)
+ lineno = Ctxt.PosTable.XPos(expr.Body.Rbrace)
return p.setlineno(expr, closurebody(body))
case *syntax.ParenExpr:
return p.nod(expr, OPAREN, p.expr(expr.X), nil)
case *syntax.LabeledStmt:
return p.labeledStmt(stmt)
case *syntax.BlockStmt:
- return p.body(stmt.Body)
+ l := p.blockStmt(stmt)
+ if len(l) == 0 {
+ // TODO(mdempsky): Line number?
+ return nod(OEMPTY, nil, nil)
+ }
+ return liststmt(l)
case *syntax.ExprStmt:
return p.wrapname(stmt, p.expr(stmt.X))
case *syntax.SendStmt:
panic("unhandled Stmt")
}
-func (p *noder) body(body []syntax.Stmt) *Node {
- l := p.bodyList(body)
- if len(l) == 0 {
- // TODO(mdempsky): Line number?
- return nod(OEMPTY, nil, nil)
- }
- return liststmt(l)
-}
-
-func (p *noder) bodyList(body []syntax.Stmt) []*Node {
+func (p *noder) blockStmt(stmt *syntax.BlockStmt) []*Node {
markdcl()
- nodes := p.stmts(body)
+ nodes := p.stmts(stmt.List)
popdcl()
return nodes
}
if stmt.Cond != nil {
n.Left = p.expr(stmt.Cond)
}
- n.Nbody.Set(p.bodyList(stmt.Then))
+ n.Nbody.Set(p.blockStmt(stmt.Then))
if stmt.Else != nil {
e := p.stmt(stmt.Else)
if e.Op == OBLOCK && e.Ninit.Len() == 0 {
n.Right = p.stmt(stmt.Post)
}
}
- n.Nbody.Set(p.bodyList(stmt.Body))
+ n.Nbody.Set(p.blockStmt(stmt.Body))
popdcl()
return n
}
// func Receiver Name Type { Body }
// func Receiver Name Type
FuncDecl struct {
- Attr map[string]bool // go:attr map
- Recv *Field // nil means regular function
- Name *Name
- Type *FuncType
- Body []Stmt // nil means no body (forward declaration)
- Lbrace, Rbrace src.Pos
- Pragma Pragma // TODO(mdempsky): Cleaner solution.
+ Attr map[string]bool // go:attr map
+ Recv *Field // nil means regular function
+ Name *Name
+ Type *FuncType
+ Body *BlockStmt // nil means no body (forward declaration)
+ Pragma Pragma // TODO(mdempsky): Cleaner solution.
decl
}
)
// Type { ElemList[0], ElemList[1], ... }
CompositeLit struct {
- Type Expr // nil means no literal type
- ElemList []Expr
- NKeys int // number of elements with keys
- Lbrace, Rbrace src.Pos
+ Type Expr // nil means no literal type
+ ElemList []Expr
+ NKeys int // number of elements with keys
+ Rbrace src.Pos
expr
}
// func Type { Body }
FuncLit struct {
- Type *FuncType
- Body []Stmt
- Lbrace, Rbrace src.Pos
+ Type *FuncType
+ Body *BlockStmt
expr
}
}
BlockStmt struct {
- Body []Stmt
+ List []Stmt
Rbrace src.Pos
stmt
}
}
IfStmt struct {
- Init SimpleStmt
- Cond Expr
- Then []Stmt
- Lbrace, Rbrace src.Pos // of Then branch
- Else Stmt // either *IfStmt or *BlockStmt
+ Init SimpleStmt
+ Cond Expr
+ Then *BlockStmt
+ Else Stmt // either *IfStmt or *BlockStmt
stmt
}
ForStmt struct {
- Init SimpleStmt // incl. *RangeClause
- Cond Expr
- Post SimpleStmt
- Body []Stmt
- Lbrace, Rbrace src.Pos
+ Init SimpleStmt // incl. *RangeClause
+ Cond Expr
+ Post SimpleStmt
+ Body *BlockStmt
stmt
}
)
testPos(t, stmts, "package p; func _() { ", "; }",
- func(f *File) Node { return f.DeclList[0].(*FuncDecl).Body[0] },
+ func(f *File) Node { return f.DeclList[0].(*FuncDecl).Body.List[0] },
)
testPos(t, ranges, "package p; func _() { for ", " {} }",
- func(f *File) Node { return f.DeclList[0].(*FuncDecl).Body[0].(*ForStmt).Init.(*RangeClause) },
+ func(f *File) Node { return f.DeclList[0].(*FuncDecl).Body.List[0].(*ForStmt).Init.(*RangeClause) },
)
testPos(t, guards, "package p; func _() { switch ", " {} }",
- func(f *File) Node { return f.DeclList[0].(*FuncDecl).Body[0].(*SwitchStmt).Tag.(*TypeSwitchGuard) },
+ func(f *File) Node { return f.DeclList[0].(*FuncDecl).Body.List[0].(*SwitchStmt).Tag.(*TypeSwitchGuard) },
)
testPos(t, cases, "package p; func _() { switch { ", " } }",
- func(f *File) Node { return f.DeclList[0].(*FuncDecl).Body[0].(*SwitchStmt).Body[0] },
+ func(f *File) Node { return f.DeclList[0].(*FuncDecl).Body.List[0].(*SwitchStmt).Body[0] },
)
testPos(t, comms, "package p; func _() { select { ", " } }",
- func(f *File) Node { return f.DeclList[0].(*FuncDecl).Body[0].(*SelectStmt).Body[0] },
+ func(f *File) Node { return f.DeclList[0].(*FuncDecl).Body.List[0].(*SelectStmt).Body[0] },
)
}
f.Name = p.name()
f.Type = p.funcType()
- if lbrace := p.pos(); p.got(_Lbrace) {
- f.Lbrace = lbrace
- f.Body = p.funcBody()
- f.Rbrace = p.pos()
- p.want(_Rbrace)
+ if p.tok == _Lbrace {
+ f.Body = p.blockStmt("")
}
f.Pragma = p.pragma
pos := p.pos()
p.next()
t := p.funcType()
- if lbrace := p.pos(); p.got(_Lbrace) {
+ if p.tok == _Lbrace {
p.xnest++
f := new(FuncLit)
f.pos = pos
- f.Lbrace = lbrace
f.Type = t
- f.Body = p.funcBody()
- f.Rbrace = p.pos()
- p.want(_Rbrace)
+ f.Body = p.blockStmt("")
p.xnest--
return f
x := new(CompositeLit)
x.pos = p.pos()
- x.Lbrace = p.pos()
p.want(_Lbrace)
p.xnest++
return s
}
-func (p *parser) blockStmt() *BlockStmt {
+func (p *parser) blockStmt(context string) *BlockStmt {
if trace {
defer p.trace("blockStmt")()
}
s := new(BlockStmt)
s.pos = p.pos()
- p.want(_Lbrace)
- s.Body = p.stmtList()
+
+ if !p.got(_Lbrace) {
+ p.syntax_error("expecting { after " + context)
+ p.advance(_Name, _Rbrace)
+ // TODO(gri) may be better to return here than to continue (#19663)
+ }
+
+ s.List = p.stmtList()
s.Rbrace = p.pos()
p.want(_Rbrace)
s.pos = p.pos()
s.Init, s.Cond, s.Post = p.header(_For)
- s.Body, s.Lbrace, s.Rbrace = p.stmtBody("for clause")
+ s.Body = p.blockStmt("for clause")
return s
}
-// stmtBody parses if and for statement bodies.
-func (p *parser) stmtBody(context string) (body []Stmt, lbrace, rbrace src.Pos) {
- if trace {
- defer p.trace("stmtBody")()
- }
-
- lbrace = p.pos()
- if !p.got(_Lbrace) {
- p.syntax_error("expecting { after " + context)
- p.advance(_Name, _Rbrace)
- }
- body = p.stmtList()
- rbrace = p.pos()
- p.want(_Rbrace)
-
- return
-}
-
+// TODO(gri) This function is now so heavily influenced by the keyword that
+// it may not make sense anymore to combine all three cases. It
+// may be simpler to just split it up for each statement kind.
func (p *parser) header(keyword token) (init SimpleStmt, cond Expr, post SimpleStmt) {
p.want(keyword)
s.pos = p.pos()
s.Init, s.Cond, _ = p.header(_If)
- s.Then, s.Lbrace, s.Rbrace = p.stmtBody("if clause")
+ s.Then = p.blockStmt("if clause")
if p.got(_Else) {
switch p.tok {
case _If:
s.Else = p.ifStmt()
case _Lbrace:
- s.Else = p.blockStmt()
+ s.Else = p.blockStmt("")
default:
p.syntax_error("else must be followed by if or statement block")
p.advance(_Name, _Rbrace)
default:
p.syntax_error("expecting case or default or }")
- p.advance(_Case, _Default, _Rbrace)
+ p.advance(_Colon, _Case, _Default, _Rbrace)
}
c.Colon = p.pos()
default:
p.syntax_error("expecting case or default or }")
- p.advance(_Case, _Default, _Rbrace)
+ p.advance(_Colon, _Case, _Default, _Rbrace)
}
c.Colon = p.pos()
switch p.tok {
case _Lbrace:
- return p.blockStmt()
+ return p.blockStmt("")
case _Var:
return p.declStmt(p.varDecl)
var verify = flag.Bool("verify", false, "verify idempotent printing")
func TestParse(t *testing.T) {
- _, err := ParseFile(*src_, nil, nil, 0)
- if err != nil {
- t.Fatal(err)
- }
+ ParseFile(*src_, func(err error) { t.Error(err) }, nil, 0)
}
func TestStdLib(t *testing.T) {
dm := float64(m2.TotalAlloc-m1.TotalAlloc) / 1e6
fmt.Printf("parsed %d lines (%d files) in %v (%d lines/s)\n", lines, count, dt, int64(float64(lines)/dt.Seconds()))
- fmt.Printf("allocated %.3fMb (%dB/line, %.3fMb/s)\n", dm, uint64(dm*(1<<20)/float64(lines)), dm/dt.Seconds())
+ fmt.Printf("allocated %.3fMb (%.3fMb/s)\n", dm, dm/dt.Seconds())
}
func walkDirs(t *testing.T, dir string, action func(string)) {
p.print(_Name, n.Value) // _Name requires actual value following immediately
case *FuncLit:
- p.print(n.Type, blank)
- p.printBody(n.Body)
+ p.print(n.Type, blank, n.Body)
case *CompositeLit:
if n.Type != nil {
}
case *BlockStmt:
- p.printBody(n.Body)
+ p.print(_Lbrace)
+ if len(n.List) > 0 {
+ p.print(newline, indent)
+ p.printStmtList(n.List, true)
+ p.print(outdent, newline)
+ }
+ p.print(_Rbrace)
case *IfStmt:
p.print(_If, blank)
if n.Init != nil {
p.print(n.Init, _Semi, blank)
}
- p.print(n.Cond, blank)
- p.printBody(n.Then)
+ p.print(n.Cond, blank, n.Then)
if n.Else != nil {
p.print(blank, _Else, blank, n.Else)
}
p.print(n.Init)
// TODO(gri) clean this up
if _, ok := n.Init.(*RangeClause); ok {
- p.print(blank)
- p.printBody(n.Body)
+ p.print(blank, n.Body)
break
}
}
p.print(n.Post, blank)
}
}
- p.printBody(n.Body)
+ p.print(n.Body)
case *ImportDecl:
if n.Group == nil {
p.print(n.Name)
p.printSignature(n.Type)
if n.Body != nil {
- p.print(blank)
- p.printBody(n.Body)
+ p.print(blank, n.Body)
}
case *printGroup:
}
}
-func (p *printer) printBody(list []Stmt) {
- p.print(_Lbrace)
- if len(list) > 0 {
- p.print(newline, indent)
- p.printStmtList(list, true)
- p.print(outdent, newline)
- }
- p.print(_Rbrace)
-}
-
func (p *printer) printSwitchBody(list []*CaseClause) {
p.print(_Lbrace)
if len(list) > 0 {