cuelang.org/go@v0.10.1/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 v := env.evalCached(c, p.Filter) 96 v = Unwrap(v) 97 98 // Fast-track certain cases. 99 switch x := v.(type) { 100 case *Bottom: 101 if x == cycle { 102 err := c.NewPosf(pos(p.Filter), "cyclic pattern constraint") 103 for _, c := range c.vertex.Conjuncts { 104 err.AddPosition(c.Elem()) 105 } 106 c.AddBottom(&Bottom{ 107 Err: err, 108 }) 109 } 110 if c.errs == nil { 111 c.AddBottom(x) 112 } 113 return false 114 case *Top: 115 return true 116 117 case *BasicType: 118 return x.K&StringKind != 0 119 120 case *BoundValue: 121 switch x.Kind() { 122 case StringKind: 123 if label == nil { 124 return false 125 } 126 str := label.(*String).Str 127 return x.validateStr(c, str) 128 129 case IntKind: 130 return x.validateInt(c, int64(f.Index())) 131 } 132 } 133 134 if label == nil { 135 return false 136 } 137 138 n := Vertex{ 139 IsDynamic: true, 140 } 141 m := MakeConjunct(env, v, c.ci) 142 n.AddConjunct(m) 143 n.AddConjunct(MakeConjunct(m.Env, label, c.ci)) 144 145 c.inConstraint++ 146 n.Finalize(c) 147 c.inConstraint-- 148 149 b, _ := n.BaseValue.(*Bottom) 150 return b == nil 151 }