github.com/TheSpiritXIII/controller-tools@v0.14.1/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  	"github.com/TheSpiritXIII/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  		hint = peekNoSpace(subScanner)
   314  		firstElemType := guessType(subScanner, subRaw, false)
   315  		if firstElemType.Type == StringType {
   316  			// might be a map or slice, parse the string and check for colon
   317  			// (blech, basically arbitrary look-ahead due to raw strings).
   318  			var keyVal string // just ignore this
   319  			(&Argument{Type: StringType}).parseString(subScanner, raw, reflect.Indirect(reflect.ValueOf(&keyVal)))
   320  
   321  			if token := subScanner.Scan(); token == ':' || hint == '}' {
   322  				// it's got a string followed by a colon -- it's a map
   323  				// or an empty map in case of {}
   324  				return &Argument{
   325  					Type:     MapType,
   326  					ItemType: &Argument{Type: AnyType},
   327  				}
   328  			}
   329  		}
   330  
   331  		// definitely a slice -- maps have to have string keys and have a value followed by a colon
   332  		return &Argument{
   333  			Type:     SliceType,
   334  			ItemType: firstElemType,
   335  		}
   336  	}
   337  
   338  	// then, bools...
   339  	probablyString := false
   340  	if hint == 't' || hint == 'f' {
   341  		// maybe a bool
   342  		if nextTok := subScanner.Scan(); nextTok == sc.Ident {
   343  			switch subScanner.TokenText() {
   344  			case "true", "false":
   345  				// definitely a bool
   346  				return &Argument{Type: BoolType}
   347  			}
   348  			// probably a string
   349  			probablyString = true
   350  		} else {
   351  			// we shouldn't ever get here
   352  			scanner.Error(scanner, fmt.Sprintf("got a token (%q) that looked like an ident, but was not", scanner.TokenText()))
   353  			return &Argument{Type: InvalidType}
   354  		}
   355  	}
   356  
   357  	// then, integers...
   358  	if !probablyString {
   359  		nextTok := subScanner.Scan()
   360  		if nextTok == '-' {
   361  			nextTok = subScanner.Scan()
   362  		}
   363  
   364  		if nextTok == sc.Int {
   365  			return &Argument{Type: IntType}
   366  		}
   367  		if nextTok == sc.Float {
   368  			return &Argument{Type: NumberType}
   369  		}
   370  	}
   371  
   372  	// otherwise assume bare strings
   373  	return &Argument{Type: StringType}
   374  }
   375  
   376  // parseString parses either of the two accepted string forms (quoted, or bare tokens).
   377  func (a *Argument) parseString(scanner *sc.Scanner, raw string, out reflect.Value) {
   378  	// we need to temporarily disable the scanner's int/float parsing, since we want to
   379  	// prevent number parsing errors.
   380  	oldMode := scanner.Mode
   381  	scanner.Mode = oldMode &^ sc.ScanInts &^ sc.ScanFloats
   382  	defer func() {
   383  		scanner.Mode = oldMode
   384  	}()
   385  
   386  	// strings are a bit weird -- the "easy" case is quoted strings (tokenized as strings),
   387  	// the "hard" case (present for backwards compat) is a bare sequence of tokens that aren't
   388  	// a comma.
   389  	tok := scanner.Scan()
   390  	if tok == sc.String || tok == sc.RawString {
   391  		// the easy case
   392  		val, err := strconv.Unquote(scanner.TokenText())
   393  		if err != nil {
   394  			scanner.Error(scanner, fmt.Sprintf("unable to parse string: %v", err))
   395  			return
   396  		}
   397  		castAndSet(out, reflect.ValueOf(val))
   398  		return
   399  	}
   400  
   401  	// the "hard" case -- bare tokens not including ',' (the argument
   402  	// separator), ';' (the slice separator), ':' (the map separator), or '}'
   403  	// (delimitted slice ender)
   404  	startPos := scanner.Position.Offset
   405  	for hint := peekNoSpace(scanner); hint != ',' && hint != ';' && hint != ':' && hint != '}' && hint != sc.EOF; hint = peekNoSpace(scanner) {
   406  		// skip this token
   407  		scanner.Scan()
   408  	}
   409  	endPos := scanner.Position.Offset + len(scanner.TokenText())
   410  	castAndSet(out, reflect.ValueOf(raw[startPos:endPos]))
   411  }
   412  
   413  // parseSlice parses either of the two slice forms (curly-brace-delimitted and semicolon-separated).
   414  func (a *Argument) parseSlice(scanner *sc.Scanner, raw string, out reflect.Value) {
   415  	// slices have two supported formats, like string:
   416  	// - `{val, val, val}` (preferred)
   417  	// - `val;val;val` (legacy)
   418  	resSlice := reflect.Zero(out.Type())
   419  	elem := reflect.Indirect(reflect.New(out.Type().Elem()))
   420  
   421  	// preferred case
   422  	if peekNoSpace(scanner) == '{' {
   423  		// NB(directxman12): supporting delimitted slices in bare slices
   424  		// would require an extra look-ahead here :-/
   425  
   426  		scanner.Scan() // skip '{'
   427  		for hint := peekNoSpace(scanner); hint != '}' && hint != sc.EOF; hint = peekNoSpace(scanner) {
   428  			a.ItemType.parse(scanner, raw, elem, true /* parsing a slice */)
   429  			resSlice = reflect.Append(resSlice, elem)
   430  			tok := peekNoSpace(scanner)
   431  			if tok == '}' {
   432  				break
   433  			}
   434  			if !expect(scanner, ',', "comma") {
   435  				return
   436  			}
   437  		}
   438  		if !expect(scanner, '}', "close curly brace") {
   439  			return
   440  		}
   441  		castAndSet(out, resSlice)
   442  		return
   443  	}
   444  
   445  	// legacy case
   446  	for hint := peekNoSpace(scanner); hint != ',' && hint != '}' && hint != sc.EOF; hint = peekNoSpace(scanner) {
   447  		a.ItemType.parse(scanner, raw, elem, true /* parsing a slice */)
   448  		resSlice = reflect.Append(resSlice, elem)
   449  		tok := peekNoSpace(scanner)
   450  		if tok == ',' || tok == '}' || tok == sc.EOF {
   451  			break
   452  		}
   453  		scanner.Scan()
   454  		if tok != ';' {
   455  			scanner.Error(scanner, fmt.Sprintf("expected comma, got %q", scanner.TokenText()))
   456  			return
   457  		}
   458  	}
   459  	castAndSet(out, resSlice)
   460  }
   461  
   462  // parseMap parses a map of the form {string: val, string: val, string: val}
   463  func (a *Argument) parseMap(scanner *sc.Scanner, raw string, out reflect.Value) {
   464  	resMap := reflect.MakeMap(out.Type())
   465  	elem := reflect.Indirect(reflect.New(out.Type().Elem()))
   466  	key := reflect.Indirect(reflect.New(out.Type().Key()))
   467  
   468  	if !expect(scanner, '{', "open curly brace") {
   469  		return
   470  	}
   471  
   472  	for hint := peekNoSpace(scanner); hint != '}' && hint != sc.EOF; hint = peekNoSpace(scanner) {
   473  		a.parseString(scanner, raw, key)
   474  		if !expect(scanner, ':', "colon") {
   475  			return
   476  		}
   477  		a.ItemType.parse(scanner, raw, elem, false /* not in a slice */)
   478  		resMap.SetMapIndex(key, elem)
   479  
   480  		if peekNoSpace(scanner) == '}' {
   481  			break
   482  		}
   483  		if !expect(scanner, ',', "comma") {
   484  			return
   485  		}
   486  	}
   487  
   488  	if !expect(scanner, '}', "close curly brace") {
   489  		return
   490  	}
   491  
   492  	castAndSet(out, resMap)
   493  }
   494  
   495  // parse functions like Parse, except that it allows passing down whether or not we're
   496  // already in a slice, to avoid duplicate legacy slice detection for AnyType
   497  func (a *Argument) parse(scanner *sc.Scanner, raw string, out reflect.Value, inSlice bool) {
   498  	// nolint:gocyclo
   499  	if a.Type == InvalidType {
   500  		scanner.Error(scanner, "cannot parse invalid type")
   501  		return
   502  	}
   503  	if a.Pointer {
   504  		out.Set(reflect.New(out.Type().Elem()))
   505  		out = reflect.Indirect(out)
   506  	}
   507  	switch a.Type {
   508  	case RawType:
   509  		// raw consumes everything else
   510  		castAndSet(out, reflect.ValueOf(raw[scanner.Pos().Offset:]))
   511  		// consume everything else
   512  		var tok rune
   513  		for {
   514  			tok = scanner.Scan()
   515  			if tok == sc.EOF {
   516  				break
   517  			}
   518  		}
   519  	case NumberType:
   520  		nextChar := scanner.Peek()
   521  		isNegative := false
   522  		if nextChar == '-' {
   523  			isNegative = true
   524  			scanner.Scan() // eat the '-'
   525  		}
   526  
   527  		tok := scanner.Scan()
   528  		if tok != sc.Float && tok != sc.Int {
   529  			scanner.Error(scanner, fmt.Sprintf("expected integer or float, got %q", scanner.TokenText()))
   530  			return
   531  		}
   532  
   533  		text := scanner.TokenText()
   534  		if isNegative {
   535  			text = "-" + text
   536  		}
   537  
   538  		val, err := strconv.ParseFloat(text, 64)
   539  		if err != nil {
   540  			scanner.Error(scanner, fmt.Sprintf("unable to parse number: %v", err))
   541  			return
   542  		}
   543  
   544  		castAndSet(out, reflect.ValueOf(val))
   545  	case IntType:
   546  		nextChar := scanner.Peek()
   547  		isNegative := false
   548  		if nextChar == '-' {
   549  			isNegative = true
   550  			scanner.Scan() // eat the '-'
   551  		}
   552  		if !expect(scanner, sc.Int, "integer") {
   553  			return
   554  		}
   555  		// TODO(directxman12): respect the size when parsing
   556  		text := scanner.TokenText()
   557  		if isNegative {
   558  			text = "-" + text
   559  		}
   560  		val, err := strconv.Atoi(text)
   561  		if err != nil {
   562  			scanner.Error(scanner, fmt.Sprintf("unable to parse integer: %v", err))
   563  			return
   564  		}
   565  		castAndSet(out, reflect.ValueOf(val))
   566  	case StringType:
   567  		// strings are a bit weird -- the "easy" case is quoted strings (tokenized as strings),
   568  		// the "hard" case (present for backwards compat) is a bare sequence of tokens that aren't
   569  		// a comma.
   570  		a.parseString(scanner, raw, out)
   571  	case BoolType:
   572  		if !expect(scanner, sc.Ident, "true or false") {
   573  			return
   574  		}
   575  		switch scanner.TokenText() {
   576  		case "true":
   577  			castAndSet(out, reflect.ValueOf(true))
   578  		case "false":
   579  			castAndSet(out, reflect.ValueOf(false))
   580  		default:
   581  			scanner.Error(scanner, fmt.Sprintf("expected true or false, got %q", scanner.TokenText()))
   582  			return
   583  		}
   584  	case AnyType:
   585  		guessedType := guessType(scanner, raw, !inSlice)
   586  		newOut := out
   587  
   588  		// we need to be able to construct the right element types, below
   589  		// in parse, so construct a concretely-typed value to use as "out"
   590  		switch guessedType.Type {
   591  		case SliceType:
   592  			newType, err := makeSliceType(*guessedType.ItemType)
   593  			if err != nil {
   594  				scanner.Error(scanner, err.Error())
   595  				return
   596  			}
   597  			newOut = reflect.Indirect(reflect.New(newType))
   598  		case MapType:
   599  			newType, err := makeMapType(*guessedType.ItemType)
   600  			if err != nil {
   601  				scanner.Error(scanner, err.Error())
   602  				return
   603  			}
   604  			newOut = reflect.Indirect(reflect.New(newType))
   605  		}
   606  		if !newOut.CanSet() {
   607  			panic("at the disco") // TODO(directxman12): this is left over from debugging -- it might need to be an error
   608  		}
   609  		guessedType.Parse(scanner, raw, newOut)
   610  		castAndSet(out, newOut)
   611  	case SliceType:
   612  		// slices have two supported formats, like string:
   613  		// - `{val, val, val}` (preferred)
   614  		// - `val;val;val` (legacy)
   615  		a.parseSlice(scanner, raw, out)
   616  	case MapType:
   617  		// maps are {string: val, string: val, string: val}
   618  		a.parseMap(scanner, raw, out)
   619  	}
   620  }
   621  
   622  // Parse attempts to consume the argument from the given scanner (based on the given
   623  // raw input as well for collecting ranges of content), and places the output value
   624  // in the given reflect.Value.  Errors are reported via the given scanner.
   625  func (a *Argument) Parse(scanner *sc.Scanner, raw string, out reflect.Value) {
   626  	a.parse(scanner, raw, out, false)
   627  }
   628  
   629  // ArgumentFromType constructs an Argument by examining the given
   630  // raw reflect.Type.  It can construct arguments from the Go types
   631  // corresponding to any of the types listed in ArgumentType.
   632  func ArgumentFromType(rawType reflect.Type) (Argument, error) {
   633  	if rawType == rawArgsType {
   634  		return Argument{
   635  			Type: RawType,
   636  		}, nil
   637  	}
   638  
   639  	if rawType == interfaceType {
   640  		return Argument{
   641  			Type: AnyType,
   642  		}, nil
   643  	}
   644  
   645  	arg := Argument{}
   646  	if rawType.Kind() == reflect.Ptr {
   647  		rawType = rawType.Elem()
   648  		arg.Pointer = true
   649  		arg.Optional = true
   650  	}
   651  
   652  	switch rawType.Kind() {
   653  	case reflect.String:
   654  		arg.Type = StringType
   655  	case reflect.Int, reflect.Int32: // NB(directxman12): all ints in kubernetes are int32, so explicitly support that
   656  		arg.Type = IntType
   657  	case reflect.Float64:
   658  		arg.Type = NumberType
   659  	case reflect.Bool:
   660  		arg.Type = BoolType
   661  	case reflect.Slice:
   662  		arg.Type = SliceType
   663  		itemType, err := ArgumentFromType(rawType.Elem())
   664  		if err != nil {
   665  			return Argument{}, fmt.Errorf("bad slice item type: %w", err)
   666  		}
   667  		arg.ItemType = &itemType
   668  	case reflect.Map:
   669  		arg.Type = MapType
   670  		if rawType.Key().Kind() != reflect.String {
   671  			return Argument{}, fmt.Errorf("bad map key type: map keys must be strings")
   672  		}
   673  		itemType, err := ArgumentFromType(rawType.Elem())
   674  		if err != nil {
   675  			return Argument{}, fmt.Errorf("bad slice item type: %w", err)
   676  		}
   677  		arg.ItemType = &itemType
   678  	default:
   679  		return Argument{}, fmt.Errorf("type has unsupported kind %s", rawType.Kind())
   680  	}
   681  
   682  	return arg, nil
   683  }
   684  
   685  // TargetType describes which kind of node a given marker is associated with.
   686  type TargetType int
   687  
   688  const (
   689  	// DescribesPackage indicates that a marker is associated with a package.
   690  	DescribesPackage TargetType = iota
   691  	// DescribesType indicates that a marker is associated with a type declaration.
   692  	DescribesType
   693  	// DescribesField indicates that a marker is associated with a struct field.
   694  	DescribesField
   695  )
   696  
   697  func (t TargetType) String() string {
   698  	switch t {
   699  	case DescribesPackage:
   700  		return "package"
   701  	case DescribesType:
   702  		return "type"
   703  	case DescribesField:
   704  		return "field"
   705  	default:
   706  		return "(unknown)"
   707  	}
   708  }
   709  
   710  // Definition is a parsed definition of a marker.
   711  type Definition struct {
   712  	// Output is the deserialized Go type of the marker.
   713  	Output reflect.Type
   714  	// Name is the marker's name.
   715  	Name string
   716  	// Target indicates which kind of node this marker can be associated with.
   717  	Target TargetType
   718  	// Fields lists out the types of each field that this marker has, by
   719  	// argument name as used in the marker (if the output type isn't a struct,
   720  	// it'll have a single, blank field name).  This only lists exported fields,
   721  	// (as per reflection rules).
   722  	Fields map[string]Argument
   723  	// FieldNames maps argument names (as used in the marker) to struct field name
   724  	// in the output type.
   725  	FieldNames map[string]string
   726  	// Strict indicates that this definition should error out when parsing if
   727  	// not all non-optional fields were seen.
   728  	Strict bool
   729  }
   730  
   731  // AnonymousField indicates that the definition has one field,
   732  // (actually the original object), and thus the field
   733  // doesn't get named as part of the name.
   734  func (d *Definition) AnonymousField() bool {
   735  	if len(d.Fields) != 1 {
   736  		return false
   737  	}
   738  	_, hasAnonField := d.Fields[""]
   739  	return hasAnonField
   740  }
   741  
   742  // Empty indicates that this definition has no fields.
   743  func (d *Definition) Empty() bool {
   744  	return len(d.Fields) == 0
   745  }
   746  
   747  // argumentInfo returns information about an argument field as the marker parser's field loader
   748  // would see it.  This can be useful if you have to interact with marker definition structs
   749  // externally (e.g. at compile time).
   750  func argumentInfo(fieldName string, tag reflect.StructTag) (argName string, optionalOpt bool) {
   751  	argName = lowerCamelCase(fieldName)
   752  	markerTag, tagSpecified := tag.Lookup("marker")
   753  	markerTagParts := strings.Split(markerTag, ",")
   754  	if tagSpecified && markerTagParts[0] != "" {
   755  		// allow overriding to support legacy cases where we don't follow camelCase conventions
   756  		argName = markerTagParts[0]
   757  	}
   758  	optionalOpt = false
   759  	for _, tagOption := range markerTagParts[1:] {
   760  		switch tagOption {
   761  		case "optional":
   762  			optionalOpt = true
   763  		}
   764  	}
   765  
   766  	return argName, optionalOpt
   767  }
   768  
   769  // loadFields uses reflection to populate argument information from the Output type.
   770  func (d *Definition) loadFields() error {
   771  	if d.Fields == nil {
   772  		d.Fields = make(map[string]Argument)
   773  		d.FieldNames = make(map[string]string)
   774  	}
   775  	if d.Output.Kind() != reflect.Struct {
   776  		// anonymous field type
   777  		argType, err := ArgumentFromType(d.Output)
   778  		if err != nil {
   779  			return err
   780  		}
   781  		d.Fields[""] = argType
   782  		d.FieldNames[""] = ""
   783  		return nil
   784  	}
   785  
   786  	for i := 0; i < d.Output.NumField(); i++ {
   787  		field := d.Output.Field(i)
   788  		if field.PkgPath != "" {
   789  			// as per the reflect package docs, pkgpath is empty for exported fields,
   790  			// so non-empty package path means a private field, which we should skip
   791  			continue
   792  		}
   793  		argName, optionalOpt := argumentInfo(field.Name, field.Tag)
   794  
   795  		argType, err := ArgumentFromType(field.Type)
   796  		if err != nil {
   797  			return fmt.Errorf("unable to extract type information for field %q: %w", field.Name, err)
   798  		}
   799  
   800  		if argType.Type == RawType {
   801  			return fmt.Errorf("RawArguments must be the direct type of a marker, and not a field")
   802  		}
   803  
   804  		argType.Optional = optionalOpt || argType.Optional
   805  
   806  		d.Fields[argName] = argType
   807  		d.FieldNames[argName] = field.Name
   808  	}
   809  
   810  	return nil
   811  }
   812  
   813  // parserScanner makes a new scanner appropriate for use in parsing definitions and arguments.
   814  func parserScanner(raw string, err func(*sc.Scanner, string)) *sc.Scanner {
   815  	scanner := &sc.Scanner{}
   816  	scanner.Init(bytes.NewBufferString(raw))
   817  	scanner.Mode = sc.ScanIdents | sc.ScanInts | sc.ScanFloats | sc.ScanStrings | sc.ScanRawStrings | sc.SkipComments
   818  	scanner.Error = err
   819  
   820  	return scanner
   821  }
   822  
   823  // Parse uses the type information in this Definition to parse the given
   824  // raw marker in the form `+a:b:c=arg,d=arg` into an output object of the
   825  // type specified in the definition.
   826  func (d *Definition) Parse(rawMarker string) (interface{}, error) {
   827  	name, anonName, fields := splitMarker(rawMarker)
   828  
   829  	out := reflect.Indirect(reflect.New(d.Output))
   830  
   831  	// if we're a not a struct or have no arguments, treat the full `a:b:c` as the name,
   832  	// otherwise, treat `c` as a field name, and `a:b` as the marker name.
   833  	if !d.AnonymousField() && !d.Empty() && len(anonName) >= len(name)+1 {
   834  		fields = anonName[len(name)+1:] + "=" + fields
   835  	}
   836  
   837  	var errs []error
   838  	scanner := parserScanner(fields, func(scanner *sc.Scanner, msg string) {
   839  		errs = append(errs, &ScannerError{Msg: msg, Pos: scanner.Position})
   840  	})
   841  
   842  	// TODO(directxman12): strict parsing where we error out if certain fields aren't optional
   843  	seen := make(map[string]struct{}, len(d.Fields))
   844  	if d.AnonymousField() && scanner.Peek() != sc.EOF {
   845  		// might still be a struct that something fiddled with, so double check
   846  		structFieldName := d.FieldNames[""]
   847  		outTarget := out
   848  		if structFieldName != "" {
   849  			// it's a struct field mapped to an anonymous marker
   850  			outTarget = out.FieldByName(structFieldName)
   851  			if !outTarget.CanSet() {
   852  				scanner.Error(scanner, fmt.Sprintf("cannot set field %q (might not exist)", structFieldName))
   853  				return out.Interface(), loader.MaybeErrList(errs)
   854  			}
   855  		}
   856  
   857  		// no need for trying to parse field names if we're not a struct
   858  		field := d.Fields[""]
   859  		field.Parse(scanner, fields, outTarget)
   860  		seen[""] = struct{}{} // mark as seen for strict definitions
   861  	} else if !d.Empty() && scanner.Peek() != sc.EOF {
   862  		// if we expect *and* actually have arguments passed
   863  		for {
   864  			// parse the argument name
   865  			if !expect(scanner, sc.Ident, "argument name") {
   866  				break
   867  			}
   868  			argName := scanner.TokenText()
   869  			if !expect(scanner, '=', "equals") {
   870  				break
   871  			}
   872  
   873  			// make sure we know the field
   874  			fieldName, known := d.FieldNames[argName]
   875  			if !known {
   876  				scanner.Error(scanner, fmt.Sprintf("unknown argument %q", argName))
   877  				break
   878  			}
   879  			fieldType, known := d.Fields[argName]
   880  			if !known {
   881  				scanner.Error(scanner, fmt.Sprintf("unknown argument %q", argName))
   882  				break
   883  			}
   884  			seen[argName] = struct{}{} // mark as seen for strict definitions
   885  
   886  			// parse the field value
   887  			fieldVal := out.FieldByName(fieldName)
   888  			if !fieldVal.CanSet() {
   889  				scanner.Error(scanner, fmt.Sprintf("cannot set field %q (might not exist)", fieldName))
   890  				break
   891  			}
   892  			fieldType.Parse(scanner, fields, fieldVal)
   893  
   894  			if len(errs) > 0 {
   895  				break
   896  			}
   897  
   898  			if scanner.Peek() == sc.EOF {
   899  				break
   900  			}
   901  			if !expect(scanner, ',', "comma") {
   902  				break
   903  			}
   904  		}
   905  	}
   906  
   907  	if tok := scanner.Scan(); tok != sc.EOF {
   908  		scanner.Error(scanner, fmt.Sprintf("extra arguments provided: %q", fields[scanner.Position.Offset:]))
   909  	}
   910  
   911  	if d.Strict {
   912  		for argName, arg := range d.Fields {
   913  			if _, wasSeen := seen[argName]; !wasSeen && !arg.Optional {
   914  				scanner.Error(scanner, fmt.Sprintf("missing argument %q", argName))
   915  			}
   916  		}
   917  	}
   918  
   919  	return out.Interface(), loader.MaybeErrList(errs)
   920  }
   921  
   922  // MakeDefinition constructs a definition from a name, type, and the output type.
   923  // All such definitions are strict by default.  If a struct is passed as the output
   924  // type, its public fields will automatically be populated into Fields (and similar
   925  // fields in Definition).  Other values will have a single, empty-string-named Fields
   926  // entry.
   927  func MakeDefinition(name string, target TargetType, output interface{}) (*Definition, error) {
   928  	def := &Definition{
   929  		Name:   name,
   930  		Target: target,
   931  		Output: reflect.TypeOf(output),
   932  		Strict: true,
   933  	}
   934  
   935  	if err := def.loadFields(); err != nil {
   936  		return nil, err
   937  	}
   938  
   939  	return def, nil
   940  }
   941  
   942  // MakeAnyTypeDefinition constructs a definition for an output struct with a
   943  // field named `Value` of type `interface{}`. The argument to the marker will
   944  // be parsed as AnyType and assigned to the field named `Value`.
   945  func MakeAnyTypeDefinition(name string, target TargetType, output interface{}) (*Definition, error) {
   946  	defn, err := MakeDefinition(name, target, output)
   947  	if err != nil {
   948  		return nil, err
   949  	}
   950  	defn.FieldNames = map[string]string{"": "Value"}
   951  	defn.Fields = map[string]Argument{"": defn.Fields["value"]}
   952  	return defn, nil
   953  }
   954  
   955  // splitMarker takes a marker in the form of `+a:b:c=arg,d=arg` and splits it
   956  // into the name (`a:b`), the name if it's not a struct (`a:b:c`), and the parts
   957  // that are definitely fields (`arg,d=arg`).
   958  func splitMarker(raw string) (name string, anonymousName string, restFields string) {
   959  	raw = raw[1:] // get rid of the leading '+'
   960  	nameFieldParts := strings.SplitN(raw, "=", 2)
   961  	if len(nameFieldParts) == 1 {
   962  		return nameFieldParts[0], nameFieldParts[0], ""
   963  	}
   964  	anonymousName = nameFieldParts[0]
   965  	name = anonymousName
   966  	restFields = nameFieldParts[1]
   967  
   968  	nameParts := strings.Split(name, ":")
   969  	if len(nameParts) > 1 {
   970  		name = strings.Join(nameParts[:len(nameParts)-1], ":")
   971  	}
   972  	return name, anonymousName, restFields
   973  }
   974  
   975  type ScannerError struct {
   976  	Msg string
   977  	Pos sc.Position
   978  }
   979  
   980  func (e *ScannerError) Error() string {
   981  	return fmt.Sprintf("%s (at %s)", e.Msg, e.Pos)
   982  }