cuelang.org/go@v0.10.1/cue/ast/walk.go (about) 1 // Copyright 2018 The CUE Authors 2 // 3 // Licensed under the Apache License, Version 2.0 (the "License"); 4 // you may not use this file except in compliance with the License. 5 // You may obtain a copy of the License at 6 // 7 // http://www.apache.org/licenses/LICENSE-2.0 8 // 9 // Unless required by applicable law or agreed to in writing, software 10 // distributed under the License is distributed on an "AS IS" BASIS, 11 // WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. 12 // See the License for the specific language governing permissions and 13 // limitations under the License. 14 15 package ast 16 17 import ( 18 "fmt" 19 ) 20 21 func walkList[N Node](list []N, before func(Node) bool, after func(Node)) { 22 for _, node := range list { 23 Walk(node, before, after) 24 } 25 } 26 27 // Walk traverses an AST in depth-first order: It starts by calling f(node); 28 // node must not be nil. If before returns true, Walk invokes f recursively for 29 // each of the non-nil children of node, followed by a call of after. Both 30 // functions may be nil. If before is nil, it is assumed to always return true. 31 func Walk(node Node, before func(Node) bool, after func(Node)) { 32 if before != nil && !before(node) { 33 return 34 } 35 36 // TODO: record the comment groups and interleave with the values like for 37 // parsing and printing? 38 walkList(Comments(node), before, after) 39 40 // walk children 41 // (the order of the cases matches the order 42 // of the corresponding node types in go) 43 switch n := node.(type) { 44 // Comments and fields 45 case *Comment: 46 // nothing to do 47 48 case *CommentGroup: 49 walkList(n.List, before, after) 50 51 case *Attribute: 52 // nothing to do 53 54 case *Field: 55 Walk(n.Label, before, after) 56 if n.Value != nil { 57 Walk(n.Value, before, after) 58 } 59 walkList(n.Attrs, before, after) 60 61 case *Func: 62 walkList(n.Args, before, after) 63 Walk(n.Ret, before, after) 64 65 case *StructLit: 66 walkList(n.Elts, before, after) 67 68 // Expressions 69 case *BottomLit, *BadExpr, *Ident, *BasicLit: 70 // nothing to do 71 72 case *Interpolation: 73 walkList(n.Elts, before, after) 74 75 case *ListLit: 76 walkList(n.Elts, before, after) 77 78 case *Ellipsis: 79 if n.Type != nil { 80 Walk(n.Type, before, after) 81 } 82 83 case *ParenExpr: 84 Walk(n.X, before, after) 85 86 case *SelectorExpr: 87 Walk(n.X, before, after) 88 Walk(n.Sel, before, after) 89 90 case *IndexExpr: 91 Walk(n.X, before, after) 92 Walk(n.Index, before, after) 93 94 case *SliceExpr: 95 Walk(n.X, before, after) 96 if n.Low != nil { 97 Walk(n.Low, before, after) 98 } 99 if n.High != nil { 100 Walk(n.High, before, after) 101 } 102 103 case *CallExpr: 104 Walk(n.Fun, before, after) 105 walkList(n.Args, before, after) 106 107 case *UnaryExpr: 108 Walk(n.X, before, after) 109 110 case *BinaryExpr: 111 Walk(n.X, before, after) 112 Walk(n.Y, before, after) 113 114 // Declarations 115 case *ImportSpec: 116 if n.Name != nil { 117 Walk(n.Name, before, after) 118 } 119 Walk(n.Path, before, after) 120 121 case *BadDecl: 122 // nothing to do 123 124 case *ImportDecl: 125 walkList(n.Specs, before, after) 126 127 case *EmbedDecl: 128 Walk(n.Expr, before, after) 129 130 case *LetClause: 131 Walk(n.Ident, before, after) 132 Walk(n.Expr, before, after) 133 134 case *Alias: 135 Walk(n.Ident, before, after) 136 Walk(n.Expr, before, after) 137 138 case *Comprehension: 139 walkList(n.Clauses, before, after) 140 Walk(n.Value, before, after) 141 142 // Files and packages 143 case *File: 144 walkList(n.Decls, before, after) 145 146 case *Package: 147 Walk(n.Name, before, after) 148 149 case *ForClause: 150 if n.Key != nil { 151 Walk(n.Key, before, after) 152 } 153 Walk(n.Value, before, after) 154 Walk(n.Source, before, after) 155 156 case *IfClause: 157 Walk(n.Condition, before, after) 158 159 default: 160 panic(fmt.Sprintf("Walk: unexpected node type %T", n)) 161 } 162 163 if after != nil { 164 after(node) 165 } 166 }