1
0
mirror of https://github.com/golang/go synced 2024-10-03 08:11:27 -06:00

the AST walker currently provides no way to find out how the

nodes in the tree are nested with respect to one another.
a simple change to the Visitor interface makes it possible
to do this (for example to maintain a current node-depth, or a
knowledge of the name of the current function).

Visit(nil) is called at the end of a node's children;
this make possible the channel-based interface below,
amongst other possibilities.

It is still just as simple to get the original behaviour - just
return the same Visitor from Visit.

Here are a couple of possible Visitor types.

// closure-based
type FVisitor func(n interface{}) FVisitor
func (f FVisitor) Visit(n interface{}) Visitor {
	return f(n);
}

// channel-based
type CVisitor chan Visit;
type Visit struct {
	node interface{};
	reply chan CVisitor;
};
func (v CVisitor) Visit(n interface{}) Visitor
{
	if n == nil {
		close(v);
	} else {
		reply := make(chan CVisitor);
		v <- Visit{n, reply};
		r := <-reply;
		if r == nil {
			return nil;
		}
		return r;
	}
	return nil;
}

R=gri
CC=rsc
https://golang.org/cl/166047
This commit is contained in:
Roger Peppe 2009-12-07 10:33:45 -08:00 committed by Robert Griesemer
parent ea98e4b5e9
commit 80e17d6797
2 changed files with 61 additions and 57 deletions

View File

@ -508,9 +508,12 @@ func (x *Indexer) visitSpec(spec ast.Spec, isVarDecl bool) {
}
func (x *Indexer) Visit(node interface{}) bool {
func (x *Indexer) Visit(node interface{}) ast.Visitor {
// TODO(gri): methods in interface types are categorized as VarDecl
switch n := node.(type) {
case nil:
return nil
case *ast.Ident:
x.visitIdent(Use, n)
@ -572,10 +575,10 @@ func (x *Indexer) Visit(node interface{}) bool {
// nodes
default:
return true
return x
}
return false;
return nil;
}

View File

@ -6,12 +6,11 @@ package ast
import "fmt"
// A Visitor's Visit method is invoked for each node encountered by Walk.
// If Visit returns true, Walk is invoked for each of the node's children.
//
// If the result visitor w is not nil, Walk visits each of the children
// of node with the visitor w, followed by a call of w.Visit(nil).
type Visitor interface {
Visit(node interface{}) bool;
Visit(node interface{}) (w Visitor);
}
@ -29,34 +28,6 @@ func walkCommentGroup(v Visitor, g *CommentGroup) {
}
func walkFieldList(v Visitor, list []*Field) {
for _, x := range list {
Walk(v, x)
}
}
func walkIdentList(v Visitor, list []*Ident) {
for _, x := range list {
Walk(v, x)
}
}
func walkExprList(v Visitor, list []Expr) {
for _, x := range list {
Walk(v, x)
}
}
func walkStmtList(v Visitor, list []Stmt) {
for _, s := range list {
Walk(v, s)
}
}
func walkBlockStmt(v Visitor, b *BlockStmt) {
if b != nil {
Walk(v, b)
@ -64,12 +35,20 @@ func walkBlockStmt(v Visitor, b *BlockStmt) {
}
// Walk traverses an AST in depth-first order and invokes v.Visit(n) for each
// non-nil node n encountered, starting with node. If v.Visit(n) returns true,
// Walk visits each of the children of n.
// Walk traverses an AST in depth-first order: If node != nil, it
// invokes v.Visit(node). If the visitor w returned by v.Visit(node) is
// not nil, Walk visits each of the children of node with the visitor w,
// followed by a call of w.Visit(nil).
//
// Walk may be called with any of the named ast node types. It also
// accepts arguments of type []*Field, []*Ident, []Expr and []Stmt;
// the respective children are the slice elements.
//
func Walk(v Visitor, node interface{}) {
if node == nil || !v.Visit(node) {
if node == nil {
return
}
if v = v.Visit(node); v == nil {
return
}
@ -93,7 +72,7 @@ func Walk(v Visitor, node interface{}) {
case *Field:
walkCommentGroup(v, n.Doc);
walkIdentList(v, n.Names);
Walk(v, n.Names);
Walk(v, n.Type);
for _, x := range n.Tag {
Walk(v, x)
@ -117,7 +96,7 @@ func Walk(v Visitor, node interface{}) {
case *CompositeLit:
Walk(v, n.Type);
walkExprList(v, n.Elts);
Walk(v, n.Elts);
case *ParenExpr:
Walk(v, n.X)
@ -141,7 +120,7 @@ func Walk(v Visitor, node interface{}) {
case *CallExpr:
Walk(v, n.Fun);
walkExprList(v, n.Args);
Walk(v, n.Args);
case *StarExpr:
Walk(v, n.X)
@ -163,14 +142,14 @@ func Walk(v Visitor, node interface{}) {
Walk(v, n.Elt);
case *StructType:
walkFieldList(v, n.Fields)
Walk(v, n.Fields)
case *FuncType:
walkFieldList(v, n.Params);
walkFieldList(v, n.Results);
Walk(v, n.Params);
Walk(v, n.Results);
case *InterfaceType:
walkFieldList(v, n.Methods)
Walk(v, n.Methods)
case *MapType:
Walk(v, n.Key);
@ -200,8 +179,8 @@ func Walk(v Visitor, node interface{}) {
Walk(v, n.X)
case *AssignStmt:
walkExprList(v, n.Lhs);
walkExprList(v, n.Rhs);
Walk(v, n.Lhs);
Walk(v, n.Rhs);
case *GoStmt:
if n.Call != nil {
@ -214,13 +193,13 @@ func Walk(v Visitor, node interface{}) {
}
case *ReturnStmt:
walkExprList(v, n.Results)
Walk(v, n.Results)
case *BranchStmt:
walkIdent(v, n.Label)
case *BlockStmt:
walkStmtList(v, n.List)
Walk(v, n.List)
case *IfStmt:
Walk(v, n.Init);
@ -229,8 +208,8 @@ func Walk(v Visitor, node interface{}) {
Walk(v, n.Else);
case *CaseClause:
walkExprList(v, n.Values);
walkStmtList(v, n.Body);
Walk(v, n.Values);
Walk(v, n.Body);
case *SwitchStmt:
Walk(v, n.Init);
@ -238,8 +217,8 @@ func Walk(v Visitor, node interface{}) {
walkBlockStmt(v, n.Body);
case *TypeCaseClause:
walkExprList(v, n.Types);
walkStmtList(v, n.Body);
Walk(v, n.Types);
Walk(v, n.Body);
case *TypeSwitchStmt:
Walk(v, n.Init);
@ -249,7 +228,7 @@ func Walk(v Visitor, node interface{}) {
case *CommClause:
Walk(v, n.Lhs);
Walk(v, n.Rhs);
walkStmtList(v, n.Body);
Walk(v, n.Body);
case *SelectStmt:
walkBlockStmt(v, n.Body)
@ -277,9 +256,9 @@ func Walk(v Visitor, node interface{}) {
case *ValueSpec:
walkCommentGroup(v, n.Doc);
walkIdentList(v, n.Names);
Walk(v, n.Names);
Walk(v, n.Type);
walkExprList(v, n.Values);
Walk(v, n.Values);
walkCommentGroup(v, n.Comment);
case *TypeSpec:
@ -322,8 +301,30 @@ func Walk(v Visitor, node interface{}) {
Walk(v, f)
}
case []*Field:
for _, x := range n {
Walk(v, x)
}
case []*Ident:
for _, x := range n {
Walk(v, x)
}
case []Expr:
for _, x := range n {
Walk(v, x)
}
case []Stmt:
for _, x := range n {
Walk(v, x)
}
default:
fmt.Printf("ast.Walk: unexpected type %T", n);
panic();
}
v.Visit(nil);
}