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 <[email protected]> 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 _______________________________________________ pkg-java-commits mailing list [email protected] http://lists.alioth.debian.org/cgi-bin/mailman/listinfo/pkg-java-commits

