parse.go 28 KB

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