...

Source file src/cuelang.org/go/cue/path.go

Documentation: cuelang.org/go/cue

     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  }
   734  

View as plain text