github.com/solo-io/cue@v0.4.7/internal/core/walk/walk.go (about) 1 // Copyright 2020 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 // walk provides functions for visiting the nodes of an ADT tree. 16 package walk 17 18 import ( 19 "fmt" 20 21 "github.com/solo-io/cue/internal/core/adt" 22 ) 23 24 // Features calls f for all features used in x and indicates whether the 25 // feature is used as a reference or not. 26 func Features(x adt.Expr, f func(label adt.Feature, src adt.Node)) { 27 w := Visitor{ 28 Feature: f, 29 } 30 w.Expr(x) 31 } 32 33 type Visitor struct { 34 // TODO: lets really should be special fields 35 letDone map[adt.Expr]bool 36 37 Feature func(f adt.Feature, src adt.Node) 38 Before func(adt.Node) bool 39 } 40 41 func (w *Visitor) init() { 42 if w.letDone == nil { 43 w.letDone = map[adt.Expr]bool{} 44 } 45 } 46 47 func (w *Visitor) Expr(x adt.Expr) { 48 w.init() 49 w.node(x) 50 } 51 52 func (w *Visitor) feature(x adt.Feature, src adt.Node) { 53 if w.Feature != nil { 54 w.Feature(x, src) 55 } 56 } 57 58 func (w *Visitor) node(n adt.Node) { 59 if w.Before != nil && !w.Before(n) { 60 return 61 } 62 63 switch x := n.(type) { 64 case nil: 65 66 // TODO: special-case Vertex? 67 case adt.Value: 68 69 case *adt.ListLit: 70 for _, x := range x.Elems { 71 w.node(x) 72 } 73 74 case *adt.StructLit: 75 for _, x := range x.Decls { 76 w.node(x) 77 } 78 79 case *adt.FieldReference: 80 w.feature(x.Label, x) 81 82 case *adt.ValueReference: 83 w.feature(x.Label, x) 84 85 case *adt.LabelReference: 86 87 case *adt.DynamicReference: 88 89 case *adt.ImportReference: 90 w.feature(x.ImportPath, x) 91 w.feature(x.Label, x) 92 93 case *adt.LetReference: 94 w.feature(x.Label, x) 95 if w.letDone == nil { 96 w.letDone = map[adt.Expr]bool{} 97 } 98 if !w.letDone[x.X] { 99 w.letDone[x.X] = true 100 w.node(x.X) 101 } 102 103 case *adt.SelectorExpr: 104 w.node(x.X) 105 w.feature(x.Sel, x) 106 107 case *adt.IndexExpr: 108 w.node(x.X) 109 w.node(x.Index) 110 111 case *adt.SliceExpr: 112 w.node(x.X) 113 w.node(x.Lo) 114 w.node(x.Hi) 115 w.node(x.Stride) 116 117 case *adt.Interpolation: 118 for _, x := range x.Parts { 119 w.node(x) 120 } 121 122 case *adt.BoundExpr: 123 w.node(x.Expr) 124 125 case *adt.UnaryExpr: 126 w.node(x.X) 127 128 case *adt.BinaryExpr: 129 w.node(x.X) 130 w.node(x.Y) 131 132 case *adt.CallExpr: 133 w.node(x.Fun) 134 for _, arg := range x.Args { 135 w.node(arg) 136 } 137 138 case *adt.DisjunctionExpr: 139 for _, d := range x.Values { 140 w.node(d.Val) 141 } 142 143 // Fields 144 145 case *adt.Ellipsis: 146 if x.Value != nil { 147 w.node(x.Value) 148 } 149 150 case *adt.Field: 151 w.feature(x.Label, x) 152 w.node(x.Value) 153 154 case *adt.OptionalField: 155 w.feature(x.Label, x) 156 w.node(x.Value) 157 158 case *adt.BulkOptionalField: 159 w.node(x.Filter) 160 w.node(x.Value) 161 162 case *adt.DynamicField: 163 w.node(x.Key) 164 w.node(x.Value) 165 166 // Yielders 167 168 case *adt.ForClause: 169 w.feature(x.Key, x) 170 w.feature(x.Value, x) 171 w.node(x.Dst) 172 173 case *adt.IfClause: 174 w.node(x.Condition) 175 w.node(x.Dst) 176 177 case *adt.LetClause: 178 w.feature(x.Label, x) 179 w.node(x.Expr) 180 w.node(x.Dst) 181 182 case *adt.ValueClause: 183 w.node(x.StructLit) 184 185 default: 186 panic(fmt.Sprintf("unknown field %T", x)) 187 } 188 }