]> Cypherpunks repositories - gostls13.git/commitdiff
regexp: bug fix: need to track whether match begins with fixed prefix.
authorRob Pike <r@golang.org>
Tue, 22 Jun 2010 23:02:14 +0000 (16:02 -0700)
committerRob Pike <r@golang.org>
Tue, 22 Jun 2010 23:02:14 +0000 (16:02 -0700)
Fixes #872.

R=rsc
CC=golang-dev
https://golang.org/cl/1731043

src/pkg/regexp/all_test.go
src/pkg/regexp/regexp.go

index fd7ee2acb60a0ede79293f0468cf2b7631467e71..9936d4f45e43f1be6af54b8d73eeb18fb659e612 100644 (file)
@@ -100,7 +100,8 @@ var matches = []tester{
 
        // fixed bugs
        tester{`ab$`, "cab", vec{1, 3}},
-       tester{`axxb$`, "axxcb", vec{}},
+       tester{`data`, "daXY data", vec{5, 9}},
+       tester{`da(.)a$`, "daXY data", vec{5, 9, 7, 8}},
 
        // can backslash-escape any punctuation
        tester{`\!\"\#\$\%\&\'\(\)\*\+\,\-\.\/\:\;\<\=\>\?\@\[\\\]\^\_\{\|\}\~`,
index edf91531de491063624ca299321dac8e94185d82..4dd430ea6990f59fa31d9647d7814ad322af3a06 100644 (file)
@@ -727,34 +727,35 @@ func (a *matchArena) noMatch() *matchVec {
 }
 
 type state struct {
-       inst  instr // next instruction to execute
-       match *matchVec
+       inst     instr // next instruction to execute
+       prefixed bool  // this match began with a fixed prefix
+       match    *matchVec
 }
 
 // Append new state to to-do list.  Leftmost-longest wins so avoid
 // adding a state that's already active.  The matchVec will be inc-ref'ed
 // if it is assigned to a state.
-func (a *matchArena) addState(s []state, inst instr, match *matchVec, pos, end int) []state {
+func (a *matchArena) addState(s []state, inst instr, prefixed bool, match *matchVec, pos, end int) []state {
        switch inst.kind() {
        case _BOT:
                if pos == 0 {
-                       s = a.addState(s, inst.next(), match, pos, end)
+                       s = a.addState(s, inst.next(), prefixed, match, pos, end)
                }
                return s
        case _EOT:
                if pos == end {
-                       s = a.addState(s, inst.next(), match, pos, end)
+                       s = a.addState(s, inst.next(), prefixed, match, pos, end)
                }
                return s
        case _BRA:
                n := inst.(*_Bra).n
                match.m[2*n] = pos
-               s = a.addState(s, inst.next(), match, pos, end)
+               s = a.addState(s, inst.next(), prefixed, match, pos, end)
                return s
        case _EBRA:
                n := inst.(*_Ebra).n
                match.m[2*n+1] = pos
-               s = a.addState(s, inst.next(), match, pos, end)
+               s = a.addState(s, inst.next(), prefixed, match, pos, end)
                return s
        }
        index := inst.index()
@@ -773,12 +774,13 @@ func (a *matchArena) addState(s []state, inst instr, match *matchVec, pos, end i
        }
        s = s[0 : l+1]
        s[l].inst = inst
+       s[l].prefixed = prefixed
        s[l].match = match
        match.ref++
        if inst.kind() == _ALT {
-               s = a.addState(s, inst.(*_Alt).left, a.copy(match), pos, end)
+               s = a.addState(s, inst.(*_Alt).left, prefixed, a.copy(match), pos, end)
                // give other branch a copy of this match vector
-               s = a.addState(s, inst.next(), a.copy(match), pos, end)
+               s = a.addState(s, inst.next(), prefixed, a.copy(match), pos, end)
        }
        return s
 }
@@ -818,10 +820,10 @@ func (re *Regexp) doExecute(str string, bytestr []byte, pos int) []int {
                        match := arena.noMatch()
                        match.m[0] = pos
                        if prefixed {
-                               s[out] = arena.addState(s[out], re.prefixStart, match, pos, end)
+                               s[out] = arena.addState(s[out], re.prefixStart, true, match, pos, end)
                                prefixed = false // next iteration should start at beginning of machine.
                        } else {
-                               s[out] = arena.addState(s[out], re.start.next(), match, pos, end)
+                               s[out] = arena.addState(s[out], re.start.next(), false, match, pos, end)
                        }
                        arena.free(match) // if addState saved it, ref was incremented
                }
@@ -852,19 +854,19 @@ func (re *Regexp) doExecute(str string, bytestr []byte, pos int) []int {
                        case _EOT:
                        case _CHAR:
                                if c == st.inst.(*_Char).char {
-                                       s[out] = arena.addState(s[out], st.inst.next(), st.match, pos, end)
+                                       s[out] = arena.addState(s[out], st.inst.next(), st.prefixed, st.match, pos, end)
                                }
                        case _CHARCLASS:
                                if st.inst.(*_CharClass).matches(c) {
-                                       s[out] = arena.addState(s[out], st.inst.next(), st.match, pos, end)
+                                       s[out] = arena.addState(s[out], st.inst.next(), st.prefixed, st.match, pos, end)
                                }
                        case _ANY:
                                if c != endOfFile {
-                                       s[out] = arena.addState(s[out], st.inst.next(), st.match, pos, end)
+                                       s[out] = arena.addState(s[out], st.inst.next(), st.prefixed, st.match, pos, end)
                                }
                        case _NOTNL:
                                if c != endOfFile && c != '\n' {
-                                       s[out] = arena.addState(s[out], st.inst.next(), st.match, pos, end)
+                                       s[out] = arena.addState(s[out], st.inst.next(), st.prefixed, st.match, pos, end)
                                }
                        case _BRA:
                        case _EBRA:
@@ -892,7 +894,7 @@ func (re *Regexp) doExecute(str string, bytestr []byte, pos int) []int {
                return nil
        }
        // if match found, back up start of match by width of prefix.
-       if re.prefix != "" && len(final.match.m) > 0 {
+       if final.prefixed && len(final.match.m) > 0 {
                final.match.m[0] -= len(re.prefix)
        }
        return final.match.m