]> Cypherpunks repositories - gostls13.git/commitdiff
cmd/compile: refactor generic AST walking code
authorMatthew Dempsky <mdempsky@google.com>
Thu, 19 Oct 2017 18:23:12 +0000 (11:23 -0700)
committerMatthew Dempsky <mdempsky@google.com>
Thu, 19 Oct 2017 20:06:45 +0000 (20:06 +0000)
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>
src/cmd/compile/internal/gc/racewalk.go
src/cmd/compile/internal/gc/syntax.go

index 4a4c4126c0fe431a15f2304b7b8353f3a1fd1bd8..2ffd0f96a8f8a5d01ad68d160dabbcb670d4be1a 100644 (file)
@@ -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) {
index 3640eb73811db43734bfa6e94c8da7ffff10912f..68067bf1b36230933a2964dac1ac9bfd6b0c7dcb 100644 (file)
@@ -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)
+       }
+}