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 15package 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. 20func (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 28outer: 29 for _, f := range o.Fields { 30 if f.Label == arc.Label { 31 for _, e := range f.Optional { 32 arc.AddConjunct(MakeConjunct(env, e, closeInfo)) 33 } 34 matched = true 35 break outer 36 } 37 } 38 39 f := arc.Label 40 if !f.IsRegular() { 41 return 42 } 43 if int64(f.Index()) == MaxIndex { 44 f = 0 45 } 46 47 var label Value 48 if o.types&HasComplexPattern != 0 && f.IsString() { 49 label = f.ToValue(c) 50 } 51 52 if len(o.Bulk) > 0 { 53 bulkEnv := *env 54 bulkEnv.DynamicLabel = f 55 bulkEnv.Deref = nil 56 bulkEnv.Cycles = nil 57 58 // match bulk optional fields / pattern properties 59 for _, b := range o.Bulk { 60 // if matched && f.additional { 61 // continue 62 // } 63 if matchBulk(c, env, b, f, label) { 64 matched = true 65 info := closeInfo.SpawnSpan(b.Value, ConstraintSpan) 66 arc.AddConjunct(MakeConjunct(&bulkEnv, b, info)) 67 } 68 } 69 } 70 71 if matched || len(o.Additional) == 0 { 72 return 73 } 74 75 addEnv := *env 76 addEnv.Deref = nil 77 addEnv.Cycles = nil 78 79 // match others 80 for _, x := range o.Additional { 81 info := closeInfo 82 if _, ok := x.(*Top); !ok { 83 info = info.SpawnSpan(x, ConstraintSpan) 84 } 85 arc.AddConjunct(MakeConjunct(&addEnv, x, info)) 86 } 87} 88 89// matchBulk reports whether feature f matches the filter of x. It evaluation of 90// the filter is erroneous, it returns false and the error will be set in c. 91func matchBulk(c *OpContext, env *Environment, x *BulkOptionalField, f Feature, label Value) bool { 92 v := env.evalCached(c, x.Filter) 93 94 // Fast-track certain cases. 95 switch x := v.(type) { 96 case *Bottom: 97 if c.errs == nil { 98 c.AddBottom(x) 99 } 100 return false 101 case *Top: 102 return true 103 104 case *BasicType: 105 return x.K&StringKind != 0 106 107 case *BoundValue: 108 switch x.Kind() { 109 case StringKind: 110 if label == nil { 111 return false 112 } 113 str := label.(*String).Str 114 return x.validateStr(c, str) 115 116 case IntKind: 117 return x.validateInt(c, int64(f.Index())) 118 } 119 } 120 121 if label == nil { 122 return false 123 } 124 125 n := Vertex{} 126 m := MakeRootConjunct(env, v) 127 n.AddConjunct(m) 128 n.AddConjunct(MakeRootConjunct(m.Env, label)) 129 130 c.inConstraint++ 131 n.Finalize(c) 132 c.inConstraint-- 133 134 b, _ := n.BaseValue.(*Bottom) 135 return b == nil 136} 137