diff --git a/test/Regex.java b/test/Regex.java index 44157d369e..48836cfe38 100644 --- a/test/Regex.java +++ b/test/Regex.java @@ -61,5 +61,6 @@ public class Regex { expectGroups("a|(b|c)", "c", "c"); expectGroups("(?=a)a", "a"); expectGroups(".*(o)(?<=[A-Z][a-z]*)", "Hello", "o"); + expectNoMatch("(?!a).", "a"); } } diff --git a/test/regex/Compiler.java b/test/regex/Compiler.java index 6967e542ba..e109be63bf 100644 --- a/test/regex/Compiler.java +++ b/test/regex/Compiler.java @@ -228,10 +228,11 @@ class Compiler implements PikeVMOpcodes { private class Lookaround extends Expression { private final Group group = new Group(false, null); - private final boolean forward; + private final boolean forward, negative; - public Lookaround(boolean forward) { + public Lookaround(boolean forward, boolean negative) { this.forward = forward; + this.negative = negative; } @Override @@ -240,7 +241,9 @@ class Compiler implements PikeVMOpcodes { if (!forward) { vm.reverse(); } - output.add(forward ? LOOKAHEAD : LOOKBEHIND); + output.add(forward ? + (negative ? NEGATIVE_LOOKAHEAD : LOOKAHEAD) : + (negative ? NEGATIVE_LOOKAHEAD : LOOKBEHIND)); output.add(output.addLookaround(vm)); } } @@ -327,9 +330,10 @@ class Compiler implements PikeVMOpcodes { case ':': capturing = false; break; + case '!': case '=': { capturing = false; - Lookaround lookaround = new Lookaround(lookAhead); + Lookaround lookaround = new Lookaround(lookAhead, c == '!'); current.push(lookaround); groups.push(lookaround.group); continue; diff --git a/test/regex/PikeVM.java b/test/regex/PikeVM.java index d0bd453d27..0888cdaa87 100644 --- a/test/regex/PikeVM.java +++ b/test/regex/PikeVM.java @@ -358,6 +358,18 @@ class PikeVM implements PikeVMOpcodes { current.queueImmediately(pc, pc + 2, false); } break; + case NEGATIVE_LOOKAHEAD: + if (!lookarounds[program[pc + 1]].matches(characters, + i, characters.length, true, false, null)) { + current.queueImmediately(pc, pc + 2, false); + } + break; + case NEGATIVE_LOOKBEHIND: + if (!lookarounds[program[pc + 1]].matches(characters, + i - 1, -1, true, false, null)) { + current.queueImmediately(pc, pc + 2, false); + } + break; /* immediate opcodes, i.e. thread continues within the same step */ case SAVE_OFFSET: if (result != null) { diff --git a/test/regex/PikeVMOpcodes.java b/test/regex/PikeVMOpcodes.java index acd67cc2fd..53aaa4c5ed 100644 --- a/test/regex/PikeVMOpcodes.java +++ b/test/regex/PikeVMOpcodes.java @@ -26,6 +26,8 @@ interface PikeVMOpcodes { final static int LOOKAHEAD = -30; final static int LOOKBEHIND = -31; + final static int NEGATIVE_LOOKAHEAD = -32; + final static int NEGATIVE_LOOKBEHIND = -33; final static int SAVE_OFFSET = -40;