Change RegexMatch from ref to Option

Also associated changes to tests and code
This commit is contained in:
Flaviu Tamas 2015-01-28 20:33:33 -05:00
commit a1110ebb14
5 changed files with 20 additions and 23 deletions

View file

@ -18,7 +18,7 @@ type
captureNameToId: Table[string, int] captureNameToId: Table[string, int]
RegexMatch* = ref object RegexMatch* = object
## Is returned upon a match. ## Is returned upon a match.
pattern*: Regex ## The regex doing the matching. pattern*: Regex ## The regex doing the matching.
## Not nil. ## Not nil.
@ -286,10 +286,8 @@ proc re*(pattern: string, options = ""): Regex = initRegex(pattern, options)
# }}} # }}}
# Operations {{{ # Operations {{{
proc matchImpl(str: string, pattern: Regex, start, endpos: int, flags: int): RegexMatch = proc matchImpl(str: string, pattern: Regex, start, endpos: int, flags: int): Option[RegexMatch] =
new(result) var result = RegexMatch(pattern : pattern, str : str)
result.pattern = pattern
result.str = str
# See PCRE man pages. # See PCRE man pages.
# 2x capture count to make room for start-end pairs # 2x capture count to make room for start-end pairs
# 1x capture count as slack space for PCRE # 1x capture count as slack space for PCRE
@ -309,13 +307,13 @@ proc matchImpl(str: string, pattern: Regex, start, endpos: int, flags: int): Reg
cast[ptr cint](addr result.pcreMatchBounds[0]), cast[ptr cint](addr result.pcreMatchBounds[0]),
cint(vecsize)) cint(vecsize))
if execRet >= 0: if execRet >= 0:
return result return Some(result)
elif execRet == pcre.ERROR_NOMATCH: elif execRet == pcre.ERROR_NOMATCH:
return nil return None[RegexMatch]()
else: else:
raise newException(AssertionError, "Internal error: errno " & $execRet) raise newException(AssertionError, "Internal error: errno " & $execRet)
proc match*(str: string, pattern: Regex, start = 0, endpos = -1): RegexMatch = proc match*(str: string, pattern: Regex, start = 0, endpos = -1): Option[RegexMatch] =
return str.matchImpl(pattern, start, endpos, pcre.ANCHORED) return str.matchImpl(pattern, start, endpos, pcre.ANCHORED)
iterator findIter*(str: string, pattern: Regex, start = 0, endpos = -1): RegexMatch = iterator findIter*(str: string, pattern: Regex, start = 0, endpos = -1): RegexMatch =
@ -325,19 +323,18 @@ iterator findIter*(str: string, pattern: Regex, start = 0, endpos = -1): RegexMa
let endpos = if endpos == -1: str.len else: endpos let endpos = if endpos == -1: str.len else: endpos
var offset = start var offset = start
var previousMatch: RegexMatch var match: Option[RegexMatch]
while true: while true:
var flags = 0 var flags = 0
if previousMatch != nil and if match and
previousMatch.matchBounds.a == previousMatch.matchBounds.b: match.get.matchBounds.a == match.get.matchBounds.b:
# 0-len match # 0-len match
flags = pcre.NOTEMPTY_ATSTART or pcre.ANCHORED flags = pcre.NOTEMPTY_ATSTART or pcre.ANCHORED
let currentMatch = str.matchImpl(pattern, offset, endpos, flags) match = str.matchImpl(pattern, offset, endpos, flags)
previousMatch = currentMatch
if currentMatch == nil: if match.isNone:
# either the end of the input or the string # either the end of the input or the string
# cannot be split here # cannot be split here
offset += 1 offset += 1
@ -351,15 +348,15 @@ iterator findIter*(str: string, pattern: Regex, start = 0, endpos = -1): RegexMa
offset += str.runeLenAt(offset) offset += str.runeLenAt(offset)
assert(offset <= endpos) assert(offset <= endpos)
else: else:
offset = currentMatch.matchBounds.b offset = match.get.matchBounds.b
yield currentMatch yield match.get
if offset >= endpos: if offset >= endpos:
# do while # do while
break break
proc find*(str: string, pattern: Regex, start = 0, endpos = -1): RegexMatch = proc find*(str: string, pattern: Regex, start = 0, endpos = -1): Option[RegexMatch] =
## Returns a `RegexMatch` if there is a match between `start` and `endpos`, otherwise ## Returns a `RegexMatch` if there is a match between `start` and `endpos`, otherwise
## it returns nil. ## it returns nil.
## ##

View file

@ -1,4 +1,4 @@
import unittest import unittest, optional_t.nonstrict
include nre include nre
suite "captures": suite "captures":

View file

@ -1,4 +1,4 @@
import unittest, sequtils, nre import unittest, sequtils, nre, optional_t.nonstrict
suite "find": suite "find":
test "find text": test "find text":

View file

@ -1,9 +1,9 @@
include nre, unittest include nre, unittest, optional_t.nonstrict
suite "match": suite "match":
test "upper bound must be exclusive": test "upper bound must be exclusive":
check("abc".match(re"abc", endpos = 0) == nil) check("abc".match(re"abc", endpos = 0) == None[RegexMatch]())
check("abc".match(re"abc", endpos = 3) != nil) check("abc".match(re"abc", endpos = 3) != None[RegexMatch]())
test "match examples": test "match examples":
check("abc".match(re"(\w)").captures[0] == "a") check("abc".match(re"(\w)").captures[0] == "a")

View file

@ -1,4 +1,4 @@
import unittest, nre import unittest, nre, optional_t.nonstrict
suite "Misc tests": suite "Misc tests":
test "unicode": test "unicode":