From 62a8ab9006413b9a74db75aacdecc9dc463088ff Mon Sep 17 00:00:00 2001 From: Flaviu Tamas Date: Fri, 10 Apr 2015 13:54:24 -0400 Subject: [PATCH] Throw an exception when replacing with a nil value --- README.asciidoc | 2 ++ src/private/util.nim | 71 ++++++++++++++++++++++++-------------------- test/replace.nim | 4 +++ 3 files changed, 45 insertions(+), 32 deletions(-) diff --git a/README.asciidoc b/README.asciidoc index 26a9c66168..c307cc153a 100644 --- a/README.asciidoc +++ b/README.asciidoc @@ -95,6 +95,8 @@ If `sub` is a string, the syntax is as follows: - `$#` - first capture - `$0` - full match +If a given capture is missing, a `ValueError` exception is thrown. + [[proc-escapere]] ==== escapeRe(string): string diff --git a/src/private/util.nim b/src/private/util.nim index 72be023b21..00fd40fac9 100644 --- a/src/private/util.nim +++ b/src/private/util.nim @@ -9,6 +9,12 @@ proc fget*[K, V](self: Table[K, V], key: K): V = const Ident = {'a'..'z', 'A'..'Z', '0'..'9', '_', '\128'..'\255'} const StartIdent = Ident - {'0'..'9'} +proc checkNil(arg: string): string = + if arg == nil: + raise newException(ValueError, "Cannot use nil capture") + else: + return arg + template formatStr*(howExpr, namegetter, idgetter: expr): expr = let how = howExpr var val = newStringOfCap(how.len) @@ -19,37 +25,38 @@ template formatStr*(howExpr, namegetter, idgetter: expr): expr = if how[i] != '$': val.add(how[i]) i += 1 - elif how[i + 1] == '$': - val.add('$') - i += 2 - elif how[i + 1] == '#': - var id {.inject.} = lastNum - val.add(idgetter) - lastNum += 1 - i += 2 - elif how[i + 1] in {'0'..'9'}: - i += 1 - var id {.inject.} = 0 - while i < how.len and how[i] in {'0'..'9'}: - id += (id * 10) + (ord(how[i]) - ord('0')) - i += 1 - val.add(idgetter) - lastNum = id + 1 - elif how[i + 1] in StartIdent: - i += 1 - var name {.inject.} = "" - while i < how.len and how[i] in Ident: - name.add(how[i]) - i += 1 - val.add(namegetter) - elif how[i + 1] == '{': - i += 2 - var name {.inject.} = "" - while i < how.len and how[i] != '}': - name.add(how[i]) - i += 1 - i += 1 - val.add(namegetter) else: - raise newException(Exception, "Syntax error in format string at " & $i) + if how[i + 1] == '$': + val.add('$') + i += 2 + elif how[i + 1] == '#': + var id {.inject.} = lastNum + val.add(checkNil(idgetter)) + lastNum += 1 + i += 2 + elif how[i + 1] in {'0'..'9'}: + i += 1 + var id {.inject.} = 0 + while i < how.len and how[i] in {'0'..'9'}: + id += (id * 10) + (ord(how[i]) - ord('0')) + i += 1 + val.add(checkNil(idgetter)) + lastNum = id + 1 + elif how[i + 1] in StartIdent: + i += 1 + var name {.inject.} = "" + while i < how.len and how[i] in Ident: + name.add(how[i]) + i += 1 + val.add(checkNil(namegetter)) + elif how[i + 1] == '{': + i += 2 + var name {.inject.} = "" + while i < how.len and how[i] != '}': + name.add(how[i]) + i += 1 + i += 1 + val.add(checkNil(namegetter)) + else: + raise newException(Exception, "Syntax error in format string at " & $i) val diff --git a/test/replace.nim b/test/replace.nim index f2fad803dc..4e0b6e3726 100644 --- a/test/replace.nim +++ b/test/replace.nim @@ -14,3 +14,7 @@ suite "replace": check("123".replace(re"(\d)(\d)", "$#$#") == "123") check("123".replace(re"(?\d)(\d)", "$foo$#$#") == "1123") check("123".replace(re"(?\d)(\d)", "${foo}$#$#") == "1123") + + test "replacing missing captures should throw instead of segfaulting": + expect ValueError: discard "ab".replace(re"(a)|(b)", "$1$2") + expect ValueError: discard "b".replace(re"(a)?(b)", "$1$2")