cuelang.org/go@v0.10.1/internal/core/dep/mixed.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 package dep 16 17 import ( 18 "fmt" 19 20 "cuelang.org/go/internal/core/adt" 21 ) 22 23 // dynamic visits conjuncts of structs that are defined by the root for all 24 // of its fields, recursively. 25 // 26 // The current algorithm visits all known conjuncts and descends into the 27 // evaluated Vertex. A more correct and more performant algorithm would be to 28 // descend into the conjuncts and evaluate the necessary values, like fields 29 // and comprehension sources. 30 func (v *visitor) dynamic(n *adt.Vertex, top bool) { 31 found := false 32 n.VisitLeafConjuncts(func(c adt.Conjunct) bool { 33 if v.marked[c.Expr()] { 34 found = true 35 return false 36 } 37 return true 38 }) 39 40 if !found { 41 return 42 } 43 44 if v.visit(n, top) != nil { 45 return 46 } 47 48 for _, a := range n.Arcs { 49 if !a.IsDefined(v.ctxt) || a.Label.IsLet() { 50 continue 51 } 52 v.dynamic(a, false) 53 } 54 } 55 56 type marked map[adt.Expr]bool 57 58 // TODO: factor out the below logic as either a low-level dependency analyzer or 59 // some walk functionality. 60 61 // markExpr visits all nodes in an expression to mark dependencies. 62 func (m marked) markExpr(x adt.Expr) { 63 m[x] = true 64 65 switch x := x.(type) { 66 default: 67 68 case nil: 69 case *adt.Vertex: 70 x.VisitLeafConjuncts(func(c adt.Conjunct) bool { 71 m.markExpr(c.Expr()) 72 return true 73 }) 74 75 case *adt.BinaryExpr: 76 if x.Op == adt.AndOp { 77 m.markExpr(x.X) 78 m.markExpr(x.Y) 79 } 80 81 case *adt.StructLit: 82 for _, e := range x.Decls { 83 switch x := e.(type) { 84 case *adt.Field: 85 m.markExpr(x.Value) 86 87 case *adt.BulkOptionalField: 88 m.markExpr(x.Value) 89 90 case *adt.LetField: 91 m.markExpr(x.Value) 92 93 case *adt.DynamicField: 94 m.markExpr(x.Value) 95 96 case *adt.Ellipsis: 97 m.markExpr(x.Value) 98 99 case adt.Expr: 100 m.markExpr(x) 101 102 case *adt.Comprehension: 103 m.markComprehension(x) 104 105 default: 106 panic(fmt.Sprintf("unreachable %T", x)) 107 } 108 } 109 110 case *adt.ListLit: 111 for _, e := range x.Elems { 112 switch x := e.(type) { 113 case adt.Expr: 114 m.markExpr(x) 115 116 case *adt.Comprehension: 117 m.markComprehension(x) 118 119 case *adt.Ellipsis: 120 m.markExpr(x.Value) 121 122 default: 123 panic(fmt.Sprintf("unreachable %T", x)) 124 } 125 } 126 127 case *adt.DisjunctionExpr: 128 for _, d := range x.Values { 129 m.markExpr(d.Val) 130 } 131 } 132 } 133 134 func (m marked) markComprehension(y *adt.Comprehension) { 135 m.markExpr(adt.ToExpr(y.Value)) 136 }