docopt.go 29 KB

123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108109110111112113114115116117118119120121122123124125126127128129130131132133134135136137138139140141142143144145146147148149150151152153154155156157158159160161162163164165166167168169170171172173174175176177178179180181182183184185186187188189190191192193194195196197198199200201202203204205206207208209210211212213214215216217218219220221222223224225226227228229230231232233234235236237238239240241242243244245246247248249250251252253254255256257258259260261262263264265266267268269270271272273274275276277278279280281282283284285286287288289290291292293294295296297298299300301302303304305306307308309310311312313314315316317318319320321322323324325326327328329330331332333334335336337338339340341342343344345346347348349350351352353354355356357358359360361362363364365366367368369370371372373374375376377378379380381382383384385386387388389390391392393394395396397398399400401402403404405406407408409410411412413414415416417418419420421422423424425426427428429430431432433434435436437438439440441442443444445446447448449450451452453454455456457458459460461462463464465466467468469470471472473474475476477478479480481482483484485486487488489490491492493494495496497498499500501502503504505506507508509510511512513514515516517518519520521522523524525526527528529530531532533534535536537538539540541542543544545546547548549550551552553554555556557558559560561562563564565566567568569570571572573574575576577578579580581582583584585586587588589590591592593594595596597598599600601602603604605606607608609610611612613614615616617618619620621622623624625626627628629630631632633634635636637638639640641642643644645646647648649650651652653654655656657658659660661662663664665666667668669670671672673674675676677678679680681682683684685686687688689690691692693694695696697698699700701702703704705706707708709710711712713714715716717718719720721722723724725726727728729730731732733734735736737738739740741742743744745746747748749750751752753754755756757758759760761762763764765766767768769770771772773774775776777778779780781782783784785786787788789790791792793794795796797798799800801802803804805806807808809810811812813814815816817818819820821822823824825826827828829830831832833834835836837838839840841842843844845846847848849850851852853854855856857858859860861862863864865866867868869870871872873874875876877878879880881882883884885886887888889890891892893894895896897898899900901902903904905906907908909910911912913914915916917918919920921922923924925926927928929930931932933934935936937938939940941942943944945946947948949950951952953954955956957958959960961962963964965966967968969970971972973974975976977978979980981982983984985986987988989990991992993994995996997998999100010011002100310041005100610071008100910101011101210131014101510161017101810191020102110221023102410251026102710281029103010311032103310341035103610371038103910401041104210431044104510461047104810491050105110521053105410551056105710581059106010611062106310641065106610671068106910701071107210731074107510761077107810791080108110821083108410851086108710881089109010911092109310941095109610971098109911001101110211031104110511061107110811091110111111121113111411151116111711181119112011211122112311241125112611271128112911301131113211331134113511361137113811391140114111421143114411451146114711481149115011511152115311541155115611571158115911601161116211631164116511661167116811691170117111721173117411751176117711781179118011811182118311841185118611871188118911901191119211931194119511961197119811991200120112021203120412051206120712081209121012111212121312141215121612171218121912201221122212231224122512261227122812291230123112321233123412351236123712381239
  1. // Licensed under terms of MIT license (see LICENSE-MIT)
  2. // Copyright (c) 2013 Keith Batten, kbatten@gmail.com
  3. /*
  4. Package docopt parses command-line arguments based on a help message.
  5. ⚠ Use the alias “docopt-go”:
  6. import "github.com/docopt/docopt-go"
  7. or
  8. $ go get github.com/docopt/docopt-go
  9. */
  10. package docopt
  11. import (
  12. "fmt"
  13. "os"
  14. "reflect"
  15. "regexp"
  16. "strings"
  17. "unicode"
  18. )
  19. /*
  20. Parse `argv` based on the command-line interface described in `doc`.
  21. Given a conventional command-line help message, docopt creates a parser and
  22. processes the arguments. See
  23. https://github.com/docopt/docopt#help-message-format for a description of the
  24. help message format. If `argv` is `nil`, `os.Args[1:]` is used.
  25. docopt returns a map of option names to the values parsed from `argv`, and an
  26. error or `nil`.
  27. Set `help` to `false` to disable automatic help messages on `-h` or `--help`.
  28. If `version` is a non-empty string, it will be printed when `--version` is
  29. specified. Set `optionsFirst` to `true` to require that options always come
  30. before positional arguments; otherwise they can overlap.
  31. By default, docopt calls `os.Exit(0)` if it handled a built-in option such as
  32. `-h` or `--version`. If the user errored with a wrong command or options,
  33. docopt exits with a return code of 1. To stop docopt from calling `os.Exit()`
  34. and to handle your own return codes, pass an optional last parameter of `false`
  35. for `exit`.
  36. */
  37. func Parse(doc string, argv []string, help bool, version string,
  38. optionsFirst bool, exit ...bool) (map[string]interface{}, error) {
  39. // if "false" was the (optional) last arg, don't call os.Exit()
  40. exitOk := true
  41. if len(exit) > 0 {
  42. exitOk = exit[0]
  43. }
  44. args, output, err := parse(doc, argv, help, version, optionsFirst)
  45. if _, ok := err.(*UserError); ok {
  46. // the user gave us bad input
  47. fmt.Fprintln(os.Stderr, output)
  48. if exitOk {
  49. os.Exit(1)
  50. }
  51. } else if len(output) > 0 && err == nil {
  52. // the user asked for help or `--version`
  53. fmt.Println(output)
  54. if exitOk {
  55. os.Exit(0)
  56. }
  57. }
  58. return args, err
  59. }
  60. // parse and return a map of args, output and all errors
  61. func parse(doc string, argv []string, help bool, version string, optionsFirst bool) (args map[string]interface{}, output string, err error) {
  62. if argv == nil && len(os.Args) > 1 {
  63. argv = os.Args[1:]
  64. }
  65. usageSections := parseSection("usage:", doc)
  66. if len(usageSections) == 0 {
  67. err = newLanguageError("\"usage:\" (case-insensitive) not found.")
  68. return
  69. }
  70. if len(usageSections) > 1 {
  71. err = newLanguageError("More than one \"usage:\" (case-insensitive).")
  72. return
  73. }
  74. usage := usageSections[0]
  75. options := parseDefaults(doc)
  76. formal, err := formalUsage(usage)
  77. if err != nil {
  78. output = handleError(err, usage)
  79. return
  80. }
  81. pat, err := parsePattern(formal, &options)
  82. if err != nil {
  83. output = handleError(err, usage)
  84. return
  85. }
  86. patternArgv, err := parseArgv(newTokenList(argv, errorUser), &options, optionsFirst)
  87. if err != nil {
  88. output = handleError(err, usage)
  89. return
  90. }
  91. patFlat, err := pat.flat(patternOption)
  92. if err != nil {
  93. output = handleError(err, usage)
  94. return
  95. }
  96. patternOptions := patFlat.unique()
  97. patFlat, err = pat.flat(patternOptionSSHORTCUT)
  98. if err != nil {
  99. output = handleError(err, usage)
  100. return
  101. }
  102. for _, optionsShortcut := range patFlat {
  103. docOptions := parseDefaults(doc)
  104. optionsShortcut.children = docOptions.unique().diff(patternOptions)
  105. }
  106. if output = extras(help, version, patternArgv, doc); len(output) > 0 {
  107. return
  108. }
  109. err = pat.fix()
  110. if err != nil {
  111. output = handleError(err, usage)
  112. return
  113. }
  114. matched, left, collected := pat.match(&patternArgv, nil)
  115. if matched && len(*left) == 0 {
  116. patFlat, err = pat.flat(patternDefault)
  117. if err != nil {
  118. output = handleError(err, usage)
  119. return
  120. }
  121. args = append(patFlat, *collected...).dictionary()
  122. return
  123. }
  124. err = newUserError("")
  125. output = handleError(err, usage)
  126. return
  127. }
  128. func handleError(err error, usage string) string {
  129. if _, ok := err.(*UserError); ok {
  130. return strings.TrimSpace(fmt.Sprintf("%s\n%s", err, usage))
  131. }
  132. return ""
  133. }
  134. func parseSection(name, source string) []string {
  135. p := regexp.MustCompile(`(?im)^([^\n]*` + name + `[^\n]*\n?(?:[ \t].*?(?:\n|$))*)`)
  136. s := p.FindAllString(source, -1)
  137. if s == nil {
  138. s = []string{}
  139. }
  140. for i, v := range s {
  141. s[i] = strings.TrimSpace(v)
  142. }
  143. return s
  144. }
  145. func parseDefaults(doc string) patternList {
  146. defaults := patternList{}
  147. p := regexp.MustCompile(`\n[ \t]*(-\S+?)`)
  148. for _, s := range parseSection("options:", doc) {
  149. // FIXME corner case "bla: options: --foo"
  150. _, _, s = stringPartition(s, ":") // get rid of "options:"
  151. split := p.Split("\n"+s, -1)[1:]
  152. match := p.FindAllStringSubmatch("\n"+s, -1)
  153. for i := range split {
  154. optionDescription := match[i][1] + split[i]
  155. if strings.HasPrefix(optionDescription, "-") {
  156. defaults = append(defaults, parseOption(optionDescription))
  157. }
  158. }
  159. }
  160. return defaults
  161. }
  162. func parsePattern(source string, options *patternList) (*pattern, error) {
  163. tokens := tokenListFromPattern(source)
  164. result, err := parseExpr(tokens, options)
  165. if err != nil {
  166. return nil, err
  167. }
  168. if tokens.current() != nil {
  169. return nil, tokens.errorFunc("unexpected ending: %s" + strings.Join(tokens.tokens, " "))
  170. }
  171. return newRequired(result...), nil
  172. }
  173. func parseArgv(tokens *tokenList, options *patternList, optionsFirst bool) (patternList, error) {
  174. /*
  175. Parse command-line argument vector.
  176. If options_first:
  177. argv ::= [ long | shorts ]* [ argument ]* [ '--' [ argument ]* ] ;
  178. else:
  179. argv ::= [ long | shorts | argument ]* [ '--' [ argument ]* ] ;
  180. */
  181. parsed := patternList{}
  182. for tokens.current() != nil {
  183. if tokens.current().eq("--") {
  184. for _, v := range tokens.tokens {
  185. parsed = append(parsed, newArgument("", v))
  186. }
  187. return parsed, nil
  188. } else if tokens.current().hasPrefix("--") {
  189. pl, err := parseLong(tokens, options)
  190. if err != nil {
  191. return nil, err
  192. }
  193. parsed = append(parsed, pl...)
  194. } else if tokens.current().hasPrefix("-") && !tokens.current().eq("-") {
  195. ps, err := parseShorts(tokens, options)
  196. if err != nil {
  197. return nil, err
  198. }
  199. parsed = append(parsed, ps...)
  200. } else if optionsFirst {
  201. for _, v := range tokens.tokens {
  202. parsed = append(parsed, newArgument("", v))
  203. }
  204. return parsed, nil
  205. } else {
  206. parsed = append(parsed, newArgument("", tokens.move().String()))
  207. }
  208. }
  209. return parsed, nil
  210. }
  211. func parseOption(optionDescription string) *pattern {
  212. optionDescription = strings.TrimSpace(optionDescription)
  213. options, _, description := stringPartition(optionDescription, " ")
  214. options = strings.Replace(options, ",", " ", -1)
  215. options = strings.Replace(options, "=", " ", -1)
  216. short := ""
  217. long := ""
  218. argcount := 0
  219. var value interface{}
  220. value = false
  221. reDefault := regexp.MustCompile(`(?i)\[default: (.*)\]`)
  222. for _, s := range strings.Fields(options) {
  223. if strings.HasPrefix(s, "--") {
  224. long = s
  225. } else if strings.HasPrefix(s, "-") {
  226. short = s
  227. } else {
  228. argcount = 1
  229. }
  230. if argcount > 0 {
  231. matched := reDefault.FindAllStringSubmatch(description, -1)
  232. if len(matched) > 0 {
  233. value = matched[0][1]
  234. } else {
  235. value = nil
  236. }
  237. }
  238. }
  239. return newOption(short, long, argcount, value)
  240. }
  241. func parseExpr(tokens *tokenList, options *patternList) (patternList, error) {
  242. // expr ::= seq ( '|' seq )* ;
  243. seq, err := parseSeq(tokens, options)
  244. if err != nil {
  245. return nil, err
  246. }
  247. if !tokens.current().eq("|") {
  248. return seq, nil
  249. }
  250. var result patternList
  251. if len(seq) > 1 {
  252. result = patternList{newRequired(seq...)}
  253. } else {
  254. result = seq
  255. }
  256. for tokens.current().eq("|") {
  257. tokens.move()
  258. seq, err = parseSeq(tokens, options)
  259. if err != nil {
  260. return nil, err
  261. }
  262. if len(seq) > 1 {
  263. result = append(result, newRequired(seq...))
  264. } else {
  265. result = append(result, seq...)
  266. }
  267. }
  268. if len(result) > 1 {
  269. return patternList{newEither(result...)}, nil
  270. }
  271. return result, nil
  272. }
  273. func parseSeq(tokens *tokenList, options *patternList) (patternList, error) {
  274. // seq ::= ( atom [ '...' ] )* ;
  275. result := patternList{}
  276. for !tokens.current().match(true, "]", ")", "|") {
  277. atom, err := parseAtom(tokens, options)
  278. if err != nil {
  279. return nil, err
  280. }
  281. if tokens.current().eq("...") {
  282. atom = patternList{newOneOrMore(atom...)}
  283. tokens.move()
  284. }
  285. result = append(result, atom...)
  286. }
  287. return result, nil
  288. }
  289. func parseAtom(tokens *tokenList, options *patternList) (patternList, error) {
  290. // atom ::= '(' expr ')' | '[' expr ']' | 'options' | long | shorts | argument | command ;
  291. tok := tokens.current()
  292. result := patternList{}
  293. if tokens.current().match(false, "(", "[") {
  294. tokens.move()
  295. var matching string
  296. pl, err := parseExpr(tokens, options)
  297. if err != nil {
  298. return nil, err
  299. }
  300. if tok.eq("(") {
  301. matching = ")"
  302. result = patternList{newRequired(pl...)}
  303. } else if tok.eq("[") {
  304. matching = "]"
  305. result = patternList{newOptional(pl...)}
  306. }
  307. moved := tokens.move()
  308. if !moved.eq(matching) {
  309. return nil, tokens.errorFunc("unmatched '%s', expected: '%s' got: '%s'", tok, matching, moved)
  310. }
  311. return result, nil
  312. } else if tok.eq("options") {
  313. tokens.move()
  314. return patternList{newOptionsShortcut()}, nil
  315. } else if tok.hasPrefix("--") && !tok.eq("--") {
  316. return parseLong(tokens, options)
  317. } else if tok.hasPrefix("-") && !tok.eq("-") && !tok.eq("--") {
  318. return parseShorts(tokens, options)
  319. } else if tok.hasPrefix("<") && tok.hasSuffix(">") || tok.isUpper() {
  320. return patternList{newArgument(tokens.move().String(), nil)}, nil
  321. }
  322. return patternList{newCommand(tokens.move().String(), false)}, nil
  323. }
  324. func parseLong(tokens *tokenList, options *patternList) (patternList, error) {
  325. // long ::= '--' chars [ ( ' ' | '=' ) chars ] ;
  326. long, eq, v := stringPartition(tokens.move().String(), "=")
  327. var value interface{}
  328. var opt *pattern
  329. if eq == "" && v == "" {
  330. value = nil
  331. } else {
  332. value = v
  333. }
  334. if !strings.HasPrefix(long, "--") {
  335. return nil, newError("long option '%s' doesn't start with --", long)
  336. }
  337. similar := patternList{}
  338. for _, o := range *options {
  339. if o.long == long {
  340. similar = append(similar, o)
  341. }
  342. }
  343. if tokens.err == errorUser && len(similar) == 0 { // if no exact match
  344. similar = patternList{}
  345. for _, o := range *options {
  346. if strings.HasPrefix(o.long, long) {
  347. similar = append(similar, o)
  348. }
  349. }
  350. }
  351. if len(similar) > 1 { // might be simply specified ambiguously 2+ times?
  352. similarLong := make([]string, len(similar))
  353. for i, s := range similar {
  354. similarLong[i] = s.long
  355. }
  356. return nil, tokens.errorFunc("%s is not a unique prefix: %s?", long, strings.Join(similarLong, ", "))
  357. } else if len(similar) < 1 {
  358. argcount := 0
  359. if eq == "=" {
  360. argcount = 1
  361. }
  362. opt = newOption("", long, argcount, false)
  363. *options = append(*options, opt)
  364. if tokens.err == errorUser {
  365. var val interface{}
  366. if argcount > 0 {
  367. val = value
  368. } else {
  369. val = true
  370. }
  371. opt = newOption("", long, argcount, val)
  372. }
  373. } else {
  374. opt = newOption(similar[0].short, similar[0].long, similar[0].argcount, similar[0].value)
  375. if opt.argcount == 0 {
  376. if value != nil {
  377. return nil, tokens.errorFunc("%s must not have an argument", opt.long)
  378. }
  379. } else {
  380. if value == nil {
  381. if tokens.current().match(true, "--") {
  382. return nil, tokens.errorFunc("%s requires argument", opt.long)
  383. }
  384. moved := tokens.move()
  385. if moved != nil {
  386. value = moved.String() // only set as string if not nil
  387. }
  388. }
  389. }
  390. if tokens.err == errorUser {
  391. if value != nil {
  392. opt.value = value
  393. } else {
  394. opt.value = true
  395. }
  396. }
  397. }
  398. return patternList{opt}, nil
  399. }
  400. func parseShorts(tokens *tokenList, options *patternList) (patternList, error) {
  401. // shorts ::= '-' ( chars )* [ [ ' ' ] chars ] ;
  402. tok := tokens.move()
  403. if !tok.hasPrefix("-") || tok.hasPrefix("--") {
  404. return nil, newError("short option '%s' doesn't start with -", tok)
  405. }
  406. left := strings.TrimLeft(tok.String(), "-")
  407. parsed := patternList{}
  408. for left != "" {
  409. var opt *pattern
  410. short := "-" + left[0:1]
  411. left = left[1:]
  412. similar := patternList{}
  413. for _, o := range *options {
  414. if o.short == short {
  415. similar = append(similar, o)
  416. }
  417. }
  418. if len(similar) > 1 {
  419. return nil, tokens.errorFunc("%s is specified ambiguously %d times", short, len(similar))
  420. } else if len(similar) < 1 {
  421. opt = newOption(short, "", 0, false)
  422. *options = append(*options, opt)
  423. if tokens.err == errorUser {
  424. opt = newOption(short, "", 0, true)
  425. }
  426. } else { // why copying is necessary here?
  427. opt = newOption(short, similar[0].long, similar[0].argcount, similar[0].value)
  428. var value interface{}
  429. if opt.argcount > 0 {
  430. if left == "" {
  431. if tokens.current().match(true, "--") {
  432. return nil, tokens.errorFunc("%s requires argument", short)
  433. }
  434. value = tokens.move().String()
  435. } else {
  436. value = left
  437. left = ""
  438. }
  439. }
  440. if tokens.err == errorUser {
  441. if value != nil {
  442. opt.value = value
  443. } else {
  444. opt.value = true
  445. }
  446. }
  447. }
  448. parsed = append(parsed, opt)
  449. }
  450. return parsed, nil
  451. }
  452. func newTokenList(source []string, err errorType) *tokenList {
  453. errorFunc := newError
  454. if err == errorUser {
  455. errorFunc = newUserError
  456. } else if err == errorLanguage {
  457. errorFunc = newLanguageError
  458. }
  459. return &tokenList{source, errorFunc, err}
  460. }
  461. func tokenListFromString(source string) *tokenList {
  462. return newTokenList(strings.Fields(source), errorUser)
  463. }
  464. func tokenListFromPattern(source string) *tokenList {
  465. p := regexp.MustCompile(`([\[\]\(\)\|]|\.\.\.)`)
  466. source = p.ReplaceAllString(source, ` $1 `)
  467. p = regexp.MustCompile(`\s+|(\S*<.*?>)`)
  468. split := p.Split(source, -1)
  469. match := p.FindAllStringSubmatch(source, -1)
  470. var result []string
  471. l := len(split)
  472. for i := 0; i < l; i++ {
  473. if len(split[i]) > 0 {
  474. result = append(result, split[i])
  475. }
  476. if i < l-1 && len(match[i][1]) > 0 {
  477. result = append(result, match[i][1])
  478. }
  479. }
  480. return newTokenList(result, errorLanguage)
  481. }
  482. func formalUsage(section string) (string, error) {
  483. _, _, section = stringPartition(section, ":") // drop "usage:"
  484. pu := strings.Fields(section)
  485. if len(pu) == 0 {
  486. return "", newLanguageError("no fields found in usage (perhaps a spacing error).")
  487. }
  488. result := "( "
  489. for _, s := range pu[1:] {
  490. if s == pu[0] {
  491. result += ") | ( "
  492. } else {
  493. result += s + " "
  494. }
  495. }
  496. result += ")"
  497. return result, nil
  498. }
  499. func extras(help bool, version string, options patternList, doc string) string {
  500. if help {
  501. for _, o := range options {
  502. if (o.name == "-h" || o.name == "--help") && o.value == true {
  503. return strings.Trim(doc, "\n")
  504. }
  505. }
  506. }
  507. if version != "" {
  508. for _, o := range options {
  509. if (o.name == "--version") && o.value == true {
  510. return version
  511. }
  512. }
  513. }
  514. return ""
  515. }
  516. type errorType int
  517. const (
  518. errorUser errorType = iota
  519. errorLanguage
  520. )
  521. func (e errorType) String() string {
  522. switch e {
  523. case errorUser:
  524. return "errorUser"
  525. case errorLanguage:
  526. return "errorLanguage"
  527. }
  528. return ""
  529. }
  530. // UserError records an error with program arguments.
  531. type UserError struct {
  532. msg string
  533. Usage string
  534. }
  535. func (e UserError) Error() string {
  536. return e.msg
  537. }
  538. func newUserError(msg string, f ...interface{}) error {
  539. return &UserError{fmt.Sprintf(msg, f...), ""}
  540. }
  541. // LanguageError records an error with the doc string.
  542. type LanguageError struct {
  543. msg string
  544. }
  545. func (e LanguageError) Error() string {
  546. return e.msg
  547. }
  548. func newLanguageError(msg string, f ...interface{}) error {
  549. return &LanguageError{fmt.Sprintf(msg, f...)}
  550. }
  551. var newError = fmt.Errorf
  552. type tokenList struct {
  553. tokens []string
  554. errorFunc func(string, ...interface{}) error
  555. err errorType
  556. }
  557. type token string
  558. func (t *token) eq(s string) bool {
  559. if t == nil {
  560. return false
  561. }
  562. return string(*t) == s
  563. }
  564. func (t *token) match(matchNil bool, tokenStrings ...string) bool {
  565. if t == nil && matchNil {
  566. return true
  567. } else if t == nil && !matchNil {
  568. return false
  569. }
  570. for _, tok := range tokenStrings {
  571. if tok == string(*t) {
  572. return true
  573. }
  574. }
  575. return false
  576. }
  577. func (t *token) hasPrefix(prefix string) bool {
  578. if t == nil {
  579. return false
  580. }
  581. return strings.HasPrefix(string(*t), prefix)
  582. }
  583. func (t *token) hasSuffix(suffix string) bool {
  584. if t == nil {
  585. return false
  586. }
  587. return strings.HasSuffix(string(*t), suffix)
  588. }
  589. func (t *token) isUpper() bool {
  590. if t == nil {
  591. return false
  592. }
  593. return isStringUppercase(string(*t))
  594. }
  595. func (t *token) String() string {
  596. if t == nil {
  597. return ""
  598. }
  599. return string(*t)
  600. }
  601. func (tl *tokenList) current() *token {
  602. if len(tl.tokens) > 0 {
  603. return (*token)(&(tl.tokens[0]))
  604. }
  605. return nil
  606. }
  607. func (tl *tokenList) length() int {
  608. return len(tl.tokens)
  609. }
  610. func (tl *tokenList) move() *token {
  611. if len(tl.tokens) > 0 {
  612. t := tl.tokens[0]
  613. tl.tokens = tl.tokens[1:]
  614. return (*token)(&t)
  615. }
  616. return nil
  617. }
  618. type patternType uint
  619. const (
  620. // leaf
  621. patternArgument patternType = 1 << iota
  622. patternCommand
  623. patternOption
  624. // branch
  625. patternRequired
  626. patternOptionAL
  627. patternOptionSSHORTCUT // Marker/placeholder for [options] shortcut.
  628. patternOneOrMore
  629. patternEither
  630. patternLeaf = patternArgument +
  631. patternCommand +
  632. patternOption
  633. patternBranch = patternRequired +
  634. patternOptionAL +
  635. patternOptionSSHORTCUT +
  636. patternOneOrMore +
  637. patternEither
  638. patternAll = patternLeaf + patternBranch
  639. patternDefault = 0
  640. )
  641. func (pt patternType) String() string {
  642. switch pt {
  643. case patternArgument:
  644. return "argument"
  645. case patternCommand:
  646. return "command"
  647. case patternOption:
  648. return "option"
  649. case patternRequired:
  650. return "required"
  651. case patternOptionAL:
  652. return "optional"
  653. case patternOptionSSHORTCUT:
  654. return "optionsshortcut"
  655. case patternOneOrMore:
  656. return "oneormore"
  657. case patternEither:
  658. return "either"
  659. case patternLeaf:
  660. return "leaf"
  661. case patternBranch:
  662. return "branch"
  663. case patternAll:
  664. return "all"
  665. case patternDefault:
  666. return "default"
  667. }
  668. return ""
  669. }
  670. type pattern struct {
  671. t patternType
  672. children patternList
  673. name string
  674. value interface{}
  675. short string
  676. long string
  677. argcount int
  678. }
  679. type patternList []*pattern
  680. func newBranchPattern(t patternType, pl ...*pattern) *pattern {
  681. var p pattern
  682. p.t = t
  683. p.children = make(patternList, len(pl))
  684. copy(p.children, pl)
  685. return &p
  686. }
  687. func newRequired(pl ...*pattern) *pattern {
  688. return newBranchPattern(patternRequired, pl...)
  689. }
  690. func newEither(pl ...*pattern) *pattern {
  691. return newBranchPattern(patternEither, pl...)
  692. }
  693. func newOneOrMore(pl ...*pattern) *pattern {
  694. return newBranchPattern(patternOneOrMore, pl...)
  695. }
  696. func newOptional(pl ...*pattern) *pattern {
  697. return newBranchPattern(patternOptionAL, pl...)
  698. }
  699. func newOptionsShortcut() *pattern {
  700. var p pattern
  701. p.t = patternOptionSSHORTCUT
  702. return &p
  703. }
  704. func newLeafPattern(t patternType, name string, value interface{}) *pattern {
  705. // default: value=nil
  706. var p pattern
  707. p.t = t
  708. p.name = name
  709. p.value = value
  710. return &p
  711. }
  712. func newArgument(name string, value interface{}) *pattern {
  713. // default: value=nil
  714. return newLeafPattern(patternArgument, name, value)
  715. }
  716. func newCommand(name string, value interface{}) *pattern {
  717. // default: value=false
  718. var p pattern
  719. p.t = patternCommand
  720. p.name = name
  721. p.value = value
  722. return &p
  723. }
  724. func newOption(short, long string, argcount int, value interface{}) *pattern {
  725. // default: "", "", 0, false
  726. var p pattern
  727. p.t = patternOption
  728. p.short = short
  729. p.long = long
  730. if long != "" {
  731. p.name = long
  732. } else {
  733. p.name = short
  734. }
  735. p.argcount = argcount
  736. if value == false && argcount > 0 {
  737. p.value = nil
  738. } else {
  739. p.value = value
  740. }
  741. return &p
  742. }
  743. func (p *pattern) flat(types patternType) (patternList, error) {
  744. if p.t&patternLeaf != 0 {
  745. if types == patternDefault {
  746. types = patternAll
  747. }
  748. if p.t&types != 0 {
  749. return patternList{p}, nil
  750. }
  751. return patternList{}, nil
  752. }
  753. if p.t&patternBranch != 0 {
  754. if p.t&types != 0 {
  755. return patternList{p}, nil
  756. }
  757. result := patternList{}
  758. for _, child := range p.children {
  759. childFlat, err := child.flat(types)
  760. if err != nil {
  761. return nil, err
  762. }
  763. result = append(result, childFlat...)
  764. }
  765. return result, nil
  766. }
  767. return nil, newError("unknown pattern type: %d, %d", p.t, types)
  768. }
  769. func (p *pattern) fix() error {
  770. err := p.fixIdentities(nil)
  771. if err != nil {
  772. return err
  773. }
  774. p.fixRepeatingArguments()
  775. return nil
  776. }
  777. func (p *pattern) fixIdentities(uniq patternList) error {
  778. // Make pattern-tree tips point to same object if they are equal.
  779. if p.t&patternBranch == 0 {
  780. return nil
  781. }
  782. if uniq == nil {
  783. pFlat, err := p.flat(patternDefault)
  784. if err != nil {
  785. return err
  786. }
  787. uniq = pFlat.unique()
  788. }
  789. for i, child := range p.children {
  790. if child.t&patternBranch == 0 {
  791. ind, err := uniq.index(child)
  792. if err != nil {
  793. return err
  794. }
  795. p.children[i] = uniq[ind]
  796. } else {
  797. err := child.fixIdentities(uniq)
  798. if err != nil {
  799. return err
  800. }
  801. }
  802. }
  803. return nil
  804. }
  805. func (p *pattern) fixRepeatingArguments() {
  806. // Fix elements that should accumulate/increment values.
  807. var either []patternList
  808. for _, child := range p.transform().children {
  809. either = append(either, child.children)
  810. }
  811. for _, cas := range either {
  812. casMultiple := patternList{}
  813. for _, e := range cas {
  814. if cas.count(e) > 1 {
  815. casMultiple = append(casMultiple, e)
  816. }
  817. }
  818. for _, e := range casMultiple {
  819. if e.t == patternArgument || e.t == patternOption && e.argcount > 0 {
  820. switch e.value.(type) {
  821. case string:
  822. e.value = strings.Fields(e.value.(string))
  823. case []string:
  824. default:
  825. e.value = []string{}
  826. }
  827. }
  828. if e.t == patternCommand || e.t == patternOption && e.argcount == 0 {
  829. e.value = 0
  830. }
  831. }
  832. }
  833. }
  834. func (p *pattern) match(left *patternList, collected *patternList) (bool, *patternList, *patternList) {
  835. if collected == nil {
  836. collected = &patternList{}
  837. }
  838. if p.t&patternRequired != 0 {
  839. l := left
  840. c := collected
  841. for _, p := range p.children {
  842. var matched bool
  843. matched, l, c = p.match(l, c)
  844. if !matched {
  845. return false, left, collected
  846. }
  847. }
  848. return true, l, c
  849. } else if p.t&patternOptionAL != 0 || p.t&patternOptionSSHORTCUT != 0 {
  850. for _, p := range p.children {
  851. _, left, collected = p.match(left, collected)
  852. }
  853. return true, left, collected
  854. } else if p.t&patternOneOrMore != 0 {
  855. if len(p.children) != 1 {
  856. panic("OneOrMore.match(): assert len(p.children) == 1")
  857. }
  858. l := left
  859. c := collected
  860. var lAlt *patternList
  861. matched := true
  862. times := 0
  863. for matched {
  864. // could it be that something didn't match but changed l or c?
  865. matched, l, c = p.children[0].match(l, c)
  866. if matched {
  867. times++
  868. }
  869. if lAlt == l {
  870. break
  871. }
  872. lAlt = l
  873. }
  874. if times >= 1 {
  875. return true, l, c
  876. }
  877. return false, left, collected
  878. } else if p.t&patternEither != 0 {
  879. type outcomeStruct struct {
  880. matched bool
  881. left *patternList
  882. collected *patternList
  883. length int
  884. }
  885. outcomes := []outcomeStruct{}
  886. for _, p := range p.children {
  887. matched, l, c := p.match(left, collected)
  888. outcome := outcomeStruct{matched, l, c, len(*l)}
  889. if matched {
  890. outcomes = append(outcomes, outcome)
  891. }
  892. }
  893. if len(outcomes) > 0 {
  894. minLen := outcomes[0].length
  895. minIndex := 0
  896. for i, v := range outcomes {
  897. if v.length < minLen {
  898. minIndex = i
  899. }
  900. }
  901. return outcomes[minIndex].matched, outcomes[minIndex].left, outcomes[minIndex].collected
  902. }
  903. return false, left, collected
  904. } else if p.t&patternLeaf != 0 {
  905. pos, match := p.singleMatch(left)
  906. var increment interface{}
  907. if match == nil {
  908. return false, left, collected
  909. }
  910. leftAlt := make(patternList, len((*left)[:pos]), len((*left)[:pos])+len((*left)[pos+1:]))
  911. copy(leftAlt, (*left)[:pos])
  912. leftAlt = append(leftAlt, (*left)[pos+1:]...)
  913. sameName := patternList{}
  914. for _, a := range *collected {
  915. if a.name == p.name {
  916. sameName = append(sameName, a)
  917. }
  918. }
  919. switch p.value.(type) {
  920. case int, []string:
  921. switch p.value.(type) {
  922. case int:
  923. increment = 1
  924. case []string:
  925. switch match.value.(type) {
  926. case string:
  927. increment = []string{match.value.(string)}
  928. default:
  929. increment = match.value
  930. }
  931. }
  932. if len(sameName) == 0 {
  933. match.value = increment
  934. collectedMatch := make(patternList, len(*collected), len(*collected)+1)
  935. copy(collectedMatch, *collected)
  936. collectedMatch = append(collectedMatch, match)
  937. return true, &leftAlt, &collectedMatch
  938. }
  939. switch sameName[0].value.(type) {
  940. case int:
  941. sameName[0].value = sameName[0].value.(int) + increment.(int)
  942. case []string:
  943. sameName[0].value = append(sameName[0].value.([]string), increment.([]string)...)
  944. }
  945. return true, &leftAlt, collected
  946. }
  947. collectedMatch := make(patternList, len(*collected), len(*collected)+1)
  948. copy(collectedMatch, *collected)
  949. collectedMatch = append(collectedMatch, match)
  950. return true, &leftAlt, &collectedMatch
  951. }
  952. panic("unmatched type")
  953. }
  954. func (p *pattern) singleMatch(left *patternList) (int, *pattern) {
  955. if p.t&patternArgument != 0 {
  956. for n, pat := range *left {
  957. if pat.t&patternArgument != 0 {
  958. return n, newArgument(p.name, pat.value)
  959. }
  960. }
  961. return -1, nil
  962. } else if p.t&patternCommand != 0 {
  963. for n, pat := range *left {
  964. if pat.t&patternArgument != 0 {
  965. if pat.value == p.name {
  966. return n, newCommand(p.name, true)
  967. }
  968. break
  969. }
  970. }
  971. return -1, nil
  972. } else if p.t&patternOption != 0 {
  973. for n, pat := range *left {
  974. if p.name == pat.name {
  975. return n, pat
  976. }
  977. }
  978. return -1, nil
  979. }
  980. panic("unmatched type")
  981. }
  982. func (p *pattern) String() string {
  983. if p.t&patternOption != 0 {
  984. return fmt.Sprintf("%s(%s, %s, %d, %+v)", p.t, p.short, p.long, p.argcount, p.value)
  985. } else if p.t&patternLeaf != 0 {
  986. return fmt.Sprintf("%s(%s, %+v)", p.t, p.name, p.value)
  987. } else if p.t&patternBranch != 0 {
  988. result := ""
  989. for i, child := range p.children {
  990. if i > 0 {
  991. result += ", "
  992. }
  993. result += child.String()
  994. }
  995. return fmt.Sprintf("%s(%s)", p.t, result)
  996. }
  997. panic("unmatched type")
  998. }
  999. func (p *pattern) transform() *pattern {
  1000. /*
  1001. Expand pattern into an (almost) equivalent one, but with single Either.
  1002. Example: ((-a | -b) (-c | -d)) => (-a -c | -a -d | -b -c | -b -d)
  1003. Quirks: [-a] => (-a), (-a...) => (-a -a)
  1004. */
  1005. result := []patternList{}
  1006. groups := []patternList{patternList{p}}
  1007. parents := patternRequired +
  1008. patternOptionAL +
  1009. patternOptionSSHORTCUT +
  1010. patternEither +
  1011. patternOneOrMore
  1012. for len(groups) > 0 {
  1013. children := groups[0]
  1014. groups = groups[1:]
  1015. var child *pattern
  1016. for _, c := range children {
  1017. if c.t&parents != 0 {
  1018. child = c
  1019. break
  1020. }
  1021. }
  1022. if child != nil {
  1023. children.remove(child)
  1024. if child.t&patternEither != 0 {
  1025. for _, c := range child.children {
  1026. r := patternList{}
  1027. r = append(r, c)
  1028. r = append(r, children...)
  1029. groups = append(groups, r)
  1030. }
  1031. } else if child.t&patternOneOrMore != 0 {
  1032. r := patternList{}
  1033. r = append(r, child.children.double()...)
  1034. r = append(r, children...)
  1035. groups = append(groups, r)
  1036. } else {
  1037. r := patternList{}
  1038. r = append(r, child.children...)
  1039. r = append(r, children...)
  1040. groups = append(groups, r)
  1041. }
  1042. } else {
  1043. result = append(result, children)
  1044. }
  1045. }
  1046. either := patternList{}
  1047. for _, e := range result {
  1048. either = append(either, newRequired(e...))
  1049. }
  1050. return newEither(either...)
  1051. }
  1052. func (p *pattern) eq(other *pattern) bool {
  1053. return reflect.DeepEqual(p, other)
  1054. }
  1055. func (pl patternList) unique() patternList {
  1056. table := make(map[string]bool)
  1057. result := patternList{}
  1058. for _, v := range pl {
  1059. if !table[v.String()] {
  1060. table[v.String()] = true
  1061. result = append(result, v)
  1062. }
  1063. }
  1064. return result
  1065. }
  1066. func (pl patternList) index(p *pattern) (int, error) {
  1067. for i, c := range pl {
  1068. if c.eq(p) {
  1069. return i, nil
  1070. }
  1071. }
  1072. return -1, newError("%s not in list", p)
  1073. }
  1074. func (pl patternList) count(p *pattern) int {
  1075. count := 0
  1076. for _, c := range pl {
  1077. if c.eq(p) {
  1078. count++
  1079. }
  1080. }
  1081. return count
  1082. }
  1083. func (pl patternList) diff(l patternList) patternList {
  1084. lAlt := make(patternList, len(l))
  1085. copy(lAlt, l)
  1086. result := make(patternList, 0, len(pl))
  1087. for _, v := range pl {
  1088. if v != nil {
  1089. match := false
  1090. for i, w := range lAlt {
  1091. if w.eq(v) {
  1092. match = true
  1093. lAlt[i] = nil
  1094. break
  1095. }
  1096. }
  1097. if match == false {
  1098. result = append(result, v)
  1099. }
  1100. }
  1101. }
  1102. return result
  1103. }
  1104. func (pl patternList) double() patternList {
  1105. l := len(pl)
  1106. result := make(patternList, l*2)
  1107. copy(result, pl)
  1108. copy(result[l:2*l], pl)
  1109. return result
  1110. }
  1111. func (pl *patternList) remove(p *pattern) {
  1112. (*pl) = pl.diff(patternList{p})
  1113. }
  1114. func (pl patternList) dictionary() map[string]interface{} {
  1115. dict := make(map[string]interface{})
  1116. for _, a := range pl {
  1117. dict[a.name] = a.value
  1118. }
  1119. return dict
  1120. }
  1121. func stringPartition(s, sep string) (string, string, string) {
  1122. sepPos := strings.Index(s, sep)
  1123. if sepPos == -1 { // no seperator found
  1124. return s, "", ""
  1125. }
  1126. split := strings.SplitN(s, sep, 2)
  1127. return split[0], sep, split[1]
  1128. }
  1129. // returns true if all cased characters in the string are uppercase
  1130. // and there are there is at least one cased charcter
  1131. func isStringUppercase(s string) bool {
  1132. if strings.ToUpper(s) != s {
  1133. return false
  1134. }
  1135. for _, c := range []rune(s) {
  1136. if unicode.IsUpper(c) {
  1137. return true
  1138. }
  1139. }
  1140. return false
  1141. }