Plan 9 from Bell Labs’s /usr/web/sources/contrib/ericvh/go-plan9/src/pkg/go/ast/walk.go

Copyright © 2021 Plan 9 Foundation.
Distributed under the MIT License.
Download the Plan 9 distribution.


// Copyright 2009 The Go Authors. All rights reserved.
// Use of this source code is governed by a BSD-style
// license that can be found in the LICENSE file.

package ast

import "fmt"

// 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
// of node with the visitor w, followed by a call of w.Visit(nil).
type Visitor interface {
	Visit(node interface{}) (w Visitor);
}


func walkIdent(v Visitor, x *Ident) {
	if x != nil {
		Walk(v, x)
	}
}


func walkCommentGroup(v Visitor, g *CommentGroup) {
	if g != nil {
		Walk(v, g)
	}
}


func walkBlockStmt(v Visitor, b *BlockStmt) {
	if b != nil {
		Walk(v, b)
	}
}


// 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 {
		return
	}
	if v = v.Visit(node); v == nil {
		return
	}

	// walk children
	// (the order of the cases matches the order
	// of the corresponding declaration in ast.go)
	switch n := node.(type) {
	// Comments and fields
	case *Comment:
		// nothing to do

	case *CommentGroup:
		for _, c := range n.List {
			Walk(v, c)
		}
		// TODO(gri): Keep comments in a list/vector instead
		// of linking them via Next. Following next will lead
		// to multiple visits and potentially n^2 behavior
		// since Doc and Comments fields point into the global
		// comments list.

	case *Field:
		walkCommentGroup(v, n.Doc);
		Walk(v, n.Names);
		Walk(v, n.Type);
		for _, x := range n.Tag {
			Walk(v, x)
		}
		walkCommentGroup(v, n.Comment);

	// Expressions
	case *BadExpr, *Ident, *Ellipsis, *BasicLit:
		// nothing to do

	case *StringList:
		for _, x := range n.Strings {
			Walk(v, x)
		}

	case *FuncLit:
		if n != nil {
			Walk(v, n.Type)
		}
		walkBlockStmt(v, n.Body);

	case *CompositeLit:
		Walk(v, n.Type);
		Walk(v, n.Elts);

	case *ParenExpr:
		Walk(v, n.X)

	case *SelectorExpr:
		Walk(v, n.X);
		walkIdent(v, n.Sel);

	case *IndexExpr:
		Walk(v, n.X);
		Walk(v, n.Index);

	case *SliceExpr:
		Walk(v, n.X);
		Walk(v, n.Index);
		Walk(v, n.End);

	case *TypeAssertExpr:
		Walk(v, n.X);
		Walk(v, n.Type);

	case *CallExpr:
		Walk(v, n.Fun);
		Walk(v, n.Args);

	case *StarExpr:
		Walk(v, n.X)

	case *UnaryExpr:
		Walk(v, n.X)

	case *BinaryExpr:
		Walk(v, n.X);
		Walk(v, n.Y);

	case *KeyValueExpr:
		Walk(v, n.Key);
		Walk(v, n.Value);

	// Types
	case *ArrayType:
		Walk(v, n.Len);
		Walk(v, n.Elt);

	case *StructType:
		Walk(v, n.Fields)

	case *FuncType:
		Walk(v, n.Params);
		Walk(v, n.Results);

	case *InterfaceType:
		Walk(v, n.Methods)

	case *MapType:
		Walk(v, n.Key);
		Walk(v, n.Value);

	case *ChanType:
		Walk(v, n.Value)

	// Statements
	case *BadStmt:
		// nothing to do

	case *DeclStmt:
		Walk(v, n.Decl)

	case *EmptyStmt:
		// nothing to do

	case *LabeledStmt:
		walkIdent(v, n.Label);
		Walk(v, n.Stmt);

	case *ExprStmt:
		Walk(v, n.X)

	case *IncDecStmt:
		Walk(v, n.X)

	case *AssignStmt:
		Walk(v, n.Lhs);
		Walk(v, n.Rhs);

	case *GoStmt:
		if n.Call != nil {
			Walk(v, n.Call)
		}

	case *DeferStmt:
		if n.Call != nil {
			Walk(v, n.Call)
		}

	case *ReturnStmt:
		Walk(v, n.Results)

	case *BranchStmt:
		walkIdent(v, n.Label)

	case *BlockStmt:
		Walk(v, n.List)

	case *IfStmt:
		Walk(v, n.Init);
		Walk(v, n.Cond);
		walkBlockStmt(v, n.Body);
		Walk(v, n.Else);

	case *CaseClause:
		Walk(v, n.Values);
		Walk(v, n.Body);

	case *SwitchStmt:
		Walk(v, n.Init);
		Walk(v, n.Tag);
		walkBlockStmt(v, n.Body);

	case *TypeCaseClause:
		Walk(v, n.Types);
		Walk(v, n.Body);

	case *TypeSwitchStmt:
		Walk(v, n.Init);
		Walk(v, n.Assign);
		walkBlockStmt(v, n.Body);

	case *CommClause:
		Walk(v, n.Lhs);
		Walk(v, n.Rhs);
		Walk(v, n.Body);

	case *SelectStmt:
		walkBlockStmt(v, n.Body)

	case *ForStmt:
		Walk(v, n.Init);
		Walk(v, n.Cond);
		Walk(v, n.Post);
		walkBlockStmt(v, n.Body);

	case *RangeStmt:
		Walk(v, n.Key);
		Walk(v, n.Value);
		Walk(v, n.X);
		walkBlockStmt(v, n.Body);

	// Declarations
	case *ImportSpec:
		walkCommentGroup(v, n.Doc);
		walkIdent(v, n.Name);
		for _, x := range n.Path {
			Walk(v, x)
		}
		walkCommentGroup(v, n.Comment);

	case *ValueSpec:
		walkCommentGroup(v, n.Doc);
		Walk(v, n.Names);
		Walk(v, n.Type);
		Walk(v, n.Values);
		walkCommentGroup(v, n.Comment);

	case *TypeSpec:
		walkCommentGroup(v, n.Doc);
		walkIdent(v, n.Name);
		Walk(v, n.Type);
		walkCommentGroup(v, n.Comment);

	case *BadDecl:
		// nothing to do

	case *GenDecl:
		walkCommentGroup(v, n.Doc);
		for _, s := range n.Specs {
			Walk(v, s)
		}

	case *FuncDecl:
		walkCommentGroup(v, n.Doc);
		if n.Recv != nil {
			Walk(v, n.Recv)
		}
		walkIdent(v, n.Name);
		if n.Type != nil {
			Walk(v, n.Type)
		}
		walkBlockStmt(v, n.Body);

	// Files and packages
	case *File:
		walkCommentGroup(v, n.Doc);
		walkIdent(v, n.Name);
		for _, d := range n.Decls {
			Walk(v, d)
		}
		walkCommentGroup(v, n.Comments);

	case *Package:
		for _, f := range n.Files {
			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);
}

Bell Labs OSI certified Powered by Plan 9

(Return to Plan 9 Home Page)

Copyright © 2021 Plan 9 Foundation. All Rights Reserved.
Comments to [email protected].