cuelang.org/go@v0.13.0/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 [Selector.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.
   201  // It panics unless [Selector.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  	// AnyDefinition is a [Selector] which can be used to ask for any definition.
   215  	//
   216  	// In paths it is used to select constraints that apply to all elements.
   217  	// AnyDefinition = anyDefinition
   218  	anyDefinition = Selector{sel: anySelector(adt.AnyDefinition)}
   219  	// AnyIndex is a [Selector] which can be used to ask for any index.
   220  	//
   221  	// In paths it is used to select constraints that apply to all elements.
   222  	AnyIndex = anyIndex
   223  	anyIndex = Selector{sel: anySelector(adt.AnyIndex)}
   224  
   225  	// AnyString is a [Selector] which can be used to ask for any regular string field.
   226  	//
   227  	// In paths it is used to select constraints that apply to all elements.
   228  	AnyString = anyString
   229  	anyString = Selector{sel: anySelector(adt.AnyString)}
   230  )
   231  
   232  // Optional converts sel into an optional constraint equivalent.
   233  // It's a no-op if the selector is already optional.
   234  //
   235  //	foo  -> foo?
   236  //	foo! -> foo?
   237  func (sel Selector) Optional() Selector {
   238  	return wrapConstraint(sel, OptionalConstraint)
   239  }
   240  
   241  // Required converts sel into a required constraint equivalent.
   242  // It's a no-op if the selector is already a required constraint.
   243  //
   244  //	foo  -> foo!
   245  //	foo? -> foo!
   246  func (sel Selector) Required() Selector {
   247  	return wrapConstraint(sel, RequiredConstraint)
   248  }
   249  
   250  type selector interface {
   251  	String() string
   252  
   253  	feature(ctx adt.Runtime) adt.Feature
   254  	labelType() SelectorType
   255  	constraintType() SelectorType
   256  	isConstraint() bool
   257  }
   258  
   259  // A Path is series of selectors to query a CUE value.
   260  // The zero value corresponds to an empty path.
   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(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  // It returns an invalid selector if the index is out of range.
   565  func Index[T interface{ int | int64 }](x T) Selector {
   566  	f, err := adt.MakeLabel(nil, int64(x), adt.IntLabel)
   567  	if err != nil {
   568  		return Selector{pathError{err}}
   569  	}
   570  	return Selector{indexSelector(f)}
   571  }
   572  
   573  type indexSelector adt.Feature
   574  
   575  func (s indexSelector) String() string {
   576  	return strconv.Itoa(adt.Feature(s).Index())
   577  }
   578  
   579  func (s indexSelector) labelType() SelectorType      { return IndexLabel }
   580  func (s indexSelector) constraintType() SelectorType { return 0 }
   581  
   582  func (s indexSelector) isConstraint() bool { return false }
   583  
   584  func (s indexSelector) feature(r adt.Runtime) adt.Feature {
   585  	return adt.Feature(s)
   586  }
   587  
   588  // an anySelector represents a wildcard option of a particular type.
   589  type anySelector adt.Feature
   590  
   591  func (s anySelector) String() string     { return "[_]" }
   592  func (s anySelector) isConstraint() bool { return true }
   593  func (s anySelector) labelType() SelectorType {
   594  	// FeatureTypes are numbered sequentially. SelectorType is a bitmap. As they
   595  	// are defined in the same order, we can go from FeatureType to SelectorType
   596  	// by left shifting. As valid FeatureTypes starts at 1, we need to end with
   597  	// a final right shift.
   598  	return SelectorType((1 << adt.Feature(s).Typ()) >> 1)
   599  }
   600  func (s anySelector) constraintType() SelectorType { return PatternConstraint }
   601  
   602  func (s anySelector) feature(r adt.Runtime) adt.Feature {
   603  	return adt.Feature(s)
   604  }
   605  
   606  // TODO: allow import paths to be represented?
   607  //
   608  // // ImportPath defines a lookup at the root of an instance. It must be the first
   609  // // element of a Path.
   610  //
   611  //	func ImportPath(s string) Selector {
   612  //		return importSelector(s)
   613  //	}
   614  type constraintSelector struct {
   615  	selector
   616  	constraint SelectorType
   617  }
   618  
   619  func (s constraintSelector) labelType() SelectorType {
   620  	return s.selector.labelType()
   621  }
   622  
   623  func (s constraintSelector) constraintType() SelectorType {
   624  	return s.constraint
   625  }
   626  
   627  func wrapConstraint(s Selector, t SelectorType) Selector {
   628  	sel := s.sel
   629  	if c, ok := sel.(constraintSelector); ok {
   630  		if c.constraint == t {
   631  			return s
   632  		}
   633  		sel = c.selector // unwrap
   634  	}
   635  	return Selector{constraintSelector{sel, t}}
   636  }
   637  
   638  // func isOptional(sel selector) bool {
   639  // 	_, ok := sel.(optionalSelector)
   640  // 	return ok
   641  // }
   642  
   643  func (s constraintSelector) isConstraint() bool {
   644  	return true
   645  }
   646  
   647  func (s constraintSelector) String() string {
   648  	var suffix string
   649  	switch s.constraint {
   650  	case OptionalConstraint:
   651  		suffix = "?"
   652  	case RequiredConstraint:
   653  		suffix = "!"
   654  	}
   655  	return s.selector.String() + suffix
   656  }
   657  
   658  // TODO: allow looking up in parent scopes?
   659  
   660  // // Parent returns a Selector for looking up in the parent of a current node.
   661  // // Parent selectors may only occur at the start of a Path.
   662  // func Parent() Selector {
   663  // 	return parentSelector{}
   664  // }
   665  
   666  // type parentSelector struct{}
   667  
   668  // func (p parentSelector) String() string { return "__up" }
   669  // func (p parentSelector) feature(r adt.Runtime) adt.Feature {
   670  // 	return adt.InvalidLabel
   671  // }
   672  
   673  type pathError struct {
   674  	errors.Error
   675  }
   676  
   677  func (p pathError) String() string               { return "" }
   678  func (p pathError) isConstraint() bool           { return false }
   679  func (p pathError) labelType() SelectorType      { return InvalidSelectorType }
   680  func (p pathError) constraintType() SelectorType { return 0 }
   681  func (p pathError) feature(r adt.Runtime) adt.Feature {
   682  	return adt.InvalidLabel
   683  }
   684  
   685  func valueToSel(v adt.Value) Selector {
   686  	switch x := adt.Unwrap(v).(type) {
   687  	case *adt.Num:
   688  		i, err := x.X.Int64()
   689  		if err != nil {
   690  			return Selector{&pathError{errors.Promote(err, "invalid number")}}
   691  		}
   692  		return Index(i)
   693  	case *adt.String:
   694  		return Str(x.Str)
   695  	default:
   696  		return Selector{pathError{errors.Newf(token.NoPos, "dynamic selector")}}
   697  	}
   698  }
   699  
   700  func featureToSel(f adt.Feature, r adt.Runtime) Selector {
   701  	switch f.Typ() {
   702  	case adt.StringLabel:
   703  		return Str(f.StringValue(r))
   704  	case adt.IntLabel:
   705  		return Index(f.Index())
   706  	case adt.DefinitionLabel:
   707  		return Def(f.IdentString(r))
   708  	case adt.HiddenLabel, adt.HiddenDefinitionLabel:
   709  		ident := f.IdentString(r)
   710  		pkg := f.PkgID(r)
   711  		return Hid(ident, pkg)
   712  	}
   713  	return Selector{pathError{
   714  		errors.Newf(token.NoPos, "unexpected feature type %v", f.Typ()),
   715  	}}
   716  }
   717  
   718  func featureToSelType(f adt.Feature, at adt.ArcType) (st SelectorType) {
   719  	switch f.Typ() {
   720  	case adt.StringLabel:
   721  		st = StringLabel
   722  	case adt.IntLabel:
   723  		st = IndexLabel
   724  	case adt.DefinitionLabel:
   725  		st = DefinitionLabel
   726  	case adt.HiddenLabel:
   727  		st = HiddenLabel
   728  	case adt.HiddenDefinitionLabel:
   729  		st = HiddenDefinitionLabel
   730  	default:
   731  		panic("unsupported arc type")
   732  	}
   733  	return st | fromArcType(at)
   734  }