forked from golang/hotime
218 lines
3.9 KiB
Go
218 lines
3.9 KiB
Go
|
package ast
|
||
|
|
||
|
import "fmt"
|
||
|
|
||
|
// Visitor Enter 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 v, followed by a call of the Exit method.
|
||
|
type Visitor interface {
|
||
|
Enter(n Node) (v Visitor)
|
||
|
Exit(n Node)
|
||
|
}
|
||
|
|
||
|
// Walk traverses an AST in depth-first order: It starts by calling
|
||
|
// v.Enter(node); node must not be nil. If the visitor v returned by
|
||
|
// v.Enter(node) is not nil, Walk is invoked recursively with visitor
|
||
|
// v for each of the non-nil children of node, followed by a call
|
||
|
// of v.Exit(node).
|
||
|
func Walk(v Visitor, n Node) {
|
||
|
if n == nil {
|
||
|
return
|
||
|
}
|
||
|
if v = v.Enter(n); v == nil {
|
||
|
return
|
||
|
}
|
||
|
|
||
|
defer v.Exit(n)
|
||
|
|
||
|
switch n := n.(type) {
|
||
|
case *ArrayLiteral:
|
||
|
if n != nil {
|
||
|
for _, ex := range n.Value {
|
||
|
Walk(v, ex)
|
||
|
}
|
||
|
}
|
||
|
case *AssignExpression:
|
||
|
if n != nil {
|
||
|
Walk(v, n.Left)
|
||
|
Walk(v, n.Right)
|
||
|
}
|
||
|
case *BadExpression:
|
||
|
case *BinaryExpression:
|
||
|
if n != nil {
|
||
|
Walk(v, n.Left)
|
||
|
Walk(v, n.Right)
|
||
|
}
|
||
|
case *BlockStatement:
|
||
|
if n != nil {
|
||
|
for _, s := range n.List {
|
||
|
Walk(v, s)
|
||
|
}
|
||
|
}
|
||
|
case *BooleanLiteral:
|
||
|
case *BracketExpression:
|
||
|
if n != nil {
|
||
|
Walk(v, n.Left)
|
||
|
Walk(v, n.Member)
|
||
|
}
|
||
|
case *BranchStatement:
|
||
|
if n != nil {
|
||
|
Walk(v, n.Label)
|
||
|
}
|
||
|
case *CallExpression:
|
||
|
if n != nil {
|
||
|
Walk(v, n.Callee)
|
||
|
for _, a := range n.ArgumentList {
|
||
|
Walk(v, a)
|
||
|
}
|
||
|
}
|
||
|
case *CaseStatement:
|
||
|
if n != nil {
|
||
|
Walk(v, n.Test)
|
||
|
for _, c := range n.Consequent {
|
||
|
Walk(v, c)
|
||
|
}
|
||
|
}
|
||
|
case *CatchStatement:
|
||
|
if n != nil {
|
||
|
Walk(v, n.Parameter)
|
||
|
Walk(v, n.Body)
|
||
|
}
|
||
|
case *ConditionalExpression:
|
||
|
if n != nil {
|
||
|
Walk(v, n.Test)
|
||
|
Walk(v, n.Consequent)
|
||
|
Walk(v, n.Alternate)
|
||
|
}
|
||
|
case *DebuggerStatement:
|
||
|
case *DoWhileStatement:
|
||
|
if n != nil {
|
||
|
Walk(v, n.Test)
|
||
|
Walk(v, n.Body)
|
||
|
}
|
||
|
case *DotExpression:
|
||
|
if n != nil {
|
||
|
Walk(v, n.Left)
|
||
|
}
|
||
|
case *EmptyExpression:
|
||
|
case *EmptyStatement:
|
||
|
case *ExpressionStatement:
|
||
|
if n != nil {
|
||
|
Walk(v, n.Expression)
|
||
|
}
|
||
|
case *ForInStatement:
|
||
|
if n != nil {
|
||
|
Walk(v, n.Into)
|
||
|
Walk(v, n.Source)
|
||
|
Walk(v, n.Body)
|
||
|
}
|
||
|
case *ForStatement:
|
||
|
if n != nil {
|
||
|
Walk(v, n.Initializer)
|
||
|
Walk(v, n.Update)
|
||
|
Walk(v, n.Test)
|
||
|
Walk(v, n.Body)
|
||
|
}
|
||
|
case *FunctionLiteral:
|
||
|
if n != nil {
|
||
|
Walk(v, n.Name)
|
||
|
for _, p := range n.ParameterList.List {
|
||
|
Walk(v, p)
|
||
|
}
|
||
|
Walk(v, n.Body)
|
||
|
}
|
||
|
case *FunctionStatement:
|
||
|
if n != nil {
|
||
|
Walk(v, n.Function)
|
||
|
}
|
||
|
case *Identifier:
|
||
|
case *IfStatement:
|
||
|
if n != nil {
|
||
|
Walk(v, n.Test)
|
||
|
Walk(v, n.Consequent)
|
||
|
Walk(v, n.Alternate)
|
||
|
}
|
||
|
case *LabelledStatement:
|
||
|
if n != nil {
|
||
|
Walk(v, n.Statement)
|
||
|
}
|
||
|
case *NewExpression:
|
||
|
if n != nil {
|
||
|
Walk(v, n.Callee)
|
||
|
for _, a := range n.ArgumentList {
|
||
|
Walk(v, a)
|
||
|
}
|
||
|
}
|
||
|
case *NullLiteral:
|
||
|
case *NumberLiteral:
|
||
|
case *ObjectLiteral:
|
||
|
if n != nil {
|
||
|
for _, p := range n.Value {
|
||
|
Walk(v, p.Value)
|
||
|
}
|
||
|
}
|
||
|
case *Program:
|
||
|
if n != nil {
|
||
|
for _, b := range n.Body {
|
||
|
Walk(v, b)
|
||
|
}
|
||
|
}
|
||
|
case *RegExpLiteral:
|
||
|
case *ReturnStatement:
|
||
|
if n != nil {
|
||
|
Walk(v, n.Argument)
|
||
|
}
|
||
|
case *SequenceExpression:
|
||
|
if n != nil {
|
||
|
for _, e := range n.Sequence {
|
||
|
Walk(v, e)
|
||
|
}
|
||
|
}
|
||
|
case *StringLiteral:
|
||
|
case *SwitchStatement:
|
||
|
if n != nil {
|
||
|
Walk(v, n.Discriminant)
|
||
|
for _, c := range n.Body {
|
||
|
Walk(v, c)
|
||
|
}
|
||
|
}
|
||
|
case *ThisExpression:
|
||
|
case *ThrowStatement:
|
||
|
if n != nil {
|
||
|
Walk(v, n.Argument)
|
||
|
}
|
||
|
case *TryStatement:
|
||
|
if n != nil {
|
||
|
Walk(v, n.Body)
|
||
|
Walk(v, n.Catch)
|
||
|
Walk(v, n.Finally)
|
||
|
}
|
||
|
case *UnaryExpression:
|
||
|
if n != nil {
|
||
|
Walk(v, n.Operand)
|
||
|
}
|
||
|
case *VariableExpression:
|
||
|
if n != nil {
|
||
|
Walk(v, n.Initializer)
|
||
|
}
|
||
|
case *VariableStatement:
|
||
|
if n != nil {
|
||
|
for _, e := range n.List {
|
||
|
Walk(v, e)
|
||
|
}
|
||
|
}
|
||
|
case *WhileStatement:
|
||
|
if n != nil {
|
||
|
Walk(v, n.Test)
|
||
|
Walk(v, n.Body)
|
||
|
}
|
||
|
case *WithStatement:
|
||
|
if n != nil {
|
||
|
Walk(v, n.Object)
|
||
|
Walk(v, n.Body)
|
||
|
}
|
||
|
default:
|
||
|
panic(fmt.Sprintf("Walk: unexpected node type %T", n))
|
||
|
}
|
||
|
}
|