mirror of https://github.com/golang/go.git
cmd/compile: refactor generic AST walking code
racewalk's "foreach" function applies a function to all of a Node's immediate children, but with a non-idiomatic signature. This CL reworks it to recursively iterate over the entire subtree rooted at Node and provides a way to short-circuit iteration. Passes toolstash -cmp for std cmd with -race. Change-Id: I738b73953d608709802c97945b7e0f4e4940d3f4 Reviewed-on: https://go-review.googlesource.com/71911 Run-TryBot: Matthew Dempsky <mdempsky@google.com> TryBot-Result: Gobot Gobot <gobot@golang.org> Reviewed-by: Robert Griesemer <gri@golang.org>
This commit is contained in:
parent
5313d3f236
commit
12c9d753f8
|
|
@ -452,9 +452,15 @@ func callinstr(np **Node, init *Nodes, wr int, skip int) bool {
|
|||
// that has got a pointer inside. Whether it points to
|
||||
// the heap or not is impossible to know at compile time
|
||||
if class == PAUTOHEAP || class == PEXTERN || b.Op == OINDEX || b.Op == ODOTPTR || b.Op == OIND {
|
||||
hascalls := 0
|
||||
foreach(n, hascallspred, &hascalls)
|
||||
if hascalls != 0 {
|
||||
hasCalls := false
|
||||
inspect(n, func(n *Node) bool {
|
||||
switch n.Op {
|
||||
case OCALL, OCALLFUNC, OCALLMETH, OCALLINTER:
|
||||
hasCalls = true
|
||||
}
|
||||
return !hasCalls
|
||||
})
|
||||
if hasCalls {
|
||||
n = detachexpr(n, init)
|
||||
*np = n
|
||||
}
|
||||
|
|
@ -542,34 +548,6 @@ func detachexpr(n *Node, init *Nodes) *Node {
|
|||
return ind
|
||||
}
|
||||
|
||||
func foreachnode(n *Node, f func(*Node, interface{}), c interface{}) {
|
||||
if n != nil {
|
||||
f(n, c)
|
||||
}
|
||||
}
|
||||
|
||||
func foreachlist(l Nodes, f func(*Node, interface{}), c interface{}) {
|
||||
for _, n := range l.Slice() {
|
||||
foreachnode(n, f, c)
|
||||
}
|
||||
}
|
||||
|
||||
func foreach(n *Node, f func(*Node, interface{}), c interface{}) {
|
||||
foreachlist(n.Ninit, f, c)
|
||||
foreachnode(n.Left, f, c)
|
||||
foreachnode(n.Right, f, c)
|
||||
foreachlist(n.List, f, c)
|
||||
foreachlist(n.Nbody, f, c)
|
||||
foreachlist(n.Rlist, f, c)
|
||||
}
|
||||
|
||||
func hascallspred(n *Node, c interface{}) {
|
||||
switch n.Op {
|
||||
case OCALL, OCALLFUNC, OCALLMETH, OCALLINTER:
|
||||
(*c.(*int))++
|
||||
}
|
||||
}
|
||||
|
||||
// appendinit is like addinit in subr.go
|
||||
// but appends rather than prepends.
|
||||
func appendinit(np **Node, init Nodes) {
|
||||
|
|
|
|||
|
|
@ -744,3 +744,23 @@ func (n *Nodes) AppendNodes(n2 *Nodes) {
|
|||
}
|
||||
n2.slice = nil
|
||||
}
|
||||
|
||||
// inspect invokes f on each node in an AST in depth-first order.
|
||||
// If f(n) returns false, inspect skips visiting n's children.
|
||||
func inspect(n *Node, f func(*Node) bool) {
|
||||
if n == nil || !f(n) {
|
||||
return
|
||||
}
|
||||
inspectList(n.Ninit, f)
|
||||
inspect(n.Left, f)
|
||||
inspect(n.Right, f)
|
||||
inspectList(n.List, f)
|
||||
inspectList(n.Nbody, f)
|
||||
inspectList(n.Rlist, f)
|
||||
}
|
||||
|
||||
func inspectList(l Nodes, f func(*Node) bool) {
|
||||
for _, n := range l.Slice() {
|
||||
inspect(n, f)
|
||||
}
|
||||
}
|
||||
|
|
|
|||
Loading…
Reference in New Issue