aboutsummaryrefslogtreecommitdiff
diff options
context:
space:
mode:
authorAlan Donovan <adonovan@google.com>2024-03-11 17:16:44 -0400
committerGopher Robot <gobot@golang.org>2024-05-15 21:44:50 +0000
commit7730e5b78308b966a1fe913cdd3086c84e0a2e25 (patch)
treed2c34ee8774f50a9a7c4c2a221b7cd715be8719c
parent3c8f9256067bb3917d7cae05cffdb56dc29e4b3c (diff)
downloadgo-7730e5b78308b966a1fe913cdd3086c84e0a2e25.tar.gz
go-7730e5b78308b966a1fe913cdd3086c84e0a2e25.zip
go/ast: add Preorder go1.23 iterator
This CL adds a new function Preorder that makes it easier to iterate over the nodes of a syntax tree. In particular, break, continue, and return retain their usual continuations. Fixes #66339 Change-Id: I438b3c23780c91ed589871ad3b8822d54e8fabc7 Reviewed-on: https://go-review.googlesource.com/c/go/+/570680 Reviewed-by: Robert Findley <rfindley@google.com> Auto-Submit: Alan Donovan <adonovan@google.com> LUCI-TryBot-Result: Go LUCI <golang-scoped@luci-project-accounts.iam.gserviceaccount.com>
-rw-r--r--api/next/66339.txt1
-rw-r--r--doc/next/6-stdlib/99-minor/go/ast/66339.md2
-rw-r--r--src/go/ast/example_test.go35
-rw-r--r--src/go/ast/walk.go22
4 files changed, 59 insertions, 1 deletions
diff --git a/api/next/66339.txt b/api/next/66339.txt
new file mode 100644
index 0000000000..a6b45adcd2
--- /dev/null
+++ b/api/next/66339.txt
@@ -0,0 +1 @@
+pkg go/ast, func Preorder(Node) iter.Seq[Node] #66339
diff --git a/doc/next/6-stdlib/99-minor/go/ast/66339.md b/doc/next/6-stdlib/99-minor/go/ast/66339.md
new file mode 100644
index 0000000000..0eec51ecd6
--- /dev/null
+++ b/doc/next/6-stdlib/99-minor/go/ast/66339.md
@@ -0,0 +1,2 @@
+The new [Preorder] function returns a convenient iterator over all the
+nodes of a syntax tree.
diff --git a/src/go/ast/example_test.go b/src/go/ast/example_test.go
index 4ce42fb153..31b32efece 100644
--- a/src/go/ast/example_test.go
+++ b/src/go/ast/example_test.go
@@ -140,6 +140,41 @@ func main() {
// 61 }
}
+func ExamplePreorder() {
+ src := `
+package p
+
+func f(x, y int) {
+ print(x + y)
+}
+`
+
+ fset := token.NewFileSet()
+ f, err := parser.ParseFile(fset, "", src, 0)
+ if err != nil {
+ panic(err)
+ }
+
+ // Print identifiers in order
+ for n := range ast.Preorder(f) {
+ id, ok := n.(*ast.Ident)
+ if !ok {
+ continue
+ }
+ fmt.Println(id.Name)
+ }
+
+ // Output:
+ // p
+ // f
+ // x
+ // y
+ // int
+ // print
+ // x
+ // y
+}
+
// This example illustrates how to remove a variable declaration
// in a Go program while maintaining correct comment association
// using an ast.CommentMap.
diff --git a/src/go/ast/walk.go b/src/go/ast/walk.go
index 59e6fc174d..0cd604ef1f 100644
--- a/src/go/ast/walk.go
+++ b/src/go/ast/walk.go
@@ -4,7 +4,10 @@
package ast
-import "fmt"
+import (
+ "fmt"
+ "iter"
+)
// A Visitor's Visit method is invoked for each node encountered by [Walk].
// If the result visitor w is not nil, [Walk] visits each of the children
@@ -368,3 +371,20 @@ func (f inspector) Visit(node Node) Visitor {
func Inspect(node Node, f func(Node) bool) {
Walk(inspector(f), node)
}
+
+// Preorder returns an iterator over all the nodes of the syntax tree
+// beneath (and including) the specified root, in depth-first
+// preorder.
+//
+// For greater control over the traversal of each subtree, use [Inspect].
+func Preorder(root Node) iter.Seq[Node] {
+ return func(yield func(Node) bool) {
+ ok := true
+ Inspect(root, func(n Node) bool {
+ if n != nil && !yield(n) {
+ ok = false
+ }
+ return ok
+ })
+ }
+}