github.com/alex123012/deckhouse-controller-tools@v0.0.0-20230510090815-d594daf1af8c/pkg/markers/parse.go (about)

     1  /*
     2  Copyright 2019 The Kubernetes Authors.
     3  
     4  Licensed under the Apache License, Version 2.0 (the "License");
     5  you may not use this file except in compliance with the License.
     6  You may obtain a copy of the License at
     7  
     8      http://www.apache.org/licenses/LICENSE-2.0
     9  
    10  Unless required by applicable law or agreed to in writing, software
    11  distributed under the License is distributed on an "AS IS" BASIS,
    12  WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
    13  See the License for the specific language governing permissions and
    14  limitations under the License.
    15  */
    16  
    17  package markers
    18  
    19  import (
    20  	"bytes"
    21  	"fmt"
    22  	"reflect"
    23  	"strconv"
    24  	"strings"
    25  	sc "text/scanner"
    26  	"unicode"
    27  
    28  	"sigs.k8s.io/controller-tools/pkg/loader"
    29  )
    30  
    31  // expect checks that the next token of the scanner is the given token, adding an error
    32  // to the scanner if not.  It returns whether the token was as expected.
    33  func expect(scanner *sc.Scanner, expected rune, errDesc string) bool {
    34  	tok := scanner.Scan()
    35  	if tok != expected {
    36  		scanner.Error(scanner, fmt.Sprintf("expected %s, got %q", errDesc, scanner.TokenText()))
    37  		return false
    38  	}
    39  	return true
    40  }
    41  
    42  // peekNoSpace is equivalent to scanner.Peek, except that it will consume intervening whitespace.
    43  func peekNoSpace(scanner *sc.Scanner) rune {
    44  	hint := scanner.Peek()
    45  	for ; hint <= rune(' ') && ((1<<uint64(hint))&scanner.Whitespace) != 0; hint = scanner.Peek() {
    46  		scanner.Next() // skip the whitespace
    47  	}
    48  	return hint
    49  }
    50  
    51  var (
    52  	// interfaceType is a pre-computed reflect.Type representing the empty interface.
    53  	interfaceType = reflect.TypeOf((*interface{})(nil)).Elem()
    54  	rawArgsType   = reflect.TypeOf((*RawArguments)(nil)).Elem()
    55  )
    56  
    57  // lowerCamelCase converts PascalCase string to
    58  // a camelCase string (by lowering the first rune).
    59  func lowerCamelCase(in string) string {
    60  	isFirst := true
    61  	return strings.Map(func(inRune rune) rune {
    62  		if isFirst {
    63  			isFirst = false
    64  			return unicode.ToLower(inRune)
    65  		}
    66  		return inRune
    67  	}, in)
    68  }
    69  
    70  // RawArguments is a special type that can be used for a marker
    71  // to receive *all* raw, underparsed argument data for a marker.
    72  // You probably want to use `interface{}` to match any type instead.
    73  // Use *only* for legacy markers that don't follow Definition's normal
    74  // parsing logic.  It should *not* be used as a field in a marker struct.
    75  type RawArguments []byte
    76  
    77  // ArgumentType is the kind of a marker argument type.
    78  // It's roughly analogous to a subset of reflect.Kind, with
    79  // an extra "AnyType" to represent the empty interface.
    80  type ArgumentType int
    81  
    82  const (
    83  	// Invalid represents a type that can't be parsed, and should never be used.
    84  	InvalidType ArgumentType = iota
    85  	// IntType is an int
    86  	IntType
    87  	// NumberType is a float64
    88  	NumberType
    89  	// StringType is a string
    90  	StringType
    91  	// BoolType is a bool
    92  	BoolType
    93  	// AnyType is the empty interface, and matches the rest of the content
    94  	AnyType
    95  	// SliceType is any slice constructed of the ArgumentTypes
    96  	SliceType
    97  	// MapType is any map constructed of string keys, and ArgumentType values.
    98  	// Keys are strings, and it's common to see AnyType (non-uniform) values.
    99  	MapType
   100  	// RawType represents content that gets passed directly to the marker
   101  	// without any parsing. It should *only* be used with anonymous markers.
   102  	RawType
   103  )
   104  
   105  // Argument is the type of a marker argument.
   106  type Argument struct {
   107  	// Type is the type of this argument For non-scalar types (map and slice),
   108  	// further information is specified in ItemType.
   109  	Type ArgumentType
   110  	// Optional indicates if this argument is optional.
   111  	Optional bool
   112  	// Pointer indicates if this argument was a pointer (this is really only
   113  	// needed for deserialization, and should alway imply optional)
   114  	Pointer bool
   115  
   116  	// ItemType is the type of the slice item for slices, and the value type
   117  	// for maps.
   118  	ItemType *Argument
   119  }
   120  
   121  // typeString contains the internals of TypeString.
   122  func (a Argument) typeString(out *strings.Builder) {
   123  	if a.Pointer {
   124  		out.WriteRune('*')
   125  	}
   126  
   127  	switch a.Type {
   128  	case InvalidType:
   129  		out.WriteString("<invalid>")
   130  	case IntType:
   131  		out.WriteString("int")
   132  	case NumberType:
   133  		out.WriteString("float64")
   134  	case StringType:
   135  		out.WriteString("string")
   136  	case BoolType:
   137  		out.WriteString("bool")
   138  	case AnyType:
   139  		out.WriteString("<any>")
   140  	case SliceType:
   141  		out.WriteString("[]")
   142  		// arguments can't be non-pointer optional, so just call into typeString again.
   143  		a.ItemType.typeString(out)
   144  	case MapType:
   145  		out.WriteString("map[string]")
   146  		a.ItemType.typeString(out)
   147  	case RawType:
   148  		out.WriteString("<raw>")
   149  	}
   150  }
   151  
   152  // TypeString returns a string roughly equivalent
   153  // (but not identical) to the underlying Go type that
   154  // this argument would parse to.  It's mainly useful
   155  // for user-friendly formatting of this argument (e.g.
   156  // help strings).
   157  func (a Argument) TypeString() string {
   158  	out := &strings.Builder{}
   159  	a.typeString(out)
   160  	return out.String()
   161  }
   162  
   163  func (a Argument) String() string {
   164  	if a.Optional {
   165  		return fmt.Sprintf("<optional arg %s>", a.TypeString())
   166  	}
   167  	return fmt.Sprintf("<arg %s>", a.TypeString())
   168  }
   169  
   170  // castAndSet casts val to out's type if needed,
   171  // then sets out to val.
   172  func castAndSet(out, val reflect.Value) {
   173  	outType := out.Type()
   174  	if outType != val.Type() {
   175  		val = val.Convert(outType)
   176  	}
   177  	out.Set(val)
   178  }
   179  
   180  // makeSliceType makes a reflect.Type for a slice of the given type.
   181  // Useful for constructing the out value for when AnyType's guess returns a slice.
   182  func makeSliceType(itemType Argument) (reflect.Type, error) {
   183  	var itemReflectedType reflect.Type
   184  	switch itemType.Type {
   185  	case IntType:
   186  		itemReflectedType = reflect.TypeOf(int(0))
   187  	case NumberType:
   188  		itemReflectedType = reflect.TypeOf(float64(0))
   189  	case StringType:
   190  		itemReflectedType = reflect.TypeOf("")
   191  	case BoolType:
   192  		itemReflectedType = reflect.TypeOf(false)
   193  	case SliceType:
   194  		subItemType, err := makeSliceType(*itemType.ItemType)
   195  		if err != nil {
   196  			return nil, err
   197  		}
   198  		itemReflectedType = subItemType
   199  	case MapType:
   200  		subItemType, err := makeMapType(*itemType.ItemType)
   201  		if err != nil {
   202  			return nil, err
   203  		}
   204  		itemReflectedType = subItemType
   205  	// TODO(directxman12): support non-uniform slices?  (probably not)
   206  	default:
   207  		return nil, fmt.Errorf("invalid type when constructing guessed slice out: %v", itemType.Type)
   208  	}
   209  
   210  	if itemType.Pointer {
   211  		itemReflectedType = reflect.PtrTo(itemReflectedType)
   212  	}
   213  
   214  	return reflect.SliceOf(itemReflectedType), nil
   215  }
   216  
   217  // makeMapType makes a reflect.Type for a map of the given item type.
   218  // Useful for constructing the out value for when AnyType's guess returns a map.
   219  func makeMapType(itemType Argument) (reflect.Type, error) {
   220  	var itemReflectedType reflect.Type
   221  	switch itemType.Type {
   222  	case IntType:
   223  		itemReflectedType = reflect.TypeOf(int(0))
   224  	case NumberType:
   225  		itemReflectedType = reflect.TypeOf(float64(0))
   226  	case StringType:
   227  		itemReflectedType = reflect.TypeOf("")
   228  	case BoolType:
   229  		itemReflectedType = reflect.TypeOf(false)
   230  	case SliceType:
   231  		subItemType, err := makeSliceType(*itemType.ItemType)
   232  		if err != nil {
   233  			return nil, err
   234  		}
   235  		itemReflectedType = subItemType
   236  	// TODO(directxman12): support non-uniform slices?  (probably not)
   237  	case MapType:
   238  		subItemType, err := makeMapType(*itemType.ItemType)
   239  		if err != nil {
   240  			return nil, err
   241  		}
   242  		itemReflectedType = subItemType
   243  	case AnyType:
   244  		// NB(directxman12): maps explicitly allow non-uniform item types, unlike slices at the moment
   245  		itemReflectedType = interfaceType
   246  	default:
   247  		return nil, fmt.Errorf("invalid type when constructing guessed slice out: %v", itemType.Type)
   248  	}
   249  
   250  	if itemType.Pointer {
   251  		itemReflectedType = reflect.PtrTo(itemReflectedType)
   252  	}
   253  
   254  	return reflect.MapOf(reflect.TypeOf(""), itemReflectedType), nil
   255  }
   256  
   257  // guessType takes an educated guess about the type of the next field.  If allowSlice
   258  // is false, it will not guess slices.  It's less efficient than parsing with actual
   259  // type information, since we need to allocate to peek ahead full tokens, and the scanner
   260  // only allows peeking ahead one character.
   261  // Maps are *always* non-uniform (i.e. type the AnyType item type), since they're frequently
   262  // used to represent things like defaults for an object in JSON.
   263  func guessType(scanner *sc.Scanner, raw string, allowSlice bool) *Argument {
   264  	if allowSlice {
   265  		maybeItem := guessType(scanner, raw, false)
   266  
   267  		subRaw := raw[scanner.Pos().Offset:]
   268  		subScanner := parserScanner(subRaw, scanner.Error)
   269  
   270  		var tok rune
   271  		for {
   272  			tok = subScanner.Scan()
   273  			if tok == ',' || tok == sc.EOF || tok == ';' {
   274  				break
   275  			}
   276  			// wait till we get something interesting
   277  		}
   278  
   279  		// semicolon means it's a legacy slice
   280  		if tok == ';' {
   281  			return &Argument{
   282  				Type:     SliceType,
   283  				ItemType: maybeItem,
   284  			}
   285  		}
   286  
   287  		return maybeItem
   288  	}
   289  
   290  	// everything else needs a duplicate scanner to scan properly
   291  	// (so we don't consume our scanner tokens until we actually
   292  	// go to use this -- Go doesn't like scanners that can be rewound).
   293  	subRaw := raw[scanner.Pos().Offset:]
   294  	subScanner := parserScanner(subRaw, scanner.Error)
   295  
   296  	// skip whitespace
   297  	hint := peekNoSpace(subScanner)
   298  
   299  	// first, try the easy case -- quoted strings strings
   300  	switch hint {
   301  	case '"', '\'', '`':
   302  		return &Argument{Type: StringType}
   303  	}
   304  
   305  	// next, check for slices or maps
   306  	if hint == '{' {
   307  		subScanner.Scan()
   308  
   309  		// TODO(directxman12): this can't guess at empty objects, but that's generally ok.
   310  		// We'll cross that bridge when we get there.
   311  
   312  		// look ahead till we can figure out if this is a map or a slice
   313  		firstElemType := guessType(subScanner, subRaw, false)
   314  		if firstElemType.Type == StringType {
   315  			// might be a map or slice, parse the string and check for colon
   316  			// (blech, basically arbitrary look-ahead due to raw strings).
   317  			var keyVal string // just ignore this
   318  			(&Argument{Type: StringType}).parseString(subScanner, raw, reflect.Indirect(reflect.ValueOf(&keyVal)))
   319  
   320  			if subScanner.Scan() == ':' {
   321  				// it's got a string followed by a colon -- it's a map
   322  				return &Argument{
   323  					Type:     MapType,
   324  					ItemType: &Argument{Type: AnyType},
   325  				}
   326  			}
   327  		}
   328  
   329  		// definitely a slice -- maps have to have string keys and have a value followed by a colon
   330  		return &Argument{
   331  			Type:     SliceType,
   332  			ItemType: firstElemType,
   333  		}
   334  	}
   335  
   336  	// then, bools...
   337  	probablyString := false
   338  	if hint == 't' || hint == 'f' {
   339  		// maybe a bool
   340  		if nextTok := subScanner.Scan(); nextTok == sc.Ident {
   341  			switch subScanner.TokenText() {
   342  			case "true", "false":
   343  				// definitely a bool
   344  				return &Argument{Type: BoolType}
   345  			}
   346  			// probably a string
   347  			probablyString = true
   348  		} else {
   349  			// we shouldn't ever get here
   350  			scanner.Error(scanner, fmt.Sprintf("got a token (%q) that looked like an ident, but was not", scanner.TokenText()))
   351  			return &Argument{Type: InvalidType}
   352  		}
   353  	}
   354  
   355  	// then, integers...
   356  	if !probablyString {
   357  		nextTok := subScanner.Scan()
   358  		if nextTok == '-' {
   359  			nextTok = subScanner.Scan()
   360  		}
   361  
   362  		if nextTok == sc.Int {
   363  			return &Argument{Type: IntType}
   364  		}
   365  		if nextTok == sc.Float {
   366  			return &Argument{Type: NumberType}
   367  		}
   368  	}
   369  
   370  	// otherwise assume bare strings
   371  	return &Argument{Type: StringType}
   372  }
   373  
   374  // parseString parses either of the two accepted string forms (quoted, or bare tokens).
   375  func (a *Argument) parseString(scanner *sc.Scanner, raw string, out reflect.Value) {
   376  	// we need to temporarily disable the scanner's int/float parsing, since we want to
   377  	// prevent number parsing errors.
   378  	oldMode := scanner.Mode
   379  	scanner.Mode = oldMode &^ sc.ScanInts &^ sc.ScanFloats
   380  	defer func() {
   381  		scanner.Mode = oldMode
   382  	}()
   383  
   384  	// strings are a bit weird -- the "easy" case is quoted strings (tokenized as strings),
   385  	// the "hard" case (present for backwards compat) is a bare sequence of tokens that aren't
   386  	// a comma.
   387  	tok := scanner.Scan()
   388  	if tok == sc.String || tok == sc.RawString {
   389  		// the easy case
   390  		val, err := strconv.Unquote(scanner.TokenText())
   391  		if err != nil {
   392  			scanner.Error(scanner, fmt.Sprintf("unable to parse string: %v", err))
   393  			return
   394  		}
   395  		castAndSet(out, reflect.ValueOf(val))
   396  		return
   397  	}
   398  
   399  	// the "hard" case -- bare tokens not including ',' (the argument
   400  	// separator), ';' (the slice separator), ':' (the map separator), or '}'
   401  	// (delimitted slice ender)
   402  	startPos := scanner.Position.Offset
   403  	for hint := peekNoSpace(scanner); hint != ',' && hint != ';' && hint != ':' && hint != '}' && hint != sc.EOF; hint = peekNoSpace(scanner) {
   404  		// skip this token
   405  		scanner.Scan()
   406  	}
   407  	endPos := scanner.Position.Offset + len(scanner.TokenText())
   408  	castAndSet(out, reflect.ValueOf(raw[startPos:endPos]))
   409  }
   410  
   411  // parseSlice parses either of the two slice forms (curly-brace-delimitted and semicolon-separated).
   412  func (a *Argument) parseSlice(scanner *sc.Scanner, raw string, out reflect.Value) {
   413  	// slices have two supported formats, like string:
   414  	// - `{val, val, val}` (preferred)
   415  	// - `val;val;val` (legacy)
   416  	resSlice := reflect.Zero(out.Type())
   417  	elem := reflect.Indirect(reflect.New(out.Type().Elem()))
   418  
   419  	// preferred case
   420  	if peekNoSpace(scanner) == '{' {
   421  		// NB(directxman12): supporting delimitted slices in bare slices
   422  		// would require an extra look-ahead here :-/
   423  
   424  		scanner.Scan() // skip '{'
   425  		for hint := peekNoSpace(scanner); hint != '}' && hint != sc.EOF; hint = peekNoSpace(scanner) {
   426  			a.ItemType.parse(scanner, raw, elem, true /* parsing a slice */)
   427  			resSlice = reflect.Append(resSlice, elem)
   428  			tok := peekNoSpace(scanner)
   429  			if tok == '}' {
   430  				break
   431  			}
   432  			if !expect(scanner, ',', "comma") {
   433  				return
   434  			}
   435  		}
   436  		if !expect(scanner, '}', "close curly brace") {
   437  			return
   438  		}
   439  		castAndSet(out, resSlice)
   440  		return
   441  	}
   442  
   443  	// legacy case
   444  	for hint := peekNoSpace(scanner); hint != ',' && hint != '}' && hint != sc.EOF; hint = peekNoSpace(scanner) {
   445  		a.ItemType.parse(scanner, raw, elem, true /* parsing a slice */)
   446  		resSlice = reflect.Append(resSlice, elem)
   447  		tok := peekNoSpace(scanner)
   448  		if tok == ',' || tok == '}' || tok == sc.EOF {
   449  			break
   450  		}
   451  		scanner.Scan()
   452  		if tok != ';' {
   453  			scanner.Error(scanner, fmt.Sprintf("expected comma, got %q", scanner.TokenText()))
   454  			return
   455  		}
   456  	}
   457  	castAndSet(out, resSlice)
   458  }
   459  
   460  // parseMap parses a map of the form {string: val, string: val, string: val}
   461  func (a *Argument) parseMap(scanner *sc.Scanner, raw string, out reflect.Value) {
   462  	resMap := reflect.MakeMap(out.Type())
   463  	elem := reflect.Indirect(reflect.New(out.Type().Elem()))
   464  	key := reflect.Indirect(reflect.New(out.Type().Key()))
   465  
   466  	if !expect(scanner, '{', "open curly brace") {
   467  		return
   468  	}
   469  
   470  	for hint := peekNoSpace(scanner); hint != '}' && hint != sc.EOF; hint = peekNoSpace(scanner) {
   471  		a.parseString(scanner, raw, key)
   472  		if !expect(scanner, ':', "colon") {
   473  			return
   474  		}
   475  		a.ItemType.parse(scanner, raw, elem, false /* not in a slice */)
   476  		resMap.SetMapIndex(key, elem)
   477  
   478  		if peekNoSpace(scanner) == '}' {
   479  			break
   480  		}
   481  		if !expect(scanner, ',', "comma") {
   482  			return
   483  		}
   484  	}
   485  
   486  	if !expect(scanner, '}', "close curly brace") {
   487  		return
   488  	}
   489  
   490  	castAndSet(out, resMap)
   491  }
   492  
   493  // parse functions like Parse, except that it allows passing down whether or not we're
   494  // already in a slice, to avoid duplicate legacy slice detection for AnyType
   495  func (a *Argument) parse(scanner *sc.Scanner, raw string, out reflect.Value, inSlice bool) {
   496  	// nolint:gocyclo
   497  	if a.Type == InvalidType {
   498  		scanner.Error(scanner, "cannot parse invalid type")
   499  		return
   500  	}
   501  	if a.Pointer {
   502  		out.Set(reflect.New(out.Type().Elem()))
   503  		out = reflect.Indirect(out)
   504  	}
   505  	switch a.Type {
   506  	case RawType:
   507  		// raw consumes everything else
   508  		castAndSet(out, reflect.ValueOf(raw[scanner.Pos().Offset:]))
   509  		// consume everything else
   510  		var tok rune
   511  		for {
   512  			tok = scanner.Scan()
   513  			if tok == sc.EOF {
   514  				break
   515  			}
   516  		}
   517  	case NumberType:
   518  		nextChar := scanner.Peek()
   519  		isNegative := false
   520  		if nextChar == '-' {
   521  			isNegative = true
   522  			scanner.Scan() // eat the '-'
   523  		}
   524  
   525  		tok := scanner.Scan()
   526  		if tok != sc.Float && tok != sc.Int {
   527  			scanner.Error(scanner, fmt.Sprintf("expected integer or float, got %q", scanner.TokenText()))
   528  			return
   529  		}
   530  
   531  		text := scanner.TokenText()
   532  		if isNegative {
   533  			text = "-" + text
   534  		}
   535  
   536  		val, err := strconv.ParseFloat(text, 64)
   537  		if err != nil {
   538  			scanner.Error(scanner, fmt.Sprintf("unable to parse number: %v", err))
   539  			return
   540  		}
   541  
   542  		castAndSet(out, reflect.ValueOf(val))
   543  	case IntType:
   544  		nextChar := scanner.Peek()
   545  		isNegative := false
   546  		if nextChar == '-' {
   547  			isNegative = true
   548  			scanner.Scan() // eat the '-'
   549  		}
   550  		if !expect(scanner, sc.Int, "integer") {
   551  			return
   552  		}
   553  		// TODO(directxman12): respect the size when parsing
   554  		text := scanner.TokenText()
   555  		if isNegative {
   556  			text = "-" + text
   557  		}
   558  		val, err := strconv.Atoi(text)
   559  		if err != nil {
   560  			scanner.Error(scanner, fmt.Sprintf("unable to parse integer: %v", err))
   561  			return
   562  		}
   563  		castAndSet(out, reflect.ValueOf(val))
   564  	case StringType:
   565  		// strings are a bit weird -- the "easy" case is quoted strings (tokenized as strings),
   566  		// the "hard" case (present for backwards compat) is a bare sequence of tokens that aren't
   567  		// a comma.
   568  		a.parseString(scanner, raw, out)
   569  	case BoolType:
   570  		if !expect(scanner, sc.Ident, "true or false") {
   571  			return
   572  		}
   573  		switch scanner.TokenText() {
   574  		case "true":
   575  			castAndSet(out, reflect.ValueOf(true))
   576  		case "false":
   577  			castAndSet(out, reflect.ValueOf(false))
   578  		default:
   579  			scanner.Error(scanner, fmt.Sprintf("expected true or false, got %q", scanner.TokenText()))
   580  			return
   581  		}
   582  	case AnyType:
   583  		guessedType := guessType(scanner, raw, !inSlice)
   584  		newOut := out
   585  
   586  		// we need to be able to construct the right element types, below
   587  		// in parse, so construct a concretely-typed value to use as "out"
   588  		switch guessedType.Type {
   589  		case SliceType:
   590  			newType, err := makeSliceType(*guessedType.ItemType)
   591  			if err != nil {
   592  				scanner.Error(scanner, err.Error())
   593  				return
   594  			}
   595  			newOut = reflect.Indirect(reflect.New(newType))
   596  		case MapType:
   597  			newType, err := makeMapType(*guessedType.ItemType)
   598  			if err != nil {
   599  				scanner.Error(scanner, err.Error())
   600  				return
   601  			}
   602  			newOut = reflect.Indirect(reflect.New(newType))
   603  		}
   604  		if !newOut.CanSet() {
   605  			panic("at the disco") // TODO(directxman12): this is left over from debugging -- it might need to be an error
   606  		}
   607  		guessedType.Parse(scanner, raw, newOut)
   608  		castAndSet(out, newOut)
   609  	case SliceType:
   610  		// slices have two supported formats, like string:
   611  		// - `{val, val, val}` (preferred)
   612  		// - `val;val;val` (legacy)
   613  		a.parseSlice(scanner, raw, out)
   614  	case MapType:
   615  		// maps are {string: val, string: val, string: val}
   616  		a.parseMap(scanner, raw, out)
   617  	}
   618  }
   619  
   620  // Parse attempts to consume the argument from the given scanner (based on the given
   621  // raw input as well for collecting ranges of content), and places the output value
   622  // in the given reflect.Value.  Errors are reported via the given scanner.
   623  func (a *Argument) Parse(scanner *sc.Scanner, raw string, out reflect.Value) {
   624  	a.parse(scanner, raw, out, false)
   625  }
   626  
   627  // ArgumentFromType constructs an Argument by examining the given
   628  // raw reflect.Type.  It can construct arguments from the Go types
   629  // corresponding to any of the types listed in ArgumentType.
   630  func ArgumentFromType(rawType reflect.Type) (Argument, error) {
   631  	if rawType == rawArgsType {
   632  		return Argument{
   633  			Type: RawType,
   634  		}, nil
   635  	}
   636  
   637  	if rawType == interfaceType {
   638  		return Argument{
   639  			Type: AnyType,
   640  		}, nil
   641  	}
   642  
   643  	arg := Argument{}
   644  	if rawType.Kind() == reflect.Ptr {
   645  		rawType = rawType.Elem()
   646  		arg.Pointer = true
   647  		arg.Optional = true
   648  	}
   649  
   650  	switch rawType.Kind() {
   651  	case reflect.String:
   652  		arg.Type = StringType
   653  	case reflect.Int, reflect.Int32: // NB(directxman12): all ints in kubernetes are int32, so explicitly support that
   654  		arg.Type = IntType
   655  	case reflect.Float64:
   656  		arg.Type = NumberType
   657  	case reflect.Bool:
   658  		arg.Type = BoolType
   659  	case reflect.Slice:
   660  		arg.Type = SliceType
   661  		itemType, err := ArgumentFromType(rawType.Elem())
   662  		if err != nil {
   663  			return Argument{}, fmt.Errorf("bad slice item type: %w", err)
   664  		}
   665  		arg.ItemType = &itemType
   666  	case reflect.Map:
   667  		arg.Type = MapType
   668  		if rawType.Key().Kind() != reflect.String {
   669  			return Argument{}, fmt.Errorf("bad map key type: map keys must be strings")
   670  		}
   671  		itemType, err := ArgumentFromType(rawType.Elem())
   672  		if err != nil {
   673  			return Argument{}, fmt.Errorf("bad slice item type: %w", err)
   674  		}
   675  		arg.ItemType = &itemType
   676  	default:
   677  		return Argument{}, fmt.Errorf("type has unsupported kind %s", rawType.Kind())
   678  	}
   679  
   680  	return arg, nil
   681  }
   682  
   683  // TargetType describes which kind of node a given marker is associated with.
   684  type TargetType int
   685  
   686  const (
   687  	// DescribesPackage indicates that a marker is associated with a package.
   688  	DescribesPackage TargetType = iota
   689  	// DescribesType indicates that a marker is associated with a type declaration.
   690  	DescribesType
   691  	// DescribesField indicates that a marker is associated with a struct field.
   692  	DescribesField
   693  )
   694  
   695  func (t TargetType) String() string {
   696  	switch t {
   697  	case DescribesPackage:
   698  		return "package"
   699  	case DescribesType:
   700  		return "type"
   701  	case DescribesField:
   702  		return "field"
   703  	default:
   704  		return "(unknown)"
   705  	}
   706  }
   707  
   708  // Definition is a parsed definition of a marker.
   709  type Definition struct {
   710  	// Output is the deserialized Go type of the marker.
   711  	Output reflect.Type
   712  	// Name is the marker's name.
   713  	Name string
   714  	// Target indicates which kind of node this marker can be associated with.
   715  	Target TargetType
   716  	// Fields lists out the types of each field that this marker has, by
   717  	// argument name as used in the marker (if the output type isn't a struct,
   718  	// it'll have a single, blank field name).  This only lists exported fields,
   719  	// (as per reflection rules).
   720  	Fields map[string]Argument
   721  	// FieldNames maps argument names (as used in the marker) to struct field name
   722  	// in the output type.
   723  	FieldNames map[string]string
   724  	// Strict indicates that this definition should error out when parsing if
   725  	// not all non-optional fields were seen.
   726  	Strict bool
   727  }
   728  
   729  // AnonymousField indicates that the definition has one field,
   730  // (actually the original object), and thus the field
   731  // doesn't get named as part of the name.
   732  func (d *Definition) AnonymousField() bool {
   733  	if len(d.Fields) != 1 {
   734  		return false
   735  	}
   736  	_, hasAnonField := d.Fields[""]
   737  	return hasAnonField
   738  }
   739  
   740  // Empty indicates that this definition has no fields.
   741  func (d *Definition) Empty() bool {
   742  	return len(d.Fields) == 0
   743  }
   744  
   745  // argumentInfo returns information about an argument field as the marker parser's field loader
   746  // would see it.  This can be useful if you have to interact with marker definition structs
   747  // externally (e.g. at compile time).
   748  func argumentInfo(fieldName string, tag reflect.StructTag) (argName string, optionalOpt bool) {
   749  	argName = lowerCamelCase(fieldName)
   750  	markerTag, tagSpecified := tag.Lookup("marker")
   751  	markerTagParts := strings.Split(markerTag, ",")
   752  	if tagSpecified && markerTagParts[0] != "" {
   753  		// allow overriding to support legacy cases where we don't follow camelCase conventions
   754  		argName = markerTagParts[0]
   755  	}
   756  	optionalOpt = false
   757  	for _, tagOption := range markerTagParts[1:] {
   758  		switch tagOption {
   759  		case "optional":
   760  			optionalOpt = true
   761  		}
   762  	}
   763  
   764  	return argName, optionalOpt
   765  }
   766  
   767  // loadFields uses reflection to populate argument information from the Output type.
   768  func (d *Definition) loadFields() error {
   769  	if d.Fields == nil {
   770  		d.Fields = make(map[string]Argument)
   771  		d.FieldNames = make(map[string]string)
   772  	}
   773  	if d.Output.Kind() != reflect.Struct {
   774  		// anonymous field type
   775  		argType, err := ArgumentFromType(d.Output)
   776  		if err != nil {
   777  			return err
   778  		}
   779  		d.Fields[""] = argType
   780  		d.FieldNames[""] = ""
   781  		return nil
   782  	}
   783  
   784  	for i := 0; i < d.Output.NumField(); i++ {
   785  		field := d.Output.Field(i)
   786  		if field.PkgPath != "" {
   787  			// as per the reflect package docs, pkgpath is empty for exported fields,
   788  			// so non-empty package path means a private field, which we should skip
   789  			continue
   790  		}
   791  		argName, optionalOpt := argumentInfo(field.Name, field.Tag)
   792  
   793  		argType, err := ArgumentFromType(field.Type)
   794  		if err != nil {
   795  			return fmt.Errorf("unable to extract type information for field %q: %w", field.Name, err)
   796  		}
   797  
   798  		if argType.Type == RawType {
   799  			return fmt.Errorf("RawArguments must be the direct type of a marker, and not a field")
   800  		}
   801  
   802  		argType.Optional = optionalOpt || argType.Optional
   803  
   804  		d.Fields[argName] = argType
   805  		d.FieldNames[argName] = field.Name
   806  	}
   807  
   808  	return nil
   809  }
   810  
   811  // parserScanner makes a new scanner appropriate for use in parsing definitions and arguments.
   812  func parserScanner(raw string, err func(*sc.Scanner, string)) *sc.Scanner {
   813  	scanner := &sc.Scanner{}
   814  	scanner.Init(bytes.NewBufferString(raw))
   815  	scanner.Mode = sc.ScanIdents | sc.ScanInts | sc.ScanFloats | sc.ScanStrings | sc.ScanRawStrings | sc.SkipComments
   816  	scanner.Error = err
   817  
   818  	return scanner
   819  }
   820  
   821  // Parse uses the type information in this Definition to parse the given
   822  // raw marker in the form `+a:b:c=arg,d=arg` into an output object of the
   823  // type specified in the definition.
   824  func (d *Definition) Parse(rawMarker string) (interface{}, error) {
   825  	name, anonName, fields := splitMarker(rawMarker)
   826  
   827  	out := reflect.Indirect(reflect.New(d.Output))
   828  
   829  	// if we're a not a struct or have no arguments, treat the full `a:b:c` as the name,
   830  	// otherwise, treat `c` as a field name, and `a:b` as the marker name.
   831  	if !d.AnonymousField() && !d.Empty() && len(anonName) >= len(name)+1 {
   832  		fields = anonName[len(name)+1:] + "=" + fields
   833  	}
   834  
   835  	var errs []error
   836  	scanner := parserScanner(fields, func(scanner *sc.Scanner, msg string) {
   837  		errs = append(errs, &ScannerError{Msg: msg, Pos: scanner.Position})
   838  	})
   839  
   840  	// TODO(directxman12): strict parsing where we error out if certain fields aren't optional
   841  	seen := make(map[string]struct{}, len(d.Fields))
   842  	if d.AnonymousField() && scanner.Peek() != sc.EOF {
   843  		// might still be a struct that something fiddled with, so double check
   844  		structFieldName := d.FieldNames[""]
   845  		outTarget := out
   846  		if structFieldName != "" {
   847  			// it's a struct field mapped to an anonymous marker
   848  			outTarget = out.FieldByName(structFieldName)
   849  			if !outTarget.CanSet() {
   850  				scanner.Error(scanner, fmt.Sprintf("cannot set field %q (might not exist)", structFieldName))
   851  				return out.Interface(), loader.MaybeErrList(errs)
   852  			}
   853  		}
   854  
   855  		// no need for trying to parse field names if we're not a struct
   856  		field := d.Fields[""]
   857  		field.Parse(scanner, fields, outTarget)
   858  		seen[""] = struct{}{} // mark as seen for strict definitions
   859  	} else if !d.Empty() && scanner.Peek() != sc.EOF {
   860  		// if we expect *and* actually have arguments passed
   861  		for {
   862  			// parse the argument name
   863  			if !expect(scanner, sc.Ident, "argument name") {
   864  				break
   865  			}
   866  			argName := scanner.TokenText()
   867  			if !expect(scanner, '=', "equals") {
   868  				break
   869  			}
   870  
   871  			// make sure we know the field
   872  			fieldName, known := d.FieldNames[argName]
   873  			if !known {
   874  				scanner.Error(scanner, fmt.Sprintf("unknown argument %q", argName))
   875  				break
   876  			}
   877  			fieldType, known := d.Fields[argName]
   878  			if !known {
   879  				scanner.Error(scanner, fmt.Sprintf("unknown argument %q", argName))
   880  				break
   881  			}
   882  			seen[argName] = struct{}{} // mark as seen for strict definitions
   883  
   884  			// parse the field value
   885  			fieldVal := out.FieldByName(fieldName)
   886  			if !fieldVal.CanSet() {
   887  				scanner.Error(scanner, fmt.Sprintf("cannot set field %q (might not exist)", fieldName))
   888  				break
   889  			}
   890  			fieldType.Parse(scanner, fields, fieldVal)
   891  
   892  			if len(errs) > 0 {
   893  				break
   894  			}
   895  
   896  			if scanner.Peek() == sc.EOF {
   897  				break
   898  			}
   899  			if !expect(scanner, ',', "comma") {
   900  				break
   901  			}
   902  		}
   903  	}
   904  
   905  	if tok := scanner.Scan(); tok != sc.EOF {
   906  		scanner.Error(scanner, fmt.Sprintf("extra arguments provided: %q", fields[scanner.Position.Offset:]))
   907  	}
   908  
   909  	if d.Strict {
   910  		for argName, arg := range d.Fields {
   911  			if _, wasSeen := seen[argName]; !wasSeen && !arg.Optional {
   912  				scanner.Error(scanner, fmt.Sprintf("missing argument %q", argName))
   913  			}
   914  		}
   915  	}
   916  
   917  	return out.Interface(), loader.MaybeErrList(errs)
   918  }
   919  
   920  // MakeDefinition constructs a definition from a name, type, and the output type.
   921  // All such definitions are strict by default.  If a struct is passed as the output
   922  // type, its public fields will automatically be populated into Fields (and similar
   923  // fields in Definition).  Other values will have a single, empty-string-named Fields
   924  // entry.
   925  func MakeDefinition(name string, target TargetType, output interface{}) (*Definition, error) {
   926  	def := &Definition{
   927  		Name:   name,
   928  		Target: target,
   929  		Output: reflect.TypeOf(output),
   930  		Strict: true,
   931  	}
   932  
   933  	if err := def.loadFields(); err != nil {
   934  		return nil, err
   935  	}
   936  
   937  	return def, nil
   938  }
   939  
   940  // MakeAnyTypeDefinition constructs a definition for an output struct with a
   941  // field named `Value` of type `interface{}`. The argument to the marker will
   942  // be parsed as AnyType and assigned to the field named `Value`.
   943  func MakeAnyTypeDefinition(name string, target TargetType, output interface{}) (*Definition, error) {
   944  	defn, err := MakeDefinition(name, target, output)
   945  	if err != nil {
   946  		return nil, err
   947  	}
   948  	defn.FieldNames = map[string]string{"": "Value"}
   949  	defn.Fields = map[string]Argument{"": defn.Fields["value"]}
   950  	return defn, nil
   951  }
   952  
   953  // splitMarker takes a marker in the form of `+a:b:c=arg,d=arg` and splits it
   954  // into the name (`a:b`), the name if it's not a struct (`a:b:c`), and the parts
   955  // that are definitely fields (`arg,d=arg`).
   956  func splitMarker(raw string) (name string, anonymousName string, restFields string) {
   957  	raw = raw[1:] // get rid of the leading '+'
   958  	nameFieldParts := strings.SplitN(raw, "=", 2)
   959  	if len(nameFieldParts) == 1 {
   960  		return nameFieldParts[0], nameFieldParts[0], ""
   961  	}
   962  	anonymousName = nameFieldParts[0]
   963  	name = anonymousName
   964  	restFields = nameFieldParts[1]
   965  
   966  	nameParts := strings.Split(name, ":")
   967  	if len(nameParts) > 1 {
   968  		name = strings.Join(nameParts[:len(nameParts)-1], ":")
   969  	}
   970  	return name, anonymousName, restFields
   971  }
   972  
   973  type ScannerError struct {
   974  	Msg string
   975  	Pos sc.Position
   976  }
   977  
   978  func (e *ScannerError) Error() string {
   979  	return fmt.Sprintf("%s (at %s)", e.Msg, e.Pos)
   980  }