...

Source file src/cuelang.org/go/internal/core/adt/errors.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  // This file contains error encodings.
    18  //
    19  //
    20  // *Bottom:
    21  //    - an adt.Value
    22  //    - always belongs to a single vertex.
    23  //    - does NOT implement error
    24  //    - marks error code used for control flow
    25  //
    26  // errors.Error
    27  //    - CUE default error
    28  //    - implements error
    29  //    - tracks error locations
    30  //    - has error message details
    31  //    - supports multiple errors
    32  //
    33  
    34  import (
    35  	"cuelang.org/go/cue/ast"
    36  	"cuelang.org/go/cue/errors"
    37  	cueformat "cuelang.org/go/cue/format"
    38  	"cuelang.org/go/cue/token"
    39  )
    40  
    41  // ErrorCode indicates the type of error. The type of error may influence
    42  // control flow. No other aspects of an error may influence control flow.
    43  type ErrorCode int8
    44  
    45  const (
    46  	// An EvalError is a fatal evaluation error.
    47  	EvalError ErrorCode = iota
    48  
    49  	// A UserError is a fatal error originating from the user.
    50  	UserError
    51  
    52  	// StructuralCycleError means a structural cycle was found. Structural
    53  	// cycles are permanent errors, but they are not passed up recursively,
    54  	// as a unification of a value with a structural cycle with one that
    55  	// doesn't may still give a useful result.
    56  	StructuralCycleError
    57  
    58  	// IncompleteError means an evaluation could not complete because of
    59  	// insufficient information that may still be added later.
    60  	IncompleteError
    61  
    62  	// A CycleError indicates a reference error. It is considered to be
    63  	// an incomplete error, as reference errors may be broken by providing
    64  	// a concrete value.
    65  	CycleError
    66  )
    67  
    68  func (c ErrorCode) String() string {
    69  	switch c {
    70  	case EvalError:
    71  		return "eval"
    72  	case UserError:
    73  		return "user"
    74  	case StructuralCycleError:
    75  		return "structural cycle"
    76  	case IncompleteError:
    77  		return "incomplete"
    78  	case CycleError:
    79  		return "cycle"
    80  	}
    81  	return "unknown"
    82  }
    83  
    84  // Bottom represents an error or bottom symbol.
    85  //
    86  // Although a Bottom node holds control data, it should not be created until the
    87  // control information already resulted in an error.
    88  type Bottom struct {
    89  	Src ast.Node
    90  	Err errors.Error
    91  
    92  	Code ErrorCode
    93  	// Permanent indicates whether an incomplete error can be
    94  	// resolved later without making the configuration more specific.
    95  	// This may happen when an arc isn't fully resolved yet.
    96  	Permanent    bool
    97  	HasRecursive bool
    98  	ChildError   bool // Err is the error of the child
    99  	NotExists    bool // This error originated from a failed lookup.
   100  	ForCycle     bool // this is a for cycle
   101  	// Value holds the computed value so far in case
   102  	Value Value
   103  }
   104  
   105  func (x *Bottom) Source() ast.Node        { return x.Src }
   106  func (x *Bottom) Kind() Kind              { return BottomKind }
   107  func (x *Bottom) Specialize(k Kind) Value { return x } // XXX remove
   108  
   109  func (b *Bottom) IsIncomplete() bool {
   110  	if b == nil {
   111  		return false
   112  	}
   113  	return b.Code == IncompleteError || b.Code == CycleError
   114  }
   115  
   116  // isLiteralBottom reports whether x is an error originating from a user.
   117  func isLiteralBottom(x Expr) bool {
   118  	b, ok := x.(*Bottom)
   119  	return ok && b.Code == UserError
   120  }
   121  
   122  // isError reports whether v is an error or nil.
   123  func isError(v Value) bool {
   124  	if v == nil {
   125  		return true
   126  	}
   127  	_, ok := v.(*Bottom)
   128  	return ok
   129  }
   130  
   131  // isIncomplete reports whether v is associated with an incomplete error.
   132  func isIncomplete(v *Vertex) bool {
   133  	if v == nil {
   134  		return true
   135  	}
   136  	if b, ok := v.BaseValue.(*Bottom); ok {
   137  		return b.IsIncomplete()
   138  	}
   139  	return false
   140  }
   141  
   142  // AddChildError updates x to record an error that occurred in one of
   143  // its descendent arcs. The resulting error will record the worst error code of
   144  // the current error or recursive error.
   145  //
   146  // If x is not already an error, the value is recorded in the error for
   147  // reference.
   148  func (v *Vertex) AddChildError(recursive *Bottom) {
   149  	v.ChildErrors = CombineErrors(nil, v.ChildErrors, recursive)
   150  	if recursive.IsIncomplete() {
   151  		return
   152  	}
   153  	x := v.BaseValue
   154  	err, _ := x.(*Bottom)
   155  	if err == nil {
   156  		v.BaseValue = &Bottom{
   157  			Code:         recursive.Code,
   158  			Value:        v,
   159  			HasRecursive: true,
   160  			ChildError:   true,
   161  			Err:          recursive.Err,
   162  		}
   163  		return
   164  	}
   165  
   166  	err.HasRecursive = true
   167  	if err.Code > recursive.Code {
   168  		err.Code = recursive.Code
   169  	}
   170  
   171  	v.BaseValue = err
   172  }
   173  
   174  // CombineErrors combines two errors that originate at the same Vertex.
   175  func CombineErrors(src ast.Node, x, y Value) *Bottom {
   176  	a, _ := Unwrap(x).(*Bottom)
   177  	b, _ := Unwrap(y).(*Bottom)
   178  
   179  	if a == b && isCyclePlaceholder(a) {
   180  		return a
   181  	}
   182  	switch {
   183  	case a != nil && b != nil:
   184  	case a != nil:
   185  		return a
   186  	case b != nil:
   187  		return b
   188  	default:
   189  		return nil
   190  	}
   191  
   192  	if a.Code != b.Code {
   193  		if a.Code > b.Code {
   194  			a, b = b, a
   195  		}
   196  
   197  		if b.Code >= IncompleteError {
   198  			return a
   199  		}
   200  	}
   201  
   202  	return &Bottom{
   203  		Src:  src,
   204  		Err:  errors.Append(a.Err, b.Err),
   205  		Code: a.Code,
   206  	}
   207  }
   208  
   209  func addPositions(err *ValueError, c Conjunct) {
   210  	switch x := c.x.(type) {
   211  	case *Field:
   212  		// if x.ArcType == ArcRequired {
   213  		err.AddPosition(c.x)
   214  		// }
   215  	case *ConjunctGroup:
   216  		for _, c := range *x {
   217  			addPositions(err, c)
   218  		}
   219  	}
   220  	if c.CloseInfo.closeInfo != nil {
   221  		err.AddPosition(c.CloseInfo.location)
   222  	}
   223  }
   224  
   225  func NewRequiredNotPresentError(ctx *OpContext, v *Vertex) *Bottom {
   226  	saved := ctx.PushArc(v)
   227  	err := ctx.Newf("field is required but not present")
   228  	for _, c := range v.Conjuncts {
   229  		if f, ok := c.x.(*Field); ok && f.ArcType == ArcRequired {
   230  			err.AddPosition(c.x)
   231  		}
   232  		if c.CloseInfo.closeInfo != nil {
   233  			err.AddPosition(c.CloseInfo.location)
   234  		}
   235  	}
   236  
   237  	b := &Bottom{
   238  		Code: IncompleteError,
   239  		Err:  err,
   240  	}
   241  	ctx.PopArc(saved)
   242  	return b
   243  }
   244  
   245  func newRequiredFieldInComprehensionError(ctx *OpContext, x *ForClause, v *Vertex) *Bottom {
   246  	err := ctx.Newf("missing required field in for comprehension: %v", v.Label)
   247  	err.AddPosition(x.Src)
   248  	for _, c := range v.Conjuncts {
   249  		addPositions(err, c)
   250  	}
   251  	return &Bottom{
   252  		Code: IncompleteError,
   253  		Err:  err,
   254  	}
   255  }
   256  
   257  func (v *Vertex) reportFieldIndexError(c *OpContext, pos token.Pos, f Feature) {
   258  	v.reportFieldError(c, pos, f,
   259  		"index out of range [%d] with length %d",
   260  		"undefined field: %s")
   261  }
   262  
   263  func (v *Vertex) reportFieldCycleError(c *OpContext, pos token.Pos, f Feature) *Bottom {
   264  	const msg = "cyclic reference to field %[1]v"
   265  	b := v.reportFieldError(c, pos, f, msg, msg)
   266  	return b
   267  }
   268  
   269  func (v *Vertex) reportFieldError(c *OpContext, pos token.Pos, f Feature, intMsg, stringMsg string) *Bottom {
   270  	code := IncompleteError
   271  	if !v.Accept(c, f) {
   272  		code = EvalError
   273  	}
   274  
   275  	label := f.SelectorString(c.Runtime)
   276  
   277  	var err errors.Error
   278  	if f.IsInt() {
   279  		err = c.NewPosf(pos, intMsg, f.Index(), len(v.Elems()))
   280  	} else {
   281  		err = c.NewPosf(pos, stringMsg, label)
   282  	}
   283  	b := &Bottom{
   284  		Code: code,
   285  		Err:  err,
   286  	}
   287  	// TODO: yield failure
   288  	c.AddBottom(b) // TODO: unify error mechanism.
   289  	return b
   290  }
   291  
   292  // A ValueError is returned as a result of evaluating a value.
   293  type ValueError struct {
   294  	r      Runtime
   295  	v      *Vertex
   296  	pos    token.Pos
   297  	auxpos []token.Pos
   298  	errors.Message
   299  }
   300  
   301  func (v *ValueError) AddPosition(n Node) {
   302  	if n == nil {
   303  		return
   304  	}
   305  	if p := pos(n); p != token.NoPos {
   306  		for _, q := range v.auxpos {
   307  			if p == q {
   308  				return
   309  			}
   310  		}
   311  		v.auxpos = append(v.auxpos, p)
   312  	}
   313  }
   314  
   315  func (v *ValueError) AddClosedPositions(c CloseInfo) {
   316  	for s := c.closeInfo; s != nil; s = s.parent {
   317  		if loc := s.location; loc != nil {
   318  			v.AddPosition(loc)
   319  		}
   320  	}
   321  }
   322  
   323  func (c *OpContext) errNode() *Vertex {
   324  	return c.vertex
   325  }
   326  
   327  // MarkPositions marks the current position stack.
   328  func (c *OpContext) MarkPositions() int {
   329  	return len(c.positions)
   330  }
   331  
   332  // ReleasePositions sets the position state to one from a call to MarkPositions.
   333  func (c *OpContext) ReleasePositions(p int) {
   334  	c.positions = c.positions[:p]
   335  }
   336  
   337  func (c *OpContext) AddPosition(n Node) {
   338  	if n != nil {
   339  		c.positions = append(c.positions, n)
   340  	}
   341  }
   342  
   343  func (c *OpContext) Newf(format string, args ...interface{}) *ValueError {
   344  	return c.NewPosf(c.pos(), format, args...)
   345  }
   346  
   347  func appendNodePositions(a []token.Pos, n Node) []token.Pos {
   348  	if p := pos(n); p != token.NoPos {
   349  		a = append(a, p)
   350  	}
   351  	if v, ok := n.(*Vertex); ok {
   352  		for _, c := range v.Conjuncts {
   353  			switch x := c.x.(type) {
   354  			case *ConjunctGroup:
   355  				for _, c := range *x {
   356  					a = appendNodePositions(a, c.Elem())
   357  				}
   358  
   359  			default:
   360  				a = appendNodePositions(a, c.Elem())
   361  			}
   362  		}
   363  	}
   364  	return a
   365  }
   366  
   367  func (c *OpContext) NewPosf(p token.Pos, format string, args ...interface{}) *ValueError {
   368  	var a []token.Pos
   369  	if len(c.positions) > 0 {
   370  		a = make([]token.Pos, 0, len(c.positions))
   371  		for _, n := range c.positions {
   372  			a = appendNodePositions(a, n)
   373  		}
   374  	}
   375  	for i, arg := range args {
   376  		switch x := arg.(type) {
   377  		case Node:
   378  			a = appendNodePositions(a, x)
   379  			args[i] = c.Str(x)
   380  		case ast.Node:
   381  			b, _ := cueformat.Node(x)
   382  			if p := x.Pos(); p != token.NoPos {
   383  				a = append(a, p)
   384  			}
   385  			args[i] = string(b)
   386  		case Feature:
   387  			args[i] = x.SelectorString(c.Runtime)
   388  		}
   389  	}
   390  	return &ValueError{
   391  		r:       c.Runtime,
   392  		v:       c.errNode(),
   393  		pos:     p,
   394  		auxpos:  a,
   395  		Message: errors.NewMessagef(format, args...),
   396  	}
   397  }
   398  
   399  func (e *ValueError) Error() string {
   400  	return errors.String(e)
   401  }
   402  
   403  func (e *ValueError) Position() token.Pos {
   404  	return e.pos
   405  }
   406  
   407  func (e *ValueError) InputPositions() (a []token.Pos) {
   408  	return e.auxpos
   409  }
   410  
   411  func (e *ValueError) Path() (a []string) {
   412  	if e.v == nil {
   413  		return nil
   414  	}
   415  	for _, f := range appendPath(nil, e.v) {
   416  		a = append(a, f.SelectorString(e.r))
   417  	}
   418  	return a
   419  }
   420  

View as plain text