@ -237,57 +237,80 @@ type VectorMatching struct {
// Visitor allows visiting a Node and its child nodes. The Visit method is
// Visitor allows visiting a Node and its child nodes. The Visit method is
// invoked for each node with the path leading to the node provided additionally.
// invoked for each node with the path leading to the node provided additionally.
// If the result visitor w is not nil, Walk visits each of the children
// If the result visitor w is not nil and no error , Walk visits each of the children
// of node with the visitor w, followed by a call of w.Visit(nil, nil).
// of node with the visitor w, followed by a call of w.Visit(nil, nil).
type Visitor interface {
type Visitor interface {
Visit ( node Node , path [ ] Node ) ( w Visitor )
Visit ( node Node , path [ ] Node ) ( w Visitor , err error )
}
}
// Walk traverses an AST in depth-first order: It starts by calling
// Walk traverses an AST in depth-first order: It starts by calling
// v.Visit(node, path); node must not be nil. If the visitor w returned by
// v.Visit(node, path); node must not be nil. If the visitor w returned by
// v.Visit(node, path) is not nil, Walk is invoked recursively with visitor
// v.Visit(node, path) is not nil and the visitor returns no error, Walk is
// w for each of the non-nil children of node, followed by a call of
// invoked recursively with visitor w for each of the non-nil children of node,
// w.Visit(nil).
// followed by a call of w.Visit(nil), returning an error
// As the tree is descended the path of previous nodes is provided.
// As the tree is descended the path of previous nodes is provided.
func Walk ( v Visitor , node Node , path [ ] Node ) {
func Walk ( v Visitor , node Node , path [ ] Node ) error {
if v = v . Visit ( node , path ) ; v == nil {
var err error
return
if v , err = v . Visit ( node , path ) ; v == nil || err != nil {
return err
}
}
path = append ( path , node )
path = append ( path , node )
switch n := node . ( type ) {
switch n := node . ( type ) {
case Statements :
case Statements :
for _ , s := range n {
for _ , s := range n {
Walk ( v , s , path )
if err := Walk ( v , s , path ) ; err != nil {
return err
}
}
}
case * AlertStmt :
case * AlertStmt :
Walk ( v , n . Expr , path )
if err := Walk ( v , n . Expr , path ) ; err != nil {
return err
}
case * EvalStmt :
case * EvalStmt :
Walk ( v , n . Expr , path )
if err := Walk ( v , n . Expr , path ) ; err != nil {
return err
}
case * RecordStmt :
case * RecordStmt :
Walk ( v , n . Expr , path )
if err := Walk ( v , n . Expr , path ) ; err != nil {
return err
}
case Expressions :
case Expressions :
for _ , e := range n {
for _ , e := range n {
Walk ( v , e , path )
if err := Walk ( v , e , path ) ; err != nil {
return err
}
}
}
case * AggregateExpr :
case * AggregateExpr :
Walk ( v , n . Expr , path )
if err := Walk ( v , n . Expr , path ) ; err != nil {
return err
}
case * BinaryExpr :
case * BinaryExpr :
Walk ( v , n . LHS , path )
if err := Walk ( v , n . LHS , path ) ; err != nil {
Walk ( v , n . RHS , path )
return err
}
if err := Walk ( v , n . RHS , path ) ; err != nil {
return err
}
case * Call :
case * Call :
Walk ( v , n . Args , path )
if err := Walk ( v , n . Args , path ) ; err != nil {
return err
}
case * ParenExpr :
case * ParenExpr :
Walk ( v , n . Expr , path )
if err := Walk ( v , n . Expr , path ) ; err != nil {
return err
}
case * UnaryExpr :
case * UnaryExpr :
Walk ( v , n . Expr , path )
if err := Walk ( v , n . Expr , path ) ; err != nil {
return err
}
case * MatrixSelector , * NumberLiteral , * StringLiteral , * VectorSelector :
case * MatrixSelector , * NumberLiteral , * StringLiteral , * VectorSelector :
// nothing to do
// nothing to do
@ -296,21 +319,23 @@ func Walk(v Visitor, node Node, path []Node) {
panic ( fmt . Errorf ( "promql.Walk: unhandled node type %T" , node ) )
panic ( fmt . Errorf ( "promql.Walk: unhandled node type %T" , node ) )
}
}
v . Visit ( nil , nil )
_ , err = v . Visit ( nil , nil )
return err
}
}
type inspector func ( Node , [ ] Node ) bool
type inspector func ( Node , [ ] Node ) error
func ( f inspector ) Visit ( node Node , path [ ] Node ) Visitor {
func ( f inspector ) Visit ( node Node , path [ ] Node ) ( Visitor , error ) {
if f ( node , path ) {
if err := f ( node , path ) ; err == nil {
return f
return f , nil
} else {
return nil , err
}
}
return nil
}
}
// Inspect traverses an AST in depth-first order: It starts by calling
// Inspect traverses an AST in depth-first order: It starts by calling
// f(node, path); node must not be nil. If f returns true , Inspect invokes f
// f(node, path); node must not be nil. If f returns a nil error , Inspect invokes f
// for all the non-nil children of node, recursively.
// for all the non-nil children of node, recursively.
func Inspect ( node Node , f func ( Node , [ ] Node ) bool ) {
func Inspect ( node Node , f inspector ) {
Walk ( inspector ( f ) , node , nil )
Walk ( inspector ( f ) , node , nil )
}
}