changeset 4661:0dce3d812e7a v7.3.1078

updated for version 7.3.1078 Problem: New regexp engine: \@! doesn't work. Solution: Implement the negated version of \@=.
author Bram Moolenaar <bram@vim.org>
date Thu, 30 May 2013 22:44:02 +0200
parents 4dcc1a7d49a5
children b792349dc858
files src/regexp_nfa.c src/testdir/test64.in src/testdir/test64.ok src/version.c
diffstat 4 files changed, 55 insertions(+), 6 deletions(-) [+]
line wrap: on
line diff
--- a/src/regexp_nfa.c
+++ b/src/regexp_nfa.c
@@ -1390,6 +1390,9 @@ nfa_regpiece()
 		case '=':
 		    EMIT(NFA_PREV_ATOM_NO_WIDTH);
 		    break;
+		case '!':
+		    EMIT(NFA_PREV_ATOM_NO_WIDTH_NEG);
+		    break;
 		case '0':
 		case '1':
 		case '2':
@@ -1400,7 +1403,6 @@ nfa_regpiece()
 		case '7':
 		case '8':
 		case '9':
-		case '!':
 		case '<':
 		case '>':
 		    /* Not supported yet */
@@ -2373,7 +2375,9 @@ post2nfa(postfix, end, nfa_calc_size)
 	    break;
 
 	case NFA_PREV_ATOM_NO_WIDTH:
+	case NFA_PREV_ATOM_NO_WIDTH_NEG:
 	    /* The \@= operator: match the preceding atom with zero width.
+	     * The \@! operator: no match for the preceding atom.
 	     * Surrounds the preceding atom with START_INVISIBLE and
 	     * END_INVISIBLE, similarly to MOPEN. */
 
@@ -2391,6 +2395,12 @@ post2nfa(postfix, end, nfa_calc_size)
 	    s = new_state(NFA_START_INVISIBLE, e.start, s1);
 	    if (s == NULL)
 		goto theend;
+	    if (*p == NFA_PREV_ATOM_NO_WIDTH_NEG)
+	    {
+		s->negated = TRUE;
+		s1->negated = TRUE;
+	    }
+
 	    PUSH(frag(s, list1(&s1->out)));
 	    break;
 
@@ -3541,8 +3551,10 @@ nfa_regmatch(start, submatch, m)
 		    addstate_here(thislist, t->state->out, &t->sub, &listidx);
 		else
 		{
-		    /* TODO: only copy positions in use. */
-		    *m = t->sub;
+		    /* do not set submatches for \@! */
+		    if (!t->state->negated)
+			/* TODO: only copy positions in use. */
+			*m = t->sub;
 		    nfa_match = TRUE;
 		}
 		break;
@@ -3593,7 +3605,8 @@ nfa_regmatch(start, submatch, m)
 		    log_fd = stderr;
 		}
 #endif
-		if (result == TRUE)
+		/* for \@! it is a match when result is FALSE */
+		if (result != t->state->negated)
 		{
 		    int j;
 
--- a/src/testdir/test64.in
+++ b/src/testdir/test64.in
@@ -303,13 +303,20 @@ STARTTEST
 :" will never match
 :call add(tl, [2, 'abcd\@=e', 'any text in here ... '])
 :call add(tl, [2, '\v(abc)@=..', 'xabcd', 'ab', 'abc'])
-:" no match
 :call add(tl, [2, '\(.*John\)\@=.*Bob', 'here is John, and here is B'])
 :call add(tl, [2, '\(John.*\)\@=.*Bob', 'John is Bobs friend', 'John is Bob', 'John is Bobs friend'])
-:" no match
 :call add(tl, [2, '.*John\&.*Bob', 'here is John, and here is B'])
 :call add(tl, [2, '.*John\&.*Bob', 'John is Bobs friend', 'John is Bob'])
 :call add(tl, [2, '\v(test1)@=.*yep', 'this is a test1, yep it is', 'test1, yep', 'test1'])
+:call add(tl, [2, 'foo\(bar\)\@!', 'foobar'])
+:call add(tl, [2, 'foo\(bar\)\@!', 'foo bar', 'foo'])
+:call add(tl, [2, 'if \(\(then\)\@!.\)*$', ' if then else'])
+:call add(tl, [2, 'if \(\(then\)\@!.\)*$', ' if else ', 'if else ', ' '])
+:call add(tl, [2, '\(foo\)\@!bar', 'foobar', 'bar'])
+:call add(tl, [2, '\(foo\)\@!...bar', 'foobar'])
+:call add(tl, [2, '^\%(.*bar\)\@!.*\zsfoo', ' bar foo '])
+:call add(tl, [2, '^\%(.*bar\)\@!.*\zsfoo', ' foo bar '])
+:call add(tl, [2, '^\%(.*bar\)\@!.*\zsfoo', ' foo xxx ', 'foo'])
 :"
 :"""" Combining different tests and features
 :call add(tl, [2, '[[:alpha:]]\{-2,6}', '787abcdiuhsasiuhb4', 'ab'])
--- a/src/testdir/test64.ok
+++ b/src/testdir/test64.ok
@@ -678,6 +678,33 @@ OK 2 - .*John\&.*Bob
 OK 0 - \v(test1)@=.*yep
 OK 1 - \v(test1)@=.*yep
 OK 2 - \v(test1)@=.*yep
+OK 0 - foo\(bar\)\@!
+OK 1 - foo\(bar\)\@!
+OK 2 - foo\(bar\)\@!
+OK 0 - foo\(bar\)\@!
+OK 1 - foo\(bar\)\@!
+OK 2 - foo\(bar\)\@!
+OK 0 - if \(\(then\)\@!.\)*$
+OK 1 - if \(\(then\)\@!.\)*$
+OK 2 - if \(\(then\)\@!.\)*$
+OK 0 - if \(\(then\)\@!.\)*$
+OK 1 - if \(\(then\)\@!.\)*$
+OK 2 - if \(\(then\)\@!.\)*$
+OK 0 - \(foo\)\@!bar
+OK 1 - \(foo\)\@!bar
+OK 2 - \(foo\)\@!bar
+OK 0 - \(foo\)\@!...bar
+OK 1 - \(foo\)\@!...bar
+OK 2 - \(foo\)\@!...bar
+OK 0 - ^\%(.*bar\)\@!.*\zsfoo
+OK 1 - ^\%(.*bar\)\@!.*\zsfoo
+OK 2 - ^\%(.*bar\)\@!.*\zsfoo
+OK 0 - ^\%(.*bar\)\@!.*\zsfoo
+OK 1 - ^\%(.*bar\)\@!.*\zsfoo
+OK 2 - ^\%(.*bar\)\@!.*\zsfoo
+OK 0 - ^\%(.*bar\)\@!.*\zsfoo
+OK 1 - ^\%(.*bar\)\@!.*\zsfoo
+OK 2 - ^\%(.*bar\)\@!.*\zsfoo
 OK 0 - [[:alpha:]]\{-2,6}
 OK 1 - [[:alpha:]]\{-2,6}
 OK 2 - [[:alpha:]]\{-2,6}
--- a/src/version.c
+++ b/src/version.c
@@ -729,6 +729,8 @@ static char *(features[]) =
 static int included_patches[] =
 {   /* Add new patch number below this line */
 /**/
+    1078,
+/**/
     1077,
 /**/
     1076,