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