[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