make nre compile with --gc:arc

This commit is contained in:
Araq 2020-01-26 11:13:24 +01:00 • committed by Andreas Rumpf
commit 6900da314c

View file

@ -65,7 +65,6 @@ from unicode import runeLenAt
export options export options
# Type definitions {{{
type type
Regex* = ref object Regex* = ref object
## Represents the pattern that things are matched against, constructed with ## Represents the pattern that things are matched against, constructed with
@ -229,7 +228,12 @@ runnableExamples:
doAssert 0 in "abc".match(re"(\w)").get.captureBounds == true doAssert 0 in "abc".match(re"(\w)").get.captureBounds == true
doAssert "abc".match(re"").get.captureBounds[-1] == 0 .. -1 doAssert "abc".match(re"").get.captureBounds[-1] == 0 .. -1
doAssert "abc".match(re"abc").get.captureBounds[-1] == 0 .. 2 doAssert "abc".match(re"abc").get.captureBounds[-1] == 0 .. 2
# }}}
proc destroyRegex(pattern: Regex) =
pcre.free_substring(cast[cstring](pattern.pcreObj))
if pattern.pcreExtra != nil:
pcre.free_study(pattern.pcreExtra)
proc getinfo[T](pattern: Regex, opt: cint): T = proc getinfo[T](pattern: Regex, opt: cint): T =
let retcode = pcre.fullinfo(pattern.pcreObj, pattern.pcreExtra, opt, addr result) let retcode = pcre.fullinfo(pattern.pcreObj, pattern.pcreExtra, opt, addr result)
@ -238,7 +242,53 @@ proc getinfo[T](pattern: Regex, opt: cint): T =
# XXX Error message that doesn't expose implementation details # XXX Error message that doesn't expose implementation details
raise newException(FieldError, "Invalid getinfo for $1, errno $2" % [$opt, $retcode]) raise newException(FieldError, "Invalid getinfo for $1, errno $2" % [$opt, $retcode])
# Regex accessors {{{ proc getNameToNumberTable(pattern: Regex): Table[string, int] =
let entryCount = getinfo[cint](pattern, pcre.INFO_NAMECOUNT)
let entrySize = getinfo[cint](pattern, pcre.INFO_NAMEENTRYSIZE)
let table = cast[ptr UncheckedArray[uint8]](
getinfo[int](pattern, pcre.INFO_NAMETABLE))
result = initTable[string, int]()
for i in 0 ..< entryCount:
let pos = i * entrySize
let num = (int(table[pos]) shl 8) or int(table[pos + 1]) - 1
var name = ""
var idx = 2
while table[pos + idx] != 0:
name.add(char(table[pos + idx]))
idx += 1
result[name] = num
proc initRegex(pattern: string, flags: int, study = true): Regex =
new(result, destroyRegex)
result.pattern = pattern
var errorMsg: cstring
var errOffset: cint
result.pcreObj = pcre.compile(cstring(pattern),
# better hope int is at least 4 bytes..
cint(flags), addr errorMsg,
addr errOffset, nil)
if result.pcreObj == nil:
# failed to compile
raise SyntaxError(msg: $errorMsg, pos: errOffset, pattern: pattern)
if study:
var options: cint = 0
var hasJit: cint
if pcre.config(pcre.CONFIG_JIT, addr hasJit) == 0:
if hasJit == 1'i32:
options = pcre.STUDY_JIT_COMPILE
result.pcreExtra = pcre.study(result.pcreObj, options, addr errorMsg)
if errorMsg != nil:
raise StudyError(msg: $errorMsg)
result.captureNameToId = result.getNameToNumberTable()
proc captureCount*(pattern: Regex): int = proc captureCount*(pattern: Regex): int =
return getinfo[cint](pattern, pcre.INFO_CAPTURECOUNT) return getinfo[cint](pattern, pcre.INFO_CAPTURECOUNT)
@ -265,9 +315,8 @@ proc matchesCrLf(pattern: Regex): bool =
of -2: return true of -2: return true
of -1: return true of -1: return true
else: return false else: return false
# }}}
# Capture accessors {{{
func captureBounds*(pattern: RegexMatch): CaptureBounds = return CaptureBounds(pattern) func captureBounds*(pattern: RegexMatch): CaptureBounds = return CaptureBounds(pattern)
func captures*(pattern: RegexMatch): Captures = return Captures(pattern) func captures*(pattern: RegexMatch): Captures = return Captures(pattern)
@ -379,10 +428,7 @@ proc `==`*(a, b: Regex): bool =
proc `==`*(a, b: RegexMatch): bool = proc `==`*(a, b: RegexMatch): bool =
return a.pattern == b.pattern and return a.pattern == b.pattern and
a.str == b.str a.str == b.str
# }}}
# Creation & Destruction {{{
# PCRE Options {{{
const PcreOptions = { const PcreOptions = {
"NEVER_UTF": pcre.NEVER_UTF, "NEVER_UTF": pcre.NEVER_UTF,
"ANCHORED": pcre.ANCHORED, "ANCHORED": pcre.ANCHORED,
@ -438,66 +484,10 @@ proc extractOptions(pattern: string): tuple[pattern: string, flags: int, study:
result.pattern.add pattern[optionStart .. pattern.high] result.pattern.add pattern[optionStart .. pattern.high]
# }}}
proc destroyRegex(pattern: Regex) =
pcre.free_substring(cast[cstring](pattern.pcreObj))
if pattern.pcreExtra != nil:
pcre.free_study(pattern.pcreExtra)
proc getNameToNumberTable(pattern: Regex): Table[string, int] =
let entryCount = getinfo[cint](pattern, pcre.INFO_NAMECOUNT)
let entrySize = getinfo[cint](pattern, pcre.INFO_NAMEENTRYSIZE)
let table = cast[ptr UncheckedArray[uint8]](
getinfo[int](pattern, pcre.INFO_NAMETABLE))
result = initTable[string, int]()
for i in 0 ..< entryCount:
let pos = i * entrySize
let num = (int(table[pos]) shl 8) or int(table[pos + 1]) - 1
var name = ""
var idx = 2
while table[pos + idx] != 0:
name.add(char(table[pos + idx]))
idx += 1
result[name] = num
proc initRegex(pattern: string, flags: int, study = true): Regex =
new(result, destroyRegex)
result.pattern = pattern
var errorMsg: cstring
var errOffset: cint
result.pcreObj = pcre.compile(cstring(pattern),
# better hope int is at least 4 bytes..
cint(flags), addr errorMsg,
addr errOffset, nil)
if result.pcreObj == nil:
# failed to compile
raise SyntaxError(msg: $errorMsg, pos: errOffset, pattern: pattern)
if study:
var options: cint = 0
var hasJit: cint
if pcre.config(pcre.CONFIG_JIT, addr hasJit) == 0:
if hasJit == 1'i32:
options = pcre.STUDY_JIT_COMPILE
result.pcreExtra = pcre.study(result.pcreObj, options, addr errorMsg)
if errorMsg != nil:
raise StudyError(msg: $errorMsg)
result.captureNameToId = result.getNameToNumberTable()
proc re*(pattern: string): Regex = proc re*(pattern: string): Regex =
let (pattern, flags, study) = extractOptions(pattern) let (pattern, flags, study) = extractOptions(pattern)
initRegex(pattern, flags, study) initRegex(pattern, flags, study)
# }}}
# Operations {{{
proc matchImpl(str: string, pattern: Regex, start, endpos: int, flags: int): Option[RegexMatch] = proc matchImpl(str: string, pattern: Regex, start, endpos: int, flags: int): Option[RegexMatch] =
var myResult = RegexMatch(pattern : pattern, str : str) var myResult = RegexMatch(pattern : pattern, str : str)
# See PCRE man pages. # See PCRE man pages.
@ -741,8 +731,6 @@ proc replace*(str: string, pattern: Regex, sub: string): string =
replaceImpl(str, pattern, replaceImpl(str, pattern,
formatStr(sub, match.captures[name], match.captures[id - 1])) formatStr(sub, match.captures[name], match.captures[id - 1]))
# }}}
let SpecialCharMatcher = re"([\\+*?[^\]$(){}=!<>|:-])" let SpecialCharMatcher = re"([\\+*?[^\]$(){}=!<>|:-])"
proc escapeRe*(str: string): string = proc escapeRe*(str: string): string =
## Escapes the string so it doesn’t match any special characters. ## Escapes the string so it doesn’t match any special characters.