From 5ec8d0d6230ad7e8a98db8f17b625448226c4837 Mon Sep 17 00:00:00 2001 From: Zahary Karadjov Date: Fri, 13 May 2022 14:43:34 +0300 Subject: [PATCH] wip --- confutils/cli_parser.nim | 58 ++++++++++++++++++++++++++++++++++++++++ confutils/defs.nim | 8 +++--- 2 files changed, 61 insertions(+), 5 deletions(-) diff --git a/confutils/cli_parser.nim b/confutils/cli_parser.nim index 0cf2a99..f5554ae 100644 --- a/confutils/cli_parser.nim +++ b/confutils/cli_parser.nim @@ -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 diff --git a/confutils/defs.nim b/confutils/defs.nim index ab5d808..b4529cc 100644 --- a/confutils/defs.nim +++ b/confutils/defs.nim @@ -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