cuelang.org/go@v0.10.1/cue/path.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 cue 16 17 import ( 18 "fmt" 19 "math/bits" 20 "strconv" 21 "strings" 22 23 "cuelang.org/go/cue/ast" 24 "cuelang.org/go/cue/errors" 25 "cuelang.org/go/cue/literal" 26 "cuelang.org/go/cue/parser" 27 "cuelang.org/go/cue/token" 28 "cuelang.org/go/internal/astinternal" 29 "cuelang.org/go/internal/core/adt" 30 "github.com/cockroachdb/apd/v3" 31 ) 32 33 // SelectorType represents the kind of a selector. It indicates both the label 34 // type as well as whether it is a constraint or an actual value. 35 type SelectorType uint16 36 37 const ( 38 // StringLabel represents a regular non-definition field. 39 StringLabel SelectorType = 1 << iota 40 // IndexLabel represents a numeric index into an array. 41 IndexLabel 42 // DefinitionLabel represents a definition. 43 DefinitionLabel 44 // HiddenLabel represents a hidden non-definition field. 45 HiddenLabel 46 // HiddenDefinitionLabel represents a hidden definition. 47 HiddenDefinitionLabel 48 49 // OptionalConstraint represents an optional constraint (?). 50 OptionalConstraint 51 // RequiredConstraint represents a required constraint (!). 52 RequiredConstraint 53 // PatternConstraint represents a selector of fields in a struct 54 // or array that match a constraint. 55 PatternConstraint 56 57 InvalidSelectorType SelectorType = 0 58 ) 59 60 // fromArcType reports the constraint type for t. 61 func fromArcType(t adt.ArcType) SelectorType { 62 switch t { 63 case adt.ArcMember: 64 return 0 65 case adt.ArcOptional: 66 return OptionalConstraint 67 case adt.ArcRequired: 68 return RequiredConstraint 69 default: 70 panic("arc type not supported") 71 } 72 } 73 74 // LabelType reports the label type of t. 75 func (t SelectorType) LabelType() SelectorType { 76 return t & 0b0001_1111 77 } 78 79 // ConstraintType reports the constraint type of t. 80 func (t SelectorType) ConstraintType() SelectorType { 81 return t & 0b1110_0000 82 } 83 84 var selectorTypeStrings = [...]string{ 85 "InvalidSelectorType", 86 "StringLabel", 87 "IndexLabel", 88 "DefinitionLabel", 89 "HiddenLabel", 90 "HiddenDefinitionLabel", 91 "OptionalConstraint", 92 "RequiredConstraint", 93 "PatternConstraint", 94 } 95 96 func (t SelectorType) String() string { 97 if t.LabelType() == 0 && t.ConstraintType() == 0 { 98 return "NoLabels" 99 } 100 single := bits.OnesCount16(uint16(t)) == 1 101 var buf strings.Builder 102 for i := range selectorTypeStrings[:len(selectorTypeStrings)-1] { 103 if t&(SelectorType(1)<<i) == 0 { 104 continue 105 } 106 if single { 107 return selectorTypeStrings[i+1] 108 } 109 if buf.Len() > 0 { 110 buf.WriteByte('|') 111 } 112 buf.WriteString(selectorTypeStrings[i+1]) 113 } 114 return buf.String() 115 } 116 117 // IsHidden reports whether t describes a hidden field, regardless of 118 // whether or not this is a constraint. 119 func (t SelectorType) IsHidden() bool { 120 t = t.LabelType() 121 return t == HiddenLabel || t == HiddenDefinitionLabel 122 } 123 124 // IsDefinition reports whether t describes a definition, regardless of 125 // whether or not this is a constraint. 126 func (t SelectorType) IsDefinition() bool { 127 t = t.LabelType() 128 return t == HiddenDefinitionLabel || t == DefinitionLabel 129 } 130 131 // A Selector is a component of a path. 132 type Selector struct { 133 sel selector 134 } 135 136 // String reports the CUE representation of a selector. 137 func (sel Selector) String() string { 138 return sel.sel.String() 139 } 140 141 // Unquoted returns the unquoted value of a string label. 142 // It panics unless sel.LabelType is StringLabel and has a concrete name. 143 func (sel Selector) Unquoted() string { 144 if sel.LabelType() != StringLabel || 145 sel.ConstraintType() >= PatternConstraint { 146 panic("Selector.Unquoted invoked on non-string label") 147 } 148 switch s := sel.sel.(type) { 149 case stringSelector: 150 return string(s) 151 case constraintSelector: 152 return string(s.selector.(stringSelector)) 153 } 154 panic(fmt.Sprintf("unreachable %T", sel.sel)) 155 } 156 157 // IsConstraint reports whether s is optional or a pattern constraint. 158 // Fields that are constraints are considered non-existing and their 159 // values may be erroneous for a configuration to be valid.. 160 func (sel Selector) IsConstraint() bool { 161 return sel.Type().ConstraintType() != 0 162 } 163 164 // IsString reports whether sel represents an optional, required, or regular 165 // member field. 166 func (sel Selector) IsString() bool { 167 // TODO: consider deprecating this method. It is a bit wonkey now. 168 t := sel.Type() 169 t &^= OptionalConstraint | RequiredConstraint 170 return t == StringLabel 171 } 172 173 // IsDefinition reports whether sel is a non-hidden definition and non-constraint label type. 174 func (sel Selector) IsDefinition() bool { 175 return sel.Type().IsDefinition() 176 } 177 178 // Type returns the type of the selector. 179 func (sel Selector) Type() SelectorType { 180 return sel.sel.labelType() | sel.sel.constraintType() 181 } 182 183 // LabelType returns the type of the label part of a selector. 184 func (sel Selector) LabelType() SelectorType { 185 return sel.sel.labelType() 186 } 187 188 // ConstraintType returns the type of the constraint part of a selector. 189 func (sel Selector) ConstraintType() SelectorType { 190 return sel.sel.constraintType() 191 } 192 193 // PkgPath reports the package path associated with a hidden label or "" if 194 // this is not a hidden label. 195 func (sel Selector) PkgPath() string { 196 s, _ := sel.sel.(scopedSelector) 197 return s.pkg 198 } 199 200 // Index returns the index of the selector. It panics 201 // unless sel.Type is IndexLabel. 202 func (sel Selector) Index() int { 203 // Note that lists will eventually have constraint types too, 204 // and in that case sel.sel would be of type constraintSelector, 205 // causing the type assertion below to fail. 206 s, ok := sel.sel.(indexSelector) 207 if !ok { 208 panic("Index called on non-index selector") 209 } 210 return adt.Feature(s).Index() 211 } 212 213 var ( 214 215 // AnyDefinition can be used to ask for any definition. 216 // 217 // In paths it is used to select constraints that apply to all elements. 218 // AnyDefinition = anyDefinition 219 anyDefinition = Selector{sel: anySelector(adt.AnyDefinition)} 220 // AnyIndex can be used to ask for any index. 221 // 222 // In paths it is used to select constraints that apply to all elements. 223 AnyIndex = anyIndex 224 anyIndex = Selector{sel: anySelector(adt.AnyIndex)} 225 226 // AnyString can be used to ask for any regular string field. 227 // 228 // In paths it is used to select constraints that apply to all elements. 229 AnyString = anyString 230 anyString = Selector{sel: anySelector(adt.AnyString)} 231 ) 232 233 // Optional converts sel into an optional constraint equivalent. 234 // It's a no-op if the selector is already optional. 235 // 236 // foo -> foo? 237 // foo! -> foo? 238 func (sel Selector) Optional() Selector { 239 return wrapConstraint(sel, OptionalConstraint) 240 } 241 242 // Required converts sel into a required constraint equivalent. 243 // It's a no-op if the selector is already a required constraint. 244 // 245 // foo -> foo! 246 // foo? -> foo! 247 func (sel Selector) Required() Selector { 248 return wrapConstraint(sel, RequiredConstraint) 249 } 250 251 type selector interface { 252 String() string 253 254 feature(ctx adt.Runtime) adt.Feature 255 labelType() SelectorType 256 constraintType() SelectorType 257 isConstraint() bool 258 } 259 260 // A Path is series of selectors to query a CUE value. 261 type Path struct { 262 path []Selector 263 } 264 265 // MakePath creates a Path from a sequence of selectors. 266 func MakePath(selectors ...Selector) Path { 267 return Path{path: selectors} 268 } 269 270 // pathToString is a utility function for creating debugging info. 271 func pathToStrings(p Path) (a []string) { 272 for _, sel := range p.Selectors() { 273 a = append(a, sel.String()) 274 } 275 return a 276 } 277 278 // ParsePath parses a CUE expression into a Path. Any error resulting from 279 // this conversion can be obtained by calling Err on the result. 280 // 281 // Unlike with normal CUE expressions, the first element of the path may be 282 // a string literal. 283 // 284 // A path may not contain hidden fields. To create a path with hidden fields, 285 // use MakePath and Ident. 286 func ParsePath(s string) Path { 287 if s == "" { 288 return Path{} 289 } 290 expr, err := parser.ParseExpr("", s) 291 if err != nil { 292 return MakePath(Selector{pathError{errors.Promote(err, "invalid path")}}) 293 } 294 295 p := Path{path: toSelectors(expr)} 296 for _, sel := range p.path { 297 if sel.Type().IsHidden() { 298 return MakePath(Selector{pathError{errors.Newf(token.NoPos, 299 "invalid path: hidden fields not allowed in path %s", s)}}) 300 } 301 } 302 return p 303 } 304 305 // Selectors reports the individual selectors of a path. 306 func (p Path) Selectors() []Selector { 307 return p.path 308 } 309 310 // String reports the CUE representation of p. 311 func (p Path) String() string { 312 if err := p.Err(); err != nil { 313 return "_|_" 314 } 315 316 b := &strings.Builder{} 317 for i, sel := range p.path { 318 switch { 319 case sel.Type() == IndexLabel: 320 // TODO: use '.' in all cases, once supported. 321 b.WriteByte('[') 322 b.WriteString(sel.sel.String()) 323 b.WriteByte(']') 324 continue 325 case i > 0: 326 b.WriteByte('.') 327 } 328 329 b.WriteString(sel.sel.String()) 330 } 331 return b.String() 332 } 333 334 // Optional returns the optional form of a Path. For instance, 335 // 336 // foo.bar --> foo?.bar? 337 func (p Path) Optional() Path { 338 q := make([]Selector, 0, len(p.path)) 339 for _, s := range p.path { 340 q = appendSelector(q, wrapConstraint(s, OptionalConstraint)) 341 } 342 return Path{path: q} 343 } 344 345 func toSelectors(expr ast.Expr) []Selector { 346 switch x := expr.(type) { 347 case *ast.Ident: 348 return []Selector{Label(x)} 349 350 case *ast.BasicLit: 351 return []Selector{basicLitSelector(x)} 352 353 case *ast.IndexExpr: 354 a := toSelectors(x.X) 355 var sel Selector 356 if b, ok := x.Index.(*ast.BasicLit); !ok { 357 sel = Selector{pathError{ 358 errors.Newf(token.NoPos, "non-constant expression %s", 359 astinternal.DebugStr(x.Index))}} 360 } else { 361 sel = basicLitSelector(b) 362 } 363 return appendSelector(a, sel) 364 365 case *ast.SelectorExpr: 366 a := toSelectors(x.X) 367 return appendSelector(a, Label(x.Sel)) 368 369 default: 370 return []Selector{{pathError{ 371 errors.Newf(token.NoPos, "invalid label %s ", astinternal.DebugStr(x)), 372 }}} 373 } 374 } 375 376 // appendSelector is like append(a, sel), except that it collects errors 377 // in a one-element slice. 378 func appendSelector(a []Selector, sel Selector) []Selector { 379 err, isErr := sel.sel.(pathError) 380 if len(a) == 1 { 381 if p, ok := a[0].sel.(pathError); ok { 382 if isErr { 383 p.Error = errors.Append(p.Error, err.Error) 384 } 385 return a 386 } 387 } 388 if isErr { 389 return []Selector{sel} 390 } 391 return append(a, sel) 392 } 393 394 func basicLitSelector(b *ast.BasicLit) Selector { 395 switch b.Kind { 396 case token.INT: 397 var n literal.NumInfo 398 if err := literal.ParseNum(b.Value, &n); err != nil { 399 return Selector{pathError{ 400 errors.Newf(token.NoPos, "invalid string index %s", b.Value), 401 }} 402 } 403 var d apd.Decimal 404 _ = n.Decimal(&d) 405 i, err := d.Int64() 406 if err != nil { 407 return Selector{pathError{ 408 errors.Newf(token.NoPos, "integer %s out of range", b.Value), 409 }} 410 } 411 return Index(int(i)) 412 413 case token.STRING: 414 info, _, _, _ := literal.ParseQuotes(b.Value, b.Value) 415 if !info.IsDouble() { 416 return Selector{pathError{ 417 errors.Newf(token.NoPos, "invalid string index %s", b.Value)}} 418 } 419 s, _ := literal.Unquote(b.Value) 420 return Selector{stringSelector(s)} 421 422 default: 423 return Selector{pathError{ 424 errors.Newf(token.NoPos, "invalid literal %s", b.Value), 425 }} 426 } 427 } 428 429 // Label converts an AST label to a Selector. 430 func Label(label ast.Label) Selector { 431 switch x := label.(type) { 432 case *ast.Ident: 433 switch s := x.Name; { 434 case strings.HasPrefix(s, "_"): 435 // TODO: extract package from a bound identifier. 436 return Selector{pathError{errors.Newf(token.NoPos, 437 "invalid path: hidden label %s not allowed", s), 438 }} 439 case strings.HasPrefix(s, "#"): 440 return Selector{definitionSelector(x.Name)} 441 default: 442 return Selector{stringSelector(x.Name)} 443 } 444 445 case *ast.BasicLit: 446 return basicLitSelector(x) 447 448 default: 449 return Selector{pathError{ 450 errors.Newf(token.NoPos, "invalid label %s ", astinternal.DebugStr(x)), 451 }} 452 } 453 } 454 455 // Err reports errors that occurred when generating the path. 456 func (p Path) Err() error { 457 var errs errors.Error 458 for _, x := range p.path { 459 if err, ok := x.sel.(pathError); ok { 460 errs = errors.Append(errs, err.Error) 461 } 462 } 463 return errs 464 } 465 466 func isHiddenOrDefinition(s string) bool { 467 return strings.HasPrefix(s, "#") || strings.HasPrefix(s, "_") 468 } 469 470 // Hid returns a selector for a hidden field. It panics if pkg is empty. 471 // Hidden fields are scoped by package, and pkg indicates for which package 472 // the hidden field must apply. For anonymous packages, it must be set to "_". 473 func Hid(name, pkg string) Selector { 474 if !ast.IsValidIdent(name) { 475 panic(fmt.Sprintf("invalid identifier %s", name)) 476 } 477 if !strings.HasPrefix(name, "_") { 478 panic(fmt.Sprintf("%s is not a hidden field identifier", name)) 479 } 480 if pkg == "" { 481 panic(fmt.Sprintf("missing package for hidden identifier %s", name)) 482 } 483 return Selector{scopedSelector{name, pkg}} 484 } 485 486 type scopedSelector struct { 487 name, pkg string 488 } 489 490 // String returns the CUE representation of the definition. 491 func (s scopedSelector) String() string { 492 return s.name 493 } 494 func (scopedSelector) isConstraint() bool { return false } 495 496 func (s scopedSelector) labelType() SelectorType { 497 if strings.HasPrefix(s.name, "_#") { 498 return HiddenDefinitionLabel 499 } 500 return HiddenLabel 501 } 502 func (s scopedSelector) constraintType() SelectorType { return 0 } 503 504 func (s scopedSelector) feature(r adt.Runtime) adt.Feature { 505 return adt.MakeIdentLabel(r, s.name, s.pkg) 506 } 507 508 // A Def marks a string as a definition label. An # will be added if a string is 509 // not prefixed with a #. It will panic if s cannot be written as a valid 510 // identifier. 511 func Def(s string) Selector { 512 if !strings.HasPrefix(s, "#") && !strings.HasPrefix(s, "_#") { 513 s = "#" + s 514 } 515 if !ast.IsValidIdent(s) { 516 panic(fmt.Sprintf("invalid definition %s", s)) 517 } 518 return Selector{definitionSelector(s)} 519 } 520 521 type definitionSelector string 522 523 // String returns the CUE representation of the definition. 524 func (d definitionSelector) String() string { 525 return string(d) 526 } 527 528 func (d definitionSelector) isConstraint() bool { return false } 529 530 func (d definitionSelector) labelType() SelectorType { 531 return DefinitionLabel 532 } 533 534 func (s definitionSelector) constraintType() SelectorType { return 0 } 535 536 func (d definitionSelector) feature(r adt.Runtime) adt.Feature { 537 return adt.MakeIdentLabel(r, string(d), "") 538 } 539 540 // A Str is a CUE string label. Definition selectors are defined with Def. 541 func Str(s string) Selector { 542 return Selector{stringSelector(s)} 543 } 544 545 type stringSelector string 546 547 func (s stringSelector) String() string { 548 str := string(s) 549 if isHiddenOrDefinition(str) || !ast.IsValidIdent(str) { 550 return literal.Label.Quote(str) 551 } 552 return str 553 } 554 555 func (s stringSelector) isConstraint() bool { return false } 556 func (s stringSelector) labelType() SelectorType { return StringLabel } 557 func (s stringSelector) constraintType() SelectorType { return 0 } 558 559 func (s stringSelector) feature(r adt.Runtime) adt.Feature { 560 return adt.MakeStringLabel(r, string(s)) 561 } 562 563 // An Index selects a list element by index. 564 func Index(x int) Selector { 565 f, err := adt.MakeLabel(nil, int64(x), adt.IntLabel) 566 if err != nil { 567 return Selector{pathError{err}} 568 } 569 return Selector{indexSelector(f)} 570 } 571 572 type indexSelector adt.Feature 573 574 func (s indexSelector) String() string { 575 return strconv.Itoa(adt.Feature(s).Index()) 576 } 577 578 func (s indexSelector) labelType() SelectorType { return IndexLabel } 579 func (s indexSelector) constraintType() SelectorType { return 0 } 580 581 func (s indexSelector) isConstraint() bool { return false } 582 583 func (s indexSelector) feature(r adt.Runtime) adt.Feature { 584 return adt.Feature(s) 585 } 586 587 // an anySelector represents a wildcard option of a particular type. 588 type anySelector adt.Feature 589 590 func (s anySelector) String() string { return "[_]" } 591 func (s anySelector) isConstraint() bool { return true } 592 func (s anySelector) labelType() SelectorType { 593 // FeatureTypes are numbered sequentially. SelectorType is a bitmap. As they 594 // are defined in the same order, we can go from FeatureType to SelectorType 595 // by left shifting. As valid FeatureTypes starts at 1, we need to end with 596 // a final right shift. 597 return SelectorType((1 << adt.Feature(s).Typ()) >> 1) 598 } 599 func (s anySelector) constraintType() SelectorType { return PatternConstraint } 600 601 func (s anySelector) feature(r adt.Runtime) adt.Feature { 602 return adt.Feature(s) 603 } 604 605 // TODO: allow import paths to be represented? 606 // 607 // // ImportPath defines a lookup at the root of an instance. It must be the first 608 // // element of a Path. 609 // 610 // func ImportPath(s string) Selector { 611 // return importSelector(s) 612 // } 613 type constraintSelector struct { 614 selector 615 constraint SelectorType 616 } 617 618 func (s constraintSelector) labelType() SelectorType { 619 return s.selector.labelType() 620 } 621 622 func (s constraintSelector) constraintType() SelectorType { 623 return s.constraint 624 } 625 626 func wrapConstraint(s Selector, t SelectorType) Selector { 627 sel := s.sel 628 if c, ok := sel.(constraintSelector); ok { 629 if c.constraint == t { 630 return s 631 } 632 sel = c.selector // unwrap 633 } 634 return Selector{constraintSelector{sel, t}} 635 } 636 637 // func isOptional(sel selector) bool { 638 // _, ok := sel.(optionalSelector) 639 // return ok 640 // } 641 642 func (s constraintSelector) isConstraint() bool { 643 return true 644 } 645 646 func (s constraintSelector) String() string { 647 var suffix string 648 switch s.constraint { 649 case OptionalConstraint: 650 suffix = "?" 651 case RequiredConstraint: 652 suffix = "!" 653 } 654 return s.selector.String() + suffix 655 } 656 657 // TODO: allow looking up in parent scopes? 658 659 // // Parent returns a Selector for looking up in the parent of a current node. 660 // // Parent selectors may only occur at the start of a Path. 661 // func Parent() Selector { 662 // return parentSelector{} 663 // } 664 665 // type parentSelector struct{} 666 667 // func (p parentSelector) String() string { return "__up" } 668 // func (p parentSelector) feature(r adt.Runtime) adt.Feature { 669 // return adt.InvalidLabel 670 // } 671 672 type pathError struct { 673 errors.Error 674 } 675 676 func (p pathError) String() string { return "" } 677 func (p pathError) isConstraint() bool { return false } 678 func (p pathError) labelType() SelectorType { return InvalidSelectorType } 679 func (p pathError) constraintType() SelectorType { return 0 } 680 func (p pathError) feature(r adt.Runtime) adt.Feature { 681 return adt.InvalidLabel 682 } 683 684 func valueToSel(v adt.Value) Selector { 685 switch x := adt.Unwrap(v).(type) { 686 case *adt.Num: 687 i, err := x.X.Int64() 688 if err != nil { 689 return Selector{&pathError{errors.Promote(err, "invalid number")}} 690 } 691 return Index(int(i)) 692 case *adt.String: 693 return Str(x.Str) 694 default: 695 return Selector{pathError{errors.Newf(token.NoPos, "dynamic selector")}} 696 } 697 } 698 699 func featureToSel(f adt.Feature, r adt.Runtime) Selector { 700 switch f.Typ() { 701 case adt.StringLabel: 702 return Str(f.StringValue(r)) 703 case adt.IntLabel: 704 return Index(f.Index()) 705 case adt.DefinitionLabel: 706 return Def(f.IdentString(r)) 707 case adt.HiddenLabel, adt.HiddenDefinitionLabel: 708 ident := f.IdentString(r) 709 pkg := f.PkgID(r) 710 return Hid(ident, pkg) 711 } 712 return Selector{pathError{ 713 errors.Newf(token.NoPos, "unexpected feature type %v", f.Typ()), 714 }} 715 } 716 717 func featureToSelType(f adt.Feature, at adt.ArcType) (st SelectorType) { 718 switch f.Typ() { 719 case adt.StringLabel: 720 st = StringLabel 721 case adt.IntLabel: 722 st = IndexLabel 723 case adt.DefinitionLabel: 724 st = DefinitionLabel 725 case adt.HiddenLabel: 726 st = HiddenLabel 727 case adt.HiddenDefinitionLabel: 728 st = HiddenDefinitionLabel 729 default: 730 panic("unsupported arc type") 731 } 732 return st | fromArcType(at) 733 }