...

Source file src/cuelang.org/go/internal/core/subsume/subsume.go

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

     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 subsume defines various subsumption relations.
    16  package subsume
    17  
    18  import (
    19  	"cuelang.org/go/cue/errors"
    20  	"cuelang.org/go/internal"
    21  	"cuelang.org/go/internal/core/adt"
    22  )
    23  
    24  // Profile configures the type of subsumption. One should typically use one
    25  // of the preconfigured profiles.
    26  type Profile struct {
    27  	// Final indicates subsumption should only consider fields that are relevant
    28  	// to data mode, and ignore definitions, hidden fields, pattern constraints
    29  	// and additional constraints.
    30  	Final bool
    31  
    32  	// Defaults indicate that default values should be used for the subsumed
    33  	// value.
    34  	Defaults bool
    35  
    36  	// LeftDefaults indicates that the default value of the subsuming value
    37  	// needs to be taken. This is necessary for simplifications like trim
    38  	// and simplifying disjunctions.
    39  	LeftDefault bool
    40  
    41  	// Ignore optional fields.
    42  	IgnoreOptional bool
    43  
    44  	// IgnoreClosedness ignores closedness of structs and is used for comparing
    45  	// APIs.
    46  	IgnoreClosedness bool
    47  }
    48  
    49  var Simplify = Profile{
    50  	LeftDefault: true,
    51  }
    52  
    53  var CUE = Profile{}
    54  
    55  // Final checks subsumption interpreting the subsumed value as data.
    56  var Final = Profile{
    57  	Final:    true,
    58  	Defaults: true,
    59  }
    60  
    61  // FinalOpen exists as an artifact of the old API. One should probably not use
    62  // this.
    63  var FinalOpen = Profile{
    64  	Final:            true,
    65  	Defaults:         true,
    66  	IgnoreClosedness: true,
    67  }
    68  
    69  // API is subsumption used for APIs.
    70  var API = Profile{
    71  	IgnoreClosedness: true,
    72  }
    73  
    74  // Value subsumes two values based on their logical (evaluated) values.
    75  func Value(ctx *adt.OpContext, a, b adt.Value) errors.Error {
    76  	return CUE.Value(ctx, a, b)
    77  }
    78  
    79  func (p *Profile) Value(ctx *adt.OpContext, a, b adt.Value) errors.Error {
    80  	s := subsumer{ctx: ctx, Profile: *p}
    81  	if !s.values(a, b) {
    82  		return s.getError()
    83  	}
    84  	return nil // ignore errors here even if there are some.
    85  }
    86  
    87  // Check reports whether b is an instance of a.
    88  func (p *Profile) Check(ctx *adt.OpContext, a, b adt.Value) bool {
    89  	s := subsumer{ctx: ctx, Profile: *p}
    90  	return s.values(a, b)
    91  }
    92  
    93  func isBottom(x adt.Node) bool {
    94  	b, _ := x.(*adt.Bottom)
    95  	return b != nil
    96  }
    97  
    98  type subsumer struct {
    99  	ctx  *adt.OpContext
   100  	errs errors.Error
   101  
   102  	Profile
   103  
   104  	inexact bool // If true, the result could be a false negative.
   105  	missing adt.Feature
   106  	gt      adt.Value
   107  	lt      adt.Value
   108  }
   109  
   110  func (s *subsumer) errf(msg string, args ...interface{}) {
   111  	b := s.ctx.NewErrf(msg, args...)
   112  	s.errs = errors.Append(s.errs, b.Err)
   113  }
   114  
   115  func unifyValue(c *adt.OpContext, a, b adt.Value) adt.Value {
   116  	v := &adt.Vertex{}
   117  	v.AddConjunct(adt.MakeRootConjunct(c.Env(0), a))
   118  	v.AddConjunct(adt.MakeRootConjunct(c.Env(0), b))
   119  	x, _ := c.Evaluate(c.Env(0), v)
   120  	return x
   121  }
   122  
   123  func (s *subsumer) getError() (err errors.Error) {
   124  	c := s.ctx
   125  	// src := binSrc(token.NoPos, opUnify, gt, lt)
   126  	if s.gt != nil && s.lt != nil {
   127  		// src := binSrc(token.NoPos, opUnify, s.gt, s.lt)
   128  		if s.missing != 0 {
   129  			s.errf("missing field %q", s.missing.SelectorString(c))
   130  		} else if b, ok := unifyValue(c, s.gt, s.lt).(*adt.Bottom); !ok {
   131  			s.errf("value not an instance")
   132  		} else {
   133  			s.errs = errors.Append(s.errs, b.Err)
   134  		}
   135  	}
   136  	if s.errs == nil {
   137  		s.errf("value not an instance")
   138  	}
   139  	err = s.errs
   140  	if s.inexact {
   141  		err = internal.DecorateError(internal.ErrInexact, err)
   142  	}
   143  	return err
   144  }
   145  

View as plain text