/*
* Permission is hereby granted, free of charge, to any person obtaining a copy of
* this software and associated documentation files (the "Software"), to deal in
* the Software without restriction, including without limitation the rights to
* use, copy, modify, merge, publish, distribute, sublicense, and/or sell copies
* of the Software, and to permit persons to whom the Software is furnished to do
* so, subject to the following conditions:
*
* The above copyright notice and this permission notice shall be included in all
* copies or substantial portions of the Software.
*
* THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR
* IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,
* FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE
* AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER
* LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM,
* OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE
* SOFTWARE.
*/
package jdk.nashorn.internal.runtime.regexp.joni.ast;
import static jdk.nashorn.internal.runtime.regexp.joni.ast.QuantifierNode.ReduceType.A;
import static jdk.nashorn.internal.runtime.regexp.joni.ast.QuantifierNode.ReduceType.AQ;
import static jdk.nashorn.internal.runtime.regexp.joni.ast.QuantifierNode.ReduceType.ASIS;
import static jdk.nashorn.internal.runtime.regexp.joni.ast.QuantifierNode.ReduceType.DEL;
import static jdk.nashorn.internal.runtime.regexp.joni.ast.QuantifierNode.ReduceType.PQ_Q;
import static jdk.nashorn.internal.runtime.regexp.joni.ast.QuantifierNode.ReduceType.P_QQ;
import static jdk.nashorn.internal.runtime.regexp.joni.ast.QuantifierNode.ReduceType.QQ;
import jdk.nashorn.internal.runtime.regexp.joni.Config;
import jdk.nashorn.internal.runtime.regexp.joni.ScanEnvironment;
import jdk.nashorn.internal.runtime.regexp.joni.constants.TargetInfo;
@SuppressWarnings("javadoc")
public final class QuantifierNode extends StateNode {
public Node target;
public int lower;
public int upper;
public boolean greedy;
public int targetEmptyInfo;
public Node headExact;
public Node nextHeadExact;
public boolean isRefered; /* include called node. don't eliminate even if {0} */
enum ReduceType {
ASIS, /* as is */
DEL, /* delete parent */
A, /* to '*' */
AQ, /* to '*?' */
QQ, /* to '??' */
P_QQ, /* to '+)??' */
PQ_Q, /* to '+?)?' */
}
private final static ReduceType[][] REDUCE_TABLE = {
{DEL, A, A, QQ, AQ, ASIS}, /* '?' */
{DEL, DEL, DEL, P_QQ, P_QQ, DEL}, /* '*' */
{A, A, DEL, ASIS, P_QQ, DEL}, /* '+' */
{DEL, AQ, AQ, DEL, AQ, AQ}, /* '??' */
{DEL, DEL, DEL, DEL, DEL, DEL}, /* '*?' */
{ASIS, PQ_Q, DEL, AQ, AQ, DEL} /* '+?' */
};
private final static String PopularQStr[] = new String[] {
"?", "*", "+", "??", "*?", "+?"
};
private final static String ReduceQStr[]= new String[] {
"", "", "*", "*?", "??", "+ and ??", "+? and ?"
};
public QuantifierNode(final int lower, final int upper, final boolean byNumber) {
this.lower = lower;
this.upper = upper;
greedy = true;
targetEmptyInfo = TargetInfo.ISNOT_EMPTY;
if (byNumber) {
setByNumber();
}
}
@Override
public int getType() {
return QTFR;
}
@Override
protected void setChild(final Node newChild) {
target = newChild;
}
@Override
protected Node getChild() {
return target;
}
public void setTarget(final Node tgt) {
target = tgt;
tgt.parent = this;
}
public StringNode convertToString(final int flag) {
final StringNode sn = new StringNode();
sn.flag = flag;
sn.swap(this);
return sn;
}
@Override
public String getName() {
return "Quantifier";
}
@Override
public String toString(final int level) {
final StringBuilder value = new StringBuilder(super.toString(level));
value.append("\n target: ").append(pad(target, level + 1));
value.append("\n lower: ").append(lower);
value.append("\n upper: ").append(upper);
value.append("\n greedy: ").append(greedy);
value.append("\n targetEmptyInfo: ").append(targetEmptyInfo);
value.append("\n headExact: ").append(pad(headExact, level + 1));
value.append("\n nextHeadExact: ").append(pad(nextHeadExact, level + 1));
value.append("\n isRefered: ").append(isRefered);
return value.toString();
}
public boolean isAnyCharStar() {
return greedy && isRepeatInfinite(upper) && target.getType() == CANY;
}
/* ?:0, *:1, +:2, ??:3, *?:4, +?:5 */
protected int popularNum() {
if (greedy) {
if (lower == 0) {
if (upper == 1) {
return 0;
} else if (isRepeatInfinite(upper)) {
return 1;
}
} else if (lower == 1) {
if (isRepeatInfinite(upper)) {
return 2;
}
}
} else {
if (lower == 0) {
if (upper == 1) {
return 3;
} else if (isRepeatInfinite(upper)) {
return 4;
}
} else if (lower == 1) {
if (isRepeatInfinite(upper)) {
return 5;
}
}
}
return -1;
}
protected void set(final QuantifierNode other) {
setTarget(other.target);
other.target = null;
lower = other.lower;
upper = other.upper;
greedy = other.greedy;
targetEmptyInfo = other.targetEmptyInfo;
//setHeadExact(other.headExact);
//setNextHeadExact(other.nextHeadExact);
headExact = other.headExact;
nextHeadExact = other.nextHeadExact;
isRefered = other.isRefered;
}
public void reduceNestedQuantifier(final QuantifierNode other) {
final int pnum = popularNum();
final int cnum = other.popularNum();
if (pnum < 0 || cnum < 0) {
return;
}
switch(REDUCE_TABLE[cnum][pnum]) {
case DEL:
// no need to set the parent here...
// swap ?
set(other); // *pnode = *cnode; ???
break;
case A:
setTarget(other.target);
lower = 0;
upper = REPEAT_INFINITE;
greedy = true;
break;
case AQ:
setTarget(other.target);
lower = 0;
upper = REPEAT_INFINITE;
greedy = false;
break;
case QQ:
setTarget(other.target);
lower = 0;
upper = 1;
greedy = false;
break;
case P_QQ:
setTarget(other);
lower = 0;
upper = 1;
greedy = false;
other.lower = 1;
other.upper = REPEAT_INFINITE;
other.greedy = true;
return;
case PQ_Q:
setTarget(other);
lower = 0;
upper = 1;
greedy = true;
other.lower = 1;
other.upper = REPEAT_INFINITE;
other.greedy = false;
return;
case ASIS:
setTarget(other);
return;
default:
break;
}
// ??? remove the parent from target ???
other.target = null; // remove target from reduced quantifier
}
@SuppressWarnings("fallthrough")
public int setQuantifier(final Node tgt, final boolean group, final ScanEnvironment env, final char[] chars, final int p, final int end) {
if (lower == 1 && upper == 1) {
return 1;
}
switch(tgt.getType()) {
case STR:
if (!group) {
final StringNode sn = (StringNode)tgt;
if (sn.canBeSplit()) {
final StringNode n = sn.splitLastChar();
if (n != null) {
setTarget(n);
return 2;
}
}
}
break;
case QTFR:
/* check redundant double repeat. */
/* verbose warn (?:.?)? etc... but not warn (.?)? etc... */
final QuantifierNode qnt = (QuantifierNode)tgt;
final int nestQNum = popularNum();
final int targetQNum = qnt.popularNum();
if (Config.USE_WARNING_REDUNDANT_NESTED_REPEAT_OPERATOR) {
if (!isByNumber() && !qnt.isByNumber() && env.syntax.warnReduntantNestedRepeat()) {
switch(REDUCE_TABLE[targetQNum][nestQNum]) {
case ASIS:
break;
case DEL:
env.reg.getWarnings().warn(new String(chars, p, end) +
" redundant nested repeat operator");
break;
default:
env.reg.getWarnings().warn(new String(chars, p, end) +
/**代码未完, 请加载全部代码(NowJava.com).**/