github.com/joomcode/cue@v0.4.4-0.20221111115225-539fe3512047/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  	var label Value
    44  
    45  	if int64(f.Index()) == MaxIndex {
    46  		f = 0
    47  	} else if o.types&HasComplexPattern != 0 && f.IsString() {
    48  		label = f.ToValue(c)
    49  	}
    50  
    51  	if len(o.Bulk) > 0 {
    52  		bulkEnv := *env
    53  		bulkEnv.DynamicLabel = f
    54  		bulkEnv.Deref = nil
    55  		bulkEnv.Cycles = nil
    56  
    57  		// match bulk optional fields / pattern properties
    58  		for _, b := range o.Bulk {
    59  			// if matched && f.additional {
    60  			// 	continue
    61  			// }
    62  			if matchBulk(c, env, b, f, label) {
    63  				matched = true
    64  				info := closeInfo.SpawnSpan(b.Value, ConstraintSpan)
    65  				arc.AddConjunct(MakeConjunct(&bulkEnv, b, info))
    66  			}
    67  		}
    68  	}
    69  
    70  	if matched || len(o.Additional) == 0 {
    71  		return
    72  	}
    73  
    74  	addEnv := *env
    75  	addEnv.Deref = nil
    76  	addEnv.Cycles = nil
    77  
    78  	// match others
    79  	for _, x := range o.Additional {
    80  		info := closeInfo
    81  		if _, ok := x.expr().(*Top); !ok {
    82  			info = info.SpawnSpan(x, ConstraintSpan)
    83  		}
    84  		// TODO: consider moving in above block (2 lines up).
    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  	v = Unwrap(v)
    94  
    95  	// Fast-track certain cases.
    96  	switch x := v.(type) {
    97  	case *Bottom:
    98  		if c.errs == nil {
    99  			c.AddBottom(x)
   100  		}
   101  		return false
   102  	case *Top:
   103  		return true
   104  
   105  	case *BasicType:
   106  		return x.K&StringKind != 0
   107  
   108  	case *BoundValue:
   109  		switch x.Kind() {
   110  		case StringKind:
   111  			if label == nil {
   112  				return false
   113  			}
   114  			str := label.(*String).Str
   115  			return x.validateStr(c, str)
   116  
   117  		case IntKind:
   118  			return x.validateInt(c, int64(f.Index()))
   119  		}
   120  	}
   121  
   122  	if label == nil {
   123  		return false
   124  	}
   125  
   126  	n := Vertex{}
   127  	m := MakeRootConjunct(env, v)
   128  	n.AddConjunct(m)
   129  	n.AddConjunct(MakeRootConjunct(m.Env, label))
   130  
   131  	c.inConstraint++
   132  	n.Finalize(c)
   133  	c.inConstraint--
   134  
   135  	b, _ := n.BaseValue.(*Bottom)
   136  	return b == nil
   137  }