[jruby-joni] 116/194: absent operator

Hideki Yamane henrich at moszumanska.debian.org
Thu Feb 1 12:04:33 UTC 2018


This is an automated email from the git hooks/post-receive script.

henrich pushed a commit to branch debian/sid
in repository jruby-joni.

commit 5a50f34e0c57f900fc2df6e3cd4e4d088aaba7ef
Author: Marcin Mielzynski <lopx at gazeta.pl>
Date:   Sun Jan 7 23:45:40 2018 +0100

    absent operator
---
 src/org/joni/Analyser.java         | 21 +++++++++++++++
 src/org/joni/ArrayCompiler.java    | 12 +++++++++
 src/org/joni/ByteCodeMachine.java  | 53 ++++++++++++++++++++++++++++++++++++--
 src/org/joni/Parser.java           |  7 +++++
 src/org/joni/StackEntry.java       | 14 ++++++++++
 src/org/joni/StackMachine.java     | 35 +++++++++++++++++++++++++
 src/org/joni/Syntax.java           |  8 +++++-
 src/org/joni/ast/EncloseNode.java  |  4 +++
 src/org/joni/constants/OPCode.java |  2 +-
 test/org/joni/test/TestU8.java     |  9 +++++++
 10 files changed, 161 insertions(+), 4 deletions(-)

diff --git a/src/org/joni/Analyser.java b/src/org/joni/Analyser.java
index c9b2048..b92d534 100644
--- a/src/org/joni/Analyser.java
+++ b/src/org/joni/Analyser.java
@@ -383,6 +383,7 @@ final class Analyser extends Parser {
             case EncloseType.OPTION:
             case EncloseNode.STOP_BACKTRACK:
             case EncloseNode.CONDITION:
+            case EncloseNode.ABSENT:
                 info = quantifiersMemoryInfo(en.target);
                 break;
 
@@ -501,6 +502,9 @@ final class Analyser extends Parser {
             case EncloseNode.CONDITION:
                 min = getMinMatchLength(en.target);
                 break;
+
+            case EncloseType.ABSENT:
+                break;
             } // inner switch
             break;
 
@@ -607,6 +611,9 @@ final class Analyser extends Parser {
             case EncloseNode.CONDITION:
                 max = getMaxMatchLength(en.target);
                 break;
+
+            case EncloseType.ABSENT:
+                break;
             } // inner switch
             break;
 
@@ -720,6 +727,9 @@ final class Analyser extends Parser {
             case EncloseNode.CONDITION:
                 len = getCharLengthTree(en.target, level);
                 break;
+
+            case EncloseType.ABSENT:
+                break;
             } // inner switch
             break;
 
@@ -968,6 +978,9 @@ final class Analyser extends Parser {
             case EncloseNode.CONDITION:
                 n = getHeadValueNode(en.target, exact);
                 break;
+
+            case EncloseType.ABSENT:
+                break;
             } // inner switch
             break;
 
@@ -1945,6 +1958,10 @@ final class Analyser extends Parser {
                 }
                 setupTree(en.target, state);
                 break;
+
+            case EncloseType.ABSENT:
+                setupTree(en.target, state);
+                break;
             } // inner switch
             break;
 
@@ -2265,6 +2282,10 @@ final class Analyser extends Parser {
             case EncloseType.CONDITION:
                 optimizeNodeLeft(en.target, opt, oenv);
                 break;
+
+            case EncloseType.ABSENT:
+                opt.length.set(0, MinMaxLen.INFINITE_DISTANCE);
+                break;
             } // inner switch
             break;
         }
diff --git a/src/org/joni/ArrayCompiler.java b/src/org/joni/ArrayCompiler.java
index d999992..8b1d963 100644
--- a/src/org/joni/ArrayCompiler.java
+++ b/src/org/joni/ArrayCompiler.java
@@ -874,6 +874,9 @@ final class ArrayCompiler extends Compiler {
                 newInternalException(ERR_PARSER_BUG);
             }
             break;
+        case EncloseType.ABSENT:
+            len = OPSize.PUSH_ABSENT_POS + OPSize.ABSENT + tlen + OPSize.ABSENT_END;
+            break;
         default:
             newInternalException(ERR_PARSER_BUG);
             return 0; // not reached
@@ -972,6 +975,15 @@ final class ArrayCompiler extends Compiler {
             }
             break;
 
+        case EncloseType.ABSENT:
+            regex.requireStack = true;
+            len = compileLengthTree(node.target);
+            addOpcode(OPCode.PUSH_ABSENT_POS);
+            addOpcodeRelAddr(OPCode.ABSENT, len + OPSize.ABSENT_END);
+            compileTree(node.target);
+            addOpcode(OPCode.ABSENT_END);
+            break;
+
         default:
             newInternalException(ERR_PARSER_BUG);
             break;
diff --git a/src/org/joni/ByteCodeMachine.java b/src/org/joni/ByteCodeMachine.java
index e55cfc8..ed4f63a 100644
--- a/src/org/joni/ByteCodeMachine.java
+++ b/src/org/joni/ByteCodeMachine.java
@@ -306,7 +306,10 @@ class ByteCodeMachine extends StackMachine {
                 case OPCode.PUSH_LOOK_BEHIND_NOT:       opPushLookBehindNot();     continue;
                 case OPCode.FAIL_LOOK_BEHIND_NOT:       opFailLookBehindNot();     continue;
 
-                // USE_SUBEXP_CALL
+                case OPCode.PUSH_ABSENT_POS:            opPushAbsentPos();         continue;
+                case OPCode.ABSENT:                     opAbsent();                continue;
+                case OPCode.ABSENT_END:                 opAbsentEnd();             continue;
+
                 case OPCode.CALL:                       opCall();                  continue;
                 case OPCode.RETURN:                     opReturn();                continue;
                 case OPCode.CONDITION:                  opCondition();             continue;
@@ -439,7 +442,10 @@ class ByteCodeMachine extends StackMachine {
                 case OPCode.PUSH_LOOK_BEHIND_NOT:       opPushLookBehindNot();     continue;
                 case OPCode.FAIL_LOOK_BEHIND_NOT:       opFailLookBehindNot();     continue;
 
-                // USE_SUBEXP_CALL
+                case OPCode.PUSH_ABSENT_POS:            opPushAbsentPos();         continue;
+                case OPCode.ABSENT:                     opAbsent();                continue;
+                case OPCode.ABSENT_END:                 opAbsentEnd();             continue;
+
                 case OPCode.CALL:                       opCall();                  continue;
                 case OPCode.RETURN:                     opReturn();                continue;
                 case OPCode.CONDITION:                  opCondition();             continue;
@@ -1882,6 +1888,49 @@ class ByteCodeMachine extends StackMachine {
         opFail();
     }
 
+    private void opPushAbsentPos() {
+        pushAbsentPos(s, end);
+    }
+
+    private void opAbsent() {
+        int aend = range; // use end for USE_MATCH_RANGE_MUST_BE_INSIDE_OF_SPECIFIED_RANGE
+        int selfip = ip - 1;
+        StackEntry e = stack[--stk];
+        int absent = e.getAbsentStr();
+        range = e.getAbsentEndStr();
+        int addr = code[ip++];
+
+        if (Config.DEBUG_MATCH) System.out.println("ABSENT: s:" + s + " end:" + end + " absent:" + absent + " aend:" + aend);
+
+        if (absent > aend && s > absent) {
+            pop();
+            opFail();
+            return;
+        } else if (s >= aend && s > absent) {
+            if (s > aend || s > end) {
+                opFail();
+                return;
+            }
+            ip += addr;
+        } else {
+            pushAlt(ip + addr, s, sprev, pkeep);
+            int n = enc.length(bytes, s, end);
+            pushAbsentPos(absent, range);
+            pushAlt(selfip, s + n, s, pkeep);
+            pushAbsent();
+            range = aend;
+        }
+    }
+
+    private void opAbsentEnd() {
+        if (sprev < range) range = sprev;
+        if (Config.DEBUG_MATCH) System.out.println("ABSENT_END: end:" + range);
+        popTilAbsent();
+        opFail();
+        return;
+        // sprev = sbegin; // break;
+    }
+
     private void opCall() {
         int addr = code[ip++];
         pushCallFrame(ip);
diff --git a/src/org/joni/Parser.java b/src/org/joni/Parser.java
index 7854833..702fceb 100644
--- a/src/org/joni/Parser.java
+++ b/src/org/joni/Parser.java
@@ -458,6 +458,13 @@ class Parser extends Lexer {
             case '>':  /* (?>...) stop backtrack */
                 node = new EncloseNode(EncloseType.STOP_BACKTRACK); // node_new_enclose
                 break;
+            case '~': /* (?~...) absent operator */
+                if (syntax.op2QMarkTildeAbsent()) {
+                    node = new EncloseNode(EncloseType.ABSENT);
+                    break;
+                } else {
+                    newSyntaxException(ERR_UNDEFINED_GROUP_OPTION);
+                }
             case '\'':
                 if (Config.USE_NAMED_GROUP) {
                     if (syntax.op2QMarkLtNamedGroup()) {
diff --git a/src/org/joni/StackEntry.java b/src/org/joni/StackEntry.java
index 24de7b6..883f563 100644
--- a/src/org/joni/StackEntry.java
+++ b/src/org/joni/StackEntry.java
@@ -169,4 +169,18 @@ final class StackEntry {
     int getCallFramePStr() {
         return E3;
     }
+
+    void setAbsentStr(int pos) {
+        E1 = pos;
+    }
+    int getAbsentStr() {
+        return E1;
+    }
+
+    void setAbsentEndStr(int pos) {
+        E2 = pos;
+    }
+    int getAbsentEndStr() {
+        return E2;
+    }
 }
diff --git a/src/org/joni/StackMachine.java b/src/org/joni/StackMachine.java
index 7715ae9..f7fe7eb 100644
--- a/src/org/joni/StackMachine.java
+++ b/src/org/joni/StackMachine.java
@@ -314,6 +314,20 @@ abstract class StackMachine extends Matcher implements StackType {
         stk++;
     }
 
+    protected final void pushAbsent() {
+        StackEntry e = ensure1();
+        e.type = ABSENT;
+        stk++;
+    }
+
+    protected final void pushAbsentPos(int start, int end) {
+        StackEntry e = ensure1();
+        e.type = ABSENT_POS;
+        e.setAbsentStr(start);
+        e.setAbsentEndStr(end);
+        stk++;
+    }
+
     // stack debug routines here
     // ...
 
@@ -427,6 +441,27 @@ abstract class StackMachine extends Matcher implements StackType {
         }
     }
 
+    protected final void popTilAbsent() {
+        while (true) {
+            stk--;
+            StackEntry e = stack[stk];
+
+            if (e.type == ABSENT) {
+                break;
+            } else if (e.type == MEM_START) {
+                repeatStk[memStartStk + e.getMemNum()] = e.getMemStart();
+                repeatStk[memEndStk + e.getMemNum()] = e.getMemEnd();
+            } else if (e.type == REPEAT_INC) {
+                stack[e.getSi()].decreaseRepeatCount();
+            } else if (e.type == MEM_END) {
+                repeatStk[memStartStk + e.getMemNum()] = e.getMemStart();
+                repeatStk[memEndStk + e.getMemNum()] = e.getMemEnd();
+            } else if (Config.USE_COMBINATION_EXPLOSION_CHECK) {
+                if (e.type == STATE_CHECK_MARK) stateCheckMark();
+            }
+        }
+    }
+
     protected final int posEnd() {
         int k = stk;
         while (true) {
diff --git a/src/org/joni/Syntax.java b/src/org/joni/Syntax.java
index 087c730..0b06267 100644
--- a/src/org/joni/Syntax.java
+++ b/src/org/joni/Syntax.java
@@ -303,6 +303,10 @@ public final class Syntax implements SyntaxProperties {
         return isOp2(OP2_ESC_CAPITAL_K_KEEP);
     }
 
+    public boolean op2QMarkTildeAbsent() {
+        return isOp2(OP2_QMARK_TILDE_ABSENT);
+    }
+
     public boolean op2EscGBraceBackref() {
         return isOp2(OP2_ESC_G_BRACE_BACKREF);
     }
@@ -432,7 +436,9 @@ public final class Syntax implements SyntaxProperties {
         OP2_ESC_H_XDIGIT |
         OP2_ESC_CAPITAL_X_EXTENDED_GRAPHEME_CLUSTER |
         OP2_QMARK_LPAREN_CONDITION |
-        OP2_ESC_CAPITAL_R_LINEBREAK | OP2_ESC_CAPITAL_K_KEEP
+        OP2_ESC_CAPITAL_R_LINEBREAK |
+        OP2_ESC_CAPITAL_K_KEEP |
+        OP2_QMARK_TILDE_ABSENT
         ),
 
         0,
diff --git a/src/org/joni/ast/EncloseNode.java b/src/org/joni/ast/EncloseNode.java
index 17646ac..cc86d92 100644
--- a/src/org/joni/ast/EncloseNode.java
+++ b/src/org/joni/ast/EncloseNode.java
@@ -96,6 +96,7 @@ public final class EncloseNode extends StateNode implements EncloseType {
         if (isMemory()) types.append("MEMORY ");
         if (isOption()) types.append("OPTION ");
         if (isCondition()) types.append("CONDITION ");
+        if (isAbsent()) types.append("ABSENT ");
         return types.toString();
     }
 
@@ -123,4 +124,7 @@ public final class EncloseNode extends StateNode implements EncloseType {
         return (type & STOP_BACKTRACK) != 0;
     }
 
+    public boolean isAbsent() {
+        return (type & ABSENT) != 0;
+    }
 }
diff --git a/src/org/joni/constants/OPCode.java b/src/org/joni/constants/OPCode.java
index 01e4fae..3e95aad 100644
--- a/src/org/joni/constants/OPCode.java
+++ b/src/org/joni/constants/OPCode.java
@@ -121,7 +121,7 @@ public interface OPCode {
     final int PUSH_LOOK_BEHIND_NOT          = 83;           /* (?<!...) start */
     final int FAIL_LOOK_BEHIND_NOT          = 84;           /* (?<!...) end   */
 
-    final int ABSENT_POS                    = 85;           /* (?~...)  start */
+    final int PUSH_ABSENT_POS               = 85;           /* (?~...)  start */
     final int ABSENT                        = 86;           /* (?~...)  start of inner loop */
     final int ABSENT_END                    = 87;           /* (?~...)  end   */
 
diff --git a/test/org/joni/test/TestU8.java b/test/org/joni/test/TestU8.java
index b474199..9782d85 100755
--- a/test/org/joni/test/TestU8.java
+++ b/test/org/joni/test/TestU8.java
@@ -282,5 +282,14 @@ public class TestU8 extends Test {
         x2s("\\b.*abc.*\\b", "abc", 0, 3);
         x2s("(?!a).*b", "ab", 1, 2);
         x2s("(?!^a).*b", "ab", 1, 2);
+
+        x2s("<-(?~->)->", "<- ->->", 0, 5);
+        x2s("<-(?~->)->\n", "<-1->2<-3->\n", 6, 12);
+        x2s("<-(?~->)->.*<-(?~->)->", "<-1->2<-3->4<-5->", 0, 17);
+        x2s("<-(?~->)->.*?<-(?~->)->", "<-1->2<-3->4<-5->", 0, 11);
+        x2s("(?~abc)c", "abc", 0, 3);
+        x2s("(?~abc)bc", "abc", 0, 3);
+        x2s("(?~abc)abc", "abc", 0, 3);
+
     }
 }

-- 
Alioth's /usr/local/bin/git-commit-notice on /srv/git.debian.org/git/pkg-java/jruby-joni.git



More information about the pkg-java-commits mailing list