Skip to content

Commit 0abba63

Browse files
committed
string and seq are not nillable anymore
Fixes #38: works on devel branch and keeps compatibility with Nim 0.18.0
1 parent cf6db16 commit 0abba63

File tree

4 files changed

+46
-52
lines changed

4 files changed

+46
-52
lines changed

src/docopt.nim

Lines changed: 27 additions & 31 deletions
Original file line numberDiff line numberDiff line change
@@ -24,6 +24,7 @@ gen_class:
2424
Pattern = ref object of RootObj
2525
m_name: string
2626
value: Value
27+
has_children: bool
2728
children: seq[Pattern]
2829

2930
ChildPattern = ref object of Pattern
@@ -57,7 +58,7 @@ proc argument(name: string, value = val()): Argument =
5758
proc command(name: string, value = val(false)): Command =
5859
Command(m_name: name, value: value)
5960

60-
proc option(short, long: string = nil, argcount = 0,
61+
proc option(short, long: string = "", argcount = 0,
6162
value = val(false)): Option =
6263
assert argcount in [0, 1]
6364
result = Option(short: short, long: long,
@@ -66,19 +67,19 @@ proc option(short, long: string = nil, argcount = 0,
6667
result.value = val()
6768

6869
proc required(children: varargs[Pattern]): Required =
69-
Required(children: @children)
70+
Required(has_children: true, children: @children, value: val())
7071

7172
proc optional(children: varargs[Pattern]): Optional =
72-
Optional(children: @children)
73+
Optional(has_children: true, children: @children, value: val())
7374

7475
proc any_options(children: varargs[Pattern]): AnyOptions =
75-
AnyOptions(children: @children)
76+
AnyOptions(has_children: true, children: @children, value: val())
7677

7778
proc one_or_more(children: varargs[Pattern]): OneOrMore =
78-
OneOrMore(children: @children)
79+
OneOrMore(has_children: true, children: @children, value: val())
7980

8081
proc either(children: varargs[Pattern]): Either =
81-
Either(children: @children)
82+
Either(has_children: true, children: @children, value: val())
8283

8384

8485
type
@@ -115,10 +116,8 @@ method match(self: Pattern, left: seq[Pattern],
115116

116117
method fix_identities(self: Pattern, uniq: seq[Pattern]) {.base, gcsafe.} =
117118
## Make pattern-tree tips point to same object if they are equal.
118-
if self.children.is_nil:
119-
return
120119
for i, child in self.children:
121-
if child.children.is_nil:
120+
if not child.has_children:
122121
assert child in uniq
123122
self.children[i] = uniq[uniq.find(child)]
124123
else:
@@ -251,7 +250,7 @@ method single_match(self: Command, left: seq[Pattern]): SingleMatchResult =
251250
proc option_parse[T](
252251
constructor: proc(short, long: string; argcount: int; value: Value): T,
253252
option_description: string): T =
254-
var short, long: string = nil
253+
var short, long: string = ""
255254
var argcount = 0
256255
var value = val(false)
257256
var (options, p, description) = option_description.strip().partition(" ")
@@ -279,7 +278,7 @@ method single_match(self: Option, left: seq[Pattern]): SingleMatchResult =
279278
raise new_exception(ValueError, "Not found")
280279

281280
method name(self: Option): string =
282-
if self.long != nil: self.long else: self.short
281+
if self.long != "": self.long else: self.short
283282

284283
method str(self: Option): string =
285284
"Option($#, $#, $#, $#)".format(self.short.str, self.long.str,
@@ -347,8 +346,7 @@ proc token_stream(source: string, error: ref Exception): TokenStream =
347346
token_stream(source.split_whitespace(), error)
348347

349348
proc current(self: TokenStream): string =
350-
if @self.len > 0:
351-
result = @self[0]
349+
if @self.len > 0: @self[0] else: ""
352350

353351
proc move(self: TokenStream): string =
354352
result = self.current
@@ -363,18 +361,18 @@ proc parse_long(tokens: TokenStream, options: var seq[Option]): seq[Pattern] =
363361
var similar = options.filter_it(it.long == long)
364362
var o: Option
365363
if tokens.error of DocoptExit and similar.len == 0: # if no exact match
366-
similar = options.filter_it(it.long != nil and
364+
similar = options.filter_it(it.long != "" and
367365
it.long.starts_with long)
368366
if similar.len > 1: # might be simply specified ambiguously 2+ times?
369367
tokens.error.msg = "$# is not a unique prefix: $#?".format(
370368
long, similar.map_it(string, it.long).join(", "))
371369
raise tokens.error
372370
elif similar.len < 1:
373371
let argcount = (if eq == "=": 1 else: 0)
374-
o = option(nil, long, argcount)
372+
o = option("", long, argcount)
375373
options.add o
376374
if tokens.error of DocoptExit:
377-
o = option(nil, long, argcount,
375+
o = option("", long, argcount,
378376
if argcount > 0: value else: val(true))
379377
else:
380378
o = option(similar[0].short, similar[0].long,
@@ -385,7 +383,7 @@ proc parse_long(tokens: TokenStream, options: var seq[Option]): seq[Pattern] =
385383
raise tokens.error
386384
else:
387385
if value.kind == vkNone:
388-
if tokens.current == nil:
386+
if tokens.current == "":
389387
tokens.error.msg = "$# requires argument".format(o.long)
390388
raise tokens.error
391389
value = val(tokens.move())
@@ -410,17 +408,17 @@ proc parse_shorts(tokens: TokenStream, options: var seq[Option]): seq[Pattern] =
410408
short, similar.len)
411409
raise tokens.error
412410
elif similar.len < 1:
413-
o = option(short, nil, 0)
411+
o = option(short, "", 0)
414412
options.add o
415413
if tokens.error of DocoptExit:
416-
o = option(short, nil, 0, val(true))
414+
o = option(short, "", 0, val(true))
417415
else: # why copying is necessary here?
418416
o = option(short, similar[0].long,
419417
similar[0].argcount, similar[0].value)
420418
var value = val()
421419
if o.argcount != 0:
422420
if left == "":
423-
if tokens.current == nil:
421+
if tokens.current == "":
424422
tokens.error.msg = "$# requires argument".format(short)
425423
raise tokens.error
426424
value = val(tokens.move())
@@ -440,7 +438,7 @@ proc parse_pattern(source: string, options: var seq[Option]): Required =
440438
new_exception(DocoptLanguageError, "")
441439
)
442440
let ret = parse_expr(tokens, options)
443-
if tokens.current != nil:
441+
if tokens.current != "":
444442
tokens.error.msg = "unexpected ending: '$#'".format(@tokens.join(" "))
445443
raise tokens.error
446444
required(ret)
@@ -467,7 +465,7 @@ proc parse_atom(tokens: TokenStream, options: var seq[Option]): seq[Pattern] {.g
467465
proc parse_seq(tokens: TokenStream, options: var seq[Option]): seq[Pattern] =
468466
## seq ::= ( atom [ '...' ] )* ;
469467
result = @[]
470-
while tokens.current notin [nil, "]", ")", "|"]:
468+
while tokens.current notin ["", "]", ")", "|"]:
471469
var atom = parse_atom(tokens, options)
472470
if tokens.current == "...":
473471
let oom = one_or_more(atom)
@@ -520,17 +518,17 @@ proc parse_argv(tokens: TokenStream, options: var seq[Option],
520518
## else:
521519
## argv ::= [ long | shorts | argument ]* [ '--' [ argument ]* ] ;
522520
result = @[]
523-
while tokens.current != nil:
521+
while tokens.current != "":
524522
if tokens.current == "--":
525-
return result & @tokens.map_it(Pattern, argument(nil, val(it)))
523+
return result & @tokens.map_it(Pattern, argument("", val(it)))
526524
elif tokens.current.starts_with "--":
527525
result.add parse_long(tokens, options)
528526
elif (tokens.current.starts_with "-") and tokens.current != "-":
529527
result.add parse_shorts(tokens, options)
530528
elif options_first:
531-
return result & @tokens.map_it(Pattern, argument(nil, val(it)))
529+
return result & @tokens.map_it(Pattern, argument("", val(it)))
532530
else:
533-
result.add argument(nil, val(tokens.move()))
531+
result.add argument("", val(tokens.move()))
534532

535533

536534
proc parse_defaults(doc: string): seq[Option] =
@@ -566,7 +564,7 @@ proc extras(help: bool, version: string, options: seq[Pattern], doc: string) =
566564
if help and options.any_it((it.name in ["-h", "--help"]) and it.value):
567565
echo(doc.strip())
568566
quit()
569-
elif version != nil and
567+
elif version != "" and
570568
options.any_it(it.name == "--version" and it.value):
571569
echo(version)
572570
quit()
@@ -576,8 +574,6 @@ proc docopt_exc(doc: string, argv: seq[string], help: bool, version: string,
576574
options_first = false): Table[string, Value] =
577575
var doc = doc.replace("\r\l", "\l")
578576

579-
var argv = (if argv.is_nil: command_line_params() else: argv)
580-
581577
var docopt_exit = new_exception(DocoptExit, "")
582578
docopt_exit.usage = printable_usage(doc)
583579

@@ -605,8 +601,8 @@ proc docopt_exc(doc: string, argv: seq[string], help: bool, version: string,
605601
raise docopt_exit
606602
607603
608-
proc docopt*(doc: string, argv: seq[string] = nil, help = true,
609-
version: string = nil, options_first = false, quit = true
604+
proc docopt*(doc: string, argv: seq[string] = command_line_params(), help = true,
605+
version: string = "", options_first = false, quit = true
610606
): Table[string, Value] {.gcsafe.} =
611607
## Parse `argv` based on command-line interface described in `doc`.
612608
##

src/docopt/util.nim

Lines changed: 1 addition & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -33,7 +33,7 @@ proc count*[T](s: openarray[T], it: T): int =
3333
proc partition*(s, sep: string): tuple[left, sep, right: string] =
3434
## "a+b".partition("+") == ("a", "+", "b")
3535
## "a+b".partition("-") == ("a+b", "", "")
36-
assert sep != nil and sep != ""
36+
assert sep != ""
3737
let pos = s.find(sep)
3838
if pos < 0:
3939
(s, "", "")

src/docopt/value.nim

Lines changed: 5 additions & 8 deletions
Original file line numberDiff line numberDiff line change
@@ -38,8 +38,8 @@ converter to_bool*(v: Value): bool =
3838
of vkNone: false
3939
of vkBool: v.bool_v
4040
of vkInt: v.int_v != 0
41-
of vkStr: v.str_v != nil and v.str_v.len > 0
42-
of vkList: not v.list_v.is_nil and v.list_v.len > 0
41+
of vkStr: v.str_v.len > 0
42+
of vkList: v.list_v.len > 0
4343

4444
proc len*(v: Value): int =
4545
## Return the integer of a vkInt Value
@@ -72,12 +72,10 @@ iterator pairs*(v: Value): tuple[key: int, val: string] =
7272
yield (key: key, val: val)
7373

7474
proc str(s: string): string =
75-
if s.is_nil: "nil"
76-
else: "\"" & s.replace("\"", "\\\"") & "\""
75+
"\"" & s.replace("\"", "\\\"") & "\""
7776

7877
proc str[T](s: seq[T]): string =
79-
if s.is_nil: "nil"
80-
else: "[" & s.map_it(string, it.str).join(", ") & "]"
78+
"[" & s.map_it(string, it.str).join(", ") & "]"
8179

8280
proc str(v: Value): string =
8381
case v.kind
@@ -93,8 +91,7 @@ proc `$`*(v: Value): string =
9391
## or a string representation of any other kind of Value.
9492
if v.kind == vkStr:
9593
v.str_v
96-
elif v.kind == vkList and
97-
not v.list_v.is_nil and v.list_v.len == 1:
94+
elif v.kind == vkList and v.list_v.len == 1:
9895
v.list_v[0]
9996
else: v.str
10097

test/test.nim

Lines changed: 13 additions & 12 deletions
Original file line numberDiff line numberDiff line change
@@ -1,4 +1,4 @@
1-
import json, strutils, tables
1+
import json, strutils, tables, options
22

33
include docopt
44

@@ -34,7 +34,8 @@ proc test(doc, args, expected_s: string): bool =
3434
echo "---------------------------------"
3535
return false
3636
37-
var doc, args, expected: string = nil
37+
var args, expected: options.Option[string]
38+
var doc: string
3839
var in_doc = false
3940
var total, passed = 0
4041
@@ -52,21 +53,21 @@ for each_line in (tests & "\n\n").split_lines():
5253
in_doc = false
5354
doc &= "\n"
5455
elif line.starts_with("$ prog"):
55-
assert args == nil and expected == nil
56-
args = line.substr(7)
56+
assert args.is_none and expected.is_none
57+
args = some(line.substr(7))
5758
elif line.starts_with("{") or line.starts_with("\""):
58-
assert args != nil and expected == nil
59-
expected = line
59+
assert args.is_some and expected.is_none
60+
expected = some(line)
6061
elif line.len > 0:
61-
assert expected != nil
62-
expected &= "\n" & line
63-
if line.len == 0 and args != nil and expected != nil:
62+
assert expected.is_some
63+
expected = some(expected.get & "\n" & line)
64+
if line.len == 0 and args.is_some and expected.is_some:
6465
total += 1
65-
if test(doc, args, expected):
66+
if test(doc, args.get, expected.get):
6667
passed += 1
6768
stdout.write("\rTests passed: $#/$#\r".format(passed, total))
68-
args = nil
69-
expected = nil
69+
args = none(string)
70+
expected = none(string)
7071
echo()
7172

7273
quit(if passed == total: 0 else: 1)

0 commit comments

Comments
 (0)