This commit is contained in:
Zahary Karadjov 2022-05-13 14:43:34 +03:00
parent 60d71e8029
commit 5ec8d0d623
No known key found for this signature in database
GPG Key ID: C8936F8A3073D609
2 changed files with 61 additions and 5 deletions

View File

@ -8,6 +8,11 @@ type
cmdLongOption, ## A long option such as --option
cmdShortOption ## A short option such as -c
TriBool* = enum
Yes,
No,
Maybe
OptParser* = object of RootObj ## Implementation of the command line parser.
pos*: int
inShortState: bool
@ -21,6 +26,59 @@ type
## or the argument, and the value is not "" if
## the option was given a value
type
FieldReader*[ConfigType] = proc (conf: var ConfigType, val: TaintedString)
{.gcsafe, raises: [Defect, CatchableError].}
Transition = object
nextState: uint16
fieldReaderState: FieldReaderState
CliDFA*[ConfigType] = object
flagNames: Table[string, int] # TODO replace this with perfect hashing
fieldReaders: seq[FieldReader[configType]]
##
FieldReaderState = distinct uint16
# 15 bits for the field reader index
# 1 bits to determine the type of the field reader (optional or not)
# The special value `noFieldReader` indicates that there is no
# current field Reader
numStates: int
stateTransitions: seq[Transition]
## You can think of this as a two dimentional array where we specify
## how each flag index is handled in each state.
##
## The flags that are invalid in a particular state are marked with
## the `invalidTransition` value. Otherwise, the transition indicates
## how the state
CliParserState = object
currentState: uint16
fieldReaderState: FieldReaderState
const
fieldNotExpected* = FieldReaderState max(uint16)
invalidTransition* = Transition(nextState: -1, fieldReaderState: fieldNotExpected)
template isFieldExpected(stateParam: FieldReaderState): TriBool =
let state = uint16(stateParam)
if state == uint16(fieldNotExpected):
No
elif (state and 1) != 0:
Yes:
else:
Maybe
template readerIdx(state: FieldReaderState) =
uint16(state) shr 1
template init(T: type FieldReaderState, idx: uint16, valueOptional: bool): T =
T((idx shl 1) or uint16(valueOptional))
proc parseWord(s: string, i: int, w: var string,
delim: set[char] = {'\t', ' '}): int =
result = i

View File

@ -17,9 +17,6 @@ type
OutDir* = distinct string
OutFile* = distinct string
RestOfCmdLine* = distinct string
SubCommandArgs* = distinct string
Flag* = object
name*: TaintedString
@ -46,16 +43,17 @@ template desc*(v: string) {.pragma.}
template longDesc*(v: string) {.pragma.}
template name*(v: string) {.pragma.}
template abbr*(v: string) {.pragma.}
template separator*(v: string) {.pragma.}
template defaultValue*(v: untyped) {.pragma.}
template defaultValueDesc*(v: string) {.pragma.}
template separator*(v: string) {.pragma.}
template required* {.pragma.}
template command* {.pragma.}
template argument* {.pragma.}
template arguments* {.pragma.}
template hidden* {.pragma.}
template ignore* {.pragma.}
template inlineConfiguration* {.pragma.}
template forwardedCmdArgs*(separator: string = "--")* {.pragma.}
template implicitlySelectable* {.pragma.}
## This can be applied to a case object discriminator
## to allow the value of the discriminator to be determined