[jruby-joni] 189/223: Support for conditional expressions

Hideki Yamane henrich at moszumanska.debian.org
Mon Nov 16 11:22:09 UTC 2015


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 8d413933ea52fe6634994b1c80460b139326ceb8
Author: Marcin Mielzynski <lopx at gazeta.pl>
Date:   Thu Apr 2 01:03:23 2015 +0200

    Support for conditional expressions
---
 src/org/joni/Analyser.java                   | 14 +++++++
 src/org/joni/ArrayCompiler.java              | 38 +++++++++++++++++
 src/org/joni/ByteCodeMachine.java            |  9 ++++
 src/org/joni/ByteCodePrinter.java            |  8 ++++
 src/org/joni/Parser.java                     | 58 +++++++++++++++++++++++++-
 src/org/joni/Syntax.java                     |  7 +++-
 src/org/joni/ast/EncloseNode.java            | 25 ++----------
 src/org/joni/constants/EncloseType.java      |  1 +
 src/org/joni/constants/OPCode.java           | 61 +++++++++++++++-------------
 src/org/joni/constants/OPSize.java           |  1 +
 src/org/joni/constants/SyntaxProperties.java |  2 +
 src/org/joni/exception/ErrorMessages.java    |  1 +
 12 files changed, 171 insertions(+), 54 deletions(-)

diff --git a/src/org/joni/Analyser.java b/src/org/joni/Analyser.java
index 9aa9acc..6cbe9c1 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:
                 info = quantifiersMemoryInfo(en.target);
                 break;
 
@@ -498,6 +499,7 @@ final class Analyser extends Parser {
 
             case EncloseType.OPTION:
             case EncloseType.STOP_BACKTRACK:
+            case EncloseNode.CONDITION:
                 min = getMinMatchLength(en.target);
                 break;
             } // inner switch
@@ -603,6 +605,7 @@ final class Analyser extends Parser {
 
             case EncloseType.OPTION:
             case EncloseType.STOP_BACKTRACK:
+            case EncloseNode.CONDITION:
                 max = getMaxMatchLength(en.target);
                 break;
             } // inner switch
@@ -715,6 +718,7 @@ final class Analyser extends Parser {
 
             case EncloseType.OPTION:
             case EncloseType.STOP_BACKTRACK:
+            case EncloseNode.CONDITION:
                 len = getCharLengthTree(en.target, level);
                 break;
             } // inner switch
@@ -938,6 +942,7 @@ final class Analyser extends Parser {
 
             case EncloseType.MEMORY:
             case EncloseType.STOP_BACKTRACK:
+            case EncloseNode.CONDITION:
                 n = getHeadValueNode(en.target, exact);
                 break;
             } // inner switch
@@ -1890,6 +1895,14 @@ final class Analyser extends Parser {
                 }
                 break;
 
+            case EncloseNode.CONDITION:
+                if (Config.USE_NAMED_GROUP) {
+                    if (!en.isNameRef() && env.numNamed > 0 && syntax.captureOnlyNamedGroup() && !isCaptureGroup(env.option)) {
+                        newValueException(ERR_NUMBERED_BACKREF_OR_CALL_NOT_ALLOWED);
+                    }
+                }
+                setupTree(en.target, state);
+                break;
             } // inner switch
             break;
 
@@ -2203,6 +2216,7 @@ final class Analyser extends Parser {
                 break;
 
             case EncloseType.STOP_BACKTRACK:
+            case EncloseType.CONDITION:
                 optimizeNodeLeft(en.target, opt, oenv);
                 break;
             } // inner switch
diff --git a/src/org/joni/ArrayCompiler.java b/src/org/joni/ArrayCompiler.java
index ac21d0e..30aeaa1 100644
--- a/src/org/joni/ArrayCompiler.java
+++ b/src/org/joni/ArrayCompiler.java
@@ -43,6 +43,8 @@ import org.joni.constants.OPCode;
 import org.joni.constants.OPSize;
 import org.joni.constants.TargetInfo;
 
+import sun.util.logging.resources.logging;
+
 final class ArrayCompiler extends Compiler {
     private int[]code;
     private int codeLength;
@@ -858,6 +860,21 @@ final class ArrayCompiler extends Compiler {
             }
             break;
 
+        case EncloseType.CONDITION:
+            len = OPSize.CONDITION;
+            if (node.target.getType() == NodeType.ALT) {
+                ConsAltNode x = (ConsAltNode)node.target;
+                tlen = compileLengthTree(x.car); /* yes-node */
+                len += tlen + OPSize.JUMP;
+                if (x.cdr == null) newInternalException(ERR_PARSER_BUG);
+                x = x.cdr;
+                tlen = compileLengthTree(x.cdr); /* no-node */
+                len += tlen;
+                if (x.cdr != null) newSyntaxException(ERR_INVALID_CONDITION_PATTERN);
+            } else {
+                newInternalException(ERR_PARSER_BUG);
+            }
+            break;
         default:
             newInternalException(ERR_PARSER_BUG);
             return 0; // not reached
@@ -932,6 +949,27 @@ final class ArrayCompiler extends Compiler {
             }
             break;
 
+        case EncloseType.CONDITION:
+            addOpcode(OPCode.CONDITION);
+            addMemNum(node.regNum);
+            if (node.target.getType() == NodeType.ALT) {
+                ConsAltNode x = (ConsAltNode)node.target;
+                len = compileLengthTree(x.car); /* yes-node */
+                if (x.cdr == null) newInternalException(ERR_PARSER_BUG);
+                x = x.cdr;
+                int len2 = compileLengthTree(x.car); /* no-node */
+                if (x.cdr != null) newSyntaxException(ERR_INVALID_CONDITION_PATTERN);
+                x = (ConsAltNode)node.target;
+                addRelAddr(len + OPSize.JUMP);
+                compileTree(x.car); /* yes-node */
+                addOpcodeRelAddr(OPCode.JUMP, len2);
+                x = x.cdr;
+                compileTree(x.car); /* no-node */
+            } else {
+                newInternalException(ERR_PARSER_BUG);
+            }
+            break;
+
         default:
             newInternalException(ERR_PARSER_BUG);
             break;
diff --git a/src/org/joni/ByteCodeMachine.java b/src/org/joni/ByteCodeMachine.java
index d5b318c..4535f4c 100644
--- a/src/org/joni/ByteCodeMachine.java
+++ b/src/org/joni/ByteCodeMachine.java
@@ -326,6 +326,7 @@ class ByteCodeMachine extends StackMachine {
 
                 case OPCode.EXACT1_IC_SB:                   opExact1ICSb();              break;
                 case OPCode.EXACTN_IC_SB:                   opExactNICSb();              continue;
+                case OPCode.CONDITION:                      opCondition();               continue;
 
                 case OPCode.FINISH:
                     return finish();
@@ -702,6 +703,14 @@ class ByteCodeMachine extends StackMachine {
         sprev = s - 1;
     }
 
+    private void opCondition() {
+        int mem = code[ip++];
+        int addr = code[ip++];
+        if (mem > regex.numMem || repeatStk[memEndStk + mem] != INVALID_INDEX || repeatStk[memStartStk + mem] != INVALID_INDEX) {
+            ip += addr;
+        }
+    }
+
     private boolean isInBitSet() {
         int c = bytes[s] & 0xff;
         return ((code[ip + (c >>> BitSet.ROOM_SHIFT)] & (1 << c)) != 0);
diff --git a/src/org/joni/ByteCodePrinter.java b/src/org/joni/ByteCodePrinter.java
index 77938da..3ffe9c0 100644
--- a/src/org/joni/ByteCodePrinter.java
+++ b/src/org/joni/ByteCodePrinter.java
@@ -386,6 +386,14 @@ class ByteCodePrinter {
                 sb.append(":" + scn + ":(" + addr + ")");
                 break;
 
+            case OPCode.CONDITION:
+                mem = code[bp];
+                bp += OPSize.MEMNUM;
+                addr = code[bp];
+                bp += OPSize.RELADDR;
+                sb.append(":" + mem + ":" + addr);
+                break;
+
             default:
                 throw new InternalException("undefined code: " + code[--bp]);
             }
diff --git a/src/org/joni/Parser.java b/src/org/joni/Parser.java
index 419993f..71f20f5 100644
--- a/src/org/joni/Parser.java
+++ b/src/org/joni/Parser.java
@@ -31,6 +31,7 @@ import org.joni.ast.AnchorNode;
 import org.joni.ast.AnyCharNode;
 import org.joni.ast.BackRefNode;
 import org.joni.ast.CClassNode;
+import org.joni.ast.CClassNode.CCStateArg;
 import org.joni.ast.CTypeNode;
 import org.joni.ast.CallNode;
 import org.joni.ast.ConsAltNode;
@@ -38,7 +39,6 @@ import org.joni.ast.EncloseNode;
 import org.joni.ast.Node;
 import org.joni.ast.QuantifierNode;
 import org.joni.ast.StringNode;
-import org.joni.ast.CClassNode.CCStateArg;
 import org.joni.constants.AnchorType;
 import org.joni.constants.CCSTATE;
 import org.joni.constants.CCVALTYPE;
@@ -493,6 +493,56 @@ class Parser extends Lexer {
                 }
                 break;
 
+            case '(':   /* conditional expression: (?(cond)yes), (?(cond)yes|no) */
+                if (syntax.op2QMarkLParenCondition()) {
+                    int num = -1;
+                    int name = -1;
+                    fetch();
+                    if (enc.isDigit(c)) { /* (n) */
+                        unfetch();
+                        num = fetchName('(', true);
+                        if (syntax.strictCheckBackref()) {
+                            if (num > env.numMem || env.memNodes == null || env.memNodes[num] == null) newValueException(ERR_INVALID_BACKREF);
+                        }
+                    } else {
+                        if (Config.USE_NAMED_GROUP) {
+                            if (c == '<' || c == '\'') {    /* (<name>), ('name') */
+                                name = p;
+                                num = fetchName(c, false);
+                                int nameEnd = value;
+                                fetch();
+                                if (c != ')') newSyntaxException(ERR_UNDEFINED_GROUP_OPTION);
+                                NameEntry e = env.reg.nameToGroupNumbers(bytes, name, nameEnd);
+                                if (e == null) newValueException(ERR_UNDEFINED_NAME_REFERENCE, name, nameEnd);
+                                if (syntax.strictCheckBackref()) {
+                                    if (e.backNum == 1) {
+                                        if (e.backRef1 > env.numMem ||
+                                            env.memNodes == null ||
+                                            env.memNodes[e.backRef1] == null) newValueException(ERR_INVALID_BACKREF);
+                                    } else {
+                                        for (int i=0; i<e.backNum; i++) {
+                                            if (e.backRefs[i] > env.numMem ||
+                                                env.memNodes == null ||
+                                                env.memNodes[e.backRefs[i]] == null) newValueException(ERR_INVALID_BACKREF);
+                                        }
+                                    }
+                                }
+
+                                num = e.backNum == 1 ? e.backRef1 : e.backRefs[0]; /* XXX: use left most named group as Perl */
+                            }
+                        } else { // USE_NAMED_GROUP
+                            newSyntaxException(ERR_INVALID_CONDITION_PATTERN);
+                        }
+                    }
+                    EncloseNode en = new EncloseNode(EncloseType.CONDITION);
+                    en.regNum = num;
+                    if (name != -1) en.setNameRef();
+                    node = en;
+                } else {
+                    newSyntaxException(ERR_UNDEFINED_GROUP_OPTION);
+                }
+                break;
+
             // case 'p': #ifdef USE_POSIXLINE_OPTION
             case '-':
             case 'i':
@@ -580,7 +630,7 @@ class Parser extends Lexer {
         Node target = parseSubExp(term);
 
         if (node.getType() == NodeType.ANCHOR) {
-            AnchorNode an = (AnchorNode) node;
+            AnchorNode an = (AnchorNode)node;
             an.setTarget(target);
             if (syntax.op2OptionECMAScript() && an.type == AnchorType.PREC_READ_NOT) {
                 env.popPrecReadNotNode(an);
@@ -594,6 +644,10 @@ class Parser extends Lexer {
                 }
                 /* Don't move this to previous of parse_subexp() */
                 env.setMemNode(en.regNum, node);
+            } else if (en.type == EncloseType.CONDITION) {
+                if (target.getType() != NodeType.ALT) { /* convert (?(cond)yes) to (?(cond)yes|empty) */
+                    en.setTarget(ConsAltNode.newAltNode(target, ConsAltNode.newAltNode(StringNode.EMPTY, null)));
+                }
             }
         }
         returnCode = 0;
diff --git a/src/org/joni/Syntax.java b/src/org/joni/Syntax.java
index 4e7b5e7..f5f9480 100644
--- a/src/org/joni/Syntax.java
+++ b/src/org/joni/Syntax.java
@@ -282,6 +282,10 @@ public final class Syntax implements SyntaxProperties{
         return isOp2(OP2_OPTION_ECMASCRIPT);
     }
 
+    public boolean op2QMarkLParenCondition() {
+        return isOp2(OP2_QMARK_LPAREN_CONDITION);
+    }
+
     /**
      * BEHAVIOR
      *
@@ -371,7 +375,8 @@ public final class Syntax implements SyntaxProperties{
         OP2_PLUS_POSSESSIVE_REPEAT |
         OP2_CCLASS_SET_OP | OP2_ESC_CAPITAL_C_BAR_CONTROL |
         OP2_ESC_CAPITAL_M_BAR_META | OP2_ESC_V_VTAB |
-        OP2_ESC_H_XDIGIT ),
+        OP2_ESC_H_XDIGIT |
+        OP2_QMARK_LPAREN_CONDITION),
 
         ( GNU_REGEX_BV |
         ALLOW_INTERVAL_LOW_ABBREV |
diff --git a/src/org/joni/ast/EncloseNode.java b/src/org/joni/ast/EncloseNode.java
index 7c45d14..0ce827e 100644
--- a/src/org/joni/ast/EncloseNode.java
+++ b/src/org/joni/ast/EncloseNode.java
@@ -101,6 +101,7 @@ public final class EncloseNode extends StateNode implements EncloseType {
         if (isStopBacktrack()) types.append("STOP_BACKTRACK ");
         if (isMemory()) types.append("MEMORY ");
         if (isOption()) types.append("OPTION ");
+        if (isCondition()) types.append("CONDITION ");
 
         return types.toString();
     }
@@ -113,36 +114,16 @@ public final class EncloseNode extends StateNode implements EncloseType {
         state &= ~flag;
     }
 
-    public void clearMemory() {
-        type &= ~MEMORY;
-    }
-
-    public void setMemory() {
-        type |= MEMORY;
-    }
-
     public boolean isMemory() {
         return (type & MEMORY) != 0;
     }
 
-    public void clearOption() {
-        type &= ~OPTION;
-    }
-
-    public void setOption() {
-        type |= OPTION;
-    }
-
     public boolean isOption() {
         return (type & OPTION) != 0;
     }
 
-    public void clearStopBacktrack() {
-        type &= ~STOP_BACKTRACK;
-    }
-
-    public void setStopBacktrack() {
-        type |= STOP_BACKTRACK;
+    public boolean isCondition() {
+        return (type & CONDITION) != 0;
     }
 
     public boolean isStopBacktrack() {
diff --git a/src/org/joni/constants/EncloseType.java b/src/org/joni/constants/EncloseType.java
index 125af0c..13d42b6 100644
--- a/src/org/joni/constants/EncloseType.java
+++ b/src/org/joni/constants/EncloseType.java
@@ -23,6 +23,7 @@ public interface EncloseType {
     final int MEMORY                = 1<<0;
     final int OPTION                = 1<<1;
     final int STOP_BACKTRACK        = 1<<2;
+    final int CONDITION             = 1<<3;
 
     final int ALLOWED_IN_LB         = MEMORY;
     final int ALLOWED_IN_LB_NOT     = 0;
diff --git a/src/org/joni/constants/OPCode.java b/src/org/joni/constants/OPCode.java
index 05d1f8b..5053d20 100644
--- a/src/org/joni/constants/OPCode.java
+++ b/src/org/joni/constants/OPCode.java
@@ -116,40 +116,41 @@ public interface OPCode {
 
     final int CALL                          = 79;           /* \g<name> */
     final int RETURN                        = 80;
+    final int CONDITION                     = 81;
 
-    final int STATE_CHECK_PUSH              = 81;           /* combination explosion check and push */
-    final int STATE_CHECK_PUSH_OR_JUMP      = 82;           /* check ok -> push, else jump  */
-    final int STATE_CHECK                   = 83;           /* check only */
-    final int STATE_CHECK_ANYCHAR_STAR      = 84;
-    final int STATE_CHECK_ANYCHAR_ML_STAR   = 85;
+    final int STATE_CHECK_PUSH              = 82;           /* combination explosion check and push */
+    final int STATE_CHECK_PUSH_OR_JUMP      = 83;           /* check ok -> push, else jump  */
+    final int STATE_CHECK                   = 84;           /* check only */
+    final int STATE_CHECK_ANYCHAR_STAR      = 85;
+    final int STATE_CHECK_ANYCHAR_ML_STAR   = 86;
 
       /* no need: IS_DYNAMIC_OPTION() == 0 */
-    final int SET_OPTION_PUSH               = 86;           /* set option and push recover option */
-    final int SET_OPTION                    = 87;           /* set option */
+    final int SET_OPTION_PUSH               = 87;           /* set option and push recover option */
+    final int SET_OPTION                    = 88;           /* set option */
 
     // single byte versions
-    final int ANYCHAR_SB                    = 88;           /* "."  */
-    final int ANYCHAR_ML_SB                 = 89;           /* "."  multi-line */
-    final int ANYCHAR_STAR_SB               = 90;           /* ".*" */
-    final int ANYCHAR_ML_STAR_SB            = 91;           /* ".*" multi-line */
-    final int ANYCHAR_STAR_PEEK_NEXT_SB     = 92;
-    final int ANYCHAR_ML_STAR_PEEK_NEXT_SB  = 93;
-    final int STATE_CHECK_ANYCHAR_STAR_SB   = 94;
-    final int STATE_CHECK_ANYCHAR_ML_STAR_SB= 95;
-
-    final int CCLASS_SB                     = 96;
-    final int CCLASS_NOT_SB                 = 97;
-    final int WORD_SB                       = 98;
-    final int NOT_WORD_SB                   = 99;
-    final int WORD_BOUND_SB                 = 100;
-    final int NOT_WORD_BOUND_SB             = 101;
-    final int WORD_BEGIN_SB                 = 102;
-    final int WORD_END_SB                   = 103;
-
-    final int LOOK_BEHIND_SB                = 104;
-
-    final int EXACT1_IC_SB                  = 105;           /* single byte, N = 1, ignore case */
-    final int EXACTN_IC_SB                  = 106;           /* single byte,        ignore case */
+    final int ANYCHAR_SB                    = 89;           /* "."  */
+    final int ANYCHAR_ML_SB                 = 90;           /* "."  multi-line */
+    final int ANYCHAR_STAR_SB               = 91;           /* ".*" */
+    final int ANYCHAR_ML_STAR_SB            = 92;           /* ".*" multi-line */
+    final int ANYCHAR_STAR_PEEK_NEXT_SB     = 93;
+    final int ANYCHAR_ML_STAR_PEEK_NEXT_SB  = 94;
+    final int STATE_CHECK_ANYCHAR_STAR_SB   = 95;
+    final int STATE_CHECK_ANYCHAR_ML_STAR_SB= 96;
+
+    final int CCLASS_SB                     = 97;
+    final int CCLASS_NOT_SB                 = 98;
+    final int WORD_SB                       = 99;
+    final int NOT_WORD_SB                   = 100;
+    final int WORD_BOUND_SB                 = 101;
+    final int NOT_WORD_BOUND_SB             = 102;
+    final int WORD_BEGIN_SB                 = 103;
+    final int WORD_END_SB                   = 104;
+
+    final int LOOK_BEHIND_SB                = 105;
+
+    final int EXACT1_IC_SB                  = 106;           /* single byte, N = 1, ignore case */
+    final int EXACTN_IC_SB                  = 107;           /* single byte,        ignore case */
 
 
     public final String OpCodeNames[] = Config.DEBUG_COMPILE ? new String[] {
@@ -234,6 +235,7 @@ public interface OPCode {
         "fail-look-behind-not", /*OP_FAIL_LOOK_BEHIND_NOT*/
         "call", /*OP_CALL*/
         "return", /*OP_RETURN*/
+        "condition", /*OP_CONDITION*/
         "state-check-push", /*OP_STATE_CHECK_PUSH*/
         "state-check-push-or-jump", /*OP_STATE_CHECK_PUSH_OR_JUMP*/
         "state-check", /*OP_STATE_CHECK*/
@@ -351,6 +353,7 @@ public interface OPCode {
         Arguments.NON, /*OP_FAIL_LOOK_BEHIND_NOT*/
         Arguments.ABSADDR, /*OP_CALL*/
         Arguments.NON, /*OP_RETURN*/
+        Arguments.SPECIAL, /*OP_CONDITION*/
         Arguments.SPECIAL, /*OP_STATE_CHECK_PUSH*/
         Arguments.SPECIAL, /*OP_STATE_CHECK_PUSH_OR_JUMP*/
         Arguments.STATE_CHECK, /*OP_STATE_CHECK*/
diff --git a/src/org/joni/constants/OPSize.java b/src/org/joni/constants/OPSize.java
index d5595ad..fa3d3c6 100644
--- a/src/org/joni/constants/OPSize.java
+++ b/src/org/joni/constants/OPSize.java
@@ -67,6 +67,7 @@ public interface OPSize {
     final int FAIL_LOOK_BEHIND_NOT          = OPCODE;
     final int CALL                          = (OPCODE + ABSADDR);
     final int RETURN                        = OPCODE;
+    final int CONDITION                     = (OPCODE + MEMNUM + RELADDR);
 
     // #ifdef USE_COMBINATION_EXPLOSION_CHECK
     final int STATE_CHECK                   = (OPCODE + STATE_CHECK_NUM);
diff --git a/src/org/joni/constants/SyntaxProperties.java b/src/org/joni/constants/SyntaxProperties.java
index 075324c..d1e2cd3 100644
--- a/src/org/joni/constants/SyntaxProperties.java
+++ b/src/org/joni/constants/SyntaxProperties.java
@@ -76,6 +76,8 @@ public interface SyntaxProperties {
     final int OP2_INEFFECTIVE_ESCAPE         = (1<<20); /* \ */
     final int OP2_OPTION_ECMASCRIPT          = (1<<21); /* EcmaScript quirks */
 
+    final int OP2_QMARK_LPAREN_CONDITION     = (1<<29); /* (?(cond)yes...|no...) */
+
     /* syntax (behavior); */
     final int CONTEXT_INDEP_ANCHORS           = (1<<31); /* not implemented */
     final int CONTEXT_INDEP_REPEAT_OPS        = (1<<0);  /* ?, *, +, {n,m} */
diff --git a/src/org/joni/exception/ErrorMessages.java b/src/org/joni/exception/ErrorMessages.java
index 683ff62..008ea0b 100644
--- a/src/org/joni/exception/ErrorMessages.java
+++ b/src/org/joni/exception/ErrorMessages.java
@@ -63,6 +63,7 @@ public interface ErrorMessages extends org.jcodings.exception.ErrorMessages {
     final String ERR_INVALID_POSIX_BRACKET_TYPE = "invalid POSIX bracket type";
     final String ERR_INVALID_LOOK_BEHIND_PATTERN = "invalid pattern in look-behind";
     final String ERR_INVALID_REPEAT_RANGE_PATTERN = "invalid repeat range {lower,upper}";
+    final String ERR_INVALID_CONDITION_PATTERN = "invalid conditional pattern";
 
     /* values error (syntax error) */
     final String ERR_TOO_BIG_NUMBER = "too big number";

-- 
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