Commit b5f81eae authored by Robert Griesemer's avatar Robert Griesemer

cmd/compile/internal/syntax: replace inlined statement lists with syntax.BlockStmt

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: default avatarMatthew Dempsky <mdempsky@google.com>
parent e0329248
...@@ -297,7 +297,7 @@ func (p *noder) funcDecl(fun *syntax.FuncDecl) *Node { ...@@ -297,7 +297,7 @@ func (p *noder) funcDecl(fun *syntax.FuncDecl) *Node {
var body []*Node var body []*Node
if fun.Body != nil { if fun.Body != nil {
body = p.stmts(fun.Body) body = p.stmts(fun.Body.List)
if body == nil { if body == nil {
body = []*Node{p.nod(fun, OEMPTY, nil, nil)} body = []*Node{p.nod(fun, OEMPTY, nil, nil)}
} }
...@@ -314,7 +314,11 @@ func (p *noder) funcDecl(fun *syntax.FuncDecl) *Node { ...@@ -314,7 +314,11 @@ func (p *noder) funcDecl(fun *syntax.FuncDecl) *Node {
yyerror("go:nosplit and go:systemstack cannot be combined") yyerror("go:nosplit and go:systemstack cannot be combined")
} }
f.Func.Pragma = pragma 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 f.Func.Endlineno = lineno
funcbody(f) funcbody(f)
...@@ -450,8 +454,8 @@ func (p *noder) expr(expr syntax.Expr) *Node { ...@@ -450,8 +454,8 @@ func (p *noder) expr(expr syntax.Expr) *Node {
return p.nod(expr, OKEY, p.expr(expr.Key), p.wrapname(expr.Value, p.expr(expr.Value))) return p.nod(expr, OKEY, p.expr(expr.Key), p.wrapname(expr.Value, p.expr(expr.Value)))
case *syntax.FuncLit: case *syntax.FuncLit:
closurehdr(p.typeExpr(expr.Type)) closurehdr(p.typeExpr(expr.Type))
body := p.stmts(expr.Body) body := p.stmts(expr.Body.List)
lineno = Ctxt.PosTable.XPos(expr.Rbrace) lineno = Ctxt.PosTable.XPos(expr.Body.Rbrace)
return p.setlineno(expr, closurebody(body)) return p.setlineno(expr, closurebody(body))
case *syntax.ParenExpr: case *syntax.ParenExpr:
return p.nod(expr, OPAREN, p.expr(expr.X), nil) return p.nod(expr, OPAREN, p.expr(expr.X), nil)
...@@ -676,7 +680,12 @@ func (p *noder) stmt(stmt syntax.Stmt) *Node { ...@@ -676,7 +680,12 @@ func (p *noder) stmt(stmt syntax.Stmt) *Node {
case *syntax.LabeledStmt: case *syntax.LabeledStmt:
return p.labeledStmt(stmt) return p.labeledStmt(stmt)
case *syntax.BlockStmt: 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: case *syntax.ExprStmt:
return p.wrapname(stmt, p.expr(stmt.X)) return p.wrapname(stmt, p.expr(stmt.X))
case *syntax.SendStmt: case *syntax.SendStmt:
...@@ -781,18 +790,9 @@ func (p *noder) stmt(stmt syntax.Stmt) *Node { ...@@ -781,18 +790,9 @@ func (p *noder) stmt(stmt syntax.Stmt) *Node {
panic("unhandled Stmt") panic("unhandled Stmt")
} }
func (p *noder) body(body []syntax.Stmt) *Node { func (p *noder) blockStmt(stmt *syntax.BlockStmt) []*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 {
markdcl() markdcl()
nodes := p.stmts(body) nodes := p.stmts(stmt.List)
popdcl() popdcl()
return nodes return nodes
} }
...@@ -806,7 +806,7 @@ func (p *noder) ifStmt(stmt *syntax.IfStmt) *Node { ...@@ -806,7 +806,7 @@ func (p *noder) ifStmt(stmt *syntax.IfStmt) *Node {
if stmt.Cond != nil { if stmt.Cond != nil {
n.Left = p.expr(stmt.Cond) n.Left = p.expr(stmt.Cond)
} }
n.Nbody.Set(p.bodyList(stmt.Then)) n.Nbody.Set(p.blockStmt(stmt.Then))
if stmt.Else != nil { if stmt.Else != nil {
e := p.stmt(stmt.Else) e := p.stmt(stmt.Else)
if e.Op == OBLOCK && e.Ninit.Len() == 0 { if e.Op == OBLOCK && e.Ninit.Len() == 0 {
...@@ -848,7 +848,7 @@ func (p *noder) forStmt(stmt *syntax.ForStmt) *Node { ...@@ -848,7 +848,7 @@ func (p *noder) forStmt(stmt *syntax.ForStmt) *Node {
n.Right = p.stmt(stmt.Post) n.Right = p.stmt(stmt.Post)
} }
} }
n.Nbody.Set(p.bodyList(stmt.Body)) n.Nbody.Set(p.blockStmt(stmt.Body))
popdcl() popdcl()
return n return n
} }
......
...@@ -97,13 +97,12 @@ type ( ...@@ -97,13 +97,12 @@ type (
// func Receiver Name Type { Body } // func Receiver Name Type { Body }
// func Receiver Name Type // func Receiver Name Type
FuncDecl struct { FuncDecl struct {
Attr map[string]bool // go:attr map Attr map[string]bool // go:attr map
Recv *Field // nil means regular function Recv *Field // nil means regular function
Name *Name Name *Name
Type *FuncType Type *FuncType
Body []Stmt // nil means no body (forward declaration) Body *BlockStmt // nil means no body (forward declaration)
Lbrace, Rbrace src.Pos Pragma Pragma // TODO(mdempsky): Cleaner solution.
Pragma Pragma // TODO(mdempsky): Cleaner solution.
decl decl
} }
) )
...@@ -141,10 +140,10 @@ type ( ...@@ -141,10 +140,10 @@ type (
// Type { ElemList[0], ElemList[1], ... } // Type { ElemList[0], ElemList[1], ... }
CompositeLit struct { CompositeLit struct {
Type Expr // nil means no literal type Type Expr // nil means no literal type
ElemList []Expr ElemList []Expr
NKeys int // number of elements with keys NKeys int // number of elements with keys
Lbrace, Rbrace src.Pos Rbrace src.Pos
expr expr
} }
...@@ -156,9 +155,8 @@ type ( ...@@ -156,9 +155,8 @@ type (
// func Type { Body } // func Type { Body }
FuncLit struct { FuncLit struct {
Type *FuncType Type *FuncType
Body []Stmt Body *BlockStmt
Lbrace, Rbrace src.Pos
expr expr
} }
...@@ -323,7 +321,7 @@ type ( ...@@ -323,7 +321,7 @@ type (
} }
BlockStmt struct { BlockStmt struct {
Body []Stmt List []Stmt
Rbrace src.Pos Rbrace src.Pos
stmt stmt
} }
...@@ -367,20 +365,18 @@ type ( ...@@ -367,20 +365,18 @@ type (
} }
IfStmt struct { IfStmt struct {
Init SimpleStmt Init SimpleStmt
Cond Expr Cond Expr
Then []Stmt Then *BlockStmt
Lbrace, Rbrace src.Pos // of Then branch Else Stmt // either *IfStmt or *BlockStmt
Else Stmt // either *IfStmt or *BlockStmt
stmt stmt
} }
ForStmt struct { ForStmt struct {
Init SimpleStmt // incl. *RangeClause Init SimpleStmt // incl. *RangeClause
Cond Expr Cond Expr
Post SimpleStmt Post SimpleStmt
Body []Stmt Body *BlockStmt
Lbrace, Rbrace src.Pos
stmt stmt
} }
......
...@@ -261,23 +261,23 @@ func TestPos(t *testing.T) { ...@@ -261,23 +261,23 @@ func TestPos(t *testing.T) {
) )
testPos(t, stmts, "package p; func _() { ", "; }", 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 ", " {} }", 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 ", " {} }", 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 { ", " } }", 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 { ", " } }", 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] },
) )
} }
......
...@@ -480,11 +480,8 @@ func (p *parser) funcDecl() *FuncDecl { ...@@ -480,11 +480,8 @@ func (p *parser) funcDecl() *FuncDecl {
f.Name = p.name() f.Name = p.name()
f.Type = p.funcType() f.Type = p.funcType()
if lbrace := p.pos(); p.got(_Lbrace) { if p.tok == _Lbrace {
f.Lbrace = lbrace f.Body = p.blockStmt("")
f.Body = p.funcBody()
f.Rbrace = p.pos()
p.want(_Rbrace)
} }
f.Pragma = p.pragma f.Pragma = p.pragma
...@@ -704,16 +701,13 @@ func (p *parser) operand(keep_parens bool) Expr { ...@@ -704,16 +701,13 @@ func (p *parser) operand(keep_parens bool) Expr {
pos := p.pos() pos := p.pos()
p.next() p.next()
t := p.funcType() t := p.funcType()
if lbrace := p.pos(); p.got(_Lbrace) { if p.tok == _Lbrace {
p.xnest++ p.xnest++
f := new(FuncLit) f := new(FuncLit)
f.pos = pos f.pos = pos
f.Lbrace = lbrace
f.Type = t f.Type = t
f.Body = p.funcBody() f.Body = p.blockStmt("")
f.Rbrace = p.pos()
p.want(_Rbrace)
p.xnest-- p.xnest--
return f return f
...@@ -902,7 +896,6 @@ func (p *parser) complitexpr() *CompositeLit { ...@@ -902,7 +896,6 @@ func (p *parser) complitexpr() *CompositeLit {
x := new(CompositeLit) x := new(CompositeLit)
x.pos = p.pos() x.pos = p.pos()
x.Lbrace = p.pos()
p.want(_Lbrace) p.want(_Lbrace)
p.xnest++ p.xnest++
...@@ -1619,15 +1612,21 @@ func (p *parser) labeledStmt(label *Name) Stmt { ...@@ -1619,15 +1612,21 @@ func (p *parser) labeledStmt(label *Name) Stmt {
return s return s
} }
func (p *parser) blockStmt() *BlockStmt { func (p *parser) blockStmt(context string) *BlockStmt {
if trace { if trace {
defer p.trace("blockStmt")() defer p.trace("blockStmt")()
} }
s := new(BlockStmt) s := new(BlockStmt)
s.pos = p.pos() 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() s.Rbrace = p.pos()
p.want(_Rbrace) p.want(_Rbrace)
...@@ -1657,29 +1656,14 @@ func (p *parser) forStmt() Stmt { ...@@ -1657,29 +1656,14 @@ func (p *parser) forStmt() Stmt {
s.pos = p.pos() s.pos = p.pos()
s.Init, s.Cond, s.Post = p.header(_For) 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 return s
} }
// stmtBody parses if and for statement bodies. // TODO(gri) This function is now so heavily influenced by the keyword that
func (p *parser) stmtBody(context string) (body []Stmt, lbrace, rbrace src.Pos) { // it may not make sense anymore to combine all three cases. It
if trace { // may be simpler to just split it up for each statement kind.
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
}
func (p *parser) header(keyword token) (init SimpleStmt, cond Expr, post SimpleStmt) { func (p *parser) header(keyword token) (init SimpleStmt, cond Expr, post SimpleStmt) {
p.want(keyword) p.want(keyword)
...@@ -1769,14 +1753,14 @@ func (p *parser) ifStmt() *IfStmt { ...@@ -1769,14 +1753,14 @@ func (p *parser) ifStmt() *IfStmt {
s.pos = p.pos() s.pos = p.pos()
s.Init, s.Cond, _ = p.header(_If) 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) { if p.got(_Else) {
switch p.tok { switch p.tok {
case _If: case _If:
s.Else = p.ifStmt() s.Else = p.ifStmt()
case _Lbrace: case _Lbrace:
s.Else = p.blockStmt() s.Else = p.blockStmt("")
default: default:
p.syntax_error("else must be followed by if or statement block") p.syntax_error("else must be followed by if or statement block")
p.advance(_Name, _Rbrace) p.advance(_Name, _Rbrace)
...@@ -1849,7 +1833,7 @@ func (p *parser) caseClause() *CaseClause { ...@@ -1849,7 +1833,7 @@ func (p *parser) caseClause() *CaseClause {
default: default:
p.syntax_error("expecting case or default or }") p.syntax_error("expecting case or default or }")
p.advance(_Case, _Default, _Rbrace) p.advance(_Colon, _Case, _Default, _Rbrace)
} }
c.Colon = p.pos() c.Colon = p.pos()
...@@ -1889,7 +1873,7 @@ func (p *parser) commClause() *CommClause { ...@@ -1889,7 +1873,7 @@ func (p *parser) commClause() *CommClause {
default: default:
p.syntax_error("expecting case or default or }") p.syntax_error("expecting case or default or }")
p.advance(_Case, _Default, _Rbrace) p.advance(_Colon, _Case, _Default, _Rbrace)
} }
c.Colon = p.pos() c.Colon = p.pos()
...@@ -1926,7 +1910,7 @@ func (p *parser) stmt() Stmt { ...@@ -1926,7 +1910,7 @@ func (p *parser) stmt() Stmt {
switch p.tok { switch p.tok {
case _Lbrace: case _Lbrace:
return p.blockStmt() return p.blockStmt("")
case _Var: case _Var:
return p.declStmt(p.varDecl) return p.declStmt(p.varDecl)
......
...@@ -23,10 +23,7 @@ var src_ = flag.String("src", "parser.go", "source file to parse") ...@@ -23,10 +23,7 @@ var src_ = flag.String("src", "parser.go", "source file to parse")
var verify = flag.Bool("verify", false, "verify idempotent printing") var verify = flag.Bool("verify", false, "verify idempotent printing")
func TestParse(t *testing.T) { func TestParse(t *testing.T) {
_, err := ParseFile(*src_, nil, nil, 0) ParseFile(*src_, func(err error) { t.Error(err) }, nil, 0)
if err != nil {
t.Fatal(err)
}
} }
func TestStdLib(t *testing.T) { func TestStdLib(t *testing.T) {
...@@ -81,7 +78,7 @@ func TestStdLib(t *testing.T) { ...@@ -81,7 +78,7 @@ func TestStdLib(t *testing.T) {
dm := float64(m2.TotalAlloc-m1.TotalAlloc) / 1e6 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("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)) { func walkDirs(t *testing.T, dir string, action func(string)) {
......
...@@ -349,8 +349,7 @@ func (p *printer) printRawNode(n Node) { ...@@ -349,8 +349,7 @@ func (p *printer) printRawNode(n Node) {
p.print(_Name, n.Value) // _Name requires actual value following immediately p.print(_Name, n.Value) // _Name requires actual value following immediately
case *FuncLit: case *FuncLit:
p.print(n.Type, blank) p.print(n.Type, blank, n.Body)
p.printBody(n.Body)
case *CompositeLit: case *CompositeLit:
if n.Type != nil { if n.Type != nil {
...@@ -524,15 +523,20 @@ func (p *printer) printRawNode(n Node) { ...@@ -524,15 +523,20 @@ func (p *printer) printRawNode(n Node) {
} }
case *BlockStmt: 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: case *IfStmt:
p.print(_If, blank) p.print(_If, blank)
if n.Init != nil { if n.Init != nil {
p.print(n.Init, _Semi, blank) p.print(n.Init, _Semi, blank)
} }
p.print(n.Cond, blank) p.print(n.Cond, blank, n.Then)
p.printBody(n.Then)
if n.Else != nil { if n.Else != nil {
p.print(blank, _Else, blank, n.Else) p.print(blank, _Else, blank, n.Else)
} }
...@@ -578,8 +582,7 @@ func (p *printer) printRawNode(n Node) { ...@@ -578,8 +582,7 @@ func (p *printer) printRawNode(n Node) {
p.print(n.Init) p.print(n.Init)
// TODO(gri) clean this up // TODO(gri) clean this up
if _, ok := n.Init.(*RangeClause); ok { if _, ok := n.Init.(*RangeClause); ok {
p.print(blank) p.print(blank, n.Body)
p.printBody(n.Body)
break break
} }
} }
...@@ -592,7 +595,7 @@ func (p *printer) printRawNode(n Node) { ...@@ -592,7 +595,7 @@ func (p *printer) printRawNode(n Node) {
p.print(n.Post, blank) p.print(n.Post, blank)
} }
} }
p.printBody(n.Body) p.print(n.Body)
case *ImportDecl: case *ImportDecl:
if n.Group == nil { if n.Group == nil {
...@@ -650,8 +653,7 @@ func (p *printer) printRawNode(n Node) { ...@@ -650,8 +653,7 @@ func (p *printer) printRawNode(n Node) {
p.print(n.Name) p.print(n.Name)
p.printSignature(n.Type) p.printSignature(n.Type)
if n.Body != nil { if n.Body != nil {
p.print(blank) p.print(blank, n.Body)
p.printBody(n.Body)
} }
case *printGroup: case *printGroup:
...@@ -882,16 +884,6 @@ func (p *printer) printStmtList(list []Stmt, braces bool) { ...@@ -882,16 +884,6 @@ func (p *printer) printStmtList(list []Stmt, braces bool) {
} }
} }
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) { func (p *printer) printSwitchBody(list []*CaseClause) {
p.print(_Lbrace) p.print(_Lbrace)
if len(list) > 0 { if len(list) > 0 {
......
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