...

Source file src/cuelang.org/go/internal/core/adt/optional.go

Documentation: cuelang.org/go/internal/core/adt

     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  }
   152  

View as plain text