Commit 7be5e09db10b63f84cbf307a4b4de0f14b2c9181
1 parent
19ec8d35
Fixed float parsing, exported PValue, added example.nim.
Showing
4 changed files
with
82 additions
and
15 deletions
README.md
0 → 100644
| 1 | +Lapp is a command line parser that uses the regular help text for the synopsis as the specification | ||
| 2 | +for the options and arguments, it was originally written by Steve Donovan in Lua: | ||
| 3 | + | ||
| 4 | +http://lua-users.org/wiki/LappFramework | ||
| 5 | + | ||
| 6 | +...and ported to Nim by Steve. Then I made it work with current Nim. | ||
| 7 | + | ||
| 8 | +See example.nim for how to use it. |
example.nim
0 → 100644
| 1 | +import lapp, tables | ||
| 2 | + | ||
| 3 | +# This is a trivial example trying to cover all features of lapp. | ||
| 4 | + | ||
| 5 | +let help = """ | ||
| 6 | + example [options] command filenames | ||
| 7 | + | ||
| 8 | + -r Just an optional single character flag. Show the args using repr. | ||
| 9 | + -a,--alpha Or with additional long variant, no whitespace there. | ||
| 10 | + -n: A colon can be added, but has no meaning, instead () specifies further. | ||
| 11 | + -N (default 10) And it can take a value, and have a default value. | ||
| 12 | + -f (default 0.04) And be a float | ||
| 13 | + -s (default banana) Or a string | ||
| 14 | + -x (int) And it can be typed with int, string, float, stdin, stdout - without a | ||
| 15 | + default value. This implies that the option is mandatory! | ||
| 16 | + -X (int...) And allow multiples. | ||
| 17 | + -v,--verbose: (bool...) Verbosity level, "..." means can be multiple. | ||
| 18 | + -o,--out (default stdout) A file to direct to. | ||
| 19 | + <command> Arguments are string by default. | ||
| 20 | + <file>: (default stdin...) One or more files or stdin by default | ||
| 21 | + | ||
| 22 | + | ||
| 23 | + The first line in this help text is arbitrary, or rather | ||
| 24 | + its only the lines (trimmed) beginning with '-' or '<' that constitute | ||
| 25 | + the speciciation, so this text is also ignored. | ||
| 26 | + | ||
| 27 | + Things we know are not working: | ||
| 28 | + ranges. The lexer in lapp does it, but there is no more support. | ||
| 29 | + """ | ||
| 30 | + | ||
| 31 | +# We call `parse` in lapp with our help text as argument. | ||
| 32 | +# This will both parse the help text above and then, parse the | ||
| 33 | +# arguments passed to this program. A table is returned | ||
| 34 | +# with all command line elements in it, keyed by their name | ||
| 35 | +# and with a PValue as value. | ||
| 36 | +var args = parse(help) | ||
| 37 | + | ||
| 38 | +# Let's examine what we got using repr | ||
| 39 | +for k,v in args: | ||
| 40 | + echo "Parameter: " & k & " PValue: " & repr(v) | ||
| 41 | + | ||
| 42 | +# Or print out a bit cleaner | ||
| 43 | +echo "Parameters and their values:" | ||
| 44 | +echo "r == " & $args["r"].asBool | ||
| 45 | +echo "alpha == " & $args["alpha"].asBool # Long name is used as key, if its specified | ||
| 46 | +echo "n == " & $args["n"].asBool | ||
| 47 | +echo "N == " & $args["N"].asInt | ||
| 48 | +echo "f == " & $args["f"].asFloat | ||
| 49 | +echo "s == " & $args["s"].asString | ||
| 50 | +echo "x == " & $args["x"].asInt | ||
| 51 | +echo "X == " & $args["X"].asSeq.map(proc(x:PValue):int = x.asInt) | ||
| 52 | +echo "verbose == " & $args["verbose"].asSeq.len | ||
| 53 | +echo "out == " & $args["out"].filename | ||
| 54 | +echo "command == " & $args["command"].asString | ||
| 55 | +echo "file == " & $args["file"].asSeq.map(proc(x:PValue):string = x.filename) | ||
| 56 | + | ||
| 57 | + |
lapp.nim
| @@ -50,10 +50,10 @@ proc get(L: PLexer; t: var TLexType): string = | @@ -50,10 +50,10 @@ proc get(L: PLexer; t: var TLexType): string = | ||
| 50 | next(L) | 50 | next(L) |
| 51 | if thisChar(L) == '.': | 51 | if thisChar(L) == '.': |
| 52 | t = tfloat | 52 | t = tfloat |
| 53 | - result.add(c) | 53 | + result.add(thisChar(L)) |
| 54 | next(L) | 54 | next(L) |
| 55 | while thisChar(L) in Digits: | 55 | while thisChar(L) in Digits: |
| 56 | - result.add(c) | 56 | + result.add(thisChar(L)) |
| 57 | next(L) | 57 | next(L) |
| 58 | of '.': # ".", "..", "..." | 58 | of '.': # ".", "..", "..." |
| 59 | if thisChar(L) == '.': | 59 | if thisChar(L) == '.': |
| @@ -89,17 +89,17 @@ type | @@ -89,17 +89,17 @@ type | ||
| 89 | vFile, | 89 | vFile, |
| 90 | vSeq | 90 | vSeq |
| 91 | 91 | ||
| 92 | - PValue = ref TValue | ||
| 93 | - TValue = object | ||
| 94 | - case kind: TValueKind | ||
| 95 | - of vInt: asInt *: int | ||
| 96 | - of vFloat: asFloat *: float | ||
| 97 | - of vString: asString *: string | ||
| 98 | - of vBool: asBool *: bool | 92 | + PValue* = ref TValue |
| 93 | + TValue* = object | ||
| 94 | + case kind*: TValueKind | ||
| 95 | + of vInt: asInt*: int | ||
| 96 | + of vFloat: asFloat*: float | ||
| 97 | + of vString: asString*: string | ||
| 98 | + of vBool: asBool*: bool | ||
| 99 | of vFile: | 99 | of vFile: |
| 100 | - asFile *: File | ||
| 101 | - fileName *: string | ||
| 102 | - of vSeq: asSeq *: seq[PValue] | 100 | + asFile*: File |
| 101 | + fileName*: string | ||
| 102 | + of vSeq: asSeq*: seq[PValue] | ||
| 103 | 103 | ||
| 104 | proc boolValue(c: bool): PValue = PValue(kind: vBool, asBool: c) | 104 | proc boolValue(c: bool): PValue = PValue(kind: vBool, asBool: c) |
| 105 | 105 | ||
| @@ -205,6 +205,7 @@ proc parseSpec(u: string) = | @@ -205,6 +205,7 @@ proc parseSpec(u: string) = | ||
| 205 | defValue = "false" | 205 | defValue = "false" |
| 206 | 206 | ||
| 207 | if name != nil: | 207 | if name != nil: |
| 208 | + # echo("Param: " & name & " type: " & $ftype & " needsvalue: " & $(ftype != "bool") & " default: " & $defValue & " multiple: " & $multiple) | ||
| 208 | let spec = PSpec(defVal:defValue, ptype: ftype, needsValue: ftype != "bool",multiple:multiple) | 209 | let spec = PSpec(defVal:defValue, ptype: ftype, needsValue: ftype != "bool",multiple:multiple) |
| 209 | aliases[alias] = name | 210 | aliases[alias] = name |
| 210 | parm_spec[name] = spec | 211 | parm_spec[name] = spec |
| @@ -314,7 +315,7 @@ proc parseArguments(usage: string, args: seq[string]): Table[string,PValue] = | @@ -314,7 +315,7 @@ proc parseArguments(usage: string, args: seq[string]): Table[string,PValue] = | ||
| 314 | try: | 315 | try: |
| 315 | v = value.parseFloat | 316 | v = value.parseFloat |
| 316 | except: | 317 | except: |
| 317 | - fail("bad integer") | 318 | + fail("bad float") |
| 318 | pval = floatValue(v) | 319 | pval = floatValue(v) |
| 319 | of "bool": | 320 | of "bool": |
| 320 | pval = boolValue(value.parseBool) | 321 | pval = boolValue(value.parseBool) |
| @@ -359,12 +360,12 @@ proc parse*(usage: string): Table[string,PValue] = | @@ -359,12 +360,12 @@ proc parse*(usage: string): Table[string,PValue] = | ||
| 359 | 360 | ||
| 360 | when isMainModule: | 361 | when isMainModule: |
| 361 | var args = parse""" | 362 | var args = parse""" |
| 362 | - head [flags] filename | 363 | + head [flags] [file1, file2 ...] [outfile] |
| 363 | -n: (default 10) number of lines | 364 | -n: (default 10) number of lines |
| 364 | -v,--verbose: (bool...) verbosity level | 365 | -v,--verbose: (bool...) verbosity level |
| 365 | -a,--alpha useless parm | 366 | -a,--alpha useless parm |
| 366 | <file>: (default stdin...) | 367 | <file>: (default stdin...) |
| 367 | - |<out>: (default stdout) | 368 | + <out>: (default stdout) |
| 368 | """ | 369 | """ |
| 369 | 370 | ||
| 370 | echo args["n"].asInt | 371 | echo args["n"].asInt |