src/jdk/nashorn/internal/runtime/regexp/joni/ast/QuantifierNode.java

Thu, 16 May 2013 19:52:39 +0200

author
hannesw
date
Thu, 16 May 2013 19:52:39 +0200
changeset 273
98798a6336de
parent 193
ed4293ceec0e
child 524
badc919cd621
permissions
-rw-r--r--

8012359: Increase code coverage in Joni
Reviewed-by: jlaskey, lagergren

     1 /*
     2  * Permission is hereby granted, free of charge, to any person obtaining a copy of
     3  * this software and associated documentation files (the "Software"), to deal in
     4  * the Software without restriction, including without limitation the rights to
     5  * use, copy, modify, merge, publish, distribute, sublicense, and/or sell copies
     6  * of the Software, and to permit persons to whom the Software is furnished to do
     7  * so, subject to the following conditions:
     8  *
     9  * The above copyright notice and this permission notice shall be included in all
    10  * copies or substantial portions of the Software.
    11  *
    12  * THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR
    13  * IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,
    14  * FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE
    15  * AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER
    16  * LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM,
    17  * OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE
    18  * SOFTWARE.
    19  */
    20 package jdk.nashorn.internal.runtime.regexp.joni.ast;
    22 import jdk.nashorn.internal.runtime.regexp.joni.Config;
    23 import jdk.nashorn.internal.runtime.regexp.joni.ScanEnvironment;
    24 import jdk.nashorn.internal.runtime.regexp.joni.constants.TargetInfo;
    26 import static jdk.nashorn.internal.runtime.regexp.joni.ast.QuantifierNode.ReduceType.*;
    28 public final class QuantifierNode extends StateNode {
    30     public Node target;
    31     public int lower;
    32     public int upper;
    33     public boolean greedy;
    35     public int targetEmptyInfo;
    37     public Node headExact;
    38     public Node nextHeadExact;
    39     public boolean isRefered;           /* include called node. don't eliminate even if {0} */
    41     enum ReduceType {
    42         ASIS,       /* as is */
    43         DEL,        /* delete parent */
    44         A,          /* to '*'    */
    45         AQ,         /* to '*?'   */
    46         QQ,         /* to '??'   */
    47         P_QQ,       /* to '+)??' */
    48         PQ_Q,       /* to '+?)?' */
    49     }
    51     private final static ReduceType[][] REDUCE_TABLE = {
    52             {DEL,     A,      A,      QQ,     AQ,     ASIS}, /* '?'  */
    53             {DEL,     DEL,    DEL,    P_QQ,   P_QQ,   DEL},  /* '*'  */
    54             {A,       A,      DEL,    ASIS,   P_QQ,   DEL},  /* '+'  */
    55             {DEL,     AQ,     AQ,     DEL,    AQ,     AQ},   /* '??' */
    56             {DEL,     DEL,    DEL,    DEL,    DEL,    DEL},  /* '*?' */
    57             {ASIS,    PQ_Q,   DEL,    AQ,     AQ,     DEL}   /* '+?' */
    58     };
    60     private final static String PopularQStr[] = new String[] {
    61             "?", "*", "+", "??", "*?", "+?"
    62     };
    64     private final static String ReduceQStr[]= new String[] {
    65             "", "", "*", "*?", "??", "+ and ??", "+? and ?"
    66     };
    69     public QuantifierNode(int lower, int upper, boolean byNumber) {
    70         this.lower = lower;
    71         this.upper = upper;
    72         greedy = true;
    73         targetEmptyInfo = TargetInfo.ISNOT_EMPTY;
    75         if (byNumber) setByNumber();
    76     }
    78     @Override
    79     public int getType() {
    80         return QTFR;
    81     }
    83     @Override
    84     protected void setChild(Node newChild) {
    85         target = newChild;
    86     }
    88     @Override
    89     protected Node getChild() {
    90         return target;
    91     }
    93     public void setTarget(Node tgt) {
    94         target = tgt;
    95         tgt.parent = this;
    96     }
    98     public StringNode convertToString(int flag) {
    99         StringNode sn = new StringNode();
   100         sn.flag = flag;
   101         sn.swap(this);
   102         return sn;
   103     }
   105     @Override
   106     public String getName() {
   107         return "Quantifier";
   108     }
   110     @Override
   111     public String toString(int level) {
   112         StringBuilder value = new StringBuilder(super.toString(level));
   113         value.append("\n  target: " + pad(target, level + 1));
   114         value.append("\n  lower: " + lower);
   115         value.append("\n  upper: " + upper);
   116         value.append("\n  greedy: " + greedy);
   117         value.append("\n  targetEmptyInfo: " + targetEmptyInfo);
   118         value.append("\n  headExact: " + pad(headExact, level + 1));
   119         value.append("\n  nextHeadExact: " + pad(nextHeadExact, level + 1));
   120         value.append("\n  isRefered: " + isRefered);
   122         return value.toString();
   123     }
   125     public boolean isAnyCharStar() {
   126         return greedy && isRepeatInfinite(upper) && target.getType() == CANY;
   127     }
   129     /* ?:0, *:1, +:2, ??:3, *?:4, +?:5 */
   130     protected int popularNum() {
   131         if (greedy) {
   132             if (lower == 0) {
   133                 if (upper == 1) return 0;
   134                 else if (isRepeatInfinite(upper)) return 1;
   135             } else if (lower == 1) {
   136                 if (isRepeatInfinite(upper)) return 2;
   137             }
   138         } else {
   139             if (lower == 0) {
   140                 if (upper == 1) return 3;
   141                 else if (isRepeatInfinite(upper)) return 4;
   142             } else if (lower == 1) {
   143                 if (isRepeatInfinite(upper)) return 5;
   144             }
   145         }
   146         return -1;
   147     }
   149     protected void set(QuantifierNode other) {
   150         setTarget(other.target);
   151         other.target = null;
   152         lower = other.lower;
   153         upper = other.upper;
   154         greedy = other.greedy;
   155         targetEmptyInfo = other.targetEmptyInfo;
   157         //setHeadExact(other.headExact);
   158         //setNextHeadExact(other.nextHeadExact);
   159         headExact = other.headExact;
   160         nextHeadExact = other.nextHeadExact;
   161         isRefered = other.isRefered;
   162     }
   164     public void reduceNestedQuantifier(QuantifierNode other) {
   165         int pnum = popularNum();
   166         int cnum = other.popularNum();
   168         if (pnum < 0 || cnum < 0) return;
   170         switch(REDUCE_TABLE[cnum][pnum]) {
   171         case DEL:
   172             // no need to set the parent here...
   173             // swap ?
   174             set(other); // *pnode = *cnode; ???
   175             break;
   177         case A:
   178             setTarget(other.target);
   179             lower = 0;
   180             upper = REPEAT_INFINITE;
   181             greedy = true;
   182             break;
   184         case AQ:
   185             setTarget(other.target);
   186             lower = 0;
   187             upper = REPEAT_INFINITE;
   188             greedy = false;
   189             break;
   191         case QQ:
   192             setTarget(other.target);
   193             lower = 0;
   194             upper = 1;
   195             greedy = false;
   196             break;
   198         case P_QQ:
   199             setTarget(other);
   200             lower = 0;
   201             upper = 1;
   202             greedy = false;
   203             other.lower = 1;
   204             other.upper = REPEAT_INFINITE;
   205             other.greedy = true;
   206             return;
   208         case PQ_Q:
   209             setTarget(other);
   210             lower = 0;
   211             upper = 1;
   212             greedy = true;
   213             other.lower = 1;
   214             other.upper = REPEAT_INFINITE;
   215             other.greedy = false;
   216             return;
   218         case ASIS:
   219             setTarget(other);
   220             return;
   221         }
   222         // ??? remove the parent from target ???
   223         other.target = null; // remove target from reduced quantifier
   224     }
   226     public int setQuantifier(Node tgt, boolean group, ScanEnvironment env, char[] chars, int p, int end) {
   227         if (lower == 1 && upper == 1) return 1;
   229         switch(tgt.getType()) {
   231         case STR:
   232             if (!group) {
   233                 StringNode sn = (StringNode)tgt;
   234                 if (sn.canBeSplit()) {
   235                     StringNode n = sn.splitLastChar();
   236                     if (n != null) {
   237                         setTarget(n);
   238                         return 2;
   239                     }
   240                 }
   241             }
   242             break;
   244         case QTFR:
   245             /* check redundant double repeat. */
   246             /* verbose warn (?:.?)? etc... but not warn (.?)? etc... */
   247             QuantifierNode qnt = (QuantifierNode)tgt;
   248             int nestQNum = popularNum();
   249             int targetQNum = qnt.popularNum();
   251             if (Config.USE_WARNING_REDUNDANT_NESTED_REPEAT_OPERATOR) {
   252                 if (!isByNumber() && !qnt.isByNumber() && env.syntax.warnReduntantNestedRepeat()) {
   253                     switch(REDUCE_TABLE[targetQNum][nestQNum]) {
   254                     case ASIS:
   255                         break;
   257                     case DEL:
   258                         env.reg.getWarnings().warn(new String(chars, p, end) +
   259                                 " redundant nested repeat operator");
   260                         break;
   262                     default:
   263                         env.reg.getWarnings().warn(new String(chars, p, end) +
   264                                 " nested repeat operator " + PopularQStr[targetQNum] +
   265                                 " and " + PopularQStr[nestQNum] + " was replaced with '" +
   266                                 ReduceQStr[REDUCE_TABLE[targetQNum][nestQNum].ordinal()] + "'");
   267                     }
   268                 }
   269             } // USE_WARNING_REDUNDANT_NESTED_REPEAT_OPERATOR
   271             if (targetQNum >= 0) {
   272                 if (nestQNum >= 0) {
   273                     reduceNestedQuantifier(qnt);
   274                     return 0;
   275                 } else if (targetQNum == 1 || targetQNum == 2) { /* * or + */
   276                     /* (?:a*){n,m}, (?:a+){n,m} => (?:a*){n,n}, (?:a+){n,n} */
   277                     if (!isRepeatInfinite(upper) && upper > 1 && greedy) {
   278                         upper = lower == 0 ? 1 : lower;
   279                     }
   280                 }
   281             }
   283         default:
   284             break;
   285         }
   287         setTarget(tgt);
   288         return 0;
   289     }
   291     public static final int REPEAT_INFINITE         = -1;
   292     public static boolean isRepeatInfinite(int n) {
   293         return n == REPEAT_INFINITE;
   294     }
   296 }

mercurial