cuelang.org/go@v0.13.0/internal/core/adt/optional.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 adt 16 17 // MatchAndInsert finds matching optional parts for a given Arc and adds its 18 // conjuncts. Bulk fields are only applied if no fields match, and additional 19 // constraints are only added if neither regular nor bulk fields match. 20 func (o *StructInfo) MatchAndInsert(c *OpContext, arc *Vertex) { 21 env := o.Env 22 23 closeInfo := o.CloseInfo 24 closeInfo.IsClosed = false 25 26 // Match normal fields 27 matched := false 28 // TODO: this could be lookup up more efficiently in the outer Vertex now. 29 // Keep this logic for now, though. 30 for _, f := range o.Fields { 31 if f.Label == arc.Label { 32 matched = true 33 break 34 } 35 } 36 37 f := arc.Label 38 if !f.IsRegular() { 39 return 40 } 41 var label Value 42 43 if int64(f.Index()) == MaxIndex { 44 f = 0 45 } else if o.types&HasComplexPattern != 0 && f.IsString() { 46 label = f.ToValue(c) 47 } 48 49 if len(o.Bulk) > 0 { 50 bulkEnv := *env 51 bulkEnv.DynamicLabel = f 52 53 // match bulk optional fields / pattern properties 54 for _, b := range o.Bulk { 55 // if matched && f.additional { 56 // continue 57 // } 58 59 // Mark the current arc as cyclic while evaluating pattern 60 // expressions, but not while adding conjuncts. 61 // TODO: make MatchAndInsert return a list of conjuncts instead? 62 // TODO: it could be that we can set the cycle before calling 63 // MatchAndInsert after the renewed implementation of disjunctions. 64 saved := arc.BaseValue 65 arc.BaseValue = cycle 66 match := matchBulk(c, env, b, f, label) 67 arc.BaseValue = saved 68 69 if match { 70 matched = true 71 info := closeInfo.SpawnSpan(b.Value, ConstraintSpan) 72 arc.AddConjunct(MakeConjunct(&bulkEnv, b, info)) 73 } 74 } 75 } 76 77 if matched || len(o.Additional) == 0 { 78 return 79 } 80 81 // match others 82 for _, x := range o.Additional { 83 info := closeInfo 84 if _, ok := x.expr().(*Top); !ok { 85 info = info.SpawnSpan(x, ConstraintSpan) 86 } 87 // TODO: consider moving in above block (2 lines up). 88 arc.AddConjunct(MakeConjunct(env, x, info)) 89 } 90 } 91 92 // matchBulk reports whether feature f matches the filter of x. It evaluation of 93 // the filter is erroneous, it returns false and the error will be set in c. 94 func matchBulk(c *OpContext, env *Environment, p *BulkOptionalField, f Feature, label Value) bool { 95 unreachableForDev(c) 96 97 v := env.evalCached(c, p.Filter) 98 v = Unwrap(v) 99 100 // Fast-track certain cases. 101 switch x := v.(type) { 102 case *Bottom: 103 if x == cycle { 104 err := c.NewPosf(pos(p.Filter), "cyclic pattern constraint") 105 for _, c := range c.vertex.Conjuncts { 106 err.AddPosition(c.Elem()) 107 } 108 c.AddBottom(&Bottom{ 109 Err: err, 110 Node: c.vertex, 111 }) 112 } 113 if c.errs == nil { 114 c.AddBottom(x) 115 } 116 return false 117 case *Top: 118 return true 119 120 case *BasicType: 121 return x.K&StringKind != 0 122 123 case *BoundValue: 124 switch x.Kind() { 125 case StringKind: 126 if label == nil { 127 return false 128 } 129 str := label.(*String).Str 130 return x.validateStr(c, str) 131 132 case IntKind: 133 return x.validateInt(c, int64(f.Index())) 134 } 135 } 136 137 if label == nil { 138 return false 139 } 140 141 n := Vertex{ 142 IsDynamic: true, 143 } 144 m := MakeConjunct(env, v, c.ci) 145 n.AddConjunct(m) 146 n.AddConjunct(MakeConjunct(m.Env, label, c.ci)) 147 148 c.inConstraint++ 149 n.Finalize(c) 150 c.inConstraint-- 151 152 b, _ := n.BaseValue.(*Bottom) 153 return b == nil 154 }