From f979505b3dda84b06a728d8ff7516757107553fb Mon Sep 17 00:00:00 2001 From: Johannes Schindelin Date: Sun, 10 Nov 2013 10:02:18 -0600 Subject: [PATCH] Regex: implement * and + operators Signed-off-by: Johannes Schindelin --- test/Regex.java | 8 ++++++- test/regex/Compiler.java | 45 +++++++++++++++++++++++++++++++++------- 2 files changed, 44 insertions(+), 9 deletions(-) diff --git a/test/Regex.java b/test/Regex.java index ae8aac9b62..39f3dfe29a 100644 --- a/test/Regex.java +++ b/test/Regex.java @@ -24,7 +24,11 @@ public class Regex { expect(matcher.matches()); expect(matcher.groupCount() == groups.length); for (int i = 1; i <= groups.length; ++i) { - expect(groups[i - 1].equals(matcher.group(i))); + if (groups[i - 1] == null) { + expect(matcher.group(i) == null); + } else { + expect(groups[i - 1].equals(matcher.group(i))); + } } } @@ -35,5 +39,7 @@ public class Regex { expectGroups("a(a*?)(a?)(a??)(a+)(a*)a", "aaaaaa", "", "a", "", "aaa", ""); expectMatch("...", "abc"); expectNoMatch(".", "\n"); + expectGroups("a(bb)*a", "abbbba", "bb"); + expectGroups("a(bb)?(bb)+a", "abba", null, "bb"); } } diff --git a/test/regex/Compiler.java b/test/regex/Compiler.java index 879c3ef0b9..75c9d2d9df 100644 --- a/test/regex/Compiler.java +++ b/test/regex/Compiler.java @@ -63,18 +63,44 @@ class Compiler implements PikeVMOpcodes { protected abstract void writeCode(Output output); } - private class QuestionMark extends Expression { + private class Repeat extends Expression { private Expression expr; + private int minCount, maxCount; - public QuestionMark(Expression expr) { + public Repeat(Expression expr, int minCount, int maxCount) { + if (minCount != 0 && minCount != 1) { + throw new RuntimeException("Unexpected min count: " + minCount); + } + if (maxCount != 1 && maxCount != -1) { + throw new RuntimeException("Unexpected max count: " + maxCount); + } this.expr = expr; + this.minCount = minCount; + this.maxCount = maxCount; } protected void writeCode(Output output) { - output.add(SPLIT); - int jump = output.markJump(); - expr.writeCode(output); - output.setJump(jump); + int start = output.offset; + if (minCount == 1 && maxCount == -1) { + expr.writeCode(output); + output.add(SPLIT_JMP); + output.add(start); + } else if (minCount == 0 && maxCount == -1) { + output.add(SPLIT); + int jump = output.markJump(); + expr.writeCode(output); + output.add(SPLIT_JMP); + output.add(start + 2); + output.setJump(jump); + } else if (minCount == 0 && maxCount == 1) { + output.add(SPLIT); + int jump = output.markJump(); + expr.writeCode(output); + output.setJump(jump); + } else { + throw new RuntimeException("Unexpected range: " + + minCount + ", " + maxCount); + } } } @@ -145,8 +171,11 @@ class Compiler implements PikeVMOpcodes { current.push(DOT); continue; case '?': - current.push(new QuestionMark(current.pop())); - break; + case '*': + case '+': + current.push(new Repeat(current.pop(), + c == '+' ? 1 : 0, c == '?' ? 1 : -1)); + continue; case '(': if (index + 1 < array.length && array[index + 1] == '?') { throw new UnsupportedOperationException("Not yet supported: "