pegs module: bugfixes for the anchor ^; pegs.replace now does what the docs say

This commit is contained in:
Araq 2011-06-16 12:50:17 +02:00
commit dc6a80bd1d
2 changed files with 61 additions and 32 deletions

View file

@ -743,6 +743,10 @@ proc rawMatch*(s: string, p: TPeg, start: int, c: var TCaptures): int {.
else: result = -1 else: result = -1
of pkRule, pkList: assert false of pkRule, pkList: assert false
template fillMatches(s, caps, c: expr) =
for k in 0..c.ml-1:
caps[k] = substr(s, c.matches[k][0], c.matches[k][1])
proc match*(s: string, pattern: TPeg, matches: var openarray[string], proc match*(s: string, pattern: TPeg, matches: var openarray[string],
start = 0): bool {.nosideEffect, rtl, extern: "npegs$1Capture".} = start = 0): bool {.nosideEffect, rtl, extern: "npegs$1Capture".} =
## returns ``true`` if ``s[start..]`` matches the ``pattern`` and ## returns ``true`` if ``s[start..]`` matches the ``pattern`` and
@ -752,9 +756,7 @@ proc match*(s: string, pattern: TPeg, matches: var openarray[string],
var c: TCaptures var c: TCaptures
c.origStart = start c.origStart = start
result = rawMatch(s, pattern, start, c) == len(s) - start result = rawMatch(s, pattern, start, c) == len(s) - start
if result: if result: fillMatches(s, matches, c)
for i in 0..c.ml-1:
matches[i] = substr(s, c.matches[i][0], c.matches[i][1])
proc match*(s: string, pattern: TPeg, proc match*(s: string, pattern: TPeg,
start = 0): bool {.nosideEffect, rtl, extern: "npegs$1".} = start = 0): bool {.nosideEffect, rtl, extern: "npegs$1".} =
@ -772,9 +774,7 @@ proc matchLen*(s: string, pattern: TPeg, matches: var openarray[string],
var c: TCaptures var c: TCaptures
c.origStart = start c.origStart = start
result = rawMatch(s, pattern, start, c) result = rawMatch(s, pattern, start, c)
if result >= 0: if result >= 0: fillMatches(s, matches, c)
for i in 0..c.ml-1:
matches[i] = substr(s, c.matches[i][0], c.matches[i][1])
proc matchLen*(s: string, pattern: TPeg, proc matchLen*(s: string, pattern: TPeg,
start = 0): int {.nosideEffect, rtl, extern: "npegs$1".} = start = 0): int {.nosideEffect, rtl, extern: "npegs$1".} =
@ -791,8 +791,13 @@ proc find*(s: string, pattern: TPeg, matches: var openarray[string],
## returns the starting position of ``pattern`` in ``s`` and the captured ## returns the starting position of ``pattern`` in ``s`` and the captured
## substrings in the array ``matches``. If it does not match, nothing ## substrings in the array ``matches``. If it does not match, nothing
## is written into ``matches`` and -1 is returned. ## is written into ``matches`` and -1 is returned.
var c: TCaptures
c.origStart = start
for i in start .. s.len-1: for i in start .. s.len-1:
if matchLen(s, pattern, matches, i) >= 0: return i c.ml = 0
if rawMatch(s, pattern, i, c) >= 0:
fillMatches(s, matches, c)
return i
return -1 return -1
# could also use the pattern here: (!P .)* P # could also use the pattern here: (!P .)* P
@ -803,29 +808,36 @@ proc findBounds*(s: string, pattern: TPeg, matches: var openarray[string],
## and the captured ## and the captured
## substrings in the array ``matches``. If it does not match, nothing ## substrings in the array ``matches``. If it does not match, nothing
## is written into ``matches`` and (-1,0) is returned. ## is written into ``matches`` and (-1,0) is returned.
var c: TCaptures
c.origStart = start
for i in start .. s.len-1: for i in start .. s.len-1:
var L = matchLen(s, pattern, matches, i) c.ml = 0
if L >= 0: return (i, i+L-1) var L = rawMatch(s, pattern, i, c)
if L >= 0:
fillMatches(s, matches, c)
return (i, i+L-1)
return (-1, 0) return (-1, 0)
proc find*(s: string, pattern: TPeg, proc find*(s: string, pattern: TPeg,
start = 0): int {.nosideEffect, rtl, extern: "npegs$1".} = start = 0): int {.nosideEffect, rtl, extern: "npegs$1".} =
## returns the starting position of ``pattern`` in ``s``. If it does not ## returns the starting position of ``pattern`` in ``s``. If it does not
## match, -1 is returned. ## match, -1 is returned.
var c: TCaptures
c.origStart = start
for i in start .. s.len-1: for i in start .. s.len-1:
if matchLen(s, pattern, i) >= 0: return i if rawMatch(s, pattern, i, c) >= 0: return i
return -1 return -1
iterator findAll*(s: string, pattern: TPeg, start = 0): string = iterator findAll*(s: string, pattern: TPeg, start = 0): string =
## yields all matching captures of pattern in `s`. ## yields all matching captures of pattern in `s`.
var matches: array[0..MaxSubpatterns-1, string] var c: TCaptures
c.origStart = start
var i = start var i = start
while i < s.len: while i < s.len:
var L = matchLen(s, pattern, matches, i) c.ml = 0
var L = rawMatch(s, pattern, i, c)
if L < 0: break if L < 0: break
for k in 0..maxSubPatterns-1: for k in 0..c.ml-1: yield substr(s, c.matches[k][0], c.matches[k][1])
if isNil(matches[k]): break
yield matches[k]
inc(i, L) inc(i, L)
proc findAll*(s: string, pattern: TPeg, start = 0): seq[string] {. proc findAll*(s: string, pattern: TPeg, start = 0): seq[string] {.
@ -834,7 +846,7 @@ proc findAll*(s: string, pattern: TPeg, start = 0): seq[string] {.
## If it does not match, @[] is returned. ## If it does not match, @[] is returned.
accumulateResult(findAll(s, pattern, start)) accumulateResult(findAll(s, pattern, start))
template `=~`*(s: string, pattern: TPeg): expr = template `=~`*(s: string, pattern: TPeg): bool =
## This calls ``match`` with an implicit declared ``matches`` array that ## This calls ``match`` with an implicit declared ``matches`` array that
## can be used in the scope of the ``=~`` call: ## can be used in the scope of the ``=~`` call:
## ##
@ -876,8 +888,10 @@ proc startsWith*(s: string, prefix: TPeg, start = 0): bool {.
proc endsWith*(s: string, suffix: TPeg, start = 0): bool {. proc endsWith*(s: string, suffix: TPeg, start = 0): bool {.
nosideEffect, rtl, extern: "npegs$1".} = nosideEffect, rtl, extern: "npegs$1".} =
## returns true if `s` ends with the pattern `prefix` ## returns true if `s` ends with the pattern `prefix`
var c: TCaptures
c.origStart = start
for i in start .. s.len-1: for i in start .. s.len-1:
if matchLen(s, suffix, i) == s.len - i: return true if rawMatch(s, suffix, i, c) == s.len - i: return true
proc replacef*(s: string, sub: TPeg, by: string): string {. proc replacef*(s: string, sub: TPeg, by: string): string {.
nosideEffect, rtl, extern: "npegs$1".} = nosideEffect, rtl, extern: "npegs$1".} =
@ -895,12 +909,15 @@ proc replacef*(s: string, sub: TPeg, by: string): string {.
result = "" result = ""
var i = 0 var i = 0
var caps: array[0..maxSubpatterns-1, string] var caps: array[0..maxSubpatterns-1, string]
var c: TCaptures
while i < s.len: while i < s.len:
var x = matchLen(s, sub, caps, i) c.ml = 0
var x = rawMatch(s, sub, i, c)
if x <= 0: if x <= 0:
add(result, s[i]) add(result, s[i])
inc(i) inc(i)
else: else:
fillMatches(s, caps, c)
addf(result, by, caps) addf(result, by, caps)
inc(i, x) inc(i, x)
add(result, substr(s, i)) add(result, substr(s, i))
@ -911,14 +928,14 @@ proc replace*(s: string, sub: TPeg, by = ""): string {.
## in `by`. ## in `by`.
result = "" result = ""
var i = 0 var i = 0
var caps: array[0..maxSubpatterns-1, string] var c: TCaptures
while i < s.len: while i < s.len:
var x = matchLen(s, sub, caps, i) var x = rawMatch(s, sub, i, c)
if x <= 0: if x <= 0:
add(result, s[i]) add(result, s[i])
inc(i) inc(i)
else: else:
addf(result, by, caps) add(result, by)
inc(i, x) inc(i, x)
add(result, substr(s, i)) add(result, substr(s, i))
@ -929,12 +946,15 @@ proc parallelReplace*(s: string, subs: openArray[
## applied in parallel. ## applied in parallel.
result = "" result = ""
var i = 0 var i = 0
var c: TCaptures
var caps: array[0..maxSubpatterns-1, string] var caps: array[0..maxSubpatterns-1, string]
while i < s.len: while i < s.len:
block searchSubs: block searchSubs:
for j in 0..high(subs): for j in 0..high(subs):
var x = matchLen(s, subs[j][0], caps, i) c.ml = 0
var x = rawMatch(s, subs[j][0], i, c)
if x > 0: if x > 0:
fillMatches(s, caps, c)
addf(result, subs[j][1], caps) addf(result, subs[j][1], caps)
inc(i, x) inc(i, x)
break searchSubs break searchSubs
@ -970,16 +990,19 @@ iterator split*(s: string, sep: TPeg): string =
## "an" ## "an"
## "example" ## "example"
## ##
var c: TCaptures
var var
first = 0 first = 0
last = 0 last = 0
while last < len(s): while last < len(s):
var x = matchLen(s, sep, last) c.ml = 0
var x = rawMatch(s, sep, last, c)
if x > 0: inc(last, x) if x > 0: inc(last, x)
first = last first = last
while last < len(s): while last < len(s):
inc(last) inc(last)
x = matchLen(s, sep, last) c.ml = 0
x = rawMatch(s, sep, last, c)
if x > 0: break if x > 0: break
if first < last: if first < last:
yield substr(s, first, last-1) yield substr(s, first, last-1)
@ -1706,6 +1729,8 @@ when isMainModule:
assert match("cccccdddddd", g2) assert match("cccccdddddd", g2)
assert("var1=key; var2=key2".replacef(peg"{\ident}'='{\ident}", "$1<-$2$2") == assert("var1=key; var2=key2".replacef(peg"{\ident}'='{\ident}", "$1<-$2$2") ==
"var1<-keykey; var2<-key2key2") "var1<-keykey; var2<-key2key2")
assert("var1=key; var2=key2".replace(peg"{\ident}'='{\ident}", "$1<-$2$2") ==
"$1<-$2$2; $1<-$2$2")
assert "var1=key; var2=key2".endsWith(peg"{\ident}'='{\ident}") assert "var1=key; var2=key2".endsWith(peg"{\ident}'='{\ident}")
if "aaaaaa" =~ peg"'aa' !. / ({'a'})+": if "aaaaaa" =~ peg"'aa' !. / ({'a'})+":
@ -1722,6 +1747,9 @@ when isMainModule:
for x in findAll("abcdef", peg"{.}", 3): for x in findAll("abcdef", peg"{.}", 3):
echo x echo x
for x in findAll("abcdef", peg"^{.}", 3):
assert x == "d"
if "f(a, b)" =~ peg"{[0-9]+} / ({\ident} '(' {@} ')')": if "f(a, b)" =~ peg"{[0-9]+} / ({\ident} '(' {@} ')')":
assert matches[0] == "f" assert matches[0] == "f"

View file

@ -5,8 +5,11 @@ High priority (version 0.8.12)
* add --deadlock_prevention:on|off switch? timeout for locks? * add --deadlock_prevention:on|off switch? timeout for locks?
* built-in serialization * built-in serialization
- bug: invoking a generic iterator twice triggers a code gen bug (titer2) - bug: invoking a generic iterator twice triggers a code gen bug (titer2)
- pegs: the anchor '^' does not work because many procs use a linear search - bug: forward proc for generic seems broken
and matchLen() - sorting with leads to a strange memory corruption!
--> system.swap or genericAssign is broken! And indeed, if reference counts
are not modified and the GC is triggered in between a swap, bad things
may happen!
version 0.9.0 version 0.9.0
@ -30,11 +33,6 @@ Bugs
- bug: generic assign still buggy - bug: generic assign still buggy
- Optimization: If we use a temporary for the result anyway the code gen - Optimization: If we use a temporary for the result anyway the code gen
should make use of this fact to generate better code... should make use of this fact to generate better code...
- bug: forward proc for generic seems broken
- sorting with leads to a strange memory corruption!
--> system.swap or genericAssign is broken! And indeed, if reference counts
are not modified and the GC is triggered in between a swap, bad things
may happen!
version 0.9.XX version 0.9.XX
@ -111,7 +109,10 @@ Version 2
- the two other parsers - the two other parsers
- rethink the syntax: distinction between expr and stmt is unfortunate; - rethink the syntax: distinction between expr and stmt is unfortunate;
indentation handling is quite complex too indentation handling is quite complex too; problem with exception handling
is that often the scope of ``try`` is wrong and apart from that ``try`` is
a full blown statement; a ``try`` expression might be a good idea to make
error handling more light-weight
Low priority Low priority