89 lines
1.8 KiB
Go
89 lines
1.8 KiB
Go
// Copyright ©2020 The go-latex Authors. All rights reserved.
|
|
// Use of this source code is governed by a BSD-style
|
|
// license that can be found in the LICENSE file.
|
|
|
|
package ast
|
|
|
|
import "fmt"
|
|
|
|
// A Visitor's Visit 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 w, followed by a call of w.Visit(nil).
|
|
type Visitor interface {
|
|
Visit(node Node) (w Visitor)
|
|
}
|
|
|
|
// Walk traverses an AST in depth-first order: It starts by calling
|
|
// v.Visit(node); node must not be nil. 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 v = v.Visit(node); v == nil {
|
|
return
|
|
}
|
|
|
|
switch n := node.(type) {
|
|
case List:
|
|
for _, x := range n {
|
|
Walk(v, x)
|
|
}
|
|
|
|
case *Macro:
|
|
if n.Name != nil {
|
|
Walk(v, n.Name)
|
|
}
|
|
walkNodes(v, n.Args)
|
|
|
|
case *Arg:
|
|
walkNodes(v, n.List)
|
|
|
|
case *OptArg:
|
|
walkNodes(v, n.List)
|
|
|
|
case *Ident:
|
|
// nothing to do.
|
|
|
|
case *MathExpr:
|
|
walkNodes(v, n.List)
|
|
|
|
case *Word, *Literal, *Symbol:
|
|
// nothing to do.
|
|
|
|
case *Sub:
|
|
Walk(v, n.Node)
|
|
|
|
case *Sup:
|
|
Walk(v, n.Node)
|
|
|
|
default:
|
|
panic(fmt.Errorf("unknown ast node %#v (type=%T)", n, n))
|
|
}
|
|
|
|
v.Visit(nil)
|
|
}
|
|
|
|
func walkNodes(v Visitor, nodes []Node) {
|
|
for _, x := range nodes {
|
|
Walk(v, x)
|
|
}
|
|
}
|
|
|
|
type inspector func(Node) bool
|
|
|
|
func (f inspector) Visit(node Node) Visitor {
|
|
if f(node) {
|
|
return f
|
|
}
|
|
return nil
|
|
}
|
|
|
|
// Inspect traverses an AST in depth-first order: It starts by calling
|
|
// f(node); node must not be nil. If f returns true, Inspect invokes f
|
|
// recursively for each of the non-nil children of node, followed by a
|
|
// call of f(nil).
|
|
//
|
|
func Inspect(node Node, f func(Node) bool) {
|
|
Walk(inspector(f), node)
|
|
}
|