87 lines
2.0 KiB
Go
87 lines
2.0 KiB
Go
package ast
|
|
|
|
import "fmt"
|
|
|
|
// A Visitor implements a Visit method, which is invoked for each Expression
|
|
// encountered by Walk.
|
|
// If the result visitor w is not nil, Walk visits each of the children
|
|
// of Expression with the visitor w, followed by a call of w.Visit(nil).
|
|
type Visitor interface {
|
|
Visit(expr Expression) (w Visitor)
|
|
}
|
|
|
|
// Walk traverses an AST in depth-first order: It starts by calling
|
|
// v.Visit(expr); Expression must not be nil. If the visitor w returned by
|
|
// v.Visit(expr) is not nil, Walk is invoked recursively with visitor
|
|
// w for each of the non-nil children of Expression, followed by a call of
|
|
// w.Visit(nil).
|
|
func Walk(v Visitor, expr Expression) {
|
|
if v = v.Visit(expr); v == nil {
|
|
return
|
|
}
|
|
|
|
switch expr := expr.(type) {
|
|
case *ActionExpr:
|
|
Walk(v, expr.Expr)
|
|
case *AndCodeExpr:
|
|
// Nothing to do
|
|
case *AndExpr:
|
|
Walk(v, expr.Expr)
|
|
case *AnyMatcher:
|
|
// Nothing to do
|
|
case *CharClassMatcher:
|
|
// Nothing to do
|
|
case *ChoiceExpr:
|
|
for _, e := range expr.Alternatives {
|
|
Walk(v, e)
|
|
}
|
|
case *Grammar:
|
|
for _, e := range expr.Rules {
|
|
Walk(v, e)
|
|
}
|
|
case *LabeledExpr:
|
|
Walk(v, expr.Expr)
|
|
case *LitMatcher:
|
|
// Nothing to do
|
|
case *NotCodeExpr:
|
|
// Nothing to do
|
|
case *NotExpr:
|
|
Walk(v, expr.Expr)
|
|
case *OneOrMoreExpr:
|
|
Walk(v, expr.Expr)
|
|
case *Rule:
|
|
Walk(v, expr.Expr)
|
|
case *RuleRefExpr:
|
|
// Nothing to do
|
|
case *SeqExpr:
|
|
for _, e := range expr.Exprs {
|
|
Walk(v, e)
|
|
}
|
|
case *StateCodeExpr:
|
|
// Nothing to do
|
|
case *ZeroOrMoreExpr:
|
|
Walk(v, expr.Expr)
|
|
case *ZeroOrOneExpr:
|
|
Walk(v, expr.Expr)
|
|
default:
|
|
panic(fmt.Sprintf("unknown expression type %T", expr))
|
|
}
|
|
}
|
|
|
|
type inspector func(Expression) bool
|
|
|
|
func (f inspector) Visit(expr Expression) Visitor {
|
|
if f(expr) {
|
|
return f
|
|
}
|
|
return nil
|
|
}
|
|
|
|
// Inspect traverses an AST in depth-first order: It starts by calling
|
|
// f(expr); expr must not be nil. If f returns true, Inspect invokes f
|
|
// recursively for each of the non-nil children of expr, followed by a
|
|
// call of f(nil).
|
|
func Inspect(expr Expression, f func(Expression) bool) {
|
|
Walk(inspector(f), expr)
|
|
}
|