github.com/solo-io/cue@v0.4.7/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  outer:
    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.
    91  func 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  }