mirror of
https://github.com/golang/go.git
synced 2025-12-08 06:10:04 +00:00
cmd/compile/internal/syntax: add position info for { and } braces
This change adds position information for { and } braces in the
source. There's a 1.9% increase in memory use for syntax.Nodes,
which is negligible relative to overall compiler memory consumption.
Parsing the std library (using syntax package only) and memory
consumption before this change (fastest of 5 runs):
$ go test -run StdLib -fast
parsed 1516827 lines (3392 files) in 780.612335ms (1943124 lines/s)
allocated 379.903Mb (486.673Mb/s)
After this change (fastest 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)
While not an exact apples-to-apples comparison (the syntax package
has changed and is also parsed), the overall impact is small.
Also: Small improvements to nodes_test.go.
Change-Id: Ib8a7f90bbe79de33d83684e33b1bf8dbc32e644a
Reviewed-on: https://go-review.googlesource.com/38435
Reviewed-by: Matthew Dempsky <mdempsky@google.com>
This commit is contained in:
parent
ec51234014
commit
e0329248d5
4 changed files with 95 additions and 74 deletions
|
|
@ -28,10 +28,7 @@ type node struct {
|
||||||
pos src.Pos
|
pos src.Pos
|
||||||
}
|
}
|
||||||
|
|
||||||
func (n *node) Pos() src.Pos {
|
func (n *node) Pos() src.Pos { return n.pos }
|
||||||
return n.pos
|
|
||||||
}
|
|
||||||
|
|
||||||
func (*node) aNode() {}
|
func (*node) aNode() {}
|
||||||
|
|
||||||
// ----------------------------------------------------------------------------
|
// ----------------------------------------------------------------------------
|
||||||
|
|
@ -105,8 +102,8 @@ type (
|
||||||
Name *Name
|
Name *Name
|
||||||
Type *FuncType
|
Type *FuncType
|
||||||
Body []Stmt // nil means no body (forward declaration)
|
Body []Stmt // nil means no body (forward declaration)
|
||||||
|
Lbrace, Rbrace src.Pos
|
||||||
Pragma Pragma // TODO(mdempsky): Cleaner solution.
|
Pragma Pragma // TODO(mdempsky): Cleaner solution.
|
||||||
Rbrace src.Pos // TODO(mdempsky): Cleaner solution.
|
|
||||||
decl
|
decl
|
||||||
}
|
}
|
||||||
)
|
)
|
||||||
|
|
@ -147,7 +144,7 @@ type (
|
||||||
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
|
||||||
Rbrace src.Pos // TODO(mdempsky): Cleaner solution.
|
Lbrace, Rbrace src.Pos
|
||||||
expr
|
expr
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|
@ -161,7 +158,7 @@ type (
|
||||||
FuncLit struct {
|
FuncLit struct {
|
||||||
Type *FuncType
|
Type *FuncType
|
||||||
Body []Stmt
|
Body []Stmt
|
||||||
Rbrace src.Pos // TODO(mdempsky): Cleaner solution.
|
Lbrace, Rbrace src.Pos
|
||||||
expr
|
expr
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|
@ -327,6 +324,7 @@ type (
|
||||||
|
|
||||||
BlockStmt struct {
|
BlockStmt struct {
|
||||||
Body []Stmt
|
Body []Stmt
|
||||||
|
Rbrace src.Pos
|
||||||
stmt
|
stmt
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|
@ -372,6 +370,7 @@ type (
|
||||||
Init SimpleStmt
|
Init SimpleStmt
|
||||||
Cond Expr
|
Cond Expr
|
||||||
Then []Stmt
|
Then []Stmt
|
||||||
|
Lbrace, Rbrace src.Pos // of Then branch
|
||||||
Else Stmt // either *IfStmt or *BlockStmt
|
Else Stmt // either *IfStmt or *BlockStmt
|
||||||
stmt
|
stmt
|
||||||
}
|
}
|
||||||
|
|
@ -381,6 +380,7 @@ type (
|
||||||
Cond Expr
|
Cond Expr
|
||||||
Post SimpleStmt
|
Post SimpleStmt
|
||||||
Body []Stmt
|
Body []Stmt
|
||||||
|
Lbrace, Rbrace src.Pos
|
||||||
stmt
|
stmt
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|
@ -388,11 +388,13 @@ type (
|
||||||
Init SimpleStmt
|
Init SimpleStmt
|
||||||
Tag Expr
|
Tag Expr
|
||||||
Body []*CaseClause
|
Body []*CaseClause
|
||||||
|
Rbrace src.Pos
|
||||||
stmt
|
stmt
|
||||||
}
|
}
|
||||||
|
|
||||||
SelectStmt struct {
|
SelectStmt struct {
|
||||||
Body []*CommClause
|
Body []*CommClause
|
||||||
|
Rbrace src.Pos
|
||||||
stmt
|
stmt
|
||||||
}
|
}
|
||||||
)
|
)
|
||||||
|
|
@ -415,12 +417,14 @@ type (
|
||||||
CaseClause struct {
|
CaseClause struct {
|
||||||
Cases Expr // nil means default clause
|
Cases Expr // nil means default clause
|
||||||
Body []Stmt
|
Body []Stmt
|
||||||
|
Colon src.Pos
|
||||||
node
|
node
|
||||||
}
|
}
|
||||||
|
|
||||||
CommClause struct {
|
CommClause struct {
|
||||||
Comm SimpleStmt // send or receive stmt; nil means default clause
|
Comm SimpleStmt // send or receive stmt; nil means default clause
|
||||||
Body []Stmt
|
Body []Stmt
|
||||||
|
Colon src.Pos
|
||||||
node
|
node
|
||||||
}
|
}
|
||||||
)
|
)
|
||||||
|
|
|
||||||
|
|
@ -145,7 +145,7 @@ var fields = []test{
|
||||||
}
|
}
|
||||||
|
|
||||||
var stmts = []test{
|
var stmts = []test{
|
||||||
{"EmptyStmt", `@;`},
|
{"EmptyStmt", `@`},
|
||||||
|
|
||||||
{"LabeledStmt", `L@:`},
|
{"LabeledStmt", `L@:`},
|
||||||
{"LabeledStmt", `L@: ;`},
|
{"LabeledStmt", `L@: ;`},
|
||||||
|
|
@ -189,44 +189,52 @@ var stmts = []test{
|
||||||
|
|
||||||
{"ReturnStmt", `@return`},
|
{"ReturnStmt", `@return`},
|
||||||
{"ReturnStmt", `@return x`},
|
{"ReturnStmt", `@return x`},
|
||||||
{"ReturnStmt", `@return a, b, c`},
|
{"ReturnStmt", `@return a, b, a + b*f(1, 2, 3)`},
|
||||||
|
|
||||||
{"IfStmt", `@if cond {}`},
|
{"IfStmt", `@if cond {}`},
|
||||||
|
{"IfStmt", `@if cond { f() } else {}`},
|
||||||
|
{"IfStmt", `@if cond { f() } else { g(); h() }`},
|
||||||
{"ForStmt", `@for {}`},
|
{"ForStmt", `@for {}`},
|
||||||
|
{"ForStmt", `@for { f() }`},
|
||||||
{"SwitchStmt", `@switch {}`},
|
{"SwitchStmt", `@switch {}`},
|
||||||
|
{"SwitchStmt", `@switch { default: }`},
|
||||||
|
{"SwitchStmt", `@switch { default: x++ }`},
|
||||||
{"SelectStmt", `@select {}`},
|
{"SelectStmt", `@select {}`},
|
||||||
|
{"SelectStmt", `@select { default: }`},
|
||||||
|
{"SelectStmt", `@select { default: ch <- false }`},
|
||||||
}
|
}
|
||||||
|
|
||||||
var ranges = []test{
|
var ranges = []test{
|
||||||
{"RangeClause", `for @range s {}`},
|
{"RangeClause", `@range s`},
|
||||||
{"RangeClause", `for _, i = @range s {}`},
|
{"RangeClause", `i = @range s`},
|
||||||
{"RangeClause", `for x, i = @range s {}`},
|
{"RangeClause", `i := @range s`},
|
||||||
{"RangeClause", `for _, i := @range s {}`},
|
{"RangeClause", `_, x = @range s`},
|
||||||
{"RangeClause", `for x, i := @range s {}`},
|
{"RangeClause", `i, x = @range s`},
|
||||||
|
{"RangeClause", `_, x := @range s.f`},
|
||||||
|
{"RangeClause", `i, x := @range f(i)`},
|
||||||
}
|
}
|
||||||
|
|
||||||
var guards = []test{
|
var guards = []test{
|
||||||
{"TypeSwitchGuard", `switch x@.(type) {}`},
|
{"TypeSwitchGuard", `x@.(type)`},
|
||||||
{"TypeSwitchGuard", `switch x := x@.(type) {}`},
|
{"TypeSwitchGuard", `x := x@.(type)`},
|
||||||
{"TypeSwitchGuard", `switch a = b; x@.(type) {}`},
|
|
||||||
{"TypeSwitchGuard", `switch a := b; x := x@.(type) {}`},
|
|
||||||
}
|
}
|
||||||
|
|
||||||
var cases = []test{
|
var cases = []test{
|
||||||
{"CaseClause", ` switch { @case x: }`},
|
{"CaseClause", `@case x:`},
|
||||||
{"CaseClause", ` switch { @case x, y, z: }`},
|
{"CaseClause", `@case x, y, z:`},
|
||||||
{"CaseClause", ` switch { @case x == 1, y == 2: }`},
|
{"CaseClause", `@case x == 1, y == 2:`},
|
||||||
{"CaseClause", ` switch { @default: }`},
|
{"CaseClause", `@default:`},
|
||||||
}
|
}
|
||||||
|
|
||||||
var comms = []test{
|
var comms = []test{
|
||||||
{"CommClause", `select { @case <-ch: }`},
|
{"CommClause", `@case <-ch:`},
|
||||||
{"CommClause", `select { @case x <- ch: }`},
|
{"CommClause", `@case x <- ch:`},
|
||||||
{"CommClause", `select { @case x = <-ch: }`},
|
{"CommClause", `@case x = <-ch:`},
|
||||||
{"CommClause", `select { @case x := <-ch: }`},
|
{"CommClause", `@case x := <-ch:`},
|
||||||
{"CommClause", `select { @case x, ok = <-ch: }`},
|
{"CommClause", `@case x, ok = <-ch: f(1, 2, 3)`},
|
||||||
{"CommClause", `select { @case x, ok := <-ch: }`},
|
{"CommClause", `@case x, ok := <-ch: x++`},
|
||||||
{"CommClause", `select { @default: }`},
|
{"CommClause", `@default:`},
|
||||||
|
{"CommClause", `@default: ch <- true`},
|
||||||
}
|
}
|
||||||
|
|
||||||
func TestPos(t *testing.T) {
|
func TestPos(t *testing.T) {
|
||||||
|
|
@ -252,23 +260,23 @@ func TestPos(t *testing.T) {
|
||||||
func(f *File) Node { return f.DeclList[0].(*FuncDecl).Type.ParamList[0] },
|
func(f *File) Node { return f.DeclList[0].(*FuncDecl).Type.ParamList[0] },
|
||||||
)
|
)
|
||||||
|
|
||||||
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[0] },
|
||||||
)
|
)
|
||||||
|
|
||||||
testPos(t, ranges, "package p; func _() { ", " } ",
|
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[0].(*ForStmt).Init.(*RangeClause) },
|
||||||
)
|
)
|
||||||
|
|
||||||
testPos(t, guards, "package p; func _() { ", " } ",
|
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[0].(*SwitchStmt).Tag.(*TypeSwitchGuard) },
|
||||||
)
|
)
|
||||||
|
|
||||||
testPos(t, cases, "package p; func _() { ", " } ",
|
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[0].(*SwitchStmt).Body[0] },
|
||||||
)
|
)
|
||||||
|
|
||||||
testPos(t, comms, "package p; func _() { ", " } ",
|
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[0].(*SelectStmt).Body[0] },
|
||||||
)
|
)
|
||||||
}
|
}
|
||||||
|
|
@ -278,14 +286,14 @@ func testPos(t *testing.T, list []test, prefix, suffix string, extract func(*Fil
|
||||||
// complete source, compute @ position, and strip @ from source
|
// complete source, compute @ position, and strip @ from source
|
||||||
src, index := stripAt(prefix + test.snippet + suffix)
|
src, index := stripAt(prefix + test.snippet + suffix)
|
||||||
if index < 0 {
|
if index < 0 {
|
||||||
t.Errorf("missing @: %s", src)
|
t.Errorf("missing @: %s (%s)", src, test.nodetyp)
|
||||||
continue
|
continue
|
||||||
}
|
}
|
||||||
|
|
||||||
// build syntaxt tree
|
// build syntaxt tree
|
||||||
file, err := ParseBytes(nil, []byte(src), nil, nil, 0)
|
file, err := ParseBytes(nil, []byte(src), nil, nil, 0)
|
||||||
if err != nil {
|
if err != nil {
|
||||||
t.Errorf("parse error: %s: %v", src, err)
|
t.Errorf("parse error: %s: %v (%s)", src, err, test.nodetyp)
|
||||||
continue
|
continue
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|
@ -297,8 +305,8 @@ func testPos(t *testing.T, list []test, prefix, suffix string, extract func(*Fil
|
||||||
}
|
}
|
||||||
|
|
||||||
// verify node position with expected position as indicated by @
|
// verify node position with expected position as indicated by @
|
||||||
if col := int(node.Pos().Col()); col != index+colbase {
|
if pos := int(node.Pos().Col()); pos != index+colbase {
|
||||||
t.Errorf("pos error: %s: col = %d, want %d", src, col, index+colbase)
|
t.Errorf("pos error: %s: pos = %d, want %d (%s)", src, pos, index+colbase, test.nodetyp)
|
||||||
continue
|
continue
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
|
||||||
|
|
@ -480,7 +480,8 @@ func (p *parser) funcDecl() *FuncDecl {
|
||||||
|
|
||||||
f.Name = p.name()
|
f.Name = p.name()
|
||||||
f.Type = p.funcType()
|
f.Type = p.funcType()
|
||||||
if p.got(_Lbrace) {
|
if lbrace := p.pos(); p.got(_Lbrace) {
|
||||||
|
f.Lbrace = lbrace
|
||||||
f.Body = p.funcBody()
|
f.Body = p.funcBody()
|
||||||
f.Rbrace = p.pos()
|
f.Rbrace = p.pos()
|
||||||
p.want(_Rbrace)
|
p.want(_Rbrace)
|
||||||
|
|
@ -703,11 +704,12 @@ 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 p.got(_Lbrace) {
|
if lbrace := p.pos(); p.got(_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.funcBody()
|
||||||
f.Rbrace = p.pos()
|
f.Rbrace = p.pos()
|
||||||
|
|
@ -900,6 +902,7 @@ 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++
|
||||||
|
|
||||||
|
|
@ -1625,6 +1628,7 @@ func (p *parser) blockStmt() *BlockStmt {
|
||||||
s.pos = p.pos()
|
s.pos = p.pos()
|
||||||
p.want(_Lbrace)
|
p.want(_Lbrace)
|
||||||
s.Body = p.stmtList()
|
s.Body = p.stmtList()
|
||||||
|
s.Rbrace = p.pos()
|
||||||
p.want(_Rbrace)
|
p.want(_Rbrace)
|
||||||
|
|
||||||
return s
|
return s
|
||||||
|
|
@ -1653,26 +1657,27 @@ 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 = p.stmtBody("for clause")
|
s.Body, s.Lbrace, s.Rbrace = p.stmtBody("for clause")
|
||||||
|
|
||||||
return s
|
return s
|
||||||
}
|
}
|
||||||
|
|
||||||
// stmtBody parses if and for statement bodies.
|
// stmtBody parses if and for statement bodies.
|
||||||
func (p *parser) stmtBody(context string) []Stmt {
|
func (p *parser) stmtBody(context string) (body []Stmt, lbrace, rbrace src.Pos) {
|
||||||
if trace {
|
if trace {
|
||||||
defer p.trace("stmtBody")()
|
defer p.trace("stmtBody")()
|
||||||
}
|
}
|
||||||
|
|
||||||
|
lbrace = p.pos()
|
||||||
if !p.got(_Lbrace) {
|
if !p.got(_Lbrace) {
|
||||||
p.syntax_error("expecting { after " + context)
|
p.syntax_error("expecting { after " + context)
|
||||||
p.advance(_Name, _Rbrace)
|
p.advance(_Name, _Rbrace)
|
||||||
}
|
}
|
||||||
|
body = p.stmtList()
|
||||||
body := p.stmtList()
|
rbrace = p.pos()
|
||||||
p.want(_Rbrace)
|
p.want(_Rbrace)
|
||||||
|
|
||||||
return body
|
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) {
|
||||||
|
|
@ -1764,7 +1769,7 @@ 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 = p.stmtBody("if clause")
|
s.Then, s.Lbrace, s.Rbrace = p.stmtBody("if clause")
|
||||||
|
|
||||||
if p.got(_Else) {
|
if p.got(_Else) {
|
||||||
switch p.tok {
|
switch p.tok {
|
||||||
|
|
@ -1798,6 +1803,7 @@ func (p *parser) switchStmt() *SwitchStmt {
|
||||||
for p.tok != _EOF && p.tok != _Rbrace {
|
for p.tok != _EOF && p.tok != _Rbrace {
|
||||||
s.Body = append(s.Body, p.caseClause())
|
s.Body = append(s.Body, p.caseClause())
|
||||||
}
|
}
|
||||||
|
s.Rbrace = p.pos()
|
||||||
p.want(_Rbrace)
|
p.want(_Rbrace)
|
||||||
|
|
||||||
return s
|
return s
|
||||||
|
|
@ -1819,6 +1825,7 @@ func (p *parser) selectStmt() *SelectStmt {
|
||||||
for p.tok != _EOF && p.tok != _Rbrace {
|
for p.tok != _EOF && p.tok != _Rbrace {
|
||||||
s.Body = append(s.Body, p.commClause())
|
s.Body = append(s.Body, p.commClause())
|
||||||
}
|
}
|
||||||
|
s.Rbrace = p.pos()
|
||||||
p.want(_Rbrace)
|
p.want(_Rbrace)
|
||||||
|
|
||||||
return s
|
return s
|
||||||
|
|
@ -1845,6 +1852,7 @@ func (p *parser) caseClause() *CaseClause {
|
||||||
p.advance(_Case, _Default, _Rbrace)
|
p.advance(_Case, _Default, _Rbrace)
|
||||||
}
|
}
|
||||||
|
|
||||||
|
c.Colon = p.pos()
|
||||||
p.want(_Colon)
|
p.want(_Colon)
|
||||||
c.Body = p.stmtList()
|
c.Body = p.stmtList()
|
||||||
|
|
||||||
|
|
@ -1884,6 +1892,7 @@ func (p *parser) commClause() *CommClause {
|
||||||
p.advance(_Case, _Default, _Rbrace)
|
p.advance(_Case, _Default, _Rbrace)
|
||||||
}
|
}
|
||||||
|
|
||||||
|
c.Colon = p.pos()
|
||||||
p.want(_Colon)
|
p.want(_Colon)
|
||||||
c.Body = p.stmtList()
|
c.Body = p.stmtList()
|
||||||
|
|
||||||
|
|
|
||||||
|
|
@ -81,7 +81,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 (%.3fMb/s)\n", dm, dm/dt.Seconds())
|
fmt.Printf("allocated %.3fMb (%dB/line, %.3fMb/s)\n", dm, uint64(dm*(1<<20)/float64(lines)), dm/dt.Seconds())
|
||||||
}
|
}
|
||||||
|
|
||||||
func walkDirs(t *testing.T, dir string, action func(string)) {
|
func walkDirs(t *testing.T, dir string, action func(string)) {
|
||||||
|
|
|
||||||
Loading…
Add table
Add a link
Reference in a new issue