grawkit/play/vendor/github.com/benhoyt/goawk/internal/ast/walk.go

178 lines
3.3 KiB
Go

package ast
import "fmt"
// Visitor has a Visit method which 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 Node) (w Visitor)
}
// WalkExprList walks a visitor over a list of expression AST nodes
func WalkExprList(v Visitor, exprs []Expr) {
for _, expr := range exprs {
Walk(v, expr)
}
}
// WalkStmtList walks a visitor over a list of statement AST nodes
func WalkStmtList(v Visitor, stmts []Stmt) {
for _, stmt := range stmts {
Walk(v, stmt)
}
}
// Walk traverses an AST in depth-first order: It starts by calling
// v.Visit(node); if node is nil, it does nothing. If the visitor w returned by
// v.Visit(node) is not nil, Walk is invoked recursively with visitor
// w for each of the non-nil children of node, followed by a call of
// w.Visit(nil).
func Walk(v Visitor, node Node) {
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 node types in ast.go)
switch n := node.(type) {
// expressions
case *FieldExpr:
Walk(v, n.Index)
case *NamedFieldExpr:
Walk(v, n.Field)
case *UnaryExpr:
Walk(v, n.Value)
case *BinaryExpr:
Walk(v, n.Left)
Walk(v, n.Right)
case *InExpr:
WalkExprList(v, n.Index)
case *CondExpr:
Walk(v, n.Cond)
Walk(v, n.True)
Walk(v, n.False)
case *NumExpr: // leaf
case *StrExpr: // leaf
case *RegExpr: // leaf
case *VarExpr: // leaf
case *IndexExpr:
WalkExprList(v, n.Index)
case *AssignExpr:
Walk(v, n.Left)
Walk(v, n.Right)
case *AugAssignExpr:
Walk(v, n.Left)
Walk(v, n.Right)
case *IncrExpr:
Walk(v, n.Expr)
case *CallExpr:
WalkExprList(v, n.Args)
case *UserCallExpr:
WalkExprList(v, n.Args)
case *MultiExpr:
WalkExprList(v, n.Exprs)
case *GetlineExpr:
Walk(v, n.Command)
Walk(v, n.Target)
Walk(v, n.File)
case *GroupingExpr:
Walk(v, n.Expr)
// statements
case *PrintStmt:
WalkExprList(v, n.Args)
Walk(v, n.Dest)
case *PrintfStmt:
WalkExprList(v, n.Args)
Walk(v, n.Dest)
case *ExprStmt:
Walk(v, n.Expr)
case *IfStmt:
Walk(v, n.Cond)
WalkStmtList(v, n.Body)
WalkStmtList(v, n.Else)
case *ForStmt:
Walk(v, n.Pre)
Walk(v, n.Cond)
Walk(v, n.Post)
WalkStmtList(v, n.Body)
case *ForInStmt:
WalkStmtList(v, n.Body)
case *WhileStmt:
Walk(v, n.Cond)
WalkStmtList(v, n.Body)
case *DoWhileStmt:
WalkStmtList(v, n.Body)
Walk(v, n.Cond)
case *BreakStmt: // leaf
case *ContinueStmt: // leaf
case *NextStmt: // leaf
case *NextfileStmt: // leaf
case *ExitStmt:
Walk(v, n.Status)
case *DeleteStmt:
WalkExprList(v, n.Index)
case *ReturnStmt:
Walk(v, n.Value)
case *BlockStmt:
WalkStmtList(v, n.Body)
case *Program:
for _, stmts := range n.Begin {
WalkStmtList(v, stmts)
}
for _, action := range n.Actions {
Walk(v, action)
}
for _, function := range n.Functions {
Walk(v, function)
}
for _, stmts := range n.End {
WalkStmtList(v, stmts)
}
case *Action:
WalkExprList(v, n.Pattern)
WalkStmtList(v, n.Stmts)
case *Function:
WalkStmtList(v, n.Body)
default:
panic(fmt.Sprintf("ast.Walk: unexpected node type %T", n))
}
v.Visit(nil)
}