internal_parsing.odin 3.5 KB

123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108109110111112113114115116117118119120121122123124125126127128129130131132133134135136137138139140141142143144145146147148149150151152153154155156157158159160161162163164165166167168169170
  1. //+private
  2. package flags
  3. import "core:container/bit_array"
  4. import "core:strconv"
  5. import "core:strings"
  6. // Used to group state together.
  7. Parser :: struct {
  8. // `fields_set` tracks which arguments have been set.
  9. // It uses their struct field index.
  10. fields_set: bit_array.Bit_Array,
  11. // `filled_pos` tracks which arguments have been filled into positional
  12. // spots, much like how `fmt` treats them.
  13. filled_pos: bit_array.Bit_Array,
  14. }
  15. parse_one_odin_arg :: proc(model: ^$T, parser: ^Parser, arg: string) -> (error: Error) {
  16. arg := arg
  17. if strings.has_prefix(arg, "-") {
  18. arg = arg[1:]
  19. flag: string
  20. assignment_rune: rune
  21. find_assignment: for r, i in arg {
  22. switch r {
  23. case ':', '=':
  24. assignment_rune = r
  25. flag = arg[:i]
  26. arg = arg[1 + i:]
  27. break find_assignment
  28. case:
  29. continue find_assignment
  30. }
  31. }
  32. if assignment_rune == 0 {
  33. if len(arg) == 0 {
  34. return Parse_Error {
  35. .No_Flag,
  36. "No flag was given.",
  37. }
  38. }
  39. // -flag
  40. set_odin_flag(model, parser, arg) or_return
  41. } else if assignment_rune == ':' {
  42. // -flag:option <OR> -map:key=value
  43. error = set_option(model, parser, flag, arg)
  44. if error != nil {
  45. // -flag:option did not work, so this may be a -map:key=value set.
  46. find_equals: for r, i in arg {
  47. if r == '=' {
  48. key := arg[:i]
  49. arg = arg[1 + i:]
  50. error = set_key_value(model, parser, flag, key, arg)
  51. break find_equals
  52. }
  53. }
  54. }
  55. } else {
  56. // -flag=option, alternative syntax
  57. set_option(model, parser, flag, arg) or_return
  58. }
  59. } else {
  60. // positional
  61. error = push_positional(model, parser, arg)
  62. }
  63. return
  64. }
  65. parse_one_unix_arg :: proc(model: ^$T, parser: ^Parser, arg: string) -> (
  66. future_args: int,
  67. current_flag: string,
  68. error: Error,
  69. ) {
  70. arg := arg
  71. if strings.has_prefix(arg, "-") {
  72. // -flag
  73. arg = arg[1:]
  74. if strings.has_prefix(arg, "-") {
  75. // Allow `--` to function as `-`.
  76. arg = arg[1:]
  77. if len(arg) == 0 {
  78. // `--`, and only `--`.
  79. // Everything from now on will be treated as an argument.
  80. future_args = max(int)
  81. current_flag = INTERNAL_VARIADIC_FLAG
  82. return
  83. }
  84. }
  85. flag: string
  86. find_assignment: for r, i in arg {
  87. if r == '=' {
  88. // --flag=option
  89. flag = arg[:i]
  90. arg = arg[1 + i:]
  91. error = set_option(model, parser, flag, arg)
  92. return
  93. }
  94. }
  95. // --flag option, potentially
  96. future_args = set_unix_flag(model, parser, arg) or_return
  97. current_flag = arg
  98. } else {
  99. // positional
  100. error = push_positional(model, parser, arg)
  101. }
  102. return
  103. }
  104. // Parse a number of requirements specifier.
  105. //
  106. // Examples:
  107. //
  108. // `min`
  109. // `<max`
  110. // `min<max`
  111. parse_requirements :: proc(str: string) -> (minimum, maximum: int, ok: bool) {
  112. if len(str) == 0 {
  113. return 1, max(int), true
  114. }
  115. if less_than := strings.index_byte(str, '<'); less_than != -1 {
  116. if len(str) == 1 {
  117. return 0, 0, false
  118. }
  119. #no_bounds_check left := str[:less_than]
  120. #no_bounds_check right := str[1 + less_than:]
  121. if left_value, parse_ok := strconv.parse_u64_of_base(left, 10); parse_ok {
  122. minimum = cast(int)left_value
  123. } else if len(left) > 0 {
  124. return 0, 0, false
  125. }
  126. if right_value, parse_ok := strconv.parse_u64_of_base(right, 10); parse_ok {
  127. maximum = cast(int)right_value
  128. } else if len(right) > 0 {
  129. return 0, 0, false
  130. } else {
  131. maximum = max(int)
  132. }
  133. } else {
  134. if value, parse_ok := strconv.parse_u64_of_base(str, 10); parse_ok {
  135. minimum = cast(int)value
  136. maximum = max(int)
  137. } else {
  138. return 0, 0, false
  139. }
  140. }
  141. ok = true
  142. return
  143. }