QuantifierNode.java revision 953:221a84ef44c0
1193323Sed/* 2193323Sed * Permission is hereby granted, free of charge, to any person obtaining a copy of 3193323Sed * this software and associated documentation files (the "Software"), to deal in 4193323Sed * the Software without restriction, including without limitation the rights to 5193323Sed * use, copy, modify, merge, publish, distribute, sublicense, and/or sell copies 6193323Sed * of the Software, and to permit persons to whom the Software is furnished to do 7193323Sed * so, subject to the following conditions: 8193323Sed * 9193323Sed * The above copyright notice and this permission notice shall be included in all 10193323Sed * copies or substantial portions of the Software. 11193323Sed * 12193323Sed * THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR 13193323Sed * IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY, 14193323Sed * FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE 15249423Sdim * AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER 16249423Sdim * LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, 17193323Sed * OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE 18193323Sed * SOFTWARE. 19263508Sdim */ 20193323Sedpackage jdk.nashorn.internal.runtime.regexp.joni.ast; 21212904Sdim 22193323Sedimport static jdk.nashorn.internal.runtime.regexp.joni.ast.QuantifierNode.ReduceType.A; 23193323Sedimport static jdk.nashorn.internal.runtime.regexp.joni.ast.QuantifierNode.ReduceType.AQ; 24193323Sedimport static jdk.nashorn.internal.runtime.regexp.joni.ast.QuantifierNode.ReduceType.ASIS; 25193323Sedimport static jdk.nashorn.internal.runtime.regexp.joni.ast.QuantifierNode.ReduceType.DEL; 26193323Sedimport static jdk.nashorn.internal.runtime.regexp.joni.ast.QuantifierNode.ReduceType.PQ_Q; 27193323Sedimport static jdk.nashorn.internal.runtime.regexp.joni.ast.QuantifierNode.ReduceType.P_QQ; 28193323Sedimport static jdk.nashorn.internal.runtime.regexp.joni.ast.QuantifierNode.ReduceType.QQ; 29193323Sed 30193323Sedimport jdk.nashorn.internal.runtime.regexp.joni.Config; 31212904Sdimimport jdk.nashorn.internal.runtime.regexp.joni.ScanEnvironment; 32193323Sedimport jdk.nashorn.internal.runtime.regexp.joni.constants.TargetInfo; 33206124Srdivacky 34206124Srdivackypublic final class QuantifierNode extends StateNode { 35206124Srdivacky 36206124Srdivacky public Node target; 37193323Sed public int lower; 38193323Sed public int upper; 39193323Sed public boolean greedy; 40193323Sed 41249423Sdim public int targetEmptyInfo; 42249423Sdim 43249423Sdim public Node headExact; 44193323Sed public Node nextHeadExact; 45193323Sed public boolean isRefered; /* include called node. don't eliminate even if {0} */ 46193323Sed 47193323Sed enum ReduceType { 48193323Sed ASIS, /* as is */ 49193323Sed DEL, /* delete parent */ 50193323Sed A, /* to '*' */ 51193323Sed AQ, /* to '*?' */ 52193323Sed QQ, /* to '??' */ 53193323Sed P_QQ, /* to '+)??' */ 54193323Sed PQ_Q, /* to '+?)?' */ 55193323Sed } 56193323Sed 57193323Sed private final static ReduceType[][] REDUCE_TABLE = { 58193323Sed {DEL, A, A, QQ, AQ, ASIS}, /* '?' */ 59193323Sed {DEL, DEL, DEL, P_QQ, P_QQ, DEL}, /* '*' */ 60193323Sed {A, A, DEL, ASIS, P_QQ, DEL}, /* '+' */ 61200581Srdivacky {DEL, AQ, AQ, DEL, AQ, AQ}, /* '??' */ 62193323Sed {DEL, DEL, DEL, DEL, DEL, DEL}, /* '*?' */ 63212904Sdim {ASIS, PQ_Q, DEL, AQ, AQ, DEL} /* '+?' */ 64193323Sed }; 65193323Sed 66193323Sed private final static String PopularQStr[] = new String[] { 67193323Sed "?", "*", "+", "??", "*?", "+?" 68193323Sed }; 69193323Sed 70193323Sed private final static String ReduceQStr[]= new String[] { 71193323Sed "", "", "*", "*?", "??", "+ and ??", "+? and ?" 72193323Sed }; 73193323Sed 74193323Sed 75193323Sed public QuantifierNode(final int lower, final int upper, final boolean byNumber) { 76193323Sed this.lower = lower; 77193323Sed this.upper = upper; 78193323Sed greedy = true; 79193323Sed targetEmptyInfo = TargetInfo.ISNOT_EMPTY; 80193323Sed 81193323Sed if (byNumber) setByNumber(); 82200581Srdivacky } 83193323Sed 84193323Sed @Override 85193323Sed public int getType() { 86193323Sed return QTFR; 87193323Sed } 88193323Sed 89226633Sdim @Override 90193323Sed protected void setChild(final Node newChild) { 91193323Sed target = newChild; 92193323Sed } 93193323Sed 94193323Sed @Override 95193323Sed protected Node getChild() { 96193323Sed return target; 97193323Sed } 98193323Sed 99193323Sed public void setTarget(final Node tgt) { 100193323Sed target = tgt; 101193323Sed tgt.parent = this; 102193323Sed } 103202878Srdivacky 104202878Srdivacky public StringNode convertToString(final int flag) { 105202878Srdivacky final StringNode sn = new StringNode(); 106193323Sed sn.flag = flag; 107193323Sed sn.swap(this); 108193323Sed return sn; 109212904Sdim } 110193323Sed 111212904Sdim @Override 112212904Sdim public String getName() { 113193323Sed return "Quantifier"; 114193323Sed } 115193323Sed 116193323Sed @Override 117193323Sed public String toString(final int level) { 118193323Sed final StringBuilder value = new StringBuilder(super.toString(level)); 119193323Sed value.append("\n target: " + pad(target, level + 1)); 120193323Sed value.append("\n lower: " + lower); 121193323Sed value.append("\n upper: " + upper); 122193323Sed value.append("\n greedy: " + greedy); 123198090Srdivacky value.append("\n targetEmptyInfo: " + targetEmptyInfo); 124198090Srdivacky value.append("\n headExact: " + pad(headExact, level + 1)); 125193323Sed value.append("\n nextHeadExact: " + pad(nextHeadExact, level + 1)); 126193323Sed value.append("\n isRefered: " + isRefered); 127198090Srdivacky 128198090Srdivacky return value.toString(); 129198090Srdivacky } 130193323Sed 131193323Sed public boolean isAnyCharStar() { 132193323Sed return greedy && isRepeatInfinite(upper) && target.getType() == CANY; 133193323Sed } 134193323Sed 135193323Sed /* ?:0, *:1, +:2, ??:3, *?:4, +?:5 */ 136193323Sed protected int popularNum() { 137193323Sed if (greedy) { 138193323Sed if (lower == 0) { 139193323Sed if (upper == 1) return 0; 140193323Sed else if (isRepeatInfinite(upper)) return 1; 141193323Sed } else if (lower == 1) { 142193323Sed if (isRepeatInfinite(upper)) return 2; 143193323Sed } 144193323Sed } else { 145193323Sed if (lower == 0) { 146193323Sed if (upper == 1) return 3; 147193323Sed else if (isRepeatInfinite(upper)) return 4; 148193323Sed } else if (lower == 1) { 149193323Sed if (isRepeatInfinite(upper)) return 5; 150193323Sed } 151193323Sed } 152193323Sed return -1; 153193323Sed } 154193323Sed 155193323Sed protected void set(final QuantifierNode other) { 156193323Sed setTarget(other.target); 157193323Sed other.target = null; 158193323Sed lower = other.lower; 159193323Sed upper = other.upper; 160193323Sed greedy = other.greedy; 161 targetEmptyInfo = other.targetEmptyInfo; 162 163 //setHeadExact(other.headExact); 164 //setNextHeadExact(other.nextHeadExact); 165 headExact = other.headExact; 166 nextHeadExact = other.nextHeadExact; 167 isRefered = other.isRefered; 168 } 169 170 public void reduceNestedQuantifier(final QuantifierNode other) { 171 final int pnum = popularNum(); 172 final int cnum = other.popularNum(); 173 174 if (pnum < 0 || cnum < 0) return; 175 176 switch(REDUCE_TABLE[cnum][pnum]) { 177 case DEL: 178 // no need to set the parent here... 179 // swap ? 180 set(other); // *pnode = *cnode; ??? 181 break; 182 183 case A: 184 setTarget(other.target); 185 lower = 0; 186 upper = REPEAT_INFINITE; 187 greedy = true; 188 break; 189 190 case AQ: 191 setTarget(other.target); 192 lower = 0; 193 upper = REPEAT_INFINITE; 194 greedy = false; 195 break; 196 197 case QQ: 198 setTarget(other.target); 199 lower = 0; 200 upper = 1; 201 greedy = false; 202 break; 203 204 case P_QQ: 205 setTarget(other); 206 lower = 0; 207 upper = 1; 208 greedy = false; 209 other.lower = 1; 210 other.upper = REPEAT_INFINITE; 211 other.greedy = true; 212 return; 213 214 case PQ_Q: 215 setTarget(other); 216 lower = 0; 217 upper = 1; 218 greedy = true; 219 other.lower = 1; 220 other.upper = REPEAT_INFINITE; 221 other.greedy = false; 222 return; 223 224 case ASIS: 225 setTarget(other); 226 return; 227 } 228 // ??? remove the parent from target ??? 229 other.target = null; // remove target from reduced quantifier 230 } 231 232 @SuppressWarnings("fallthrough") 233 public int setQuantifier(final Node tgt, final boolean group, final ScanEnvironment env, final char[] chars, final int p, final int end) { 234 if (lower == 1 && upper == 1) return 1; 235 236 switch(tgt.getType()) { 237 238 case STR: 239 if (!group) { 240 final StringNode sn = (StringNode)tgt; 241 if (sn.canBeSplit()) { 242 final StringNode n = sn.splitLastChar(); 243 if (n != null) { 244 setTarget(n); 245 return 2; 246 } 247 } 248 } 249 break; 250 251 case QTFR: 252 /* check redundant double repeat. */ 253 /* verbose warn (?:.?)? etc... but not warn (.?)? etc... */ 254 final QuantifierNode qnt = (QuantifierNode)tgt; 255 final int nestQNum = popularNum(); 256 final int targetQNum = qnt.popularNum(); 257 258 if (Config.USE_WARNING_REDUNDANT_NESTED_REPEAT_OPERATOR) { 259 if (!isByNumber() && !qnt.isByNumber() && env.syntax.warnReduntantNestedRepeat()) { 260 switch(REDUCE_TABLE[targetQNum][nestQNum]) { 261 case ASIS: 262 break; 263 264 case DEL: 265 env.reg.getWarnings().warn(new String(chars, p, end) + 266 " redundant nested repeat operator"); 267 break; 268 269 default: 270 env.reg.getWarnings().warn(new String(chars, p, end) + 271 " nested repeat operator " + PopularQStr[targetQNum] + 272 " and " + PopularQStr[nestQNum] + " was replaced with '" + 273 ReduceQStr[REDUCE_TABLE[targetQNum][nestQNum].ordinal()] + "'"); 274 } 275 } 276 } // USE_WARNING_REDUNDANT_NESTED_REPEAT_OPERATOR 277 278 if (targetQNum >= 0) { 279 if (nestQNum >= 0) { 280 reduceNestedQuantifier(qnt); 281 return 0; 282 } else if (targetQNum == 1 || targetQNum == 2) { /* * or + */ 283 /* (?:a*){n,m}, (?:a+){n,m} => (?:a*){n,n}, (?:a+){n,n} */ 284 if (!isRepeatInfinite(upper) && upper > 1 && greedy) { 285 upper = lower == 0 ? 1 : lower; 286 } 287 } 288 } 289 290 default: 291 break; 292 } 293 294 setTarget(tgt); 295 return 0; 296 } 297 298 public static final int REPEAT_INFINITE = -1; 299 public static boolean isRepeatInfinite(final int n) { 300 return n == REPEAT_INFINITE; 301 } 302 303} 304