this repo has no description
0
fork

Configure Feed

Select the types of activity you want to include in your feed.

cue: more support for required fields for selectors

Signed-off-by: Marcel van Lohuizen <mpvl@gmail.com>
Change-Id: I559d2ca73facfb618107a9b34397a33bc6f84152
Reviewed-on: https://review.gerrithub.io/c/cue-lang/cue/+/552171
Reviewed-by: Roger Peppe <rogpeppe@gmail.com>
Unity-Result: CUEcueckoo <cueckoo@cuelang.org>
TryBot-Result: CUEcueckoo <cueckoo@cuelang.org>

+165 -47
+83 -26
cue/path.go
··· 57 57 InvalidSelectorType SelectorType = 0 58 58 ) 59 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 + 60 74 // LabelType reports the label type of t. 61 75 func (t SelectorType) LabelType() SelectorType { 62 76 return t & 0b0001_1111 ··· 134 148 switch s := sel.sel.(type) { 135 149 case stringSelector: 136 150 return string(s) 137 - case optionalSelector: 151 + case constraintSelector: 138 152 return string(s.selector.(stringSelector)) 139 153 } 140 154 panic(fmt.Sprintf("unreachable %T", sel.sel)) ··· 147 161 return sel.Type().ConstraintType() != 0 148 162 } 149 163 150 - // IsString reports whether sel represents an optional or regular member field. 164 + // IsString reports whether sel represents an optional, required, or regular 165 + // member field. 151 166 func (sel Selector) IsString() bool { 152 167 // TODO: consider deprecating this method. It is a bit wonkey now. 153 168 t := sel.Type() 154 - t &^= OptionalConstraint 169 + t &^= OptionalConstraint | RequiredConstraint 155 170 return t == StringLabel 156 171 } 157 172 ··· 212 227 anyString = Selector{sel: anySelector(adt.AnyString)} 213 228 ) 214 229 215 - // Optional converts sel into an optional equivalent. 230 + // Optional converts sel into an optional constraint equivalent. 216 231 // It's a no-op if the selector is already optional. 217 232 // 218 - // foo -> foo? 233 + // foo -> foo? 234 + // foo! -> foo? 219 235 func (sel Selector) Optional() Selector { 220 - return wrapOptional(sel) 236 + return wrapConstraint(sel, OptionalConstraint) 237 + } 238 + 239 + // Required converts sel into a required constraint equivalent. 240 + // It's a no-op if the selector is already a required constraint. 241 + // 242 + // foo -> foo! 243 + // foo? -> foo! 244 + func (sel Selector) Required() Selector { 245 + return wrapConstraint(sel, RequiredConstraint) 221 246 } 222 247 223 248 type selector interface { ··· 226 251 feature(ctx adt.Runtime) adt.Feature 227 252 labelType() SelectorType 228 253 constraintType() SelectorType 229 - optional() bool 254 + isConstraint() bool 230 255 } 231 256 232 257 // A Path is series of selectors to query a CUE value. ··· 309 334 func (p Path) Optional() Path { 310 335 q := make([]Selector, 0, len(p.path)) 311 336 for _, s := range p.path { 312 - q = appendSelector(q, wrapOptional(s)) 337 + q = appendSelector(q, wrapConstraint(s, OptionalConstraint)) 313 338 } 314 339 return Path{path: q} 315 340 } ··· 463 488 func (s scopedSelector) String() string { 464 489 return s.name 465 490 } 466 - func (scopedSelector) optional() bool { return false } 491 + func (scopedSelector) isConstraint() bool { return false } 467 492 468 493 func (s scopedSelector) labelType() SelectorType { 469 494 if strings.HasPrefix(s.name, "_#") { ··· 497 522 return string(d) 498 523 } 499 524 500 - func (d definitionSelector) optional() bool { return false } 525 + func (d definitionSelector) isConstraint() bool { return false } 501 526 502 527 func (d definitionSelector) labelType() SelectorType { 503 528 return DefinitionLabel ··· 524 549 return str 525 550 } 526 551 527 - func (s stringSelector) optional() bool { return false } 552 + func (s stringSelector) isConstraint() bool { return false } 528 553 func (s stringSelector) labelType() SelectorType { return StringLabel } 529 554 func (s stringSelector) constraintType() SelectorType { return 0 } 530 555 ··· 550 575 func (s indexSelector) labelType() SelectorType { return IndexLabel } 551 576 func (s indexSelector) constraintType() SelectorType { return 0 } 552 577 553 - func (s indexSelector) optional() bool { return false } 578 + func (s indexSelector) isConstraint() bool { return false } 554 579 555 580 func (s indexSelector) feature(r adt.Runtime) adt.Feature { 556 581 return adt.Feature(s) ··· 559 584 // an anySelector represents a wildcard option of a particular type. 560 585 type anySelector adt.Feature 561 586 562 - func (s anySelector) String() string { return "[_]" } 563 - func (s anySelector) optional() bool { return true } 587 + func (s anySelector) String() string { return "[_]" } 588 + func (s anySelector) isConstraint() bool { return true } 564 589 func (s anySelector) labelType() SelectorType { 565 590 // FeatureTypes are numbered sequentially. SelectorType is a bitmap. As they 566 591 // are defined in the same order, we can go from FeatureType to SelectorType ··· 582 607 // func ImportPath(s string) Selector { 583 608 // return importSelector(s) 584 609 // } 585 - type optionalSelector struct { 610 + type constraintSelector struct { 586 611 selector 612 + constraint SelectorType 587 613 } 588 614 589 - func (s optionalSelector) labelType() SelectorType { 615 + func (s constraintSelector) labelType() SelectorType { 590 616 return s.selector.labelType() 591 617 } 592 618 593 - func (s optionalSelector) constraintType() SelectorType { 594 - return OptionalConstraint 619 + func (s constraintSelector) constraintType() SelectorType { 620 + return s.constraint 595 621 } 596 622 597 - func wrapOptional(sel Selector) Selector { 598 - if !sel.sel.optional() { 599 - sel = Selector{optionalSelector{sel.sel}} 623 + func wrapConstraint(s Selector, t SelectorType) Selector { 624 + sel := s.sel 625 + if c, ok := sel.(constraintSelector); ok { 626 + if c.constraint == t { 627 + return s 628 + } 629 + sel = c.selector // unwrap 600 630 } 601 - return sel 631 + return Selector{constraintSelector{sel, t}} 602 632 } 603 633 604 634 // func isOptional(sel selector) bool { ··· 606 636 // return ok 607 637 // } 608 638 609 - func (s optionalSelector) optional() bool { return true } 639 + func (s constraintSelector) isConstraint() bool { 640 + return true 641 + } 610 642 611 - func (s optionalSelector) String() string { 612 - return s.selector.String() + "?" 643 + func (s constraintSelector) String() string { 644 + var suffix string 645 + switch s.constraint { 646 + case OptionalConstraint: 647 + suffix = "?" 648 + case RequiredConstraint: 649 + suffix = "!" 650 + } 651 + return s.selector.String() + suffix 613 652 } 614 653 615 654 // TODO: allow looking up in parent scopes? ··· 632 671 } 633 672 634 673 func (p pathError) String() string { return "" } 635 - func (p pathError) optional() bool { return false } 674 + func (p pathError) isConstraint() bool { return false } 636 675 func (p pathError) labelType() SelectorType { return InvalidSelectorType } 637 676 func (p pathError) constraintType() SelectorType { return 0 } 638 677 func (p pathError) feature(r adt.Runtime) adt.Feature { ··· 671 710 errors.Newf(token.NoPos, "unexpected feature type %v", f.Typ()), 672 711 }} 673 712 } 713 + 714 + func featureToSelType(f adt.Feature, at adt.ArcType) (st SelectorType) { 715 + switch f.Typ() { 716 + case adt.StringLabel: 717 + st = StringLabel 718 + case adt.IntLabel: 719 + st = IndexLabel 720 + case adt.DefinitionLabel: 721 + st = DefinitionLabel 722 + case adt.HiddenLabel: 723 + st = HiddenLabel 724 + case adt.HiddenDefinitionLabel: 725 + st = HiddenDefinitionLabel 726 + default: 727 + panic("unsupported arc type") 728 + } 729 + return st | fromArcType(at) 730 + }
+14 -1
cue/path_test.go
··· 213 213 isString: true, 214 214 isConstraint: true, 215 215 }, { 216 - sel: Def("foo").Optional(), 216 + sel: Str("foo").Required(), 217 + stype: StringLabel | RequiredConstraint, 218 + string: "foo!", 219 + unquoted: "foo", 220 + isString: true, 221 + isConstraint: true, 222 + }, { 223 + sel: Def("foo").Required().Optional(), 217 224 stype: DefinitionLabel | OptionalConstraint, 218 225 string: "#foo?", 226 + isDefinition: true, 227 + isConstraint: true, 228 + }, { 229 + sel: Def("foo").Optional().Required(), 230 + stype: DefinitionLabel | RequiredConstraint, 231 + string: "#foo!", 219 232 isDefinition: true, 220 233 isConstraint: true, 221 234 }, {
+2 -3
cue/query.go
··· 48 48 f := sel.sel.feature(v.idx) 49 49 for _, a := range n.Arcs { 50 50 if a.Label == f { 51 - if a.IsConstraint() && !sel.sel.optional() { 51 + if a.IsConstraint() && !sel.sel.isConstraint() { 52 52 break 53 53 } 54 54 parent = linkParent(parent, n, a) ··· 56 56 continue outer 57 57 } 58 58 } 59 - if sel.sel.optional() { 60 - // pattern or additional constraints. 59 + if sel.sel.isConstraint() { 61 60 x := &adt.Vertex{ 62 61 Parent: n, 63 62 Label: sel.sel.feature(ctx),
+22 -12
cue/types.go
··· 210 210 211 211 // An Iterator iterates over values. 212 212 type Iterator struct { 213 - val Value 214 - idx *runtime.Runtime 215 - ctx *adt.OpContext 216 - arcs []*adt.Vertex 217 - p int 218 - cur Value 219 - f adt.Feature 220 - isOpt bool 213 + val Value 214 + idx *runtime.Runtime 215 + ctx *adt.OpContext 216 + arcs []*adt.Vertex 217 + p int 218 + cur Value 219 + f adt.Feature 220 + arcType adt.ArcType 221 221 } 222 222 223 223 type hiddenIterator = Iterator ··· 234 234 p := linkParent(i.val.parent_, i.val.v, arc) 235 235 i.cur = makeValue(i.val.idx, arc, p) 236 236 i.f = arc.Label 237 - i.isOpt = arc.ArcType == adt.ArcOptional 237 + i.arcType = arc.ArcType 238 238 i.p++ 239 239 return true 240 240 } ··· 247 247 248 248 // Selector reports the field label of this iteration. 249 249 func (i *Iterator) Selector() Selector { 250 - return featureToSel(i.f, i.idx) 250 + return wrapConstraint(featureToSel(i.f, i.idx), fromArcType(i.arcType)) 251 251 } 252 252 253 253 // Label reports the label of the value if i iterates over struct fields and "" ··· 271 271 272 272 // IsOptional reports if a field is optional. 273 273 func (i *Iterator) IsOptional() bool { 274 - return i.isOpt 274 + return i.arcType == adt.ArcOptional 275 + } 276 + 277 + // FieldType reports the type of the field. 278 + func (i *Iterator) FieldType() SelectorType { 279 + return featureToSelType(i.f, i.arcType) 275 280 } 276 281 277 282 // IsDefinition reports if a field is a definition. ··· 1460 1465 type hiddenStruct = Struct 1461 1466 1462 1467 // FieldInfo contains information about a struct field. 1468 + // 1469 + // Deprecated: only used by deprecated functions. 1463 1470 type FieldInfo struct { 1464 1471 Selector string 1465 1472 Name string // Deprecated: use Selector 1466 1473 Pos int 1467 1474 Value Value 1475 + 1476 + SelectorType SelectorType 1468 1477 1469 1478 IsDefinition bool 1470 1479 IsOptional bool ··· 1479 1488 func (s *hiddenStruct) Field(i int) FieldInfo { 1480 1489 a := s.at(i) 1481 1490 opt := a.ArcType == adt.ArcOptional 1491 + selType := featureToSelType(a.Label, a.ArcType) 1482 1492 ctx := s.v.ctx() 1483 1493 1484 1494 v := makeChildValue(s.v, a) 1485 1495 name := s.v.idx.LabelStr(a.Label) 1486 1496 str := a.Label.SelectorString(ctx) 1487 - return FieldInfo{str, name, i, v, a.Label.IsDef(), opt, a.Label.IsHidden()} 1497 + return FieldInfo{str, name, i, v, selType, a.Label.IsDef(), opt, a.Label.IsHidden()} 1488 1498 } 1489 1499 1490 1500 // FieldByName looks up a field for the given name. If isIdent is true, it will
+44 -5
cue/types_test.go
··· 848 848 err string 849 849 }{{ 850 850 value: `{a:1,"_b":2,c:3,_d:4}`, 851 - res: "{a:1,_b:2,c:3,_d:4,}", 851 + res: `{a:1,"_b":2,c:3,_d:4,}`, 852 852 }, { 853 853 value: `{_a:"a"}`, 854 854 res: `{_a:"a",}`, ··· 859 859 // Issue #1879 860 860 value: `{a: 1, if false { b: 2 }}`, 861 861 res: `{a:1,}`, 862 + }, { 863 + value: `{a!:1,b?:2,c:3}`, 864 + res: `{a!:1,b?:2,c:3,}`, 862 865 }} 863 866 for _, tc := range testCases { 864 867 t.Run(tc.value, func(t *testing.T) { ··· 870 873 871 874 buf := []byte{'{'} 872 875 for iter.Next() { 873 - buf = append(buf, iter.Label()...) 874 - if iter.IsOptional() { 875 - buf = append(buf, '?') 876 - } 876 + buf = append(buf, iter.Selector().String()...) 877 877 buf = append(buf, ':') 878 878 b, err := iter.Value().MarshalJSON() 879 879 checkFatal(t, err, tc.err, "Obj.At") ··· 883 883 buf = append(buf, '}') 884 884 if got := string(buf); got != tc.res { 885 885 t.Errorf("got %v; want %v", got, tc.res) 886 + } 887 + }) 888 + } 889 + } 890 + 891 + func TestFieldType(t *testing.T) { 892 + testCases := []struct { 893 + value string 894 + want string 895 + }{{ 896 + value: `{a:1,"_b":2,c:3,_d:4,#def: 1}`, 897 + want: ` 898 + StringLabel 899 + StringLabel 900 + StringLabel 901 + HiddenLabel 902 + DefinitionLabel`, 903 + }, { 904 + value: `{a!:1,b?:2,c:3}`, 905 + want: ` 906 + StringLabel|RequiredConstraint 907 + StringLabel|OptionalConstraint 908 + StringLabel`, 909 + }} 910 + for _, tc := range testCases { 911 + t.Run(tc.value, func(t *testing.T) { 912 + obj := getInstance(t, tc.value).Value() 913 + 914 + iter, err := obj.Fields(All()) 915 + if err != nil { 916 + t.Fatal(err) 917 + } 918 + 919 + b := &strings.Builder{} 920 + for iter.Next() { 921 + fmt.Fprint(b, "\n\t\t", iter.FieldType()) 922 + } 923 + if got := b.String(); got != tc.want { 924 + t.Errorf("got:%v\nwant:%v", got, tc.want) 886 925 } 887 926 }) 888 927 }