cuelang.org/go@v0.10.1/internal/core/adt/errors.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 // 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 := v.Bottom(); b != nil { 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 // TODO: ideally the core evaluator should not depend on higher 382 // level packages. This will allow the debug packages to be used 383 // more widely. 384 b, _ := cueformat.Node(x) 385 if p := x.Pos(); p != token.NoPos { 386 a = append(a, p) 387 } 388 args[i] = string(b) 389 case Feature: 390 args[i] = x.SelectorString(c.Runtime) 391 } 392 } 393 return &ValueError{ 394 r: c.Runtime, 395 v: c.errNode(), 396 pos: p, 397 auxpos: a, 398 Message: errors.NewMessagef(format, args...), 399 } 400 } 401 402 func (e *ValueError) Error() string { 403 return errors.String(e) 404 } 405 406 func (e *ValueError) Position() token.Pos { 407 return e.pos 408 } 409 410 func (e *ValueError) InputPositions() (a []token.Pos) { 411 return e.auxpos 412 } 413 414 func (e *ValueError) Path() (a []string) { 415 if e.v == nil { 416 return nil 417 } 418 for _, f := range appendPath(nil, e.v) { 419 a = append(a, f.SelectorString(e.r)) 420 } 421 return a 422 }