mirror of https://github.com/deuill/grawkit.git
178 lines
3.3 KiB
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)
|
|
}
|